risei 1.0.3 → 1.1.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.
@@ -0,0 +1,180 @@
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
+ /* Exercising the code. */
31
+ test.actual = target[test.of](...test.in); // Must use `...`.
32
+
33
+ /* Comparing. */
34
+ test.didPass = this.#compare(test.out, test.actual);
35
+ }
36
+
37
+ testReturnValueOfStaticCall(test) {
38
+ /* Groundwork. */
39
+ /* No instance is constructed. */
40
+
41
+ /* Exercising the code. */
42
+ test.actual = test.on[test.of](...test.in); // Must use `...`.
43
+
44
+ /* Comparing. */
45
+ test.didPass = this.#compare(test.out, test.actual);
46
+ }
47
+
48
+ // The second-most basic test: whether a property
49
+ // has the expected value after a method call.
50
+ testCodeElementAfterCall(test) {
51
+ /* Groundwork. */
52
+ let prototype = test.on.prototype;
53
+ let target = new prototype.constructor(...test.with); // Must use `...`.
54
+
55
+ /* Exercising the code. */
56
+ target[test.of](...test.in); // Must use `...`.
57
+
58
+ /* Retrieving. */
59
+ // The `actual` is a property or other code element somewhere.
60
+ test.actual = this.#supplyNonReturnActual(test, target);
61
+
62
+ /* Comparing. */
63
+ test.didPass = this.#compare(test.out, test.actual);
64
+ }
65
+
66
+ testCodeElementAfterStaticCall(test) {
67
+ /* Groundwork. */
68
+ /* No instance is constructed. */
69
+
70
+ /* Exercising the code. */
71
+ test.on[test.of](...test.in); // Must use `...`.
72
+
73
+ /* Retrieving. */
74
+ test.actual = this.#supplyNonReturnActual(test); // No `target` here.
75
+
76
+ /* Comparing. */
77
+ test.didPass = this.#compare(test.out, test.actual);
78
+ }
79
+
80
+ // The third-most basic test: whether a property has
81
+ // the expected value after an object is constructed.
82
+ testCodeElementAfterConstruction(test) {
83
+ /* Groundwork. */
84
+ // For definition consistency, initing with test.in, not test.with.
85
+ let prototype = test.on.prototype;
86
+
87
+ /* Exercising the code. */
88
+ let target = new prototype.constructor(...test.in); // Must use `...`.
89
+
90
+ /* Retrieving. */
91
+ // The `actual` is a property or other code element somewhere.
92
+ test.actual = this.#supplyNonReturnActual(test, target);
93
+
94
+ /* Comparing. */
95
+ test.didPass = this.#compare(test.out, test.actual);
96
+ }
97
+
98
+ testThrowResultAfterCall(test) {
99
+ /* Groundwork. */
100
+ let prototype = test.on.prototype;
101
+ let target = new prototype.constructor(...test.with); // Must use `...`.
102
+
103
+ /* Exercising the code. */
104
+ try {
105
+ target[test.of](...test.in); // Must use `...`.
106
+ }
107
+ /* Retrieving. */
108
+ catch (thrown) {
109
+ test.actual = thrown.message;
110
+ }
111
+
112
+ /* Comparing. */
113
+ test.didPass = this.#compare(test.out, test.actual);
114
+ }
115
+
116
+ testThrowResultAfterStaticCall(test) {
117
+ /* Groundwork. */
118
+ /* No instance is constructed. */
119
+
120
+ /* Exercising the code. */
121
+ try {
122
+ test.on[test.of](...test.in) // Must use `...`.
123
+ }
124
+ catch (thrown) {
125
+ test.actual = thrown.message;
126
+ }
127
+
128
+ /* Comparing. */
129
+ test.didPass = this.#compare(test.out, test.actual);
130
+ }
131
+
132
+ // region Dependencies of test frames
133
+
134
+ #compare(expected, actual) {
135
+ return this.#comparer.compare(expected, actual);
136
+ }
137
+
138
+ #supplyNonReturnActual(test, target) {
139
+ // When there is a .from that's a string,
140
+ // the actual is the named target member.
141
+ if (typeof test.from === "string") {
142
+ // Common member host;
143
+ // undefined if static.
144
+ let host = target;
145
+
146
+ // When .and defines static.
147
+ if (this.#doesAddressStatics(test)) {
148
+ host = test.on;
149
+ }
150
+
151
+ return host[test.from];
152
+ }
153
+
154
+ // When there is a .from that's a function,
155
+ // the actual is the result of calling it,
156
+ // given everything that might be needed.
157
+ if (test.from instanceof Function) {
158
+ return test.from(target, test);
159
+ }
160
+
161
+ // When there is any other .from, the actual is the
162
+ // value of the code element provided as .from.
163
+ return test.from;
164
+ }
165
+
166
+ /* &cruft : refactor to merge with same on TestFrameChooser */
167
+ #doesAddressStatics(test) {
168
+ if (typeof test.and === "string") {
169
+ if (test.and.includes(this.staticName)) {
170
+ return true;
171
+ }
172
+ }
173
+
174
+ return false;
175
+ }
176
+
177
+ // endregion Dependencies of test frames
178
+
179
+
180
+ }
@@ -9,13 +9,13 @@ import { MethodTestGroup } from "./MethodTestGroup.js";
9
9
  import { TestResult } from "./TestResult.js";
