From 0294bea9979e71cae5c0d639569c38252a3af712 Mon Sep 17 00:00:00 2001
From: Cam Tenny <cam@igalia.com>
Date: Tue, 22 Nov 2022 18:07:14 -0800
Subject: [PATCH] Harness tests for asyncHelpers.js' assert.throwsAsync
 function

---
 ...yncHelpers-throwsAsync-custom-typeerror.js | 72 +++++++++++++++++++
 .../asyncHelpers-throwsAsync-custom.js        | 17 +++++
 ...-throwsAsync-funcOrThenable-throws-sync.js | 63 ++++++++++++++++
 ...asyncHelpers-throwsAsync-incorrect-ctor.js | 33 +++++++++
 ...pers-throwsAsync-invalid-funcOrThenable.js | 71 ++++++++++++++++++
 .../asyncHelpers-throwsAsync-native.js        | 47 ++++++++++++
 .../asyncHelpers-throwsAsync-no-arg.js        | 32 +++++++++
 .../asyncHelpers-throwsAsync-no-error.js      | 32 +++++++++
 test/harness/asyncHelpers-throwsAsync-null.js | 34 +++++++++
 .../asyncHelpers-throwsAsync-primitive.js     | 34 +++++++++
 ...asyncHelpers-throwsAsync-resolved-error.js | 35 +++++++++
 .../asyncHelpers-throwsAsync-same-realm.js    | 37 ++++++++++
 .../asyncHelpers-throwsAsync-single-arg.js    | 31 ++++++++
 13 files changed, 538 insertions(+)
 create mode 100644 test/harness/asyncHelpers-throwsAsync-custom-typeerror.js
 create mode 100644 test/harness/asyncHelpers-throwsAsync-custom.js
 create mode 100644 test/harness/asyncHelpers-throwsAsync-funcOrThenable-throws-sync.js
 create mode 100644 test/harness/asyncHelpers-throwsAsync-incorrect-ctor.js
 create mode 100644 test/harness/asyncHelpers-throwsAsync-invalid-funcOrThenable.js
 create mode 100644 test/harness/asyncHelpers-throwsAsync-native.js
 create mode 100644 test/harness/asyncHelpers-throwsAsync-no-arg.js
 create mode 100644 test/harness/asyncHelpers-throwsAsync-no-error.js
 create mode 100644 test/harness/asyncHelpers-throwsAsync-null.js
 create mode 100644 test/harness/asyncHelpers-throwsAsync-primitive.js
 create mode 100644 test/harness/asyncHelpers-throwsAsync-resolved-error.js
 create mode 100644 test/harness/asyncHelpers-throwsAsync-same-realm.js
 create mode 100644 test/harness/asyncHelpers-throwsAsync-single-arg.js

