risei 1.0.4 → 1.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.
Files changed (78) hide show
  1. package/README.md +236 -339
  2. package/index.js +8 -8
  3. package/package.json +23 -9
  4. package/{public/javascript → system}/ASpoofingFixture.js +1 -1
  5. package/{public/javascript → system}/ChosenTestFinder.js +4 -3
  6. package/{public/javascript → system}/SpoofClassMethodsFixture.js +38 -22
  7. package/system/SpoofObjectMethodsFixture.js +58 -0
  8. package/{public/javascript → system}/SpoofTuple.js +14 -1
  9. package/{public/javascript → system}/TerminalReporter.js +249 -222
  10. package/system/TestFrame.js +187 -0
  11. package/system/TestFrameChooser.js +54 -0
  12. package/system/TestFrames.js +232 -0
  13. package/system/TestResult.js +187 -0
  14. package/system/TestRunner.js +280 -0
  15. package/system/TestStages.js +278 -0
  16. package/{public/javascript → system}/TestTuple.js +132 -13
  17. package/{public/javascript → system}/TotalComparer.js +12 -0
  18. package/system/TotalCopier.js +79 -0
  19. package/system/TotalDisplayer.js +143 -0
  20. package/system/TypeAnalyzer.js +103 -0
  21. package/system/TypeIdentifier.js +70 -0
  22. package/system/Types.js +17 -0
  23. package/tests/other-tests/ASpoofingFixture.tests.js +242 -0
  24. package/tests/other-tests/SpoofClassesFixture.tests.js +130 -0
  25. package/tests/other-tests/SpoofObjectsFixture.tests.js +95 -0
  26. package/tests/other-tests/SpoofTuple.tests.js +93 -0
  27. package/tests/other-tests/TotalComparer.tests.js +920 -0
  28. package/tests/other-tests/package.json +7 -0
  29. package/tests/risei-tests/ASpoofingFixtureTests.rt.js +51 -0
  30. package/tests/risei-tests/MomentTests.rt.js +103 -0
  31. package/tests/risei-tests/SpoofTupleTests.rt.js +274 -0
  32. package/tests/risei-tests/TestFrameChooserTests.rt.js +74 -0
  33. package/tests/risei-tests/TestFrameTests.rt.js +84 -0
  34. package/tests/risei-tests/TestStagesTests.rt.js +99 -0
  35. package/tests/risei-tests/TestTupleTests.rt.js +140 -0
  36. package/tests/risei-tests/TotalComparerTests.rt.js +184 -0
  37. package/tests/risei-tests/TotalCopierTests.rt.js +74 -0
  38. package/tests/risei-tests/TotalDisplayerTests.rt.js +186 -0
  39. package/tests/risei-tests/TypeAnalyzerTests.rt.js +29 -0
  40. package/tests/risei-tests/TypeIdentifierTests.rt.js +44 -0
  41. package/tests/self-tests/SelfTests.outward-rt.js +583 -0
  42. package/tests/target-objects/CompositionModel.js +38 -0
  43. package/tests/target-objects/ConditionalThrowModel.js +11 -0
  44. package/tests/target-objects/CountModel.js +46 -0
  45. package/tests/target-objects/DomModel.js +37 -0
  46. package/tests/target-objects/MixedContents.js +33 -0
  47. package/tests/target-objects/MutationModel.js +27 -0
  48. package/tests/target-objects/ObjectCompositionModel.js +34 -0
  49. package/tests/target-objects/PolySpoofableInner.js +30 -0
  50. package/tests/target-objects/PolySpoofableOuter.js +52 -0
  51. package/tests/target-objects/PropertiesModel.js +47 -0
  52. package/tests/target-objects/Returner.js +9 -0
  53. package/tests/target-objects/SearchModel.js +25 -0
  54. package/tests/target-objects/SortModel.js +91 -0
  55. package/tests/target-objects/SpoofCaller.js +24 -0
  56. package/tests/target-objects/Spoofable.js +36 -0
  57. package/tests/target-objects/SpoofableArgsCaller.js +33 -0
  58. package/tests/target-objects/StateModel.js +34 -0
  59. package/tests/target-objects/StaticModel.js +17 -0
  60. package/tests/target-objects/TestableModel.js +47 -0
  61. package/tests/topic-tests/TopicTests.outward-rt.js +354 -0
  62. package/public/javascript/SpoofObjectMethodsFixture.js +0 -52
  63. package/public/javascript/TestResult.js +0 -338
  64. package/public/javascript/TestRunner.js +0 -476
  65. /package/{public/javascript → system}/AComparer.js +0 -0
  66. /package/{public/javascript → system}/ATestCaller.js +0 -0
  67. /package/{public/javascript → system}/ATestFinder.js +0 -0
  68. /package/{public/javascript → system}/ATestFixture.js +0 -0
  69. /package/{public/javascript → system}/ATestReporter.js +0 -0
  70. /package/{public/javascript → system}/ATestSource.js +0 -0
  71. /package/{public/javascript → system}/ClassTestGroup.js +0 -0
  72. /package/{public/javascript → system}/LocalCaller.js +0 -0
  73. /package/{public/javascript → system}/MethodTestGroup.js +0 -0
  74. /package/{public/javascript → system}/Moment.js +0 -0
  75. /package/{public/javascript → system}/Risei.js +0 -0
  76. /package/{public/javascript → system}/TestFinder.js +0 -0
  77. /package/{public/javascript → system}/TestGroup.js +0 -0
  78. /package/{public/javascript → system}/TestSummary.js +0 -0