10
10
  import { TestSummary } from "./TestSummary.js";
11
11
 
12
+ import { TestFrameChooser } from "./TestFrameChooser.js";
13
+ import { TestFrames } from "./TestFrames.js";
14
+
12
15
  import { SpoofClassMethodsFixture } from "./SpoofClassMethodsFixture.js";
13
16
  import { SpoofObjectMethodsFixture } from "./SpoofObjectMethodsFixture.js";
14
17
  import { SpoofTuple } from "./SpoofTuple.js";
15
18
 
16
- import { AComparer } from "./AComparer.js";
17
- import { TotalComparer } from "./TotalComparer.js";
18
-
19
19
  export class TestRunner {
20
20
  // region Static definition fields
21
21
 
@@ -33,6 +33,9 @@ export class TestRunner {
33
33
  #classSpoofer;
34
34
  #instanceSpoofer;
35
35
 
36
+ #frameSource;
37
+ #frameChooser;
38
+
36
39
  #comparer;
37
40
 
38
41
  // Results summary.
@@ -73,14 +76,6 @@ export class TestRunner {
73
76
 
74
77
  // endregion Spoofing
75
78
 
76
- get comparer() {
77
- return this.#comparer;
78
- }
79
-
80
- set comparer(value) {
81
- this.#comparer = value;
82
- }
83
-
84
79
  get numberRun() {
85
80
  return this.#numberRun;
86
81
  }
@@ -119,15 +114,15 @@ export class TestRunner {
119
114
  this.#tests = [];
120
115
  this.#classSpoofer = new SpoofClassMethodsFixture();
121
116
  this.#instanceSpoofer = new SpoofObjectMethodsFixture();
117
+
118
+ this.#frameSource = new TestFrames();
119
+ this.#frameChooser = new TestFrameChooser(this.#frameSource);
122
120
 
123
121
  this.#numberRun = 0;
124
122
  this.#numberPassed = 0;
125
123
  this.#numberFailed = 0;
126
124
 
127
125
  this.#allDidPass = true;
128
-
129
- // Comparer is inited once for all tests, since compare() is reentrant.
130
- this.#comparer = new TotalComparer();
131
126
  }
132
127
 
133
128
  // region Tests to run
@@ -188,16 +183,20 @@ export class TestRunner {
188
183
 
189
184
  // Spoofing based on any spoof
190
185
  // definitions in .with and .of.
191
- this.#spoofObjects(test);
186
+ this.#anyObjectSpoofing(test);
192
187
 
193
188
  // Gathering facts defining the nature of the test,
194
189
  // some of which might change after the test is run.
195
190
  let result = new TestResult(test);
196
191
  result.setNature();
197
192
 
198
- // Choosing the right test frame for the definition.
199
- let testFrame = this.#supplyTestFrame(test);
200
- testFrame = testFrame.bind(this);
193
+ // Aspects of the test determine the right test frame,
194
+ // bound back to its class to use private class members.
195
+ let testFrame = this.#frameChooser.supplyTestFrame(test);
196
+ testFrame = testFrame.bind(this.#frameSource);
197
+
198
+ // Done in every test.
199
+ this.#anyMethodSpoofing(test);
201
200
 
202
201
  // Actually running the test.
203
202
  try {
@@ -205,8 +204,12 @@ export class TestRunner {
205
204
  }
206
205
  catch (thrown) {
207
206
  test.anyThrow = thrown;
207
+ test.didPass = false;
208
208
  }
209
209
 
210
+ // Done in every test, whether passed, failed, or thrown.
211
+ this.#anyMethodRestoring(test);
212
+
210
213
  // Gathering facts based on the test run.
211
214
  result.setResults();
212
215
 
@@ -221,64 +224,31 @@ export class TestRunner {
221
224
 
222
225
  // Spoofs objects as defined in TestTuple's
223
226
  // .with and .in, which can contain spoofs.
224
- #spoofObjects(test) {
225
- this.#instanceSpoofer.spoof(test);
226
- }
227
-
228
- #supplyTestFrame(test) {
229
- // If `.and` includes "static", a call of a static member
230
- // is made, and the actual is its return value.
227
+ #anyObjectSpoofing(test) {
228
+ // Spoofing objects may be skipped for self-testing.
231
229
  if (typeof test.and === "string") {
232
- if (this.#doesAddressStatics(test)) {
233
- // If .from, a static call is made, then the actual is
234
- // retrieved from a named code element or custom code.
235
- if (test.from !== undefined) {
236
- return this.testCodeElementAfterStaticCall;
237
- }
238
-
239
- // Otherwise, the return value
240
- // of the static call is used.
241
- return this.testReturnValueOfStaticCall;
230
+ if (test.and.includes("nospoof")) {
231
+ return;
242
232
  }
243
233
  }
244
234
 
245
- // Constructors are a special case; no second call should
246
- // be made, and actual must be retrieved from property.
247
- if (test.of === TestRunner.#constructorName) {
248
- return this.testCodeElementAfterConstruction;
249
- }
235
+ // Actually spoofing, if any is defined.
236
+ this.#instanceSpoofer.spoof(test);
237
+ }
250
238
 
251
- // If .from, a call of the target is made, then the actual
252
- // is retrieved from a named code element or custom code.
253
- if (this.#isRetrievalTest(test.from)) {
254
- return this.testCodeElementAfterCall;
239
+ #anyMethodSpoofing(test) {
240
+ if (test.plus === undefined) {
241
+ return;
255
242
  }
256
243
 
257
- // The most common case: the target is called,
258
- // and the actual is its return value.
259
- return this.testReturnValueOfCall;
244
+ this.#classSpoofer.spoof(test);
260
245
  }
261
-
262
- #isRetrievalTest(testFrom) {
263
- // Falsy code elements never are a retrieval.
264
- if (!testFrom) {
265
- return false;
266
- }
267
-
268
- // If a (non-falsy) string, must be a retrieval.
269
- if (typeof testFrom === "string") {
270
- return true;
271
- }
272
-
273
- // If a function, is a retrieval.
274
- if (testFrom instanceof Function) {
275
- return true;
276
- }
277
-
278
- // Anything else is not a retrieval.
279
- return false;
246
+
247
+ #anyMethodRestoring(test) {
248
+ this.#classSpoofer.unspoof();
249
+ this.#classSpoofer.removeDefinitions();
280
250
  }
281
-
251
+
282
252
  #retainTestResults(test) {
283
253
  this.#numberRun++;
284
254
 
@@ -307,170 +277,4 @@ export class TestRunner {
307
277
 
308
278
  // endregion Running tests
309
279
 
310
- // region Test frames
311
-
312
- // The most basic test: whether a call of
313
- // a method returns the expected value.
314
- testReturnValueOfCall(test) {
315
- /* Groundwork. */
316
- this.#anyMethodSpoofing(test);
317
-
318
- let prototype = test.on.prototype;
319
- let target = new prototype.constructor(...test.with); // Must use `...`.
320
-
321
- /* Exercising the code. */
322
- test.actual = target[test.of](...test.in); // Must use `...`.
323
-
324
- /* Restoring. */
325
- this.#anyMethodRestoring(test);
326
-
327
- /* Comparing. */
328
- test.didPass = this.#compare(test.out, test.actual);
329
- }
330
-
331
- testReturnValueOfStaticCall(test) {
332
- /* Groundwork. */
333
- this.#anyMethodSpoofing(test);
334
-
335
- /* No instance is constructed. */
336
-
337
- /* Exercising the code. */
338
- test.actual = test.on[test.of](...test.in); // Must use `...`.
339
-
340
- /* Restoring. */
341
- this.#anyMethodRestoring(test);
342
-
343
- /* Comparing. */
344
- test.didPass = this.#compare(test.out, test.actual);
345
- }
346
-
347
- // The second-most basic test: whether a property
348
- // has the expected value after a method call.
349
- testCodeElementAfterCall(test) {
350
- /* Groundwork. */
351
- this.#anyMethodSpoofing(test);
352
-
353
- let prototype = test.on.prototype;
354
- let target = new prototype.constructor(...test.with); // Must use `...`.
355
-
356
- /* Exercising the code. */
357
- target[test.of](...test.in); // Must use `...`.
358
-
359
- /* Retrieving. */
360
- // The `actual` is a property or other code element somewhere.
361
- test.actual = this.#supplyNonReturnActual(test, target);
362
-
363
- /* Restoring. */
364
- this.#anyMethodRestoring(test);
365
-
366
- /* Comparing. */
367
- test.didPass = this.#compare(test.out, test.actual);
368
- }
369
-
370
- testCodeElementAfterStaticCall(test) {
371
- /* Groundwork. */
372
- this.#anyMethodSpoofing(test);
373
-
374
- /* No instance is constructed. */
375
-
376
- /* Exercising the code. */
377
- test.on[test.of](...test.in); // Must use `...`.
378
-
379
- /* Retrieving. */
380
- test.actual = this.#supplyNonReturnActual(test); // No `target` here.
381
-
382
- /* Restoring. */
383
- this.#anyMethodRestoring(test);
384
-
385
- /* Comparing. */
386
- test.didPass = this.#compare(test.out, test.actual);
387
- }
388
-
389
- // The third-most basic test: whether a property has
390
- // the expected value after an object is constructed.
391
- testCodeElementAfterConstruction(test) {
392
- /* Groundwork. */
393
- this.#anyMethodSpoofing(test);
394
-
395
- /* Exercising the code. */
396
- // For definition consistency, initing with test.in, not test.with.
397
- let prototype = test.on.prototype;
398
- let target = new prototype.constructor(...test.in); // Must use `...`.
399
-
400
- /* Retrieving. */
401
- // The `actual` is a property or other code element somewhere.
402
- test.actual = this.#supplyNonReturnActual(test, target);
403
-
404
- /* Restoring. */
405
- this.#anyMethodRestoring(test);
406
-
407
- /* Comparing. */
408
- test.didPass = this.#compare(test.out, test.actual);
409
- }
410
-
411
- // endregion Test frames
412
-
413
- // region Dependencies of test frames
414
-
415
- #anyMethodSpoofing(test) {
416
- if (test.plus === undefined) {
417
- return;
418
- }
419
-
420
- this.#classSpoofer.spoof(test);
421
- }
422
-
423
- #compare(expected, actual) {
424
- return this.#comparer.compare(expected, actual);
425
- }
426
-
427
- #supplyNonReturnActual(test, target) {
428
- // When there is a .from that's a string,
429
- // the actual is the named target member.
430
- if (typeof test.from === "string") {
431
- // Common member host;
432
- // undefined if static.
433
- let host = target;
434
-
435
- // When .and defines static.
436
- if (this.#doesAddressStatics(test)) {
437
- host = test.on;
438
- }
439
-
440
- return host[test.from];
441
- }
442
-
443
- // When there is a .from that's a function,
444
- // the actual is the result of calling it,
445
- // given everything that might be needed.
446
- if (test.from instanceof Function) {
447
- return test.from(target, test);
448
- }
449
-
450
- // When there is any other .from, the actual is the
451
- // value of the code element provided as .from.
452
- return test.from;
453
- }
454
-
455
- #anyMethodRestoring(test) {
456
- this.#classSpoofer.unspoof();
457
- this.#classSpoofer.removeDefinitions();
458
- }
459
-
460
- // endregion Dependencies of test frames
461
-
462
- // region Cross-region dependencies
463
-
464
- #doesAddressStatics(test) {
465
- if (typeof test.and === "string") {
466
- if (test.and.includes("static")) { /* &cruft, abstract */
467
- return true;
468
- }
469
- }
470
-
471
- return false;
472
- }
473
-
474
- // endregion Cross-region dependencies
475
-
476
280
  }
@@ -19,7 +19,7 @@ export class TestTuple {
19
19
 
20
20
  // endregion Static fields
21
21
 
22
- // region Private fields
22
+ // region Fields
23
23
 
24
24
  /* These longer names match the constructor-arg names.
25
25
  The short-name properties use the same fields. */
@@ -33,8 +33,11 @@ export class TestTuple {
33
33
  output;
34
34
  source;
35
35
  factors;
36
+
37
+ // Outcome field is not part of general system.
38
+ #actual = null;
36
39
 
37
- // endregion Private fields
40
+ // endregion Fields
38
41
 
39
42
  // region Properties
40
43
 
@@ -130,6 +133,14 @@ export class TestTuple {
130
133
  return isRunnable;
131
134
  }
132
135
 
136
+ get actual() {
137
+ return this.#actual;
138
+ }
139
+
140
+ set actual(value) {
141
+ this.#actual = value;
142
+ }
143
+
133
144
  // endregion Tuple state
134
145
 
135
146
  // endregion Properties