diff --git a/test/harness/asyncHelpers-throwsAsync-custom-typeerror.js b/test/harness/asyncHelpers-throwsAsync-custom-typeerror.js
new file mode 100644
index 0000000000..0f5cf43354
--- /dev/null
+++ b/test/harness/asyncHelpers-throwsAsync-custom-typeerror.js
@@ -0,0 +1,72 @@
+// Copyright (C) 2022 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+/*---
+description: |
+    Thenables that reject with instances of the specified constructor function
+    satisfy the assertion, without collision with error constructors of the same name.
+flags: [async]
+includes: [asyncHelpers.js]
+---*/
+
+var intrinsicTypeError = TypeError;
+
+(async function () {
+  function TypeError() {}
+  var caught = false;
+
+  var p = assert.throwsAsync(
+    TypeError,
+    async function () {
+      throw new TypeError();
+    },
+    "Throws an instance of the matching custom TypeError"
+  );
+  assert(p instanceof Promise);
+  await p;
+
+  p = assert.throwsAsync(intrinsicTypeError, async function () {
+    throw new TypeError();
+  });
+  assert(p instanceof Promise);
+  try {
+    await p;
+  } catch (err) {
+    caught = true;
+    assert.sameValue(
+      err.constructor,
+      Test262Error,
+      "Expected a Test262Error, but a '" +
+        err.constructor.name +
+        "' was thrown."
+    );
+  } finally {
+    assert(
+      caught,
+      "assert.throwsAsync did not reject a collision of constructor names"
+    );
+  }
+
+  caught = false;
+
+  p = assert.throwsAsync(TypeError, async function () {
+    throw new intrinsicTypeError();
+  });
+  assert(p instanceof Promise);
+  try {
+    await p;
+  } catch (err) {
+    caught = true;
+    assert.sameValue(
+      err.constructor,
+      Test262Error,
+      "Expected a Test262Error, but a '" +
+        err.constructor.name +
+        "' was thrown."
+    );
+  } finally {
+    assert(
+      caught,
+      "assert.throwsAsync did not reject a collision of constructor names"
+    );
+  }
+})().then($DONE, $DONE);
diff --git a/test/harness/asyncHelpers-throwsAsync-custom.js b/test/harness/asyncHelpers-throwsAsync-custom.js
new file mode 100644
index 0000000000..db009d07a1
--- /dev/null
+++ b/test/harness/asyncHelpers-throwsAsync-custom.js
@@ -0,0 +1,17 @@
+// Copyright (C) 2022 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+/*---
+description: |
+    Thenables that reject with values of the specified constructor function
+    satisfy the assertion.
+flags: [async]
+includes: [asyncHelpers.js]
+---*/
+
+function MyError() {}
+
+(async function () {
+  const p = assert.throwsAsync(MyError, Promise.reject(new MyError()));
+  assert(p instanceof Promise);
+  await p;
+})().then($DONE, $DONE);
diff --git a/test/harness/asyncHelpers-throwsAsync-funcOrThenable-throws-sync.js b/test/harness/asyncHelpers-throwsAsync-funcOrThenable-throws-sync.js
new file mode 100644
index 0000000000..accad26ea6
--- /dev/null
+++ b/test/harness/asyncHelpers-throwsAsync-funcOrThenable-throws-sync.js
@@ -0,0 +1,63 @@
+// Copyright (C) 2022 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+/*---
+description: |
+    assert.throwsAsync returns a promise that rejects if funcOrThenable or the inner thenable synchronously throws.
+flags: [async]
+includes: [asyncHelpers.js]
+---*/
+
+async function checkRejects(funcOrThenable) {
+  var caught = false;
+  const p = assert.throwsAsync(Test262Error, funcOrThenable);
+  assert(p instanceof Promise, "assert.throwsAsync should return a promise");
+  try {
+    await p;
+  } catch (e) {
+    caught = true;
+    assert.sameValue(
+      e.constructor,
+      Test262Error,
+      "throwsAsync should reject improper funcOrThenable with a Test262Error"
+    );
+  } finally {
+    assert(
+      caught,
+      "assert.throwsAsync did not reject improper funcOrThenable " +
+        funcOrThenable
+    );
+  }
+}
+
+(async function () {
+  await checkRejects(function () {
+    throw new Error();
+  });
+  await checkRejects(function () {
+    throw new Test262Error();
+  });
+  await checkRejects({
+    then: function () {
+      throw new Error();
+    },
+  });
+  await checkRejects({
+    then: function () {
+      throw new Test262Error();
+    },
+  });
+  await checkRejects(function () {
+    return {
+      then: function () {
+        throw new Error();
+      },
+    };
+  });
+  await checkRejects(function () {
+    return {
+      then: function () {
+        throw new Test262Error();
+      },
+    };
+  });
+})().then($DONE, $DONE);
diff --git a/test/harness/asyncHelpers-throwsAsync-incorrect-ctor.js b/test/harness/asyncHelpers-throwsAsync-incorrect-ctor.js
new file mode 100644
index 0000000000..7ed83e3da6
--- /dev/null
+++ b/test/harness/asyncHelpers-throwsAsync-incorrect-ctor.js
@@ -0,0 +1,33 @@
+// Copyright (C) 2022 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+/*---
+description: |
+    Thenables that reject with values whose constructor does not match the specified
+    constructor do not satisfy the assertion.
+flags: [async]
+includes: [asyncHelpers.js]
+---*/
+
+(async function () {
+  var caught = false;
+
+  const p = assert.throwsAsync(Error, Promise.reject(new TypeError()));
+  assert(p instanceof Promise);
+  try {
+    await p;
+  } catch (err) {
+    caught = true;
+    assert.sameValue(
+      err.constructor,
+      Test262Error,
+      "Expected a Test262Error, but a '" +
+        err.constructor.name +
+        "' was thrown."
+    );
+  } finally {
+    assert(
+      caught,
+      "assert.throwsAsync did not reject when a value with incorrect constructor was thrown"
+    );
+  }
+})().then($DONE, $DONE);
diff --git a/test/harness/asyncHelpers-throwsAsync-invalid-funcOrThenable.js b/test/harness/asyncHelpers-throwsAsync-invalid-funcOrThenable.js
new file mode 100644
index 0000000000..6b5156807c
--- /dev/null
+++ b/test/harness/asyncHelpers-throwsAsync-invalid-funcOrThenable.js
@@ -0,0 +1,71 @@
+// Copyright (C) 2022 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+/*---
+description: |
+    assert.throwsAsync returns a promise that rejects if funcOrThenable is not a function returning a thenable or a thenable.
+flags: [async]
+includes: [asyncHelpers.js]
+---*/
+
+async function checkRejects(funcOrThenable) {
+  var caught = false;
+  const p = assert.throwsAsync(Test262Error, funcOrThenable);
+  assert(p instanceof Promise, "assert.throwsAsync should return a promise");
+  try {
+    await p;
+  } catch (e) {
+    caught = true;
+    assert.sameValue(
+      e.constructor,
+      Test262Error,
+      "throwsAsync should reject improper funcOrThenable with a Test262Error"
+    );
+  } finally {
+    assert(
+      caught,
+      "assert.throwsAsync did not reject improper funcOrThenable " +
+        funcOrThenable
+    );
+  }
+}
+
+(async function () {
+  await checkRejects(null);
+  await checkRejects({});
+  await checkRejects("string");
+  await checkRejects(10);
+  await checkRejects();
+  await checkRejects({ then: null });
+  await checkRejects({ then: {} });
+  await checkRejects({ then: "string" });
+  await checkRejects({ then: 10 });
+  await checkRejects({ then: undefined });
+  await checkRejects(function () {
+    return null;
+  });
+  await checkRejects(function () {
+    return {};
+  });
+  await checkRejects(function () {
+    return "string";
+  });
+  await checkRejects(function () {
+    return 10;
+  });
+  await checkRejects(function () {});
+  await checkRejects(function () {
+    return { then: null };
+  });
+  await checkRejects(function () {
+    return { then: {} };
+  });
+  await checkRejects(function () {
+    return { then: "string" };
+  });
+  await checkRejects(function () {
+    return { then: 10 };
+  });
+  await checkRejects(function () {
+    return { then: undefined };
+  });
+})().then($DONE, $DONE);
diff --git a/test/harness/asyncHelpers-throwsAsync-native.js b/test/harness/asyncHelpers-throwsAsync-native.js
new file mode 100644
index 0000000000..08e416a18c
--- /dev/null
+++ b/test/harness/asyncHelpers-throwsAsync-native.js
@@ -0,0 +1,47 @@
+// Copyright (C) 2022 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+/*---
+description: |
+    Thenables that reject with instances of the specified native Error constructor
+    satisfy the assertion.
+flags: [async]
+includes: [asyncHelpers.js]
+---*/
+
+(async function () {
+  var p = assert.throwsAsync(Error, async function () {
+    throw new Error();
+  });
+  assert(p instanceof Promise);
+  await p;
+  p = assert.throwsAsync(EvalError, async function () {
+    throw new EvalError();
+  });
+  assert(p instanceof Promise);
+  await p;
+  p = assert.throwsAsync(RangeError, async function () {
+    throw new RangeError();
+  });
+  assert(p instanceof Promise);
+  await p;
+  p = assert.throwsAsync(ReferenceError, async function () {
+    throw new ReferenceError();
+  });
+  assert(p instanceof Promise);
+  await p;
+  p = assert.throwsAsync(SyntaxError, async function () {
+    throw new SyntaxError();
+  });
+  assert(p instanceof Promise);
+  await p;
+  p = assert.throwsAsync(TypeError, async function () {
+    throw new TypeError();
+  });
+  assert(p instanceof Promise);
+  await p;
+  p = assert.throwsAsync(URIError, async function () {
+    throw new URIError();
+  });
+  assert(p instanceof Promise);
+  await p;
+})().then($DONE, $DONE);
diff --git a/test/harness/asyncHelpers-throwsAsync-no-arg.js b/test/harness/asyncHelpers-throwsAsync-no-arg.js
new file mode 100644
index 0000000000..b51b94345d
--- /dev/null
+++ b/test/harness/asyncHelpers-throwsAsync-no-arg.js
@@ -0,0 +1,32 @@
+// Copyright (C) 2022 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+/*---
+description: |
+    The assertion fails when invoked without arguments.
+flags: [async]
+includes: [asyncHelpers.js]
+---*/
+
+(async function () {
+  var caught = false;
+
+  const p = assert.throwsAsync();
+  assert(p instanceof Promise);
+  try {
+    await p;
+  } catch (err) {
+    caught = true;
+    assert.sameValue(
+      err.constructor,
+      Test262Error,
+      "Expected a Test262Error, but a '" +
+        err.constructor.name +
+        "' was thrown."
+    );
+  } finally {
+    assert(
+      caught,
+      "assert.throwsAsync did not reject when invoked without arguments"
+    );
+  }
+})().then($DONE, $DONE);
diff --git a/test/harness/asyncHelpers-throwsAsync-no-error.js b/test/harness/asyncHelpers-throwsAsync-no-error.js
new file mode 100644
index 0000000000..97f9f3f3c1
--- /dev/null
+++ b/test/harness/asyncHelpers-throwsAsync-no-error.js
@@ -0,0 +1,32 @@
+// Copyright (C) 2022 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+/*---
+description: |
+    Thenables that do not reject do not satisfy the assertion.
+flags: [async]
+includes: [asyncHelpers.js]
+---*/
+
+(async function () {
+  var caught = false;
+
+  const p = assert.throwsAsync(Error, async function () {});
+  assert(p instanceof Promise);
+  try {
+    await p;
+  } catch (err) {
+    caught = true;
+    assert.sameValue(
+      err.constructor,
+      Test262Error,
+      "Expected a Test262Error, but a '" +
+        err.constructor.name +
+        "' was thrown."
+    );
+  } finally {
+    assert(
+      caught,
+      "assert.throwsAsync did not reject when the thenable did not reject"
+    );
+  }
+})().then($DONE, $DONE);
diff --git a/test/harness/asyncHelpers-throwsAsync-null.js b/test/harness/asyncHelpers-throwsAsync-null.js
new file mode 100644
index 0000000000..3ab1d36d51
--- /dev/null
+++ b/test/harness/asyncHelpers-throwsAsync-null.js
@@ -0,0 +1,34 @@
+// Copyright (C) 2022 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+/*---
+description: |
+    Thenables that reject with the `null` value do not satisfy the assertion.
+flags: [async]
+includes: [asyncHelpers.js]
+---*/
+
+(async function () {
+  var caught = false;
+
+  const p = assert.throwsAsync(Error, async function () {
+    throw null;
+  });
+  assert(p instanceof Promise);
+  try {
+    await p;
+  } catch (err) {
+    caught = true;
+    assert.sameValue(
+      err.constructor,
+      Test262Error,
+      "Expected a Test262Error, but a '" +
+        err.constructor.name +
+        "' was thrown."
+    );
+  } finally {
+    assert(
+      caught,
+      "assert.throwsAsync did not reject when null was thrown"
+    );
+  }
+})().then($DONE, $DONE);
diff --git a/test/harness/asyncHelpers-throwsAsync-primitive.js b/test/harness/asyncHelpers-throwsAsync-primitive.js
new file mode 100644
index 0000000000..a54004e2fb
--- /dev/null
+++ b/test/harness/asyncHelpers-throwsAsync-primitive.js
@@ -0,0 +1,34 @@
+// Copyright (C) 2022 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+/*---
+description: |
+    Thenables that reject with primitive values do not satisfy the assertion.
+flags: [async]
+includes: [asyncHelpers.js]
+---*/
+
+(async function () {
+  var caught = false;
+
+  const p = assert.throwsAsync(Error, async function () {
+    throw 3;
+  });
+  assert(p instanceof Promise);
+  try {
+    await p;
+  } catch (err) {
+    caught = true;
+    assert.sameValue(
+      err.constructor,
+      Test262Error,
+      "Expected a Test262Error, but a '" +
+        err.constructor.name +
+        "' was thrown."
+    );
+  } finally {
+    assert(
+      caught,
+      "assert.throwsAsync did not reject when a primitive was thrown"
+    );
+  }
+})().then($DONE, $DONE);
diff --git a/test/harness/asyncHelpers-throwsAsync-resolved-error.js b/test/harness/asyncHelpers-throwsAsync-resolved-error.js
new file mode 100644
index 0000000000..94d8a3b065
--- /dev/null
+++ b/test/harness/asyncHelpers-throwsAsync-resolved-error.js
@@ -0,0 +1,35 @@
+// Copyright (C) 2022 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+/*---
+description: |
+    Thenables that resolve with an error do not satisfy the assertion.
+flags: [async]
+includes: [asyncHelpers.js]
+---*/
+
+(async function () {
+  var caught = false;
+
+  const p = assert.throwsAsync(
+    Error,
+    Promise.resolve(new Error("it's-a-me, Chris Pratt"))
+  );
+  assert(p instanceof Promise);
+  try {
+    await p;
+  } catch (err) {
+    caught = true;
+    assert.sameValue(
+      err.constructor,
+      Test262Error,
+      "Expected a Test262Error, but a '" +
+        err.constructor.name +
+        "' was thrown."
+    );
+  } finally {
+    assert(
+      caught,
+      "assert.throwsAsync did not reject when the thenable resolved with an error"
+    );
+  }
+})().then($DONE, $DONE);
diff --git a/test/harness/asyncHelpers-throwsAsync-same-realm.js b/test/harness/asyncHelpers-throwsAsync-same-realm.js
new file mode 100644
index 0000000000..aa5ce1743e
--- /dev/null
+++ b/test/harness/asyncHelpers-throwsAsync-same-realm.js
@@ -0,0 +1,37 @@
+// Copyright (C) 2022 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+/*---
+description: |
+    Thenables that reject with instances of the realm specified constructor function
+    satisfy the assertion, without cross realms collisions.
+flags: [async]
+includes: [asyncHelpers.js]
+---*/
+
+(async function () {
+  var intrinsicTypeError = TypeError;
+  var caught = false;
+  var realmGlobal = $262.createRealm().global;
+
+  const p = assert.throwsAsync(TypeError, async function () {
+    throw new realmGlobal.TypeError();
+  });
+  assert(p instanceof Promise);
+  try {
+    await p;
+  } catch (err) {
+    caught = true;
+    assert.sameValue(
+      err.constructor,
+      Test262Error,
+      "Expected a Test262Error, but a '" +
+        err.constructor.name +
+        "' was thrown."
+    );
+  } finally {
+    assert(
+      caught,
+      "assert.throwsAsync did not reject when a different realm's error was thrown"
+    );
+  }
+})().then($DONE, $DONE);
diff --git a/test/harness/asyncHelpers-throwsAsync-single-arg.js b/test/harness/asyncHelpers-throwsAsync-single-arg.js
new file mode 100644
index 0000000000..196558c5a1
--- /dev/null
+++ b/test/harness/asyncHelpers-throwsAsync-single-arg.js
@@ -0,0 +1,31 @@
+// Copyright (C) 2022 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+/*---
+description: |
+    assert.throwsAsync returns a promise that rejects when invoked with a single argument
+flags: [async]
+includes: [asyncHelpers.js]
+---*/
+
+(async function () {
+  var caught = false;
+  const p = assert.throwsAsync(function () {});
+  assert(p instanceof Promise);
+  try {
+    await p;
+  } catch (err) {
+    caught = true;
+    assert.sameValue(
+      err.constructor,
+      Test262Error,
+      "Expected a Test262Error, but a '" +
+        err.constructor.name +
+        "' was thrown."
+    );
+  } finally {
+    assert(
+      caught,
+      "assert.throwsAsync did not reject when invoked with a single argumemnt"
+    );
+  }
+})().then($DONE, $DONE);