risei 1.3.4 → 2.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (44) hide show
  1. package/README.md +134 -479
  2. package/index.js +5 -5
  3. package/package.json +10 -11
  4. package/system/ASpoofingFixture.js +7 -8
  5. package/system/ATestCaller.js +3 -3
  6. package/system/ATestFinder.js +2 -2
  7. package/system/ATestReporter.js +2 -1
  8. package/system/ATestSource.js +5 -1
  9. package/system/ChosenTestFinder.js +4 -4
  10. package/system/ClassTestGroup.js +2 -2
  11. package/system/LocalCaller.js +5 -5
  12. package/system/{ClassMethodSpoofer.js → MethodSpoofer.js} +54 -48
  13. package/system/MethodTestGroup.js +2 -2
  14. package/system/Moment.js +1 -1
  15. package/system/NameAnalyzer.js +26 -0
  16. package/system/PropertySpoofer.js +156 -0
  17. package/system/Risei.js +5 -5
  18. package/system/SpoofDef.js +260 -0
  19. package/system/TerminalReporter.js +8 -8
  20. package/system/{TestDefinition.js → TestDef.js} +153 -107
  21. package/system/TestFinder.js +3 -3
  22. package/system/TestFrame.js +15 -52
  23. package/system/TestGroup.js +1 -1
  24. package/system/TestResult.js +2 -2
  25. package/system/TestRunner.js +23 -107
  26. package/system/TestStages.js +80 -76
  27. package/system/TestSummary.js +1 -1
  28. package/system/TotalComparer.js +60 -11
  29. package/system/TotalDisplayer.js +33 -12
  30. package/system/TypeAnalyzer.js +41 -79
  31. package/system/TypeIdentifier.js +18 -8
  32. package/system/Types.js +3 -1
  33. package/system/AComparer.js +0 -9
  34. package/system/ATestFixture.js +0 -44
  35. package/system/ClassPropertySpoofer.js +0 -185
  36. package/system/ObjectMethodSpoofer.js +0 -58
  37. package/system/ObjectPropertySpoofer.js +0 -136
  38. package/system/SpoofDefinition.js +0 -243
  39. package/system/TestFrameChooser.js +0 -54
  40. package/system/TestFrames.js +0 -232
  41. package/system/TotalCopier.js +0 -106
  42. package/usage-examples/Output-example.png +0 -0
  43. package/usage-examples/Summary-example.png +0 -0
  44. package/usage-examples/Syntax-example.png +0 -0
