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.
Files changed (38) hide show
  1. package/README.md +195 -338
  2. package/index.js +9 -9
  3. package/package.json +7 -7
  4. package/{public/javascript → system}/ChosenTestFinder.js +2 -2
  5. package/{public/javascript → system}/SpoofClassMethodsFixture.js +38 -22
  6. package/system/SpoofObjectMethodsFixture.js +58 -0
  7. package/{public/javascript → system}/SpoofTuple.js +14 -0
  8. package/system/TestFrame.js +187 -0
  9. package/{public/javascript → system}/TestFrameChooser.js +6 -47
  10. package/{public/javascript → system}/TestFrames.js +232 -180
  11. package/system/TestResult.js +187 -0
  12. package/system/TestStages.js +278 -0
  13. package/{public/javascript → system}/TestTuple.js +126 -18
  14. package/{public/javascript → system}/TotalComparer.js +12 -0
  15. package/system/TotalCopier.js +79 -0
  16. package/system/TotalDisplayer.js +143 -0
  17. package/system/TypeAnalyzer.js +103 -0
  18. package/system/TypeIdentifier.js +70 -0
  19. package/system/Types.js +17 -0
  20. package/public/javascript/SpoofObjectMethodsFixture.js +0 -52
  21. package/public/javascript/TestResult.js +0 -338
  22. /package/{public/javascript → system}/AComparer.js +0 -0
  23. /package/{public/javascript → system}/ASpoofingFixture.js +0 -0
  24. /package/{public/javascript → system}/ATestCaller.js +0 -0
  25. /package/{public/javascript → system}/ATestFinder.js +0 -0
  26. /package/{public/javascript → system}/ATestFixture.js +0 -0
  27. /package/{public/javascript → system}/ATestReporter.js +0 -0
  28. /package/{public/javascript → system}/ATestSource.js +0 -0
  29. /package/{public/javascript → system}/ClassTestGroup.js +0 -0
  30. /package/{public/javascript → system}/LocalCaller.js +0 -0
  31. /package/{public/javascript → system}/MethodTestGroup.js +0 -0
  32. /package/{public/javascript → system}/Moment.js +0 -0
  33. /package/{public/javascript → system}/Risei.js +0 -0
  34. /package/{public/javascript → system}/TerminalReporter.js +0 -0
  35. /package/{public/javascript → system}/TestFinder.js +0 -0
  36. /package/{public/javascript → system}/TestGroup.js +0 -0
  37. /package/{public/javascript → system}/TestRunner.js +0 -0
  38. /package/{public/javascript → system}/TestSummary.js +0 -0
