Home | History | Annotate | Download | only in harmony
      1 // Copyright 2016 the V8 project authors. All rights reserved.
      2 // Use of this source code is governed by a BSD-style license that can be
      3 // found in the LICENSE file.
      4 
      5 // Flags: --harmony-async-await --allow-natives-syntax
      6 
      7 // Do not install `AsyncFunction` constructor on global object
      8 
      9 function assertThrowsAsync(run, errorType, message) {
     10   var actual;
     11   var hadValue = false;
     12   var hadError = false;
     13   var promise = run();
     14 
     15   if (typeof promise !== "object" || typeof promise.then !== "function") {
     16     throw new MjsUnitAssertionError(
     17         "Expected " + run.toString() +
     18         " to return a Promise, but it returned " + PrettyPrint(promise));
     19   }
     20 
     21   promise.then(function(value) { hadValue = true; actual = value; },
     22                function(error) { hadError = true; actual = error; });
     23 
     24   assertFalse(hadValue || hadError);
     25 
     26   %RunMicrotasks();
     27 
     28   if (!hadError) {
     29     throw new MjsUnitAssertionError(
     30         "Expected " + run + "() to throw " + errorType.name +
     31         ", but did not throw.");
     32   }
     33   if (!(actual instanceof errorType))
     34     throw new MjsUnitAssertionError(
     35         "Expected " + run + "() to throw " + errorType.name +
     36         ", but threw '" + actual + "'");
     37   if (message !== void 0 && actual.message !== message)
     38     throw new MjsUnitAssertionError(
     39         "Expected " + run + "() to throw '" + message + "', but threw '" +
     40         actual.message + "'");
     41 };
     42 
     43 function assertEqualsAsync(expected, run, msg) {
     44   var actual;
     45   var hadValue = false;
     46   var hadError = false;
     47   var promise = run();
     48 
     49   if (typeof promise !== "object" || typeof promise.then !== "function") {
     50     throw new MjsUnitAssertionError(
     51         "Expected " + run.toString() +
     52         " to return a Promise, but it returned " + PrettyPrint(promise));
     53   }
     54 
     55   promise.then(function(value) { hadValue = true; actual = value; },
     56                function(error) { hadError = true; actual = error; });
     57 
     58   assertFalse(hadValue || hadError);
     59 
     60   %RunMicrotasks();
     61 
     62   if (hadError) throw actual;
     63 
     64   assertTrue(
     65       hadValue, "Expected '" + run.toString() + "' to produce a value");
     66 
     67   assertEquals(expected, actual, msg);
     68 };
     69 
     70 assertEquals(undefined, this.AsyncFunction);
     71 let AsyncFunction = (async function() {}).constructor;
     72 
     73 // Let functionPrototype be the intrinsic object %AsyncFunctionPrototype%.
     74 async function asyncFunctionForProto() {}
     75 assertEquals(AsyncFunction.prototype,
     76              Object.getPrototypeOf(asyncFunctionForProto));
     77 assertEquals(AsyncFunction.prototype,
     78              Object.getPrototypeOf(async function() {}));
     79 assertEquals(AsyncFunction.prototype, Object.getPrototypeOf(async () => {}));
     80 assertEquals(AsyncFunction.prototype,
     81              Object.getPrototypeOf({ async method() {} }.method));
     82 assertEquals(AsyncFunction.prototype, Object.getPrototypeOf(AsyncFunction()));
     83 assertEquals(AsyncFunction.prototype,
     84              Object.getPrototypeOf(new AsyncFunction()));
     85 
     86 // AsyncFunctionCreate does not produce an object with a Prototype
     87 assertEquals(undefined, asyncFunctionForProto.prototype);
     88 assertEquals(false, asyncFunctionForProto.hasOwnProperty("prototype"));
     89 assertEquals(undefined, (async function() {}).prototype);
     90 assertEquals(false, (async function() {}).hasOwnProperty("prototype"));
     91 assertEquals(undefined, (async() => {}).prototype);
     92 assertEquals(false, (async() => {}).hasOwnProperty("prototype"));
     93 assertEquals(undefined, ({ async method() {} }).method.prototype);
     94 assertEquals(false, ({ async method() {} }).method.hasOwnProperty("prototype"));
     95 assertEquals(undefined, AsyncFunction().prototype);
     96 assertEquals(false, AsyncFunction().hasOwnProperty("prototype"));
     97 assertEquals(undefined, (new AsyncFunction()).prototype);
     98 assertEquals(false, (new AsyncFunction()).hasOwnProperty("prototype"));
     99 
    100 assertEquals(1, async function(a) { await 1; }.length);
    101 assertEquals(2, async function(a, b) { await 1; }.length);
    102 assertEquals(1, async function(a, b = 2) { await 1; }.length);
    103 assertEquals(2, async function(a, b, ...c) { await 1; }.length);
    104 
    105 assertEquals(1, (async(a) => await 1).length);
    106 assertEquals(2, (async(a, b) => await 1).length);
    107 assertEquals(1, (async(a, b = 2) => await 1).length);
    108 assertEquals(2, (async(a, b, ...c) => await 1).length);
    109 
    110 assertEquals(1, ({ async f(a) { await 1; } }).f.length);
    111 assertEquals(2, ({ async f(a, b) { await 1; } }).f.length);
    112 assertEquals(1, ({ async f(a, b = 2) { await 1; } }).f.length);
    113 assertEquals(2, ({ async f(a, b, ...c) { await 1; } }).f.length);
    114 
    115 assertEquals(1, AsyncFunction("a", "await 1").length);
    116 assertEquals(2, AsyncFunction("a", "b", "await 1").length);
    117 assertEquals(1, AsyncFunction("a", "b = 2", "await 1").length);
    118 assertEquals(2, AsyncFunction("a", "b", "...c", "await 1").length);
    119 
    120 assertEquals(1, (new AsyncFunction("a", "await 1")).length);
    121 assertEquals(2, (new AsyncFunction("a", "b", "await 1")).length);
    122 assertEquals(1, (new AsyncFunction("a", "b = 2", "await 1")).length);
    123 assertEquals(2, (new AsyncFunction("a", "b", "...c", "await 1")).length);
    124 
    125 // AsyncFunction.prototype[ @@toStringTag ]
    126 var descriptor =
    127     Object.getOwnPropertyDescriptor(AsyncFunction.prototype,
    128                                     Symbol.toStringTag);
    129 assertEquals("AsyncFunction", descriptor.value);
    130 assertEquals(false, descriptor.enumerable);
    131 assertEquals(false, descriptor.writable);
    132 assertEquals(true, descriptor.configurable);
    133 
    134 assertEquals(1, AsyncFunction.length);
    135 
    136 // Let F be ! FunctionAllocate(functionPrototype, Strict, "non-constructor")
    137 async function asyncNonConstructorDecl() {}
    138 assertThrows(
    139     () => new asyncNonConstructorDecl(), TypeError);
    140 assertThrows(
    141     () => new (async function() {}), TypeError);
    142 assertThrows(
    143     () => new ({ async nonConstructor() {} }).nonConstructor(), TypeError);
    144 assertThrows(
    145     () => new (() => "not a constructor!"), TypeError);
    146 assertThrows(
    147     () => new (AsyncFunction()), TypeError);
    148 assertThrows(
    149     () => new (new AsyncFunction()), TypeError);
    150 
    151 // Normal completion
    152 async function asyncDecl() { return "test"; }
    153 assertEqualsAsync("test", asyncDecl);
    154 assertEqualsAsync("test2", async function() { return "test2"; });
    155 assertEqualsAsync("test3", async () => "test3");
    156 assertEqualsAsync("test4", () => ({ async f() { return "test4"; } }).f());
    157 assertEqualsAsync("test5", () => AsyncFunction("no", "return 'test' + no;")(5));
    158 assertEqualsAsync("test6",
    159                   () => (new AsyncFunction("no", "return 'test' + no;"))(6));
    160 
    161 class MyError extends Error {};
    162 
    163 // Throw completion
    164 async function asyncDeclThrower(e) { throw new MyError(e); }
    165 assertThrowsAsync(() => asyncDeclThrower("boom!"), MyError, "boom!");
    166 assertThrowsAsync(
    167   () => (async function(e) { throw new MyError(e); })("boom!!!"),
    168   MyError, "boom!!!");
    169 assertThrowsAsync(
    170   () => (async e => { throw new MyError(e) })("boom!!"), MyError, "boom!!");
    171 assertThrowsAsync(
    172   () => ({ async thrower(e) { throw new MyError(e); } }).thrower("boom!1!"),
    173   MyError, "boom!1!");
    174 assertThrowsAsync(
    175   () => AsyncFunction("msg", "throw new MyError(msg)")("boom!2!!"),
    176   MyError, "boom!2!!");
    177 assertThrowsAsync(
    178   () => (new AsyncFunction("msg", "throw new MyError(msg)"))("boom!2!!!"),
    179   MyError, "boom!2!!!");
    180 
    181 function resolveLater(value) { return Promise.resolve(value); }
    182 function rejectLater(error) { return Promise.reject(error); }
    183 
    184 // Resume after Normal completion
    185 var log = [];
    186 async function resumeAfterNormal(value) {
    187   log.push("start:" + value);
    188   value = await resolveLater(value + 1);
    189   log.push("resume:" + value);
    190   value = await resolveLater(value + 1);
    191   log.push("resume:" + value);
    192   return value + 1;
    193 }
    194 
    195 assertEqualsAsync(4, () => resumeAfterNormal(1));
    196 assertEquals("start:1 resume:2 resume:3", log.join(" "));
    197 
    198 var O = {
    199   async resumeAfterNormal(value) {
    200     log.push("start:" + value);
    201     value = await resolveLater(value + 1);
    202     log.push("resume:" + value);
    203     value = await resolveLater(value + 1);
    204     log.push("resume:" + value);
    205     return value + 1;
    206   }
    207 };
    208 log = [];
    209 assertEqualsAsync(5, () => O.resumeAfterNormal(2));
    210 assertEquals("start:2 resume:3 resume:4", log.join(" "));
    211 
    212 var resumeAfterNormalArrow = async (value) => {
    213   log.push("start:" + value);
    214   value = await resolveLater(value + 1);
    215   log.push("resume:" + value);
    216   value = await resolveLater(value + 1);
    217   log.push("resume:" + value);
    218   return value + 1;
    219 };
    220 log = [];
    221 assertEqualsAsync(6, () => resumeAfterNormalArrow(3));
    222 assertEquals("start:3 resume:4 resume:5", log.join(" "));
    223 
    224 var resumeAfterNormalEval = AsyncFunction("value", `
    225     log.push("start:" + value);
    226     value = await resolveLater(value + 1);
    227     log.push("resume:" + value);
    228     value = await resolveLater(value + 1);
    229     log.push("resume:" + value);
    230     return value + 1;`);
    231 log = [];
    232 assertEqualsAsync(7, () => resumeAfterNormalEval(4));
    233 assertEquals("start:4 resume:5 resume:6", log.join(" "));
    234 
    235 var resumeAfterNormalNewEval = new AsyncFunction("value", `
    236     log.push("start:" + value);
    237     value = await resolveLater(value + 1);
    238     log.push("resume:" + value);
    239     value = await resolveLater(value + 1);
    240     log.push("resume:" + value);
    241     return value + 1;`);
    242 log = [];
    243 assertEqualsAsync(8, () => resumeAfterNormalNewEval(5));
    244 assertEquals("start:5 resume:6 resume:7", log.join(" "));
    245 
    246 // Resume after Throw completion
    247 async function resumeAfterThrow(value) {
    248   log.push("start:" + value);
    249   try {
    250     value = await rejectLater("throw1");
    251   } catch (e) {
    252     log.push("resume:" + e);
    253   }
    254   try {
    255     value = await rejectLater("throw2");
    256   } catch (e) {
    257     log.push("resume:" + e);
    258   }
    259   return value + 1;
    260 }
    261 
    262 log = [];
    263 assertEqualsAsync(2, () => resumeAfterThrow(1));
    264 assertEquals("start:1 resume:throw1 resume:throw2", log.join(" "));
    265 
    266 var O = {
    267   async resumeAfterThrow(value) {
    268     log.push("start:" + value);
    269     try {
    270       value = await rejectLater("throw1");
    271     } catch (e) {
    272       log.push("resume:" + e);
    273     }
    274     try {
    275       value = await rejectLater("throw2");
    276     } catch (e) {
    277       log.push("resume:" + e);
    278     }
    279     return value + 1;
    280   }
    281 }
    282 log = [];
    283 assertEqualsAsync(3, () => O.resumeAfterThrow(2));
    284 assertEquals("start:2 resume:throw1 resume:throw2", log.join(" "));
    285 
    286 var resumeAfterThrowArrow = async (value) => {
    287   log.push("start:" + value);
    288   try {
    289     value = await rejectLater("throw1");
    290   } catch (e) {
    291     log.push("resume:" + e);
    292   }
    293   try {
    294     value = await rejectLater("throw2");
    295   } catch (e) {
    296     log.push("resume:" + e);
    297   }
    298  return value + 1;
    299 };
    300 
    301 log = [];
    302 
    303 assertEqualsAsync(4, () => resumeAfterThrowArrow(3));
    304 assertEquals("start:3 resume:throw1 resume:throw2", log.join(" "));
    305 
    306 var resumeAfterThrowEval = AsyncFunction("value", `
    307     log.push("start:" + value);
    308     try {
    309       value = await rejectLater("throw1");
    310     } catch (e) {
    311       log.push("resume:" + e);
    312     }
    313     try {
    314       value = await rejectLater("throw2");
    315     } catch (e) {
    316       log.push("resume:" + e);
    317     }
    318     return value + 1;`);
    319 log = [];
    320 assertEqualsAsync(5, () => resumeAfterThrowEval(4));
    321 assertEquals("start:4 resume:throw1 resume:throw2", log.join(" "));
    322 
    323 var resumeAfterThrowNewEval = new AsyncFunction("value", `
    324     log.push("start:" + value);
    325     try {
    326       value = await rejectLater("throw1");
    327     } catch (e) {
    328       log.push("resume:" + e);
    329     }
    330     try {
    331       value = await rejectLater("throw2");
    332     } catch (e) {
    333       log.push("resume:" + e);
    334     }
    335     return value + 1;`);
    336 log = [];
    337 assertEqualsAsync(6, () => resumeAfterThrowNewEval(5));
    338 assertEquals("start:5 resume:throw1 resume:throw2", log.join(" "));
    339 
    340 async function foo() {}
    341 assertEquals("async function foo() {}", foo.toString());
    342 assertEquals("async function () {}", async function() {}.toString());
    343 assertEquals("async x => x", (async x => x).toString());
    344 assertEquals("async x => { return x }", (async x => { return x }).toString());
    345 class AsyncMethod { async foo() { } }
    346 assertEquals("async foo() { }",
    347              Function.prototype.toString.call(AsyncMethod.prototype.foo));
    348 assertEquals("async foo() { }",
    349              Function.prototype.toString.call({async foo() { }}.foo));
    350 
    351 // Async functions are not constructible
    352 assertThrows(() => class extends (async function() {}) {}, TypeError);
    353 
    354 // Regress v8:5148
    355 assertEqualsAsync("1", () => (async({ a = NaN }) => a)({ a: "1" }));
    356 assertEqualsAsync(
    357     "10", () => (async(foo, { a = NaN }) => foo + a)("1", { a: "0" }));
    358 assertEqualsAsync("2", () => (async({ a = "2" }) => a)({ a: undefined }));
    359 assertEqualsAsync(
    360     "20", () => (async(foo, { a = "0" }) => foo + a)("2", { a: undefined }));
    361 assertThrows(() => eval("async({ foo = 1 })"), SyntaxError);
    362 assertThrows(() => eval("async(a, { foo = 1 })"), SyntaxError);
    363 
    364 // https://bugs.chromium.org/p/chromium/issues/detail?id=638019
    365 async function gaga() {
    366   let i = 1;
    367   while (i-- > 0) { await 42 }
    368 }
    369 assertDoesNotThrow(gaga);
    370