@@ -1,243 +0,0 @@
1
- /**/
2
-
3
- import { TypeAnalyzer } from "./TypeAnalyzer.js";
4
-
5
- /* Defines what is found in a spoof-definition tuple (SDT). Actual SDTs don't need to be instances of this class. */
6
-
7
- export class SpoofDefinition {
8
- // region Static fields
9
-
10
- /* Properties can have short or long names. */
11
- static #longsByShort = new Map([
12
- [ "on", "target" ],
13
- [ "of", "method" ],
14
- [ "as", "output" ],
15
- ]);
16
-
17
- /* Objects with either of these property names aren't
18
- converted to SpoofDefinitions by from-nonce methods. */
19
- static skipNames = [ "not", "skip" ];
20
-
21
- // endregion Static fields
22
-
23
- // region Public fields (long names)
24
-
25
- /* These long names are clearer and match the constructor's parameter names. */
26
-
27
- /* The test-definition field names use the longer, possibly clearer forms.
28
- Equivalent short-name and long-name properties use the same fields. */
29
-
30
- target;
31
- method;
32
- output;
33
-
34
- // endregion Public fields (long names)
35
-
36
- // region Properties
37
-
38
- // region Spoof definition, short names
39
-
40
- /* These short names make JSON-like definitions easier. */
41
-
42
- get on() {
43
- return this.target;
44
- }
45
-
46
- set on(value) {
47
- this.target = value;
48
- }
49
-
50
- get of() {
51
- return this.method;
52
- }
53
-
54
- set of(value) {
55
- this.method = value;
56
- }
57
-
58
- get as() {
59
- return this.output;
60
- }
61
-
62
- set as(value) {
63
- this.output = value;
64
- }
65
-
66
- // endregion Spoof definition, short names
67
-
68
- // region Tuple state
69
-
70
- /* Returns true if instance provides enough to spoof with.
71
- A spoof must define at least either a method to spoof, or an output
72
- containing an array of methods to spoof, with optional outputs.
73
- See .notASpoof() for a contrasting condition. */
74
- isSpoofable() /* passed */ {
75
- let isSpoofable
76
- = this.method !== undefined
77
- || this.output !== undefined;
78
-
79
- return isSpoofable;
80
- }
81
-
82
- isPropertySpoof() /* passed */ {
83
- return TypeAnalyzer.memberIsProperty(this.target, this.method);
84
- }
85
-
86
- // endregion Tuple state
87
-
88
- // endregion Properties
89
-
90
- // region Initing, including constructor()
91
-
92
- /* Constructor can't use param names like `of`, because when not .-prefixed, they are keywords. */
93
-
94
- constructor(target, method, output) /* passed */ {
95
- this.target = target;
96
- this.method = method;
97
- this.output = output;
98
- }
99
-
100
- static fromNonceTuples(nonces) {
101
- // Throughput and output.
102
- let full = new SpoofDefinition();
103
- let output = [];
104
-
105
- // Looping over all.
106
- for (let nonce of nonces) {
107
- // Don't convert non-tuples, but output
108
- // them unchanged for the caller.
109
- if (SpoofDefinition.isNotASpoof(nonce)) {
110
- output.push(nonce);
111
- continue;
112
- }
113
-
114
- // Get latest spoof definition.
115
- let latest = SpoofDefinition.fromNonceTuple(nonce);
116
-
117
- // Restarting spoof definitions when desired.
118
- full = SpoofDefinition.maybeRestartFull(full, latest);
119
-
120
- // Merge any previous
121
- // values into latest.
122
- latest.combineWith(full);
123
-
124
- // Make latest the tuple for
125
- // combining with next time.
126
- full = latest;
127
-
128
- // Add latest only if it's
129
- // ready to use to spoof.
130
- if (latest.isSpoofable) {
131
- output.push(latest);
132
- }
133
- }
134
-
135
- // Back to caller.
136
- return output;
137
- }
138
-
139
- /* Returns true if arg should not be used for spoofing.
140
- See isSpoofable() for a contrasting condition. */
141
- static isNotASpoof(nonce) /* passed */ {
142
- /* Any nonce that is null or undefined is not a SpoofDefinition. */
143
- if (nonce === undefined || nonce === null) {
144
- return true;
145
- }
146
-
147
- /* Any nonce with .not or .skip isn't a SpoofDefinition, even if it has SpoofDefinition properties. */
148
- for (let non of SpoofDefinition.skipNames) {
149
- if (nonce[non] !== undefined) {
150
- return true;
151
- }
152
- }
153
-
154
- /* Any other nonce with any SpoofDefinition properties is a full or partial SpoofDefinition. */
155
- for (let key of SpoofDefinition.#longsByShort.keys()) {
156
- let value = SpoofDefinition.#longsByShort.get(key);
157
-
158
- if (nonce[key] !== undefined) {
159
- return false;
160
- }
161
-
162
- if (nonce[value] !== undefined) {
163
- return false;
164
- }
165
- }
166
-
167
- /* Any nonce without SpoofDefinition properties is not a spoof. */
168
- return true;
169
- }
170
-
171
- static isASpoof(nonce) {
172
- return !this.isNotASpoof(nonce);
173
- }
174
-
175
- static fromNonceTuple(nonce) /* passed */ {
176
- // Empty, since properties can be set
177
- // by either of two nonce naming styles.
178
- let tuple = new SpoofDefinition();
179
-
180
- let shortNames = SpoofDefinition.#longsByShort.keys();
181
-
182
- // Traversing matching pairs of names and applying
183
- // whichever one is present as the tuple property;
184
- // if neither is present, the property is undefined.
185
- for (let shortName of shortNames) {
186
- let longName = SpoofDefinition.#longsByShort.get(shortName);
187
- tuple[shortName] = shortName in nonce ? nonce[shortName] : nonce[longName];
188
- }
189
-
190
- // Back to caller.
191
- return tuple;
192
- }
193
-
194
- // region Dependencies of nonce-tuple initing methods
195
-
196
- static maybeRestartFull(full, latest) /* passed */ {
197
- // When a (new) spoof target is named, return the new
198
- // SpoofDefinition to wipe out all reused spoof values.
199
- if (latest.target !== undefined) {
200
- full = latest;
201
- }
202
-
203
- return full;
204
- }
205
-
206
- combineWith(other) {
207
- let shortNames = SpoofDefinition.#longsByShort.keys();
208
-
209
- for (let shortName of shortNames) {
210
- SpoofDefinition.combineValues(this, other, shortName);
211
- }
212
- }
213
-
214
- static combineValues(self, other, name) /* passed */ {
215
- // Property may still end up undefined.
216
- if (self[name] === undefined) {
217
- self[name] = other[name];
218
- }
219
- }
220
-
221
- // endregion Dependencies of nonce-tuple initing methods
222
-
223
- // endregion Initing, including constructor()
224
-
225
- // region Overrides and dependencies
226
-
227
- toString() /* passed */ {
228
- let text = `SpoofDefinition:{ target:${ this.#asRawOrString(this.target) }, `
229
- + `method:${ this.#asRawOrString(this.method) }, `
230
- + `output:${ this.#asRawOrString(this.output) } }`;
231
- return text;
232
- }
233
-
234
- #asRawOrString(value) /* verified */ {
235
- if (typeof value === "string") {
236
- return `"${ value }"`;
237
- }
238
-
239
- return value;
240
- }
241
-
242
- // endregion Overrides and dependencies
243
- }
@@ -1,54 +0,0 @@
1
- /**/
2
-
3
- export class TestFrameChooser {
4
- // Used for special test cases.
5
- constructorName = "constructor";
6
- staticName = "static";
7
- throwName = "throw";
8
-
9
- frames;
10
-
11
- constructor(frameSource) /* verified */ {
12
- this.frames = frameSource;
13
- }
14
-
15
- supplyTestFrame(test) /* passed */ {
16
- // If `.and` includes "static", a call of a static member
17
- // is made, and the actual is its return value.
18
- if (test.isStaticTest) {
19
- if (test.isThrowTest) {
20
- return this.frames.testThrowResultAfterStaticCall;
21
- }
22
-
23
- // If .from, a static call is made, then the actual is
24
- // retrieved from a named code element or custom code.
25
- if (test.isRetrievalTest) {
26
- return this.frames.testCodeElementAfterStaticCall;
27
- }
28
-
29
- // Otherwise, the return value
30
- // of the static call is used.
31
- return this.frames.testReturnValueOfStaticCall;
32
- }
33
-
34
- // Constructors are a special case; no second call should
35
- // be made, and actual must be retrieved from property.
36
- if (test.isConstructorTest) {
37
- return this.frames.testCodeElementAfterConstruction;
38
- }
39
-
40
- if (test.isThrowTest) {
41
- return this.frames.testThrowResultAfterCall;
42
- }
43
-
44
- // If .from, a call of the target is made, then the actual
45
- // is retrieved from a named code element or custom code.
46
- if (test.isRetrievalTest) {
47
- return this.frames.testCodeElementAfterCall;
48
- }
49
-
50
- // The most common case: the target is called,
51
- // and the actual is its return value.
52
- return this.frames.testReturnValueOfCall;
53
- }
54
- }
@@ -1,232 +0,0 @@
1
- /**/
2
-
3
- import { AComparer } from "./AComparer.js";
4
- import { TotalComparer } from "./TotalComparer.js";
5
-
6
- export class TestFrames {
7
- /* &cruft, refactor to merge with same on TestFrameChooser */
8
- // Used for special test cases.
9
- constructorName = "constructor";
10
- staticName = "static";
11
-
12
- /* &cruft, probably refactor comparing usage */
13
- /* Each test frame is bound to the calling instance of TestRunner,
14
- for now at least. TestRunner includes #compare() for now. */
15
-
16
- #comparer;
17
-
18
- constructor() {
19
- // Comparer is inited once for all tests, since compare() is reentrant.
20
- this.#comparer = new TotalComparer();
21
- }
22
-
23
- // The most basic test: whether a call of
24
- // a method returns the expected value.
25
- testReturnValueOfCall(test) {
26
- /* Groundwork. */
27
- let prototype = test.on.prototype;
28
- let target = new prototype.constructor(...test.with); // Must use `...`.
29
-
30
- this.#anyPropertySetting(target, test.settables);
31
-
32
- /* Exercising the code. */
33
- test.actual = target[test.of](...test.in); // Must use `...`.
34
-
35
- /* Comparing. */
36
- test.didPass = this.#compare(test.out, test.actual);
37
- }
38
-
39
- testReturnValueOfStaticCall(test) {
40
- /* Groundwork. */
41
- /* No instance is constructed. */
42
-
43
- let unsettables = this.#anyOriginalPropertyGetting(test.type, test.settables);
44
- this.#anyPropertySetting(test.type, test.settables);
45
-
46
- /* Exercising the code. */
47
- test.actual = test.on[test.of](...test.in); // Must use `...`.
48
-
49
- this.#anyPropertyUnsetting(test.type, unsettables);
50
-
51
- /* Comparing. */
52
- test.didPass = this.#compare(test.out, test.actual);
53
- }
54
-
55
- // The second-most basic test: whether a property
56
- // has the expected value after a method call.
57
- testCodeElementAfterCall(test) {
58
- /* Groundwork. */
59
- let prototype = test.on.prototype;
60
- let target = new prototype.constructor(...test.with); // Must use `...`.
61
-
62
- /* Exercising the code. */
63
- target[test.of](...test.in); // Must use `...`.
64
-
65
- /* Retrieving. */
66
- // The `actual` is a property or other code element somewhere.
67
- test.actual = this.#supplyNonReturnActual(test, target);
68
-
69
- /* Comparing. */
70
- test.didPass = this.#compare(test.out, test.actual);
71
- }
72
-
73
- testCodeElementAfterStaticCall(test) {
74
- /* Groundwork. */
75
- /* No instance is constructed. */
76
-
77
- /* Exercising the code. */
78
- test.on[test.of](...test.in); // Must use `...`.
79
-
80
- /* Retrieving. */
81
- test.actual = this.#supplyNonReturnActual(test); // No `target` here.
82
-
83
- /* Comparing. */
84
- test.didPass = this.#compare(test.out, test.actual);
85
- }
86
-
87
- // The third-most basic test: whether a property has
88
- // the expected value after an object is constructed.
89
- testCodeElementAfterConstruction(test) {
90
- /* Groundwork. */
91
- // For definition consistency, initing with test.in, not test.with.
92
- let prototype = test.on.prototype;
93
-
94
- /* Exercising the code. */
95
- let target = new prototype.constructor(...test.in); // Must use `...`.
96
-
97
- /* Retrieving. */
98
- // The `actual` is a property or other code element somewhere.
99
- test.actual = this.#supplyNonReturnActual(test, target);
100
-
101
- /* Comparing. */
102
- test.didPass = this.#compare(test.out, test.actual);
103
- }
104
-
105
- testThrowResultAfterCall(test) {
106
- /* Groundwork. */
107
- let prototype = test.on.prototype;
108
- let target = new prototype.constructor(...test.with); // Must use `...`.
109
-
110
- /* Exercising the code. */
111
- try {
112
- target[test.of](...test.in); // Must use `...`.
113
- }
114
- /* Retrieving. */
115
- catch (thrown) {
116
- test.actual = thrown.message;
117
- }
118
-
119
- /* Comparing. */
120
- test.didPass = this.#compare(test.out, test.actual);
121
- }
122
-
123
- testThrowResultAfterStaticCall(test) {
124
- /* Groundwork. */
125
- /* No instance is constructed. */
126
-
127
- /* Exercising the code. */
128
- try {
129
- test.on[test.of](...test.in) // Must use `...`.
130
- }
131
- catch (thrown) {
132
- test.actual = thrown.message;
133
- }
134
-
135
- /* Comparing. */
136
- test.didPass = this.#compare(test.out, test.actual);
137
- }
138
-
139
- // region Dependencies of test frames
140
-
141
- #anyOriginalPropertyGetting(target, settables) {
142
- if (!Array.isArray(settables)) {
143
- return;
144
- }
145
-
146
- let unsettables = [ ];
147
-
148
- for (let settable of settables) {
149
- // Not a setter tuple.
150
- if (!settable.of) {
151
- continue;
152
- }
153
-
154
- // Retaining original.
155
- let original = target[settable.of];
156
- let unsettable = { of: settable.of, as: original };
157
- unsettables.push(unsettable);
158
- }
159
-
160
- return unsettables;
161
- }
162
-
163
- #anyPropertySetting(target, settables) {
164
- // No properties to set.
165
- if (!Array.isArray(settables)) {
166
- return;
167
- }
168
-
169
- for (let settable of settables) {
170
- // Not a setter tuple.
171
- if (!settable.of) {
172
- continue;
173
- }
174
-
175
- // Actually setting property.
176
- target[settable.of] = settable.as;
177
- }
178
- }
179
-
180
- #anyPropertyUnsetting(target, unsettables) {
181
- // Unsetting is the same as setting,
182
- // but with tuples of original values.
183
- return this.#anyPropertySetting(target, unsettables);
184
- }
185
-
186
- #compare(expected, actual) {
187
- return this.#comparer.compare(expected, actual);
188
- }
189
-
190
- #supplyNonReturnActual(test, target) {
191
- // When there is a .from that's a string,
192
- // the actual is the named target member.
193
- if (typeof test.from === "string") {
194
- // Common member host;
195
- // undefined if static.
196
- let host = target;
197
-
198
- // When .and defines static.
199
- if (this.#doesAddressStatics(test)) {
200
- host = test.on;
201
- }
202
-
203
- return host[test.from];
204
- }
205
-
206
- // When there is a .from that's a function,
207
- // the actual is the result of calling it,
208
- // given everything that might be needed.
209
- if (test.from instanceof Function) {
210
- return test.from(target, test);
211
- }
212
-
213
- // When there is any other .from, the actual is the
214
- // value of the code element provided as .from.
215
- return test.from;
216
- }
217
-
218
- /* &cruft, refactor to merge with same on TestFrameChooser */
219
- #doesAddressStatics(test) {
220
- if (typeof test.and === "string") {
221
- if (test.and.includes(this.staticName)) {
222
- return true;
223
- }
224
- }
225
-
226
- return false;
227
- }
228
-
229
- // endregion Dependencies of test frames
230
-
231
-
232
- }
@@ -1,106 +0,0 @@
1
- /**/
2
-
3
- import { TypeIdentifier } from "./TypeIdentifier.js";
4
- import { Types } from "./Types.js";
5
-
6
- export class TotalCopier {
7
- #identifier = new TypeIdentifier();
8
-
9
- copy(original) /* passed */ {
10
- return this.recursiveCopy(original);
11
- }
12
-
13
- recursiveCopy(original) /* verified */ {
14
- /* &cruft, factor, possibly abstracting similar code,
15
- and/or return copy only once, or similar */
16
-
17
- /* Algorithm: First copied at current level by value if a value, by reference if
18
- not a value; then recursively replaced at next level, and so on. */
19
-
20
- let copy;
21
-
22
- let type = this.#identifier.identify(original);
23
-
24
- if (type === Types.isArray) {
25
- copy = [ ];
26
-
27
- // Traversal construction with recursion.
28
- for (let item of original) {
29
- let next = this.recursiveCopy(item);
30
- copy.push(next);
31
- }
32
-
33
- return copy;
34
- }
35
-
36
- if (type === Types.isMap) {
37
- copy = new Map();
38
-
39
- // Traversal construction with recursion.
40
- for (let entry of original.entries()) {
41
- let next = this.recursiveCopy(entry);
42
- copy.set(next[0], next[1]);
43
- }
44
-
45
- return copy;
46
- }
47
-
48
- if (type === Types.isSet) {
49
- copy = new Set();
50
-
51
- // Traversal construction with recursion.
52
- for (let value of original.values()) {
53
- let next = this.recursiveCopy(value);
54
- copy.add(next);
55
- }
56
-
57
- return copy;
58
- }
59
-
60
- if (type === Types.isDate) {
61
- copy = new Date(original);
62
- return copy;
63
- }
64
-
65
- // Actually copying isn't needed (or desirable) here,
66
- // since should always point to same thing regardless.
67
- if (type === Types.isClass) {
68
- copy = original;
69
- return copy;
70
- }
71
-
72
- // The workaround here makes a true independent copy of the
73
- // original function, regardless of its definition style.
74
- if (type === Types.isFunction) {
75
- let passer = [ original ];
76
- passer = [ ...passer ];
77
- copy = passer[0];
78
-
79
- return copy;
80
- }
81
-
82
- if (original instanceof Object) {
83
- // If original has a prototype, it's probably a class instance,
84
- // so it's constructed, so it includes all methods and accessors.
85
- let prototype = Object.getPrototypeOf(original);
86
- copy = prototype !== null ? new prototype.constructor() : { };
87
-
88
- let keys = Object.keys(original);
89
-
90
- // Settable properties are added, with recursion.
91
- for (let key of Object.keys(original)) {
92
- let next = this.recursiveCopy(original[key]);
93
- copy[key] = next;
94
- }
95
-
96
- return copy;
97
- }
98
-
99
- /* &cruft, other object types here */
100
-
101
- // All object types exhausted, so this is a value,
102
- // which can be used directly for a copy.
103
- copy = original;
104
- return copy;
105
- }
106
- }
Binary file
Binary file
Binary file