@@ -0,0 +1,143 @@
1
+ /**/
2
+
3
+ import { TypeIdentifier } from "./TypeIdentifier.js";
4
+ import { Types } from "./Types.js";
5
+
6
+ export class TotalDisplayer {
7
+ #identifier;
8
+
9
+ constructor() /* verified */ {
10
+ this.#identifier = new TypeIdentifier();
11
+ }
12
+
13
+ display(value) /* passed */ {
14
+ let typeId = this.#identifier.identify(value);
15
+
16
+ switch (typeId) {
17
+ case Types.isValue: return this.displayValue(value);
18
+ case Types.isString: return this.displayString(value);
19
+ case Types.isArray: return this.displayArray(value);
20
+ case Types.isMap: return this.displayMap(value);
21
+ case Types.isSet: return this.displaySet(value);
22
+ case Types.isClass: return this.displayClass(value);
23
+ case Types.isFunction: return this.displayFunction(value);
24
+ case Types.isObject: return this.displayObject(value);
25
+ case Types.isDate: return this.displayValue(value);
26
+ case Types.isUndefined: return this.displayUndefined(value);
27
+ case Types.isNull: return this.displayNull(value);
28
+ }
29
+ }
30
+
31
+ // region Displaying different types
32
+
33
+ /* Plain values (numbers, booleans) and Dates
34
+ are handled together using JS defaults. */
35
+ displayValue(value) /* passed */ {
36
+ return `${ value }`;
37
+ }
38
+
39
+ displayString(value) /* passed */ {
40
+ return `"${ value }"`;
41
+ }
42
+
43
+ displayArray(value) /* passed */ {
44
+ // Cross-recursion.
45
+ let outputs = value
46
+ .map(x => this.display(x));
47
+
48
+ // Brackets around, commas between.
49
+ let output = `[${ outputs.join(",") }]`;
50
+
51
+ // And back to caller.
52
+ return output;
53
+ }
54
+
55
+ displayMap(value) /* passed */ {
56
+ // Array used for clearer display.
57
+ let items = [ ];
58
+
59
+ // Each key-value pair is handled individually.
60
+ for (let key of value.keys()) {
61
+ let item = value.get(key);
62
+
63
+ // Cross-recursion.
64
+ items.push(`${ this.display(key) }:${ this.display(item) }`);
65
+ }
66
+
67
+ // Key-value pairs are all listed together.
68
+ let output = `Map{${ items.join(",") }}`;
69
+ return output;
70
+ }
71
+
72
+ displaySet(value) /* passed */ {
73
+ // Array used for clearer display.
74
+ let items = [ ];
75
+
76
+ // Each element is handled individually.
77
+ for (let item of value) {
78
+ // Cross-recursion for styling values.
79
+ let display = `${ this.display(item) }`;
80
+ items.push(display);
81
+ }
82
+
83
+ // Items are all listed together.
84
+ let output = `Set{${ items.join(",") }}`;
85
+ return output;
86
+ }
87
+
88
+ displayClass(value) /* passed */ {
89
+ // Class definitions have a .name.
90
+ let output = value.name;
91
+ return output;
92
+ }
93
+
94
+ displayFunction(value) /* passed */ {
95
+ // toString() lists the definition, including code.
96
+ let output = value.toString();
97
+
98
+ // Most whitespace is eliminated for readability.
99
+ output = output.replace(/(\r\n?)/g, "");
100
+ output = output.replace(/\s{2,}/g, " ");
101
+
102
+ // Back to caller.
103
+ return output;
104
+ }
105
+
106
+ displayObject(value) /* passed */ {
107
+ // Use toString() text if it's meaningful.
108
+ let asString = value.toString();
109
+
110
+ if (asString !== "[object Object]") {
111
+ return asString;
112
+ }
113
+
114
+ // If toString() not meaningful, list members.
115
+ let items = [ ];
116
+
117
+ // Each property of the object is handled individually.
118
+ for (let p in value) {
119
+ // Cross-recursion.
120
+ let item = this.display(value[p]);
121
+ items.push(`${ p }:${ item }`);
122
+ }
123
+
124
+ // Properties are all listed together.
125
+ let output = `{ ${ items.join(", ") } }`;
126
+
127
+ // If empty, internal empty space reduced.
128
+ output = output !== "{ }" ? output : "{ }";
129
+
130
+ // Back to caller.
131
+ return output;
132
+ }
133
+
134
+ displayUndefined(value) /* passed */ {
135
+ return "undefined";
136
+ }
137
+
138
+ displayNull(value) /* passed */ {
139
+ return "null";
140
+ }
141
+
142
+ // endregion Displaying different types
143
+ }
@@ -0,0 +1,103 @@
1
+ /**/
2
+
3
+ /* Used to analyze classes / members of classes being tested. */
4
+
5
+ export class TypeAnalyzer {
6
+ // region Definitions
7
+
8
+ static constructorName = "constructor";
9
+ static getName = "get";
10
+ static setName = "set";
11
+
12
+ // endregion Definitions
13
+
14
+ // region Fields
15
+
16
+ #type;
17
+
18
+ // endregion Fields
19
+
20
+ constructor(type) {
21
+ this.#type = type;
22
+ }
23
+
24
+ /* Returns true if instance or static member is a property (value or accessor). Returns false if member is a method. */
25
+ memberIsProperty(name) /* passed */ {
26
+ // Constructor is never a property and is irregular,
27
+ // so other type-analysis code can't handle it.
28
+ if (name === TypeAnalyzer.constructorName) {
29
+ return false;
30
+ }
31
+
32
+ // Static methods and properties (value or accessor) are on type.
33
+ if (name in this.#type) {
34
+ return this.#staticMemberIsProperty(this.#type, name);
35
+ }
36
+
37
+ // Methods and accessor properties are on prototype.
38
+ if (name in this.#type.prototype) {
39
+ return this.#instanceMemberIsProperty(this.#type.prototype, name);
40
+ }
41
+
42
+ // Instance value properties are not on type or prototype.
43
+ return true;
44
+ }
45
+
46
+ // region Dependencies of memberIsProperty()
47
+
48
+ /* Algorithm specialized with function check for static members. */
49
+ #staticMemberIsProperty(type, name) {
50
+ let descriptor = Object.getOwnPropertyDescriptor(type, name);
51
+
52
+ // If on type and has accessors, it's a static accessor property.
53
+ if (this.#doesHaveAccessorProps(descriptor)) {
54
+ return true;
55
+ }
56
+
57
+ // If on type and has non-Function .value, it's a static value property.
58
+ if (this.#doesNotHaveFunctionValue(descriptor)) {
59
+ return true;
60
+ }
61
+
62
+ // If on type but not a static property, it's a static method.
63
+ return false;
64
+ }
65
+
66
+ /* Algorithm specialized for instance members, no function check. */
67
+ #instanceMemberIsProperty(prototype, name) {
68
+ let descriptor = Object.getOwnPropertyDescriptor(prototype, name);
69
+
70
+ // If on prototype and has accessors, it's an accessor property.
71
+ if (this.#doesHaveAccessorProps(descriptor)) {
72
+ return true;
73
+ }
74
+
75
+ // If on prototype but not an accessor property, it's a method.
76
+ return false;
77
+ }
78
+
79
+ // region Internally reused dependencies of other memberIsProperty() dependencies
80
+
81
+ #doesHaveAccessorProps(descriptor) /* verified */ {
82
+ // Accessor properties have one or both of these in descriptor.
83
+ if (TypeAnalyzer.getName in descriptor || TypeAnalyzer.setName in descriptor) {
84
+ return true;
85
+ }
86
+
87
+ return false;
88
+ }
89
+
90
+ #doesNotHaveFunctionValue(descriptor) /* verified */ {
91
+ // Simple inverter of other method for readability.
92
+ return !this.#doesHaveFunctionValue(descriptor);
93
+ }
94
+
95
+ #doesHaveFunctionValue(descriptor) /* verified */ {
96
+ // If no member, .value of undefined.
97
+ return descriptor.value instanceof Function;
98
+ }
99
+
100
+ // endregion Internally reused dependencies of other memberIsProperty() dependencies
101
+
102
+ // endregion Dependencies of memberIsProperty()
103
+ }
@@ -0,0 +1,70 @@
1
+ /**/
2
+
3
+ import { Types } from "./Types.js";
4
+
5
+ export class TypeIdentifier {
6
+ identify(value) /* passed */ {
7
+ // Basis for most top branching.
8
+ let rawType = typeof value;
9
+
10
+ // Array, Map, Set, Date, null, and actual
11
+ // objects are all "object" to JavaScript.
12
+ if (rawType === "object") {
13
+ if (Array.isArray(value)) {
14
+ return Types.isArray;
15
+ }
16
+
17
+ if (value instanceof Map) {
18
+ return Types.isMap;
19
+ }
20
+
21
+ if (value instanceof Set) {
22
+ return Types.isSet;
23
+ }
24
+
25
+ if (value instanceof Date) {
26
+ return Types.isDate;
27
+ }
28
+
29
+ if (value === null) {
30
+ return Types.isNull;
31
+ }
32
+
33
+ return Types.isObject;
34
+ }
35
+
36
+ // Functions and classes are both "function" to Javascript.
37
+ if (rawType === "function") {
38
+ // Functions can be anonymous.
39
+ if (!value.name) {
40
+ return Types.isFunction;
41
+ }
42
+
43
+ // Classes all start with this syntax
44
+ // in their defs (never with `export`).
45
+ let classSyntax = `class ${ value.name }`;
46
+
47
+ let definition = value.toString();
48
+
49
+ if (definition.startsWith(classSyntax)) {
50
+ return Types.isClass;
51
+ }
52
+
53
+ // Function but not class is a named function.
54
+ return Types.isFunction;
55
+ }
56
+
57
+ // Strings may be handled specially.
58
+ if (typeof value === "string") {
59
+ return Types.isString;
60
+ }
61
+
62
+ // Undefined is different from the rest.
63
+ if (value === undefined) {
64
+ return Types.isUndefined;
65
+ }
66
+
67
+ // Non-string values all handled the same.
68
+ return Types.isValue;
69
+ }
70
+ }
@@ -0,0 +1,17 @@
1
+ /**/
2
+
3
+ export class Types {
4
+ /* This class is essentially an enum. */
5
+
6
+ static isValue = "value";
7
+ static isString = "string";
8
+ static isArray = "array";
9
+ static isObject = "object";
10
+ static isMap = "map";
11
+ static isSet = "set";
12
+ static isFunction = "function";
13
+ static isClass = "class";
14
+ static isDate = "date";
15
+ static isUndefined = "undefined";
16
+ static isNull = "null";
17
+ }
@@ -1,52 +0,0 @@
1
- /* */
2
-
3
- import { ASpoofingFixture } from "./ASpoofingFixture.js";
4
- import { SpoofTuple } from "./SpoofTuple.js";
5
-
6
- export class SpoofObjectMethodsFixture extends ASpoofingFixture {
7
- constructor() {
8
- super("SpoofObjectMethodsFixture", "Construction");
9
- }
10
-
11
- /* Spoofs methods of any objects in test.with and test.in
12
- for which nonce spoof-tuple definitions are provided. */
13
- spoof(test) {
14
- // These array test aspects may contain object-spoof definitions.
15
- let topics = [ test.with, test.in ];
16
-
17
- // Spoofing each element, or leaving it in place if not a spoof.
18
- for (let topic of topics) {
19
- for (let at = 0; at < topic.length; at++) {
20
- let target = topic[at];
21
- topic[at] = this.spoofTarget(target);
22
- }
23
- }
24
- }
25
-
26
- spoofTarget(target) {
27
- // Non-spoofs are returned unchanged.
28
- if (SpoofTuple.isNotASpoof(target)) {
29
- return target;
30
- }
31
-
32
- // Spoofs are converted to their type.
33
- let tuple = SpoofTuple.fromNonceTuple(target);
34
-
35
- // Actually spoofing.
36
- let spoof = this.#supplySpoof(tuple);
37
- return spoof;
38
- }
39
-
40
- #supplySpoof(target) {
41
- // Common case.
42
- let ofAsPairs = [{ of: target.method, as: target.output }];
43
-
44
- // Complex case.
45
- if (!target.method) {
46
- ofAsPairs = target.output;
47
- }
48
-
49
- let spoof = super.spoofObjectTree(ofAsPairs);
50
- return spoof;
51
- }
52
- }