Add Promises/A+ Compliance Test Suite.
authorrossberg@chromium.org <rossberg@chromium.org@ce2b1a6d-e550-0410-aec6-3dcde31c8c00>
Mon, 17 Mar 2014 10:03:01 +0000 (10:03 +0000)
committerrossberg@chromium.org <rossberg@chromium.org@ce2b1a6d-e550-0410-aec6-3dcde31c8c00>
Mon, 17 Mar 2014 10:03:01 +0000 (10:03 +0000)
This CL introduces Promises/A+ tests[1].
This CL doesn't contain the test itself: it will be downloaded by test cfg.py.
This CL includes some helper JS functions to run the test in d8 shell.

[1]: https://github.com/promises-aplus/promises-tests

BUG=347095
LOG=Y
R=rossberg@chromium.org

Review URL: https://codereview.chromium.org/196733002

Patch from Yutaka Hirano <yhirano@chromium.org>.

git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@19973 ce2b1a6d-e550-0410-aec6-3dcde31c8c00

test/promises-aplus/README [new file with mode: 0644]
test/promises-aplus/lib/adapter.js [new file with mode: 0644]
test/promises-aplus/lib/assert.js [new file with mode: 0644]
test/promises-aplus/lib/global.js [new file with mode: 0644]
test/promises-aplus/lib/mocha.js [new file with mode: 0644]
test/promises-aplus/lib/require.js [new file with mode: 0644]
test/promises-aplus/lib/run-tests.js [new file with mode: 0644]
test/promises-aplus/promises-aplus.status [new file with mode: 0644]
test/promises-aplus/testcfg.py [new file with mode: 0644]

