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.
- package/README.md +88 -46
- package/package.json +22 -8
- package/public/javascript/ASpoofingFixture.js +1 -1
- package/public/javascript/ChosenTestFinder.js +4 -3
- package/public/javascript/SpoofTuple.js +0 -1
- package/public/javascript/TerminalReporter.js +249 -222
- package/public/javascript/TestFrameChooser.js +95 -0
- package/public/javascript/TestFrames.js +180 -0
- package/public/javascript/TestRunner.js +37 -233
- package/public/javascript/TestTuple.js +13 -2
|
@@ -1,222 +1,249 @@
|
|
|
1
|
-
/**/
|
|
2
|
-
|
|
3
|
-
/* TerminalReporter is an ATestReporter that sends each result to the terminal / console for display. */
|
|
4
|
-
|
|
5
|
-
import { ATestReporter } from "./ATestReporter.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 chalk from "chalk";
|
|
13
|
-
|
|
14
|
-
export class TerminalReporter extends ATestReporter {
|
|
15
|
-
// region Private fields
|
|
16
|
-
|
|
17
|
-
/* Foreground-colors using dependency calls and hex. */
|
|
18
|
-
#trueWhite = chalk.hex("FFFFFF");
|
|
19
|
-
#trueBlack = chalk.hex("000000");
|
|
20
|
-
|
|
21
|
-
/* Background colors as hex for dependency
|
|
22
|
-
calls to use, needed syntactically. */
|
|
23
|
-
#blue = "0000CD";
|
|
24
|
-
#aqua = "00BFFF";
|
|
25
|
-
#paleGreen = "90EE90";
|
|
26
|
-
#paleRed = "F08080";
|
|
27
|
-
|
|
28
|
-
/* Full fore- and background color output styles. */
|
|
29
|
-
|
|
30
|
-
#classGroup = this.#trueWhite.bgHex(this.#blue).bold;
|
|
31
|
-
#methodGroup = this.#trueWhite.bgHex(this.#aqua).bold;
|
|
32
|
-
#passed = this.#trueBlack.bgHex(this.#paleGreen);
|
|
33
|
-
#failed = this.#trueBlack.bgHex(this.#paleRed);
|
|
34
|
-
#passedSummary = this.#trueBlack.bgHex(this.#paleGreen).bold;
|
|
35
|
-
#failedSummary = this.#trueBlack.bgHex(this.#paleRed).bold;
|
|
36
|
-
#summary = chalk.hex("000080").bgHex("FAFAD2").bold;
|
|
37
|
-
|
|
38
|
-
// Count of characters used for indent
|
|
39
|
-
// and text to the left of each test.
|
|
40
|
-
#preUsedWidth = 20;
|
|
41
|
-
|
|
42
|
-
// endregion PrivateFields
|
|
43
|
-
|
|
44
|
-
// region ATestReporter
|
|
45
|
-
|
|
46
|
-
reportNext(result) {
|
|
47
|
-
// The next result introduces a group of tests.
|
|
48
|
-
if (result instanceof TestGroup) {
|
|
49
|
-
this.reportGroup(result);
|
|
50
|
-
return;
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
// The next result is from one test.
|
|
54
|
-
if (result instanceof TestResult) {
|
|
55
|
-
this.#reportTestResult(result);
|
|
56
|
-
return;
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
// The next result is the summary of all tests.
|
|
60
|
-
if (result instanceof TestSummary) {
|
|
61
|
-
this.reportSummary(result);
|
|
62
|
-
return;
|
|
63
|
-
}
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
reportGroup(result) {
|
|
67
|
-
if (result instanceof ClassTestGroup) {
|
|
68
|
-
console.log(this.#classGroup(` ${ result.group }: `));
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
if (result instanceof MethodTestGroup) {
|
|
72
|
-
console.log(" " + this.#methodGroup(` ${ result.group }(): `));
|
|
73
|
-
}
|
|
74
|
-
}
|
|
75
|
-
|
|
76
|
-
// region Private dependencies of reportNext()
|
|
77
|
-
|
|
78
|
-
#reportTestResult(result) {
|
|
79
|
-
if (result.didPass) {
|
|
80
|
-
this.reportPassed(result);
|
|
81
|
-
}
|
|
82
|
-
|
|
83
|
-
if (!result.didPass) {
|
|
84
|
-
this.reportFailed(result);
|
|
85
|
-
}
|
|
86
|
-
}
|
|
87
|
-
|
|
88
|
-
// endregion Private dependencies of reportNext()
|
|
89
|
-
|
|
90
|
-
reportPassed(result) {
|
|
91
|
-
this.#reportOneTestResult(result, "Passed", this.#passed);
|
|
92
|
-
}
|
|
93
|
-
|
|
94
|
-
reportFailed(result) {
|
|
95
|
-
this.#reportOneTestResult(result, "Failed", this.#failed);
|
|
96
|
-
}
|
|
97
|
-
|
|
98
|
-
// region Private dependencies of reportPassed() and reportFailed()
|
|
99
|
-
|
|
100
|
-
/* cruft, changes here
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
let
|
|
133
|
-
=
|
|
134
|
-
+ result.
|
|
135
|
-
+ result.
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
let
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
1
|
+
/**/
|
|
2
|
+
|
|
3
|
+
/* TerminalReporter is an ATestReporter that sends each result to the terminal / console for display. */
|
|
4
|
+
|
|
5
|
+
import { ATestReporter } from "./ATestReporter.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 chalk from "chalk";
|
|
13
|
+
|
|
14
|
+
export class TerminalReporter extends ATestReporter {
|
|
15
|
+
// region Private fields
|
|
16
|
+
|
|
17
|
+
/* Foreground-colors using dependency calls and hex. */
|
|
18
|
+
#trueWhite = chalk.hex("FFFFFF");
|
|
19
|
+
#trueBlack = chalk.hex("000000");
|
|
20
|
+
|
|
21
|
+
/* Background colors as hex for dependency
|
|
22
|
+
calls to use, needed syntactically. */
|
|
23
|
+
#blue = "0000CD";
|
|
24
|
+
#aqua = "00BFFF";
|
|
25
|
+
#paleGreen = "90EE90";
|
|
26
|
+
#paleRed = "F08080";
|
|
27
|
+
|
|
28
|
+
/* Full fore- and background color output styles. */
|
|
29
|
+
|
|
30
|
+
#classGroup = this.#trueWhite.bgHex(this.#blue).bold;
|
|
31
|
+
#methodGroup = this.#trueWhite.bgHex(this.#aqua).bold;
|
|
32
|
+
#passed = this.#trueBlack.bgHex(this.#paleGreen);
|
|
33
|
+
#failed = this.#trueBlack.bgHex(this.#paleRed);
|
|
34
|
+
#passedSummary = this.#trueBlack.bgHex(this.#paleGreen).bold;
|
|
35
|
+
#failedSummary = this.#trueBlack.bgHex(this.#paleRed).bold;
|
|
36
|
+
#summary = chalk.hex("000080").bgHex("FAFAD2").bold;
|
|
37
|
+
|
|
38
|
+
// Count of characters used for indent
|
|
39
|
+
// and text to the left of each test.
|
|
40
|
+
#preUsedWidth = 20;
|
|
41
|
+
|
|
42
|
+
// endregion PrivateFields
|
|
43
|
+
|
|
44
|
+
// region ATestReporter
|
|
45
|
+
|
|
46
|
+
reportNext(result) {
|
|
47
|
+
// The next result introduces a group of tests.
|
|
48
|
+
if (result instanceof TestGroup) {
|
|
49
|
+
this.reportGroup(result);
|
|
50
|
+
return;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
// The next result is from one test.
|
|
54
|
+
if (result instanceof TestResult) {
|
|
55
|
+
this.#reportTestResult(result);
|
|
56
|
+
return;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
// The next result is the summary of all tests.
|
|
60
|
+
if (result instanceof TestSummary) {
|
|
61
|
+
this.reportSummary(result);
|
|
62
|
+
return;
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
reportGroup(result) {
|
|
67
|
+
if (result instanceof ClassTestGroup) {
|
|
68
|
+
console.log(this.#classGroup(` ${ result.group }: `));
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
if (result instanceof MethodTestGroup) {
|
|
72
|
+
console.log(" " + this.#methodGroup(` ${ result.group }(): `));
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
// region Private dependencies of reportNext()
|
|
77
|
+
|
|
78
|
+
#reportTestResult(result) {
|
|
79
|
+
if (result.didPass) {
|
|
80
|
+
this.reportPassed(result);
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
if (!result.didPass) {
|
|
84
|
+
this.reportFailed(result);
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
// endregion Private dependencies of reportNext()
|
|
89
|
+
|
|
90
|
+
reportPassed(result) {
|
|
91
|
+
this.#reportOneTestResult(result, "Passed", this.#passed);
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
reportFailed(result) {
|
|
95
|
+
this.#reportOneTestResult(result, "Failed", this.#failed);
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
// region Private dependencies of reportPassed() and reportFailed()
|
|
99
|
+
|
|
100
|
+
/* &cruft, changes here / in dependencies
|
|
101
|
+
for better splitting to multiple lines */
|
|
102
|
+
#reportOneTestResult(result, net, styler) {
|
|
103
|
+
let { lineOne, lineTwo, lineThree, lineFour } = this.#calculateResultDisplay(result);
|
|
104
|
+
|
|
105
|
+
console.log(
|
|
106
|
+
"\t" + styler(` ${ net }: ${ lineOne }`)
|
|
107
|
+
);
|
|
108
|
+
|
|
109
|
+
if (lineTwo) {
|
|
110
|
+
console.log(
|
|
111
|
+
"\t\t " + styler(` ${ lineTwo }`)
|
|
112
|
+
);
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
if (lineThree) {
|
|
116
|
+
console.log(
|
|
117
|
+
"\t\t " + styler(` ${ lineThree }`)
|
|
118
|
+
);
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
if (lineFour) {
|
|
122
|
+
console.log(
|
|
123
|
+
"\t\t " + styler(` ${ lineFour }`)
|
|
124
|
+
);
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
#calculateResultDisplay(result) {
|
|
129
|
+
/* Getting lengths to determine if output should
|
|
130
|
+
* be split to multiple lines to fit the window. */
|
|
131
|
+
|
|
132
|
+
let forInputsLength
|
|
133
|
+
= this.#preUsedWidth
|
|
134
|
+
+ result.identityText.length
|
|
135
|
+
+ result.inputsText.length;
|
|
136
|
+
|
|
137
|
+
let allLength
|
|
138
|
+
= forInputsLength
|
|
139
|
+
+ result.expectedText.length
|
|
140
|
+
+ result.actualText.length;
|
|
141
|
+
|
|
142
|
+
let forOutputsLength
|
|
143
|
+
= this.#preUsedWidth
|
|
144
|
+
+ result.expectedText.length
|
|
145
|
+
+ result.actualText.length;
|
|
146
|
+
|
|
147
|
+
/* Splitting as much as is needed. */
|
|
148
|
+
|
|
149
|
+
let identityText = result.identityText;
|
|
150
|
+
let inputsText = result.inputsText;
|
|
151
|
+
let expectedText = result.expectedText;
|
|
152
|
+
let actualText = result.actualText;
|
|
153
|
+
|
|
154
|
+
if (forOutputsLength >= process.stdout.columns) {
|
|
155
|
+
return this.#fourLineTactic(identityText, inputsText, expectedText, actualText);
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
if (forInputsLength >= process.stdout.columns) {
|
|
159
|
+
return this.#threeLineTactic(identityText, inputsText, expectedText, actualText);
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
if (allLength >= process.stdout.columns) {
|
|
163
|
+
return this.#twoLineTactic(identityText, inputsText, expectedText, actualText);
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
return this.#oneLineTactic(identityText, inputsText, expectedText, actualText);
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
// region Private dependencies of #calculateResultDisplay()
|
|
170
|
+
|
|
171
|
+
#fourLineTactic(identityText, inputsText, expectedText, actualText) {
|
|
172
|
+
// Each line on its own.
|
|
173
|
+
let lineOne = identityText;
|
|
174
|
+
let lineTwo = inputsText;
|
|
175
|
+
let lineThree = expectedText;
|
|
176
|
+
let lineFour = actualText;
|
|
177
|
+
|
|
178
|
+
return { lineOne, lineTwo, lineThree, lineFour };
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
#threeLineTactic(identityText, inputsText, expectedText, actualText) {
|
|
182
|
+
// Each line, with two spaces between phrases on same line.
|
|
183
|
+
let lineOne = identityText;
|
|
184
|
+
let lineTwo = inputsText;
|
|
185
|
+
let lineThree = expectedText + " " + actualText;
|
|
186
|
+
|
|
187
|
+
// Left undefined.
|
|
188
|
+
let lineFour;
|
|
189
|
+
|
|
190
|
+
return { lineOne, lineTwo, lineThree, lineFour };
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
#twoLineTactic(identityText, inputsText, expectedText, actualText) {
|
|
194
|
+
// Each line, with two spaces between phrases on same line.
|
|
195
|
+
let lineOne = identityText + " " + inputsText;
|
|
196
|
+
let lineTwo = expectedText + " " + actualText;
|
|
197
|
+
|
|
198
|
+
// Left undefined.
|
|
199
|
+
let lineThree, lineFour;
|
|
200
|
+
|
|
201
|
+
return { lineOne, lineTwo, lineThree, lineFour };
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
#oneLineTactic(identityText, inputsText, expectedText, actualText) {
|
|
205
|
+
// Single line, with two spaces between all phrases.
|
|
206
|
+
let lineOne
|
|
207
|
+
= identityText
|
|
208
|
+
+ " "
|
|
209
|
+
+ inputsText
|
|
210
|
+
+ " "
|
|
211
|
+
+ expectedText
|
|
212
|
+
+ " "
|
|
213
|
+
+ actualText;
|
|
214
|
+
|
|
215
|
+
// Left undefined.
|
|
216
|
+
let lineTwo, lineThree, lineFour;
|
|
217
|
+
|
|
218
|
+
return { lineOne, lineTwo, lineThree, lineFour };
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
// endregion Private dependencies of #calculateResultDisplay()
|
|
222
|
+
|
|
223
|
+
// endregion Private dependencies of reportPassed() and reportFailed()
|
|
224
|
+
|
|
225
|
+
reportSummary(summary) {
|
|
226
|
+
console.log();
|
|
227
|
+
|
|
228
|
+
if (summary.anyWereRun) {
|
|
229
|
+
if (summary.allDidPass) {
|
|
230
|
+
console.log(this.#passedSummary(this.#toFullWidth(" Test run succeeded.")));
|
|
231
|
+
}
|
|
232
|
+
else {
|
|
233
|
+
console.log(this.#failedSummary(this.#toFullWidth(" Test run failed.")));
|
|
234
|
+
}
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
console.log(this.#summary(this.#toFullWidth(` ${ summary.summary }`)));
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
#toFullWidth(text) {
|
|
241
|
+
text = text || "";
|
|
242
|
+
let width = process.stdout.columns;
|
|
243
|
+
|
|
244
|
+
return text.padEnd(width, "\u00A0");
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
// endregion ATestReporter
|
|
248
|
+
|
|
249
|
+
}
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
/**/
|
|
2
|
+
|
|
3
|
+
export class TestFrameChooser {
|
|
4
|
+
// Used for special test cases.
|
|
5
|
+
constructorName = "constructor";
|
|
6
|
+
staticName = "static";
|
|
7
|
+
throwName = "throw";
|
|
8
|
+
|
|
9
|
+
frames;
|
|
10
|
+
|
|
11
|
+
constructor(frameSource) /* verified */ {
|
|
12
|
+
this.frames = frameSource;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
supplyTestFrame(test) /* passed */ {
|
|
16
|
+
// If `.and` includes "static", a call of a static member
|
|
17
|
+
// is made, and the actual is its return value.
|
|
18
|
+
if (this.doesAddressStatics(test)) {
|
|
19
|
+
if (this.isThrowTest(test)) {
|
|
20
|
+
return this.frames.testThrowResultAfterStaticCall;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
// If .from, a static call is made, then the actual is
|
|
24
|
+
// retrieved from a named code element or custom code.
|
|
25
|
+
if (this.isRetrievalTest(test)) {
|
|
26
|
+
return this.frames.testCodeElementAfterStaticCall;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
// Otherwise, the return value
|
|
30
|
+
// of the static call is used.
|
|
31
|
+
return this.frames.testReturnValueOfStaticCall;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
// Constructors are a special case; no second call should
|
|
35
|
+
// be made, and actual must be retrieved from property.
|
|
36
|
+
if (test.of === this.constructorName) {
|
|
37
|
+
return this.frames.testCodeElementAfterConstruction;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
if (this.isThrowTest(test)) {
|
|
41
|
+
return this.frames.testThrowResultAfterCall;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
// If .from, a call of the target is made, then the actual
|
|
45
|
+
// is retrieved from a named code element or custom code.
|
|
46
|
+
if (this.isRetrievalTest(test)) {
|
|
47
|
+
return this.frames.testCodeElementAfterCall;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
// The most common case: the target is called,
|
|
51
|
+
// and the actual is its return value.
|
|
52
|
+
return this.frames.testReturnValueOfCall;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
doesAddressStatics(test) /* passed */ {
|
|
56
|
+
if (typeof test.and === "string") {
|
|
57
|
+
if (test.and.includes(this.staticName)) {
|
|
58
|
+
return true;
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
return false;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
isThrowTest(test) /* passed */ {
|
|
66
|
+
if (typeof test.and === "string") {
|
|
67
|
+
if (test.and.includes(this.throwName)) {
|
|
68
|
+
return true;
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
return false;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
isRetrievalTest(test) /* passed */ {
|
|
76
|
+
// Falsy code elements never are a retrieval.
|
|
77
|
+
if (!test.from) {
|
|
78
|
+
return false;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
// If a (non-falsy) string, must be a retrieval.
|
|
82
|
+
if (typeof test.from === "string") {
|
|
83
|
+
return true;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
// If a function, is a retrieval.
|
|
87
|
+
if (test.from instanceof Function) {
|
|
88
|
+
return true;
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
// Anything else is not a retrieval.
|
|
92
|
+
return false;
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
}
|