Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(51)

Side by Side Diff: third_party/WebKit/LayoutTests/webaudio/resources/audio-testing.js

Issue 2872703004: Remove old Audit implementation (Closed)
Patch Set: Created 3 years, 7 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(Empty)
1 /* global self */
2
3 // testharness.js has the higher priority.
4 var TESTHARNESS = true;
5 var JSTEST = false;
6
7 (function () {
8 // Selected properies from testharness.js
9 var testharnessProperties = [
10 'test', 'async_test', 'promise_test', 'promise_rejects',
11 'generate_tests', 'setup', 'done', 'assert_true', 'assert_false'
12 ];
13
14 // Selected properties from js-test.js
15 var jsTestProperties = [
16 'isJsTest', 'testPassed', 'testFailed', 'gc', 'finishJSTest'
17 ];
18
19 // Check if testharness.js is properly loaded and set up a flag for it.
20 for (var name in testharnessProperties) {
21 if (!self.hasOwnProperty(testharnessProperties[name])) {
22 TESTHARNESS = false;
23 break;
24 }
25 }
26
27 // Immediately return here because testharness.js is ready.
28 if (TESTHARNESS)
29 return;
30
31 // Because testharness.js is not loaded, let us assume that js-test.js might
32 // be in use. Check if js-test.js is properly loaded and set up a flag for
33 // it.
34 JSTEST = true;
35 for (var name in jsTestProperties) {
36 if (!self.hasOwnProperty(jsTestProperties[name])) {
37 JSTEST = false;
38 break;
39 }
40 }
41
42 // If both are not loaded at all, throw here.
43 if (!JSTEST)
44 throw new Error('Cannot proceed. No test infrastructure is loaded.');
45 })();
46
47
48 // |Audit| is a task runner for web audio test. It makes asynchronous web audio
49 // testing simple and manageable.
50 //
51 // EXAMPLE:
52 //
53 // var audit = Audit.createTaskRunner();
54 // // Define test routine. Make sure to call done() when reached at the end.
55 // audit.defineTask('foo', function (done) {
56 // var context = new AudioContext();
57 // // do things
58 // context.oncomplete = function () {
59 // // verification here
60 // done();
61 // };
62 // });
63 //
64 // audit.defineTask('bar', function (done) {
65 // // your code here
66 // done();
67 // });
68 //
69 // // Queue tasks by readable task names.
70 // audit.runTasks('foo', 'bar');
71 //
72 // // Alternatively, if you want to run all of the defined tasks in the order in which they were
73 // // defined, use no arguments:
74 // audit.runTasks();
75 var Audit = (function () {
76
77 'use strict';
78
79 function Tasks() {
80 this.tasks = {};
81 this.queue = [];
82 this.currentTask = 0;
83 }
84
85 // This is to prime the task runner for the testharness.js async operation.
86 Tasks.prototype._initialize = function () {
87 if (TESTHARNESS) {
88 setup(new Function(), {
89 explicit_done: true
90 });
91 }
92 };
93
94 // Finalize the task runner by notifying testharness and testRunner that
95 // all the task is completed.
96 Tasks.prototype._finalize = function () {
97 if (TESTHARNESS) {
98 // From testharness.js
99 done();
100 }
101 };
102
103 Tasks.prototype.defineTask = function (taskName, taskFunc) {
104 // Check if there is a task defined with the same name. If found, do
105 // not add the task to the roster.
106 if (this.tasks.hasOwnProperty(taskName)) {
107 debug('>> Audit.defineTask:: Duplicate task definition. ("' + taskNa me + '")');
108 return;
109 }
110
111 this.tasks[taskName] = taskFunc;
112
113 // Push the task name in the order of definition.
114 this.queue.push(taskName);
115 };
116
117 // If arguments are given, only run the requested tasks. Check for any
118 // undefined or duplicate task in the requested task arguments. If there
119 // is no argument, run all the defined tasks.
120 Tasks.prototype.runTasks = function () {
121
122 this._initialize();
123
124 if (arguments.length > 0) {
125
126 // Reset task queue and refill it with the with the given arguments,
127 // in argument order.
128 this.queue = [];
129
130 for (var i = 0; i < arguments.length; i++) {
131 if (!this.tasks.hasOwnProperty(arguments[i]))
132 debug('>> Audit.runTasks:: Ignoring undefined task. ("' + ar guments[i] + '")');
133 else if (this.queue.indexOf(arguments[i]) > -1)
134 debug('>> Audit.runTasks:: Ignoring duplicate task request. ("' + arguments[i] + '")');
135 else
136 this.queue.push(arguments[i]);
137 }
138 }
139
140 if (this.queue.length === 0) {
141 debug('>> Audit.runTasks:: No task to run.');
142 return;
143 }
144
145 // taskDone() callback from each task. Increase the task index and call
146 // the next task. Note that explicit signaling by taskDone() in each
147 // task is needed because some of tests run asynchronously.
148 var taskDone = function () {
149 if (this.currentTask !== this.queue.length - 1) {
150 ++this.currentTask;
151 // debug('>> Audit.runTasks: ' + this.queue[this.currentTask]);
152 this.tasks[this.queue[this.currentTask]](taskDone);
153 } else {
154 this._finalize();
155 }
156 return;
157 }.bind(this);
158
159 // Start the first task.
160 // debug('>> Audit.runTasks: ' + this.queue[this.currentTask]);
161 this.tasks[this.queue[this.currentTask]](taskDone);
162 };
163
164 return {
165 createTaskRunner: function () {
166 return new Tasks();
167 }
168 };
169
170 })();
171
172
173 // |Should| JS layout test utility.
174 // Dependency: ../resources/js-test.js
175 var Should = (function () {
176
177 'use strict';
178
179 // ShouldModel internal class. For the exposed (factory) method, it is the
180 // return value of this closure.
181 function ShouldModel(desc, target, opts) {
182 this.desc = desc;
183 this.target = target;
184
185 // Check if the target contains any NaN value.
186 this._checkNaN(this.target, 'ACTUAL');
187
188 // |_testPassed| and |_testFailed| set this appropriately.
189 this._success = false;
190
191 // If the number of errors is greater than this, the rest of error
192 // messages are suppressed. the value is fairly arbitrary, but shouldn't
193 // be too small or too large.
194 this.NUM_ERRORS_LOG = opts.numberOfErrorLog;
195
196 // If the number of array elements is greater than this, the rest of
197 // elements will be omitted.
198 this.NUM_ARRAY_LOG = opts.numberOfArrayLog;
199
200 // If true, verbose output for the failure case is printed, for methods where this makes
201 // sense.
202 this.verbose = !opts.brief;
203
204 // If set, this is the precision with which numbers will be printed.
205 this.PRINT_PRECISION = opts.precision;
206 }
207
208 // Internal methods starting with a underscore.
209 ShouldModel.prototype._testPassed = function (msg, addNewline) {
210 this._success = true;
211 var newLine = addNewline ? '\n' : '';
212 if (TESTHARNESS) {
213 // Using testharness.js
214 test(function () {
215 assert_true(true);
216 }, this.desc + ' ' + msg + '.' + newLine);
217 } else {
218 // Using js-test.js
219 testPassed(this.desc + ' ' + msg + '.' + newLine);
220 }
221 };
222
223 ShouldModel.prototype._testFailed = function (msg, addNewline) {
224 this._success = false;
225 var that = this;
226 var newLine = addNewline ? '\n' : '';
227 if (TESTHARNESS) {
228 test(function () {
229 assert_true(false, that.desc + ' ' + msg + '.' + newLine);
230 }, this.desc);
231 } else {
232 testFailed(this.desc + ' ' + msg + '.' + newLine);
233 }
234 };
235
236 ShouldModel.prototype._isArray = function (arg) {
237 return arg instanceof Array || arg instanceof Float32Array || arg instance of Uint8Array ||
238 arg instanceof Uint16Array || arg instanceof Uint32Array || arg instance of Int8Array ||
239 arg instanceof Int16Array || arg instanceof Int32Array || arg instanceof Uint8ClampedArray ||
240 arg instanceof Float64Array;
241 };
242
243 ShouldModel.prototype._assert = function (expression, reason, value) {
244 if (expression)
245 return;
246
247 var failureMessage = 'Assertion failed: ' + reason + ' ' + this.desc +'. ';
248 if (arguments.length >= 3)
249 failureMessage += ": " + value;
250
251 if (TESTHARNESS) {
252 test(function () {
253 assert_true(false, reason + ' (' + value + ')');
254 }, this.desc)
255 } else {
256 testFailed(failureMessage);
257 }
258
259 throw failureMessage;
260 };
261
262 // Check the expected value if it is a NaN (Number) or has NaN(s) in
263 // its content (Array or Float32Array). Returns a string depends on the
264 // result of check.
265 ShouldModel.prototype._checkNaN = function (value, label) {
266 var failureMessage = 'NaN found in ' + label + ' while testing "' +
267 this.desc + '"';
268
269 // Checking a single variable first.
270 if (Number.isNaN(value)) {
271 if (TESTHARNESS) {
272 test(function () {
273 assert_true(false, failureMessage);
274 }, this.desc)
275 } else {
276 testFailed(failureMessage);
277 }
278
279 throw failureMessage;
280 }
281
282 // If the value is not a NaN nor array, we can assume it is safe.
283 if (!this._isArray(value))
284 return;
285
286 // Otherwise, check the array array.
287 var indices = [];
288 for (var i = 0; i < value.length; i++) {
289 if (Number.isNaN(value[i]))
290 indices.push(i);
291 }
292
293 if (indices.length === 0)
294 return;
295
296 var failureDetail = ' (' + indices.length + ' instances total)\n';
297 for (var n = 0; n < indices.length; n++) {
298 failureDetail += ' >> [' + indices[n] + '] = NaN\n';
299 if (n >= this.NUM_ERRORS_LOG) {
300 failureDetail += ' and ' + (indices.length - n) +
301 ' more NaNs...';
302 break;
303 }
304 }
305
306 if (TESTHARNESS) {
307 test(function () {
308 assert_true(false, failureMessage + failureDetail);
309 }, this.desc)
310 } else {
311 testFailed(failureMessage + failureDetail);
312 }
313
314 throw failureMessage;
315 };
316
317 // Check if |target| exists.
318 //
319 // Example:
320 // Should('Object', {}).exist();
321 // Result:
322 // "PASS Object exists."
323 ShouldModel.prototype.exist = function () {
324 if (this.target !== null && this.target !== undefined) {
325 this._testPassed('exists');
326 } else {
327 this._testFailed('does not exist');
328 }
329
330 return this._success;
331 };
332
333 // Check if |target| is equal to |value|.
334 //
335 // Example:
336 // Should('Zero', 0).beEqualTo(0);
337 // Result:
338 // "PASS Zero is equal to 0."
339 ShouldModel.prototype.beEqualTo = function (value) {
340 if (value != null) {
341 var type = typeof value;
342 this._assert(type === 'number' || type === 'string' || type === 'boo lean',
343 'value should be number, string, or boolean for', value );
344 }
345
346 this._checkNaN(value, 'EXPECTED');
347
348 var outputValue = value;
349 if (type === 'string')
350 outputValue = '"' + outputValue + '"';
351 if (this.target === value) {
352 var outputValue = (type === 'string') ? '"' + value + '"' : value;
353 this._testPassed('is equal to ' + outputValue);
354 } else {
355 var targetValue = this.target;
356 if (typeof this.target === 'string')
357 targetValue = '"' + targetValue + '"';
358 this._testFailed('was ' + targetValue + ' instead of ' + outputValue );
359 }
360 return this._success;
361 };
362
363 // Check if |target| is not equal to |value|.
364 //
365 // Example:
366 // Should('One', one).notBeEqualTo(0);
367 // Result:
368 // "PASS One is not equal to 0."
369 ShouldModel.prototype.notBeEqualTo = function (value) {
370 var type = typeof value;
371 this._assert(type === 'number' || type === 'string' || type === "boolean ",
372 'value should be number, string, or boolean for', value);
373
374 this._checkNaN(value, 'EXPECTED');
375
376 if (this.target === value)
377 this._testFailed('should not be equal to ' + value);
378 else
379 this._testPassed('is not equal to ' + value);
380 return this._success;
381 };
382
383 // Check if |target| is greater than or equal to |value|.
384 //
385 // Example:
386 // Should("SNR", snr).beGreaterThanOrEqualTo(100);
387 // Result:
388 // "PASS SNR exceeds 100"
389 // "FAIL SNR (n) is not greater than or equal to 100"
390 ShouldModel.prototype.beGreaterThanOrEqualTo = function (value) {
391 var type = typeof value;
392 this._assert(type === 'number' || type === 'string',
393 'value should be number or string for', value);
394
395 this._checkNaN(value, 'EXPECTED');
396
397 var prefix = '(' + this.target + ') ';
398
399 if (this.target >= value) {
400 if (!this.verbose)
401 prefix = '';
402 this._testPassed(prefix + "is greater than or equal to " + value);
403 } else {
404 this._testFailed(prefix + "is not greater than or equal to " + value );
405 }
406 return this._success;
407 }
408
409 // Check if |target| is greater than |value|.
410 //
411 // Example:
412 // Should("SNR", snr).beGreaterThan(100);
413 // Result:
414 // "PASS SNR is greater than 100"
415 // "FAIL SNR (n) is not greater than 100"
416 ShouldModel.prototype.beGreaterThan = function (value) {
417 var type = typeof value;
418 this._assert(type === 'number' || type === 'string',
419 'value should be number or string for', value);
420
421 this._checkNaN(value, 'EXPECTED');
422
423 if (this.target > value)
424 this._testPassed("is greater than " + value);
425 else
426 this._testFailed("(" + this.target + ") is not greater than " + valu e);
427 return this._success;
428 }
429
430 // Check if |target| is lest than or equal to |value|.
431 //
432 // Example:
433 // maxError = 1e-6;
434 // Should("max error", maxError).beLessThanOrEqualTo(1e-5);
435 // Should("max error", maxError).beLessThanOrEqualTo(-1);
436 // Result:
437 // "PASS max error is less than or equal to 1e-5"
438 // "FAIL max error (1e-6) is not less than or equal to -1"
439 ShouldModel.prototype.beLessThanOrEqualTo = function (value) {
440 var type = typeof value;
441 this._assert(type === 'number', 'value should be number or string for', value);
442
443 this._checkNaN(value, 'EXPECTED');
444
445 var prefix = '(' + this.target + ') ';
446
447 if (this.target <= value) {
448 if (!this.verbose)
449 prefix = '';
450 this._testPassed(prefix + "is less than or equal to " + value);
451 } else {
452 this._testFailed(prefix + "is not less than or equal to " + value);
453 }
454 return this._success;
455 }
456
457 // Check if |target| is close to |value| using the given relative error |thr eshold|. |value|
458 // should not be zero, but no check is made for that. The |target| value is printed to
459 // precision |precision|, with |precision| defaulting to 7.
460 //
461 // If |value| is 0, however, |threshold| is treated as an absolute threshold .
462 //
463 // Example:
464 // Should("One", 1.001).beCloseTo(1, .1);
465 // Should("One", 2).beCloseTo(1, .1);
466 // Result:
467 // "PASS One is 1 within a relative error of 0.1."
468 // "FAIL One is not 1 within a relative error of 0.1: 2"
469 ShouldModel.prototype.beCloseTo = function (value, errorThreshold) {
470 var type = typeof value;
471 this._assert(type === 'number', 'value should be number for', value);
472
473 this._checkNaN(value, 'EXPECTED');
474
475 if (value) {
476 var relativeError = Math.abs(this.target - value) / Math.abs(value);
477 if (relativeError <= errorThreshold) {
478 this._testPassed("is " + value.toPrecision(this.PRINT_PRECISION) +
479 " within a relative error of " + errorThreshold);
480 } else {
481 // Include actual relative error so the failed test case can be updated with the actual
482 // relative error, if appropriate.
483 this._testFailed("is not " + value.toPrecision(this.PRINT_PRECIS ION) +
484 " within a relative error of " + errorThreshold +
485 ": " + this.target + " with relative error " + relativeError
486 );
487 }
488 } else {
489 var absoluteError = Math.abs(this.target - value);
490 if (absoluteError <= errorThreshold) {
491 this._testPassed("is " + value.toPrecision(this.PRINT_PRECISION) +
492 " within an absolute error of " + errorThreshold);
493 } else {
494 // Include actual absolute error so the failed test case can be updated with the
495 // actual error, if appropriate.
496 this._testFailed("is not " + value.toPrecision(this.PRINT_PRECIS ION) +
497 " within an absolute error of " + errorThreshold +
498 ": " + this.target + " with absolute error " + absoluteError
499 );
500 }
501 }
502 return this._success;
503 }
504
505 // Check if |func| throws an exception with a certain |errorType| correctly.
506 // |errorType| is optional.
507 //
508 // Example:
509 // Should('A bad code', function () { var a = b; }).throw();
510 // Result:
511 // "PASS A bad code threw an exception."
512 // Example:
513 // Should('var c = d', function () { var c = d; }).throw('ReferenceError');
514 // "PASS var c = d threw ReferenceError."
515 ShouldModel.prototype.throw = function (errorType) {
516 if (typeof this.target !== 'function') {
517 console.log('target is not a function. test halted.');
518 return;
519 }
520
521 try {
522 this.target();
523 this._testFailed('did not throw an exception');
524 } catch (error) {
525 if (errorType === undefined)
526 this._testPassed('threw an exception of type ' + error.name);
527 else if (error.name === errorType)
528 this._testPassed('threw ' + errorType + ': ' + error.message);
529 else if (self.hasOwnProperty(errorType) && error instanceof self[err orType])
530 this._testPassed('threw ' + errorType + ': ' + error.message);
531 else
532 this._testFailed('threw ' + error.name + ' instead of ' + errorT ype);
533 }
534 return this._success;
535 };
536
537 // Check if |func| does not throw an exception.
538 //
539 // Example:
540 // Should('var foo = "bar"', function () { var foo = 'bar'; }).notThrow();
541 // Result:
542 // "PASS var foo = "bar" did not throw an exception."
543 ShouldModel.prototype.notThrow = function () {
544 try {
545 this.target();
546 this._testPassed('did not throw an exception');
547 } catch (error) {
548 this._testFailed('threw ' + error.name + ': ' + error.message);
549 }
550 return this._success;
551 };
552
553 // Check if |target| array is filled with constant values.
554 //
555 // Example:
556 // Should('[2, 2, 2]', [2, 2, 2]).beConstantValueOf(2);
557 // Result:
558 // "PASS [2, 2, 2] has constant values of 2."
559 ShouldModel.prototype.beConstantValueOf = function (value) {
560 this._checkNaN(value, 'EXPECTED');
561
562 var mismatches = {};
563 for (var i = 0; i < this.target.length; i++) {
564 if (this.target[i] !== value)
565 mismatches[i] = this.target[i];
566 }
567
568 var numberOfmismatches = Object.keys(mismatches).length;
569
570 if (numberOfmismatches === 0) {
571 this._testPassed('contains only the constant ' + value);
572 } else {
573 var counter = 0;
574 var failureMessage = 'contains ' + numberOfmismatches +
575 ' values that are NOT equal to ' + value + ':';
576 for (var index in mismatches) {
577 failureMessage += '\n[' + index + '] : ' + mismatches[index];
578 if (++counter >= this.NUM_ERRORS_LOG) {
579 failureMessage += '\nand ' + (numberOfmismatches - counter) +
580 ' more differences...';
581 break;
582 }
583 }
584 this._testFailed(failureMessage);
585 }
586 return this._success;
587 };
588
589 // Check if |target| array is identical to |expected| array element-wise.
590 //
591 // Example:
592 // Should('[1, 2, 3]', [1, 2, 3]).beEqualToArray([1, 2, 3]);
593 // Result:
594 // "PASS [1, 2, 3] is identical to the array [1,2,3]."
595 ShouldModel.prototype.beEqualToArray = function (array) {
596 this._assert(this._isArray(array) && this.target.length === array.length ,
597 'Invalid array or the length does not match.', array);
598
599 this._checkNaN(array, 'EXPECTED');
600
601 var mismatches = {};
602 for (var i = 0; i < this.target.length; i++) {
603 if (this.target[i] !== array[i])
604 mismatches[i] = this.target[i];
605 }
606
607 var numberOfmismatches = Object.keys(mismatches).length;
608 var arrSlice = array.slice(0, this.NUM_ARRAY_LOG);
609 var arrStr = arrSlice[0].toPrecision(this.PRINT_PRECISION);
610 for (var k = 1; k < arrSlice.length; ++k)
611 arrStr += ',' + arrSlice[k].toPrecision(this.PRINT_PRECISION);
612 if (array.length > this.NUM_ARRAY_LOG)
613 arrStr += ',...';
614
615 if (numberOfmismatches === 0) {
616 this._testPassed('is identical to the array [' + arrStr + ']');
617 } else {
618 var counter = 0;
619 var failureMessage = 'is not equal to the array [' + arrStr + ']';
620 if (this.verbose)
621 failureMessage += '\nindex\tActual\t\tExpected';
622 for (var index in mismatches) {
623 failureMessage += '\n[' + index + '] : ' + mismatches[index];
624 if (this.verbose)
625 failureMessage += '\t' + array[index];
626 if (++counter >= this.NUM_ERRORS_LOG) {
627 failureMessage += '\nand ' + (numberOfmismatches - counter) +
628 ' more differences...';
629 break;
630 }
631 }
632
633 this._testFailed(failureMessage);
634 }
635 return this._success;
636 };
637
638 // Check if |target| array is close to |expected| array element-wise within
639 // an certain error bound given by |absoluteThresholdOrOptions|.
640 //
641 // The error criterion is:
642 //
643 // Math.abs(target[k] - expected[k]) < Math.max(abserr, relerr * Math.abs( expected))
644 //
645 // If |absoluteThresholdOrOptions| is a number, t, then abserr = t and reler r = 0. That is the
646 // max difference is bounded by t.
647 //
648 // If |absoluteThresholdOrOptions| is a property bag, then abserr is the val ue of the
649 // absoluteThreshold property and relerr is the value of the relativeThresho ld property. If
650 // nothing is given, then abserr = relerr = 0. If abserr = 0, then the erro r criterion is a
651 // relative error. A non-zero abserr value produces a mix intended to handl e the case where the
652 // expected value is 0, allowing the target value to differ by abserr from t he expected.
653 //
654 // Example:
655 // Should('My array', [0.11, 0.19]).beCloseToArray([0.1, 0.2], 0.02);
656 // Result:
657 // "PASS My array equals [0.1,0.2] within an element-wise tolerance of 0.02. "
658 ShouldModel.prototype.beCloseToArray = function (expected, absoluteThreshold OrOptions) {
659 // For the comparison, the target length must be bigger than the expecte d.
660 this._assert(this.target.length >= expected.length,
661 'The target array length must be longer than ' + expected.length +
662 ' but got ' + this.target.length + '.');
663
664 this._checkNaN(expected, 'EXPECTED');
665
666 var absoluteErrorThreshold = 0;
667 var relativeErrorThreshold = 0;
668
669 // A collection of all of the values that satisfy the error criterion. This holds the
670 // absolute difference between the target element and the expected eleme nt.
671 var mismatches = {};
672
673 // Keep track of the max absolute error found
674 var maxAbsError = -Infinity;
675 var maxAbsErrorIndex = -1;
676 // Keep trac of the max relative error found, ignoring cases where the r elative error is
677 // Infinity because the expected value is 0.
678 var maxRelError = -Infinity;
679 var maxRelErrorIndex = -1;
680
681 // A number or string for printing out the actual thresholds used for th e error criterion.
682 var maxAllowedError;
683
684 // Set up the thresholds based on |absoluteThresholdOrOptions|.
685 if (typeof(absoluteThresholdOrOptions) === 'number') {
686 absoluteErrorThreshold = absoluteThresholdOrOptions;
687 maxAllowedError = absoluteErrorThreshold;
688 } else {
689 var opts = absoluteThresholdOrOptions;
690 if (opts.hasOwnProperty('absoluteThreshold'))
691 absoluteErrorThreshold = opts.absoluteThreshold;
692 if (opts.hasOwnProperty('relativeThreshold'))
693 relativeErrorThreshold = opts.relativeThreshold;
694 maxAllowedError = '{absoluteThreshold: ' + absoluteErrorThreshold
695 + ', relativeThreshold: ' + relativeErrorThreshold
696 + '}';
697 }
698
699 for (var i = 0; i < expected.length; i++) {
700 var diff = Math.abs(this.target[i] - expected[i]);
701 if (diff > Math.max(absoluteErrorThreshold, relativeErrorThreshold * Math.abs(expected[i]))) {
702 mismatches[i] = diff;
703 // Keep track of the location of the absolute max difference.
704 if (diff > maxAbsError) {
705 maxAbsErrorIndex = i;
706 maxAbsError = diff;
707 }
708 // Keep track of the location of the max relative error, ignorin g cases where the
709 // relative error is NaN.
710 var relError = diff / Math.abs(expected[i]);
711 if (!isNaN(relError) && relError > maxRelError) {
712 maxRelErrorIndex = i;
713 maxRelError = relError;
714 }
715 }
716 }
717
718 var numberOfmismatches = Object.keys(mismatches).length;
719 var arrSlice = expected.slice(0, Math.min(expected.length, this.NUM_ARRA Y_LOG));
720 var arrStr;
721
722 arrStr = arrSlice[0].toPrecision(this.PRINT_PRECISION);
723 for (var k = 1; k < arrSlice.length; ++k)
724 arrStr += ',' + arrSlice[k].toPrecision(this.PRINT_PRECISION);
725
726 if (expected.length > this.NUM_ARRAY_LOG)
727 arrStr += ',...';
728 if (numberOfmismatches === 0) {
729 this._testPassed('equals [' + arrStr +
730 '] with an element-wise tolerance of ' + maxAllowedError);
731 } else {
732 var counter = 0;
733 var failureMessage = 'does not equal [' + arrStr +
734 '] with an element-wise tolerance of ' + maxAllowedError;
735
736 // Print a nice header for the table to follow.
737 if (this.verbose)
738 failureMessage += "\nIndex Actual Expected Diff Relative";
739 else
740 failureMessage += "\nDifference between expected and actual:";
741
742 for (var index in mismatches) {
743 failureMessage += '\n[' + index + ']: ';
744 if (this.verbose) {
745 // When verbose, print out actual, expected, absolute error, and relative error.
746 // TODO: print these out in nice columns to make it easier t o read.
747 var relError = Math.abs(this.target[index] - expected[index] ) / Math.abs(expected[index]);
748 failureMessage += this.target[index].toExponential(16) + ' '
749 + expected[index].toExponential(16) + ' '
750 + mismatches[index].toExponential(16) + ' '
751 + relError.toExponential(16) + ' '
752 + Math.max(absoluteErrorThreshold,
753 relativeErrorThreshold * Math.abs(expecte d[index]));
754 } else {
755 // Otherwise, just the print the absolute error.
756 failureMessage += mismatches[index];
757 }
758 if (++counter >= this.NUM_ERRORS_LOG) {
759 failureMessage += '\nand ' + (numberOfmismatches - counter) +
760 ' more differences, with max absolute error';
761 if (this.verbose) {
762 // When verbose, print out the location of both the max absolute error and
763 // the max relative error so we can adjust thresholds ap propriately in the
764 // test.
765 var relError = Math.abs(this.target[maxAbsErrorIndex] - expected[maxAbsErrorIndex])
766 / Math.abs(expected[maxAbsErrorIndex]);
767 failureMessage += ' at index ' + maxAbsErrorIndex + ':';
768 failureMessage += '\n[' + maxAbsErrorIndex + ']: ';
769 failureMessage += this.target[maxAbsErrorIndex].toExpone ntial(16) + ' '
770 + expected[maxAbsErrorIndex].toExponential(16) + ' '
771 + mismatches[maxAbsErrorIndex].toExponential(16) + ' '
772 + relError.toExponential(16) + ' '
773 + Math.max(absoluteErrorThreshold,
774 relativeErrorThreshold * Math.abs(expected[m axAbsErrorIndex]));
775 failureMessage += '\nand max relative error';
776 failureMessage += ' at index ' + maxRelErrorIndex + ':';
777 failureMessage += '\n[' + maxRelErrorIndex + ']: ';
778 failureMessage += this.target[maxRelErrorIndex].toExpone ntial(16) + ' '
779 + expected[maxRelErrorIndex].toExponential(16) + ' '
780 + mismatches[maxRelErrorIndex].toExponential(16) + ' '
781 + maxRelError.toExponential(16) + ' '
782 + Math.max(absoluteErrorThreshold,
783 relativeErrorThreshold * Math.abs(expected[m axRelErrorIndex]));
784 } else {
785 // Not verbose, so just print out the max absolute error
786 failureMessage += ' of ' + maxAbsError + ' at index ' + maxAbsErrorIndex;
787 }
788 break;
789 }
790 }
791
792 this._testFailed(failureMessage);
793 }
794 return this._success;
795 };
796
797 // Check if |target| array contains a set of values in a certain order.
798 //
799 // Example:
800 // Should('My random array', [1, 1, 3, 3, 2]).containValues([1, 3, 2]);
801 // Result:
802 // "PASS My random array contains all the expected values in the correct
803 // order: [1,3,2]."
804 ShouldModel.prototype.containValues = function (expected) {
805 this._checkNaN(expected, 'EXPECTED');
806
807 var indexExpected = 0, indexActual = 0;
808 while (indexExpected < expected.length && indexActual < this.target.leng th) {
809 if (expected[indexExpected] === this.target[indexActual])
810 indexActual++;
811 else
812 indexExpected++;
813 }
814
815 if (indexExpected < expected.length-1 || indexActual < this.target.lengt h-1) {
816 this._testFailed('contains an unexpected value ' + this.target[index Actual] +
817 ' at index ' + indexActual);
818 } else {
819 this._testPassed('contains all the expected values in the correct or der: [' +
820 expected + ']');
821 }
822 return this._success;
823 };
824
825 // Check if |target| array does not have any glitches. Note that |threshold|
826 // is not optional and is to define the desired threshold value.
827 //
828 // Example:
829 // Should('Channel #0', chanL).notGlitch(0.0005);
830 // Result:
831 // "PASS Channel #0 has no glitch above the threshold of 0.0005."
832 ShouldModel.prototype.notGlitch = function (threshold) {
833 this._checkNaN(threshold, 'EXPECTED');
834
835 for (var i = 1; i < this.target.length; i++) {
836 var diff = Math.abs(this.target[i-1] - this.target[i]);
837 if (diff >= threshold) {
838 this._testFailed('has a glitch at index ' + i + ' of size ' + di ff);
839 return this._success;
840 }
841 }
842 this._testPassed('has no glitch above the threshold of ' + threshold);
843 return this._success;
844 };
845
846 // Check if the target promise is resolved correctly.
847 //
848 // Example:
849 // Should('My promise', promise).beResolved().then(nextStuff);
850 // Result:
851 // "PASS My promise resolved correctly."
852 // "FAIL My promise rejected incorrectly (with _ERROR_)."
853 ShouldModel.prototype.beResolved = function () {
854 return this.target.then(function () {
855 this._testPassed('resolved correctly');
856 }.bind(this), function (err) {
857 this._testFailed('rejected incorrectly (with ' + err + ')');
858 }.bind(this));
859 };
860
861 // Check if the target promise is rejected correctly.
862 //
863 // Example:
864 // Should('My promise', promise).beRejected().then(nextStuff);
865 // Result:
866 // "PASS My promise rejected correctly (with _ERROR_)."
867 // "FAIL My promise resolved incorrectly."
868 ShouldModel.prototype.beRejected = function () {
869 return this.target.then(function () {
870 this._testFailed('resolved incorrectly');
871 }.bind(this), function (err) {
872 this._testPassed('rejected correctly (with ' + err + ')');
873 }.bind(this));
874 };
875
876 // A summary message
877 //
878 // Example:
879 // Should("Summary1", true).summarize("passed1", "failed1");
880 // Should("Summary2", false).summarize("passed2", "failed2");
881 // Result:
882 // "PASS Summary1: passed1."
883 // "FAIL Summary2: failed2."
884 ShouldModel.prototype.summarize = function (pass, fail) {
885 // It's really nice to have blank lines after the summary, but
886 // testharness thinks the whole testsuite fails if we do that.
887 if (this.target)
888 this._testPassed(pass, false);
889 else
890 this._testFailed(fail, false);
891 return this._success;
892 }
893
894 // Should() method.
895 //
896 // |desc| is the description of the task or check and |target| is a value
897 // needs to be checked or a task to be performed. |opt| contains options for
898 // printing out log messages: options are |opt.numberOfErrorLog| and
899 // |opts.numberOfArrayLog|.
900 return function (desc, target, opts) {
901 var _opts = {
902 numberOfErrorLog: 8,
903 numberOfArrayLog: 16,
904 verbose: true
905 };
906
907 if (opts instanceof Object) {
908 if (opts.hasOwnProperty('numberOfErrorLog'))
909 _opts.numberOfErrorLog = opts.numberOfErrorLog;
910 if (opts.hasOwnProperty('numberOfArrayLog'))
911 _opts.numberOfArrayLog = opts.numberOfArrayLog;
912 if (opts.hasOwnProperty('brief'))
913 _opts.brief = opts.brief;
914 if (opts.hasOwnProperty('precision'))
915 _opts.precision = opts.precision;
916 }
917
918 return new ShouldModel(desc, target, _opts);
919 };
920
921 })();
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698