risei 1.1.0 → 1.1.2
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 +195 -338
- package/index.js +9 -9
- package/package.json +7 -7
- package/{public/javascript → system}/ChosenTestFinder.js +2 -2
- package/{public/javascript → system}/SpoofClassMethodsFixture.js +38 -22
- package/system/SpoofObjectMethodsFixture.js +58 -0
- package/{public/javascript → system}/SpoofTuple.js +14 -0
- package/system/TestFrame.js +187 -0
- package/{public/javascript → system}/TestFrameChooser.js +6 -47
- package/{public/javascript → system}/TestFrames.js +232 -180
- package/system/TestResult.js +187 -0
- package/system/TestStages.js +278 -0
- package/{public/javascript → system}/TestTuple.js +126 -18
- package/{public/javascript → system}/TotalComparer.js +12 -0
- package/system/TotalCopier.js +79 -0
- package/system/TotalDisplayer.js +143 -0
- package/system/TypeAnalyzer.js +103 -0
- package/system/TypeIdentifier.js +70 -0
- package/system/Types.js +17 -0
- package/public/javascript/SpoofObjectMethodsFixture.js +0 -52
- package/public/javascript/TestResult.js +0 -338
- /package/{public/javascript → system}/AComparer.js +0 -0
- /package/{public/javascript → system}/ASpoofingFixture.js +0 -0
- /package/{public/javascript → system}/ATestCaller.js +0 -0
- /package/{public/javascript → system}/ATestFinder.js +0 -0
- /package/{public/javascript → system}/ATestFixture.js +0 -0
- /package/{public/javascript → system}/ATestReporter.js +0 -0
- /package/{public/javascript → system}/ATestSource.js +0 -0
- /package/{public/javascript → system}/ClassTestGroup.js +0 -0
- /package/{public/javascript → system}/LocalCaller.js +0 -0
- /package/{public/javascript → system}/MethodTestGroup.js +0 -0
- /package/{public/javascript → system}/Moment.js +0 -0
- /package/{public/javascript → system}/Risei.js +0 -0
- /package/{public/javascript → system}/TerminalReporter.js +0 -0
- /package/{public/javascript → system}/TestFinder.js +0 -0
- /package/{public/javascript → system}/TestGroup.js +0 -0
- /package/{public/javascript → system}/TestRunner.js +0 -0
- /package/{public/javascript → system}/TestSummary.js +0 -0
package/index.js
CHANGED
|
@@ -10,17 +10,17 @@
|
|
|
10
10
|
|
|
11
11
|
// region Test-running dependencies
|
|
12
12
|
|
|
13
|
-
import { TestRunner } from "./
|
|
14
|
-
import { LocalCaller } from "./
|
|
15
|
-
import { TerminalReporter } from "./
|
|
16
|
-
import { TestFinder } from "./
|
|
13
|
+
import { TestRunner } from "./system/TestRunner.js";
|
|
14
|
+
import { LocalCaller } from "./system/LocalCaller.js";
|
|
15
|
+
import { TerminalReporter } from "./system/TerminalReporter.js";
|
|
16
|
+
import { TestFinder } from "./system/TestFinder.js";
|
|
17
17
|
|
|
18
18
|
// endregion Test-running dependencies
|
|
19
19
|
|
|
20
20
|
// region Display dependencies
|
|
21
21
|
|
|
22
22
|
import chalk from "chalk";
|
|
23
|
-
import { Moment } from "./
|
|
23
|
+
import { Moment } from "./system/Moment.js";
|
|
24
24
|
|
|
25
25
|
// endregion Display dependencies
|
|
26
26
|
|
|
@@ -30,14 +30,14 @@ import { Moment } from "./public/javascript/Moment.js";
|
|
|
30
30
|
|
|
31
31
|
// region Classes that users typically subclass
|
|
32
32
|
|
|
33
|
-
export * from "./
|
|
33
|
+
export * from "./system/ATestSource.js";
|
|
34
34
|
|
|
35
35
|
// endregion Classes that users typically subclass
|
|
36
36
|
|
|
37
37
|
// region Classes that users might subclass for uncommon cases
|
|
38
38
|
|
|
39
|
-
export * from "./
|
|
40
|
-
export * from "./
|
|
39
|
+
export * from "./system/ATestFinder.js";
|
|
40
|
+
export * from "./system/ATestReporter.js";
|
|
41
41
|
|
|
42
42
|
// endregion Classes that users might subclass for uncommon cases
|
|
43
43
|
|
|
@@ -66,7 +66,7 @@ let wide = (text) => {
|
|
|
66
66
|
async function runRiseiTests(testFinderPath) {
|
|
67
67
|
// region Converting test-finder from path to class
|
|
68
68
|
|
|
69
|
-
testFinderPath = testFinderPath || "./
|
|
69
|
+
testFinderPath = testFinderPath || "./system/TestFinder.js";
|
|
70
70
|
let finderModule = await import(testFinderPath);
|
|
71
71
|
|
|
72
72
|
let moduleKeys = Object.keys(finderModule);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "risei",
|
|
3
|
-
"version": "1.1.
|
|
3
|
+
"version": "1.1.2",
|
|
4
4
|
"description": "Risei is the framework that allows you to write unit tests as collections of values in JavaScript objects, so it's easy and fast, and tests don't serve as a drag on redesigns.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"unit test",
|
|
@@ -14,17 +14,17 @@
|
|
|
14
14
|
"objects",
|
|
15
15
|
"declarative"
|
|
16
16
|
],
|
|
17
|
-
"author": "Ed Fallin <
|
|
17
|
+
"author": "Ed Fallin <riseimaker@gmail.com>",
|
|
18
18
|
"license": "MIT",
|
|
19
19
|
"type": "module",
|
|
20
20
|
"private": false,
|
|
21
21
|
"scripts": {
|
|
22
22
|
"start": "node ./bin/www",
|
|
23
|
-
"rself": "clear; node
|
|
23
|
+
"rself": "clear; node system/Risei.js",
|
|
24
24
|
"rtest": "clear; node ./node_modules/risei/index.js",
|
|
25
25
|
"xtest": "clear; mocha **/*.tests.js",
|
|
26
26
|
"mixedtest": "clear; mocha **/*.tests.js; node ./node_modules/risei/index.js",
|
|
27
|
-
"alltest": "clear; mocha **/*.tests.js; node ./node_modules/risei/index.js; node
|
|
27
|
+
"alltest": "clear; mocha **/*.tests.js; node ./node_modules/risei/index.js; node system/Risei.js",
|
|
28
28
|
"test": "clear; node ./node_modules/risei/index.js"
|
|
29
29
|
},
|
|
30
30
|
"risei": {
|
|
@@ -32,7 +32,7 @@
|
|
|
32
32
|
},
|
|
33
33
|
"exports": {
|
|
34
34
|
".": "./index.js",
|
|
35
|
-
"./ATestSource": "./
|
|
35
|
+
"./ATestSource": "./system/ATestSource.js"
|
|
36
36
|
},
|
|
37
37
|
"dependencies": {
|
|
38
38
|
"chalk": "^5.0.0",
|
|
@@ -44,10 +44,10 @@
|
|
|
44
44
|
"chalk": "^5.0.0",
|
|
45
45
|
"cookie-parser": "~1.4.4",
|
|
46
46
|
"debug": "~2.6.9",
|
|
47
|
-
"express": "
|
|
47
|
+
"express": "^4.18.2",
|
|
48
48
|
"fs": "^0.0.1-security",
|
|
49
49
|
"mocha": "^10.0.0",
|
|
50
50
|
"morgan": "~1.9.1",
|
|
51
|
-
"risei": "
|
|
51
|
+
"risei": "1.1.2"
|
|
52
52
|
}
|
|
53
53
|
}
|
|
@@ -3,8 +3,8 @@
|
|
|
3
3
|
/* ChosenTestFinder is an ATestFinder that finds tests in the places coded in its constructor. */
|
|
4
4
|
|
|
5
5
|
import { ATestFinder } from "./ATestFinder.js";
|
|
6
|
-
import { TopicTests } from "
|
|
7
|
-
import { SelfTests } from "
|
|
6
|
+
import { TopicTests } from "../tests/topic-tests/TopicTests.outward-rt.js";
|
|
7
|
+
import { SelfTests } from "../tests/self-tests/SelfTests.outward-rt.js";
|
|
8
8
|
|
|
9
9
|
export class ChosenTestFinder extends ATestFinder {
|
|
10
10
|
constructor() {
|
|
@@ -4,6 +4,11 @@ import { ASpoofingFixture } from "./ASpoofingFixture.js";
|
|
|
4
4
|
import { SpoofTuple } from "./SpoofTuple.js";
|
|
5
5
|
|
|
6
6
|
export class SpoofClassMethodsFixture extends ASpoofingFixture {
|
|
7
|
+
/* Algorithm: Forward method spoof() looks at spoof definitions in .plus and applies them
|
|
8
|
+
to each class' prototypes after first saving the original member definitions.
|
|
9
|
+
Reverse method unspoof() restores each original member definition.
|
|
10
|
+
Fundamentally different from what SpoofObjectMethodsFixture does. */
|
|
11
|
+
|
|
7
12
|
// region Private fields
|
|
8
13
|
|
|
9
14
|
#spoofsByClass = new Map();
|
|
@@ -51,16 +56,18 @@ export class SpoofClassMethodsFixture extends ASpoofingFixture {
|
|
|
51
56
|
let spoofTuples = SpoofTuple.fromNonceTuples(spoofNonces);
|
|
52
57
|
|
|
53
58
|
// Storing spoofing definitions.
|
|
54
|
-
this.#
|
|
59
|
+
this.#retainSpoofsByClass(type, spoofTuples);
|
|
55
60
|
|
|
56
61
|
// Storing originals for restoring later.
|
|
57
|
-
this.#
|
|
62
|
+
this.#reserveOriginalsByClass();
|
|
58
63
|
|
|
59
64
|
// Actually spoofing.
|
|
60
|
-
this.#
|
|
65
|
+
this.#spoofMembersByClass();
|
|
61
66
|
}
|
|
62
67
|
|
|
63
|
-
|
|
68
|
+
// region Dependencies of spoof()
|
|
69
|
+
|
|
70
|
+
#retainSpoofsByClass(type, spoofTuples) {
|
|
64
71
|
// Map of Maps: by type, then by method.
|
|
65
72
|
for (let tuple of spoofTuples) {
|
|
66
73
|
// If no .target, use `type`.
|
|
@@ -68,13 +75,7 @@ export class SpoofClassMethodsFixture extends ASpoofingFixture {
|
|
|
68
75
|
tuple.target = type;
|
|
69
76
|
}
|
|
70
77
|
|
|
71
|
-
|
|
72
|
-
let spoofsByTarget = this.#spoofsByClass.get(tuple.target);
|
|
73
|
-
|
|
74
|
-
if (!spoofsByTarget) {
|
|
75
|
-
spoofsByTarget = new Map();
|
|
76
|
-
this.#spoofsByClass.set(tuple.target, spoofsByTarget);
|
|
77
|
-
}
|
|
78
|
+
let spoofsByTarget = this.#supplyMemberMap(this.#spoofsByClass, tuple.target);
|
|
78
79
|
|
|
79
80
|
// A single-method spoof is set for later use.
|
|
80
81
|
if (tuple.method) {
|
|
@@ -95,23 +96,20 @@ export class SpoofClassMethodsFixture extends ASpoofingFixture {
|
|
|
95
96
|
}
|
|
96
97
|
}
|
|
97
98
|
|
|
98
|
-
#
|
|
99
|
+
#reserveOriginalsByClass() {
|
|
99
100
|
/* Any spoofing of multiple methods on each class has already been
|
|
100
101
|
split up into Map elements, so this code can use those naively. */
|
|
101
102
|
|
|
102
103
|
let types = this.#spoofsByClass.keys();
|
|
103
104
|
|
|
105
|
+
// For each class.
|
|
104
106
|
for (let type of types) {
|
|
105
|
-
let originalsByTarget = this.#originalsByClass
|
|
107
|
+
let originalsByTarget = this.#supplyMemberMap(this.#originalsByClass, type);
|
|
106
108
|
|
|
107
|
-
if (!originalsByTarget) {
|
|
108
|
-
originalsByTarget = new Map();
|
|
109
|
-
this.#originalsByClass.set(type, originalsByTarget);
|
|
110
|
-
}
|
|
111
|
-
|
|
112
109
|
let spoofsByTarget = this.#spoofsByClass.get(type);
|
|
113
110
|
let names = spoofsByTarget.keys();
|
|
114
111
|
|
|
112
|
+
// Saving originals in the Map for later.
|
|
115
113
|
for (let name of names) {
|
|
116
114
|
let original = type.prototype[name];
|
|
117
115
|
originalsByTarget.set(name, original);
|
|
@@ -119,16 +117,31 @@ export class SpoofClassMethodsFixture extends ASpoofingFixture {
|
|
|
119
117
|
}
|
|
120
118
|
}
|
|
121
119
|
|
|
122
|
-
#
|
|
120
|
+
/* Dependency of #retainSpoofsByClass()
|
|
121
|
+
and #reserveOriginalsByClass(). */
|
|
122
|
+
#supplyMemberMap(source, target) {
|
|
123
|
+
let mapForType = source.get(target);
|
|
124
|
+
|
|
125
|
+
if (!mapForType) {
|
|
126
|
+
mapForType = new Map();
|
|
127
|
+
source.set(target, mapForType);
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
return mapForType;
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
#spoofMembersByClass() {
|
|
123
134
|
/* Any spoofing of multiple methods on each class has already been
|
|
124
135
|
split up into Map elements, so this code can use those naively. */
|
|
125
136
|
|
|
126
137
|
let types = this.#spoofsByClass.keys();
|
|
127
138
|
|
|
139
|
+
// For each class.
|
|
128
140
|
for (let type of types) {
|
|
129
141
|
let spoofsByTarget = this.#spoofsByClass.get(type);
|
|
130
142
|
let names = spoofsByTarget.keys();
|
|
131
143
|
|
|
144
|
+
// Actually spoofing, one by one.
|
|
132
145
|
for (let name of names) {
|
|
133
146
|
let spoofSource = spoofsByTarget.get(name);
|
|
134
147
|
let spoof = super.spoofMethod(spoofSource);
|
|
@@ -137,25 +150,28 @@ export class SpoofClassMethodsFixture extends ASpoofingFixture {
|
|
|
137
150
|
}
|
|
138
151
|
}
|
|
139
152
|
|
|
153
|
+
// endregion Dependencies of spoof()
|
|
154
|
+
|
|
140
155
|
// Spoofed methods on any targeted classes
|
|
141
156
|
// are restored to their original forms.
|
|
142
157
|
unspoof() {
|
|
143
158
|
let types = this.#originalsByClass.keys();
|
|
144
159
|
|
|
160
|
+
// For each class.
|
|
145
161
|
for (let target of types) {
|
|
146
|
-
let originalsByTarget = this.#originalsByClass.get(target);
|
|
147
|
-
|
|
148
162
|
let prototype = target.prototype;
|
|
149
163
|
|
|
164
|
+
let originalsByTarget = this.#originalsByClass.get(target);
|
|
150
165
|
let names = originalsByTarget.keys();
|
|
151
166
|
|
|
167
|
+
// Actually restoring, one by one.
|
|
152
168
|
for (let name of names) {
|
|
153
169
|
let original = originalsByTarget.get(name);
|
|
154
170
|
target.prototype[name] = original;
|
|
155
171
|
}
|
|
156
172
|
}
|
|
157
173
|
}
|
|
158
|
-
|
|
174
|
+
|
|
159
175
|
// Removes definitions, useful if this instance is reused,
|
|
160
176
|
// or else they might be applied when they shouldn't be.
|
|
161
177
|
removeDefinitions() {
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
/* */
|
|
2
|
+
|
|
3
|
+
import { ASpoofingFixture } from "./ASpoofingFixture.js";
|
|
4
|
+
import { SpoofTuple } from "./SpoofTuple.js";
|
|
5
|
+
|
|
6
|
+
export class SpoofObjectMethodsFixture extends ASpoofingFixture {
|
|
7
|
+
/* Algorithm: Forward method spoof() looks at a test's .with and .in, and replaces entire objects
|
|
8
|
+
in each with spoofed object trees, if the originals are spoof definitions.
|
|
9
|
+
No reverse unspoofing method is needed, since objects are nonces tossed after tests.
|
|
10
|
+
Fundamentally different from much of what SpoofClassMethodsFixture does. */
|
|
11
|
+
|
|
12
|
+
constructor() {
|
|
13
|
+
super("SpoofObjectMethodsFixture", "Construction");
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
/* Spoofs methods of any objects in test.with and test.in
|
|
17
|
+
for which nonce spoof-tuple definitions are provided. */
|
|
18
|
+
spoof(test) {
|
|
19
|
+
// These array test aspects may contain object-spoof definitions.
|
|
20
|
+
let topics = [ test.with, test.in ];
|
|
21
|
+
|
|
22
|
+
// Spoofing each array of test-aspect elements.
|
|
23
|
+
for (let topic of topics) {
|
|
24
|
+
// Replacing whole element with spoof or with unchanged self.
|
|
25
|
+
for (let at = 0; at < topic.length; at++) {
|
|
26
|
+
let target = topic[at];
|
|
27
|
+
topic[at] = this.spoofTarget(target);
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
spoofTarget(target) {
|
|
33
|
+
// Non-spoof targets are returned unchanged.
|
|
34
|
+
if (SpoofTuple.isNotASpoof(target)) {
|
|
35
|
+
return target;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
// Spoof definition targets are converted.
|
|
39
|
+
let tuple = SpoofTuple.fromNonceTuple(target);
|
|
40
|
+
let ofAsPairs = this.#supplySpoofPairs(tuple);
|
|
41
|
+
|
|
42
|
+
// Returning object with one or more spoofed members.
|
|
43
|
+
let spoofedTarget = super.spoofObjectTree(ofAsPairs);
|
|
44
|
+
return spoofedTarget;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
#supplySpoofPairs(tuple) {
|
|
48
|
+
// Single-spoof output.
|
|
49
|
+
let ofAsPairs = [{ of: tuple.method, as: tuple.output }];
|
|
50
|
+
|
|
51
|
+
// Poly-spoof output.
|
|
52
|
+
if (!tuple.method) {
|
|
53
|
+
ofAsPairs = tuple.output;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
return ofAsPairs;
|
|
57
|
+
}
|
|
58
|
+
}
|
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
/**/
|
|
2
2
|
|
|
3
|
+
import { TypeAnalyzer } from "./TypeAnalyzer.js";
|
|
4
|
+
|
|
3
5
|
/* Defines what is found in a spoof-definition tuple (SDT). Actual SDTs don't need to be instances of this class. */
|
|
4
6
|
|
|
5
7
|
export class SpoofTuple {
|
|
@@ -18,6 +20,12 @@ export class SpoofTuple {
|
|
|
18
20
|
|
|
19
21
|
// endregion Static fields
|
|
20
22
|
|
|
23
|
+
// region Private fields
|
|
24
|
+
|
|
25
|
+
#typeAnalyzer;
|
|
26
|
+
|
|
27
|
+
// endregion Private fields
|
|
28
|
+
|
|
21
29
|
// region Public fields (long names)
|
|
22
30
|
|
|
23
31
|
/* These long names are clearer and match the constructor's parameter names. */
|
|
@@ -76,6 +84,10 @@ export class SpoofTuple {
|
|
|
76
84
|
|
|
77
85
|
return isSpoofable;
|
|
78
86
|
}
|
|
87
|
+
|
|
88
|
+
isPropertySpoof() /* passed */ {
|
|
89
|
+
return this.#typeAnalyzer.memberIsProperty(this.method);
|
|
90
|
+
}
|
|
79
91
|
|
|
80
92
|
// endregion Tuple state
|
|
81
93
|
|
|
@@ -89,6 +101,8 @@ export class SpoofTuple {
|
|
|
89
101
|
this.target = target;
|
|
90
102
|
this.method = method;
|
|
91
103
|
this.output = output;
|
|
104
|
+
|
|
105
|
+
this.#typeAnalyzer = new TypeAnalyzer(target);
|
|
92
106
|
}
|
|
93
107
|
|
|
94
108
|
static fromNonceTuples(nonces) {
|
|
@@ -0,0 +1,187 @@
|
|
|
1
|
+
/**/
|
|
2
|
+
|
|
3
|
+
import { TestStages } from "./TestStages.js";
|
|
4
|
+
|
|
5
|
+
export class TestFrame {
|
|
6
|
+
/* &cruft : when TestStages is ready, use it and its methods here */
|
|
7
|
+
|
|
8
|
+
#stages;
|
|
9
|
+
|
|
10
|
+
constructor() {
|
|
11
|
+
// A TestStages is inited for each test.
|
|
12
|
+
this.#stages = new TestStages();
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
testFrame(test) {
|
|
16
|
+
console.log(`cruft : a`);
|
|
17
|
+
// Outer try for fails of groundwork requested.
|
|
18
|
+
try {
|
|
19
|
+
console.log(`cruft : b`);
|
|
20
|
+
/* &cruft, maybe simplify explanations here */
|
|
21
|
+
|
|
22
|
+
// Certain args must be isolated for collapsing forward, in case tested
|
|
23
|
+
// code mutates them. Sets test.localInitors and test.localInputs.
|
|
24
|
+
this.#stages.setLocalInitorsAndInputs(test);
|
|
25
|
+
|
|
26
|
+
console.log(`cruft : c`);
|
|
27
|
+
|
|
28
|
+
// Spoofing, setting static properties, and so on.
|
|
29
|
+
this.#stages.anyPreTargetingGroundwork(test);
|
|
30
|
+
|
|
31
|
+
console.log(`cruft : d`);
|
|
32
|
+
|
|
33
|
+
// Target may be instance, prototype for constructors, the class
|
|
34
|
+
// itself for statics, or nonce for properties. Sets test.target.
|
|
35
|
+
this.#stages.setLocalTarget(test);
|
|
36
|
+
|
|
37
|
+
console.log(`cruft : e`);
|
|
38
|
+
|
|
39
|
+
// Method under test may be on instance, class,
|
|
40
|
+
// or nonce for properties. Sets test.callable.
|
|
41
|
+
this.#stages.setLocalCallable(test);
|
|
42
|
+
|
|
43
|
+
console.log(`cruft : f`);
|
|
44
|
+
|
|
45
|
+
// Setting instance properties and so on.
|
|
46
|
+
this.#stages.anyPostTargetingGroundwork(test);
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
console.log(`cruft : g`);
|
|
50
|
+
|
|
51
|
+
// Inner try for fails of targeted code only.
|
|
52
|
+
try {
|
|
53
|
+
console.log(`cruft : h`);
|
|
54
|
+
|
|
55
|
+
console.log(`cruft : test.actual:`, test.actual);
|
|
56
|
+
console.log(`cruft : test.localTarget:`, test.localTarget);
|
|
57
|
+
console.log(`cruft : test.localCallable:`, test.localCallable);
|
|
58
|
+
console.log(`cruft : test.localInputs:`, test.localInputs);
|
|
59
|
+
|
|
60
|
+
// Tests usually look for this.
|
|
61
|
+
test.actual = test.localTarget[test.localCallable](...test.localInputs);
|
|
62
|
+
|
|
63
|
+
console.log(`cruft : test.actual:`, test.actual);
|
|
64
|
+
console.log(`cruft : i`);
|
|
65
|
+
}
|
|
66
|
+
catch (thrown) {
|
|
67
|
+
console.log(`cruft : j`);
|
|
68
|
+
|
|
69
|
+
// Sometimes tests look for this.
|
|
70
|
+
test.thrown = thrown;
|
|
71
|
+
|
|
72
|
+
console.log(`cruft : k`);
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
console.log(`cruft : l`);
|
|
76
|
+
|
|
77
|
+
// Sometimes tests look for results elsewhere.
|
|
78
|
+
this.#stages.anyModifyActual(test);
|
|
79
|
+
|
|
80
|
+
console.log(`cruft : m`);
|
|
81
|
+
|
|
82
|
+
/* &cruft, remove test-checking line when all tests pass */
|
|
83
|
+
// test.didPass = "fails";
|
|
84
|
+
|
|
85
|
+
// Actually testing the result.
|
|
86
|
+
test.didPass = this.#stages.compareResults(test.output, test.actual);
|
|
87
|
+
|
|
88
|
+
console.log(`cruft : n`);
|
|
89
|
+
|
|
90
|
+
}
|
|
91
|
+
finally {
|
|
92
|
+
console.log(`cruft : o`);
|
|
93
|
+
|
|
94
|
+
// Undoing any groundwork changes made.
|
|
95
|
+
this.#stages.anyGroundworkReversion(test);
|
|
96
|
+
|
|
97
|
+
console.log(`cruft : p`);
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
console.log(`cruft : q`);
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
// // region Dependencies of test frames
|
|
104
|
+
//
|
|
105
|
+
// /* &cruft, remove if / once superseded by code in TestStages */
|
|
106
|
+
//
|
|
107
|
+
// #anyOriginalPropertyGetting(target, settables) {
|
|
108
|
+
// if (!Array.isArray(settables)) {
|
|
109
|
+
// return;
|
|
110
|
+
// }
|
|
111
|
+
//
|
|
112
|
+
// let unsettables = [ ];
|
|
113
|
+
//
|
|
114
|
+
// for (let settable of settables) {
|
|
115
|
+
// // Not a setter tuple.
|
|
116
|
+
// if (!settable.of) {
|
|
117
|
+
// continue;
|
|
118
|
+
// }
|
|
119
|
+
//
|
|
120
|
+
// // Retaining original.
|
|
121
|
+
// let original = target[settable.of];
|
|
122
|
+
// let unsettable = { of: settable.of, as: original };
|
|
123
|
+
// unsettables.push(unsettable);
|
|
124
|
+
// }
|
|
125
|
+
//
|
|
126
|
+
// return unsettables;
|
|
127
|
+
// }
|
|
128
|
+
//
|
|
129
|
+
// #anyPropertySetting(target, settables) {
|
|
130
|
+
// // No properties to set.
|
|
131
|
+
// if (!Array.isArray(settables)) {
|
|
132
|
+
// return;
|
|
133
|
+
// }
|
|
134
|
+
//
|
|
135
|
+
// for (let settable of settables) {
|
|
136
|
+
// // Not a setter tuple.
|
|
137
|
+
// if (!settable.of) {
|
|
138
|
+
// continue;
|
|
139
|
+
// }
|
|
140
|
+
//
|
|
141
|
+
// // Actually setting property.
|
|
142
|
+
// target[settable.of] = settable.as;
|
|
143
|
+
// }
|
|
144
|
+
// }
|
|
145
|
+
//
|
|
146
|
+
// #anyPropertyUnsetting(target, unsettables) {
|
|
147
|
+
// // Unsetting is the same as setting,
|
|
148
|
+
// // but with tuples of original values.
|
|
149
|
+
// return this.#anyPropertySetting(target, unsettables);
|
|
150
|
+
// }
|
|
151
|
+
//
|
|
152
|
+
// // #compare(expected, actual) {
|
|
153
|
+
// // return this.#comparer.compare(expected, actual);
|
|
154
|
+
// // }
|
|
155
|
+
//
|
|
156
|
+
// #supplyNonReturnActual(test, target) {
|
|
157
|
+
// // When there is a .from that's a string,
|
|
158
|
+
// // the actual is the named target member.
|
|
159
|
+
// if (typeof test.from === "string") {
|
|
160
|
+
// // Common member host;
|
|
161
|
+
// // undefined if static.
|
|
162
|
+
// let host = target;
|
|
163
|
+
//
|
|
164
|
+
// // When .and defines static.
|
|
165
|
+
// if (this.#doesAddressStatics(test)) {
|
|
166
|
+
// host = test.on;
|
|
167
|
+
// }
|
|
168
|
+
//
|
|
169
|
+
// return host[test.from];
|
|
170
|
+
// }
|
|
171
|
+
//
|
|
172
|
+
// // When there is a .from that's a function,
|
|
173
|
+
// // the actual is the result of calling it,
|
|
174
|
+
// // given everything that might be needed.
|
|
175
|
+
// if (test.from instanceof Function) {
|
|
176
|
+
// return test.from(target, test);
|
|
177
|
+
// }
|
|
178
|
+
//
|
|
179
|
+
// // When there is any other .from, the actual is the
|
|
180
|
+
// // value of the code element provided as .from.
|
|
181
|
+
// return test.from;
|
|
182
|
+
// }
|
|
183
|
+
//
|
|
184
|
+
// // endregion Dependencies of test frames
|
|
185
|
+
//
|
|
186
|
+
|
|
187
|
+
}
|
|
@@ -15,14 +15,14 @@ export class TestFrameChooser {
|
|
|
15
15
|
supplyTestFrame(test) /* passed */ {
|
|
16
16
|
// If `.and` includes "static", a call of a static member
|
|
17
17
|
// is made, and the actual is its return value.
|
|
18
|
-
if (
|
|
19
|
-
if (
|
|
18
|
+
if (test.isStaticTest) {
|
|
19
|
+
if (test.isThrowTest) {
|
|
20
20
|
return this.frames.testThrowResultAfterStaticCall;
|
|
21
21
|
}
|
|
22
22
|
|
|
23
23
|
// If .from, a static call is made, then the actual is
|
|
24
24
|
// retrieved from a named code element or custom code.
|
|
25
|
-
if (
|
|
25
|
+
if (test.isRetrievalTest) {
|
|
26
26
|
return this.frames.testCodeElementAfterStaticCall;
|
|
27
27
|
}
|
|
28
28
|
|
|
@@ -33,17 +33,17 @@ export class TestFrameChooser {
|
|
|
33
33
|
|
|
34
34
|
// Constructors are a special case; no second call should
|
|
35
35
|
// be made, and actual must be retrieved from property.
|
|
36
|
-
if (test.
|
|
36
|
+
if (test.isConstructorTest) {
|
|
37
37
|
return this.frames.testCodeElementAfterConstruction;
|
|
38
38
|
}
|
|
39
39
|
|
|
40
|
-
if (
|
|
40
|
+
if (test.isThrowTest) {
|
|
41
41
|
return this.frames.testThrowResultAfterCall;
|
|
42
42
|
}
|
|
43
43
|
|
|
44
44
|
// If .from, a call of the target is made, then the actual
|
|
45
45
|
// is retrieved from a named code element or custom code.
|
|
46
|
-
if (
|
|
46
|
+
if (test.isRetrievalTest) {
|
|
47
47
|
return this.frames.testCodeElementAfterCall;
|
|
48
48
|
}
|
|
49
49
|
|
|
@@ -51,45 +51,4 @@ export class TestFrameChooser {
|
|
|
51
51
|
// and the actual is its return value.
|
|
52
52
|
return this.frames.testReturnValueOfCall;
|
|
53
53
|
}
|
|
54
|
-
|
|
55
|
-
doesAddressStatics(test) /* passed */ {
|
|
56
|
-
if (typeof test.and === "string") {
|
|
57
|
-
if (test.and.includes(this.staticName)) {
|
|
58
|
-
return true;
|
|
59
|
-
}
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
return false;
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
isThrowTest(test) /* passed */ {
|
|
66
|
-
if (typeof test.and === "string") {
|
|
67
|
-
if (test.and.includes(this.throwName)) {
|
|
68
|
-
return true;
|
|
69
|
-
}
|
|
70
|
-
}
|
|
71
|
-
|
|
72
|
-
return false;
|
|
73
|
-
}
|
|
74
|
-
|
|
75
|
-
isRetrievalTest(test) /* passed */ {
|
|
76
|
-
// Falsy code elements never are a retrieval.
|
|
77
|
-
if (!test.from) {
|
|
78
|
-
return false;
|
|
79
|
-
}
|
|
80
|
-
|
|
81
|
-
// If a (non-falsy) string, must be a retrieval.
|
|
82
|
-
if (typeof test.from === "string") {
|
|
83
|
-
return true;
|
|
84
|
-
}
|
|
85
|
-
|
|
86
|
-
// If a function, is a retrieval.
|
|
87
|
-
if (test.from instanceof Function) {
|
|
88
|
-
return true;
|
|
89
|
-
}
|
|
90
|
-
|
|
91
|
-
// Anything else is not a retrieval.
|
|
92
|
-
return false;
|
|
93
|
-
}
|
|
94
|
-
|
|
95
54
|
}
|