265 lines
7.1 KiB
JavaScript
265 lines
7.1 KiB
JavaScript
|
// 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;
|
||
|
|
||
|
function PostMicrotask(fn) {
|
||
|
var o = {};
|
||
|
Object.observe(o, function() {
|
||
|
fn();
|
||
|
});
|
||
|
// Change something to enqueue a microtask.
|
||
|
o.x = 'hello';
|
||
|
}
|
||
|
|
||
|
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);
|
||
|
}
|
||
|
PostMicrotask(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) {
|
||
|
PostMicrotask(Run);
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
// TestCase.prototype.Run cannot throw an exception.
|
||
|
this.cases[this.currentIndex].Run(this, function() {
|
||
|
++this.currentIndex;
|
||
|
PostMicrotask(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;
|
||
|
PostMicrotask(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;
|
||
|
}
|
||
|
|
||
|
}());
|