risei 1.3.4 → 2.0.0

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 (69) hide show
  1. package/README.md +142 -379
  2. package/Read-me reduced.md +294 -0
  3. package/Read-me redux.md +581 -0
  4. package/index.js +5 -5
  5. package/package.json +10 -11
  6. package/system/ASpoofingFixture.js +7 -8
  7. package/system/ATestCaller.js +3 -3
  8. package/system/ATestFinder.js +2 -2
  9. package/system/ATestReporter.js +2 -1
  10. package/system/ATestSource.js +5 -1
  11. package/system/ChosenTestFinder.js +4 -4
  12. package/system/ClassTestGroup.js +2 -2
  13. package/system/LocalCaller.js +5 -5
  14. package/system/{ClassMethodSpoofer.js → MethodSpoofer.js} +54 -48
  15. package/system/MethodTestGroup.js +2 -2
  16. package/system/Moment.js +1 -1
  17. package/system/NameAnalyzer.js +26 -0
  18. package/system/PropertySpoofer.js +156 -0
  19. package/system/Risei.js +5 -5
  20. package/system/SpoofDef.js +260 -0
  21. package/system/TerminalReporter.js +8 -8
  22. package/system/{TestDefinition.js → TestDef.js} +153 -107
  23. package/system/TestFinder.js +3 -3
  24. package/system/TestFrame.js +15 -52
  25. package/system/TestGroup.js +1 -1
  26. package/system/TestResult.js +2 -2
  27. package/system/TestRunner.js +23 -107
  28. package/system/TestStages.js +80 -76
  29. package/system/TestSummary.js +1 -1
  30. package/system/TotalComparer.js +60 -11
  31. package/system/TotalDisplayer.js +33 -12
  32. package/system/TypeAnalyzer.js +41 -79
  33. package/system/TypeIdentifier.js +18 -8
  34. package/system/Types.js +3 -1
  35. package/test-target-objects/ConditionalThrowTarget.js +11 -0
  36. package/test-target-objects/Counter.js +46 -0
  37. package/test-target-objects/DomTarget.js +37 -0
  38. package/test-target-objects/InterSpoofer.js +230 -0
  39. package/test-target-objects/MixedContents.js +33 -0
  40. package/test-target-objects/MutationTarget.js +37 -0
  41. package/test-target-objects/ObjectComposer.js +34 -0
  42. package/test-target-objects/PolySpoofableInner.js +29 -0
  43. package/test-target-objects/PolySpoofableOuter.js +52 -0
  44. package/test-target-objects/PropertiesTarget.js +98 -0
  45. package/test-target-objects/Returner.js +7 -0
  46. package/test-target-objects/Searcher.js +25 -0
  47. package/test-target-objects/Sorter.js +91 -0
  48. package/test-target-objects/Spoofable.js +36 -0
  49. package/test-target-objects/StateTarget.js +34 -0
  50. package/test-target-objects/StaticTarget.js +17 -0
  51. package/test-target-objects/TestableTarget.js +57 -0
  52. package/trial-tests/SelfTests.outward-rt.js +511 -0
  53. package/trial-tests/TopicTests.outward-rt.js +313 -0
  54. package/usage-examples/Gold-bar-example.png +0 -0
  55. package/usage-examples/Title-example.png +0 -0
  56. package/xternal-tests/ASpoofingFixture.tests.js +242 -0
  57. package/xternal-tests/MethodSpoofer.tests.js +130 -0
  58. package/xternal-tests/SpoofDef.tests.js +91 -0
  59. package/xternal-tests/TotalComparer.tests.js +1055 -0
  60. package/xternal-tests/package.json +7 -0
  61. package/system/AComparer.js +0 -9
  62. package/system/ATestFixture.js +0 -44
  63. package/system/ClassPropertySpoofer.js +0 -185
  64. package/system/ObjectMethodSpoofer.js +0 -58
  65. package/system/ObjectPropertySpoofer.js +0 -136
  66. package/system/SpoofDefinition.js +0 -243
  67. package/system/TestFrameChooser.js +0 -54
  68. package/system/TestFrames.js +0 -232
  69. package/system/TotalCopier.js +0 -106
