]> git.kaiwu.me - njs.git/commitdiff
Tests: refactored JavaScript tests.
authorDmitry Volyntsev <xeioex@nginx.com>
Mon, 29 Nov 2021 16:50:41 +0000 (16:50 +0000)
committerDmitry Volyntsev <xeioex@nginx.com>
Mon, 29 Nov 2021 16:50:41 +0000 (16:50 +0000)
A generic runner test/run is introduced.  It runs all available tests
in test/ directory.  JavaScript files are expected to be compliant with
Test262.

149 files changed:
auto/make
test/finalize [new file with mode: 0644]
test/fs/methods.t.js [moved from test/fs/methods.js with 76% similarity]
test/fs/promises_01.t.js [new file with mode: 0644]
test/fs/promises_02.t.js [moved from test/js/fs_promises_002.js with 63% similarity]
test/fs/promises_03.t.js [moved from test/js/fs_promises_003.js with 84% similarity]
test/fs/promises_04.t.js [moved from test/js/fs_promises_004.js with 87% similarity]
test/fs/promises_05.t.js [moved from test/js/fs_promises_005.js with 83% similarity]
test/fs/promises_06.t.js [moved from test/js/fs_promises_006.js with 81% similarity]
test/fs/promises_07.t.js [moved from test/js/fs_promises_007.js with 90% similarity]
test/fs/promises_08.t.js [moved from test/js/fs_promises_008.js with 87% similarity]
test/fs/promises_09.t.js [moved from test/js/fs_promises_009.js with 88% similarity]
test/harness/assert.js [new file with mode: 0644]
test/harness/compareArray.js [new file with mode: 0644]
test/harness/compatBuffer.js [new file with mode: 0644]
test/harness/compatFs.js [new file with mode: 0644]
test/harness/compatPrint.js [new file with mode: 0644]
test/harness/compatWebcrypto.js [new file with mode: 0644]
test/harness/doneprintHandle.js [new file with mode: 0644]
test/harness/runTsuite.js [new file with mode: 0644]
test/harness/sta.js [new file with mode: 0644]
test/harness/webCryptoUtils.js [new file with mode: 0644]
test/js/async_await_add.js [deleted file]
test/js/async_await_add.t.js [new file with mode: 0644]
test/js/async_await_blank.js [deleted file]
test/js/async_await_blank.t.js [new file with mode: 0644]
test/js/async_await_catch.js [deleted file]
test/js/async_await_catch.t.js [new file with mode: 0644]
test/js/async_await_finally.js [deleted file]
test/js/async_await_finally.t.js [new file with mode: 0644]
test/js/async_await_for.t.js [moved from test/js/async_await_for.js with 57% similarity]
test/js/async_await_inline.t.js [moved from test/js/async_await_inline.js with 52% similarity]
test/js/async_await_many_call.t.js [moved from test/js/async_await_many_call.js with 78% similarity]
test/js/async_await_reject.js [deleted file]
test/js/async_await_reject.t.js [new file with mode: 0644]
test/js/async_await_stages.t.js [moved from test/js/async_await_stages.js with 66% similarity]
test/js/async_await_throw.t.js [moved from test/js/async_await_throw.js with 56% similarity]
test/js/async_await_throw_async.t.js [moved from test/js/async_await_throw_catch_async.js with 57% similarity]
test/js/async_await_throw_catch.t.js [moved from test/js/async_await_throw_catch.js with 64% similarity]
test/js/async_await_throw_catch_async.t.js [moved from test/js/async_await_throw_async.js with 57% similarity]
test/js/async_await_try_catch.js [deleted file]
test/js/async_await_try_catch.t.js [new file with mode: 0644]
test/js/async_await_try_finally.t.js [moved from test/js/async_await_try_finally.js with 57% similarity]
test/js/async_await_try_resolve.t.js [moved from test/js/async_await_try_resolve.js with 61% similarity]
test/js/async_await_try_throw.js [deleted file]
test/js/async_await_try_throw.t.js [new file with mode: 0644]
test/js/async_await_try_throw_catch.js [deleted file]
test/js/async_await_try_throw_catch.t.js [new file with mode: 0644]
test/js/fs_promises_001.js [deleted file]
test/js/promise_all.js [deleted file]
test/js/promise_all.t.js [new file with mode: 0644]
test/js/promise_allSettled.t.js [moved from test/js/promise_allSettled.js with 81% similarity]
test/js/promise_allSettled_string.t.js [moved from test/js/promise_allSettled_string.js with 64% similarity]
test/js/promise_all_throw.t.js [moved from test/js/promise_all_throw.js with 65% similarity]
test/js/promise_any.t.js [moved from test/js/promise_any.js with 59% similarity]
test/js/promise_any_all_rejected.js [deleted file]
test/js/promise_any_all_rejected.t.js [new file with mode: 0644]
test/js/promise_catch_then_throw_catch.js [deleted file]
test/js/promise_catch_then_throw_catch.t.js [new file with mode: 0644]
test/js/promise_catch_throw.js [deleted file]
test/js/promise_catch_throw.t.js [new file with mode: 0644]
test/js/promise_finally.js [deleted file]
test/js/promise_finally.t.js [new file with mode: 0644]
test/js/promise_finally_throw.js [deleted file]
test/js/promise_finally_throw.t.js [new file with mode: 0644]
test/js/promise_finally_throw_catch.js [deleted file]
test/js/promise_finally_throw_catch.t.js [new file with mode: 0644]
test/js/promise_race.t.js [moved from test/js/promise_race.js with 60% similarity]
test/js/promise_race_throw.t.js [moved from test/js/promise_race_throw.js with 58% similarity]
test/js/promise_reject_catch.js [deleted file]
test/js/promise_reject_catch.t.js [new file with mode: 0644]
test/js/promise_reject_post_catch.js [deleted file]
test/js/promise_reject_post_catch.t.js [new file with mode: 0644]
test/js/promise_rejection_tracker.js [deleted file]
test/js/promise_rejection_tracker.t.js [new file with mode: 0644]
test/js/promise_s01.t.js [new file with mode: 0644]
test/js/promise_s02.t.js [new file with mode: 0644]
test/js/promise_s03.t.js [new file with mode: 0644]
test/js/promise_s04.t.js [new file with mode: 0644]
test/js/promise_s05.t.js [new file with mode: 0644]
test/js/promise_s06.t.js [new file with mode: 0644]
test/js/promise_s07.t.js [new file with mode: 0644]
test/js/promise_s08.t.js [new file with mode: 0644]
test/js/promise_s09.t.js [new file with mode: 0644]
test/js/promise_s1.js [deleted file]
test/js/promise_s10.js [deleted file]
test/js/promise_s10.t.js [new file with mode: 0644]
test/js/promise_s11.js [deleted file]
test/js/promise_s11.t.js [new file with mode: 0644]
test/js/promise_s12.js [deleted file]
test/js/promise_s12.t.js [new file with mode: 0644]
test/js/promise_s13.js [deleted file]
test/js/promise_s13.t.js [new file with mode: 0644]
test/js/promise_s14.js [deleted file]
test/js/promise_s14.t.js [new file with mode: 0644]
test/js/promise_s15.js [deleted file]
test/js/promise_s15.t.js [new file with mode: 0644]
test/js/promise_s16.js [deleted file]
test/js/promise_s16.t.js [new file with mode: 0644]
test/js/promise_s17.js [deleted file]
test/js/promise_s17.t.js [new file with mode: 0644]
test/js/promise_s18.t.js [moved from test/js/promise_s18.js with 50% similarity]
test/js/promise_s19.js [deleted file]
test/js/promise_s19.t.js [new file with mode: 0644]
test/js/promise_s2.js [deleted file]
test/js/promise_s20.js [deleted file]
test/js/promise_s20.t.js [new file with mode: 0644]
test/js/promise_s21.t.js [moved from test/js/promise_s21.js with 51% similarity]
test/js/promise_s22.js [deleted file]
test/js/promise_s22.t.js [new file with mode: 0644]
test/js/promise_s23.js [deleted file]
test/js/promise_s23.t.js [new file with mode: 0644]
test/js/promise_s24.t.js [moved from test/js/promise_s24.js with 65% similarity]
test/js/promise_s25.js [deleted file]
test/js/promise_s25.t.js [new file with mode: 0644]
test/js/promise_s26.js [deleted file]
test/js/promise_s26.t.js [new file with mode: 0644]
test/js/promise_s3.js [deleted file]
test/js/promise_s4.js [deleted file]
test/js/promise_s5.js [deleted file]
test/js/promise_s6.js [deleted file]
test/js/promise_s7.js [deleted file]
test/js/promise_s8.js [deleted file]
test/js/promise_s9.js [deleted file]
test/js/promise_set_timeout.t.js [moved from test/js/promise_set_timeout.js with 63% similarity]
test/js/promise_then_throw.js [deleted file]
test/js/promise_then_throw.t.js [new file with mode: 0644]
test/js/promise_then_throw_catch.js [deleted file]
test/js/promise_then_throw_catch.t.js [new file with mode: 0644]
test/js/promise_then_throw_finally_catch.js [deleted file]
test/js/promise_then_throw_finally_catch.t.js [new file with mode: 0644]
test/js/promise_two_first_then_throw.t.js [moved from test/js/promise_two_first_then_throw.js with 65% similarity]
test/js/promise_two_then_throw.js [deleted file]
test/js/promise_two_then_throw.t.js [new file with mode: 0644]
test/njs_expect_test.exp
test/options [new file with mode: 0644]
test/prepare [new file with mode: 0644]
test/report [new file with mode: 0644]
test/setup [new file with mode: 0644]
test/test262 [new file with mode: 0755]
test/webcrypto/aes.t.js [moved from test/webcrypto/aes.js with 77% similarity]
test/webcrypto/aes_decoding.t.js [moved from test/webcrypto/aes_decoding.js with 69% similarity]
test/webcrypto/derive.t.js [moved from test/webcrypto/derive.js with 70% similarity]
test/webcrypto/digest.t.js [moved from test/webcrypto/digest.js with 69% similarity]
test/webcrypto/rsa.t.js [moved from test/webcrypto/rsa.js with 61% similarity]
test/webcrypto/rsa_decoding.js [deleted file]
test/webcrypto/rsa_decoding.t.js [new file with mode: 0644]
test/webcrypto/sign.t.js [moved from test/webcrypto/sign.js with 81% similarity]
test/webcrypto/verify.t.js [moved from test/webcrypto/verify.js with 70% similarity]

index 9a807a8fee437a4fdcd212be24059b6ff1dee016..2aaafeac293b440a67e82183eed14ba6589caed5 100644 (file)
--- a/auto/make
+++ b/auto/make
@@ -209,12 +209,16 @@ lib_test: $NJS_BUILD_DIR/njs_auto_config.h \\
        $NJS_BUILD_DIR/lvlhsh_unit_test
        $NJS_BUILD_DIR/unicode_unit_test
 
+test262: njs
+
+       test/test262
+
 unit_test: $NJS_BUILD_DIR/njs_auto_config.h \\
        $NJS_BUILD_DIR/njs_unit_test
 
        $NJS_BUILD_DIR/njs_unit_test
 
-test: expect_test unit_test
+test: expect_test unit_test test262
 
 benchmark: $NJS_BUILD_DIR/njs_auto_config.h \\
        $NJS_BUILD_DIR/njs_benchmark