diff --git a/test/promises-aplus/README b/test/promises-aplus/README
new file mode 100644 (file)
index 0000000..de15da3
--- /dev/null
@@ -0,0 +1,29 @@
+This directory contains code for running Promise/A+ Compliance Test Suite[1].
+You can download the it from [1], or by specifying --download to
+tools/run-tests.py.
+Promise/A+ Compliance Test Suite requires Node environment and needs some
+libraries. To run it in d8 shell, we provides some emulation functions in the
+lib/ directory.
+
+ - lib/adapter.js
+  - An adapter for harmony Promise used in Promise/A+ tests.
+ - lib/assert.js
+  - Emulates assert modules in Node.
+ - lib/global.js
+  - Provides global functions and variables.
+ - lib/mocha.js
+  - Emulates Mocha[2] test framework.
+ - lib/require.j
+  - Emulate require function in Node.
+ - lib/run-tests.js
+  - Run all describe tests.
+
+The emulation is not complete. Upgrading Promise/A+ tests will require
+changing lib/ scripts.
+
+Sinon.JS[3], required by Promise/A+ tests, is also downloaded by run-tests.py.
+
+[1]: https://github.com/promises-aplus/promises-tests
+[2]: http://visionmedia.github.io/mocha/
+[3]: http://sinonjs.org/
+
diff --git a/test/promises-aplus/lib/adapter.js b/test/promises-aplus/lib/adapter.js
new file mode 100644 (file)
index 0000000..d99913a
--- /dev/null
@@ -0,0 +1,41 @@
+// 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.
+
+var global = this.global || {};
+
+global.adapter = {
+  resolved: function(value) { return Promise.resolve(value); },
+  rejected: function(reason) { return Promise.reject(reason); },
+  deferred: function() {
+    var resolve, reject;
+    var promise = new Promise(function(res, rej) {
+      resolve = res;
+      reject = rej;
+    });
+    return {promise: promise, resolve: resolve, reject: reject};
+  }
+};
diff --git a/test/promises-aplus/lib/assert.js b/test/promises-aplus/lib/assert.js
new file mode 100644 (file)
index 0000000..0138f36
--- /dev/null
@@ -0,0 +1,97 @@
+// 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.
+
+// Mimics assert module in node.
+
+function compose(message1, message2) {
+  return message2 ? message1 + ': ' + message2 : message1
+}
+
+function fail(actual, expected, message, operator) {
+  var e = Error(compose('FAIL', message) +
+    ': (' + actual + ' ' + operator + ' ' + expected + ') should hold');
+  fails.push(e);
+  throw e;
+}
+
+function ok(value, message) {
+  if (!value) {
+    throw Error(compose('FAIL', + message) + ': value = ' + value);
+  }
+}
+
+function equal(actual, expected, message) {
+  if (!(expected == actual)) {
+    fail(actual, expected, message, '==');
+  }
+}
+
+function notEqual(actual, expected, message) {
+  if (!(expected != actual)) {
+    fail(actual, expected, message, '!=');
+  }
+}
+
+function strictEqual(actual, expected, message) {
+  if (!(expected === actual)) {
+    fail(actual, expected, message, '===');
+  }
+}
+
+function notStrictEqual(actual, expected, message) {
+  if (!(expected !== actual)) {
+    fail(actual, expected, message, '!==');
+  }
+}
+
+function assert(value, message) {
+  return ok(value, message);
+}
+
+function notImplemented() {
+  throw Error('FAIL: This assertion function is not yet implemented.');
+}
+
+function clear() {
+  this.fails = [];
+}
+
+assert.fail = fail;
+assert.ok = ok;
+assert.equal = equal;
+assert.notEqual = notEqual;
+assert.deepEqual = notImplemented;
+assert.notDeepEqual = notImplemented;
+assert.strictEqual = strictEqual;
+assert.notStrictEqual = notStrictEqual;
+assert.throws = notImplemented;
+assert.doesNotThrow = notImplemented;
+assert.ifError = notImplemented;
+
+assert.clear = clear;
+
+exports = assert;
diff --git a/test/promises-aplus/lib/global.js b/test/promises-aplus/lib/global.js
new file mode 100644 (file)
index 0000000..1466d20
--- /dev/null
@@ -0,0 +1,76 @@
+// 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.
+
+var global = this.global || {};
+var setTimeout;
+var clearTimeout;
+
+(function() {
+var timers = {};
+var currentId = 0;
+
+function PostMicrotask(fn) {
+  var o = {};
+  Object.observe(o, function() {
+    fn();
+  });
+  // Change something to enqueue a microtask.
+  o.x = 'hello';
+}
+
+setInterval = function(fn, delay) {
+  var i = 0;
+  var id = currentId++;
+  function loop() {
+    if (!timers[id]) {
+      return;
+    }
+    if (i++ >= delay) {
+      fn();
+    }
+    PostMicrotask(loop);
+  }
+  PostMicrotask(loop);
+  timers[id] = true;
+  return id;
+}
+
+clearTimeout = function(id) {
+  delete timers[id];
+}
+
+clearInterval = clearTimeout;
+
+setTimeout = function(fn, delay) {
+  var id = setInterval(function() {
+    fn();
+    clearInterval(id);
+  }, delay);
+  return id;
+}
+
+}());
diff --git a/test/promises-aplus/lib/mocha.js b/test/promises-aplus/lib/mocha.js
new file mode 100644 (file)
index 0000000..24d294e
--- /dev/null
@@ -0,0 +1,264 @@
+// 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;
+}
+
+}());
diff --git a/test/promises-aplus/lib/require.js b/test/promises-aplus/lib/require.js
new file mode 100644 (file)
index 0000000..725e45e
--- /dev/null
@@ -0,0 +1,50 @@
+// 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.
+
+var global = this.global || {};
+
+// Emulates 'require' function in Node.
+// This is not a generic function: it only works for known modules.
+var require = function(name) {
+  var exports = {};
+  var path;
+  var base = 'test/promises-aplus/'
+  if (name.search('./helpers/') === 0) {
+    path = base + 'promises-tests/lib/tests/' + name + '.js';
+  } else if (name === 'assert') {
+    path = base + 'lib/assert.js';
+  } else if (name === 'sinon') {
+    path = base + 'sinon/sinon.js';
+  } else {
+    throw Error('We cannnot load the library: ' + name);
+  }
+  eval('(function() { ' + read(path) + '}())');
+  if (name === 'sinon') {
+    return this.sinon;
+  }
+  return exports;
+};
diff --git a/test/promises-aplus/lib/run-tests.js b/test/promises-aplus/lib/run-tests.js
new file mode 100644 (file)
index 0000000..6a0a96c
--- /dev/null
@@ -0,0 +1,29 @@
+// 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.
+
+// Defined in lib/mocha.js
+RunAllTests();
diff --git a/test/promises-aplus/promises-aplus.status b/test/promises-aplus/promises-aplus.status
new file mode 100644 (file)
index 0000000..c68eae9
--- /dev/null
@@ -0,0 +1,34 @@
+# 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.
+
+
+[
+[ALWAYS, {
+  # http://crbug.com/347455
+  '2.2.7': FAIL
+}],  # ALWAYS
+]
diff --git a/test/promises-aplus/testcfg.py b/test/promises-aplus/testcfg.py
new file mode 100644 (file)
index 0000000..99495e6
--- /dev/null
@@ -0,0 +1,148 @@
+# 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.
+
+
+import hashlib
+import os
+import shutil
+import sys
+import tarfile
+import urllib
+
+from testrunner.local import testsuite
+from testrunner.objects import testcase
+
+
+SINON_TAG = '1.7.3'
+SINON_NAME = 'sinon'
+SINON_FILENAME = 'sinon.js'
+SINON_URL = 'http://sinonjs.org/releases/sinon-' + SINON_TAG + '.js'
+SINON_HASH = 'b7ab4dd9a1a2cf0460784af3728ad15caf4bbea923f680c5abde5c8332f35984'
+
+TEST_TAG = '2.0.3'
+TEST_ARCHIVE_TOP = 'promises-tests-' + TEST_TAG
+TEST_NAME = 'promises-tests'
+TEST_ARCHIVE = TEST_NAME + '.tar.gz'
+TEST_URL = 'https://github.com/promises-aplus/promises-tests/archive/' + \
+    TEST_TAG + '.tar.gz'
+TEST_ARCHIVE_HASH = \
+    'e446ca557ac5836dd439fecd19689c243a28b1d5a6644dd7fed4274d0fa67270'
+
+
+class PromiseAplusTestSuite(testsuite.TestSuite):
+
+  def __init__(self, name, root):
+    self.root = root
+    self.test_files_root = os.path.join(self.root, TEST_NAME, 'lib', 'tests')
+    self.name = name
+    self.helper_files_pre = [
+      os.path.join(root, 'lib', name) for name in
+      ['global.js', 'require.js', 'mocha.js', 'adapter.js']
+    ]
+    self.helper_files_post = [
+      os.path.join(root, 'lib', name) for name in
+      ['run-tests.js']
+    ]
+
+  def CommonTestName(self, testcase):
+    return testcase.path.split(os.path.sep)[-1]
+
+  def ListTests(self, context):
+    return [testcase.TestCase(self, fname[:-len('.js')]) for fname in
+            os.listdir(os.path.join(self.root, TEST_NAME, 'lib', 'tests'))
+            if fname.endswith('.js')]
+
+  def GetFlagsForTestCase(self, testcase, context):
+    return (testcase.flags + context.mode_flags + ['--harmony'] +
+            self.helper_files_pre +
+            [os.path.join(self.test_files_root, testcase.path + '.js')] +
+            self.helper_files_post)
+
+  def GetSourceForTest(self, testcase):
+    filename = os.path.join(self.root, TEST_NAME,
+                            'lib', 'tests', testcase.path + '.js')
+    return 'print("FAIL: fail");'
+    with open(filename) as f:
+      return f.read()
+
+  def IsNegativeTest(self, testcase):
+    return '@negative' in self.GetSourceForTest(testcase)
+
+  def IsFailureOutput(self, output, testpath):
+    if output.exit_code != 0:
+      return True
+    return not 'All tests have run.' in output.stdout or \
+           'FAIL:' in output.stdout
+
+  def DownloadTestData(self):
+    archive = os.path.join(self.root, TEST_ARCHIVE)
+    directory = os.path.join(self.root, TEST_NAME)
+    if not os.path.exists(archive):
+      print('Downloading {0} from {1} ...'.format(TEST_NAME, TEST_URL))
+      urllib.urlretrieve(TEST_URL, archive)
+      if os.path.exists(directory):
+        shutil.rmtree(directory)
+
+    if not os.path.exists(directory):
+      print('Extracting {0} ...'.format(TEST_ARCHIVE))
+      hash = hashlib.sha256()
+      with open(archive, 'rb') as f:
+        for chunk in iter(lambda: f.read(8192), ''):
+          hash.update(chunk)
+        if hash.hexdigest() != TEST_ARCHIVE_HASH:
+          os.remove(archive)
+          raise Exception('Hash mismatch of test data file')
+      archive = tarfile.open(archive, 'r:gz')
+      if sys.platform in ('win32', 'cygwin'):
+        # Magic incantation to allow longer path names on Windows.
+        archive.extractall(u'\\\\?\\%s' % self.root)
+      else:
+        archive.extractall(self.root)
+      shutil.move(os.path.join(self.root, TEST_ARCHIVE_TOP), directory)
+
+  def DownloadSinon(self):
+    directory = os.path.join(self.root, SINON_NAME)
+    if not os.path.exists(directory):
+      os.mkdir(directory)
+    path = os.path.join(directory, SINON_FILENAME)
+    if not os.path.exists(path):
+      urllib.urlretrieve(SINON_URL, path)
+    hash = hashlib.sha256()
+    with open(path, 'rb') as f:
+      for chunk in iter(lambda: f.read(8192), ''):
+        hash.update(chunk)
+    if hash.hexdigest() != SINON_HASH:
+      os.remove(path)
+      raise Exception('Hash mismatch of test data file')
+
+  def DownloadData(self):
+    self.DownloadTestData()
+    self.DownloadSinon()
+
+
+def GetSuite(name, root):
+  return PromiseAplusTestSuite(name, root)