@@ -0,0 +1,280 @@
1
+ /**/
2
+
3
+ /* Runs tests one by one as an ATestCaller requests them. */
4
+
5
+ import { TestTuple } from "./TestTuple.js";
6
+ import { TestGroup } from "./TestGroup.js";
7
+ import { ClassTestGroup } from "./ClassTestGroup.js";
8
+ import { MethodTestGroup } from "./MethodTestGroup.js";
9
+ import { TestResult } from "./TestResult.js";
10
+ import { TestSummary } from "./TestSummary.js";
11
+
12
+ import { TestFrameChooser } from "./TestFrameChooser.js";
13
+ import { TestFrames } from "./TestFrames.js";
14
+
15
+ import { SpoofClassMethodsFixture } from "./SpoofClassMethodsFixture.js";
16
+ import { SpoofObjectMethodsFixture } from "./SpoofObjectMethodsFixture.js";
17
+ import { SpoofTuple } from "./SpoofTuple.js";
18
+
19
+ export class TestRunner {
20
+ // region Static definition fields
21
+
22
+ // Used for a special test structural case;
23
+ // classes have one constructor by this name.
24
+ static #constructorName = "constructor";
25
+
26
+ // endregion Static definition fields
27
+
28
+ // region Private fields
29
+
30
+ // Components and state.
31
+ #tests;
32
+
33
+ #classSpoofer;
34
+ #instanceSpoofer;
35
+
36
+ #frameSource;
37
+ #frameChooser;
38
+
39
+ #comparer;
40
+
41
+ // Results summary.
42
+ #numberRun;
43
+ #numberPassed;
44
+ #numberFailed;
45
+ #allDidPass;
46
+
47
+ // endregion Private fields
48
+
49
+ // region Properties
50
+
51
+ get tests() {
52
+ return this.#tests;
53
+ }
54
+
55
+ set tests(value) {
56
+ this.#tests = value;
57
+ }
58
+
59
+ // region Spoofing
60
+
61
+ get classSpoofer() {
62
+ return this.#classSpoofer;
63
+ }
64
+
65
+ set classSpoofer(value) {
66
+ this.#classSpoofer = value;
67
+ }
68
+
69
+ get instanceSpoofer() {
70
+ return this.#instanceSpoofer;
71
+ }
72
+
73
+ set instanceSpoofer(value) {
74
+ this.#instanceSpoofer = value;
75
+ }
76
+
77
+ // endregion Spoofing
78
+
79
+ get numberRun() {
80
+ return this.#numberRun;
81
+ }
82
+
83
+ set numberRun(value) {
84
+ this.#numberRun = value;
85
+ }
86
+
87
+ get numberPassed() {
88
+ return this.#numberPassed;
89
+ }
90
+
91
+ set numberPassed(value) {
92
+ this.#numberPassed = value;
93
+ }
94
+
95
+ get numberFailed() {
96
+ return this.#numberFailed;
97
+ }
98
+
99
+ set numberFailed(value) {
100
+ this.#numberFailed = value;
101
+ }
102
+
103
+ get allDidPass() {
104
+ return this.#allDidPass;
105
+ }
106
+
107
+ set allDidPass(value) {
108
+ this.#allDidPass = value;
109
+ }
110
+
111
+ // endregion Properties
112
+
113
+ constructor() {
114
+ this.#tests = [];
115
+ this.#classSpoofer = new SpoofClassMethodsFixture();
116
+ this.#instanceSpoofer = new SpoofObjectMethodsFixture();
117
+
118
+ this.#frameSource = new TestFrames();
119
+ this.#frameChooser = new TestFrameChooser(this.#frameSource);
120
+
121
+ this.#numberRun = 0;
122
+ this.#numberPassed = 0;
123
+ this.#numberFailed = 0;
124
+
125
+ this.#allDidPass = true;
126
+ }
127
+
128
+ // region Tests to run
129
+
130
+ useTests(tests) {
131
+ this.#tests = tests;
132
+ }
133
+
134
+ // endregion Tests to run
135
+
136
+ // region Running tests
137
+
138
+ // Generator for all test results,
139
+ // including groups and summary.
140
+ * [Symbol.iterator]() {
141
+ if (!this.#tests) {
142
+ throw new Error("No tests available to run. TestRunner's .tests must be set before an attempt to run is made.");
143
+ }
144
+
145
+ // Converting so that property names can be relied on.
146
+ this.#tests = TestTuple.fromNonceTuples(this.tests);
147
+
148
+ // Needed for displaying classes and methods as groups.
149
+ let classGroup = new ClassTestGroup();
150
+ let methodGroup = new MethodTestGroup();
151
+ let atFirstClassMethod = false;
152
+
153
+ // Iterative running of all tests in current order.
154
+ for (let test of this.#tests) {
155
+ // Each new class should be a group, and its start
156
+ // should be retained for grouping of methods.
157
+ if (test.on.name !== classGroup.group) {
158
+ classGroup.group = test.on.name;
159
+ atFirstClassMethod = true;
160
+ yield classGroup;
161
+ }
162
+
163
+ // Each new method name should be a group,
164
+ // and so should each method for a class.
165
+ if (test.of !== methodGroup.group || atFirstClassMethod) {
166
+ methodGroup.group = test.of;
167
+ atFirstClassMethod = false;
168
+ yield methodGroup;
169
+ }
170
+
171
+ let result = this.runOneTest(test);
172
+ yield result;
173
+ }
174
+
175
+ // Iterative returning of final results summary.
176
+ yield this.summarize();
177
+ }
178
+
179
+ runOneTest(test) {
180
+ // Default outputs. Never left undefined.
181
+ test.didPass = false;
182
+ test.anyThrow = null;
183
+
184
+ // Spoofing based on any spoof
185
+ // definitions in .with and .of.
186
+ this.#anyObjectSpoofing(test);
187
+
188
+ // Gathering facts defining the nature of the test,
189
+ // some of which might change after the test is run.
190
+ let result = new TestResult(test);
191
+ result.setNature();
192
+
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);
200
+
201
+ // Actually running the test.
202
+ try {
203
+ testFrame(test);
204
+ }
205
+ catch (thrown) {
206
+ test.anyThrow = thrown;
207
+ test.didPass = false;
208
+ }
209
+
210
+ // Done in every test, whether passed, failed, or thrown.
211
+ this.#anyMethodRestoring(test);
212
+
213
+ // Gathering facts based on the test run.
214
+ result.setResults();
215
+
216
+ // For later summarizing.
217
+ this.#retainTestResults(test);
218
+
219
+ // Results and test back to the caller.
220
+ return result;
221
+ }
222
+
223
+ // region Dependencies of runOneTest()
224
+
225
+ // Spoofs objects as defined in TestTuple's
226
+ // .with and .in, which can contain spoofs.
227
+ #anyObjectSpoofing(test) {
228
+ // Spoofing objects may be skipped for self-testing.
229
+ if (typeof test.and === "string") {
230
+ if (test.and.includes("nospoof")) {
231
+ return;
232
+ }
233
+ }
234
+
235
+ // Actually spoofing, if any is defined.
236
+ this.#instanceSpoofer.spoof(test);
237
+ }
238
+
239
+ #anyMethodSpoofing(test) {
240
+ if (test.plus === undefined) {
241
+ return;
242
+ }
243
+
244
+ this.#classSpoofer.spoof(test);
245
+ }
246
+
247
+ #anyMethodRestoring(test) {
248
+ this.#classSpoofer.unspoof();
249
+ this.#classSpoofer.removeDefinitions();
250
+ }
251
+
252
+ #retainTestResults(test) {
253
+ this.#numberRun++;
254
+
255
+ if (test.didPass) {
256
+ this.#numberPassed++;
257
+ }
258
+ else {
259
+ this.#numberFailed++;
260
+ }
261
+
262
+ this.#allDidPass &= test.didPass;
263
+ }
264
+
265
+ // endregion Dependencies of runOneTest()
266
+
267
+ summarize() {
268
+ let summary = `Ran ${ this.#numberRun } test${ this.#numberRun !== 1 ? "s" : "" }. `
269
+ + `${ this.#allDidPass ? "All tests passed. " : "" }`
270
+ + `${ this.#numberPassed } passed. `
271
+ + `${ this.#numberFailed } failed.`;
272
+
273
+ let anyWereRun = this.#numberRun > 0;
274
+
275
+ return new TestSummary(summary, this.#allDidPass, anyWereRun);
276
+ }
277
+
278
+ // endregion Running tests
279
+
280
+ }
@@ -0,0 +1,278 @@
1
+ /**/
2
+
3
+ import { TestTuple } from "./TestTuple.js";
4
+ import { TotalComparer } from "./TotalComparer.js";
5
+ import { TotalCopier } from "./TotalCopier.js";
6
+
7
+ export class TestStages {
8
+ /* &cruft, implement all of these under test, and eventually factor them */
9
+
10
+ /* These methods hold operations carried out in the test frame,
11
+ or before / after all test frames, in the test runner.
12
+ Not necessarily all test steps are found here. */
13
+
14
+ static #comparer = new TotalComparer();
15
+ static #copier = new TotalCopier();
16
+
17
+ setLocalInitorsAndInputs(test) /* passed */ {
18
+ /* Sets local__ of each to a copy of the original,
19
+ so any mutated args aren't collapsed forward. */
20
+
21
+ test.localInitors = TestStages.#copier.copy(test.with);
22
+ test.localInputs = TestStages.#copier.copy(test.in);
23
+ }
24
+
25
+ anyPreTargetingGroundwork(test) {
26
+ // Spoofing of class members here.
27
+ // Setting any static properties here.
28
+ }
29
+
30
+ setLocalTarget(test) /* passed */ {
31
+ /* Target may be instance, prototype for constructors,
32
+ the class itself for statics, or a nonce for either
33
+ static or instance properties. */
34
+
35
+ if (test.isConstructorTest) {
36
+ test.localTarget = test.on.prototype;
37
+ return;
38
+ }
39
+
40
+ let callable = TestTuple.plainNameOf(test.of);
41
+
42
+ let target = test.isInstanceTest
43
+ ? this.#supplyInstanceLocalTarget(test, callable)
44
+ : this.#supplyStaticLocalTarget(test, callable);
45
+
46
+ test.localTarget = target;
47
+ }
48
+
49
+ // region Dependencies of setLocalTarget()
50
+
51
+ #supplyStaticLocalTarget(test, callable) /* verified */ {
52
+ let type = test.on;
53
+
54
+ // Methods are called on class directly.
55
+ // Properties are called on class in nonce.
56
+ let target = test.isMethodTest
57
+ ? type
58
+ : { localCallable: () => { return type[callable]; } };
59
+
60
+ return target;
61
+ }
62
+
63
+ #supplyInstanceLocalTarget(test, callable) /* verified */ {
64
+ let instance = new test.on.prototype.constructor(...test.localInitors);
65
+
66
+ // Methods are called on instance directly.
67
+ // Properties are called on instance in nonce.
68
+ let target = test.isMethodTest
69
+ ? instance
70
+ : { localCallable: () => { return instance[callable]; } };
71
+
72
+ return target;
73
+ }
74
+
75
+ // endregion Dependencies of setLocalTarget()
76
+
77
+ setLocalCallable(test) /* passed */ {
78
+ /* Method under test is a method named in test,
79
+ or a nonce method for a property test. */
80
+
81
+ test.localCallable = test.isMethodTest
82
+ ? TestTuple.plainNameOf(test.method)
83
+ : TestTuple.nonceLocalCallableName;
84
+ }
85
+
86
+ anyPostTargetingGroundwork(test) {
87
+ // Setting instance properties.
88
+ }
89
+
90
+ anyModifyActual(test) /* passed */ {
91
+ /* Original test.actual is used if a normal test, but replaced with .thrown
92
+ if a throw test, or result of supplier method if a retrieval test. */
93
+
94
+ if (test.isThrowTest) {
95
+ // May be undefined, if no throw.
96
+ test.actual = test.thrown;
97
+ }
98
+
99
+ if (test.isRetrievalTest) {
100
+ test.actual = this.supplyNonReturnActual(test);
101
+ }
102
+ }
103
+
104
+ compareResults(expected, actual) /* passed */ {
105
+ return TestStages.#comparer.compare(expected, actual);
106
+ }
107
+
108
+ anyGroundworkReversion(test) {
109
+ // Unspoofing.
110
+ // Unsetting static properties.
111
+ // Undoing any other groundwork changes made.
112
+ }
113
+
114
+
115
+ // region Dependencies of test stages
116
+
117
+ #anyOriginalPropertyGetting(target, settables) {
118
+ if (!Array.isArray(settables)) {
119
+ return;
120
+ }
121
+
122
+ let unsettables = [ ];
123
+
124
+ for (let settable of settables) {
125
+ // Not a setter tuple.
126
+ if (!settable.of) {
127
+ continue;
128
+ }
129
+
130
+ // Retaining original.
131
+ let original = target[settable.of];
132
+ let unsettable = { of: settable.of, as: original };
133
+ unsettables.push(unsettable);
134
+ }
135
+
136
+ return unsettables;
137
+ }
138
+
139
+ #anyPropertySetting(target, settables) {
140
+ // No properties to set.
141
+ if (!Array.isArray(settables)) {
142
+ return;
143
+ }
144
+
145
+ for (let settable of settables) {
146
+ // Not a setter tuple.
147
+ if (!settable.of) {
148
+ continue;
149
+ }
150
+
151
+ // Actually setting property.
152
+ target[settable.of] = settable.as;
153
+ }
154
+ }
155
+
156
+ #anyPropertyUnsetting(target, unsettables) {
157
+ // Unsetting is the same as setting,
158
+ // but with tuples of original values.
159
+ return this.#anyPropertySetting(target, unsettables);
160
+ }
161
+
162
+ #compare(expected, actual) {
163
+ return this.#comparer.compare(expected, actual);
164
+ }
165
+
166
+ supplyNonReturnActual(test) {
167
+ // When there is a .from that's a string,
168
+ // the actual is the named target member.
169
+ if (typeof test.from === "string") {
170
+ /* &cruft, maybe explain how this differs from setting .localTarget,
171
+ which can be a nonce, or else maybe make them the same */
172
+
173
+ // Common member host;
174
+ // undefined if static.
175
+ let host = test.target;
176
+
177
+ // When .and defines static.
178
+ if (test.isStaticTest) {
179
+ host = test.on;
180
+ }
181
+
182
+ return host[test.from];
183
+ }
184
+
185
+ /* &cruft, possibly change all .from syntax to (actual, test),
186
+ or maybe to (test), or else switch back args here */
187
+ // When there is a .from that's a function,
188
+ // the actual is the result of calling it,
189
+ // given everything that might be needed.
190
+ if (test.from instanceof Function) {
191
+ return test.from(test.actual, test.localTarget);
192
+ }
193
+
194
+ /* &cruft, probably drop this, change maybe to a throw */
195
+ // When there is any other .from, the actual is the
196
+ // value of the code element provided as .from.
197
+ return test.from;
198
+ }
199
+
200
+ // endregion Dependencies of test stages
201
+
202
+
203
+ /* &cruft, remove or use this code... */
204
+
205
+ // anyOriginalPropertyGetting(target, settables) {
206
+ // if (!Array.isArray(settables)) {
207
+ // return;
208
+ // }
209
+ //
210
+ // let unsettables = [ ];
211
+ //
212
+ // for (let settable of settables) {
213
+ // // Not a setter tuple.
214
+ // if (!settable.of) {
215
+ // continue;
216
+ // }
217
+ //
218
+ // // Retaining original.
219
+ // let original = target[settable.of];
220
+ // let unsettable = { of: settable.of, as: original };
221
+ // unsettables.push(unsettable);
222
+ // }
223
+ //
224
+ // return unsettables;
225
+ // }
226
+ //
227
+ // anyPropertySetting(target, settables) {
228
+ // // No properties to set.
229
+ // if (!Array.isArray(settables)) {
230
+ // return;
231
+ // }
232
+ //
233
+ // for (let settable of settables) {
234
+ // // Not a setter tuple.
235
+ // if (!settable.of) {
236
+ // continue;
237
+ // }
238
+ //
239
+ // // Actually setting property.
240
+ // target[settable.of] = settable.as;
241
+ // }
242
+ // }
243
+ //
244
+ // anyPropertyUnsetting(target, unsettables) {
245
+ // // Unsetting is the same as setting,
246
+ // // but with tuples of original values.
247
+ // return this.anyPropertySetting(target, unsettables);
248
+ // }
249
+ //
250
+ // supplyNonReturnActual(test, target) {
251
+ // // When there is a .from that's a string,
252
+ // // the actual is the named target member.
253
+ // if (typeof test.from === "string") {
254
+ // // Common member host;
255
+ // // undefined if static.
256
+ // let host = target;
257
+ //
258
+ // // When .and defines static.
259
+ // if (test.isStaticTest) {
260
+ // host = test.on;
261
+ // }
262
+ //
263
+ // return host[test.from];
264
+ // }
265
+ //
266
+ // // When there is a .from that's a function,
267
+ // // the actual is the result of calling it,
268
+ // // given everything that might be needed.
269
+ // if (test.from instanceof Function) {
270
+ // return test.from(target, test);
271
+ // }
272
+ //
273
+ // // When there is any other .from, the actual is the
274
+ // // value of the code element provided as .from.
275
+ // return test.from;
276
+ // }
277
+
278
+ }