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.
- package/README.md +134 -479
- package/index.js +5 -5
- package/package.json +10 -11
- package/system/ASpoofingFixture.js +7 -8
- package/system/ATestCaller.js +3 -3
- package/system/ATestFinder.js +2 -2
- package/system/ATestReporter.js +2 -1
- package/system/ATestSource.js +5 -1
- package/system/ChosenTestFinder.js +4 -4
- package/system/ClassTestGroup.js +2 -2
- package/system/LocalCaller.js +5 -5
- package/system/{ClassMethodSpoofer.js → MethodSpoofer.js} +54 -48
- package/system/MethodTestGroup.js +2 -2
- package/system/Moment.js +1 -1
- package/system/NameAnalyzer.js +26 -0
- package/system/PropertySpoofer.js +156 -0
- package/system/Risei.js +5 -5
- package/system/SpoofDef.js +260 -0
- package/system/TerminalReporter.js +8 -8
- package/system/{TestDefinition.js → TestDef.js} +153 -107
- package/system/TestFinder.js +3 -3
- package/system/TestFrame.js +15 -52
- package/system/TestGroup.js +1 -1
- package/system/TestResult.js +2 -2
- package/system/TestRunner.js +23 -107
- package/system/TestStages.js +80 -76
- package/system/TestSummary.js +1 -1
- package/system/TotalComparer.js +60 -11
- package/system/TotalDisplayer.js +33 -12
- package/system/TypeAnalyzer.js +41 -79
- package/system/TypeIdentifier.js +18 -8
- package/system/Types.js +3 -1
- package/system/AComparer.js +0 -9
- package/system/ATestFixture.js +0 -44
- package/system/ClassPropertySpoofer.js +0 -185
- package/system/ObjectMethodSpoofer.js +0 -58
- package/system/ObjectPropertySpoofer.js +0 -136
- package/system/SpoofDefinition.js +0 -243
- package/system/TestFrameChooser.js +0 -54
- package/system/TestFrames.js +0 -232
- package/system/TotalCopier.js +0 -106
- package/usage-examples/Output-example.png +0 -0
- package/usage-examples/Summary-example.png +0 -0
- 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
|
-
}
|
package/system/TestFrames.js
DELETED
|
@@ -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
|
-
}
|
package/system/TotalCopier.js
DELETED
|
@@ -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
|