risei 1.2.0 → 1.3.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 +118 -46
- package/index.js +18 -5
- package/package.json +3 -4
- package/system/ASpoofingFixture.js +3 -3
- package/system/ATestFinder.js +13 -0
- package/system/Risei.js +82 -52
- package/system/SpoofClassMethodsFixture.js +5 -5
- package/system/{SpoofTuple.js → SpoofDefinition.js} +20 -20
- package/system/SpoofObjectMethodsFixture.js +3 -3
- package/system/{TestTuple.js → TestDefinition.js} +41 -27
- package/system/TestFinder.js +11 -5
- package/system/TestFrame.js +17 -108
- package/system/TestRunner.js +4 -4
- package/system/TestStages.js +5 -13
- package/system/TotalCopier.js +106 -79
- package/system/TypeAnalyzer.js +103 -103
package/system/TotalCopier.js
CHANGED
|
@@ -1,79 +1,106 @@
|
|
|
1
|
-
/**/
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
if
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
return copy;
|
|
70
|
-
}
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
1
|
+
/**/
|
|
2
|
+
|
|
3
|
+
import { TypeIdentifier } from "./TypeIdentifier.js";
|
|
4
|
+
import { Types } from "./Types.js";
|
|
5
|
+
|
|
6
|
+
export class TotalCopier {
|
|
7
|
+
#identifier = new TypeIdentifier();
|
|
8
|
+
|
|
9
|
+
copy(original) /* passed */ {
|
|
10
|
+
return this.recursiveCopy(original);
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
recursiveCopy(original) /* verified */ {
|
|
14
|
+
/* &cruft, factor, possibly abstracting similar code,
|
|
15
|
+
and/or return copy only once, or similar */
|
|
16
|
+
|
|
17
|
+
/* Algorithm: First copied at current level by value if a value, by reference if
|
|
18
|
+
not a value; then recursively replaced at next level, and so on. */
|
|
19
|
+
|
|
20
|
+
let copy;
|
|
21
|
+
|
|
22
|
+
let type = this.#identifier.identify(original);
|
|
23
|
+
|
|
24
|
+
if (type === Types.isArray) {
|
|
25
|
+
copy = [ ];
|
|
26
|
+
|
|
27
|
+
// Traversal construction with recursion.
|
|
28
|
+
for (let item of original) {
|
|
29
|
+
let next = this.recursiveCopy(item);
|
|
30
|
+
copy.push(next);
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
return copy;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
if (type === Types.isMap) {
|
|
37
|
+
copy = new Map();
|
|
38
|
+
|
|
39
|
+
// Traversal construction with recursion.
|
|
40
|
+
for (let entry of original.entries()) {
|
|
41
|
+
let next = this.recursiveCopy(entry);
|
|
42
|
+
copy.set(next[0], next[1]);
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
return copy;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
if (type === Types.isSet) {
|
|
49
|
+
copy = new Set();
|
|
50
|
+
|
|
51
|
+
// Traversal construction with recursion.
|
|
52
|
+
for (let value of original.values()) {
|
|
53
|
+
let next = this.recursiveCopy(value);
|
|
54
|
+
copy.add(next);
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
return copy;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
if (type === Types.isDate) {
|
|
61
|
+
copy = new Date(original);
|
|
62
|
+
return copy;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
// Actually copying isn't needed (or desirable) here,
|
|
66
|
+
// since should always point to same thing regardless.
|
|
67
|
+
if (type === Types.isClass) {
|
|
68
|
+
copy = original;
|
|
69
|
+
return copy;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
// The workaround here makes a true independent copy of the
|
|
73
|
+
// original function, regardless of its definition style.
|
|
74
|
+
if (type === Types.isFunction) {
|
|
75
|
+
let passer = [ original ];
|
|
76
|
+
passer = [ ...passer ];
|
|
77
|
+
copy = passer[0];
|
|
78
|
+
|
|
79
|
+
return copy;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
if (original instanceof Object) {
|
|
83
|
+
// If original has a prototype, it's probably a class instance,
|
|
84
|
+
// so it's constructed, so it includes all methods and accessors.
|
|
85
|
+
let prototype = Object.getPrototypeOf(original);
|
|
86
|
+
copy = prototype !== null ? new prototype.constructor() : { };
|
|
87
|
+
|
|
88
|
+
let keys = Object.keys(original);
|
|
89
|
+
|
|
90
|
+
// Settable properties are added, with recursion.
|
|
91
|
+
for (let key of Object.keys(original)) {
|
|
92
|
+
let next = this.recursiveCopy(original[key]);
|
|
93
|
+
copy[key] = next;
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
return copy;
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
/* &cruft, other object types here */
|
|
100
|
+
|
|
101
|
+
// All object types exhausted, so this is a value,
|
|
102
|
+
// which can be used directly for a copy.
|
|
103
|
+
copy = original;
|
|
104
|
+
return copy;
|
|
105
|
+
}
|
|
106
|
+
}
|
package/system/TypeAnalyzer.js
CHANGED
|
@@ -1,103 +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
|
-
}
|
|
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
|
+
}
|