@lumjs/tests 1.0.0 → 1.3.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/src/test.js DELETED
@@ -1,402 +0,0 @@
1
-
2
- const {F,S,N,isType,isInstance,def} = require('@lumjs/core').types;
3
-
4
- // We use a separate class to represent test logs.
5
- const Log = require('./log');
6
-
7
- /**
8
- * A simple testing library with TAP support.
9
- *
10
- * Based on Lum.php's Test library.
11
- * Which itself was based on Perl 5's Test::More, and
12
- * Raku's Test libraries.
13
- */
14
- class Test
15
- {
16
- /**
17
- * Build a new Test instance.
18
- *
19
- * @param {number} [plan] If used, passed to `plan()` method.
20
- *
21
- */
22
- constructor (plan)
23
- {
24
- this.failed = 0;
25
- this.skipped = 0;
26
- this.planned = 0;
27
- this.log = [];
28
- if (plan)
29
- {
30
- this.plan(plan);
31
- }
32
- }
33
-
34
- /**
35
- * Indicate how many tests are planned to be run in this set.
36
- *
37
- * @param {number} num - The number of tests that should run.
38
- */
39
- plan (num)
40
- {
41
- if (typeof num === N)
42
- {
43
- this.planned = num;
44
- }
45
- else if (num === false)
46
- {
47
- this.planned = 0;
48
- }
49
- else
50
- {
51
- throw new Error("Invalid value passed to plan()");
52
- }
53
- }
54
-
55
- /**
56
- * Check if a value is truthy, and add a log indicating the result.
57
- *
58
- * This is the absolute most basic method that every other testing method
59
- * uses to log the results.
60
- *
61
- * I won't document the `desc` and `directive` parameters on any of the
62
- * other methods as they are exactly the same as here.
63
- *
64
- * @param {*} test - Any value, usually the output of a test function.
65
- * If the value evaluates as `true` (aka a truthy value), the test passes.
66
- * If it evaluates as `false` (a falsey value), the test fails.
67
- *
68
- * @param {string} desc - A short description of the test.
69
- *
70
- * @param {(string|Error)} [directive] Further information for the log.
71
- *
72
- * @returns {Log} The test log with the results.
73
- */
74
- ok (test, desc, directive)
75
- {
76
- const log = new Log();
77
-
78
- if (test)
79
- {
80
- log.ok = true;
81
- }
82
- else
83
- {
84
- this.failed++;
85
- }
86
-
87
- if (typeof desc === S)
88
- {
89
- log.desc = desc;
90
- }
91
-
92
- if (directive)
93
- {
94
- log.directive = directive;
95
- }
96
-
97
- this.log.push(log);
98
-
99
- return log;
100
- }
101
-
102
- /**
103
- * Mark a test as failed.
104
- *
105
- * @param {string} desc
106
- * @param {*} [directive]
107
- * @returns {Log}
108
- */
109
- fail (desc, directive)
110
- {
111
- return this.ok(false, desc, directive);
112
- }
113
-
114
- /**
115
- * Mark a test as passed.
116
- *
117
- * @param {string} desc
118
- * @param {*} [directive]
119
- * @returns {Log}
120
- */
121
- pass (desc, directive)
122
- {
123
- return this.ok(true, desc, directive);
124
- }
125
-
126
- /**
127
- * See if a function throws an Error.
128
- *
129
- * The function will be called in a `try { } catch (err) { }` block.
130
- *
131
- * If an error is caught, the test will be considered to have passed,
132
- * and the `Error` object will be used as the `directive` in the `ok()`
133
- * call. If no error is caught the test will be considered to have failed.
134
- *
135
- * @param {function} testfunc
136
- * @param {string} desc
137
- * @returns {Log}
138
- */
139
- dies (testfunc, desc)
140
- {
141
- let ok = false;
142
- let err;
143
- try { testfunc(); }
144
- catch (e)
145
- {
146
- ok = true;
147
- err = e;
148
- }
149
- return this.ok(ok, desc, err);
150
- }
151
-
152
- /**
153
- * See if a value is what we expect it to be.
154
- *
155
- * @param {*} got - The result value from the test function.
156
- * @param {*} want - The value we expected from the test function.
157
- * @param {string} comp - A comparitor to test with.
158
- *
159
- * - `===`, `is` (See also: `is()`)
160
- * - `!==`, `isnt` (See also: `isnt()`)
161
- * - `==`, `eq`
162
- * - `!=`, `ne`
163
- * - `>`, `gt`
164
- * - `<`, `lt`
165
- * - `>=`, `ge`, `gte`
166
- * - `<=`, `le`, `lte`
167
- *
168
- * @param {string} desc
169
- * @param {boolean} [stringify=true] Stringify values in TAP output?
170
- * @returns {Log}
171
- */
172
- cmp (got, want, comp, desc, stringify=true)
173
- {
174
- let test;
175
- switch(comp)
176
- {
177
- case 'is':
178
- case '===':
179
- test = (got === want);
180
- break;
181
- case 'isnt':
182
- case '!==':
183
- test = (got !== want);
184
- break;
185
- case 'eq':
186
- case '==':
187
- test = (got == want);
188
- break;
189
- case 'ne':
190
- case '!=':
191
- test = (got != want);
192
- break;
193
- case 'lt':
194
- case '<':
195
- test = (got < want);
196
- break;
197
- case '>':
198
- case 'gt':
199
- test = (got > want);
200
- break;
201
- case 'le':
202
- case 'lte':
203
- case '<=':
204
- test = (got <= want);
205
- break;
206
- case 'ge':
207
- case 'gte':
208
- case '>=':
209
- test = (got >= want);
210
- break;
211
- default:
212
- test = false;
213
- }
214
-
215
- const log = this.ok(test, desc);
216
- if (!test)
217
- {
218
- log.details.got = got;
219
- log.details.wanted = want;
220
- log.details.stringify = stringify;
221
- log.details.comparitor = comp;
222
- }
223
- return log;
224
- }
225
-
226
- /**
227
- * See if two values are equal.
228
- *
229
- * The same as using `cmp()` with the `===` comparitor.
230
- *
231
- * @param {*} got
232
- * @param {*} want
233
- * @param {string} desc
234
- * @param {boolean} [stringify=true]
235
- * @returns {Log}
236
- */
237
- is (got, want, desc, stringify=true)
238
- {
239
- return this.cmp(got, want, '===', desc, stringify);
240
- }
241
-
242
- /**
243
- * See if two values are NOT equal.
244
- *
245
- * The same as using `cmp()` with the `!==` comparitor.
246
- *
247
- * @param {*} got - The result value from the test function.
248
- * @param {*} want - The value we expected from the test function.
249
- * @param {string} desc
250
- * @param {boolean} [stringify=true] Use JSON details in TAP output?
251
- * @returns {Log}
252
- */
253
- isnt (got, want, desc, stringify=true)
254
- {
255
- return this.cmp(got, want, '!==', desc, stringify);
256
- }
257
-
258
- /**
259
- * See if a value is of a certain type.
260
- *
261
- * @param {*} got
262
- * @param {(string|function)} want - A type name, or a constructor function.
263
- *
264
- * This uses two type checking functions from `@lumsj/core`.
265
- * If this is a string, we use the `isType()` function.
266
- * If this is a constructor function, we use the `isInstance()` function.
267
- *
268
- * @param {string} desc
269
- * @param {boolean} [stringify=true]
270
- * @returns {Log}
271
- */
272
- isa (got, want, desc, stringify=true)
273
- {
274
- let test;
275
- if (typeof want === S)
276
- { // A string, we're going to use the isType function.
277
- test = isType(want, got);
278
- }
279
- else if (typeof want === F)
280
- { // Assuming it's a constructor.
281
- test = isInstance(got, want);
282
- }
283
- else
284
- { // That's not supported.
285
- throw new TypeError("'want' must be a string or a constructor");
286
- }
287
-
288
- const log = this.ok(test, desc);
289
- if (!test)
290
- {
291
- log.details.got = got;
292
- log.details.wanted = want;
293
- log.details.stringify = stringify;
294
- }
295
- return log;
296
- }
297
-
298
- /**
299
- * An `is()` test, but encode both values as JSON first.
300
- *
301
- * @param {*} got
302
- * @param {*} want
303
- * @param {string} desc
304
- * @returns
305
- */
306
- isJSON (got, want, desc)
307
- {
308
- got = JSON.stringify(got);
309
- want = JSON.stringify(want);
310
- return this.is(got, want, desc, false);
311
- }
312
-
313
- /**
314
- * Skip a test.
315
- *
316
- * @param {?string} reason - Why the test was skipped.
317
- * @param {string} desc
318
- * @returns {Log}
319
- */
320
- skip (reason, desc)
321
- {
322
- var log = this.ok(true, desc);
323
- log.skipped = true;
324
- if (typeof reason === S)
325
- log.skippedReason = reason;
326
- this.skipped++;
327
- return log;
328
- }
329
-
330
- /**
331
- * Add diagnostics info directly to our test logs.
332
- *
333
- * @param {*} msg - The info to add.
334
- * If this is a `string` it will be displayed as a comment as is.
335
- * If it is anything else, it will be encoded as JSON first.
336
- *
337
- */
338
- diag (msg)
339
- {
340
- this.log.push(msg);
341
- }
342
-
343
- /**
344
- * Return TAP formatted output for all the tests.
345
- *
346
- * @returns {string} The test logs, in TAP format.
347
- */
348
- tap ()
349
- {
350
- var out = '';
351
- if (this.planned > 0)
352
- {
353
- out += '1..'+this.planned+"\n";
354
- }
355
- var t = 1;
356
- for (var i = 0; i < this.log.length; i++)
357
- {
358
- var log = this.log[i];
359
- if (log instanceof Log)
360
- {
361
- out += log.tap(t++);
362
- }
363
- else
364
- { // A comment.
365
- out += '# ' + (typeof log === S ? log : JSON.stringify(log)) + "\n";
366
- }
367
- }
368
- if (this.skipped)
369
- {
370
- out += '# Skipped '+this.skipped+" tests\n";
371
- }
372
- if (this.failed)
373
- {
374
- out += '# Failed '+this.failed+(this.failed>1?' tests':' test');
375
- if (this.planned)
376
- out += ' out of '+this.planned;
377
- out += "\n";
378
- }
379
- var ran = t-1;
380
- if (this.planned > 0 && this.planned != ran)
381
- {
382
- out += '# Looks like you planned '+this.planned+' but ran '+ran+" tests\n";
383
- }
384
- return out;
385
- }
386
-
387
- /**
388
- * Send the TAP output to the `console`.
389
- */
390
- output ()
391
- {
392
- console.log(this.tap());
393
- return this;
394
- }
395
-
396
- } // class Test
397
-
398
- // Should never need this, but...
399
- def(Test, 'Log', Log);
400
-
401
- // Export the class
402
- module.exports = Test;