risei 3.0.0 → 3.1.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 +38 -23
- package/index.js +18 -66
- package/package.json +7 -6
- package/system/CallTypes.js +10 -0
- package/system/Choices.js +92 -0
- package/system/LocalCaller.js +45 -5
- package/system/ObjectAnalyzer.js +36 -0
- package/system/SpoofDef.js +73 -58
- package/system/TerminalReporter.js +109 -25
- package/system/TestDef.js +72 -5
- package/system/TestFinder.js +31 -29
- package/system/TestFrame.js +14 -3
- package/system/TestResult.js +63 -13
- package/system/TestRunner.js +75 -40
- package/system/TestStages.js +40 -37
- package/system/TestSummary.js +22 -15
- package/system/TotalComparer.js +54 -17
- package/system/TotalDisplayer.js +29 -6
- package/system/TypeAnalyzer.js +52 -14
- package/system/TypeIdentifier.js +10 -6
- package/system/Types.js +1 -0
- package/system/ATestCaller.js +0 -61
- package/system/ATestFinder.js +0 -38
- package/system/ATestReporter.js +0 -26
package/system/SpoofDef.js
CHANGED
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
import TypeAnalyzer from "./TypeAnalyzer.js";
|
|
4
4
|
import NameAnalyzer from "./NameAnalyzer.js";
|
|
5
|
+
import TotalDisplayer from "./TotalDisplayer.js";
|
|
5
6
|
|
|
6
7
|
/* Defines what is found in a spoof definition, typically as
|
|
7
8
|
a nonce object rather than an instance of this class. */
|
|
@@ -130,14 +131,14 @@ export default class SpoofDef {
|
|
|
130
131
|
|
|
131
132
|
// region Initing, including constructor() and statics
|
|
132
133
|
|
|
133
|
-
/*
|
|
134
|
-
|
|
134
|
+
/* Long names used, just in case. */
|
|
135
135
|
constructor(target, method, output) /* passed */ {
|
|
136
136
|
this.target = target;
|
|
137
137
|
this.method = method;
|
|
138
138
|
this.output = output;
|
|
139
139
|
}
|
|
140
140
|
|
|
141
|
+
/* Arg 'type' should be test.type if present. */
|
|
141
142
|
static fromNonceTuples(nonces, type) /* passed */ {
|
|
142
143
|
// Throughput and output.
|
|
143
144
|
let full = new SpoofDef();
|
|
@@ -154,82 +155,102 @@ export default class SpoofDef {
|
|
|
154
155
|
return output;
|
|
155
156
|
}
|
|
156
157
|
|
|
158
|
+
/* Arg 'type' should be test.type if present. */
|
|
157
159
|
static fromNonceTuple(nonce, type) /* passed */ {
|
|
158
|
-
|
|
160
|
+
// No spoof-def to output.
|
|
159
161
|
if (SpoofDef.isNotASpoof(nonce)) {
|
|
160
162
|
return [ ];
|
|
161
163
|
}
|
|
162
164
|
|
|
163
|
-
|
|
164
|
-
|
|
165
|
+
let defs = [ ];
|
|
166
|
+
|
|
167
|
+
// Nonce defines one spoof.
|
|
168
|
+
if (SpoofDef.#isMonoSpoof(nonce)) {
|
|
169
|
+
let def = SpoofDef.#fromMonoNonce(nonce, type);
|
|
170
|
+
defs.push(def);
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
// Nonce defines more than one spoof: Recursion.
|
|
174
|
+
if (SpoofDef.#isPolySpoof(nonce)) {
|
|
175
|
+
let locals = SpoofDef.#fromPolyNonce(nonce, type);
|
|
176
|
+
defs.push(...locals);
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
return defs;
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
// region Dependencies of nonce-tuple initing methods
|
|
183
|
+
|
|
184
|
+
static #isMonoSpoof(nonce) /* verified */ {
|
|
185
|
+
return SpoofDef.#hasEitherName(nonce, SpoofDef.#ofNames);
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
static #isPolySpoof(nonce) /* verified */ {
|
|
189
|
+
return !SpoofDef.#isMonoSpoof(nonce);
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
/* Arg 'type' should be test.type if present. */
|
|
193
|
+
static #fromMonoNonce(nonce, type) /* verified */ {
|
|
194
|
+
// Empty, since each prop can
|
|
195
|
+
// have either of two names.
|
|
165
196
|
let def = new SpoofDef();
|
|
166
197
|
|
|
167
198
|
let shortNames = SpoofDef.#longsByShort.keys();
|
|
168
199
|
|
|
169
|
-
|
|
170
|
-
recurse internally using it without inner arrays, for a cleaner algorithm */
|
|
171
|
-
|
|
172
|
-
// Traversing matching pairs of names and applying
|
|
173
|
-
// whichever one is present as the tuple property;
|
|
200
|
+
// Traversing name pairs to use whichever one is present;
|
|
174
201
|
// if neither is present, the property is undefined.
|
|
175
202
|
for (let shortName of shortNames) {
|
|
176
203
|
let longName = SpoofDef.#longsByShort.get(shortName);
|
|
177
|
-
|
|
204
|
+
|
|
205
|
+
def[shortName]
|
|
206
|
+
= nonce[shortName] !== undefined
|
|
207
|
+
? nonce[shortName]
|
|
208
|
+
: nonce[longName];
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
// Adding test target's type, if no type provided.
|
|
212
|
+
if (def.target === undefined) {
|
|
213
|
+
def.target = type;
|
|
178
214
|
}
|
|
179
215
|
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
let defs = [ def ];
|
|
216
|
+
return def;
|
|
217
|
+
}
|
|
183
218
|
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
219
|
+
/* Arg 'type' should be test.type if present. */
|
|
220
|
+
static #fromPolyNonce(nonce, type) /* verified */ {
|
|
221
|
+
let defs = [ ];
|
|
187
222
|
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
let localAs = ofAsPair.as !== undefined ? ofAsPair.as : ofAsPair.output;
|
|
223
|
+
// Poly-nonce's .on applies to all its partial spoofs.
|
|
224
|
+
let on = nonce.on !== undefined ? nonce.on : nonce.target;
|
|
191
225
|
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
}
|
|
226
|
+
// Poly-nonce's .as is an array of partial-spoof nonces.
|
|
227
|
+
let pairs = nonce.as !== undefined ? nonce.as : nonce.output;
|
|
195
228
|
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
229
|
+
// Traversing partial-spoof nonces (.of and .as only).
|
|
230
|
+
for (let pair of pairs) {
|
|
231
|
+
// Either name (or neither) may exist on nonce partial.
|
|
232
|
+
let of = pair.of !== undefined ? pair.of : pair.method;
|
|
233
|
+
let as = pair.as !== undefined ? pair.as : pair.output;
|
|
200
234
|
|
|
201
|
-
|
|
202
|
-
|
|
235
|
+
// Only one level of recursion.
|
|
236
|
+
let passer = SpoofDef.#fromMonoNonce({ on, of, as }, type);
|
|
237
|
+
|
|
238
|
+
defs.push(passer);
|
|
239
|
+
}
|
|
203
240
|
|
|
204
|
-
// Back to caller.
|
|
205
241
|
return defs;
|
|
206
242
|
}
|
|
207
243
|
|
|
208
|
-
// region Dependencies of nonce-tuple initing methods
|
|
209
|
-
|
|
210
244
|
static #hasEitherName(nonce, names) /* verified */ {
|
|
211
245
|
let hasEither = false;
|
|
212
246
|
|
|
213
247
|
for (let name of names) {
|
|
214
|
-
hasEither ||=
|
|
248
|
+
hasEither ||= nonce[name] !== undefined;
|
|
215
249
|
}
|
|
216
250
|
|
|
217
251
|
return hasEither;
|
|
218
252
|
}
|
|
219
253
|
|
|
220
|
-
static #hasName(nonce, name) /* verified */ {
|
|
221
|
-
return nonce[name] !== undefined;
|
|
222
|
-
}
|
|
223
|
-
|
|
224
|
-
static #setAnyMissingTypes(defs, type) /* verified */ {
|
|
225
|
-
// Adding test target's type, if no type provided.
|
|
226
|
-
for (let def of defs) {
|
|
227
|
-
if (def.target === undefined) {
|
|
228
|
-
def.target = type;
|
|
229
|
-
}
|
|
230
|
-
}
|
|
231
|
-
}
|
|
232
|
-
|
|
233
254
|
// endregion Dependencies of nonce-tuple initing methods
|
|
234
255
|
|
|
235
256
|
// endregion Initing, including constructor() and statics
|
|
@@ -237,19 +258,13 @@ export default class SpoofDef {
|
|
|
237
258
|
// region Overrides and dependencies
|
|
238
259
|
|
|
239
260
|
toString() /* passed */ {
|
|
240
|
-
let
|
|
241
|
-
|
|
242
|
-
|
|
261
|
+
let displayer = new TotalDisplayer();
|
|
262
|
+
|
|
263
|
+
let text = `SpoofDef{ on:${ displayer.display(this.target) }, `
|
|
264
|
+
+ `of:${ displayer.display(this.method) }, `
|
|
265
|
+
+ `as:${ displayer.display(this.output) } }`;
|
|
243
266
|
return text;
|
|
244
267
|
}
|
|
245
|
-
|
|
246
|
-
#asRawOrString(value) /* verified */ {
|
|
247
|
-
if (typeof value === "string") {
|
|
248
|
-
return `"${ value }"`;
|
|
249
|
-
}
|
|
250
|
-
|
|
251
|
-
return value;
|
|
252
|
-
}
|
|
253
|
-
|
|
268
|
+
|
|
254
269
|
// endregion Overrides and dependencies
|
|
255
270
|
}
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
/**/
|
|
2
2
|
|
|
3
|
-
/* TerminalReporter
|
|
3
|
+
/* TerminalReporter displays each test result in the terminal / console window. */
|
|
4
4
|
|
|
5
|
-
import
|
|
5
|
+
import Moment from "./Moment.js";
|
|
6
6
|
import TestGroup from "./TestGroup.js";
|
|
7
7
|
import ClassTestGroup from "./ClassTestGroup.js";
|
|
8
8
|
import MethodTestGroup from "./MethodTestGroup.js";
|
|
@@ -11,8 +11,12 @@ import TestSummary from "./TestSummary.js";
|
|
|
11
11
|
|
|
12
12
|
import chalk from "chalk";
|
|
13
13
|
|
|
14
|
-
export default class TerminalReporter
|
|
15
|
-
// region
|
|
14
|
+
export default class TerminalReporter {
|
|
15
|
+
// region Fields
|
|
16
|
+
|
|
17
|
+
/* Display styles for the start title and other general needs. */
|
|
18
|
+
#title = chalk.hex("FFFFFF").bgHex("191970").bold;
|
|
19
|
+
#fails = chalk.hex("000000").bgHex("FFD700").bold;
|
|
16
20
|
|
|
17
21
|
/* Foreground-colors using dependency calls and hex. */
|
|
18
22
|
#trueWhite = chalk.hex("FFFFFF");
|
|
@@ -31,22 +35,53 @@ export default class TerminalReporter extends ATestReporter {
|
|
|
31
35
|
#methodGroup = this.#trueWhite.bgHex(this.#aqua).bold;
|
|
32
36
|
#passed = this.#trueBlack.bgHex(this.#paleGreen);
|
|
33
37
|
#failed = this.#trueBlack.bgHex(this.#paleRed);
|
|
38
|
+
#problems = chalk.hex("000000").bgHex("FFD700").bold;
|
|
39
|
+
|
|
34
40
|
#passedSummary = this.#trueBlack.bgHex(this.#paleGreen).bold;
|
|
35
41
|
#failedSummary = this.#trueBlack.bgHex(this.#paleRed).bold;
|
|
36
42
|
#summary = chalk.hex("000080").bgHex("FAFAD2").bold;
|
|
37
43
|
|
|
44
|
+
|
|
38
45
|
// Count of characters used for indent
|
|
39
46
|
// and text to the left of each test.
|
|
40
47
|
#preUsedWidth = 20;
|
|
41
48
|
|
|
42
|
-
// endregion
|
|
49
|
+
// endregion Fields
|
|
50
|
+
|
|
51
|
+
reportTitle() {
|
|
52
|
+
// This moment, ready for use in title.
|
|
53
|
+
let now = new Date();
|
|
54
|
+
now = new Moment(now);
|
|
55
|
+
|
|
56
|
+
// Top of screen and leading color stripe.
|
|
57
|
+
console.clear();
|
|
58
|
+
console.log();
|
|
59
|
+
console.log(this.#title(this.#wide()));
|
|
43
60
|
|
|
44
|
-
|
|
61
|
+
// Actually reporting title.
|
|
62
|
+
console.log(this.#title(this.#wide(` Risei tests run on ${ now.asReadable() } local time.`)));
|
|
63
|
+
|
|
64
|
+
// Trailing color stripe and blank line.
|
|
65
|
+
console.log(this.#title(this.#wide()));
|
|
66
|
+
console.log();
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
// region Dependencies of reportTitle()
|
|
70
|
+
|
|
71
|
+
/* Styling for color stripes. */
|
|
72
|
+
#wide(text) {
|
|
73
|
+
let width = process.stdout.columns;
|
|
74
|
+
text = text || "";
|
|
75
|
+
|
|
76
|
+
return text.padEnd(width, "\u00A0");
|
|
77
|
+
};
|
|
78
|
+
|
|
79
|
+
// endregion Dependencies of reportTitle()
|
|
45
80
|
|
|
46
81
|
reportNext(result) {
|
|
47
82
|
// The next result introduces a group of tests.
|
|
48
83
|
if (result instanceof TestGroup) {
|
|
49
|
-
this
|
|
84
|
+
this.#reportGroup(result);
|
|
50
85
|
return;
|
|
51
86
|
}
|
|
52
87
|
|
|
@@ -58,12 +93,14 @@ export default class TerminalReporter extends ATestReporter {
|
|
|
58
93
|
|
|
59
94
|
// The next result is the summary of all tests.
|
|
60
95
|
if (result instanceof TestSummary) {
|
|
61
|
-
this
|
|
96
|
+
this.#reportSummary(result);
|
|
62
97
|
return;
|
|
63
98
|
}
|
|
64
99
|
}
|
|
65
100
|
|
|
66
|
-
|
|
101
|
+
// region Direct dependencies of reportNext(), except summary
|
|
102
|
+
|
|
103
|
+
#reportGroup(result) {
|
|
67
104
|
if (result instanceof ClassTestGroup) {
|
|
68
105
|
console.log(this.#classGroup(` ${ result.group }: `));
|
|
69
106
|
}
|
|
@@ -73,32 +110,44 @@ export default class TerminalReporter extends ATestReporter {
|
|
|
73
110
|
}
|
|
74
111
|
}
|
|
75
112
|
|
|
76
|
-
// region Private dependencies of reportNext()
|
|
77
|
-
|
|
78
113
|
#reportTestResult(result) {
|
|
114
|
+
if (result.doesHaveThrow) {
|
|
115
|
+
this.#reportThrew(result.anyThrow.stack);
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
if (result.doesHaveTrouble) {
|
|
119
|
+
this.#reportThrew(result.anyTrouble.stack);
|
|
120
|
+
}
|
|
121
|
+
|
|
79
122
|
if (result.didPass) {
|
|
80
|
-
this
|
|
123
|
+
this.#reportPassed(result);
|
|
81
124
|
}
|
|
82
125
|
|
|
83
126
|
if (!result.didPass) {
|
|
84
|
-
this
|
|
127
|
+
this.#reportFailed(result);
|
|
85
128
|
}
|
|
86
129
|
}
|
|
87
130
|
|
|
88
|
-
// endregion
|
|
131
|
+
// endregion Direct dependencies of reportNext(), except summary
|
|
132
|
+
|
|
133
|
+
// region Direct dependencies of #reportTestResult()
|
|
134
|
+
|
|
135
|
+
#reportThrew(threw) {
|
|
136
|
+
console.log(this.#problems(threw));
|
|
137
|
+
}
|
|
89
138
|
|
|
90
|
-
reportPassed(result) {
|
|
139
|
+
#reportPassed(result) {
|
|
91
140
|
this.#reportOneTestResult(result, "Passed", this.#passed);
|
|
92
141
|
}
|
|
93
142
|
|
|
94
|
-
reportFailed(result) {
|
|
143
|
+
#reportFailed(result) {
|
|
95
144
|
this.#reportOneTestResult(result, "Failed", this.#failed);
|
|
96
145
|
}
|
|
97
146
|
|
|
98
|
-
//
|
|
147
|
+
// endregion Direct dependencies of #reportTestResult()
|
|
148
|
+
|
|
149
|
+
// region Dependencies of #reportPassed() and #reportFailed()
|
|
99
150
|
|
|
100
|
-
/* &cruft, changes here / in dependencies
|
|
101
|
-
for better splitting to multiple lines */
|
|
102
151
|
#reportOneTestResult(result, net, styler) {
|
|
103
152
|
let { lineOne, lineTwo, lineThree, lineFour } = this.#calculateResultDisplay(result);
|
|
104
153
|
|
|
@@ -166,7 +215,7 @@ export default class TerminalReporter extends ATestReporter {
|
|
|
166
215
|
return this.#oneLineTactic(identityText, inputsText, expectedText, actualText);
|
|
167
216
|
}
|
|
168
217
|
|
|
169
|
-
// region
|
|
218
|
+
// region Dependencies of #calculateResultDisplay()
|
|
170
219
|
|
|
171
220
|
#fourLineTactic(identityText, inputsText, expectedText, actualText) {
|
|
172
221
|
// Each line on its own.
|
|
@@ -218,13 +267,17 @@ export default class TerminalReporter extends ATestReporter {
|
|
|
218
267
|
return { lineOne, lineTwo, lineThree, lineFour };
|
|
219
268
|
}
|
|
220
269
|
|
|
221
|
-
// endregion
|
|
270
|
+
// endregion Dependencies of #calculateResultDisplay()
|
|
271
|
+
|
|
272
|
+
// endregion Dependencies of #reportPassed() and #reportFailed()
|
|
222
273
|
|
|
223
|
-
//
|
|
274
|
+
// region Summary dependency of reportNext()
|
|
224
275
|
|
|
225
|
-
reportSummary(summary) {
|
|
276
|
+
#reportSummary(summary) {
|
|
226
277
|
console.log();
|
|
227
278
|
|
|
279
|
+
/* Actual summary. */
|
|
280
|
+
|
|
228
281
|
if (summary.anyWereRun) {
|
|
229
282
|
if (summary.allDidPass) {
|
|
230
283
|
console.log(this.#passedSummary(this.#toFullWidth(" Test run succeeded.")));
|
|
@@ -235,7 +288,31 @@ export default class TerminalReporter extends ATestReporter {
|
|
|
235
288
|
}
|
|
236
289
|
|
|
237
290
|
console.log(this.#summary(this.#toFullWidth(` ${ summary.summary }`)));
|
|
238
|
-
|
|
291
|
+
|
|
292
|
+
/* Post-summary reporting of any throws. */
|
|
293
|
+
|
|
294
|
+
// Unsought throws in tested code.
|
|
295
|
+
if (summary.anyThrows.length !== 0) {
|
|
296
|
+
console.log();
|
|
297
|
+
console.log(this.#problems(summary.anyThrows.join("\n")));
|
|
298
|
+
}
|
|
299
|
+
|
|
300
|
+
// Throws in code in scope of test frame.
|
|
301
|
+
if (summary.anyTroubles.length !== 0) {
|
|
302
|
+
console.log();
|
|
303
|
+
console.log(this.#problems(summary.anyTroubles.join("\n")));
|
|
304
|
+
}
|
|
305
|
+
|
|
306
|
+
// Throws in code in scope of test runner.
|
|
307
|
+
if (summary.anyCaught.length !== 0) {
|
|
308
|
+
console.log();
|
|
309
|
+
console.log(this.#problems(summary.anyCaught.join("\n")));
|
|
310
|
+
}
|
|
311
|
+
}
|
|
312
|
+
|
|
313
|
+
// endregion Summary dependency of reportNext()
|
|
314
|
+
|
|
315
|
+
// region Dependencies of #reportSummary()
|
|
239
316
|
|
|
240
317
|
#toFullWidth(text) {
|
|
241
318
|
text = text || "";
|
|
@@ -244,6 +321,13 @@ export default class TerminalReporter extends ATestReporter {
|
|
|
244
321
|
return text.padEnd(width, "\u00A0");
|
|
245
322
|
}
|
|
246
323
|
|
|
247
|
-
// endregion
|
|
324
|
+
// endregion Dependencies of #reportSummary()
|
|
248
325
|
|
|
326
|
+
blankLine() {
|
|
327
|
+
console.log();
|
|
328
|
+
}
|
|
329
|
+
|
|
330
|
+
reportLoadFail(fail) {
|
|
331
|
+
console.log(this.#fails(this.#wide(` ${ fail }`)));
|
|
332
|
+
}
|
|
249
333
|
}
|
package/system/TestDef.js
CHANGED
|
@@ -4,6 +4,8 @@ import TypeAnalyzer from "./TypeAnalyzer.js";
|
|
|
4
4
|
import NameAnalyzer from "./NameAnalyzer.js";
|
|
5
5
|
import TypeIdentifier from "./TypeIdentifier.js";
|
|
6
6
|
import Types from "./Types.js";
|
|
7
|
+
import CallTypes from "./CallTypes.js";
|
|
8
|
+
import TotalDisplayer from "./TotalDisplayer.js";
|
|
7
9
|
|
|
8
10
|
/* Defines what is found in a test definition, typically as
|
|
9
11
|
a nonce object rather than an instance of this class. */
|
|
@@ -57,7 +59,8 @@ export default class TestDef {
|
|
|
57
59
|
target;
|
|
58
60
|
|
|
59
61
|
actual;
|
|
60
|
-
thrown;
|
|
62
|
+
thrown; // Throw in inner scope (tested code).
|
|
63
|
+
trouble; // Throw in outer scope (test system or .do / .undo / .from).
|
|
61
64
|
|
|
62
65
|
// endregion Fields
|
|
63
66
|
|
|
@@ -187,6 +190,10 @@ export default class TestDef {
|
|
|
187
190
|
return is;
|
|
188
191
|
}
|
|
189
192
|
|
|
193
|
+
get isMonoCallTest() /* passed */ {
|
|
194
|
+
return !this.isPolyCallTest;
|
|
195
|
+
}
|
|
196
|
+
|
|
190
197
|
get isPolyCallTest() /* passed */ {
|
|
191
198
|
let is = this.andStringContains(TestDef.polyName);
|
|
192
199
|
return is;
|
|
@@ -198,7 +205,7 @@ export default class TestDef {
|
|
|
198
205
|
}
|
|
199
206
|
|
|
200
207
|
get isMethodTest() /* passed */ {
|
|
201
|
-
return !this.isPropertyTest;
|
|
208
|
+
return !this.isPropertyTest && !this.isConstructorTest;
|
|
202
209
|
}
|
|
203
210
|
|
|
204
211
|
get isPropertyTest() /* passed */ {
|
|
@@ -211,6 +218,22 @@ export default class TestDef {
|
|
|
211
218
|
return isPropertyTest;
|
|
212
219
|
}
|
|
213
220
|
|
|
221
|
+
get callType() /* passed */ {
|
|
222
|
+
let type;
|
|
223
|
+
|
|
224
|
+
if (this.isMethodTest) {
|
|
225
|
+
type = this.isMonoCallTest ? CallTypes.methodMono : CallTypes.methodPoly;
|
|
226
|
+
}
|
|
227
|
+
else if (this.isPropertyTest) {
|
|
228
|
+
type = this.isMonoCallTest ? CallTypes.propMono : CallTypes.propPoly;
|
|
229
|
+
}
|
|
230
|
+
else if (this.isConstructorTest) {
|
|
231
|
+
type = this.isMonoCallTest ? CallTypes.conMono : CallTypes.conPoly;
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
return type;
|
|
235
|
+
}
|
|
236
|
+
|
|
214
237
|
get isRetrievalTest() /* passed */ {
|
|
215
238
|
// Falsy code elements never are a retrieval.
|
|
216
239
|
if (!this.from) {
|
|
@@ -256,7 +279,7 @@ export default class TestDef {
|
|
|
256
279
|
get runName() /* passed */ {
|
|
257
280
|
let plain = NameAnalyzer.plainNameOf(this.of);
|
|
258
281
|
|
|
259
|
-
if (this.
|
|
282
|
+
if (!this.isPropertyTest) {
|
|
260
283
|
return `${ plain }()`;
|
|
261
284
|
}
|
|
262
285
|
else {
|
|
@@ -264,6 +287,23 @@ export default class TestDef {
|
|
|
264
287
|
}
|
|
265
288
|
}
|
|
266
289
|
|
|
290
|
+
get anyUnsoughtThrow() /* passed */ {
|
|
291
|
+
// Prop is true when throw is sought.
|
|
292
|
+
if (this.isThrowTest) {
|
|
293
|
+
return;
|
|
294
|
+
}
|
|
295
|
+
|
|
296
|
+
return this.thrown;
|
|
297
|
+
}
|
|
298
|
+
|
|
299
|
+
get doesHaveUnsoughtThrow() /* passed */ {
|
|
300
|
+
return this.anyUnsoughtThrow !== undefined;
|
|
301
|
+
}
|
|
302
|
+
|
|
303
|
+
get doesHaveTrouble() /* passed */ {
|
|
304
|
+
return this.trouble !== undefined;
|
|
305
|
+
}
|
|
306
|
+
|
|
267
307
|
// endregion State properties
|
|
268
308
|
|
|
269
309
|
// region State methods
|
|
@@ -282,8 +322,7 @@ export default class TestDef {
|
|
|
282
322
|
|
|
283
323
|
// region Initing, including constructor()
|
|
284
324
|
|
|
285
|
-
/*
|
|
286
|
-
when not .-prefixed, they are purely keywords. */
|
|
325
|
+
/* Long names used, since some short names, like `for`, are parsed as keywords. */
|
|
287
326
|
constructor(nature, type, spoofed, initors, method, inputs, output, source, factors, enact, counteract) /* ok */ {
|
|
288
327
|
this.nature = nature; // .for
|
|
289
328
|
this.type = type; // .on
|
|
@@ -305,6 +344,11 @@ export default class TestDef {
|
|
|
305
344
|
|
|
306
345
|
// Looping over all.
|
|
307
346
|
for (let nonce of nonces) {
|
|
347
|
+
// No possible test definition to output.
|
|
348
|
+
if (!TestDef.isANonce(nonce)) {
|
|
349
|
+
continue;
|
|
350
|
+
}
|
|
351
|
+
|
|
308
352
|
// Get latest test definition.
|
|
309
353
|
let latest = TestDef.fromNonceTuple(nonce);
|
|
310
354
|
|
|
@@ -359,6 +403,11 @@ export default class TestDef {
|
|
|
359
403
|
|
|
360
404
|
// region Dependencies of nonce-tuple initing methods
|
|
361
405
|
|
|
406
|
+
static isANonce(topic) /* passed */ {
|
|
407
|
+
let type = TypeIdentifier.identify(topic);
|
|
408
|
+
return type === Types.isObject;
|
|
409
|
+
}
|
|
410
|
+
|
|
362
411
|
/* Replaces some or all of the 'full' that gathers test
|
|
363
412
|
props for reuse when targeting changes significantly
|
|
364
413
|
in the middle of the collapsing-forward process. */
|
|
@@ -417,4 +466,22 @@ export default class TestDef {
|
|
|
417
466
|
|
|
418
467
|
// endregion Initing, including constructor()
|
|
419
468
|
|
|
469
|
+
toString() /* verified */ {
|
|
470
|
+
let displayer = new TotalDisplayer();
|
|
471
|
+
|
|
472
|
+
let text = `TestDef{ for:${ displayer.display(this.for) }, `
|
|
473
|
+
+ `on:${ displayer.display(this.on) }, `
|
|
474
|
+
+ `with:${ displayer.display(this.with) }, `
|
|
475
|
+
+ `of:${ displayer.display(this.of) }, `
|
|
476
|
+
+ `plus:${ displayer.display(this.plus) }, `
|
|
477
|
+
+ `in:${ displayer.display(this.in) }, `
|
|
478
|
+
+ `out:${ displayer.display(this.out) }, `
|
|
479
|
+
+ `from:${ displayer.display(this.from) }, `
|
|
480
|
+
+ `and:${ displayer.display(this.and) }, `
|
|
481
|
+
+ `do:${ displayer.display(this.do) }, `
|
|
482
|
+
+ `undo:${ displayer.display(this.undo) } }`
|
|
483
|
+
|
|
484
|
+
return text;
|
|
485
|
+
}
|
|
486
|
+
|
|
420
487
|
}
|
package/system/TestFinder.js
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
/**/
|
|
2
2
|
|
|
3
|
-
/* TestFinder
|
|
3
|
+
/* TestFinder retrieves test sources based on .risei.tests in package.json. */
|
|
4
4
|
|
|
5
|
-
import ATestFinder from "./ATestFinder.js";
|
|
6
5
|
import ATestSource from "./ATestSource.js";
|
|
6
|
+
import Choices from "./Choices.js";
|
|
7
7
|
import fs from "node:fs";
|
|
8
8
|
import path from "node:path";
|
|
9
9
|
import { minimatch } from "minimatch";
|
|
10
10
|
|
|
11
|
-
export default class TestFinder
|
|
11
|
+
export default class TestFinder {
|
|
12
12
|
// region Definitions
|
|
13
13
|
|
|
14
14
|
static NO_SUCH_FILE = "ENOENT";
|
|
@@ -21,20 +21,37 @@ export default class TestFinder extends ATestFinder {
|
|
|
21
21
|
// endregion Definitions
|
|
22
22
|
|
|
23
23
|
// region Fields
|
|
24
|
-
|
|
24
|
+
|
|
25
|
+
#testSources;
|
|
26
|
+
#thrown = [];
|
|
27
|
+
|
|
25
28
|
#sought;
|
|
26
29
|
|
|
27
30
|
// endregion Fields
|
|
28
31
|
|
|
32
|
+
// region Properties
|
|
33
|
+
|
|
34
|
+
get testSources() {
|
|
35
|
+
return this.#testSources;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
set testSources(value) {
|
|
39
|
+
this.#testSources = value;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
get thrown() {
|
|
43
|
+
return this.#thrown;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
// endregion Properties
|
|
47
|
+
|
|
29
48
|
constructor() {
|
|
30
|
-
|
|
49
|
+
this.#testSources = [];
|
|
31
50
|
}
|
|
32
51
|
|
|
33
52
|
async findAllTests() {
|
|
34
|
-
|
|
35
|
-
let
|
|
36
|
-
this.#sought = source.tests;
|
|
37
|
-
let testPaths = this.pathsFromTargetingSource();
|
|
53
|
+
this.#sought = this.supplyTestTargeting();
|
|
54
|
+
let testPaths = this.pathsFromTargeting();
|
|
38
55
|
|
|
39
56
|
testPaths = this.sortTestPaths(testPaths);
|
|
40
57
|
|
|
@@ -54,28 +71,13 @@ export default class TestFinder extends ATestFinder {
|
|
|
54
71
|
return tests;
|
|
55
72
|
}
|
|
56
73
|
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
// Contents of package.json are just a single JSON object.
|
|
63
|
-
let packageJson = fs.readFileSync(pathAndName, { encoding: "utf8" });
|
|
64
|
-
packageJson = JSON.parse(packageJson);
|
|
65
|
-
|
|
66
|
-
// Can't run or reasonably recover if this is not defined.
|
|
67
|
-
if (!packageJson.risei) {
|
|
68
|
-
throw new Error(
|
|
69
|
-
`For Risei tests to run, this app's package.json must contain `
|
|
70
|
-
+ `a node like this: "risei": { tests: "path-or-glob-here" }. `
|
|
71
|
-
+ `One glob or path may be used, or an array of them.`);
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
// Only Risei's own metadata is needed.
|
|
75
|
-
return packageJson.risei;
|
|
74
|
+
// Spoofing point for self-testing.
|
|
75
|
+
supplyTestTargeting() {
|
|
76
|
+
// Value retrieved from package.json.
|
|
77
|
+
return Choices.testTargeting;
|
|
76
78
|
}
|
|
77
79
|
|
|
78
|
-
|
|
80
|
+
pathsFromTargeting() {
|
|
79
81
|
let paths = [];
|
|
80
82
|
let root = process.cwd();
|
|
81
83
|
|