@lumjs/tests 1.6.0 → 1.7.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.
@@ -1,10 +1,10 @@
1
1
  // A functional interface to the test library.
2
- const Test = require('./test');
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,N,isObj,isArray,needs,def} = types;
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
- if (typeof opts === N)
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
- if (typeof opts.id === S)
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 {string} skippedReason - If the test was skipped, why?
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 an `is` test.
18
- * @property {*} [details.wanted] The value that was expectged in an `is` test.
19
- * @property {*} [details.stringify] If `true` then output the details as JSON.
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 {module:@lumjs/tests/test} test - The parent `Test` instance.
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.skippedReason = '';
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.skippedReason;
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 += `## ${line}\n`;
110
+ out += `# - ${line}\n`;
105
111
  }
106
112
  }
107
113