diff --git a/test/finalize b/test/finalize
new file mode 100644 (file)
index 0000000..59d8d09
--- /dev/null
@@ -0,0 +1,11 @@
+#!/bin/sh
+
+# Copyright (C) Dmitry Volyntsev
+# Copyright (C) NGINX, Inc.
+
+if [ -z "$NJS_TEST_VERBOSE"  ]; then
+    verbose "Removing dir: $NJS_TEST_DIR\n"
+    verbose "\n"
+
+    rm -fr $NJS_TEST_DIR
+fi
similarity index 76%
rename from test/fs/methods.js
rename to test/fs/methods.t.js
index 2769bc746321c439570c5d4fd5159437cdb803b9..64aa809b92976067dd87e588f098624223512f5e 100644 (file)
@@ -1,41 +1,7 @@
-var fs = require('fs');
-
-async function run(tlist) {
-    function validate(t, r, i) {
-        if (r.status == "fulfilled") {
-            return r.value === "SUCCESS";
-        }
-
-        if (r.status == "rejected" && t[i].exception) {
-            if (process.argv[2] === '--match-exception-text') {
-                /* is not compatible with node.js format */
-                return r.reason.toString().startsWith(t[i].exception);
-            }
-
-            return true;
-        }
-
-        if (r.status == "rejected" && t[i].optional) {
-            return r.reason.toString().startsWith("Error: No such file or directory");
-        }
-
-        return false;
-    }
-
-    for (let k = 0; k < tlist.length; k++) {
-        let ts = tlist[k];
-        let results = await Promise.allSettled(ts.tests.map(t => ts.T(ts.prepare_args(t, ts.opts))));
-        let r = results.map((r, i) => validate(ts.tests, r, i));
-
-        console.log(`${ts.name} ${r.every(v=>v == true) ? "SUCCESS" : "FAILED"}`);
-
-        r.forEach((v, i) => {
-            if (!v) {
-                console.log(`FAILED ${i}: ${JSON.stringify(ts.tests[i])}\n    with reason: ${results[i].reason}`);
-            }
-        })
-    }
-}
+/*---
+includes: [compatFs.js, compatBuffer.js, runTsuite.js]
+flags: [async]
+---*/
 
 function p(args, default_opts) {
     let params = Object.assign({}, default_opts, args);
@@ -73,41 +39,15 @@ async function method(name, params) {
 
     switch (params.type) {
     case "sync":
-        try {
-            data = fs[name + "Sync"].apply(null, params.args);
-
-        } catch (e) {
-            if (!params.stringify) {
-                throw e;
-            }
-
-            data = Buffer.from(JSON.stringify(e));
-        }
-
+        data = fs[name + "Sync"].apply(null, params.args);
         break;
 
     case "callback":
-        data = await promisify(fs[name]).apply(null, params.args)
-              .catch(e => {
-                  if (!params.stringify) {
-                      throw e;
-                  }
-
-                  return Buffer.from(JSON.stringify(e));
-              });
-
+        data = await promisify(fs[name]).apply(null, params.args);
         break;
 
     case "promise":
-        data = await fs.promises[name].apply(null, params.args)
-              .catch(e => {
-                  if (!params.stringify) {
-                      throw e;
-                  }
-
-                  return Buffer.from(JSON.stringify(e));
-              });
-
+        data = await fs.promises[name].apply(null, params.args);
         break;
     }
 
@@ -115,37 +55,63 @@ async function method(name, params) {
 }
 
 async function read_test(params) {
-    let data = await method("readFile", params);
+    let data = await method("readFile", params).catch(e => ({error:e}));
 
-    if (params.slice) {
+    if (params.slice && !data.error) {
         data = data.slice.apply(data, params.slice);
     }
 
-    let success = true;
-    if (data instanceof Buffer) {
-        if (data.compare(params.expected) != 0) {
-            success = false;
+    if (params.check) {
+        if (!params.check(data, params)) {
+            throw Error(`readFile failed check`);
         }
 
-    } else if (data != params.expected) {
-        success = false;
-    }
+    } else if (params.exception) {
+        throw data.error;
+
+    } else {
+        let success = true;
+        if (data instanceof Buffer) {
+            if (data.compare(params.expected) != 0) {
+                success = false;
+            }
+
+        } else if (data != params.expected) {
+            success = false;
+        }
 
-    if (!success) {
-        throw Error(`readFile unexpected data`);
+        if (!success) {
+            throw Error(`readFile unexpected data`);
+        }
     }
 
     return 'SUCCESS';
 }
 
-let read_tests = [
+let read_tests = () => [
     { args: ["test/fs/utf8"], expected: Buffer.from("αβZγ") },
     { args: [Buffer.from("@test/fs/utf8").slice(1)], expected: Buffer.from("αβZγ") },
     { args: ["test/fs/utf8", "utf8"], expected: "αβZγ" },
     { args: ["test/fs/utf8", {encoding: "utf8", flags:"r+"}], expected: "αβZγ" },
-    { args: ["test/fs/nonexistent"], stringify: true,
-      expected: Buffer.from('{"errno":2,"code":"ENOENT","path":"test/fs/nonexistent","syscall":"open"}'),
-      exception: "Error: No such file or directory" },
+    { args: ["test/fs/nonexistent"],
+      check: (err, params) => {
+          let e = err.error;
+
+          if (e.syscall != 'open') {
+              throw Error(`${e.syscall} unexpected syscall`);
+          }
+
+          if (e.code != "ENOENT") {
+              throw Error(`${e.code} unexpected code`);
+          }
+
+          if (e.path != "test/fs/nonexistent") {
+              throw Error(`${e.path} unexpected path`);
+          }
+
+          return true;
+      } },
+
     { args: ["test/fs/non_utf8", "utf8"], expected: "��" },
     { args: ["test/fs/non_utf8", {encoding: "hex"}], expected: "8080" },
     { args: ["test/fs/non_utf8", "base64"], expected: "gIA=" },
@@ -155,32 +121,61 @@ let read_tests = [
     { args: [Buffer.from([0x80, 0x80])], exception: "Error: No such file or directory" },
     { args: ['x'.repeat(8192)], exception: "TypeError: \"path\" is too long" },
 
-    { args: ["/proc/version"], slice:[0,5], expected: Buffer.from("Linux"), optional: true },
-    { args: ["/proc/cpuinfo"], slice:[0,9], expected: Buffer.from("processor"), optional: true },
+    { args: ["/proc/version"], slice:[0,5], expected: Buffer.from("Linux"),
+      check: (data, params) => {
+
+          if (data.error) {
+              let e = data.error;
+              if (e.syscall != 'open') {
+                  throw Error(`${e.syscall} unexpected syscall`);
+              }
+
+              return true;
+          }
+
+          return data.compare(params.expected) == 0;
+      } },
+    { args: ["/proc/cpuinfo"], slice:[0,9], expected: Buffer.from("processor"),
+      check: (data, params) => {
+
+          if (data.error) {
+              let e = data.error;
+              if (e.syscall != 'open') {
+                  throw Error(`${e.syscall} unexpected syscall`);
+              }
+
+              return true;
+          }
+
+          return data.compare(params.expected) == 0;
+      } },
 ];
 
 let readFile_tsuite = {
     name: "fs readFile",
+    skip: () => (!has_fs() || !has_buffer()),
     T: read_test,
     prepare_args: p,
     opts: { type: "callback" },
-    tests: read_tests,
+    get tests() { return read_tests() },
 };
 
 let readFileSync_tsuite = {
     name: "fs readFileSync",
+    skip: () => (!has_fs() || !has_buffer()),
     T: read_test,
     prepare_args: p,
     opts: { type: "sync" },
-    tests: read_tests,
+    get tests() { return read_tests() },
 };
 
 let readFileP_tsuite = {
     name: "fsp readFile",
+    skip: () => (!has_fs() || !has_buffer()),
     T: read_test,
     prepare_args: p,
     opts: { type: "promise" },
-    tests: read_tests,
+    get tests() { return read_tests() },
 };
 
 async function write_test(params) {
@@ -213,7 +208,7 @@ async function write_test(params) {
     return 'SUCCESS';
 }
 
-let write_tests = [
+let write_tests = () => [
     { args: ["@", Buffer.from(Buffer.alloc(4).fill(65).buffer, 1)],
       expected: Buffer.from("AAA") },
     { args: ["@", Buffer.from("XYZ"), "utf8"], expected: Buffer.from("XYZ") },
@@ -247,26 +242,29 @@ let write_tests = [
 
 let writeFile_tsuite = {
     name: "fs writeFile",
+    skip: () => (!has_fs() || !has_buffer()),
     T: write_test,
     prepare_args: p,
     opts: { type: "callback" },
-    tests: write_tests,
+    get tests() { return write_tests() },
 };
 
 let writeFileSync_tsuite = {
     name: "fs writeFileSync",
+    skip: () => (!has_fs() || !has_buffer()),
     T: write_test,
     prepare_args: p,
     opts: { type: "sync" },
-    tests: write_tests,
+    get tests() { return write_tests() },
 };
 
 let writeFileP_tsuite = {
     name: "fsp writeFile",
+    skip: () => (!has_fs() || !has_buffer()),
     T: write_test,
     prepare_args: p,
     opts: { type: "promise" },
-    tests: write_tests,
+    get tests() { return write_tests() },
 };
 
 async function append_test(params) {
@@ -300,7 +298,7 @@ async function append_test(params) {
     return 'SUCCESS';
 }
 
-let append_tests = [
+let append_tests = () => [
     { args: ["@", Buffer.from(Buffer.alloc(4).fill(65).buffer, 1)],
       expected: Buffer.from("AAAAAA") },
     { args: ["@", Buffer.from("XYZ"), "utf8"], expected: Buffer.from("XYZXYZ") },
@@ -334,26 +332,29 @@ let append_tests = [
 
 let appendFile_tsuite = {
     name: "fs appendFile",
+    skip: () => (!has_fs() || !has_buffer()),
     T: append_test,
     prepare_args: p,
     opts: { type: "callback" },
-    tests: append_tests,
+    get tests() { return append_tests() },
 };
 
 let appendFileSync_tsuite = {
     name: "fs appendFileSync",
+    skip: () => (!has_fs() || !has_buffer()),
     T: append_test,
     prepare_args: p,
     opts: { type: "sync" },
-    tests: append_tests,
+    get tests() { return append_tests() },
 };
 
 let appendFileP_tsuite = {
     name: "fsp appendFile",
+    skip: () => (!has_fs() || !has_buffer()),
     T: append_test,
     prepare_args: p,
     opts: { type: "promise" },
-    tests: append_tests,
+    get tests() { return append_tests() },
 };
 
 async function realpath_test(params) {
@@ -366,35 +367,38 @@ async function realpath_test(params) {
     return 'SUCCESS';
 }
 
-let realpath_tests = [
-    { args: ["./build/test/.."],
+let realpath_tests = () => [
+    { args: ["build/test/.."],
       check: (data) => data.endsWith("build") },
-    { args: ["./build/test/", {encoding:'buffer'}],
+    { args: ["build/test/", {encoding:'buffer'}],
       check: (data) => data instanceof Buffer },
 ];
 
 let realpath_tsuite = {
     name: "fs realpath",
+    skip: () => (!has_fs() || !has_buffer()),
     T: realpath_test,
     prepare_args: p,
     opts: { type: "callback" },
-    tests: realpath_tests,
+    get tests() { return realpath_tests() },
 };
 
 let realpathSync_tsuite = {
     name: "fs realpathSync",
+    skip: () => (!has_fs() || !has_buffer()),
     T: realpath_test,
     prepare_args: p,
     opts: { type: "sync" },
-    tests: realpath_tests,
+    get tests() { return realpath_tests() },
 };
 
 let realpathP_tsuite = {
     name: "fsp realpath",
+    skip: () => (!has_fs() || !has_buffer()),
     T: realpath_test,
     prepare_args: p,
     opts: { type: "promise" },
-    tests: realpath_tests,
+    get tests() { return realpath_tests() },
 };
 
 async function stat_test(params) {
@@ -423,7 +427,7 @@ function contains(arr, elts) {
     });
 }
 
-let stat_tests = [
+let stat_tests = () => [
     { args: ["/invalid_path"],
       check: (err, params) => {
           let e = err.error;
@@ -474,14 +478,14 @@ let stat_tests = [
           return true;
       } },
 
-    { args: ["./build/"],
+    { args: ["build/"],
       check: (st) => contains(Object.keys(st),
                               [ "atime", "atimeMs", "birthtime", "birthtimeMs",
                                 "blksize", "blocks", "ctime", "ctimeMs", "dev",
                                 "gid", "ino", "mode", "mtime", "mtimeMs","nlink",
                                 "rdev", "size", "uid" ]) },
 
-    { args: ["./build/"],
+    { args: ["build/"],
       check: (st) => Object.keys(st).every(p => {
         let v = st[p];
         if (p == 'atime' || p == 'ctime' || p == 'mtime' || p == 'birthtime') {
@@ -499,7 +503,7 @@ let stat_tests = [
         return true;
       }) },
 
-    { args: ["./build/"],
+    { args: ["build/"],
       check: (st) => ['atime', 'birthtime', 'ctime', 'mtime'].every(p => {
           let date = st[p].valueOf();
           let num = st[p + 'Ms'];
@@ -511,7 +515,7 @@ let stat_tests = [
           return true;
       }) },
 
-    { args: ["./build/"],
+    { args: ["build/"],
       check: (st) => ['isBlockDevice',
                       'isCharacterDevice',
                       'isDirectory',
@@ -531,50 +535,56 @@ let stat_tests = [
 
 let stat_tsuite = {
     name: "fs stat",
+    skip: () => (!has_fs() || !has_buffer()),
     T: stat_test,
     prepare_args: p,
     opts: { type: "callback", method: "stat" },
-    tests: stat_tests,
+    get tests() { return stat_tests() },
 };
 
 let statSync_tsuite = {
     name: "fs statSync",
+    skip: () => (!has_fs() || !has_buffer()),
     T: stat_test,
     prepare_args: p,
     opts: { type: "sync", method: "stat" },
-    tests: stat_tests,
+    get tests() { return stat_tests() },
 };
 
 let statP_tsuite = {
     name: "fsp stat",
+    skip: () => (!has_fs() || !has_buffer()),
     T: stat_test,
     prepare_args: p,
     opts: { type: "promise", method: "stat" },
-    tests: stat_tests,
+    get tests() { return stat_tests() },
 };
 
 let lstat_tsuite = {
     name: "fs lstat",
+    skip: () => (!has_fs() || !has_buffer()),
     T: stat_test,
     prepare_args: p,
     opts: { type: "callback", method: "lstat" },
-    tests: stat_tests,
+    get tests() { return stat_tests() },
 };
 
 let lstatSync_tsuite = {
     name: "fs lstatSync",
+    skip: () => (!has_fs() || !has_buffer()),
     T: stat_test,
     prepare_args: p,
     opts: { type: "sync", method: "lstat" },
-    tests: stat_tests,
+    get tests() { return stat_tests() },
 };
 
 let lstatP_tsuite = {
     name: "fsp lstat",
+    skip: () => (!has_fs() || !has_buffer()),
     T: stat_test,
     prepare_args: p,
     opts: { type: "promise", method: "lstat" },
-    tests: stat_tests,
+    get tests() { return stat_tests() },
 };
 
 run([
@@ -596,4 +606,5 @@ run([
     lstat_tsuite,
     lstatSync_tsuite,
     lstatP_tsuite,
-]);
+])
+.then($DONE, $DONE);
diff --git a/test/fs/promises_01.t.js b/test/fs/promises_01.t.js
new file mode 100644 (file)
index 0000000..2219315
--- /dev/null
@@ -0,0 +1,42 @@
+/*---
+includes: [compareArray.js, compatFs.js]
+flags: [async]
+---*/
+
+var fname = 'build/test/fs_promises_01';
+
+let stages = [];
+
+Promise.resolve()
+.then(() => {
+    return fsp.writeFile(fname, fname);
+})
+.then(data => {
+    stages.push('init');
+    assert.sameValue(data, undefined, 'init');
+})
+.then(() => {
+    return fsp.readFile(fname).then(fsp.readFile);
+})
+.then(data => {
+    stages.push('short circut');
+    assert.sameValue(data.toString(), fname, 'short circut');
+})
+.then(() => {
+    var read = fsp.readFile.bind(fsp, fname, 'utf8');
+    var write = fsp.writeFile.bind(fsp, fname);
+    var append = fsp.appendFile.bind(fsp, fname);
+
+    return write(fname).then(read).then(append).then(read);
+})
+.then(data => {
+    stages.push('chain');
+    assert.sameValue(data, fname + fname, 'chain');
+})
+.then(() => {
+    stages.push('errors ok');
+})
+.then(() => {
+    assert.compareArray(stages, ["init", "short circut", "chain", "errors ok"]);
+})
+.then($DONE, $DONE);
similarity index 63%
rename from test/js/fs_promises_002.js
rename to test/fs/promises_02.t.js
index 8345ca400b2015661d2e50de777578558cbed28a..a07f74125fd8962833165a4da3c7c758633ab108 100644 (file)
@@ -1,6 +1,9 @@
-var fs = require('fs');
-var fsp  = fs.promises;
-var fname = './build/test/fs_promises_002';
+/*---
+includes: [compareArray.js, compatFs.js]
+flags: [async]
+---*/
+
+var fname = 'build/test/fs_promises_02';
 
 var testSync = new Promise((resolve, reject) => {
     var failed = false;
@@ -16,7 +19,7 @@ var testSync = new Promise((resolve, reject) => {
         } catch(e) {
             failed = (e.syscall != 'access') || e.code != 'ENOENT';
         }
-        resolve(failed);
+        resolve(Boolean(failed));
     } catch (e) {
         reject(e);
     }
@@ -34,26 +37,24 @@ var testCallback = new Promise((resolve, reject) => {
             fs.access(fname + '___', (err) => {
                 failed |= ((err === undefined) || (err.syscall != 'access')
                                                || err.code != 'ENOENT');
-                resolve(failed);
+                resolve(Boolean(failed));
             });
         });
     });
 });
 
+let stages = [];
+
 Promise.resolve()
 .then(() => testSync)
-.then((failed) => {
-    console.log('testSync ok', !failed);
-})
-.catch((e) => {
-    console.log('testSync failed', e);
+.then(failed => {
+    stages.push('testSync');
+    assert.sameValue(failed, false, 'testSync');
 })
 .then(() => testCallback)
-.then((failed) => {
-    console.log('testCallback ok', !failed);
-})
-.catch((e) => {
-    console.log('testCallback failed', e);
+.then(failed => {
+    stages.push('testCallback');
+    assert.sameValue(failed, false, 'testCallback');
 })
 .then(() => {
     fs.writeFileSync(fname, fname);
@@ -63,10 +64,15 @@ Promise.resolve()
         .then(() => fsp.access(fname + '___'));
 })
 .then(() => {
-    console.log('testPromise failed');
+    $DONOTEVALUATE();
+})
+.catch(e => {
+    stages.push('testPromise');
+    assert.sameValue(e.syscall, 'access', 'testPromise');
+    assert.sameValue(e.path, fname + '___', 'testPromise');
+    assert.sameValue(e.code, 'ENOENT', 'testPromise');
 })
-.catch((e) => {
-    console.log('testPromise ok', (e.syscall == 'access') && (e.path == fname + '___')
-                                                          && e.code == 'ENOENT');
+.then(() => {
+    assert.compareArray(stages, ["testSync", "testCallback", "testPromise"]);
 })
-;
+.then($DONE, $DONE);
similarity index 84%
rename from test/js/fs_promises_003.js
rename to test/fs/promises_03.t.js
index 671a97e95020a2d84d32c9bd92c9c13df68736cd..1c7d94c84aa616df6826ddf4c07118f9512ef4d9 100644 (file)
@@ -1,7 +1,9 @@
-var fs = require('fs');
-var fsp  = fs.promises;
-var fname = './build/test/fs_promises_003';
+/*---
+includes: [compareArray.js, compatFs.js]
+flags: [async]
+---*/
 
+var fname = 'build/test/fs_promises_03';
 
 var testSync = () => new Promise((resolve, reject) => {
     try {
@@ -68,22 +70,17 @@ var testCallback = () => new Promise((resolve, reject) => {
     });
 });
 
+let stages = [];
 
 Promise.resolve()
 .then(testSync)
 .then(() => {
-    console.log('test fs.unlinkSync');
-})
-.catch((e) => {
-    console.log('test fs.unlinkSync failed', e);
+    stages.push("unlinkSync");
 })
 
 .then(testCallback)
 .then(() => {
-    console.log('test fs.unlink');
-})
-.catch((e) => {
-    console.log('test fs.unlink failed', e);
+    stages.push("unlink");
 })
 
 .then(() => fsp.unlink(fname)
@@ -101,8 +98,7 @@ Promise.resolve()
 .catch((e) => { if (e.syscall != 'access') { throw e; } })
 
 .then(() => {
-    console.log('test fsp.unlink');
+    stages.push("fsp.unlink");
 })
-.catch((e) => {
-    console.log('test fsp.unlink failed', e);
-});
+.then(() => assert.compareArray(stages, ['unlinkSync', 'unlink', 'fsp.unlink']))
+.then($DONE, $DONE);
similarity index 87%
rename from test/js/fs_promises_004.js
rename to test/fs/promises_04.t.js
index 873e787ca40911471959ec17e639885c6f9f2f22..d6e61ae2411d518e937f32b625810e33638bce90 100644 (file)
@@ -1,10 +1,12 @@
-var fs = require('fs');
-var fsp  = fs.promises;
-var dname = './build/test/';
-var fname = dname + 'fs_promises_004';
-var fname_utf8 = dname + 'fs_promises_αβγ_004';
-var lname = dname + 'fs_promises_004_lnk';
+/*---
+includes: [compareArray.js, compatFs.js]
+flags: [async]
+---*/
 
+var dname = 'build/test/';
+var fname = dname + 'fs_promises_04';
+var fname_utf8 = dname + 'fs_promises_αβγ_04';
+var lname = dname + 'fs_promises_04_lnk';
 
 var testSync = () => new Promise((resolve, reject) => {
     try {
@@ -44,7 +46,7 @@ var testSync = () => new Promise((resolve, reject) => {
         }
 
         var rname_utf8 = fs.realpathSync(fname_utf8);
-        if (rname_utf8.slice(-7,-4) != 'αβγ') {
+        if (rname_utf8.slice(-6,-3) != 'αβγ') {
             throw new Error('fs.realpathSync error 2');
         }
 
@@ -140,22 +142,17 @@ var testCallback = () => new Promise((resolve, reject) => {
     }
 });
 
+let stages = [];
 
 Promise.resolve()
 .then(testSync)
 .then(() => {
-    console.log('test fs.symlinkSync');
-})
-.catch((e) => {
-    console.log('test fs.symlinkSync failed', e);
+    stages.push("symlinkSync");
 })
 
 .then(testCallback)
 .then(() => {
-    console.log('test fs.symlink');
-})
-.catch((e) => {
-    console.log('test fs.symlink failed', e);
+    stages.push("symlink");
 })
 
 .then(() => fsp.unlink(fname)
@@ -179,7 +176,7 @@ Promise.resolve()
 .then((rname) => fsp.realpath(lname)
                  .then((xname) => {
                      if (rname != xname) {
-                        throw new Error('fsp.symlink error 2');
+                        throw new Error(`fsp.symlink error 2`);
                      }
                  }))
 .then(() => {
@@ -193,8 +190,7 @@ Promise.resolve()
 })
 
 .then(() => {
-    console.log('test fsp.symlink');
+    stages.push("fsp.symlink");
 })
-.catch((e) => {
-    console.log('test fsp.symlink failed', e);
-});
+.then(() => assert.compareArray(stages, ['symlinkSync', 'symlink', 'fsp.symlink']))
+.then($DONE, $DONE);
similarity index 83%
rename from test/js/fs_promises_005.js
rename to test/fs/promises_05.t.js
index 544e2047959684f98e85dc36a9c2657da0175f49..f957d776fa76048d65052829ae3a622e687041a1 100644 (file)
@@ -1,10 +1,12 @@
-var fs = require('fs');
-var fsp  = fs.promises;
-var rname = './build/test/';
-var dname = rname + 'fs_promises_005';
-var dname_utf8 = rname + 'fs_promises_αβγ_005';
-var fname = (d) => d + '/fs_promises_005_file';
+/*---
+includes: [compareArray.js, compatFs.js]
+flags: [async]
+---*/
 
+var rname = 'build/test/';
+var dname = rname + 'fs_promises_05';
+var dname_utf8 = rname + 'fs_promises_αβγ_05';
+var fname = (d) => d + '/fs_promises_05_file';
 
 var testSync = () => new Promise((resolve, reject) => {
     try {
@@ -104,21 +106,18 @@ var testCallback = () => new Promise((resolve, reject) => {
 });
 
 
+let stages = [];
+
 Promise.resolve()
 .then(testSync)
 .then(() => {
-    console.log('test fs.mkdirSync');
-})
-.catch((e) => {
-    console.log('test fs.mkdirSync failed', JSON.stringify(e));
+    stages.push("mkdirSync");
 })
 
+
 .then(testCallback)
 .then(() => {
-    console.log('test fs.mkdir');
-})
-.catch((e) => {
-    console.log('test fs.mkdir failed', JSON.stringify(e));
+    stages.push("mkdir");
 })
 
 .then(() => {
@@ -136,8 +135,7 @@ Promise.resolve()
 })
 .then(() => fsp.rmdir(dname))
 .then(() => {
-    console.log('test fsp.mkdir');
+    stages.push("fsp.mkdir");
 })
-.catch((e) => {
-    console.log('test fsp.mkdir failed', JSON.stringify(e));
-});
+.then(() => assert.compareArray(stages, ['mkdirSync', 'mkdir', 'fsp.mkdir']))
+.then($DONE, $DONE);
similarity index 81%
rename from test/js/fs_promises_006.js
rename to test/fs/promises_06.t.js
index a5794f9234f7cfd4e621ff5a3f806d9517a650b1..9a5186c2aee59f840dab9cd4a974583f50de97af 100644 (file)
@@ -1,8 +1,11 @@
-var fs = require('fs');
-var fsp  = fs.promises;
-var dname = './build/test/';
-var fname = (d) => d + '/fs_promises_006_file';
-var fname_utf8 = (d) => d + '/fs_promises_αβγ_006';
+/*---
+includes: [compareArray.js, compatFs.js]
+flags: [async]
+---*/
+
+var dname = 'build/test/';
+var fname = (d) => d + '/fs_promises_06_file';
+var fname_utf8 = (d) => d + '/fs_promises_αβγ_06';
 
 var testSync = new Promise((resolve, reject) => {
     try {
@@ -63,18 +66,17 @@ var testCallback = new Promise((resolve, reject) => {
     }
 });
 
+let stages = [];
+
 Promise.resolve()
 .then(() => testSync)
 .then(() => {
-    console.log('test fs.renameSync');
-})
-.catch((e) => {
-    console.log('test fs.renameSync failed', JSON.stringify(e));
+    stages.push("renameSync");
 })
 
 .then(testCallback)
 .then(() => {
-    console.log('test fs.rename');
+    stages.push("rename");
 })
 .catch((e) => {
     console.log('test fs.rename failed', JSON.stringify(e));
@@ -97,8 +99,7 @@ Promise.resolve()
     }
 })
 .then(() => {
-    console.log('test fsp.rename');
+    stages.push("fsp.rename");
 })
-.catch((e) => {
-    console.log('test fsp.rename failed', JSON.stringify(e));
-});
+.then(() => assert.compareArray(stages, ["renameSync", "rename", "fsp.rename"]))
+.then($DONE, $DONE);
similarity index 90%
rename from test/js/fs_promises_007.js
rename to test/fs/promises_07.t.js
index e02796cbbe49a67aad4289df7f8322e3dd459999..e4fcb42ca188755cdb8ad52a5b466309d4b0ec29 100644 (file)
@@ -1,10 +1,13 @@
-var fs = require('fs');
-var fsp  = fs.promises;
-var dname = './build/test/fs_promises_007';
-var dname_utf8 = './build/test/fs_promises_αβγ_007';
-var fname = (d) => d + '/fs_promises_007_file';
-var lname = (d) => d + '/fs_promises_007_link';
-var cname = (d) => d + '/fs_promises_αβγ_007_dir';
+/*---
+includes: [compareArray.js, compatFs.js]
+flags: [async]
+---*/
+
+var dname = 'build/test/fs_promises_07';
+var dname_utf8 = 'build/test/fs_promises_αβγ_07';
+var fname = (d) => d + '/fs_promises_07_file';
+var lname = (d) => d + '/fs_promises_07_link';
+var cname = (d) => d + '/fs_promises_αβγ_07_dir';
 
 
 var dir_test = [cname(''), lname(''), fname('')].map((x) => x.substring(1));
@@ -175,21 +178,17 @@ var testCallback = () => new Promise((resolve, reject) => {
 });
 
 
+let stages = [];
+
 Promise.resolve()
 .then(testSync)
 .then(() => {
-    console.log('test fs.readdirSync');
-})
-.catch((e) => {
-    console.log('test fs.readdirSync failed', e, JSON.stringify(e));
+    stages.push("readdirSync");
 })
 
 .then(testCallback)
 .then(() => {
-    console.log('test fs.readdir');
-})
-.catch((e) => {
-    console.log('test fs.readdir failed', e, JSON.stringify(e));
+    stages.push("readdir");
 })
 
 .then(() => {
@@ -234,8 +233,7 @@ Promise.resolve()
     }
 })
 .then(() => {
-    console.log('test fsp.readdir');
+    stages.push("fsp.readdir");
 })
-.catch((e) => {
-    console.log('test fsp.readdir failed', e, JSON.stringify(e));
-});
+.then(() => assert.compareArray(stages, ["readdirSync", "readdir", "fsp.readdir"]))
+.then($DONE, $DONE);
similarity index 87%
rename from test/js/fs_promises_008.js
rename to test/fs/promises_08.t.js
index 8e83c307008ba4ed0872325e983f2e0ba744b2c3..f0b393b7279641d0e125c8a6f8939e1088c1fe36 100644 (file)
@@ -1,6 +1,9 @@
-var fs = require('fs');
-var fsp  = fs.promises;
-var dname = './build/test/fs_promises_αβγ_008/';
+/*---
+includes: [compareArray.js, compatFs.js]
+flags: [async]
+---*/
+
+var dname = 'build/test/fs_promises_αβγ_08/';
 var path = 'one/two/three/αβγ';
 
 var wipePath = (root, path, nofail) => {
@@ -69,11 +72,15 @@ var testSync = () => new Promise((resolve, reject) => {
     }
 });
 
+let stages = [];
+
 Promise.resolve()
 .then(testSync)
 .then(() => {
-    console.log('test recursive fs.mkdirSync');
+    stages.push("mkdirSync");
 })
 .catch((e) => {
-    console.log('test failed recursive fs.mkdirSync', JSON.stringify(e));
+    $DONOTEVALUATE();
 })
+.then(() => assert.compareArray(stages, ["mkdirSync"]))
+.then($DONE, $DONE);
similarity index 88%
rename from test/js/fs_promises_009.js
rename to test/fs/promises_09.t.js
index 90b6df99d0c3786c1a1c2a41d70e317e6e621d14..7ca0b8c5d8afdadbb9bccd7114046cdd61556672 100644 (file)
@@ -1,11 +1,13 @@
-var fs = require('fs');
-var fsp  = fs.promises;
-var root = './build/test/';
-var dname = 'fs_promises_αβγ_009/';
-var lname = 'fs_promises_αβγ_009_lnk';
+/*---
+includes: [compareArray.js, compatFs.js]
+flags: [async]
+---*/
+
+var root = 'build/test/';
+var dname = 'fs_promises_αβγ_09/';
+var lname = 'fs_promises_αβγ_09_lnk';
 var path = 'one/two/three/αβγ';
 
-
 var setContent = (root, path) => {
     fs.mkdirSync(root + path, { recursive: true });
     path
@@ -96,11 +98,12 @@ var testSync = () => new Promise((resolve, reject) => {
 });
 
 
+let stages = [];
+
 Promise.resolve()
 .then(testSync)
 .then(() => {
-    console.log('test recursive fs.rmdirSync()');
+    stages.push("rmdirSync");
 })
-.catch((e) => {
-    console.log('test failed recursive fs.rmdirSync()', e.message, JSON.stringify(e));
-});
+.then(() => assert.compareArray(stages, ["rmdirSync"]))
+.then($DONE, $DONE);
diff --git a/test/harness/assert.js b/test/harness/assert.js
new file mode 100644 (file)
index 0000000..34eed55
--- /dev/null
@@ -0,0 +1,118 @@
+// Copyright (C) 2017 Ecma International.  All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+/*---
+description: |
+    Collection of assertion functions used throughout test262
+defines: [assert]
+---*/
+
+
+function assert(mustBeTrue, message) {
+  if (mustBeTrue === true) {
+    return;
+  }
+
+  if (message === undefined) {
+    message = 'Expected true but got ' + assert._toString(mustBeTrue);
+  }
+  throw new Test262Error(message);
+}
+
+assert._isSameValue = function (a, b) {
+  if (a === b) {
+    // Handle +/-0 vs. -/+0
+    return a !== 0 || 1 / a === 1 / b;
+  }
+
+  // Handle NaN vs. NaN
+  return a !== a && b !== b;
+};
+
+assert.sameValue = function (actual, expected, message) {
+  try {
+    if (assert._isSameValue(actual, expected)) {
+      return;
+    }
+  } catch (error) {
+    throw new Test262Error(message + ' (_isSameValue operation threw) ' + error);
+    return;
+  }
+
+  if (message === undefined) {
+    message = '';
+  } else {
+    message += ' ';
+  }
+
+  message += 'Expected SameValue(«' + assert._toString(actual) + '», Â«' + assert._toString(expected) + '») to be true';
+
+  throw new Test262Error(message);
+};
+
+assert.notSameValue = function (actual, unexpected, message) {
+  if (!assert._isSameValue(actual, unexpected)) {
+    return;
+  }
+
+  if (message === undefined) {
+    message = '';
+  } else {
+    message += ' ';
+  }
+
+  message += 'Expected SameValue(«' + assert._toString(actual) + '», Â«' + assert._toString(unexpected) + '») to be false';
+
+  throw new Test262Error(message);
+};
+
+assert.throws = function (expectedErrorConstructor, func, message) {
+  var expectedName, actualName;
+  if (typeof func !== "function") {
+    throw new Test262Error('assert.throws requires two arguments: the error constructor ' +
+      'and a function to run');
+    return;
+  }
+  if (message === undefined) {
+    message = '';
+  } else {
+    message += ' ';
+  }
+
+  try {
+    func();
+  } catch (thrown) {
+    if (typeof thrown !== 'object' || thrown === null) {
+      message += 'Thrown value was not an object!';
+      throw new Test262Error(message);
+    } else if (thrown.constructor !== expectedErrorConstructor) {
+      expectedName = expectedErrorConstructor.name;
+      actualName = thrown.constructor.name;
+      if (expectedName === actualName) {
+        message += 'Expected a ' + expectedName + ' but got a different error constructor with the same name';
+      } else {
+        message += 'Expected a ' + expectedName + ' but got a ' + actualName;
+      }
+      throw new Test262Error(message);
+    }
+    return;
+  }
+
+  message += 'Expected a ' + expectedErrorConstructor.name + ' to be thrown but no exception was thrown at all';
+  throw new Test262Error(message);
+};
+
+assert._toString = function (value) {
+  try {
+    if (value === 0 && 1 / value === -Infinity) {
+      return '-0';
+    }
+
+    return String(value);
+  } catch (err) {
+    if (err.name === 'TypeError') {
+      return Object.prototype.toString.call(value);
+    }
+
+    throw err;
+  }
+};
diff --git a/test/harness/compareArray.js b/test/harness/compareArray.js
new file mode 100644 (file)
index 0000000..adf294b
--- /dev/null
@@ -0,0 +1,42 @@
+// Copyright (C) 2017 Ecma International.  All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+/*---
+description: |
+    Compare the contents of two arrays
+defines: [compareArray]
+---*/
+
+function compareArray(a, b) {
+  if (b.length !== a.length) {
+    return false;
+  }
+
+  for (var i = 0; i < a.length; i++) {
+    if (!compareArray.isSameValue(b[i], a[i])) {
+      return false;
+    }
+  }
+  return true;
+}
+
+compareArray.isSameValue = function(a, b) {
+  if (a === 0 && b === 0) return 1 / a === 1 / b;
+  if (a !== a && b !== b) return true;
+
+  return a === b;
+};
+
+compareArray.format = function(array) {
+  return `[${array.map(String).join(', ')}]`;
+};
+
+assert.compareArray = function(actual, expected, message) {
+  message  = message === undefined ? '' : message;
+  assert(actual != null, `First argument shouldn't be nullish. ${message}`);
+  assert(expected != null, `Second argument shouldn't be nullish. ${message}`);
+  var format = compareArray.format;
+  assert(
+    compareArray(actual, expected),
+    `Expected ${format(actual)} and ${format(expected)} to have the same contents. ${message}`
+  );
+};
diff --git a/test/harness/compatBuffer.js b/test/harness/compatBuffer.js
new file mode 100644 (file)
index 0000000..5b82aa3
--- /dev/null
@@ -0,0 +1,3 @@
+function has_buffer() {
+    return (typeof Buffer === 'function') && Buffer.from;
+}
diff --git a/test/harness/compatFs.js b/test/harness/compatFs.js
new file mode 100644 (file)
index 0000000..e4732c9
--- /dev/null
@@ -0,0 +1,11 @@
+let fs = null;
+let fsp = null;
+
+if (typeof require == 'function') {
+    fs = require('fs');
+    fsp = fs.promises;
+}
+
+function has_fs() {
+    return fs;
+}
diff --git a/test/harness/compatPrint.js b/test/harness/compatPrint.js
new file mode 100644 (file)
index 0000000..db33030
--- /dev/null
@@ -0,0 +1,3 @@
+if (typeof print !== 'function') {
+    print = console.log;
+}
diff --git a/test/harness/compatWebcrypto.js b/test/harness/compatWebcrypto.js
new file mode 100644 (file)
index 0000000..be757e1
--- /dev/null
@@ -0,0 +1,8 @@
+if (typeof crypto == 'undefined' && typeof require == 'function') {
+    crypto = require('crypto').webcrypto;
+}
+
+function has_webcrypto() {
+    return (typeof crypto != 'undefied') ? crypto : null;
+}
+
diff --git a/test/harness/doneprintHandle.js b/test/harness/doneprintHandle.js
new file mode 100644 (file)
index 0000000..e968124
--- /dev/null
@@ -0,0 +1,22 @@
+// Copyright (C) 2017 Ecma International.  All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+/*---
+description: |
+defines: [$DONE]
+---*/
+
+function __consolePrintHandle__(msg) {
+  print(msg);
+}
+
+function $DONE(error) {
+  if (error) {
+    if(typeof error === 'object' && error !== null && 'name' in error) {
+      __consolePrintHandle__('Test262:AsyncTestFailure:' + error.name + ': ' + error.message);
+    } else {
+      __consolePrintHandle__('Test262:AsyncTestFailure:Test262Error: ' + error);
+    }
+  } else {
+    __consolePrintHandle__('Test262:AsyncTestComplete');
+  }
+}
diff --git a/test/harness/runTsuite.js b/test/harness/runTsuite.js
new file mode 100644 (file)
index 0000000..51b335a
--- /dev/null
@@ -0,0 +1,54 @@
+async function run(tlist) {
+    function validate(t, r, i) {
+        if (r.status == "fulfilled" && r.value === "SKIPPED") {
+            return true;
+        }
+
+        if (r.status == "fulfilled" && !t[i].exception) {
+            return r.value === "SUCCESS";
+        }
+
+        if (r.status == "rejected" && t[i].exception) {
+            return true;
+        }
+
+        if (r.status == "rejected" && t[i].optional) {
+            return r.reason.toString().startsWith("InternalError: not implemented");
+        }
+
+        return false;
+    }
+
+    for (let k = 0; k < tlist.length; k++) {
+        let ts = tlist[k];
+
+        if (ts.skip && ts.skip()) {
+            continue;
+        }
+
+        let results = await Promise.allSettled(ts.tests.map(t => ts.T(ts.prepare_args(t, ts.opts))));
+        let r = results.map((r, i) => validate(ts.tests, r, i));
+
+        r.forEach((v, i) => {
+            assert.sameValue(v, true, `FAILED ${i}: ${JSON.stringify(ts.tests[i])}\n    with reason: ${results[i].reason}`);
+        })
+    }
+}
+
+function merge(to, from) {
+    let r = Object.assign({}, to);
+    Object.keys(from).forEach(v => {
+        if (typeof r[v] == 'object' && typeof from[v] == 'object') {
+            r[v] = merge(r[v], from[v]);
+
+        } else if (typeof from[v] == 'object') {
+            r[v] = Object.assign({}, from[v]);
+
+        } else {
+            r[v] = from[v];
+        }
+    })
+
+    return r;
+}
+
diff --git a/test/harness/sta.js b/test/harness/sta.js
new file mode 100644 (file)
index 0000000..b249ee4
--- /dev/null
@@ -0,0 +1,27 @@
+// Copyright (c) 2012 Ecma International.  All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+/*---
+description: |
+    Provides both:
+
+    - An error class to avoid false positives when testing for thrown exceptions
+    - A function to explicitly throw an exception using the Test262Error class
+defines: [Test262Error, $DONOTEVALUATE]
+---*/
+
+
+function Test262Error(message) {
+  this.message = message || "";
+}
+
+Test262Error.prototype.toString = function () {
+  return "Test262Error: " + this.message;
+};
+
+Test262Error.thrower = (message) => {
+  throw new Test262Error(message);
+};
+
+function $DONOTEVALUATE() {
+  throw "Test262: This statement should not be evaluated.";
+}
diff --git a/test/harness/webCryptoUtils.js b/test/harness/webCryptoUtils.js
new file mode 100644 (file)
index 0000000..243098e
--- /dev/null
@@ -0,0 +1,13 @@
+function pem_to_der(pem, type) {
+    const pemJoined = pem.toString().split('\n').join('');
+    const pemHeader = `-----BEGIN ${type} KEY-----`;
+    const pemFooter = `-----END ${type} KEY-----`;
+    const pemContents = pemJoined.substring(pemHeader.length, pemJoined.length - pemFooter.length);
+    return Buffer.from(pemContents, 'base64');
+}
+
+function base64decode(b64) {
+    const joined = b64.toString().split('\n').join('');
+    return Buffer.from(joined, 'base64');
+}
+
diff --git a/test/js/async_await_add.js b/test/js/async_await_add.js
deleted file mode 100644 (file)
index 62d46e7..0000000
+++ /dev/null
@@ -1,7 +0,0 @@
-async function af(x) {
-    const y = await new Promise(resolve => {resolve(x + 10)});
-
-    return x + y;
-}
-
-af(50).then(v => console.log(v));
diff --git a/test/js/async_await_add.t.js b/test/js/async_await_add.t.js
new file mode 100644 (file)
index 0000000..5c7eef2
--- /dev/null
@@ -0,0 +1,15 @@
+/*---
+includes: []
+flags: [async]
+---*/
+
+async function af(x) {
+    const y = await new Promise(resolve => {resolve(x + 10)});
+
+    return x + y;
+}
+
+af(50).then(v => {
+    assert.sameValue(v, 110);
+})
+.then($DONE, $DONE);
diff --git a/test/js/async_await_blank.js b/test/js/async_await_blank.js
deleted file mode 100644 (file)
index deaa8cf..0000000
+++ /dev/null
@@ -1,5 +0,0 @@
-async function af(x) {
-    return x;
-}
-
-af(12345).then(v => console.log(v));
diff --git a/test/js/async_await_blank.t.js b/test/js/async_await_blank.t.js
new file mode 100644 (file)
index 0000000..9399f56
--- /dev/null
@@ -0,0 +1,13 @@
+/*---
+includes: []
+flags: [async]
+---*/
+
+async function af(x) {
+    return x;
+}
+
+af(12345).then(v => {
+    assert.sameValue(v, 12345)
+})
+.then($DONE, $DONE);
diff --git a/test/js/async_await_catch.js b/test/js/async_await_catch.js
deleted file mode 100644 (file)
index c47a512..0000000
+++ /dev/null
@@ -1,5 +0,0 @@
-async function add(x) {
-    return await new Promise((resolve, reject) => {reject(x)}).catch(v => v + 1);
-}
-
-add(50).then(v => {console.log(v)});
diff --git a/test/js/async_await_catch.t.js b/test/js/async_await_catch.t.js
new file mode 100644 (file)
index 0000000..db85b16
--- /dev/null
@@ -0,0 +1,13 @@
+/*---
+includes: []
+flags: [async]
+---*/
+
+async function add(x) {
+    return await new Promise((resolve, reject) => {reject(x)}).catch(v => v + 1);
+}
+
+add(50).then(v => {
+    assert.sameValue(v, 51);
+})
+.then($DONE, $DONE);
diff --git a/test/js/async_await_finally.js b/test/js/async_await_finally.js
deleted file mode 100644 (file)
index 5c2ae73..0000000
+++ /dev/null
@@ -1,6 +0,0 @@
-async function add(x) {
-    return await new Promise((resolve, reject) => {reject(x)})
-                                                 .finally(() => console.log(x + 1));
-}
-
-add(50).then(v => {console.log(v)});
diff --git a/test/js/async_await_finally.t.js b/test/js/async_await_finally.t.js
new file mode 100644 (file)
index 0000000..999c66d
--- /dev/null
@@ -0,0 +1,15 @@
+/*---
+includes: []
+flags: [async]
+---*/
+
+let called = false;
+async function add(x) {
+    return await new Promise((resolve, reject) => {reject(x + 1)})
+                     .finally(() => {called = true});
+}
+
+add(50).catch(e => {
+    assert.sameValue(e, 51);
+    assert.sameValue(called, true, "finally was not invoked");
+}).then($DONE, $DONE);
similarity index 57%
rename from test/js/async_await_for.js
rename to test/js/async_await_for.t.js
index 1256a0689a08246c6d8f38cc8f909975a86806f7..24cea5988ecb233f84d5d433030fde4a743f8cfd 100644 (file)
@@ -1,3 +1,8 @@
+/*---
+includes: [compareArray.js]
+flags: [async]
+---*/
+
 let stage = [];
 
 async function f() {
@@ -18,6 +23,9 @@ async function f() {
 
 stage.push(1);
 
-f().then(v => {console.log(v, stage.join(", "))})
+f().then(v => {
+    assert.sameValue(v, 85);
+    assert.compareArray(stage, [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, "end"]);
+}).then($DONE, $DONE);
 
 stage.push(3);
similarity index 52%
rename from test/js/async_await_inline.js
rename to test/js/async_await_inline.t.js
index 2901738ba1553d89915c01aa4207bd322e9f3a2a..a20b77105b6c8414d979091ad34f0f4bf6a9d6c6 100644 (file)
@@ -1,11 +1,18 @@
+/*---
+includes: []
+flags: [async]
+---*/
+
 function pr(x) {
     return new Promise(resolve => {resolve(x)});
 }
 
-async function add(x) {
+async function add() {
     const a = pr(20);
     const b = pr(50);
     return await a + await b;
 }
 
-add(50).then(v => {console.log(v)});
+add().then(v => {
+    assert.sameValue(v, 70);
+}).then($DONE, $DONE);
similarity index 78%
rename from test/js/async_await_many_call.js
rename to test/js/async_await_many_call.t.js
index 52f24ac7e7cf5b068a7b3069d2bb8d0778f4ee16..43cfee556dd43368b0c6b519dd1c0c07cdae957f 100644 (file)
@@ -1,3 +1,8 @@
+/*---
+includes: [compareArray.js]
+flags: [async]
+---*/
+
 async function test(name) {
     let k1, k2;
 
@@ -26,5 +31,5 @@ async function test(name) {
 
 Promise.all(['First', 'Second', 'Third'].map(v => test(v)))
 .then(results => {
-    console.log(results)
-})
+    assert.compareArray(results, ['First: SUN MOON','Second: CAT MOUSE','Third: MAN WOMAN']);
+}).then($DONE, $DONE);
diff --git a/test/js/async_await_reject.js b/test/js/async_await_reject.js
deleted file mode 100644 (file)
index eeaec34..0000000
+++ /dev/null
@@ -1,5 +0,0 @@
-async function add(x) {
-    return await new Promise((resolve, reject) => {reject(x)});
-}
-
-add(50).then(v => {console.log(v)});
diff --git a/test/js/async_await_reject.t.js b/test/js/async_await_reject.t.js
new file mode 100644 (file)
index 0000000..f2faf9f
--- /dev/null
@@ -0,0 +1,15 @@
+/*---
+includes: []
+flags: [async]
+---*/
+
+async function add(x) {
+    return await new Promise((resolve, reject) => {reject(x)});
+}
+
+add(50)
+.then(v => $DONOTEVALUATE())
+.catch(v => {
+    assert.sameValue(v, 50);
+})
+.then($DONE, $DONE);
similarity index 66%
rename from test/js/async_await_stages.js
rename to test/js/async_await_stages.t.js
index e3ff18e483d85638c5305e4afda3740f1dd1b89f..164c1e454f628e6df488ec8259f72d05f529563b 100644 (file)
@@ -1,3 +1,8 @@
+/*---
+includes: [compareArray.js]
+flags: [async]
+---*/
+
 function pr(x) {
     return new Promise(resolve => {resolve(x)})
     .then(v => v).then(v => v);
@@ -23,6 +28,9 @@ async function f() {
 
 stage.push(1);
 
-f().then(v => {console.log(v, stage.join(", "))})
+f().then(v => {
+    stage.push(v);
+    assert.compareArray(stage, [1, 2, 3, 4, 5, 30]);
+}).then($DONE, $DONE);
 
 stage.push(3);
similarity index 56%
rename from test/js/async_await_throw.js
rename to test/js/async_await_throw.t.js
index 8923e5d4a7ef9dae27995f03c1d79b15cb216c5c..b872080c7c5c89bd2594949203460fb6521ce105 100644 (file)
@@ -1,3 +1,8 @@
+/*---
+includes: []
+flags: [async]
+---*/
+
 function pr(x) {
     return new Promise(resolve => {resolve(x)}).then(v => {throw v});
 }
@@ -9,4 +14,9 @@ async function add(x) {
     return a + b;
 }
 
-add(50).then(v => {console.log(v)});
+add(50)
+.then(v => $DONOTEVALUATE())
+.catch(v => {
+    assert.sameValue(v, 50);
+})
+.then($DONE, $DONE);
similarity index 57%
rename from test/js/async_await_throw_catch_async.js
rename to test/js/async_await_throw_async.t.js
index e7c510319fce0dbad5d6e3cb1613c8b3e70bcb8f..e59d68f6f13680bbb5a882b6e4af20a206295105 100644 (file)
@@ -1,3 +1,8 @@
+/*---
+includes: []
+flags: [async]
+---*/
+
 function pr(x) {
     return new Promise(resolve => {resolve(x)});
 }
@@ -12,4 +17,9 @@ async function add(x) {
     return a + b;
 }
 
-add(50).then(v => {console.log(v - 1)}).catch(v => console.log(v));
+add(50)
+.then(v => $DONOTEVALUATE())
+.catch(v => {
+    assert.sameValue(v, 51);
+})
+.then($DONE, $DONE);
similarity index 64%
rename from test/js/async_await_throw_catch.js
rename to test/js/async_await_throw_catch.t.js
index 5e9025f3a5a678aa5cf2df61a285cb51c246b7b1..cafcab4c99e89a3abffdd41d16e36b8d612c7052 100644 (file)
@@ -1,3 +1,8 @@
+/*---
+includes: []
+flags: [async]
+---*/
+
 function pr(x) {
     return new Promise(resolve => {resolve(x)}).then(v => {throw v}).catch(v => v);
 }
@@ -9,4 +14,7 @@ async function add(x) {
     return a + b;
 }
 
-add(50).then(v => {console.log(v)});
+add(50).then(v => {
+    assert.sameValue(v, 110);
+})
+.then($DONE, $DONE);
similarity index 57%
rename from test/js/async_await_throw_async.js
rename to test/js/async_await_throw_catch_async.t.js
index b5b6bb2767ea5272d6137542f0654323e02d6e63..e59d68f6f13680bbb5a882b6e4af20a206295105 100644 (file)
@@ -1,3 +1,8 @@
+/*---
+includes: []
+flags: [async]
+---*/
+
 function pr(x) {
     return new Promise(resolve => {resolve(x)});
 }
@@ -12,4 +17,9 @@ async function add(x) {
     return a + b;
 }
 
-add(50).then(v => {console.log(v)});
+add(50)
+.then(v => $DONOTEVALUATE())
+.catch(v => {
+    assert.sameValue(v, 51);
+})
+.then($DONE, $DONE);
diff --git a/test/js/async_await_try_catch.js b/test/js/async_await_try_catch.js
deleted file mode 100644 (file)
index 5c11ec5..0000000
+++ /dev/null
@@ -1,19 +0,0 @@
-async function af() {
-    try {
-        await new Promise(function(resolve, reject) {
-            reject("reject");
-        });
-
-        console.log("shouldn't happen");
-    }
-    catch (v) {
-        console.log(v);
-    }
-    finally {
-        console.log("finally");
-    }
-
-    return "end";
-};
-
-af().then(v => console.log(v));
diff --git a/test/js/async_await_try_catch.t.js b/test/js/async_await_try_catch.t.js
new file mode 100644 (file)
index 0000000..abb5786
--- /dev/null
@@ -0,0 +1,30 @@
+/*---
+includes: [compareArray.js]
+flags: [async]
+---*/
+
+let stages = [];
+
+async function af() {
+    try {
+        await new Promise(function(resolve, reject) {
+            reject("reject");
+        });
+
+        $DONOTEVALUATE();
+    }
+    catch (v) {
+        stages.push(v);
+    }
+    finally {
+        stages.push('finally');
+    }
+
+    return "end";
+};
+
+af().then(v => {
+    stages.push(v);
+    assert.compareArray(stages, ['reject', 'finally', 'end']);
+})
+.then($DONE, $DONE)
similarity index 57%
rename from test/js/async_await_try_finally.js
rename to test/js/async_await_try_finally.t.js
index 9feb1b5f5a1231417ffebd683122a0d4c0adc57e..c78697143859ba15d6500409c39bb73d8194d03b 100644 (file)
@@ -1,20 +1,32 @@
+/*---
+includes: []
+flags: [async]
+---*/
+
+let stages = [];
+
 async function af() {
     try {
         await new Promise(function(resolve, reject) {
             reject("reject");
         });
 
-        console.log("shouldn't happen: try");
+        $DONOTEVALUATE();
     }
     finally {
         await new Promise(function(resolve, reject) {
             reject("finally reject");
         });
 
-        console.log("shouldn't happen: finally");
+        $DONOTEVALUATE();
     }
 
     return "shouldn't happen: end";
 };
 
-af().then(v => console.log(v));
+af()
+.then(v => $DONOTEVALUATE())
+.catch(v => {
+    assert.sameValue(v, "finally reject");
+})
+.then($DONE, $DONE);
similarity index 61%
rename from test/js/async_await_try_resolve.js
rename to test/js/async_await_try_resolve.t.js
index b041de154615743197357e706bded9e9d04b17c4..02ef98999a070935e59f4d177058f6f626417eb7 100644 (file)
@@ -1,3 +1,8 @@
+/*---
+includes: []
+flags: [async]
+---*/
+
 async function af() {
     let key;
 
@@ -12,4 +17,7 @@ async function af() {
     return key;
 };
 
-af().then(v => console.log(v));
+af().then(v => {
+    assert.sameValue(v, "key: resolve");
+})
+.then($DONE, $DONE);
diff --git a/test/js/async_await_try_throw.js b/test/js/async_await_try_throw.js
deleted file mode 100644 (file)
index d5f51e5..0000000
+++ /dev/null
@@ -1,14 +0,0 @@
-async function af() {
-    try {
-        throw "try";
-
-        console.log("shouldn't happen: try");
-    }
-    finally {
-        console.log("finally");
-    }
-
-    return "shouldn't happen: end";
-};
-
-af().then(v => console.log(v));
diff --git a/test/js/async_await_try_throw.t.js b/test/js/async_await_try_throw.t.js
new file mode 100644 (file)
index 0000000..1374214
--- /dev/null
@@ -0,0 +1,27 @@
+/*---
+includes: [compareArray.js]
+flags: [async]
+---*/
+
+let stages = [];
+
+async function af() {
+    try {
+        throw "try";
+
+        $DONOTEVALUATE();
+    }
+    finally {
+        stages.push("finally");
+    }
+
+    return "shouldn't happen: end";
+};
+
+af()
+.then(v => $DONOTEVALUATE())
+.catch(v => {
+    stages.push(v);
+    assert.compareArray(stages, ['finally', 'try']);
+})
+.then($DONE, $DONE)
diff --git a/test/js/async_await_try_throw_catch.js b/test/js/async_await_try_throw_catch.js
deleted file mode 100644 (file)
index d4bd5b3..0000000
+++ /dev/null
@@ -1,17 +0,0 @@
-async function af() {
-    try {
-        throw "try";
-
-        console.log("shouldn't happen: try");
-    }
-    catch (v) {
-        console.log(v);
-    }
-    finally {
-        console.log("finally");
-    }
-
-    return "end";
-};
-
-af().then(v => console.log(v));
diff --git a/test/js/async_await_try_throw_catch.t.js b/test/js/async_await_try_throw_catch.t.js
new file mode 100644 (file)
index 0000000..0417c43
--- /dev/null
@@ -0,0 +1,27 @@
+/*---
+includes: [compareArray.js]
+flags: [async]
+---*/
+
+let stage = [];
+
+async function af() {
+    try {
+        throw "try";
+
+        $DONOTEVALUATE();
+    }
+    catch (v) {
+        stage.push(v);
+    }
+    finally {
+        stage.push("finally");
+    }
+
+    return "end";
+};
+
+af().then(v => {
+    stage.push(v);
+    assert.compareArray(stage, ['try', 'finally', 'end'])
+}).then($DONE, $DONE);
diff --git a/test/js/fs_promises_001.js b/test/js/fs_promises_001.js
deleted file mode 100644 (file)
index 22a1efc..0000000
+++ /dev/null
@@ -1,55 +0,0 @@
-var fs = require('fs').promises;
-var fname = './build/test/fs_promises_001';
-
-Promise.resolve()
-.then(() => {
-    return fs.writeFile(fname, fname);
-})
-.then((data) => {
-    console.log('init ok', data === undefined);
-})
-.catch((e) => {
-    console.log('init failed', e);
-})
-.then(() => {
-    return fs.readFile(fname).then(fs.readFile);
-})
-.then((data) => {
-    console.log('short circut ok', data == fname);
-})
-.catch((e) => {
-    console.log('short circut failed', e);
-})
-.then(() => {
-    var read = fs.readFile.bind(fs, fname, 'utf8');
-    var write = fs.writeFile.bind(fs, fname);
-    var append = fs.appendFile.bind(fs, fname);
-
-    return write(fname).then(read).then(append).then(read);
-})
-.then((data) => {
-    console.log('chain ok', data == (fname + fname));
-})
-.catch((e) => {
-    console.log('chain failed', e);
-})
-.then(() => {
-    // nodejs incompatible
-    try {
-        return fs.readFile();
-    } catch (e) {
-        console.log('error 1 ok', e instanceof TypeError)
-    }
-    try {
-        return fs.writeFile();
-    } catch (e) {
-        console.log('error 2 ok', e instanceof TypeError)
-    }
-})
-.then((data) => {
-    console.log('errors ok');
-})
-.catch((e) => {
-    console.log('errors failed - reject on bad args');
-})
-;
diff --git a/test/js/promise_all.js b/test/js/promise_all.js
deleted file mode 100644 (file)
index afe885f..0000000
+++ /dev/null
@@ -1,9 +0,0 @@
-function resolve(value) {
-    return new Promise(resolve => setTimeout(() => resolve(value), 0));
-}
-
-Promise.all([resolve(['one', 'two']), resolve(['three', 'four'])])
-.then(
-    (v) => {console.log(`resolved:${njs.dump(v)}`)},
-    (v) => {console.log(`rejected:${njs.dump(v)}`)}
-);
diff --git a/test/js/promise_all.t.js b/test/js/promise_all.t.js
new file mode 100644 (file)
index 0000000..7f8b25d
--- /dev/null
@@ -0,0 +1,16 @@
+/*---
+includes: [compareArray.js]
+flags: [async]
+---*/
+
+function resolve(value) {
+    return new Promise(resolve => setTimeout(() => resolve(value), 0));
+}
+
+Promise.all([resolve(['one', 'two']), resolve(['three', 'four'])])
+.then(
+    v => { assert.compareArray(v[0], ['one', 'two']);
+           assert.compareArray(v[1], ['three', 'four']); },
+    v => $DONOTEVALUATE(),
+)
+.then($DONE, $DONE);
similarity index 81%
rename from test/js/promise_allSettled.js
rename to test/js/promise_allSettled.t.js
index bf9971216f25780ffb0deaaf01f1a279cd298d7f..a4e4980725cdf631c7d3b2c61b0d56aed449cd56 100644 (file)
@@ -1,3 +1,8 @@
+/*---
+includes: []
+flags: [async]
+---*/
+
 var p0 = Promise.resolve(2).then(v => v + 1);
 var p1 = Promise.reject(21).catch(v => v * 2);
 var p2 = Promise.resolve('nope').then(() => { throw 'foo' });
@@ -15,6 +20,7 @@ function dump(v) {
 }
 
 Promise.allSettled([p0, p1, p2, p3, p4, p5, p6, p7, p8]).then(
-    (v) => {console.log(`resolved:${dump(v)}`)},
-    (v) => {console.log(`rejected:${dump(v)}`)}
-);
+    v => assert.sameValue(dump(v), "F:0,3,42,here|R:finally,finally after rejected,foo,here too,yes"),
+    v => $DONOTEVALUATE(),
+)
+.then($DONE, $DONE);
similarity index 64%
rename from test/js/promise_allSettled_string.js
rename to test/js/promise_allSettled_string.t.js
index fc47a7db3e897baf56820d80c24f9636bcd62e51..e99792d73954ea7f151a34c3556053474f5332ec 100644 (file)
@@ -1,3 +1,8 @@
+/*---
+includes: []
+flags: [async]
+---*/
+
 function dump(v) {
     var fulfilled = v.filter(v=>v.status == 'fulfilled').map(v=>v.value).sort();
     var rejected = v.filter(v=>v.status == 'rejected').map(v=>v.reason).sort();
@@ -5,6 +10,7 @@ function dump(v) {
 }
 
 Promise.allSettled("abc").then(
-    (v) => {console.log(`resolved:${dump(v)}`)},
-    (v) => {console.log(`rejected:${dump(v)}`)}
-);
+    v => assert.sameValue(dump(v), "F:a,b,c|R:"),
+    v => $DONOTEVALUATE(),
+)
+.then($DONE, $DONE);
similarity index 65%
rename from test/js/promise_all_throw.js
rename to test/js/promise_all_throw.t.js
index 1994b37e1cd73e3a401584a83ac2416192028d0c..008952a122e48af7febee3003ac94ea06ab75725 100644 (file)
@@ -1,9 +1,15 @@
+/*---
+includes: []
+flags: [async]
+---*/
+
 var p0 = Promise.resolve(1).then(v => v + 1);
 var p1 = Promise.reject(2).catch(v => v * 2);
 var p2 = Promise.resolve().then(() => { throw 'foo' });
 var p3 = Promise.reject().then(() => { throw 'oof'; });
 
 Promise.all([p0, p1, p2, p3]).then(
-    (v) => {console.log(`resolved:${v}`)},
-    (v) => {console.log(`rejected:${v}`)}
-);
+    v => $DONOTEVALUATE(),
+    v => assert.sameValue(v, 'foo')
+)
+.then($DONE, $DONE);
similarity index 59%
rename from test/js/promise_any.js
rename to test/js/promise_any.t.js
index 3ea4b545da98a0c009217107afccc9bb0e25f2c0..fb287ba9ce4ed0df5f82f8adca0cf931a99307e4 100644 (file)
@@ -1,8 +1,14 @@
+/*---
+includes: []
+flags: [async]
+---*/
+
 var p0 = Promise.resolve().then(() => { throw 'foo' });
 var p1 = Promise.reject(2).catch(v => v * 2);
 var p2 = Promise.resolve(1).then(v => v + 1);
 
 Promise.any([p0, p1, p2]).then(
-    (v) => {console.log(`resolved:${v}`)},
-    (v) => {console.log(`rejected:${v}`)}
-);
+    v => assert.sameValue(v, 4),
+    v => $DONOTEVALUATE(),
+)
+.then($DONE, $DONE);
diff --git a/test/js/promise_any_all_rejected.js b/test/js/promise_any_all_rejected.js
deleted file mode 100644 (file)
index f008fe3..0000000
+++ /dev/null
@@ -1,7 +0,0 @@
-var p0 = Promise.reject(1);
-var p1 = Promise.reject(2);
-
-Promise.any([p0, p1]).then(
-    (v) => {console.log(`resolve:${v}`)},
-    (v) => {console.log(`reject:${v}`)}
-);
diff --git a/test/js/promise_any_all_rejected.t.js b/test/js/promise_any_all_rejected.t.js
new file mode 100644 (file)
index 0000000..c6a7254
--- /dev/null
@@ -0,0 +1,13 @@
+/*---
+includes: []
+flags: [async]
+---*/
+
+var p0 = Promise.reject(1);
+var p1 = Promise.reject(2);
+
+Promise.any([p0, p1]).then(
+    v => $DONOTEVALUATE(),
+    v => assert.sameValue(v.constructor, AggregateError),
+)
+.then($DONE, $DONE);
diff --git a/test/js/promise_catch_then_throw_catch.js b/test/js/promise_catch_then_throw_catch.js
deleted file mode 100644 (file)
index b4f99e8..0000000
+++ /dev/null
@@ -1,5 +0,0 @@
-Promise.resolve()
-.then(() => {})
-.catch(() => {})
-.then(() => {nonExsisting()})
-.catch(() => {console.log("Done")});
\ No newline at end of file
diff --git a/test/js/promise_catch_then_throw_catch.t.js b/test/js/promise_catch_then_throw_catch.t.js
new file mode 100644 (file)
index 0000000..bbe6b59
--- /dev/null
@@ -0,0 +1,14 @@
+/*---
+includes: []
+flags: [async]
+---*/
+
+let called = false;
+
+Promise.resolve()
+.then(() => {})
+.catch(() => {})
+.then(() => {nonExsisting()})
+.catch(() => { called = true; })
+.then(() => assert.sameValue(called, true))
+.then($DONE, $DONE);
diff --git a/test/js/promise_catch_throw.js b/test/js/promise_catch_throw.js
deleted file mode 100644 (file)
index 9c246eb..0000000
+++ /dev/null
@@ -1,3 +0,0 @@
-Promise.resolve()
-.then(() => {nonExsisting()})
-.catch(() => {nonExsistingInCatch()});
\ No newline at end of file
diff --git a/test/js/promise_catch_throw.t.js b/test/js/promise_catch_throw.t.js
new file mode 100644 (file)
index 0000000..9bf99da
--- /dev/null
@@ -0,0 +1,10 @@
+/*---
+includes: []
+flags: [async]
+---*/
+
+Promise.resolve()
+.then(() => {nonExsisting()})
+.catch(() => {nonExsistingInCatch()})
+.catch(v => assert.sameValue(v.constructor, ReferenceError))
+.then($DONE, $DONE);
diff --git a/test/js/promise_finally.js b/test/js/promise_finally.js
deleted file mode 100644 (file)
index b628688..0000000
+++ /dev/null
@@ -1,7 +0,0 @@
-Promise.resolve('here')
-.finally(() => {'nope'})
-.then(v => {console.log(v)});
-
-Promise.resolve('here')
-.finally(() => {throw 'nope'})
-.then(v => {console.log(v)});
diff --git a/test/js/promise_finally.t.js b/test/js/promise_finally.t.js
new file mode 100644 (file)
index 0000000..bd12bdf
--- /dev/null
@@ -0,0 +1,14 @@
+/*---
+includes: []
+flags: [async]
+---*/
+
+Promise.resolve('here')
+.finally(() => {'nope'})
+.then(v => assert.sameValue(v, 'here'));
+
+Promise.resolve('here')
+.finally(() => {throw 'nope'})
+.then(v => $DONOTEVALUATE())
+.catch(v => assert.sameValue(v, 'nope'))
+.then($DONE, $DONE);
diff --git a/test/js/promise_finally_throw.js b/test/js/promise_finally_throw.js
deleted file mode 100644 (file)
index 7ae947e..0000000
+++ /dev/null
@@ -1,2 +0,0 @@
-Promise.resolve()
-.finally(() => {nonExsistingInFinally()});
\ No newline at end of file
diff --git a/test/js/promise_finally_throw.t.js b/test/js/promise_finally_throw.t.js
new file mode 100644 (file)
index 0000000..74fe0d9
--- /dev/null
@@ -0,0 +1,9 @@
+/*---
+includes: []
+flags: []
+negative:
+  phase: runtime
+---*/
+
+Promise.resolve()
+.finally(() => {nonExsistingInFinally()});
diff --git a/test/js/promise_finally_throw_catch.js b/test/js/promise_finally_throw_catch.js
deleted file mode 100644 (file)
index 03301be..0000000
+++ /dev/null
@@ -1,3 +0,0 @@
-Promise.resolve()
-.finally(() => {nonExsistingInFinally()})
-.catch(() => {console.log("Done")});
\ No newline at end of file
diff --git a/test/js/promise_finally_throw_catch.t.js b/test/js/promise_finally_throw_catch.t.js
new file mode 100644 (file)
index 0000000..2d5ae3d
--- /dev/null
@@ -0,0 +1,9 @@
+/*---
+includes: []
+flags: [async]
+---*/
+
+Promise.resolve()
+.finally(() => {nonExsistingInFinally()})
+.catch(e => {})
+.then($DONE, $DONE);
similarity index 60%
rename from test/js/promise_race.js
rename to test/js/promise_race.t.js
index 81a6d57278663bdb7451accaf38ffdc220ab3637..eb34dd7fc02eecf745daa02f6446c1ddea022e0f 100644 (file)
@@ -1,3 +1,8 @@
+/*---
+includes: []
+flags: [async]
+---*/
+
 var p1 = new Promise((resolve, reject) => {
     setTimeout(resolve, 0, 'one');
 });
@@ -7,6 +12,7 @@ var p2 = new Promise((resolve, reject) => {
 });
 
 Promise.race([p1, p2]).then(
-    (v) => {console.log(`resolved:${v}`)},
-    (v) => {console.log(`rejected:${v}`)}
-);
+    v => assert.sameValue(v, 'one'),
+    v => $DONOTEVALUATE(),
+)
+.then($DONE, $DONE);
similarity index 58%
rename from test/js/promise_race_throw.js
rename to test/js/promise_race_throw.t.js
index 0fc9145b636defdd2695505e3b5f56b8c9f7ba81..f53cb6d5e4a57b614e2115fca810c789b1c750c2 100644 (file)
@@ -1,3 +1,8 @@
+/*---
+includes: []
+flags: [async]
+---*/
+
 var p1 = new Promise((resolve, reject) => {
     throw 'one';
 });
@@ -7,6 +12,7 @@ var p2 = new Promise((resolve, reject) => {
 });
 
 Promise.race([p1, p2]).then(
-    (v) => {console.log(`resolved:${v}`)},
-    (v) => {console.log(`rejected:${v}`)}
-);
+    v => $DONOTEVALUATE(),
+    v => assert.sameValue(v, 'one'),
+)
+.then($DONE, $DONE);
diff --git a/test/js/promise_reject_catch.js b/test/js/promise_reject_catch.js
deleted file mode 100644 (file)
index 81dff1f..0000000
+++ /dev/null
@@ -1 +0,0 @@
-Promise.reject("test").catch((x) => console.log('rejected', x));
\ No newline at end of file
diff --git a/test/js/promise_reject_catch.t.js b/test/js/promise_reject_catch.t.js
new file mode 100644 (file)
index 0000000..727bf77
--- /dev/null
@@ -0,0 +1,8 @@
+/*---
+includes: []
+flags: [async]
+---*/
+
+Promise.reject("test")
+.catch(v => assert.sameValue(v, "test"))
+.then($DONE, $DONE);
diff --git a/test/js/promise_reject_post_catch.js b/test/js/promise_reject_post_catch.js
deleted file mode 100644 (file)
index b2e617b..0000000
+++ /dev/null
@@ -1,2 +0,0 @@
-var p = Promise.reject();
-setImmediate(() => {p.catch(() => {})});
\ No newline at end of file
diff --git a/test/js/promise_reject_post_catch.t.js b/test/js/promise_reject_post_catch.t.js
new file mode 100644 (file)
index 0000000..0061cbc
--- /dev/null
@@ -0,0 +1,9 @@
+/*---
+includes: []
+flags: []
+negative:
+  phase: runtime
+---*/
+
+var p = Promise.reject();
+setImmediate(() => {p.catch(() => {})});
diff --git a/test/js/promise_rejection_tracker.js b/test/js/promise_rejection_tracker.js
deleted file mode 100644 (file)
index db06e22..0000000
+++ /dev/null
@@ -1 +0,0 @@
-Promise.reject(1);
\ No newline at end of file
diff --git a/test/js/promise_rejection_tracker.t.js b/test/js/promise_rejection_tracker.t.js
new file mode 100644 (file)
index 0000000..865b744
--- /dev/null
@@ -0,0 +1,9 @@
+/*---
+includes: []
+flags: []
+negative:
+  phase: runtime
+---*/
+
+Promise.reject(1);
+
diff --git a/test/js/promise_s01.t.js b/test/js/promise_s01.t.js
new file mode 100644 (file)
index 0000000..acd98d0
--- /dev/null
@@ -0,0 +1,22 @@
+/*---
+includes: [compareArray.js]
+flags: [async]
+---*/
+
+let stages = [];
+
+var promise = new Promise(function(resolve, reject) {
+    stages.push('One');
+
+    reject(123);
+}).catch((v) => {stages.push(v)});
+
+stages.push('Two');
+
+promise.then(() => {stages.push('Four'); return {num: 'Five'}})
+.then(obj => {stages.push(obj.num);  return {num: 'Six'}})
+.then(obj => {stages.push(obj.num)})
+.then(() => assert.compareArray(stages, ["One", "Two", "Three", 123, "Four", "Five", "Six"]))
+.then($DONE, $DONE);
+
+stages.push('Three');
diff --git a/test/js/promise_s02.t.js b/test/js/promise_s02.t.js
new file mode 100644 (file)
index 0000000..3e89abf
--- /dev/null
@@ -0,0 +1,23 @@
+/*---
+includes: [compareArray.js]
+flags: [async]
+---*/
+
+let stages = [];
+
+var promise = new Promise(function(resolve, reject) {
+    stages.push('One');
+
+    reject(123);
+})
+
+stages.push('Two');
+
+promise.then(() => {stages.push('Four'); return {num: 'Five'}})
+.then(obj => {stages.push(obj.num);  return {num: 'Six'}})
+.then(obj => {stages.push(obj.num)})
+.catch(v => assert.sameValue(v, 123))
+.then(() => assert.compareArray(stages, ["One", "Two", "Three"]))
+.then($DONE, $DONE);
+
+stages.push('Three');
diff --git a/test/js/promise_s03.t.js b/test/js/promise_s03.t.js
new file mode 100644 (file)
index 0000000..9492dd6
--- /dev/null
@@ -0,0 +1,21 @@
+/*---
+includes: [compareArray.js]
+flags: [async]
+---*/
+
+let stages = [];
+
+var promise = new Promise(function(resolve, reject) {
+    stages.push('One');
+    reject(42);
+});
+
+stages.push('Two');
+
+promise.then(
+    v => $DONOTEVALUATE(),
+    v => assert.sameValue(v, 42))
+.then(() => assert.compareArray(stages, ['One', 'Two', 'Three']))
+.then($DONE, $DONE);
+
+stages.push('Three');
diff --git a/test/js/promise_s04.t.js b/test/js/promise_s04.t.js
new file mode 100644 (file)
index 0000000..0230356
--- /dev/null
@@ -0,0 +1,12 @@
+/*---
+includes: []
+flags: []
+negative:
+  phase: runtime
+---*/
+
+Promise.reject(new Error('Oh my'))
+.then(
+    function(success) {},
+    function(error) { throw error;}
+);
diff --git a/test/js/promise_s05.t.js b/test/js/promise_s05.t.js
new file mode 100644 (file)
index 0000000..2cb4981
--- /dev/null
@@ -0,0 +1,18 @@
+/*---
+includes: []
+flags: [async]
+---*/
+
+let called = false;
+
+Promise.resolve('Success')
+.then(
+    function(value) {
+        assert.sameValue(value, 'Success');
+        called = true;
+    },
+    function(value) {
+        $DONOTEVALUATE()
+})
+.then(() => assert.sameValue(called, true))
+.then($DONE, $DONE);
diff --git a/test/js/promise_s06.t.js b/test/js/promise_s06.t.js
new file mode 100644 (file)
index 0000000..4562714
--- /dev/null
@@ -0,0 +1,10 @@
+/*---
+includes: []
+flags: [async]
+---*/
+
+var p = Promise.resolve([1,2,3]);
+p.then(function(v) {
+    assert.sameValue(v[0], 1);
+})
+.then($DONE, $DONE);
diff --git a/test/js/promise_s07.t.js b/test/js/promise_s07.t.js
new file mode 100644 (file)
index 0000000..35b3ee6
--- /dev/null
@@ -0,0 +1,15 @@
+/*---
+includes: []
+flags: [async]
+---*/
+
+var p1 = Promise.resolve({
+    then: function(onFulfill, onReject) { onFulfill('fulfilled!'); }
+});
+
+p1.then(
+    function(v) { assert.sameValue(v, 'fulfilled!'); },
+    function(e) { $DONOTEVALUATE() },
+)
+.then(() => assert.sameValue(p1 instanceof Promise, true))
+.then($DONE, $DONE);
diff --git a/test/js/promise_s08.t.js b/test/js/promise_s08.t.js
new file mode 100644 (file)
index 0000000..83f3730
--- /dev/null
@@ -0,0 +1,22 @@
+/*---
+includes: []
+flags: [async]
+---*/
+
+let called = false;
+
+var thenable = {
+    then: function(resolve) {
+        called = true;
+        resolve();
+    }
+};
+
+function executor(resolve, reject) {
+    resolve(thenable);
+    throw new Error('ignored');
+}
+
+new Promise(executor)
+.then(() => assert.sameValue(called, true))
+.then($DONE, $DONE);
diff --git a/test/js/promise_s09.t.js b/test/js/promise_s09.t.js
new file mode 100644 (file)
index 0000000..ff41002
--- /dev/null
@@ -0,0 +1,15 @@
+/*---
+includes: [compareArray.js]
+flags: []
+---*/
+
+let calls = [];
+
+function NotPromise(executor) {
+  assert.sameValue(Object.isExtensible(executor), true);
+  executor(function() {calls.push('S')}, function() {calls.push('R')});
+}
+
+Promise.resolve.call(NotPromise);
+
+assert.compareArray(calls, ['S']);
diff --git a/test/js/promise_s1.js b/test/js/promise_s1.js
deleted file mode 100644 (file)
index 308dbe2..0000000
+++ /dev/null
@@ -1,15 +0,0 @@
-var promise = new Promise(function(resolve, reject) {
-    console.log('One');
-
-    reject(123);
-}).catch((v) => {console.log(v)});
-
-console.log('Two');
-
-promise.then(() => {console.log('Four'); return {num: 'Five'}})
-.then((obj) => {console.log(obj.num);  return {num: 'Six'}})
-.then((obj) => {console.log(obj.num);  return {num: 'Seven'}})
-.then((obj) => {console.log(obj.num);  return {num: 'Eight'}})
-.then((obj) => {console.log(obj.num)});
-
-console.log('Three');
\ No newline at end of file
diff --git a/test/js/promise_s10.js b/test/js/promise_s10.js
deleted file mode 100644 (file)
index 6fd1d6b..0000000
+++ /dev/null
@@ -1,11 +0,0 @@
-var promise = new Promise(function(resolve, reject) {
-    console.log('One');
-    reject('Oh no');
-});
-
-console.log('Two');
-
-promise.then(() => {console.log('Three')})
-.catch((v) => {console.log(v)});
-
-console.log('Three');
\ No newline at end of file
diff --git a/test/js/promise_s10.t.js b/test/js/promise_s10.t.js
new file mode 100644 (file)
index 0000000..a3e155f
--- /dev/null
@@ -0,0 +1,20 @@
+/*---
+includes: [compareArray.js]
+flags: [async]
+---*/
+
+let stages = [];
+
+var promise = new Promise(function(resolve, reject) {
+    stages.push('One');
+    reject('Oh no');
+});
+
+stages.push('Two');
+
+promise.then(() => {stages.push('Three')})
+.catch((v) => {stages.push(v)})
+.then(() => assert.compareArray(stages, ['One', 'Two', 'Three', 'Oh no']))
+.then($DONE, $DONE);
+
+stages.push('Three');
diff --git a/test/js/promise_s11.js b/test/js/promise_s11.js
deleted file mode 100644 (file)
index ecffccc..0000000
+++ /dev/null
@@ -1,13 +0,0 @@
-var promise = new Promise((resolve, reject) => resolve('all'));
-
-promise.then( function f1(result) {
-    console.log('S: ' + result);
-    return 'f1';
-});
-
-promise.then( function f2(result) {
-    console.log('R: ' + result);
-    return 'f2';
-});
-
-console.log('end')
\ No newline at end of file
diff --git a/test/js/promise_s11.t.js b/test/js/promise_s11.t.js
new file mode 100644 (file)
index 0000000..d37bfb6
--- /dev/null
@@ -0,0 +1,22 @@
+/*---
+includes: [compareArray.js]
+flags: [async]
+---*/
+
+let stages = [];
+
+var promise = new Promise((resolve, reject) => resolve('all'));
+
+promise.then( function f1(result) {
+    stages.push('S: ' + result);
+    return 'f1';
+});
+
+promise.then( function f2(result) {
+    stages.push('R: ' + result);
+    return 'f2';
+})
+.then(() => assert.compareArray(stages, ['end', 'S: all', 'R: all']))
+.then($DONE, $DONE);
+
+stages.push('end');
diff --git a/test/js/promise_s12.js b/test/js/promise_s12.js
deleted file mode 100644 (file)
index e157b47..0000000
+++ /dev/null
@@ -1,10 +0,0 @@
-var thenable = new Promise(function() {});
-
-var p = new Promise(function(resolve) {
-    resolve();
-    throw thenable;
-});
-
-p.then(function() {
-    console.log('Done');
-});
\ No newline at end of file
diff --git a/test/js/promise_s12.t.js b/test/js/promise_s12.t.js
new file mode 100644 (file)
index 0000000..dec5ca7
--- /dev/null
@@ -0,0 +1,19 @@
+/*---
+includes: []
+flags: [async]
+---*/
+
+let called = false;
+
+var thenable = new Promise(function() {});
+
+var p = new Promise(function(resolve) {
+    resolve();
+    throw thenable;
+});
+
+p.then(function() {
+    called = true;
+})
+.then(() => assert.sameValue(called, true))
+.then($DONE, $DONE);
diff --git a/test/js/promise_s13.js b/test/js/promise_s13.js
deleted file mode 100644 (file)
index 4ace323..0000000
+++ /dev/null
@@ -1,21 +0,0 @@
-var thenable = Promise.resolve();
-var p = new Promise(function(a,b) {
-    throw thenable;
-});
-
-p.then(function() {
-    console.log('The promise should not be fulfilled.');
-})
-.then(
-    function() {
-        console.log('The promise should not be fulfilled.');
-    },
-    function(x) {
-        if (x !== thenable) {
-            console.log('The promise should be rejected with the resolution value.');
-            return;
-        }
-
-        console.log('Done');
-    }
-);
\ No newline at end of file
diff --git a/test/js/promise_s13.t.js b/test/js/promise_s13.t.js
new file mode 100644 (file)
index 0000000..fe4bb01
--- /dev/null
@@ -0,0 +1,23 @@
+/*---
+includes: []
+flags: [async]
+---*/
+
+let called = false;
+
+var thenable = Promise.resolve();
+var p = new Promise(function(a,b) {
+    throw thenable;
+});
+
+p
+.then(v => $DONOTEVALUATE())
+.then(
+    v => $DONOTEVALUATE(),
+    function(x) {
+        assert.sameValue(x, thenable, 'The promise should be rejected with the resolution value.');
+        called = true;
+    }
+)
+.then(() => assert.sameValue(called, true))
+.then($DONE, $DONE);
diff --git a/test/js/promise_s14.js b/test/js/promise_s14.js
deleted file mode 100644 (file)
index 63494ee..0000000
+++ /dev/null
@@ -1,9 +0,0 @@
-var isLoading = true;
-var promise = new Promise((a, b) => {a()} );
-
-promise.then(function(response) {
-    throw new TypeError('oops');
-})
-.then(function(json) { })
-.catch(function(error) { console.log(error); })
-.finally(function() { console.log('Done') });
\ No newline at end of file
diff --git a/test/js/promise_s14.t.js b/test/js/promise_s14.t.js
new file mode 100644 (file)
index 0000000..a6e81d4
--- /dev/null
@@ -0,0 +1,21 @@
+/*---
+includes: []
+flags: [async]
+---*/
+
+let stages = [];
+
+var isLoading = true;
+var promise = new Promise((a, b) => {a()} );
+
+promise.then(function(response) {
+    throw new TypeError('oops');
+})
+.then(function(json) { })
+.catch(e => stages.push(e))
+.finally(() => stages.push('Done'))
+.then(() => {
+    assert.sameValue(stages[0] instanceof TypeError, true);
+    assert.sameValue(stages[1], 'Done');
+})
+.then($DONE, $DONE);
diff --git a/test/js/promise_s15.js b/test/js/promise_s15.js
deleted file mode 100644 (file)
index 5b134bd..0000000
+++ /dev/null
@@ -1,10 +0,0 @@
-var obj = {};
-var p = Promise.resolve(obj);
-
-p.then(undefined, undefined)
-.then(function(arg) {
-    if (arg !== obj) {
-        console.log('Expected resolution object to be passed through, got ' + arg);
-    }
-})
-.then(() => {console.log('Done')}, () => {console.log('Error')});
\ No newline at end of file
diff --git a/test/js/promise_s15.t.js b/test/js/promise_s15.t.js
new file mode 100644 (file)
index 0000000..df5c82e
--- /dev/null
@@ -0,0 +1,16 @@
+/*---
+includes: []
+flags: [async]
+---*/
+
+var obj = {};
+var p = Promise.resolve(obj);
+
+p.then(undefined, undefined)
+.then(
+    v => {
+        assert.sameValue(v, obj,
+                         'Expected resolution object to be passed through, got ' + v);
+    },
+    e => $DONOTEVALUATE())
+.then($DONE, $DONE);
diff --git a/test/js/promise_s16.js b/test/js/promise_s16.js
deleted file mode 100644 (file)
index 769d38a..0000000
+++ /dev/null
@@ -1,10 +0,0 @@
-var obj = {};
-var p = Promise.reject(obj);
-
-p.then(undefined, undefined).then(function() {
-    console.log('Should not be called -- promise was rejected.');
-}, function(arg) {
-    if (arg !== obj) {
-        console.log('Expected resolution object to be passed through, got ' + arg);
-    }
-}).then(() => {console.log('Done')}, () => {console.log('Error')});
diff --git a/test/js/promise_s16.t.js b/test/js/promise_s16.t.js
new file mode 100644 (file)
index 0000000..b492488
--- /dev/null
@@ -0,0 +1,16 @@
+/*---
+includes: []
+flags: [async]
+---*/
+
+var obj = {};
+var p = Promise.reject(obj);
+
+p.then(undefined, undefined)
+.then(
+    v => DONOTEVALUATE(),
+    e => {
+        assert.sameValue(e, obj,
+                         'Expected resolution object to be passed through, got ' + e);
+})
+.then($DONE, $DONE);
diff --git a/test/js/promise_s17.js b/test/js/promise_s17.js
deleted file mode 100644 (file)
index 769d38a..0000000
+++ /dev/null
@@ -1,10 +0,0 @@
-var obj = {};
-var p = Promise.reject(obj);
-
-p.then(undefined, undefined).then(function() {
-    console.log('Should not be called -- promise was rejected.');
-}, function(arg) {
-    if (arg !== obj) {
-        console.log('Expected resolution object to be passed through, got ' + arg);
-    }
-}).then(() => {console.log('Done')}, () => {console.log('Error')});
diff --git a/test/js/promise_s17.t.js b/test/js/promise_s17.t.js
new file mode 100644 (file)
index 0000000..b5bc869
--- /dev/null
@@ -0,0 +1,18 @@
+/*---
+includes: []
+flags: [async]
+---*/
+
+/* Duplicate of s16. */
+
+var obj = {};
+var p = Promise.reject(obj);
+
+p.then(undefined, undefined)
+.then(
+    v => DONOTEVALUATE(),
+    e => {
+        assert.sameValue(e, obj,
+                         'Expected resolution object to be passed through, got ' + e);
+})
+.then($DONE, $DONE);
similarity index 50%
rename from test/js/promise_s18.js
rename to test/js/promise_s18.t.js
index 10d10641bb04e651c1035448bca45d9957e07a7b..ce0da2fe5439b8753ca6fa0aaec991a1f16aaafb 100644 (file)
@@ -1,23 +1,32 @@
+/*---
+includes: [compareArray.js]
+flags: [async]
+---*/
+
+let stages = [];
+
 var thenable = {
     then: function(resolve) {
         resolve();
-        console.log('State 5');
+        stages.push(5);
     }
 };
 
 var thenableWithError = {
     then: function(resolve) {
-        console.log('State 3');
+        stages.push(3);
         resolve(thenable);
-        console.log('State 4');
+        stages.push(4);
         throw new Error('ignored exception');
     }
 };
 
 function executor(resolve, reject) {
-    console.log('State 1');
+    stages.push(1);
     resolve(thenableWithError);
-    console.log('State 2');
+    stages.push(2);
 }
 
-new Promise(executor).then(() => {console.log('Done')}, () => {console.log('Error')});
\ No newline at end of file
+new Promise(executor)
+.then(() => assert.compareArray(stages, [1, 2, 3, 4, 5]))
+.then($DONE, $DONE);
diff --git a/test/js/promise_s19.js b/test/js/promise_s19.js
deleted file mode 100644 (file)
index 451f710..0000000
+++ /dev/null
@@ -1,33 +0,0 @@
-var returnValue = null;
-var value = {};
-var resolve;
-
-var poisonedThen = Object.defineProperty({}, 'then', {
-    get: function() {
-        console.log('Throw!');
-        throw value;
-    }
-});
-
-var promise = new Promise(function(_resolve) {
-    resolve = _resolve;
-});
-
-promise.then(
-function() {
-    console.log('Resolve!');
-    console.log('The promise should not be fulfilled.');
-},
-function(val) {
-    console.log('Reject!');
-    if (val !== value) {
-        console.log('The promise should be fulfilled with the provided value.');
-        return;
-    }
-
-    console.log('Done');
-});
-
-returnValue = resolve(poisonedThen);
-
-console.log(returnValue);
\ No newline at end of file
diff --git a/test/js/promise_s19.t.js b/test/js/promise_s19.t.js
new file mode 100644 (file)
index 0000000..d339b3f
--- /dev/null
@@ -0,0 +1,34 @@
+/*---
+includes: [compareArray.js]
+flags: [async]
+---*/
+
+let stages = [];
+
+var returnValue = null;
+var value = {};
+var resolve;
+
+var poisonedThen = Object.defineProperty({}, 'then', {
+    get: function() {
+        stages.push('Throw!');
+        throw value;
+    }
+});
+
+var promise = new Promise(function(_resolve) {
+    resolve = _resolve;
+});
+
+promise.then(
+    v => $DONOTEVALUATE(),
+    e => {
+        stages.push('Reject!');
+        assert.sameValue(e, value, 'The promise should be fulfilled with the provided value.');
+})
+.then(() => assert.compareArray(stages, ['Throw!', undefined, 'Reject!']))
+.then($DONE, $DONE);
+
+returnValue = resolve(poisonedThen);
+
+stages.push(returnValue);
diff --git a/test/js/promise_s2.js b/test/js/promise_s2.js
deleted file mode 100644 (file)
index 92d92dd..0000000
+++ /dev/null
@@ -1,14 +0,0 @@
-var promise = new Promise(function(resolve, reject) {
-    console.log('One');
-    reject(123);
-});
-
-console.log('Two');
-
-promise.then(() => {console.log('Four'); return {num: 'Five'}})
-.then((obj) => {console.log(obj.num);  return {num: 'Six'}})
-.then((obj) => {console.log(obj.num);  return {num: 'Seven'}})
-.then((obj) => {console.log(obj.num);  return {num: 'Eight'}})
-.then((obj) => {console.log(obj.num)});
-
-console.log('Three');
\ No newline at end of file
diff --git a/test/js/promise_s20.js b/test/js/promise_s20.js
deleted file mode 100644 (file)
index 0934bba..0000000
+++ /dev/null
@@ -1,23 +0,0 @@
-var returnValue = null;
-var value = {};
-var poisonedThen = Object.defineProperty({}, 'then', {
-    get: function() {
-        throw value;
-    }
-});
-var promise = new Promise(function(resolve) {
-    returnValue = resolve(poisonedThen);
-});
-
-console.log(returnValue == undefined);
-
-promise.then(function() {
-    console.log('The promise should not be fulfilled.');
-}, function(val) {
-    if (val !== value) {
-        console.log('The promise should be fulfilled with the provided value.');
-        return;
-    }
-
-    console.log('Done');
-});
\ No newline at end of file
diff --git a/test/js/promise_s20.t.js b/test/js/promise_s20.t.js
new file mode 100644 (file)
index 0000000..4c6a151
--- /dev/null
@@ -0,0 +1,25 @@
+/*---
+includes: []
+flags: [async]
+---*/
+
+var returnValue = null;
+var value = {};
+var poisonedThen = Object.defineProperty({}, 'then', {
+    get: function() {
+        throw value;
+    }
+});
+var promise = new Promise(function(resolve) {
+    returnValue = resolve(poisonedThen);
+});
+
+assert.sameValue(returnValue, undefined);
+
+promise
+.then(
+    v => $DONOTEVALUATE(),
+    e => {
+        assert.sameValue(e, value, 'The promise should be fulfilled with the provided value.');
+})
+.then($DONE, $DONE);
similarity index 51%
rename from test/js/promise_s21.js
rename to test/js/promise_s21.t.js
index aad00ccad5018c08988237ddbc0d3d758b6943f8..77689f6f68d96528ffe66398a633ca5b48f77e57 100644 (file)
@@ -1,3 +1,8 @@
+/*---
+includes: []
+flags: [async]
+---*/
+
 var value = {};
 var resolve;
 var poisonedThen = Object.defineProperty({}, 'then', {
@@ -16,15 +21,12 @@ p2 = p1.then(function() {
     return poisonedThen;
 });
 
-p2.then(function(x) {
-    console.log('The promise should not be fulfilled.');
-}, function(x) {
-    if (x !== value) {
-        console.log('The promise should be rejected with the thrown exception.');
-        return;
-    }
-
-    console.log('Done');
-});
+p2
+.then(
+    v => $DONOTEVALUATE(),
+    e =>  {
+        assert.sameValue(e, value, 'The promise should be rejected with the thrown exception.');
+})
+.then($DONE, $DONE);
 
-resolve();
\ No newline at end of file
+resolve();
diff --git a/test/js/promise_s22.js b/test/js/promise_s22.js
deleted file mode 100644 (file)
index 9dee7c1..0000000
+++ /dev/null
@@ -1,32 +0,0 @@
-var returnValue = null;
-var value = {};
-var resolve;
-
-var thenable = new Promise(function(resolve) {
-    resolve();
-});
-
-var promise = new Promise(function(_resolve) {
-    resolve = _resolve;
-});
-
-thenable.then = function(resolve) {
-    resolve(value);
-};
-
-promise.then(
-function(val) {
-    if (val !== value) {
-        console.log('The promise should be fulfilled with the provided value.');
-        return;
-    }
-
-    console.log('Done');
-},
-function() {
-    console.log('The promise should not be rejected.');
-});
-
-returnValue = resolve(thenable);
-
-console.log(returnValue == undefined);
\ No newline at end of file
diff --git a/test/js/promise_s22.t.js b/test/js/promise_s22.t.js
new file mode 100644 (file)
index 0000000..a590726
--- /dev/null
@@ -0,0 +1,32 @@
+/*---
+includes: []
+flags: [async]
+---*/
+
+var returnValue = null;
+var value = {};
+var resolve;
+
+var thenable = new Promise(function(resolve) {
+    resolve();
+});
+
+var promise = new Promise(function(_resolve) {
+    resolve = _resolve;
+});
+
+thenable.then = function(resolve) {
+    resolve(value);
+};
+
+promise
+.then(
+    v => {
+        assert.sameValue(v, value, 'The promise should be fulfilled with the provided value.');
+    },
+    e => $DONOTEVALUATE)
+.then($DONE, $DONE);
+
+returnValue = resolve(thenable);
+
+assert.sameValue(returnValue, undefined);
diff --git a/test/js/promise_s23.js b/test/js/promise_s23.js
deleted file mode 100644 (file)
index 8525cde..0000000
+++ /dev/null
@@ -1,28 +0,0 @@
-var returnValue = null;
-var resolve;
-
-var promise = new Promise(function(_resolve) {
-    resolve = _resolve;
-});
-
-promise.then(
-function() {
-    console.log('The promise should not be fulfilled.');
-},
-function(reason) {
-    if (!reason) {
-        console.log('The promise should be rejected with a value.');
-        return;
-    }
-
-    if (reason.constructor !== TypeError) {
-        console.log('The promise should be rejected with a TypeError instance.');
-        return;
-    }
-
-    console.log('Done');
-});
-
-returnValue = resolve(promise);
-
-console.log(returnValue == undefined)
\ No newline at end of file
diff --git a/test/js/promise_s23.t.js b/test/js/promise_s23.t.js
new file mode 100644 (file)
index 0000000..c9befa1
--- /dev/null
@@ -0,0 +1,25 @@
+/*---
+includes: []
+flags: [async]
+---*/
+
+var returnValue = null;
+var resolve;
+
+var promise = new Promise(function(_resolve) {
+    resolve = _resolve;
+});
+
+promise
+.then(
+    v => $DONOTEVALUATE(),
+    e => {
+
+        assert.sameValue(e.constructor, TypeError,
+                         'The promise should be rejected with a TypeError instance.');
+})
+.then($DONE, $DONE);
+
+returnValue = resolve(promise);
+
+assert.sameValue(returnValue, undefined);
similarity index 65%
rename from test/js/promise_s24.js
rename to test/js/promise_s24.t.js
index bb3dddff449caeee9d41723c6e0348772c5e5d34..f1e4a4ad2a0b2dafb876f3d53b9c48248e992fc6 100644 (file)
@@ -1,4 +1,9 @@
-var checkPoint = '';
+/*---
+includes: []
+flags: []
+---*/
+
+let checkPoint = '';
 
 Promise.reject.call(function(executor) {
     checkPoint += 'a';
@@ -10,4 +15,4 @@ Promise.reject.call(function(executor) {
     checkPoint += 'c';
 }, {});
 
-console.log(checkPoint == 'abc');
\ No newline at end of file
+assert.sameValue(checkPoint, 'abc');
diff --git a/test/js/promise_s25.js b/test/js/promise_s25.js
deleted file mode 100644 (file)
index 3b70e46..0000000
+++ /dev/null
@@ -1,29 +0,0 @@
-var resolve, reject;
-var promise = new Promise(function(_resolve, _reject) {
-    resolve = _resolve;
-    reject = _reject;
-});
-
-var P = function(executor) {
-    executor(resolve, reject);
-    return promise;
-};
-
-Promise.resolve.call(P, promise)
-.then(
-function() {
-    console.log('The promise should not be fulfilled.');
-},
-function(value) {
-    if (!value) {
-        console.log('The promise should be rejected with a value.');
-        return;
-    }
-
-    if (value.constructor !== TypeError) {
-        console.log('The promise should be rejected with a TypeError instance.');
-        return;
-    }
-
-    console.log('Done');
-});
\ No newline at end of file
diff --git a/test/js/promise_s25.t.js b/test/js/promise_s25.t.js
new file mode 100644 (file)
index 0000000..8fe8b74
--- /dev/null
@@ -0,0 +1,24 @@
+/*---
+includes: []
+flags: [async]
+---*/
+
+var resolve, reject;
+var promise = new Promise(function(_resolve, _reject) {
+    resolve = _resolve;
+    reject = _reject;
+});
+
+var P = function(executor) {
+    executor(resolve, reject);
+    return promise;
+};
+
+Promise.resolve.call(P, promise)
+.then(
+    v => $DONOTEVALUATE(),
+    e => {
+        assert.sameValue(e.constructor, TypeError,
+                         'The promise should be rejected with a TypeError instance.');
+})
+.then($DONE, $DONE);
diff --git a/test/js/promise_s26.js b/test/js/promise_s26.js
deleted file mode 100644 (file)
index f5244d3..0000000
+++ /dev/null
@@ -1,144 +0,0 @@
-var inherits = (child, parent) => {
-    child.prototype = Object.create(parent.prototype, {
-        constructor: {
-            value: child,
-            enumerable: false,
-            writable: true,
-            configurable: true
-        }
-    });
-    Object.setPrototypeOf(child, parent);
-};
-
-
-var BoxedPromise = (() => {
-    function BoxedPromise(executor) {
-        console.log('BoxedPromise.constructor');
-
-        if (!(this instanceof BoxedPromise)) {
-            return Promise(executor);
-        }
-
-        if (typeof executor !== 'function') {
-            return new Promise(executor);
-        }
-
-        var context, args;
-        var promise = new Promise(wrappedExecutor);
-        this.boxed = promise;
-
-        try {
-            executor.apply(context, args);
-
-        } catch (e) {
-            args[1](e);
-        }
-
-        function wrappedExecutor(resolve, reject) {
-            context = this;
-            args = [wrappedResolve, wrappedReject];
-            function wrappedResolve(val) {
-                return resolve(val);
-            }
-            function wrappedReject(val) {
-                return reject(val);
-            }
-        }
-    }
-
-    inherits(BoxedPromise, Promise);
-
-    BoxedPromise.prototype.then = function(res, rej) {
-        console.log('BoxedPromise.prototype.then');
-        var rs = Object.create(Object.getPrototypeOf(this));
-        rs.boxed = this.boxed.then(res, rej);
-        return rs;
-    };
-
-    return BoxedPromise;
-})();
-
-
-var PatchedPromise = (() => {
-    function PatchedPromise(executor) {
-        console.log('PatchedPromise.constructor');
-
-        if (!(this instanceof PatchedPromise)) {
-            return Promise(executor);
-        }
-
-        if (typeof executor !== 'function') {
-            return new Promise(executor);
-        }
-
-        var context, args;
-        var promise = new Promise(wrappedExecutor);
-        Object.setPrototypeOf(promise, PatchedPromise.prototype);
-
-        try {
-            executor.apply(context, args);
-
-        } catch (e) {
-            args[1](e);
-        }
-
-        return promise;
-
-        function wrappedExecutor(resolve, reject) {
-            context = this;
-            args = [wrappedResolve, wrappedReject];
-            function wrappedResolve(val) {
-                return resolve(val);
-            }
-            function wrappedReject(val) {
-                return reject(val);
-            }
-        }
-    }
-
-    inherits(PatchedPromise, Promise);
-
-    return PatchedPromise;
-})();
-
-
-var testSubclass = (Class, name) => {
-    return new Promise((resolve) => {
-        var resolved = Class.resolve(name)
-            .then((x) => console.log('resolved', name));
-
-        console.log(name, 'resolve', resolved instanceof Class ? 'OK' : 'failed');
-
-
-        var rejected = Class.reject(name)
-            .catch((x) => console.log('rejected', name));
-
-        console.log(name, 'reject', rejected instanceof Class ? 'OK' : 'failed');
-
-
-        var instance = new Class((resolve) => {
-            setImmediate(() => resolve(name));
-        });
-
-        var chain = instance
-            .then((x) => { console.log('then', x); return x; })
-            .then((x) => { console.log('then', x); return x; });
-
-        console.log(name, 'chain', chain instanceof Class ? 'OK' : 'failed');
-
-        var fin = chain
-            .finally(() => console.log('finally', name));
-
-        console.log(name, 'finally', fin instanceof Class ? 'OK' : 'failed');
-
-        console.log(name, 'sync done\n');
-
-        fin
-            .then(() => console.log(name, 'async done\n'))
-            .then(resolve);
-    });
-};
-
-Promise.resolve()
-    .then(() => testSubclass(BoxedPromise, 'BoxedPromise'))
-    .then(() => testSubclass(PatchedPromise, 'PatchedPromise'));
diff --git a/test/js/promise_s26.t.js b/test/js/promise_s26.t.js
new file mode 100644 (file)
index 0000000..499e520
--- /dev/null
@@ -0,0 +1,211 @@
+/*---
+includes: [compareArray.js]
+flags: [async]
+---*/
+
+let stages = [];
+
+var inherits = (child, parent) => {
+    child.prototype = Object.create(parent.prototype, {
+        constructor: {
+            value: child,
+            enumerable: false,
+            writable: true,
+            configurable: true
+        }
+    });
+    Object.setPrototypeOf(child, parent);
+};
+
+
+var BoxedPromise = (() => {
+    function BoxedPromise(executor) {
+        stages.push('BoxedPromise.constructor');
+
+        if (!(this instanceof BoxedPromise)) {
+            return Promise(executor);
+        }
+
+        if (typeof executor !== 'function') {
+            return new Promise(executor);
+        }
+
+        var context, args;
+        var promise = new Promise(wrappedExecutor);
+        this.boxed = promise;
+
+        try {
+            executor.apply(context, args);
+
+        } catch (e) {
+            args[1](e);
+        }
+
+        function wrappedExecutor(resolve, reject) {
+            context = this;
+            args = [wrappedResolve, wrappedReject];
+            function wrappedResolve(val) {
+                return resolve(val);
+            }
+            function wrappedReject(val) {
+                return reject(val);
+            }
+        }
+    }
+
+    inherits(BoxedPromise, Promise);
+
+    BoxedPromise.prototype.then = function(res, rej) {
+        stages.push('BoxedPromise.prototype.then');
+        var rs = Object.create(Object.getPrototypeOf(this));
+        rs.boxed = this.boxed.then(res, rej);
+        return rs;
+    };
+
+    return BoxedPromise;
+})();
+
+
+var PatchedPromise = (() => {
+    function PatchedPromise(executor) {
+        stages.push('PatchedPromise.constructor');
+
+        if (!(this instanceof PatchedPromise)) {
+            return Promise(executor);
+        }
+
+        if (typeof executor !== 'function') {
+            return new Promise(executor);
+        }
+
+        var context, args;
+        var promise = new Promise(wrappedExecutor);
+        Object.setPrototypeOf(promise, PatchedPromise.prototype);
+
+        try {
+            executor.apply(context, args);
+
+        } catch (e) {
+            args[1](e);
+        }
+
+        return promise;
+
+        function wrappedExecutor(resolve, reject) {
+            context = this;
+            args = [wrappedResolve, wrappedReject];
+            function wrappedResolve(val) {
+                return resolve(val);
+            }
+            function wrappedReject(val) {
+                return reject(val);
+            }
+        }
+    }
+
+    inherits(PatchedPromise, Promise);
+
+    return PatchedPromise;
+})();
+
+
+var testSubclass = (Class, name) => {
+    return new Promise((resolve) => {
+        var resolved = Class.resolve(name)
+            .then((x) => stages.push(`resolved ${name}`));
+
+        stages.push(`${name} resolve ${resolved instanceof Class ? 'OK' : 'failed'}`);
+
+
+        var rejected = Class.reject(name)
+            .catch((x) => stages.push(`rejected ${name}`));
+
+        stages.push(`${name} reject ${rejected instanceof Class ? 'OK' : 'failed'}`);
+
+        var instance = new Class((resolve) => {
+            setImmediate(() => resolve(name));
+        });
+
+        var chain = instance
+            .then((x) => { stages.push(`then ${x}`); return x; })
+            .then((x) => { stages.push(`then ${x}`); return x; });
+
+        stages.push(`${name} chain ${chain instanceof Class ? 'OK' : 'failed'}`);
+
+        var fin = chain
+            .finally(() => stages.push(`finally ${name}`));
+
+        stages.push(`${name} finally ${fin instanceof Class ? 'OK' : 'failed'}`);
+
+        stages.push(`${name} sync done`);
+
+        fin
+            .then(() => stages.push(`${name} async done`))
+            .then(resolve);
+    });
+};
+
+Promise.resolve()
+.then(() => testSubclass(BoxedPromise, 'BoxedPromise'))
+.then(() => {
+    assert.compareArray(stages, [
+      "BoxedPromise.constructor",
+      "BoxedPromise.prototype.then",
+      "BoxedPromise resolve OK",
+      "BoxedPromise.constructor",
+      "BoxedPromise.prototype.then",
+      "BoxedPromise reject OK",
+      "BoxedPromise.constructor",
+      "BoxedPromise.prototype.then",
+      "BoxedPromise.prototype.then",
+      "BoxedPromise chain OK",
+      "BoxedPromise.prototype.then",
+      "BoxedPromise finally OK",
+      "BoxedPromise sync done",
+
+      "BoxedPromise.prototype.then",
+      "BoxedPromise.prototype.then",
+      "resolved BoxedPromise",
+      "rejected BoxedPromise",
+      "then BoxedPromise",
+      "then BoxedPromise",
+      "finally BoxedPromise",
+      "BoxedPromise.constructor",
+      "BoxedPromise.prototype.then",
+      "BoxedPromise.prototype.then",
+      "BoxedPromise async done",
+    ]);
+    stages = [];
+})
+.then(() => testSubclass(PatchedPromise, 'PatchedPromise'))
+.then(() => {
+    assert.compareArray(stages, [
+        "PatchedPromise.constructor",
+        "PatchedPromise.constructor",
+        "PatchedPromise resolve OK",
+        "PatchedPromise.constructor",
+        "PatchedPromise.constructor",
+        "PatchedPromise reject OK",
+        "PatchedPromise.constructor",
+        "PatchedPromise.constructor",
+        "PatchedPromise.constructor",
+        "PatchedPromise chain OK",
+        "PatchedPromise.constructor",
+        "PatchedPromise finally OK",
+        "PatchedPromise sync done",
+
+        "PatchedPromise.constructor",
+        "PatchedPromise.constructor",
+        "resolved PatchedPromise",
+        "rejected PatchedPromise",
+        "then PatchedPromise",
+        "then PatchedPromise",
+        "finally PatchedPromise",
+        "PatchedPromise.constructor",
+        "PatchedPromise.constructor",
+        "PatchedPromise.constructor",
+        "PatchedPromise async done",
+    ]);
+    stages = [];
+})
+.then($DONE, $DONE);
diff --git a/test/js/promise_s3.js b/test/js/promise_s3.js
deleted file mode 100644 (file)
index 8e71fe3..0000000
+++ /dev/null
@@ -1,11 +0,0 @@
-
-var promise = new Promise(function(resolve, reject) {
-    console.log('One');
-    reject(new Error('Blah'));
-});
-
-console.log('Two');
-
-promise.then((response) => console.log(`Fulfilled: ${response}`), (error) => console.log(`Rejected: ${error}`));
-
-console.log('Three');
\ No newline at end of file
diff --git a/test/js/promise_s4.js b/test/js/promise_s4.js
deleted file mode 100644 (file)
index ce52e6b..0000000
+++ /dev/null
@@ -1,6 +0,0 @@
-Promise.reject(new Error('Oh my')).then(function(success) {
-},
-function(error) {
-    console.log(error);
-    throw error;
-});
\ No newline at end of file
diff --git a/test/js/promise_s5.js b/test/js/promise_s5.js
deleted file mode 100644 (file)
index 91995f9..0000000
+++ /dev/null
@@ -1,7 +0,0 @@
-
-Promise.resolve('Success').then(function(value) {
-    console.log(value);
-},
-function(value) {
-    console.log('ignored');
-});
\ No newline at end of file
diff --git a/test/js/promise_s6.js b/test/js/promise_s6.js
deleted file mode 100644 (file)
index 9451c6e..0000000
+++ /dev/null
@@ -1,4 +0,0 @@
-var p = Promise.resolve([1,2,3]);
-p.then(function(v) {
-    console.log(v[0]);
-});
\ No newline at end of file
diff --git a/test/js/promise_s7.js b/test/js/promise_s7.js
deleted file mode 100644 (file)
index 5ecc378..0000000
+++ /dev/null
@@ -1,12 +0,0 @@
-var p1 = Promise.resolve({
-    then: function(onFulfill, onReject) { onFulfill('fulfilled!'); }
-});
-
-console.log(p1 instanceof Promise);
-
-p1.then(function(v) {
-    console.log(v);
-},
-function(e) {
-    console.log('ignored');
-});
\ No newline at end of file
diff --git a/test/js/promise_s8.js b/test/js/promise_s8.js
deleted file mode 100644 (file)
index da87ff7..0000000
+++ /dev/null
@@ -1,13 +0,0 @@
-var thenable = {
-    then: function(resolve) {
-        console.log('Ok')
-        resolve();
-    }
-};
-
-function executor(resolve, reject) {
-    resolve(thenable);
-    throw new Error('ignored');
-}
-
-new Promise(executor).then(() => {});
\ No newline at end of file
diff --git a/test/js/promise_s9.js b/test/js/promise_s9.js
deleted file mode 100644 (file)
index 4c014bb..0000000
+++ /dev/null
@@ -1,10 +0,0 @@
-var executorFunction;
-
-function NotPromise(executor) {
-  executorFunction = executor;
-  executor(function() {console.log('S')}, function() {console.log('R')});
-}
-
-Promise.resolve.call(NotPromise);
-
-console.log(Object.isExtensible(executorFunction));
\ No newline at end of file
similarity index 63%
rename from test/js/promise_set_timeout.js
rename to test/js/promise_set_timeout.t.js
index c0d365bd241dbfa9419a412d93dd3f6a652b87c0..fe908f13ceae4de9dd9366e39ceb0570f9ccff06 100644 (file)
@@ -1,3 +1,8 @@
+/*---
+includes: [compareArray.js]
+flags: []
+---*/
+
 var res = [];
 function abc() {
     var promise = new Promise(function(resolve, reject) {
@@ -7,11 +12,10 @@ function abc() {
     res.push('Two');
     promise.then(() => {res.push('Four'); return {num: 'Five'}})
     .then((obj) => {res.push(obj.num);  return {num: 'Six'}})
-    .then((obj) => {res.push(obj.num);  return {num: 'Seven'}})
-    .then((obj) => {res.push(obj.num);  return {num: 'Eight'}})
     .then((obj) => {res.push(obj.num)});
     res.push('Three');
 }
+
 abc();
-console.log(res.join(','));
-setTimeout(() => console.log(res.join(',')), 0);
+assert.compareArray(res, ['One', 'Two', 'Three']);
+setTimeout(() => assert.compareArray(res, ['One', 'Two', 'Three', 'Four', 'Five', 'Six']), 0);
diff --git a/test/js/promise_then_throw.js b/test/js/promise_then_throw.js
deleted file mode 100644 (file)
index 0a14dfd..0000000
+++ /dev/null
@@ -1,2 +0,0 @@
-Promise.resolve()
-.then(() => {nonExsisting()});
\ No newline at end of file
diff --git a/test/js/promise_then_throw.t.js b/test/js/promise_then_throw.t.js
new file mode 100644 (file)
index 0000000..a2e5761
--- /dev/null
@@ -0,0 +1,9 @@
+/*---
+includes: []
+flags: []
+negative:
+  phase: runtime
+---*/
+
+Promise.resolve()
+.then(() => {nonExsisting()});
diff --git a/test/js/promise_then_throw_catch.js b/test/js/promise_then_throw_catch.js
deleted file mode 100644 (file)
index eee458b..0000000
+++ /dev/null
@@ -1,3 +0,0 @@
-Promise.resolve()
-.then(() => {nonExsisting()})
-.catch(() => {console.log("Done")});
\ No newline at end of file
diff --git a/test/js/promise_then_throw_catch.t.js b/test/js/promise_then_throw_catch.t.js
new file mode 100644 (file)
index 0000000..afa1ca7
--- /dev/null
@@ -0,0 +1,12 @@
+/*---
+includes: []
+flags: [async]
+---*/
+
+let called = false;
+
+Promise.resolve()
+.then(() => {nonExsisting()})
+.catch(() => {called = true;})
+.then(v => assert.sameValue(called, true))
+.then($DONE, $DONE);
diff --git a/test/js/promise_then_throw_finally_catch.js b/test/js/promise_then_throw_finally_catch.js
deleted file mode 100644 (file)
index 534154c..0000000
+++ /dev/null
@@ -1,4 +0,0 @@
-Promise.resolve()
-.then(() => {nonExsisting()})
-.finally(() => {})
-.catch(() => {console.log("Done")});
\ No newline at end of file
diff --git a/test/js/promise_then_throw_finally_catch.t.js b/test/js/promise_then_throw_finally_catch.t.js
new file mode 100644 (file)
index 0000000..4f00a39
--- /dev/null
@@ -0,0 +1,13 @@
+/*---
+includes: []
+flags: [async]
+---*/
+
+let called = false;
+
+Promise.resolve()
+.then(() => {nonExsisting()})
+.finally(() => {})
+.catch(() => {called = true;})
+.then(v => assert.sameValue(called, true))
+.then($DONE, $DONE);
similarity index 65%
rename from test/js/promise_two_first_then_throw.js
rename to test/js/promise_two_first_then_throw.t.js
index 2752287b91662c93f1ecfc3ce9a0fe3efd18de36..e2406c11c3088d714223cc94547c64505a260893 100644 (file)
@@ -1,3 +1,10 @@
+/*---
+includes: []
+flags: []
+negative:
+  phase: runtime
+---*/
+
 Promise.resolve()
 .then(() => {nonExsistingOne()});
 
diff --git a/test/js/promise_two_then_throw.js b/test/js/promise_two_then_throw.js
deleted file mode 100644 (file)
index af0a00b..0000000
+++ /dev/null
@@ -1,5 +0,0 @@
-Promise.resolve()
-.then(() => {nonExsistingOne()});
-
-Promise.resolve()
-.then(() => {nonExsistingTwo()});
\ No newline at end of file
diff --git a/test/js/promise_two_then_throw.t.js b/test/js/promise_two_then_throw.t.js
new file mode 100644 (file)
index 0000000..f29bf1b
--- /dev/null
@@ -0,0 +1,12 @@
+/*---
+includes: []
+flags: []
+negative:
+  phase: runtime
+---*/
+
+Promise.resolve()
+.then(() => {nonExsistingOne()});
+
+Promise.resolve()
+.then(() => {nonExsistingTwo()});
index 8d0a4a37647fbdf8931684f5054e42d0736505c1..69d9cc8d608bacb4d7651cc89f99b6f9f409b18d 100644 (file)
@@ -648,405 +648,3 @@ njs_test {
 # version
 
 njs_run {"-v"} "\\d+\.\\d+\.\\d+"
-
-# Promise
-
-njs_run {"./test/js/promise_set_timeout.js"} \
-"One,Two,Three
-One,Two,Three,Four,Five,Six,Seven,Eight"
-
-njs_run {"./test/js/promise_s1.js"} \
-"One
-Two
-Three
-123
-Four
-Five
-Six
-Seven
-Eight"
-
-njs_run {"./test/js/promise_s2.js"} \
-"One
-Two
-Three"
-
-njs_run {"./test/js/promise_s3.js"} \
-"One
-Two
-Three
-Rejected: Error: Blah"
-
-njs_run {"./test/js/promise_s4.js"} \
-"Error: Oh my"
-
-njs_run {"./test/js/promise_s5.js"} \
-"Success"
-
-njs_run {"./test/js/promise_s6.js"} \
-"1"
-
-njs_run {"./test/js/promise_s7.js"} \
-"true
-fulfilled!"
-
-njs_run {"./test/js/promise_s8.js"} \
-"Ok"
-
-njs_run {"./test/js/promise_s9.js"} \
-"S
-true"
-
-njs_run {"./test/js/promise_s10.js"} \
-"One
-Two
-Three
-Oh no"
-
-njs_run {"./test/js/promise_s11.js"} \
-"end
-S: all
-R: all"
-
-njs_run {"./test/js/promise_s12.js"} \
-"Done"
-
-njs_run {"./test/js/promise_s13.js"} \
-"Done"
-
-njs_run {"./test/js/promise_s14.js"} \
-"TypeError: oops
-    at anonymous \\\(promise_s14.js:5\\\)
-    at native \\\(native\\\)
-    at main \\\(promise_s14.js:9\\\)
-
-Done"
-
-njs_run {"./test/js/promise_s15.js"} \
-"Done"
-
-njs_run {"./test/js/promise_s16.js"} \
-"Done"
-
-njs_run {"./test/js/promise_s17.js"} \
-"Done"
-
-njs_run {"./test/js/promise_s18.js"} \
-"State 1
-State 2
-State 3
-State 4
-State 5
-Done"
-
-njs_run {"./test/js/promise_s19.js"} \
-"Throw!
-undefined
-Reject!
-Done"
-
-njs_run {"./test/js/promise_s20.js"} \
-"true
-Done"
-
-njs_run {"./test/js/promise_s21.js"} \
-"Done"
-
-njs_run {"./test/js/promise_s22.js"} \
-"true
-Done"
-
-njs_run {"./test/js/promise_s23.js"} \
-"true
-Done"
-
-njs_run {"./test/js/promise_s24.js"} \
-"true"
-
-njs_run {"./test/js/promise_s25.js"} \
-"Done"
-
-njs_run {"./test/js/promise_s26.js"} \
-"BoxedPromise.constructor
-BoxedPromise.prototype.then
-BoxedPromise resolve OK
-BoxedPromise.constructor
-BoxedPromise.prototype.then
-BoxedPromise reject OK
-BoxedPromise.constructor
-BoxedPromise.prototype.then
-BoxedPromise.prototype.then
-BoxedPromise chain OK
-BoxedPromise.prototype.then
-BoxedPromise finally OK
-BoxedPromise sync done
-
-BoxedPromise.prototype.then
-BoxedPromise.prototype.then
-resolved BoxedPromise
-rejected BoxedPromise
-then BoxedPromise
-then BoxedPromise
-finally BoxedPromise
-BoxedPromise.constructor
-BoxedPromise.prototype.then
-BoxedPromise.prototype.then
-BoxedPromise async done
-
-PatchedPromise.constructor
-PatchedPromise.constructor
-PatchedPromise resolve OK
-PatchedPromise.constructor
-PatchedPromise.constructor
-PatchedPromise reject OK
-PatchedPromise.constructor
-PatchedPromise.constructor
-PatchedPromise.constructor
-PatchedPromise chain OK
-PatchedPromise.constructor
-PatchedPromise finally OK
-PatchedPromise sync done
-
-PatchedPromise.constructor
-PatchedPromise.constructor
-resolved PatchedPromise
-rejected PatchedPromise
-then PatchedPromise
-then PatchedPromise
-finally PatchedPromise
-PatchedPromise.constructor
-PatchedPromise.constructor
-PatchedPromise.constructor
-PatchedPromise async done"
-
-# fs
-
-njs_run {"./test/fs/methods.js" "--match-exception-text"} \
-"fs readFile SUCCESS
-fs readFileSync SUCCESS
-fsp readFile SUCCESS
-fs writeFile SUCCESS
-fs writeFileSync SUCCESS
-fsp writeFile SUCCESS
-fs appendFile SUCCESS
-fs appendFileSync SUCCESS
-fsp appendFile SUCCESS
-fs realpath SUCCESS
-fs realpathSync SUCCESS
-fsp realpath SUCCESS
-fs stat SUCCESS
-fs statSync SUCCESS
-fsp stat SUCCESS
-fs lstat SUCCESS
-fs lstatSync SUCCESS
-fsp lstat SUCCESS"
-
-njs_run {"./test/js/fs_promises_001.js"} \
-"init ok true
-short circut ok true
-chain ok true
-error 1 ok true
-error 2 ok true
-errors ok"
-
-njs_run {"./test/js/fs_promises_002.js"} \
-"testSync ok true
-testCallback ok true
-testPromise ok true"
-
-njs_run {"./test/js/fs_promises_003.js"} \
-"test fs.unlinkSync
-test fs.unlink
-test fsp.unlink"
-
-njs_run {"./test/js/fs_promises_004.js"} \
-"test fs.symlinkSync
-test fs.symlink
-test fsp.symlink"
-
-njs_run {"./test/js/fs_promises_005.js"} \
-"test fs.mkdirSync
-test fs.mkdir
-test fsp.mkdir"
-
-njs_run {"./test/js/fs_promises_006.js"} \
-"test fs.renameSync
-test fs.rename
-test fsp.rename"
-
-njs_run {"./test/js/fs_promises_007.js"} \
-"test fs.readdirSync
-test fs.readdir
-test fsp.readdir"
-
-njs_run {"./test/js/fs_promises_008.js"} \
-"test recursive fs.mkdirSync"
-
-njs_run {"./test/js/fs_promises_009.js"} \
-"test recursive fs.rmdirSync"
-
-njs_run {"./test/js/promise_then_throw_finally_catch.js"} \
-"Done"
-
-njs_run {"./test/js/promise_catch_throw.js"} \
-"Error: unhandled promise rejection: ReferenceError: \"nonExsistingInCatch\" is not defined"
-
-njs_run {"./test/js/promise_then_throw.js"} \
-"Error: unhandled promise rejection: ReferenceError: \"nonExsisting\" is not defined"
-
-njs_run {"./test/js/promise_then_throw_catch.js"} \
-"Done"
-
-njs_run {"./test/js/promise_catch_then_throw_catch.js"} \
-"Done"
-
-njs_run {"./test/js/promise_finally.js"} \
-"here
-Thrown:
-Error: unhandled promise rejection: nope"
-
-njs_run {"./test/js/promise_finally_throw.js"} \
-"Error: unhandled promise rejection: ReferenceError: \"nonExsistingInFinally\" is not defined"
-
-njs_run {"./test/js/promise_finally_throw_catch.js"} \
-"Done"
-
-njs_run {"./test/js/promise_two_then_throw.js"} \
-"Error: unhandled promise rejection: ReferenceError: \"nonExsistingOne\" is not defined"
-
-njs_run {"./test/js/promise_two_first_then_throw.js"} \
-"Error: unhandled promise rejection: ReferenceError: \"nonExsistingOne\" is not defined"
-
-njs_run {"./test/js/promise_reject_catch.js"} \
-"rejected test"
-
-njs_run {"./test/js/promise_reject_post_catch.js"} \
-"Error: unhandled promise rejection: undefined"
-
-njs_run {"./test/js/promise_rejection_tracker.js"} \
-"Thrown:
-Error: unhandled promise rejection: 1"
-
-njs_run {"./test/js/promise_all.js"} \
-"resolved:\\\[\\\['one','two'],\\\['three','four']]"
-
-njs_run {"./test/js/promise_all_throw.js"} \
-"rejected:foo"
-
-njs_run {"./test/js/promise_allSettled.js"} \
-"resolved:resolved:F:0,3,42,here|R:finally,finally after rejected,foo,here too,yes"
-
-njs_run {"./test/js/promise_allSettled_string.js"} \
-"resolved:F:a,b,c|R:"
-
-njs_run {"./test/js/promise_any.js"} \
-"resolved:4"
-
-njs_run {"./test/js/promise_any_all_rejected.js"} \
-"reject:AggregateError: All promises were rejected"
-
-njs_run {"./test/js/promise_race.js"} \
-"resolved:one"
-
-njs_run {"./test/js/promise_race_throw.js"} \
-"rejected:one"
-
-# Webcrypto
-
-njs_run {"./test/webcrypto/rsa_decoding.js" "--match-exception-text"} \
-"RSA-OAEP decoding SUCCESS"
-
-njs_run {"./test/webcrypto/rsa.js" "--match-exception-text"} \
-"RSA-OAEP encoding/decoding SUCCESS"
-
-njs_run {"./test/webcrypto/aes_decoding.js" "--match-exception-text"} \
-"AES decoding SUCCESS"
-
-njs_run {"./test/webcrypto/aes.js" "--match-exception-text"} \
-"AES encoding/decoding SUCCESS"
-
-njs_run {"./test/webcrypto/derive.js" "--match-exception-text"} \
-"derive SUCCESS"
-
-njs_run {"./test/webcrypto/digest.js" "--match-exception-text"} \
-"SHA digest SUCCESS"
-
-njs_run {"./test/webcrypto/sign.js" "--match-exception-text"} \
-"HMAC sign SUCCESS
-RSASSA-PKCS1-v1_5 sign SUCCESS
-RSA-PSS sign SUCCESS
-ECDSA sign SUCCESS"
-
-njs_run {"./test/webcrypto/verify.js" "--match-exception-text"} \
-"HMAC verify SUCCESS
-RSASSA-PKCS1-v1_5 verify SUCCESS
-RSA-PSS verify SUCCESS
-ECDSA verify SUCCESS"
-
-# Async/Await
-
-njs_run {"./test/js/async_await_inline.js"} \
-"70"
-
-njs_run {"./test/js/async_await_add.js"} \
-"110"
-
-njs_run {"./test/js/async_await_stages.js"} \
-"30 1, 2, 3, 4, 5"
-
-njs_run {"./test/js/async_await_for.js"} \
-"85 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, end"
-
-njs_run {"./test/js/async_await_blank.js"} \
-"12345"
-
-njs_run {"./test/js/async_await_reject.js"} \
-"Thrown:
-Error: unhandled promise rejection: 50"
-
-njs_run {"./test/js/async_await_catch.js"} \
-"51"
-
-njs_run {"./test/js/async_await_finally.js"} \
-"51
-Thrown:
-Error: unhandled promise rejection: 50"
-
-njs_run {"./test/js/async_await_throw.js"} \
-"Thrown:
-Error: unhandled promise rejection: 50"
-
-njs_run {"./test/js/async_await_throw_catch.js"} \
-"110"
-
-njs_run {"./test/js/async_await_throw_async.js"} \
-"Thrown:
-Error: unhandled promise rejection: 51"
-
-njs_run {"./test/js/async_await_throw_catch_async.js"} \
-"51"
-
-njs_run {"./test/js/async_await_try_catch.js"} \
-"reject
-finally
-end"
-
-njs_run {"./test/js/async_await_try_finally.js"} \
-"Thrown:
-Error: unhandled promise rejection: finally reject"
-
-njs_run {"./test/js/async_await_try_throw.js"} \
-"finally
-Thrown:
-Error: unhandled promise rejection: try"
-
-njs_run {"./test/js/async_await_try_throw_catch.js"} \
-"try
-finally
-end"
-
-njs_run {"./test/js/async_await_try_resolve.js"} \
-"key: resolve"
-
-njs_run {"./test/js/async_await_many_call.js"} \
-"\\\['First: SUN MOON','Second: CAT MOUSE','Third: MAN WOMAN']"
diff --git a/test/options b/test/options
new file mode 100644 (file)
index 0000000..023fde0
--- /dev/null
@@ -0,0 +1,61 @@
+#!/bin/sh
+
+# Copyright (C) Dmitry Volyntsev
+# Copyright (C) NGINX, Inc.
+
+NJS_TEST_DIR=`mktemp -d /tmp/njs_test.XXX`
+NJS_TEST_LOG_DEFAULT="$NJS_TEST_DIR/log.log"
+
+NJS_TEST_VERBOSE=${NJS_TEST_VERBOSE:-}
+NJS_TEST_BINARY=${NJS_TEST_BINARY:-build/njs}
+NJS_TEST_LOG=${NJS_TEST_LOG:-${NJS_TEST_LOG_DEFAULT}}
+
+for njs_option
+do
+    case "$njs_option" in
+        -*=*) value=`echo "$njs_option" | sed -e 's/[-_a-zA-Z0-9]*=//'`      ;;
+           *) value="" ;;
+    esac
+
+    case "$njs_option" in
+        --binary=*)
+            NJS_TEST_BINARY="$value"
+            shift
+        ;;
+
+        --log=*)
+            NJS_TEST_LOG="$value"
+            shift
+        ;;
+
+        --test-dir=*)
+            NJS_TEST_DIR="$value"
+            shift
+        ;;
+
+        --verbose=*)
+            NJS_TEST_VERBOSE="$value"
+            shift
+        ;;
+
+        --help)
+            . test/help
+            exit 0
+        ;;
+
+        --*)
+            echo
+            echo $0: error: invalid option \"$njs_option\".
+            echo Run \"$0 --help\" to see available options.
+            echo
+            exit 1
+        ;;
+
+        *)
+            break
+        ;;
+    esac
+
+done
+
+NJS_TEST_PATHS=${@:-test}
diff --git a/test/prepare b/test/prepare
new file mode 100644 (file)
index 0000000..45adcfb
--- /dev/null
@@ -0,0 +1,36 @@
+#!/bin/sh
+
+# Copyright (C) Dmitry Volyntsev
+# Copyright (C) NGINX, Inc.
+
+njs_includes=`grep 'includes: \[[^]]*]' $njs_test \
+             | sed -e 's/includes: \[//' | sed -e 's/,/ /g' | sed -e 's/\]//'`
+njs_includes="assert.js sta.js $njs_includes"
+
+njs_flags=`grep 'flags: \[[^]]*]' $njs_test \
+             | sed -e 's/flags: \[//' | sed -e 's/,/ /g' | sed -e 's/\]//'`
+
+njs_negative=`grep 'negative:' $njs_test > /dev/null \
+              && grep 'phase: ' $njs_test | sed -e 's/ *phase: //' || true`
+
+njs_async=no
+for flag in $njs_flags; do
+    case $flag in
+        async)
+            njs_async=yes
+            njs_includes="compatPrint.js doneprintHandle.js $njs_includes"
+
+        ;;
+    esac
+done
+
+njs_inc=
+for file in $njs_includes; do
+    njs_inc="$njs_inc test/harness/$file"
+done
+
+mkdir -p `dirname $NJS_TEST_DIR/$njs_test`
+
+cat $njs_inc $njs_test > $NJS_TEST_DIR/$njs_test
+
+njs_total=$((njs_total+1))
diff --git a/test/report b/test/report
new file mode 100644 (file)
index 0000000..6aafe59
--- /dev/null
@@ -0,0 +1,18 @@
+#!/bin/sh
+
+# Copyright (C) Dmitry Volyntsev
+# Copyright (C) NGINX, Inc.
+
+NJS_STATUS="PASSED"
+if [ $njs_passed -ne $njs_total ]; then
+    NJS_STATUS="FAILED"
+fi
+
+if [ -n "$njs_failed_list" ]; then
+    for t in $njs_failed_list; do
+        printf "$t FAILED\n"
+    done
+fi
+
+printf "TOTAL: $NJS_STATUS [$njs_passed/$njs_total]\n"
+exit $(($njs_passed != $njs_total))
diff --git a/test/setup b/test/setup
new file mode 100644 (file)
index 0000000..5760a9f
--- /dev/null
@@ -0,0 +1,39 @@
+#!/bin/sh
+
+# Copyright (C) Dmitry Volyntsev
+# Copyright (C) NGINX, Inc.
+
+verbose() {
+    if [ -n "$NJS_TEST_VERBOSE" ]; then
+        printf "$1"
+    fi
+}
+
+passed() {
+    verbose " PASSED\n"
+    njs_passed=$((njs_passed+1))
+}
+
+failed() {
+    njs_failed_list="$njs_failed_list $1"
+    verbose " FAILED\n"
+}
+
+verbose "Test dir: $NJS_TEST_DIR\n"
+verbose "Log file: $NJS_TEST_LOG\n"
+verbose "\n"
+
+njs_passed=0
+njs_total=0
+njs_failed_list=""
+
+NJS_TESTS=""
+for arg in $NJS_TEST_PATHS; do
+    if [ -d $arg ]; then
+        NJS_TESTS="$NJS_TESTS $(find $arg -name '*\.t\.js')"
+    else
+        NJS_TESTS="$NJS_TESTS $arg"
+    fi
+done
+
+NJS_TESTS=`printf "%s\n" $NJS_TESTS  | sort`
diff --git a/test/test262 b/test/test262
new file mode 100755 (executable)
index 0000000..56e16df
--- /dev/null
@@ -0,0 +1,64 @@
+#!/bin/sh
+
+# Copyright (C) Dmitry Volyntsev
+# Copyright (C) NGINX, Inc.
+
+set -e
+
+. test/options
+. test/setup
+
+for njs_test in $NJS_TESTS; do
+    . test/prepare
+
+    njs_log="$NJS_TEST_DIR/${njs_test%.*}.log"
+
+    verbose "$njs_test $njs_log"
+    cat << END >> $NJS_TEST_LOG
+----------------------------------------
+running $njs_test $njs_log
+END
+
+    if /bin/sh -c "($NJS_TEST_BINARY $NJS_TEST_DIR/$njs_test)" > $njs_log 2>&1; then
+        njs_success=yes
+    else
+        njs_success=no
+    fi
+
+    cat $njs_log >> $NJS_TEST_LOG
+    njs_out=`cat $njs_log`
+
+    if [ $njs_success = yes ]; then
+        if [ -n "$njs_negative" ]; then
+            failed $njs_test
+
+        elif [ $njs_async = yes ]; then
+            if [ "$njs_out" != 'Test262:AsyncTestComplete' ]; then
+                failed $njs_test
+
+            else
+                passed $njs_test
+            fi
+
+        else
+            if [ -n "$njs_out" ]; then
+                failed $njs_test
+
+            else
+                passed $njs_test
+            fi
+        fi
+
+    else
+        if [ -n "$njs_negative" ]; then
+            passed $njs_test
+
+        else
+            failed $njs_test
+        fi
+    fi
+
+done
+
+. test/finalize
+. test/report
similarity index 77%
rename from test/webcrypto/aes.js
rename to test/webcrypto/aes.t.js
index 85577fc9f80642d9221e726ccc63d0eec34e26c2..ad08e35b837119ae4f6023c583466eb82b3861cb 100644 (file)
@@ -1,38 +1,26 @@
-if (typeof crypto == 'undefined') {
-    crypto = require('crypto').webcrypto;
-}
+/*---
+includes: [compatFs.js, compatBuffer.js, compatWebcrypto.js, runTsuite.js, webCryptoUtils.js]
+flags: [async]
+---*/
 
-async function run(tlist) {
-    function validate(t, r, i) {
-        if (r.status == "fulfilled" && !t[i].exception) {
-            return r.value === "SUCCESS";
-        }
+async function test(params) {
+    let dkey = await crypto.subtle.importKey("raw", params.key,
+                                       {name: params.name},
+                                       false, ["decrypt"]);
 
-        if (r.status == "rejected" && t[i].exception) {
-            if (process.argv[2] === '--match-exception-text') {
-                /* is not compatible with node.js format */
-                return r.reason.toString().startsWith(t[i].exception);
-            }
+    let ekey = await crypto.subtle.importKey("raw", params.key,
+                                       {name: params.name},
+                                       false, ["encrypt"]);
 
-            return true;
-        }
+    let enc = await crypto.subtle.encrypt(params, ekey, params.data);
+    let plaintext = await crypto.subtle.decrypt(params, dkey, enc);
+    plaintext = Buffer.from(plaintext);
 
-        return false;
+    if (params.data.compare(plaintext) != 0) {
+        throw Error(`${params.name} encoding/decoding failed length ${data.length}`);
     }
 
-    for (let k = 0; k < tlist.length; k++) {
-        let ts = tlist[k];
-        let results = await Promise.allSettled(ts.tests.map(t => ts.T(ts.prepare_args(t, ts.opts))));
-        let r = results.map((r, i) => validate(ts.tests, r, i));
-
-        console.log(`${ts.name} ${r.every(v=>v == true) ? "SUCCESS" : "FAILED"}`);
-
-        r.forEach((v, i) => {
-            if (!v) {
-                console.log(`FAILED ${i}: ${JSON.stringify(ts.tests[i])}\n    with reason: ${results[i].reason}`);
-            }
-        })
-    }
+    return 'SUCCESS';
 }
 
 function p(args, default_opts) {
@@ -55,28 +43,10 @@ function p(args, default_opts) {
     return params;
 }
 
-async function test(params) {
-    let dkey = await crypto.subtle.importKey("raw", params.key,
-                                       {name: params.name},
-                                       false, ["decrypt"]);
-
-    let ekey = await crypto.subtle.importKey("raw", params.key,
-                                       {name: params.name},
-                                       false, ["encrypt"]);
-
-    let enc = await crypto.subtle.encrypt(params, ekey, params.data);
-    let plaintext = await crypto.subtle.decrypt(params, dkey, enc);
-    plaintext = Buffer.from(plaintext);
-
-    if (params.data.compare(plaintext) != 0) {
-        throw Error(`${params.name} encoding/decoding failed length ${data.length}`);
-    }
-
-    return 'SUCCESS';
-}
 
 let aes_tsuite = {
     name: "AES encoding/decoding",
+    skip: () => (!has_fs() || !has_buffer() || !has_webcrypto()),
     T: test,
     prepare_args: p,
     opts: {
@@ -122,4 +92,5 @@ let aes_tsuite = {
         { name: "AES-CBC", data: "aabbccdd".repeat(5), iv: "ffffffffffffffffffffffffffffffff" },
 ]};
 
-run([aes_tsuite]);
+run([aes_tsuite])
+.then($DONE, $DONE);
similarity index 69%
rename from test/webcrypto/aes_decoding.js
rename to test/webcrypto/aes_decoding.t.js
index d518856ad583b18e1a1def8585c39252879eb29d..c1aff369576540f5ef2735716caa942b20c95d0d 100644 (file)
@@ -1,45 +1,22 @@
-const fs = require('fs');
+/*---
+includes: [compatFs.js, compatBuffer.js, compatWebcrypto.js, runTsuite.js, webCryptoUtils.js]
+flags: [async]
+---*/
 
-if (typeof crypto == 'undefined') {
-    crypto = require('crypto').webcrypto;
-}
-
-async function run(tlist) {
-    function validate(t, r, i) {
-        if (r.status == "fulfilled" && !t[i].exception) {
-            return r.value === "SUCCESS";
-        }
-
-        if (r.status == "rejected" && t[i].exception) {
-            if (process.argv[2] === '--match-exception-text') {
-                /* is not compatible with node.js format */
-                return r.reason.toString().startsWith(t[i].exception);
-            }
-
-            return true;
-        }
-
-        return false;
-    }
-
-    for (let k = 0; k < tlist.length; k++) {
-        let ts = tlist[k];
-        let results = await Promise.allSettled(ts.tests.map(t => ts.T(ts.prepare_args(t, ts.opts))));
-        let r = results.map((r, i) => validate(ts.tests, r, i));
+async function test(params) {
+    let enc = base64decode(fs.readFileSync(`test/webcrypto/${params.file}`));
+    let key = await crypto.subtle.importKey("raw", params.key,
+                                            {name: params.name},
+                                            false, ["decrypt"]);
 
-        console.log(`${ts.name} ${r.every(v=>v == true) ? "SUCCESS" : "FAILED"}`);
+    let plaintext = await crypto.subtle.decrypt(params, key, enc);
+    plaintext = new TextDecoder().decode(plaintext);
 
-        r.forEach((v, i) => {
-            if (!v) {
-                console.log(`FAILED ${i}: ${JSON.stringify(ts.tests[i])}\n    with reason: ${results[i].reason}`);
-            }
-        })
+    if (params.expected != plaintext) {
+        throw Error(`${params.name} decoding failed expected: "${params.expected}" vs "${plaintext}"`);
     }
-}
 
-function base64decode(b64) {
-    const joined = b64.toString().split('\n').join('');
-    return Buffer.from(joined, 'base64');
+    return 'SUCCESS';
 }
 
 function p(args, default_opts) {
@@ -61,24 +38,9 @@ function p(args, default_opts) {
     return params;
 }
 
-async function test(params) {
-    let enc = base64decode(fs.readFileSync(`test/webcrypto/${params.file}`));
-    let key = await crypto.subtle.importKey("raw", params.key,
-                                            {name: params.name},
-                                            false, ["decrypt"]);
-
-    let plaintext = await crypto.subtle.decrypt(params, key, enc);
-    plaintext = new TextDecoder().decode(plaintext);
-
-    if (params.expected != plaintext) {
-        throw Error(`${params.name} decoding failed expected: "${params.expected}" vs "${plaintext}"`);
-    }
-
-    return 'SUCCESS';
-}
-
 let aes_tsuite = {
     name: "AES decoding",
+    skip: () => (!has_fs() || !has_buffer() || !has_webcrypto()),
     T: test,
     prepare_args: p,
     opts: {
@@ -115,4 +77,5 @@ let aes_tsuite = {
           expected: "AES-CBC-256-SECRET-TEXT" },
 ]};
 
-run([aes_tsuite]);
+run([aes_tsuite])
+.then($DONE, $DONE);
similarity index 70%
rename from test/webcrypto/derive.js
rename to test/webcrypto/derive.t.js
index 8c87c013b3c17ef3ac997bf90f21ce6db29933c4..60a2188999b3125153968907291196b975b0f7cf 100644 (file)
@@ -1,71 +1,7 @@
-if (typeof crypto == 'undefined') {
-    crypto = require('crypto').webcrypto;
-}
-
-async function run(tlist) {
-    function validate(t, r, i) {
-        if (r.status == "fulfilled" && !t[i].exception) {
-            return r.value === "SUCCESS";
-        }
-
-        if (r.status == "rejected" && t[i].exception) {
-            if (process.argv[2] === '--match-exception-text') {
-                /* is not compatible with node.js format */
-                return r.reason.toString().startsWith(t[i].exception);
-            }
-
-            return true;
-        }
-
-        if (r.status == "rejected" && t[i].optional) {
-            return r.reason.toString().startsWith("InternalError: not implemented");
-        }
-
-        return false;
-    }
-
-    for (let k = 0; k < tlist.length; k++) {
-        let ts = tlist[k];
-        let results = await Promise.allSettled(ts.tests.map(t => ts.T(ts.prepare_args(t, ts.opts))));
-        let r = results.map((r, i) => validate(ts.tests, r, i));
-
-        console.log(`${ts.name} ${r.every(v=>v == true) ? "SUCCESS" : "FAILED"}`);
-
-        r.forEach((v, i) => {
-            if (!v) {
-                console.log(`FAILED ${i}: ${JSON.stringify(ts.tests[i])}\n    with reason: ${results[i].reason}`);
-            }
-        })
-    }
-}
-
-function merge(to, from) {
-    let r = Object.assign({}, to);
-    Object.keys(from).forEach(v => {
-        if (typeof r[v] == 'object' && typeof from[v] == 'object') {
-            r[v] = merge(r[v], from[v]);
-
-        } else if (typeof from[v] == 'object') {
-            r[v] = Object.assign({}, from[v]);
-
-        } else {
-            r[v] = from[v];
-        }
-    })
-
-    return r;
-};
-
-function p(args, default_opts) {
-    let params = Object.assign({}, default_opts);
-    params = merge(params, args);
-
-    params.algorithm.salt = Buffer.from(params.algorithm.salt, "hex");
-    params.algorithm.info = Buffer.from(params.algorithm.info, "hex");
-    params.derivedAlgorithm.iv = Buffer.from(params.derivedAlgorithm.iv, "hex");
-
-    return params;
-}
+/*---
+includes: [compatFs.js, compatBuffer.js, compatWebcrypto.js, runTsuite.js, webCryptoUtils.js]
+flags: [async]
+---*/
 
 async function test(params) {
     let r;
@@ -94,8 +30,20 @@ async function test(params) {
     return "SUCCESS";
 }
 
+function p(args, default_opts) {
+    let params = Object.assign({}, default_opts);
+    params = merge(params, args);
+
+    params.algorithm.salt = Buffer.from(params.algorithm.salt, "hex");
+    params.algorithm.info = Buffer.from(params.algorithm.info, "hex");
+    params.derivedAlgorithm.iv = Buffer.from(params.derivedAlgorithm.iv, "hex");
+
+    return params;
+}
+
 let derive_tsuite = {
     name: "derive",
+    skip: () => (!has_fs() || !has_buffer() || !has_webcrypto()),
     T: test,
     prepare_args: p,
     opts: {
@@ -148,4 +96,5 @@ let derive_tsuite = {
           expected: "e089c7491711306c69e077aa19fae6bfd2d4a6d240b0d37317d50472d7291a3e" },
 ]};
 
-run([derive_tsuite]);
+run([derive_tsuite])
+.then($DONE, $DONE);
similarity index 69%
rename from test/webcrypto/digest.js
rename to test/webcrypto/digest.t.js
index 77d6ad143ffa2a78ccef3fc26715ad92d27e27d0..f6413348330cb23af6df7fde8a868e8cd83da4f5 100644 (file)
@@ -1,45 +1,7 @@
-if (typeof crypto == 'undefined') {
-    crypto = require('crypto').webcrypto;
-}
-
-async function run(tlist) {
-    function validate(t, r, i) {
-        if (r.status == "fulfilled" && !t[i].exception) {
-            return r.value === "SUCCESS";
-        }
-
-        if (r.status == "rejected" && t[i].exception) {
-            if (process.argv[2] === '--match-exception-text') {
-                /* is not compatible with node.js format */
-                return r.reason.toString().startsWith(t[i].exception);
-            }
-
-            return true;
-        }
-
-        return false;
-    }
-
-    for (let k = 0; k < tlist.length; k++) {
-        let ts = tlist[k];
-        let results = await Promise.allSettled(ts.tests.map(t => ts.T(ts.prepare_args(t, ts.opts))));
-        let r = results.map((r, i) => validate(ts.tests, r, i));
-
-        console.log(`${ts.name} ${r.every(v=>v == true) ? "SUCCESS" : "FAILED"}`);
-
-        r.forEach((v, i) => {
-            if (!v) {
-                console.log(`FAILED ${i}: ${JSON.stringify(ts.tests[i])}\n    with reason: ${results[i].reason}`);
-            }
-        })
-    }
-}
-
-function p(args) {
-    let params = Object.assign({}, args);
-    params.data = Buffer.from(params.data, "hex");
-    return params;
-}
+/*---
+includes: [compatFs.js, compatBuffer.js, compatWebcrypto.js, runTsuite.js, webCryptoUtils.js]
+flags: [async]
+---*/
 
 async function test(params) {
     let digest = await crypto.subtle.digest(params.name, params.data);
@@ -52,8 +14,15 @@ async function test(params) {
     return 'SUCCESS';
 }
 
+function p(args) {
+    let params = Object.assign({}, args);
+    params.data = Buffer.from(params.data, "hex");
+    return params;
+}
+
 let digest_tsuite = {
     name: "SHA digest",
+    skip: () => (!has_fs() || !has_buffer() || !has_webcrypto()),
     T: test,
     prepare_args: p,
     opts: { },
@@ -87,4 +56,5 @@ let digest_tsuite = {
           expected: "cdea58919606ea9ae078f7595b192b84446f2189" },
 ]};
 
-run([digest_tsuite]);
+run([digest_tsuite])
+.then($DONE, $DONE);
similarity index 61%
rename from test/webcrypto/rsa.js
rename to test/webcrypto/rsa.t.js
index 42d68d022ff8113ffed62898415b642ab83d93b9..1e4c540984d804cd7636d8065f32e11ae0f56a38 100644 (file)
@@ -1,57 +1,7 @@
-const fs = require('fs');
-
-if (typeof crypto == 'undefined') {
-    crypto = require('crypto').webcrypto;
-}
-
-async function run(tlist) {
-    function validate(t, r, i) {
-        if (r.status == "fulfilled" && !t[i].exception) {
-            return r.value === "SUCCESS";
-        }
-
-        if (r.status == "rejected" && t[i].exception) {
-            if (process.argv[2] === '--match-exception-text') {
-                /* is not compatible with node.js format */
-                return r.reason.toString().startsWith(t[i].exception);
-            }
-
-            return true;
-        }
-
-        return false;
-    }
-
-    for (let k = 0; k < tlist.length; k++) {
-        let ts = tlist[k];
-        let results = await Promise.allSettled(ts.tests.map(t => ts.T(ts.prepare_args(t, ts.opts))));
-        let r = results.map((r, i) => validate(ts.tests, r, i));
-
-        console.log(`${ts.name} ${r.every(v=>v == true) ? "SUCCESS" : "FAILED"}`);
-
-        r.forEach((v, i) => {
-            if (!v) {
-                console.log(`FAILED ${i}: ${JSON.stringify(ts.tests[i])}\n    with reason: ${results[i].reason}`);
-            }
-        })
-    }
-}
-
-function pem_to_der(pem, type) {
-    const pemJoined = pem.toString().split('\n').join('');
-    const pemHeader = `-----BEGIN ${type} KEY-----`;
-    const pemFooter = `-----END ${type} KEY-----`;
-    const pemContents = pemJoined.substring(pemHeader.length, pemJoined.length - pemFooter.length);
-    return Buffer.from(pemContents, 'base64');
-}
-
-function p(args, default_opts) {
-    let params = Object.assign({}, default_opts, args);
-
-    params.data = Buffer.from(params.data, "hex");
-
-    return params;
-}
+/*---
+includes: [compatFs.js, compatBuffer.js, compatWebcrypto.js, runTsuite.js, webCryptoUtils.js]
+flags: [async]
+---*/
 
 async function test(params) {
     let spki = await crypto.subtle.importKey("spki",
@@ -75,10 +25,19 @@ async function test(params) {
     }
 
     return 'SUCCESS';
-};
+}
+
+function p(args, default_opts) {
+    let params = Object.assign({}, default_opts, args);
+
+    params.data = Buffer.from(params.data, "hex");
+
+    return params;
+}
 
 let rsa_tsuite = {
     name: "RSA-OAEP encoding/decoding",
+    skip: () => (!has_fs() || !has_buffer() || !has_webcrypto()),
     T: test,
     prepare_args: p,
     opts: {
@@ -105,4 +64,5 @@ let rsa_tsuite = {
         { data: "aabbcc", spki: "rsa2.spki", exception: "Error: EVP_PKEY_decrypt() failed" },
 ]};
 
-run([rsa_tsuite]);
+run([rsa_tsuite])
+.then($DONE, $DONE);
diff --git a/test/webcrypto/rsa_decoding.js b/test/webcrypto/rsa_decoding.js
deleted file mode 100644 (file)
index 4ebdd0f..0000000
+++ /dev/null
@@ -1,83 +0,0 @@
-const fs = require('fs');
-
-if (typeof crypto == 'undefined') {
-    crypto = require('crypto').webcrypto;
-}
-
-async function run(tlist) {
-    function validate(t, r, i) {
-        if (r.status == "fulfilled" && !t[i].exception) {
-            return r.value === "SUCCESS";
-        }
-
-        if (r.status == "rejected" && t[i].exception) {
-            if (process.argv[2] === '--match-exception-text') {
-                /* is not compatible with node.js format */
-                return r.reason.toString().startsWith(t[i].exception);
-            }
-
-            return true;
-        }
-
-        return false;
-    }
-
-    for (let k = 0; k < tlist.length; k++) {
-        let ts = tlist[k];
-        let results = await Promise.allSettled(ts.tests.map(t => ts.T(ts.prepare_args(t, ts.opts))));
-        let r = results.map((r, i) => validate(ts.tests, r, i));
-
-        console.log(`${ts.name} ${r.every(v=>v == true) ? "SUCCESS" : "FAILED"}`);
-
-        r.forEach((v, i) => {
-            if (!v) {
-                console.log(`FAILED ${i}: ${JSON.stringify(ts.tests[i])}\n    with reason: ${results[i].reason}`);
-            }
-        })
-    }
-}
-
-function pem_to_der(pem) {
-    const pemJoined = pem.toString().split('\n').join('');
-    const pemHeader = '-----BEGIN PRIVATE KEY-----';
-    const pemFooter = '-----END PRIVATE KEY-----';
-    const pemContents = pemJoined.substring(pemHeader.length, pemJoined.length - pemFooter.length);
-    return Buffer.from(pemContents, 'base64');
-}
-
-function base64decode(b64) {
-    const joined = b64.toString().split('\n').join('');
-    return Buffer.from(joined, 'base64');
-}
-
-async function test(params) {
-    let pem = fs.readFileSync(`test/webcrypto/${params.pem}`);
-    let enc = base64decode(fs.readFileSync(`test/webcrypto/${params.src}`));
-
-    let key = await crypto.subtle.importKey("pkcs8", pem_to_der(pem),
-                                            {name:"RSA-OAEP", hash:"SHA-1"},
-                                            false, ["decrypt"]);
-
-    let plaintext = await crypto.subtle.decrypt({name: "RSA-OAEP"}, key, enc);
-    plaintext = new TextDecoder().decode(plaintext);
-
-    if (params.expected != plaintext) {
-        throw Error(`RSA-OAEP decoding failed expected: "${params.expected}" vs "${plaintext}"`);
-    }
-
-    return "SUCCESS";
-}
-
-let rsa_tsuite = {
-    name: "RSA-OAEP decoding",
-    T: test,
-    prepare_args: (v) => v,
-    opts: { },
-
-    tests: [
-        { pem: "rsa.pkcs8", src: "text.base64.rsa-oaep.enc", expected: "WAKAWAKA" },
-        { pem: "ec.pkcs8", src: "text.base64.rsa-oaep.enc", exception: "Error: RSA key is not found" },
-        { pem: "rsa.pkcs8.broken", src: "text.base64.rsa-oaep.enc", exception: "Error: d2i_PKCS8_PRIV_KEY_INFO_bio() failed" },
-]};
-
-run([rsa_tsuite]);
diff --git a/test/webcrypto/rsa_decoding.t.js b/test/webcrypto/rsa_decoding.t.js
new file mode 100644 (file)
index 0000000..3253dab
--- /dev/null
@@ -0,0 +1,41 @@
+/*---
+includes: [compatFs.js, compatBuffer.js, compatWebcrypto.js, runTsuite.js, webCryptoUtils.js]
+flags: [async]
+---*/
+
+async function test(params) {
+    if (!has_fs() || !has_buffer() || !has_webcrypto()) {
+        return 'SKIPPED';
+    }
+
+    let pem = fs.readFileSync(`test/webcrypto/${params.pem}`);
+    let enc = base64decode(fs.readFileSync(`test/webcrypto/${params.src}`));
+
+    let key = await crypto.subtle.importKey("pkcs8", pem_to_der(pem, "PRIVATE"),
+                                            {name:"RSA-OAEP", hash:"SHA-1"},
+                                            false, ["decrypt"]);
+
+    let plaintext = await crypto.subtle.decrypt({name: "RSA-OAEP"}, key, enc);
+    plaintext = new TextDecoder().decode(plaintext);
+
+    if (params.expected != plaintext) {
+        throw Error(`RSA-OAEP decoding failed expected: "${params.expected}" vs "${plaintext}"`);
+    }
+
+    return "SUCCESS";
+}
+
+let rsa_tsuite = {
+    name: "RSA-OAEP decoding",
+    T: test,
+    prepare_args: (v) => v,
+    opts: { },
+
+    tests: [
+        { pem: "rsa.pkcs8", src: "text.base64.rsa-oaep.enc", expected: "WAKAWAKA" },
+        { pem: "ec.pkcs8", src: "text.base64.rsa-oaep.enc", exception: "Error: RSA key is not found" },
+        { pem: "rsa.pkcs8.broken", src: "text.base64.rsa-oaep.enc", exception: "Error: d2i_PKCS8_PRIV_KEY_INFO_bio() failed" },
+]};
+
+run([rsa_tsuite])
+.then($DONE, $DONE);
similarity index 81%
rename from test/webcrypto/sign.js
rename to test/webcrypto/sign.t.js
index 60f5fa77fe536d1e51f0cbf6c9a55c2131570204..d9eb3dc7123caa58d1e64b7d1fdb21a9c0921e84 100644 (file)
@@ -1,107 +1,7 @@
-const fs = require('fs');
-if (typeof crypto == 'undefined') {
-    crypto = require('crypto').webcrypto;
-}
-
-async function run(tlist) {
-    function validate(t, r, i) {
-        if (r.status == "fulfilled" && !t[i].exception) {
-            return r.value === "SUCCESS";
-        }
-
-        if (r.status == "rejected" && t[i].exception) {
-            if (process.argv[2] === '--match-exception-text') {
-                /* is not compatible with node.js format */
-                return r.reason.toString().startsWith(t[i].exception);
-            }
-
-            return true;
-        }
-
-        return false;
-    }
-
-    for (let k = 0; k < tlist.length; k++) {
-        let ts = tlist[k];
-        let results = await Promise.allSettled(ts.tests.map(t => ts.T(ts.prepare_args(t, ts.opts))));
-        let r = results.map((r, i) => validate(ts.tests, r, i));
-
-        console.log(`${ts.name} ${r.every(v=>v == true) ? "SUCCESS" : "FAILED"}`);
-
-        r.forEach((v, i) => {
-            if (!v) {
-                console.log(`FAILED ${i}: ${JSON.stringify(ts.tests[i])}\n    with reason: ${results[i].reason}`);
-            }
-        })
-    }
-}
-
-function merge(to, from) {
-    let r = Object.assign({}, to);
-    Object.keys(from).forEach(v => {
-        if (typeof r[v] == 'object' && typeof from[v] == 'object') {
-            r[v] = merge(r[v], from[v]);
-
-        } else if (typeof from[v] == 'object') {
-            r[v] = Object.assign({}, from[v]);
-
-        } else {
-            r[v] = from[v];
-        }
-    })
-
-    return r;
-};
-
-function pem_to_der(pem, type) {
-    const pemJoined = pem.toString().split('\n').join('');
-    const pemHeader = `-----BEGIN ${type} KEY-----`;
-    const pemFooter = `-----END ${type} KEY-----`;
-    const pemContents = pemJoined.substring(pemHeader.length, pemJoined.length - pemFooter.length);
-    return Buffer.from(pemContents, 'base64');
-}
-
-function base64decode(b64) {
-    const joined = b64.toString().split('\n').join('');
-    return Buffer.from(joined, 'base64');
-}
-
-function p(args, default_opts) {
-    let key;
-    let encoder = new TextEncoder();
-    let params = merge({}, default_opts);
-    params = merge(params, args);
-
-    switch (params.sign_key.fmt) {
-    case "pkcs8":
-        let pem = fs.readFileSync(`test/webcrypto/${params.sign_key.key}`);
-        key = pem_to_der(pem, "PRIVATE");
-        break;
-    case "raw":
-        key = encoder.encode(params.sign_key.key);
-        break;
-    default:
-        throw Error("Unknown sign key format");
-    }
-
-    params.sign_key.key = key;
-
-    switch (params.verify_key.fmt) {
-    case "spki":
-        let pem = fs.readFileSync(`test/webcrypto/${params.verify_key.key}`);
-        key = pem_to_der(pem, "PUBLIC");
-        break;
-    case "raw":
-        key = encoder.encode(params.verify_key.key);
-        break;
-    default:
-        throw Error("Unknown verify key format");
-    }
-
-    params.verify_key.key = key;
-
-    return params;
-}
+/*---
+includes: [compatFs.js, compatBuffer.js, compatWebcrypto.js, runTsuite.js, webCryptoUtils.js]
+flags: [async]
+---*/
 
 async function test(params) {
     let encoder = new TextEncoder();
@@ -158,8 +58,46 @@ async function test(params) {
     return "SUCCESS";
 }
 
+function p(args, default_opts) {
+    let key;
+    let encoder = new TextEncoder();
+    let params = merge({}, default_opts);
+    params = merge(params, args);
+
+    switch (params.sign_key.fmt) {
+    case "pkcs8":
+        let pem = fs.readFileSync(`test/webcrypto/${params.sign_key.key}`);
+        key = pem_to_der(pem, "PRIVATE");
+        break;
+    case "raw":
+        key = encoder.encode(params.sign_key.key);
+        break;
+    default:
+        throw Error("Unknown sign key format");
+    }
+
+    params.sign_key.key = key;
+
+    switch (params.verify_key.fmt) {
+    case "spki":
+        let pem = fs.readFileSync(`test/webcrypto/${params.verify_key.key}`);
+        key = pem_to_der(pem, "PUBLIC");
+        break;
+    case "raw":
+        key = encoder.encode(params.verify_key.key);
+        break;
+    default:
+        throw Error("Unknown verify key format");
+    }
+
+    params.verify_key.key = key;
+
+    return params;
+}
+
 let hmac_tsuite = {
     name: "HMAC sign",
+    skip: () => (!has_fs() || !has_buffer() || !has_webcrypto()),
     T: test,
     prepare_args: p,
     opts: {
@@ -195,6 +133,7 @@ let hmac_tsuite = {
 
 let rsassa_pkcs1_v1_5_tsuite = {
     name: "RSASSA-PKCS1-v1_5 sign",
+    skip: () => (!has_fs() || !has_buffer() || !has_webcrypto()),
     T: test,
     prepare_args: p,
     opts: {
@@ -225,6 +164,7 @@ let rsassa_pkcs1_v1_5_tsuite = {
 
 let rsa_pss_tsuite = {
     name: "RSA-PSS sign",
+    skip: () => (!has_fs() || !has_buffer() || !has_webcrypto()),
     T: test,
     prepare_args: p,
     opts: {
@@ -256,6 +196,7 @@ let rsa_pss_tsuite = {
 
 let ecdsa_tsuite = {
     name: "ECDSA sign",
+    skip: () => (!has_fs() || !has_buffer() || !has_webcrypto()),
     T: test,
     prepare_args: p,
     opts: {
@@ -287,4 +228,5 @@ run([
     rsassa_pkcs1_v1_5_tsuite,
     rsa_pss_tsuite,
     ecdsa_tsuite
-]);
+])
+.then($DONE, $DONE);
similarity index 70%
rename from test/webcrypto/verify.js
rename to test/webcrypto/verify.t.js
index 6ae24d02c3b9288bff78e380f71fa80638e23ec4..b77f5c16b195c9fda9788cb76973c98c5c1bb2ae 100644 (file)
@@ -1,70 +1,23 @@
-const fs = require('fs');
+/*---
+includes: [compatFs.js, compatBuffer.js, compatWebcrypto.js, runTsuite.js, webCryptoUtils.js]
+flags: [async]
+---*/
 
-if (typeof crypto == 'undefined') {
-    crypto = require('crypto').webcrypto;
-}
-
-async function run(tlist) {
-    function validate(t, r, i) {
-        if (r.status == "fulfilled" && !t[i].exception) {
-            return r.value === "SUCCESS";
-        }
-
-        if (r.status == "rejected" && t[i].exception) {
-            if (process.argv[2] === '--match-exception-text') {
-                /* is not compatible with node.js format */
-                return r.reason.toString().startsWith(t[i].exception);
-            }
-
-            return true;
-        }
-
-        return false;
-    }
-
-    for (let k = 0; k < tlist.length; k++) {
-        let ts = tlist[k];
-        let results = await Promise.allSettled(ts.tests.map(t => ts.T(ts.prepare_args(t, ts.opts))));
-        let r = results.map((r, i) => validate(ts.tests, r, i));
+async function test(params) {
+    let key = await crypto.subtle.importKey(params.key.fmt,
+                                            params.key.file,
+                                            params.import_alg,
+                                            false, ["verify"]);
 
-        console.log(`${ts.name} ${r.every(v=>v == true) ? "SUCCESS" : "FAILED"}`);
+    let r = await crypto.subtle.verify(params.verify_alg,
+                                       key, params.signature,
+                                       params.text);
 
-        r.forEach((v, i) => {
-            if (!v) {
-                console.log(`FAILED ${i}: ${JSON.stringify(ts.tests[i])}\n    with reason: ${results[i].reason}`);
-            }
-        })
+    if (params.expected !== r) {
+        throw Error(`${params.import_alg.name} failed expected: "${params.expected}" vs "${r}"`);
     }
-}
-
-function merge(to, from) {
-    let r = Object.assign({}, to);
-    Object.keys(from).forEach(v => {
-        if (typeof r[v] == 'object' && typeof from[v] == 'object') {
-            r[v] = merge(r[v], from[v]);
-
-        } else if (typeof from[v] == 'object') {
-            r[v] = Object.assign({}, from[v]);
-
-        } else {
-            r[v] = from[v];
-        }
-    })
-
-    return r;
-};
 
-function base64decode(b64) {
-    const joined = b64.toString().split('\n').join('');
-    return Buffer.from(joined, 'base64');
-}
-
-function pem_to_der(pem, type) {
-    const pemJoined = pem.toString().split('\n').join('');
-    const pemHeader = `-----BEGIN ${type} KEY-----`;
-    const pemFooter = `-----END ${type} KEY-----`;
-    const pemContents = pemJoined.substring(pemHeader.length, pemJoined.length - pemFooter.length);
-    return Buffer.from(pemContents, 'base64');
+    return 'SUCCESS';
 }
 
 function p(args, default_opts) {
@@ -88,26 +41,9 @@ function p(args, default_opts) {
     return params;
 }
 
-
-async function test(params) {
-    let key = await crypto.subtle.importKey(params.key.fmt,
-                                            params.key.file,
-                                            params.import_alg,
-                                            false, ["verify"]);
-
-    let r = await crypto.subtle.verify(params.verify_alg,
-                                       key, params.signature,
-                                       params.text);
-
-    if (params.expected !== r) {
-        throw Error(`${params.import_alg.name} failed expected: "${params.expected}" vs "${r}"`);
-    }
-
-    return 'SUCCESS';
-}
-
 let hmac_tsuite = {
     name: "HMAC verify",
+    skip: () => (!has_fs() || !has_buffer() || !has_webcrypto()),
     T: test,
     prepare_args: p,
     opts: {
@@ -132,6 +68,7 @@ let hmac_tsuite = {
 
 let rsassa_pkcs1_v1_5_tsuite = {
     name: "RSASSA-PKCS1-v1_5 verify",
+    skip: () => (!has_fs() || !has_buffer() || !has_webcrypto()),
     T: test,
     prepare_args: p,
     opts: {
@@ -156,6 +93,7 @@ let rsassa_pkcs1_v1_5_tsuite = {
 
 let rsa_pss_tsuite = {
     name: "RSA-PSS verify",
+    skip: () => (!has_fs() || !has_buffer() || !has_webcrypto()),
     T: test,
     prepare_args: p,
     opts: {
@@ -185,6 +123,7 @@ let rsa_pss_tsuite = {
 
 let ecdsa_tsuite = {
     name: "ECDSA verify",
+    skip: () => (!has_fs() || !has_buffer() || !has_webcrypto()),
     T: test,
     prepare_args: p,
     opts: {
@@ -212,4 +151,5 @@ run([
     rsassa_pkcs1_v1_5_tsuite,
     rsa_pss_tsuite,
     ecdsa_tsuite,
-]);
+])
+.then($DONE, $DONE);