@@ -1,23 +1,20 @@
1
1
  /**/
2
2
 
3
- import { TypeAnalyzer } from "./TypeAnalyzer.js";
4
- import { TypeIdentifier } from "./TypeIdentifier.js";
5
- import { Types } from "./Types.js";
6
- import { TotalCopier } from "./TotalCopier.js";
3
+ import TypeAnalyzer from "./TypeAnalyzer.js";
4
+ import NameAnalyzer from "./NameAnalyzer.js";
5
+ import TypeIdentifier from "./TypeIdentifier.js";
6
+ import Types from "./Types.js";
7
7
 
8
- /* Defines what is found in a test-definition tuple (TDT). Actual TDTs don't need to be instances of this class. */
8
+ /* Defines what is found in a test definition, typically as
9
+ a nonce object rather than an instance of this class. */
9
10
 
10
- export class TestDefinition {
11
+ export default class TestDef {
11
12
  // region Definitions
12
13
 
13
14
  static staticName = "static";
14
15
  static throwName = "throw";
15
16
  static constructorName = "constructor";
16
- static nonceLocalCallableName = "localCallable";
17
- static dotOperator = ".";
18
- static colonOperator = ":";
19
- static parensOperator = "()";
20
- static operatorsRegExp = /\.|:|\(\)/g;
17
+ static nonceLocalCallableName = "nonce";
21
18
 
22
19
  // endregion Definitions
23
20
 
@@ -29,17 +26,14 @@ export class TestDefinition {
29
26
  [ "with", "initors" ],
30
27
  [ "of", "method" ],
31
28
  [ "plus", "spoofed" ],
32
- [ "amid", "settables" ],
33
29
  [ "in", "inputs" ],
34
30
  [ "out", "output" ],
35
31
  [ "from", "source" ],
36
- [ "and", "factors" ]
32
+ [ "and", "factors" ],
33
+ [ "do", "enact" ],
34
+ [ "undo", "counteract" ]
37
35
  ]);
38
36
 
39
- static #copier = new TotalCopier();
40
-
41
- static #identifier = new TypeIdentifier();
42
-
43
37
  // endregion Static fields
44
38
 
45
39
  // region Fields
@@ -52,14 +46,14 @@ export class TestDefinition {
52
46
  initors;
53
47
  method;
54
48
  spoofed;
55
- settables;
56
49
  inputs;
57
50
  output;
58
51
  source;
59
52
  factors;
53
+ enact;
54
+ counteract;
60
55
 
61
56
  target;
62
- localCallable;
63
57
 
64
58
  actual;
65
59
  thrown;
@@ -112,15 +106,6 @@ export class TestDefinition {
112
106
  this.spoofed = value;
113
107
  }
114
108
 
115
- /* &cruft, drop or rename this .amid property pair */
116
- get amid() {
117
- return this.settables;
118
- }
119
-
120
- set amid(value) {
121
- this.settables = value;
122
- }
123
-
124
109
  get in() {
125
110
  return this.inputs;
126
111
  }
@@ -153,11 +138,27 @@ export class TestDefinition {
153
138
  this.factors = value;
154
139
  }
155
140
 
141
+ get do() {
142
+ return this.enact;
143
+ }
144
+
145
+ set do(value) {
146
+ this.enact = value;
147
+ }
148
+
149
+ get undo() {
150
+ return this.counteract;
151
+ }
152
+
153
+ set undo(value) {
154
+ this.counteract = value;
155
+ }
156
+
156
157
  // endregion Test definition, short names
157
158
 
158
- // region Tuple state and dependencies
159
+ // region Def state
159
160
 
160
- get isRunnable() {
161
+ get isRunnable() /* passed */ {
161
162
  let isRunnable
162
163
  = this.nature !== undefined
163
164
  && this.type !== undefined
@@ -174,32 +175,22 @@ export class TestDefinition {
174
175
  }
175
176
 
176
177
  get isStaticTest() /* passed */ {
177
- let plainName = TestDefinition.plainNameOf(this.of);
178
+ let plainName = NameAnalyzer.plainNameOf(this.of);
178
179
 
179
- let is = TypeAnalyzer.memberIsStatic(this.on, plainName);
180
- let stated = this.andStringContains(TestDefinition.staticName);
180
+ let is = TypeAnalyzer.isStaticMember(this.on, plainName);
181
+ let stated = this.andStringContains(TestDef.staticName);
181
182
 
182
183
  return is || stated;
183
184
  }
184
185
 
185
186
  get isThrowTest() /* passed */ {
186
- let is = this.andStringContains(TestDefinition.throwName);
187
+ let is = this.andStringContains(TestDef.throwName);
187
188
  return is;
188
189
  }
189
190
 
190
- /* Needed externally, and dependency
191
- of all .and-based properties. */
192
- andStringContains(keyword) /* passed */ {
193
- let doesContain
194
- = typeof this.and === "string"
195
- && this.and.includes(keyword);
196
-
197
- return doesContain;
198
- }
199
-
200
191
  get isConstructorTest() /* passed */ {
201
- let plainTarget = TestDefinition.plainNameOf(this.of);
202
- return plainTarget === TestDefinition.constructorName;
192
+ let plainTarget = NameAnalyzer.plainNameOf(this.of);
193
+ return plainTarget === TestDef.constructorName;
203
194
  }
204
195
 
205
196
  get isMethodTest() /* passed */ {
@@ -207,12 +198,11 @@ export class TestDefinition {
207
198
  }
208
199
 
209
200
  get isPropertyTest() /* passed */ {
210
- let plainName = TestDefinition.plainNameOf(this.of);
201
+ let plainName = NameAnalyzer.plainNameOf(this.of);
211
202
 
212
203
  let isPropertyTest
213
- = this.of.startsWith(TestDefinition.dotOperator)
214
- || this.of.endsWith(TestDefinition.colonOperator)
215
- || TypeAnalyzer.memberIsProperty(this.on, plainName);
204
+ = NameAnalyzer.hasPropertySigil(this.of)
205
+ || TypeAnalyzer.isPropertyMember(this.on, plainName);
216
206
 
217
207
  return isPropertyTest;
218
208
  }
@@ -237,121 +227,185 @@ export class TestDefinition {
237
227
  return false;
238
228
  }
239
229
 
240
- // endregion Tuple state and dependencies
230
+ get doesHaveDoEarly() /* passed */ {
231
+ if (this.do === undefined) {
232
+ return false;
233
+ }
241
234
 
242
- // endregion Properties
235
+ return TypeIdentifier.identify(this.do.early) === Types.isFunction;
236
+ }
237
+
238
+ get doesHaveDoLate() /* passed */ {
239
+ if (this.do === undefined) {
240
+ return false;
241
+ }
242
+
243
+ return TypeIdentifier.identify(this.do.late) === Types.isFunction;
244
+ }
245
+
246
+ get doesHaveUndo() /* passed */ {
247
+ return TypeIdentifier.identify(this.undo) === Types.isFunction;
248
+ }
243
249
 
244
- // region Initing, including constructor()
250
+ /* Used for grouping in output by method or
251
+ prop name, with type sigil only once. */
252
+ get runName() /* passed */ {
253
+ let plain = NameAnalyzer.plainNameOf(this.of);
245
254
 
246
- /* Constructor can't use param names like `for`, because when not .-prefixed, they are keywords. */
255
+ if (this.isMethodTest) {
256
+ return `${ plain }()`;
257
+ }
247
258
 
248
- constructor(nature, type, spoofed, initors, settables, method, inputs, output, source, factors) {
249
- this.nature = nature; // .for
250
- this.type = type; // .on
251
- this.spoofed = spoofed; // .plus
252
- this.initors = initors; // .with
253
- this.settables = settables; // .amid
254
- this.method = method; // .of
255
- this.inputs = inputs; // .in
256
- this.output = output; // .out
257
- this.source = source; // .from
258
- this.factors = factors; // .and
259
+ if (this.isPropertyTest) {
260
+ return `.${ plain }`;
261
+ }
259
262
  }
260
263
 
261
- copy() {
262
- // Empty initial copy.
263
- let copy = new TestDefinition();
264
+ // endregion Def state
264
265
 
265
- let names = TestDefinition.longsByShort.values();
266
+ // endregion Properties
266
267
 
267
- for (let name of names) {
268
- copy[name] = TestDefinition.#copier.copy(this[name]);
269
- }
270
-
271
- return copy;
268
+ // region Def state methods
269
+
270
+ /* Needed externally, and dependency
271
+ of all .and-based properties. */
272
+ andStringContains(keyword) /* passed */ {
273
+ let doesContain
274
+ = typeof this.and === "string"
275
+ && this.and.includes(keyword);
276
+
277
+ return doesContain;
272
278
  }
273
279
 
274
- static fromNonceTuples(nonces) {
280
+ // endregion Def state methods
281
+
282
+ // region Initing, including constructor()
283
+
284
+ /* Constructor can't use parameter names like `for`:
285
+ when not .-prefixed, they are purely keywords. */
286
+ constructor(nature, type, spoofed, initors, method, inputs, output, source, factors, enact, counteract) /* ok */ {
287
+ this.nature = nature; // .for
288
+ this.type = type; // .on
289
+ this.spoofed = spoofed; // .plus
290
+ this.initors = initors; // .with
291
+ this.method = method; // .of
292
+ this.inputs = inputs; // .in
293
+ this.output = output; // .out
294
+ this.source = source; // .from
295
+ this.factors = factors; // .and
296
+ this.enact = enact; // .do
297
+ this.counteract = counteract; // .undo
298
+ }
299
+
300
+ static fromNonceTuples(nonces) /* passed */ {
275
301
  // Throughput and output.
276
- let full = new TestDefinition();
277
- let tuples = [];
302
+ let full = new TestDef();
303
+ let defs = [];
278
304
 
279
305
  // Looping over all.
280
306
  for (let nonce of nonces) {
281
307
  // Get latest test definition.
282
- let latest = TestDefinition.fromNonceTuple(nonce);
308
+ let latest = TestDef.fromNonceTuple(nonce);
283
309
 
284
310
  // Restarting test definitions when desired.
285
- full = TestDefinition.maybeRestartFull(full, latest);
311
+ full = TestDef.maybeRestartFull(full, latest);
286
312
 
287
313
  // Merge any previous
288
314
  // values into latest.
289
- latest.combineWith(full);
315
+ TestDef.combine(latest, full);
290
316
 
291
317
  // Make latest the tuple for
292
318
  // combining with next time.
293
319
  full = latest;
294
320
 
321
+ // Changes to the current def, rather than
322
+ // a new one, should not result in a new def.
323
+ if (TestDef.isChangeOnlyNonce(nonce)) {
324
+ continue;
325
+ }
326
+
295
327
  // Add latest, if it's ready to run as a test.
296
328
  if (latest.isRunnable) {
297
- tuples.push(latest);
329
+ defs.push(latest);
298
330
  }
299
331
  }
300
332
 
301
333
  // Back to caller.
302
- return tuples;
334
+ return defs;
303
335
  }
304
336
 
305
- static fromNonceTuple(nonce) {
337
+ /* Transfers properties in 'nonce' to a new TestDef
338
+ if they match by either (first) short or long name.
339
+ Unmatched props remain undefined on the TestDef. */
340
+ static fromNonceTuple(nonce) /* passed */ {
306
341
  // Empty, since properties can be set
307
342
  // by either of two nonce naming styles.
308
- let tuple = new TestDefinition();
343
+ let def = new TestDef();
309
344
 
310
- let shortNames = TestDefinition.longsByShort.keys();
345
+ let shortNames = TestDef.longsByShort.keys();
311
346
 
312
347
  // Traversing matching pairs of names and applying
313
348
  // whichever one is present as the tuple property;
314
349
  // if neither is present, the property is undefined.
315
350
  for (let shortName of shortNames) {
316
- let longName = TestDefinition.longsByShort.get(shortName);
317
- tuple[shortName] = shortName in nonce ? nonce[shortName] : nonce[longName];
351
+ let longName = TestDef.longsByShort.get(shortName);
352
+ def[shortName] = shortName in nonce ? nonce[shortName] : nonce[longName];
318
353
  }
319
354
 
320
355
  // Back to caller.
321
- return tuple;
356
+ return def;
322
357
  }
323
358
 
324
359
  // region Dependencies of nonce-tuple initing methods
325
360
 
326
- static maybeRestartFull(full, latest) {
361
+ /* Replaces some or all of the 'full' that gathers test
362
+ props for reuse when targeting changes significantly
363
+ in the middle of the collapsing-forward process. */
364
+ static maybeRestartFull(full, latest) /* passed */ {
327
365
  // When a (new) model class is named,
328
366
  // wipe out all reused test values.
329
367
  if (latest.type !== undefined) {
330
- full = new TestDefinition();
368
+ full = new TestDef();
331
369
  }
332
370
 
333
371
  // When a (new) model method is named, wipe out reused
334
- // test values except the general ones for its class.
372
+ // test values except the general ones for its class
373
+ // and .nature, needed for collapsing forward.
335
374
  if (latest.method !== undefined) {
336
- full = new TestDefinition(
337
- full.nature, full.type,
338
- full.spoofed, full.initors
339
- );
375
+ full = TestDef.classOnlyDefFrom(full);
340
376
  }
341
377
 
342
378
  return full;
343
379
  }
344
380
 
345
- combineWith(other) {
346
- let shortNames = TestDefinition.longsByShort.keys();
381
+ static classOnlyDefFrom(original) /* passed */ {
382
+ let output = new TestDef();
383
+
384
+ output.type = original.type;
385
+ output.initors = original.initors;
386
+ output.spoofed = original.spoofed;
387
+
388
+ return output;
389
+ }
390
+
391
+ /* Replaces properties of the 'self'
392
+ TestDef with any from 'other'. */
393
+ static combine(self, other) /* passed */ {
394
+ let shortNames = TestDef.longsByShort.keys();
347
395
 
348
396
  // Collapse properties forward.
349
397
  for (let shortName of shortNames) {
350
- TestDefinition.combineValues(this, other, shortName);
398
+ TestDef.combineValues(self, other, shortName);
351
399
  }
352
400
  }
353
401
 
354
- static combineValues(self, other, name) {
402
+ static isChangeOnlyNonce(nonce) /* passed */ {
403
+ return nonce.just !== undefined || nonce.only !== undefined;
404
+ }
405
+
406
+ /* Replaces the named property of 'self', if
407
+ missing, with any new property of 'other'. */
408
+ static combineValues(self, other, name) /* passed */ {
355
409
  // Property may still end up undefined.
356
410
  if (self[name] === undefined) {
357
411
  self[name] = other[name];
@@ -362,12 +416,4 @@ export class TestDefinition {
362
416
 
363
417
  // endregion Initing, including constructor()
364
418
 
365
- // region Other statics
366
-
367
- static plainNameOf(name) /* passed */ {
368
- let plain = name.replaceAll(TestDefinition.operatorsRegExp, "");
369
- return plain;
370
- }
371
-
372
- // endregion Other statics
373
419
  }
@@ -2,13 +2,13 @@
2
2
 
3
3
  /* TestFinder is an ATestFinder that finds tests in the places identified in package.json. */
4
4
 
5
- import { ATestFinder } from "./ATestFinder.js";
6
- import { ATestSource } from "./ATestSource.js";
5
+ import ATestFinder from "./ATestFinder.js";
6
+ import ATestSource from "./ATestSource.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 class TestFinder extends ATestFinder {
11
+ export default class TestFinder extends ATestFinder {
12
12
  // region Definitions
13
13
 
14
14
  static NO_SUCH_FILE = "ENOENT";
@@ -1,95 +1,58 @@
1
1
  /**/
2
2
 
3
- import { TestStages } from "./TestStages.js";
3
+ import TestStages from "./TestStages.js";
4
4
 
5
- export class TestFrame {
6
- /* &cruft, when TestStages is ready, use it and its methods here */
7
-
5
+ export default class TestFrame {
8
6
  #stages;
9
7
 
10
- constructor() {
8
+ constructor() /* ok */ {
11
9
  // A TestStages is inited for each test.
12
10
  this.#stages = new TestStages();
13
11
  }
14
12
 
15
- testFrame(test) {
16
- /* &cruft, removing logging after it's no longer needed */
17
- // console.log(`cruft : a`);
18
-
13
+ run(test) /* passed */ {
19
14
  // Outer try for fails of groundwork requested.
20
15
  try {
21
- // console.log(`cruft : b`);
22
-
23
- // Spoofing, setting static properties, and so on.
16
+ // Spoofing and so on.
24
17
  this.#stages.anyPreTargetingGroundwork(test);
25
18
 
26
- // console.log(`cruft : c`);
27
-
28
19
  // Target may be instance, prototype for constructors, the class
29
20
  // itself for statics, or nonce for properties. Sets test.target.
30
21
  this.#stages.setTarget(test);
31
22
 
32
- // console.log(`cruft : d`);
33
-
23
+ let target = this.#stages.supplyLocalTarget(test);
24
+
34
25
  // Method under test may be on instance, class,
35
26
  // or nonce for properties. Sets test.callable.
36
- this.#stages.setLocalCallable(test);
27
+ let callable = this.#stages.supplyCallableName(test);
37
28
 
38
- // console.log(`cruft : e`);
39
-
40
- // Setting instance properties and so on.
29
+ // Setting (spoofing) properties and so on.
41
30
  this.#stages.anyPostTargetingGroundwork(test);
42
31
 
43
- // console.log(`cruft : f`);
44
-
45
32
  // Inner try for fails of targeted code only.
46
33
  try {
47
- // console.log(`cruft : g`);
48
-
49
- // console.log(`cruft : test.actual:`, test.actual);
50
- // console.log(`cruft : test.target:`, test.target);
51
- // console.log(`cruft : test.localCallable:`, test.localCallable);
52
- // console.log(`cruft : test.in:`, test.in);
53
-
54
34
  // Tests usually look for this.
55
- test.actual = test.target[test.localCallable](...test.in);
56
-
57
- // console.log(`cruft : test.actual:`, test.actual);
58
- // console.log(`cruft : h`);
35
+ test.actual = target[callable](...test.in);
59
36
  }
60
37
  catch (thrown) {
61
- // console.log(`cruft : i`);
62
-
63
38
  // Sometimes tests look for this.
64
39
  test.thrown = thrown;
65
-
66
- // console.log(`cruft : j`);
67
40
  }
68
41
 
69
- // console.log(`cruft : k`);
70
-
71
42
  // Sometimes tests look for results elsewhere.
72
43
  this.#stages.anyModifyActual(test);
73
44
 
74
- // console.log(`cruft : l`);
75
-
76
45
  // Actually testing the result.
77
46
  test.didPass = this.#stages.compareResults(test.output, test.actual);
78
-
79
- /* &cruft, remove this test-checking line when all tests pass */
80
- // test.didPass = !test.didPass;
81
-
82
- // console.log(`cruft : m`);
47
+ }
48
+ catch (thrown) {
49
+ /* Block needed, but no operations. */
83
50
  }
84
51
  finally {
85
- // console.log(`cruft : n`);
86
-
87
52
  // Undoing any groundwork changes made.
88
- this.#stages.anyGroundworkReversion(test);
89
-
90
- // console.log(`cruft : o`);
53
+ this.#stages.anyGroundworkReversal(test);
91
54
  }
92
55
 
93
- // console.log(`cruft : p`);
56
+ // console.log(`cruft : q, outer try-catch : after`);
94
57
  }
95
58
  }
@@ -1,6 +1,6 @@
1
1
  /**/
2
2
 
3
- export class TestGroup {
3
+ export default class TestGroup {
4
4
  // region Private fields
5
5
 
6
6
  #group;
@@ -1,8 +1,8 @@
1
1
  /**/
2
2
 
3
- import { TotalDisplayer } from "./TotalDisplayer.js";
3
+ import TotalDisplayer from "./TotalDisplayer.js";
4
4
 
5
- export class TestResult {
5
+ export default class TestResult {
6
6
  // region Components
7
7
 
8
8
  #displayer;