@lumjs/tests 1.6.0 → 1.7.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/CHANGELOG.md +32 -2
- package/TODO.md +2 -3
- package/bin/lumtest.js +65 -0
- package/lib/grammar/README.md +6 -0
- package/lib/grammar/tap.js +996 -0
- package/lib/harness/browser.js +18 -0
- package/lib/harness/errors.js +44 -0
- package/lib/harness/index.js +260 -0
- package/lib/harness/node.js +71 -0
- package/lib/harness/parser.js +153 -0
- package/lib/harness/plugin.js +77 -0
- package/lib/harness/queuedtest.js +14 -0
- package/lib/index.js +19 -14
- package/lib/{functional.js → test/functional.js} +4 -4
- package/lib/{test.js → test/index.js} +10 -309
- package/lib/{log.js → test/log.js} +14 -8
- package/lib/test/stats.js +385 -0
- package/package.json +22 -13
- package/lib/harness.js +0 -25
- package/test/basics.js +0 -50
- package/test/data/people.js +0 -58
- package/test/dies.js +0 -17
- package/test/functional_basics.js +0 -54
- package/test/functional_dies.js +0 -17
- package/test/functional_isa.js +0 -23
- package/test/inc/basics.js +0 -72
- package/test/inc/dies.js +0 -78
- package/test/inc/isa.js +0 -110
- package/test/isa.js +0 -23
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
// A functional interface to the test library.
|
|
2
|
-
const Test = require('./
|
|
2
|
+
const Test = require('./index');
|
|
3
3
|
|
|
4
4
|
/**
|
|
5
5
|
* A new test instance and a set of functions wrapping it.
|
|
6
6
|
*
|
|
7
|
-
* @typedef {object} module:@lumjs/tests/functional.Functional
|
|
7
|
+
* @typedef {object} module:@lumjs/tests/test/functional.Functional
|
|
8
8
|
* @property {Test} test - The new test instance.
|
|
9
9
|
*
|
|
10
10
|
* All of the rest of the properties are functions that
|
|
@@ -45,9 +45,9 @@ const Test = require('./test');
|
|
|
45
45
|
* likely not useful for most end users, as knowledge of the internals is
|
|
46
46
|
* required to make the functional API work.
|
|
47
47
|
*
|
|
48
|
-
* @returns {module:@lumjs/tests/functional.Functional}
|
|
48
|
+
* @returns {module:@lumjs/tests/test/functional.Functional}
|
|
49
49
|
*
|
|
50
|
-
* @exports module:@lumjs/tests/functional
|
|
50
|
+
* @exports module:@lumjs/tests/test/functional
|
|
51
51
|
*/
|
|
52
52
|
function functional(opts={}, testClass=Test)
|
|
53
53
|
{
|
|
@@ -1,8 +1,7 @@
|
|
|
1
1
|
const core = require('@lumjs/core');
|
|
2
2
|
const {types,obj} = core;
|
|
3
|
-
const {F,S,
|
|
4
|
-
|
|
5
|
-
// We use a separate class to represent test logs.
|
|
3
|
+
const {F,S,isObj,isArray,needs,def} = types;
|
|
4
|
+
const Stats = require('./stats');
|
|
6
5
|
const Log = require('./log');
|
|
7
6
|
|
|
8
7
|
// A list of Test methods that return Log objects.
|
|
@@ -41,16 +40,10 @@ function $call (testfunc, args)
|
|
|
41
40
|
* Raku's Test libraries.
|
|
42
41
|
*
|
|
43
42
|
* @exports module:@lumjs/tests/test
|
|
43
|
+
* @extends module:@lumjs/tests/test~Base
|
|
44
44
|
*
|
|
45
|
-
* @property {number} planned - Number of tests planned, `0` if unplanned.
|
|
46
|
-
* @property {number} failed - Number of tests that failed.
|
|
47
|
-
* @property {number} skipped - Number of tests that were skipped.
|
|
48
|
-
* @property {number} ran - Number of tests ran (*calculated*).
|
|
49
|
-
* @property {string} id - Unique test id used by `Harness` libary.
|
|
50
|
-
* @property {boolean} isTop - Test module was loaded from the command line.
|
|
51
|
-
* @property {?object} harness - The top-level `Harness` if one was found.
|
|
52
45
|
*/
|
|
53
|
-
class Test
|
|
46
|
+
class Test extends Stats
|
|
54
47
|
{
|
|
55
48
|
/**
|
|
56
49
|
* Build a new Test instance.
|
|
@@ -73,68 +66,11 @@ class Test
|
|
|
73
66
|
*
|
|
74
67
|
*/
|
|
75
68
|
constructor (opts={})
|
|
76
|
-
{
|
|
77
|
-
|
|
78
|
-
{
|
|
79
|
-
opts = {plan: opts};
|
|
80
|
-
}
|
|
81
|
-
else if (typeof opts === S)
|
|
82
|
-
{
|
|
83
|
-
opts = {id: opts};
|
|
84
|
-
}
|
|
85
|
-
|
|
86
|
-
const hasModule = isObj(opts.module);
|
|
69
|
+
{ // First call the Base constructor.
|
|
70
|
+
super(opts);
|
|
87
71
|
|
|
88
|
-
|
|
89
|
-
{ // A specific id was specified.
|
|
90
|
-
this.id = opts.id;
|
|
91
|
-
}
|
|
92
|
-
else if (hasModule)
|
|
93
|
-
{ // We're going to generate a simple name.
|
|
94
|
-
this.id = core.modules.name(opts.module, opts.moduleName);
|
|
95
|
-
}
|
|
96
|
-
else
|
|
97
|
-
{ // An anonymous test.
|
|
98
|
-
this.id = null;
|
|
99
|
-
}
|
|
100
|
-
|
|
101
|
-
this.stringifyDepth = opts.stringify ?? 1;
|
|
102
|
-
|
|
103
|
-
this.failed = 0;
|
|
104
|
-
this.skipped = 0;
|
|
105
|
-
this.planned = 0;
|
|
106
|
-
this.log = [];
|
|
107
|
-
|
|
108
|
-
// These three will be updated below if possible.
|
|
109
|
-
this.isTop = false;
|
|
110
|
-
this.harness = null;
|
|
111
|
-
|
|
112
|
-
// Methods that can be ran via run().
|
|
72
|
+
// Now register methods that can be ran via run().
|
|
113
73
|
this.$testMethods = TEST_METHODS.slice();
|
|
114
|
-
|
|
115
|
-
if (typeof opts.plan === N)
|
|
116
|
-
{
|
|
117
|
-
this.plan(opts.plan);
|
|
118
|
-
}
|
|
119
|
-
|
|
120
|
-
if (hasModule)
|
|
121
|
-
{ // If a module was passed, its going to export this test.
|
|
122
|
-
opts.module.exports = this;
|
|
123
|
-
// We'll also use the module to determine if we're Harnessed or not.
|
|
124
|
-
if (require.main === opts.module)
|
|
125
|
-
{ // Was called directly.
|
|
126
|
-
this.isTop = true;
|
|
127
|
-
}
|
|
128
|
-
}
|
|
129
|
-
|
|
130
|
-
if (!this.isTop)
|
|
131
|
-
{ // Try to find a Harness instance.
|
|
132
|
-
if (isObj(require.main) && require.main.exports instanceof Harness)
|
|
133
|
-
{ // We found the Harness instance.
|
|
134
|
-
this.harness = require.main.exports;
|
|
135
|
-
}
|
|
136
|
-
}
|
|
137
|
-
|
|
138
74
|
}
|
|
139
75
|
|
|
140
76
|
/**
|
|
@@ -160,84 +96,6 @@ class Test
|
|
|
160
96
|
return require('./functional')(opts, this);
|
|
161
97
|
}
|
|
162
98
|
|
|
163
|
-
// A wrapper around types.stringify()
|
|
164
|
-
stringify(what)
|
|
165
|
-
{
|
|
166
|
-
return types.stringify(what, this.stringifyDepth);
|
|
167
|
-
}
|
|
168
|
-
|
|
169
|
-
/**
|
|
170
|
-
* Indicate how many tests are planned to be run in this set.
|
|
171
|
-
*
|
|
172
|
-
* @param {number} num - The number of tests that should run.
|
|
173
|
-
*/
|
|
174
|
-
plan (num)
|
|
175
|
-
{
|
|
176
|
-
if (typeof num === N)
|
|
177
|
-
{
|
|
178
|
-
this.planned = num;
|
|
179
|
-
}
|
|
180
|
-
else if (num === false)
|
|
181
|
-
{
|
|
182
|
-
this.planned = 0;
|
|
183
|
-
}
|
|
184
|
-
else
|
|
185
|
-
{
|
|
186
|
-
throw new Error("Invalid value passed to plan()");
|
|
187
|
-
}
|
|
188
|
-
}
|
|
189
|
-
|
|
190
|
-
/**
|
|
191
|
-
* Check if a value is truthy, and add a log indicating the result.
|
|
192
|
-
*
|
|
193
|
-
* This is the absolute most basic method that every other testing method
|
|
194
|
-
* uses to log the results.
|
|
195
|
-
*
|
|
196
|
-
* I won't document the `desc` and `directive` parameters on any of the
|
|
197
|
-
* other methods as they are exactly the same as here.
|
|
198
|
-
*
|
|
199
|
-
* @param {*} test - Any value, usually the output of a test function.
|
|
200
|
-
* If the value evaluates as `true` (aka a truthy value), the test passes.
|
|
201
|
-
* If it evaluates as `false` (a falsey value), the test fails.
|
|
202
|
-
*
|
|
203
|
-
* @param {string} [desc] A short description of the test.
|
|
204
|
-
* @param {(string|Error)} [directive] Further information for the log.
|
|
205
|
-
* @param {object} [details] Extra details to add to the log.
|
|
206
|
-
* @returns {Log} The test log with the results.
|
|
207
|
-
*/
|
|
208
|
-
ok (test, desc, directive, details)
|
|
209
|
-
{
|
|
210
|
-
const log = new Log(this);
|
|
211
|
-
|
|
212
|
-
if (test)
|
|
213
|
-
{
|
|
214
|
-
log.ok = true;
|
|
215
|
-
}
|
|
216
|
-
else
|
|
217
|
-
{
|
|
218
|
-
this.failed++;
|
|
219
|
-
}
|
|
220
|
-
|
|
221
|
-
if (typeof desc === S)
|
|
222
|
-
{
|
|
223
|
-
log.desc = desc;
|
|
224
|
-
}
|
|
225
|
-
|
|
226
|
-
if (directive)
|
|
227
|
-
{
|
|
228
|
-
log.directive = directive;
|
|
229
|
-
}
|
|
230
|
-
|
|
231
|
-
if (isObj(details))
|
|
232
|
-
{
|
|
233
|
-
log.details = details;
|
|
234
|
-
}
|
|
235
|
-
|
|
236
|
-
this.log.push(log);
|
|
237
|
-
|
|
238
|
-
return log;
|
|
239
|
-
}
|
|
240
|
-
|
|
241
99
|
/**
|
|
242
100
|
* Run a function and pass its return value to `ok()`.
|
|
243
101
|
*
|
|
@@ -256,30 +114,6 @@ class Test
|
|
|
256
114
|
return this.ok(ret.val, desc, ret.err);
|
|
257
115
|
}
|
|
258
116
|
|
|
259
|
-
/**
|
|
260
|
-
* Mark a test as failed.
|
|
261
|
-
*
|
|
262
|
-
* @param {string} desc
|
|
263
|
-
* @param {*} [directive]
|
|
264
|
-
* @returns {Log}
|
|
265
|
-
*/
|
|
266
|
-
fail (desc, directive)
|
|
267
|
-
{
|
|
268
|
-
return this.ok(false, desc, directive);
|
|
269
|
-
}
|
|
270
|
-
|
|
271
|
-
/**
|
|
272
|
-
* Mark a test as passed.
|
|
273
|
-
*
|
|
274
|
-
* @param {string} desc
|
|
275
|
-
* @param {*} [directive]
|
|
276
|
-
* @returns {Log}
|
|
277
|
-
*/
|
|
278
|
-
pass (desc, directive)
|
|
279
|
-
{
|
|
280
|
-
return this.ok(true, desc, directive);
|
|
281
|
-
}
|
|
282
|
-
|
|
283
117
|
/**
|
|
284
118
|
* See if a function throws an Error.
|
|
285
119
|
*
|
|
@@ -712,36 +546,6 @@ class Test
|
|
|
712
546
|
}
|
|
713
547
|
}
|
|
714
548
|
|
|
715
|
-
/**
|
|
716
|
-
* Skip a test.
|
|
717
|
-
*
|
|
718
|
-
* @param {?string} reason - Why the test was skipped.
|
|
719
|
-
* @param {string} desc
|
|
720
|
-
* @returns {Log}
|
|
721
|
-
*/
|
|
722
|
-
skip (reason, desc)
|
|
723
|
-
{
|
|
724
|
-
const log = this.ok(true, desc);
|
|
725
|
-
log.skipped = true;
|
|
726
|
-
if (typeof reason === S)
|
|
727
|
-
log.skippedReason = reason;
|
|
728
|
-
this.skipped++;
|
|
729
|
-
return log;
|
|
730
|
-
}
|
|
731
|
-
|
|
732
|
-
/**
|
|
733
|
-
* Add diagnostics info directly to our test logs.
|
|
734
|
-
*
|
|
735
|
-
* @param {*} msg - The info to add.
|
|
736
|
-
* If this is a `string` it will be displayed as a comment as is.
|
|
737
|
-
* If it is anything else, it will be encoded as JSON first.
|
|
738
|
-
*
|
|
739
|
-
*/
|
|
740
|
-
diag (msg)
|
|
741
|
-
{
|
|
742
|
-
this.log.push(msg);
|
|
743
|
-
}
|
|
744
|
-
|
|
745
549
|
/**
|
|
746
550
|
* Run an assortment of tests using a map.
|
|
747
551
|
*
|
|
@@ -814,109 +618,11 @@ class Test
|
|
|
814
618
|
return logs;
|
|
815
619
|
}
|
|
816
620
|
|
|
817
|
-
/**
|
|
818
|
-
* Return TAP formatted output for all the tests.
|
|
819
|
-
*
|
|
820
|
-
* @returns {string} The test logs, in TAP format.
|
|
821
|
-
*/
|
|
822
|
-
tap ()
|
|
823
|
-
{
|
|
824
|
-
let out = '';
|
|
825
|
-
if (this.planned > 0)
|
|
826
|
-
{
|
|
827
|
-
out += '1..'+this.planned+"\n";
|
|
828
|
-
}
|
|
829
|
-
let t = 1;
|
|
830
|
-
for (const log of this.log)
|
|
831
|
-
{
|
|
832
|
-
if (log instanceof Log)
|
|
833
|
-
{
|
|
834
|
-
out += log.tap(t++);
|
|
835
|
-
}
|
|
836
|
-
else
|
|
837
|
-
{ // A comment.
|
|
838
|
-
out += '# ' + (typeof log === S ? log : types.stringify(log)) + "\n";
|
|
839
|
-
}
|
|
840
|
-
}
|
|
841
|
-
if (this.skipped)
|
|
842
|
-
{
|
|
843
|
-
out += '# Skipped '+this.skipped+" tests\n";
|
|
844
|
-
}
|
|
845
|
-
if (this.failed)
|
|
846
|
-
{
|
|
847
|
-
out += '# Failed '+this.failed+(this.failed>1?' tests':' test');
|
|
848
|
-
if (this.planned)
|
|
849
|
-
out += ' out of '+this.planned;
|
|
850
|
-
out += "\n";
|
|
851
|
-
}
|
|
852
|
-
const ran = t-1;
|
|
853
|
-
if (this.planned > 0 && this.planned != ran)
|
|
854
|
-
{
|
|
855
|
-
out += '# Looks like you planned '+this.planned+' but ran '+ran+" tests\n";
|
|
856
|
-
}
|
|
857
|
-
return out;
|
|
858
|
-
}
|
|
859
|
-
|
|
860
|
-
/**
|
|
861
|
-
* A read-only *accessor* property alias for `tap()`.
|
|
862
|
-
* @returns {string}
|
|
863
|
-
* @see {@link module:@lumjs/tests/test#tap}
|
|
864
|
-
*/
|
|
865
|
-
get TAP()
|
|
866
|
-
{
|
|
867
|
-
return this.tap();
|
|
868
|
-
}
|
|
869
|
-
|
|
870
|
-
/**
|
|
871
|
-
* A calculated property of the number of tests that were ran.
|
|
872
|
-
* @type {int}
|
|
873
|
-
*/
|
|
874
|
-
get ran ()
|
|
875
|
-
{
|
|
876
|
-
let ran = 0;
|
|
877
|
-
for (const log of this.log)
|
|
878
|
-
{
|
|
879
|
-
if (log instanceof Log)
|
|
880
|
-
{
|
|
881
|
-
ran++;
|
|
882
|
-
}
|
|
883
|
-
}
|
|
884
|
-
return ran;
|
|
885
|
-
}
|
|
886
|
-
|
|
887
|
-
/**
|
|
888
|
-
* Send the TAP output to the `console`.
|
|
889
|
-
*
|
|
890
|
-
* This is a low-level method and is no longer recommended for use.
|
|
891
|
-
* Instead call the `done()` method, which will *do the right thing*.
|
|
892
|
-
*/
|
|
893
|
-
output ()
|
|
894
|
-
{
|
|
895
|
-
console.log(this.tap());
|
|
896
|
-
return this;
|
|
897
|
-
}
|
|
898
|
-
|
|
899
|
-
/**
|
|
900
|
-
* We're done testing.
|
|
901
|
-
*
|
|
902
|
-
* This will mark the test-set as finished, so attempting to run further
|
|
903
|
-
* tests after will result in a `RangeError` being thrown.
|
|
904
|
-
*
|
|
905
|
-
* If no `Harness` is in use, this will also run `this.output()`.
|
|
906
|
-
*/
|
|
907
|
-
done ()
|
|
908
|
-
{
|
|
909
|
-
if (this.$done)
|
|
910
|
-
{
|
|
911
|
-
throw new RangeError('Test set is already done');
|
|
912
|
-
}
|
|
913
|
-
this.$done = true;
|
|
914
|
-
|
|
915
|
-
return (this.harness ? this : this.output());
|
|
916
|
-
}
|
|
917
|
-
|
|
918
621
|
} // class Test
|
|
919
622
|
|
|
623
|
+
// May want this for sub-classes.
|
|
624
|
+
def(Test, 'Stats', Stats);
|
|
625
|
+
|
|
920
626
|
// Should never need this, but...
|
|
921
627
|
def(Test, 'Log', Log);
|
|
922
628
|
|
|
@@ -980,8 +686,3 @@ def(Test, '$METHODS',
|
|
|
980
686
|
|
|
981
687
|
// Export the class
|
|
982
688
|
module.exports = Test;
|
|
983
|
-
|
|
984
|
-
// Finally at the bottom after `module.exports` has been set, we will load
|
|
985
|
-
// the Harness class to avoid circular references failing.
|
|
986
|
-
const Harness = require('./harness');
|
|
987
|
-
|
|
@@ -9,27 +9,31 @@ const {S,O,isArray,stringify,def} = types;
|
|
|
9
9
|
*
|
|
10
10
|
* @property {boolean} ok - Did the test pass.
|
|
11
11
|
* @property {boolean} skipped - Was the test skipped?
|
|
12
|
-
* @property {
|
|
12
|
+
* @property {boolean} todo - Was the test marked TODO?
|
|
13
|
+
* @property {string} reason - If the test was skipped or TODO, why?
|
|
13
14
|
* @property {?string} desc - A short description of the test.
|
|
14
15
|
* @property {*} directive - Special directives describing the test.
|
|
15
16
|
* @property {object} details - Extra information about the test.
|
|
16
17
|
*
|
|
17
|
-
* @property {*} [details.got] The value that was received in
|
|
18
|
-
* @property {*} [details.wanted] The value that was expectged in
|
|
19
|
-
* @property {
|
|
18
|
+
* @property {*} [details.got] The value that was received in a test.
|
|
19
|
+
* @property {*} [details.wanted] The value that was expectged in a test.
|
|
20
|
+
* @property {string} [details.comparitor] The comparitor used in a test.
|
|
21
|
+
* @property {boolean} [details.stringify] If `true` then output the details as JSON.
|
|
22
|
+
* @property {object} [details.info] An optional array of extra information.
|
|
20
23
|
*
|
|
21
24
|
*/
|
|
22
25
|
class Log
|
|
23
26
|
{
|
|
24
27
|
/**
|
|
25
28
|
* (Internal Constructor)
|
|
26
|
-
* @param {
|
|
29
|
+
* @param {object} test - The parent `Test` or `Stats` instance.
|
|
27
30
|
*/
|
|
28
31
|
constructor (test)
|
|
29
32
|
{
|
|
30
33
|
this.ok = false;
|
|
31
34
|
this.skipped = false;
|
|
32
|
-
this.
|
|
35
|
+
this.todo = false;
|
|
36
|
+
this.reason = '';
|
|
33
37
|
this.desc = null;
|
|
34
38
|
this.directive = null;
|
|
35
39
|
this.details = {};
|
|
@@ -66,7 +70,9 @@ class Log
|
|
|
66
70
|
else if (typeof this.directive == O && this.directive instanceof Error)
|
|
67
71
|
out += ` # ${this.directive.name}: ${this.directive.message}`;
|
|
68
72
|
else if (this.skipped)
|
|
69
|
-
out += ' # SKIP ' + this.
|
|
73
|
+
out += ' # SKIP ' + this.reason;
|
|
74
|
+
else if (this.todo)
|
|
75
|
+
out += ' # TODO ' + this.reason;
|
|
70
76
|
|
|
71
77
|
out += "\n";
|
|
72
78
|
|
|
@@ -101,7 +107,7 @@ class Log
|
|
|
101
107
|
for (const i in info)
|
|
102
108
|
{
|
|
103
109
|
const line = (typeof info[i] === S) ? info[i] : stringify(info[i], SD);
|
|
104
|
-
out +=
|
|
110
|
+
out += `# - ${line}\n`;
|
|
105
111
|
}
|
|
106
112
|
}
|
|
107
113
|
|