| // Copyright 2014 the V8 project authors. All rights reserved. |
| // Redistribution and use in source and binary forms, with or without |
| // modification, are permitted provided that the following conditions are |
| // met: |
| // |
| // * Redistributions of source code must retain the above copyright |
| // notice, this list of conditions and the following disclaimer. |
| // * Redistributions in binary form must reproduce the above |
| // copyright notice, this list of conditions and the following |
| // disclaimer in the documentation and/or other materials provided |
| // with the distribution. |
| // * Neither the name of Google Inc. nor the names of its |
| // contributors may be used to endorse or promote products derived |
| // from this software without specific prior written permission. |
| // |
| // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
| // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
| // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
| // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
| // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
| // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
| // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
| // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
| // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
| // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
| // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
| |
| // This file emulates Mocha test framework used in promises-aplus tests. |
| |
| var describe; |
| var it; |
| var specify; |
| var before; |
| var after; |
| var beforeEach; |
| var afterEach; |
| var RunAllTests; |
| |
| var assert = require('assert'); |
| |
| (function() { |
| var TIMEOUT = 1000; |
| |
| var context = { |
| beingDescribed: undefined, |
| currentSuiteIndex: 0, |
| suites: [] |
| }; |
| |
| function Run() { |
| function current() { |
| while (context.currentSuiteIndex < context.suites.length && |
| context.suites[context.currentSuiteIndex].hasRun) { |
| ++context.currentSuiteIndex; |
| } |
| if (context.suites.length == context.currentSuiteIndex) { |
| return undefined; |
| } |
| return context.suites[context.currentSuiteIndex]; |
| } |
| var suite = current(); |
| if (!suite) { |
| // done |
| print('All tests have run.'); |
| return; |
| } |
| suite.Run(); |
| } |
| |
| RunAllTests = function() { |
| context.currentSuiteIndex = 0; |
| var numRegularTestCases = 0; |
| for (var i = 0; i < context.suites.length; ++i) { |
| numRegularTestCases += context.suites[i].numRegularTestCases(); |
| } |
| print(context.suites.length + ' suites and ' + numRegularTestCases + |
| ' test cases are found'); |
| Run(); |
| }; |
| |
| function TestCase(name, before, fn, after, isRegular) { |
| this.name = name; |
| this.before = before; |
| this.fn = fn; |
| this.after = after; |
| this.isRegular = isRegular; |
| this.hasDone = false; |
| } |
| |
| TestCase.prototype.RunFunction = function(suite, fn, postAction) { |
| if (!fn) { |
| postAction(); |
| return; |
| } |
| try { |
| if (fn.length === 0) { |
| // synchronous |
| fn(); |
| postAction(); |
| } else { |
| // asynchronous |
| fn(postAction); |
| } |
| } catch (e) { |
| suite.ReportError(this, e); |
| } |
| } |
| |
| TestCase.prototype.MarkAsDone = function() { |
| this.hasDone = true; |
| clearTimeout(this.timer); |
| } |
| |
| TestCase.prototype.Run = function(suite, postAction) { |
| print('Running ' + suite.description + '#' + this.name + ' ...'); |
| assert.clear(); |
| |
| this.timer = setTimeout(function() { |
| suite.ReportError(this, Error('timeout')); |
| }.bind(this), TIMEOUT); |
| |
| this.RunFunction(suite, this.before, function(e) { |
| if (this.hasDone) { |
| return; |
| } |
| if (e instanceof Error) { |
| return suite.ReportError(this, e); |
| } |
| if (assert.fails.length > 0) { |
| return suite.ReportError(this, assert.fails[0]); |
| } |
| this.RunFunction(suite, this.fn, function(e) { |
| if (this.hasDone) { |
| return; |
| } |
| if (e instanceof Error) { |
| return suite.ReportError(this, e); |
| } |
| if (assert.fails.length > 0) { |
| return suite.ReportError(this, assert.fails[0]); |
| } |
| this.RunFunction(suite, this.after, function(e) { |
| if (this.hasDone) { |
| return; |
| } |
| if (e instanceof Error) { |
| return suite.ReportError(this, e); |
| } |
| if (assert.fails.length > 0) { |
| return suite.ReportError(this, assert.fails[0]); |
| } |
| this.MarkAsDone(); |
| if (this.isRegular) { |
| print('PASS: ' + suite.description + '#' + this.name); |
| } |
| %EnqueueMicrotask(postAction); |
| }.bind(this)); |
| }.bind(this)); |
| }.bind(this)); |
| }; |
| |
| function TestSuite(described) { |
| this.description = described.description; |
| this.cases = []; |
| this.currentIndex = 0; |
| this.hasRun = false; |
| |
| if (described.before) { |
| this.cases.push(new TestCase(this.description + ' :before', undefined, |
| described.before, undefined, false)); |
| } |
| for (var i = 0; i < described.cases.length; ++i) { |
| this.cases.push(new TestCase(described.cases[i].description, |
| described.beforeEach, |
| described.cases[i].fn, |
| described.afterEach, |
| true)); |
| } |
| if (described.after) { |
| this.cases.push(new TestCase(this.description + ' :after', |
| undefined, described.after, undefined, false)); |
| } |
| } |
| |
| TestSuite.prototype.Run = function() { |
| this.hasRun = this.currentIndex === this.cases.length; |
| if (this.hasRun) { |
| %EnqueueMicrotask(Run); |
| return; |
| } |
| |
| // TestCase.prototype.Run cannot throw an exception. |
| this.cases[this.currentIndex].Run(this, function() { |
| ++this.currentIndex; |
| %EnqueueMicrotask(Run); |
| }.bind(this)); |
| }; |
| |
| TestSuite.prototype.numRegularTestCases = function() { |
| var n = 0; |
| for (var i = 0; i < this.cases.length; ++i) { |
| if (this.cases[i].isRegular) { |
| ++n; |
| } |
| } |
| return n; |
| } |
| |
| TestSuite.prototype.ReportError = function(testCase, e) { |
| if (testCase.hasDone) { |
| return; |
| } |
| testCase.MarkAsDone(); |
| this.hasRun = this.currentIndex === this.cases.length; |
| print('FAIL: ' + this.description + '#' + testCase.name + ': ' + |
| e.name + ' (' + e.message + ')'); |
| ++this.currentIndex; |
| %EnqueueMicrotask(Run); |
| }; |
| |
| describe = function(description, fn) { |
| var parent = context.beingDescribed; |
| var incomplete = { |
| cases: [], |
| description: parent ? parent.description + ' ' + description : description, |
| parent: parent, |
| }; |
| context.beingDescribed = incomplete; |
| fn(); |
| context.beingDescribed = parent; |
| |
| context.suites.push(new TestSuite(incomplete)); |
| } |
| |
| specify = it = function(description, fn) { |
| context.beingDescribed.cases.push({description: description, fn: fn}); |
| } |
| |
| before = function(fn) { |
| context.beingDescribed.before = fn; |
| } |
| |
| after = function(fn) { |
| context.beingDescribed.after = fn; |
| } |
| |
| beforeEach = function(fn) { |
| context.beingDescribed.beforeEach = fn; |
| } |
| |
| afterEach = function(fn) { |
| context.beingDescribed.afterEach = fn; |
| } |
| |
| }()); |