Chromium Code Reviews| Index: tests/language/async_await_test.dart |
| diff --git a/tests/language/async_await_test.dart b/tests/language/async_await_test.dart |
| new file mode 100644 |
| index 0000000000000000000000000000000000000000..e8f30cd86160141f989eb1e5ea336e1a8a8e860a |
| --- /dev/null |
| +++ b/tests/language/async_await_test.dart |
| @@ -0,0 +1,1918 @@ |
| +// Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file |
| +// for details. All rights reserved. Use of this source code is governed by a |
| +// BSD-style license that can be found in the LICENSE file. |
| + |
| +library async_await_test; |
| + |
| +import "package:unittest/unittest.dart"; |
| +import "dart:async"; |
| + |
| +main() { |
| + group("basic", () { |
| + test("async w/o await", () { |
| + f() async { return id(42); } |
| + return expect42(f()); |
| + }); |
| + |
| + test("async waits", () { |
| + // Calling an "async" function won't do anything immediately. |
| + var result = []; |
| + f() async { |
| + result.add(1); |
| + return id(42); |
| + }; |
| + var future = f(); |
| + result.add(0); |
| + return future.whenComplete(() { |
| + expect(result, equals([0, 1])); |
| + }); |
| + }); |
| + |
| + test("async throws", () { |
| + f() async { |
| + throw "err"; |
| + return id(42); |
| + } |
| + return throwsErr(f()); |
| + }); |
| + |
| + test("await future", () { |
| + f() async { |
| + var v = await new Future.value(42); |
| + return v; |
| + }; |
| + return expect42(f()); |
| + }); |
| + |
| + test("await value", () { |
| + f() async { |
| + var v = await id(42); |
| + return v; |
| + }; |
| + return expect42(f()); |
| + }); |
| + |
| + test("await null", () { |
| + f() async { |
| + var v = await null; |
| + expect(v, equals(null)); |
| + }; |
| + return f(); |
| + }); |
| + |
| + test("await await", () { |
| + f() async { |
| + return await await new Future.value(42); |
| + } |
| + return expect42(f()); |
| + }); |
| + |
| + test("await fake value future", () { |
| + f() async { |
| + return await new FakeValueFuture(42); |
| + } |
| + return expect42(f()); |
| + }); |
| + |
| + test("await fake error future", () { |
| + f() async { |
| + return await new FakeErrorFuture("err"); |
| + } |
| + return throwsErr(f()); |
| + }); |
| + |
| + test("await value is delayed", () { |
| + f() async { |
| + bool x = false; |
| + scheduleMicrotask(() { x = true; }); |
| + var y = await true; |
| + expect(x, equals(y)); |
| + } |
| + return f(); |
| + }); |
| + |
| + test("await throw", () { |
| + f() async { |
| + await (throw "err"); // Check grammar: Are parentheses necessary? |
| + return id(42); |
| + } |
| + return throwsErr(f()); |
| + }); |
| + |
| + test("throw before await", () { |
| + f() async { |
| + var x = throw "err"; |
| + await x; // Check grammar: Are parentheses necessary? |
| + return id(42); |
| + } |
| + return throwsErr(f()); |
| + }); |
| + |
| + test("async await error", () { |
| + f() async { |
| + await new Future.error("err"); |
| + return id(42); |
| + } |
| + return throwsErr(f()); |
| + }); |
| + |
| + test("async flattens futures", () { |
| + f() async { |
| + return new Future.value(42); // Not awaited. |
| + }; |
| + return f().then((v) { |
| + expect(v, equals(42)); // And not a Future with value 42. |
| + }); |
| + }); |
| + |
| + test("async flattens futures, error", () { |
| + f() async { |
| + return new Future.error("err"); // Not awaited. |
| + }; |
| + return throwsErr(f()); |
| + }); |
| + |
| + test("await for", () { |
| + f(s) async { |
| + int i = 0; |
| + await for (int v in s) { |
| + i += v; |
| + } |
| + return i; |
| + } |
| + return f(mkStream()).then((v) { |
| + expect(v, equals(45)); // 0 + 1 + ... + 9 |
| + }); |
| + }); |
| + |
| + test("await for w/ await", () { |
| + f(s) async { |
| + int i = 0; |
| + await for (int v in s) { |
| + i += await new Future.value(v); |
| + } |
| + return i; |
| + } |
| + return f(mkStream()).then((v) { |
| + expect(v, equals(45)); // 0 + 1 + ... + 9 |
| + }); |
| + }); |
| + |
| + test("await for empty", () { |
| + f(s) async { |
| + int v = 0; |
| + await for (int i in s) { |
| + v += i; |
| + } |
| + return v; |
| + } |
| + var s = (new StreamController()..close()).stream; |
| + return f(s).then((v) { |
| + expect(v, equals(0)); |
| + }); |
| + }); |
| + }); |
| + |
| + group("for", () { |
| + test("await in for-loop", () { |
| + f() async { |
| + int v = 0; |
| + for (int i = 0; i < 10; i++) { |
| + v += await new Future.value(42); |
| + } |
| + return v; |
| + } |
| + return f().then((v) { |
| + expect(v, equals(10 * id(42))); |
| + }); |
| + }); |
| + |
| + test("await in for-init", () { |
| + f() async { |
| + int v = 0; |
| + for (int i = await new Future.value(42); i >= 0; i -= 10) { |
| + v += 10; |
| + } |
| + return v; |
| + } |
| + return f().then((v) { |
| + expect(v, equals(10 * 5)); |
| + }); |
| + }); |
| + |
| + test("await in for-test", () { |
| + f() async { |
| + int v = 0; |
| + for (int i = 0; i < await new Future.value(42); i += 10) { |
| + v += 10; |
| + } |
| + return v; |
| + } |
| + return f().then((v) { |
| + expect(v, equals(10 * 5)); |
| + }); |
| + }); |
| + |
| + test("await in for-incr", () { |
| + f() async { |
| + int v = 0; |
| + for (int i = 0; i < 100; i += await new Future.value(42)) { |
| + v += 10; |
| + } |
| + return v; |
| + } |
| + return f().then((v) { |
| + expect(v, equals(10 * 3)); |
| + }); |
| + }); |
| + |
| + test("await err in for-loop", () { |
| + f() async { |
| + int v = 0; |
| + for (int i = 0; i < 10; i++) { |
| + v += await new Future.error("err"); |
| + } |
| + return v; |
| + } |
| + return throwsErr(f()); |
| + }); |
| + |
| + test("await err in for-init", () { |
| + f() async { |
| + int v = 0; |
| + for (int i = await new Future.error("err"); i >= 0; i -= 10) { |
| + v += 10; |
| + } |
| + return v; |
| + } |
| + return throwsErr(f()); |
| + }); |
| + |
| + test("await err in for-test", () { |
| + f() async { |
| + int v = 0; |
| + for (int i = 0; i < await new Future.error("err"); i += 10) { |
| + v += 10; |
| + } |
| + return v; |
| + } |
| + return throwsErr(f()); |
| + }); |
| + |
| + test("await err in for-incr", () { |
| + f() async { |
| + int v = 0; |
| + for (int i = 0; i < 100; i += await new Future.error("err")) { |
| + v += 10; |
| + } |
| + return v; |
| + } |
| + return throwsErr(f()); |
| + }); |
| + |
| + test("await in empty for-loop", () { |
| + f() async { |
| + int v = 0; |
| + for (int i = 0; i > 0; i += 1) { |
| + v += await new Future.value(42); |
| + } |
| + return v; |
| + } |
| + return f().then((v) { |
| + expect(v, equals(0)); |
| + }); |
| + }); |
| + |
| + test("await in empty for-loop 2", () { |
| + f() async { |
| + int v = 0; |
| + for (int i = 0; i > 0; i += await new Future.value(1)) { |
| + v += 1; |
| + } |
| + return v; |
| + } |
| + return f().then((v) { |
| + expect(v, equals(0)); |
| + }); |
| + }); |
| + |
| + test("break before await in for-loop", () { |
| + f() async { |
| + int v = 0; |
| + for (int i = 0; i < 10; i += 1) { |
| + if (i == 2) break; |
| + v += await new Future.value(42); |
| + } |
| + return v; |
| + } |
| + return f().then((v) { |
| + expect(v, equals(42 * 2)); |
| + }); |
| + }); |
| + |
| + test("break before await in for-loop 2", () { |
| + f() async { |
| + int v = 0; |
| + for (int i = 0; i < 10; i += await new Future.value(1)) { |
| + if (i == 2) break; |
| + v += id(42); |
| + } |
| + return v; |
| + } |
| + return f().then((v) { |
| + expect(v, equals(42 * 2)); |
| + }); |
| + }); |
| + |
| + test("continue before await", () { |
| + f() async { |
| + int v = 0; |
| + for (int i = 0; i < 10; i += 1) { |
| + if (i == 2) continue; |
| + v += await new Future.value(42); |
| + } |
| + return v; |
| + } |
| + return f().then((v) { |
| + expect(v, equals(42 * 9)); |
| + }); |
| + }); |
| + |
| + test("continue after await", () { |
| + f() async { |
| + int v = 0; |
| + for (int i = 0; i < 10; i += 1) { |
| + var j = await new Future.value(42); |
| + if (i == 2) continue; |
| + v += j; |
| + } |
| + return v; |
| + } |
| + return f().then((v) { |
| + expect(v, equals(42 * 9)); |
| + }); |
| + }); |
| + }); |
| + |
| + group("while", () { |
| + test("await in while-loop", () { |
| + f() async { |
| + int v = 0; |
| + int i = 0; |
| + while (i < 10) { |
| + v += await new Future.value(42); |
| + i++; |
| + } |
| + return v; |
| + } |
| + return f().then((v) { |
| + expect(v, equals(10 * id(42))); |
| + }); |
| + }); |
| + |
| + test("await in while-test", () { |
| + f() async { |
| + int v = 0; |
| + int i = 0; |
| + while (i < await new Future.value(42)) { |
| + v += 10; |
| + i += 10; |
| + } |
| + return v; |
| + } |
| + return f().then((v) { |
| + expect(v, equals(10 * 5)); |
| + }); |
| + }); |
| + |
| + test("await err in loop", () { |
| + f() async { |
| + int v = 0; |
| + int i = 0; |
| + while (i < 10) { |
| + v += await new Future.error("err"); |
| + i++; |
| + } |
| + return v; |
| + } |
| + return throwsErr(f()); |
| + }); |
| + |
| + test("await err in test", () { |
| + f() async { |
| + int v = 0; |
| + int i = 0; |
| + while (i < await new Future.error("err")) { |
| + v += 10; |
| + i += 10; |
| + } |
| + return v; |
| + } |
| + return throwsErr(f()); |
| + }); |
| + |
| + test("break before await", () { |
| + f() async { |
| + int v = 0; |
| + int i = 0; |
| + while (i < 10) { |
| + if (i == 2) break; |
| + v += await new Future.value(42); |
| + i += 1; |
| + } |
| + return v; |
| + } |
| + return f().then((v) { |
| + expect(v, equals(42 * 2)); |
| + }); |
| + }); |
| + |
| + test("break after await", () { |
| + f() async { |
| + int v = 0; |
| + int i = 0; |
| + while (i < 10) { |
| + v += await new Future.value(42); |
| + if (i == 2) break; |
| + i += 1; |
| + } |
| + return v; |
| + } |
| + return f().then((v) { |
| + expect(v, equals(42 * 3)); |
| + }); |
| + }); |
| + |
| + test("continue before await", () { |
| + f() async { |
| + int v = 0; |
| + int i = 0; |
| + while (i < 10) { |
| + i += 1; |
| + if (i == 2) continue; |
| + v += await new Future.value(42); |
| + } |
| + return v; |
| + } |
| + return f().then((v) { |
| + expect(v, equals(42 * 9)); |
| + }); |
| + }); |
| + |
| + test("continue after await", () { |
| + f() async { |
| + int v = 0; |
| + int i = 0; |
| + while (i < 10) { |
| + i += 1; |
| + int j = await new Future.value(42); |
| + if (i == 2) continue; |
| + v += j; |
| + } |
| + return v; |
| + } |
| + return f().then((v) { |
| + expect(v, equals(42 * 9)); |
| + }); |
| + }); |
| + }); |
| + |
| + group("do-while", () { |
| + test("await in loop", () { |
| + f() async { |
| + int v = 0; |
| + int i = 0; |
| + do { |
| + v += await new Future.value(42); |
| + i++; |
| + } while (i < 10); |
| + return v; |
| + } |
| + return f().then((v) { |
| + expect(v, equals(10 * id(42))); |
| + }); |
| + }); |
| + |
| + test("await in test", () { |
| + f() async { |
| + int v = 0; |
| + int i = 0; |
| + do { |
| + v += 10; |
| + i += 10; |
| + } while (i < await new Future.value(42)); |
| + return v; |
| + } |
| + return f().then((v) { |
| + expect(v, equals(10 * 5)); |
| + }); |
| + }); |
| + |
| + test("await err in loop", () { |
| + f() async { |
| + int v = 0; |
| + int i = 0; |
| + do { |
| + v += await new Future.error("err"); |
| + i++; |
| + } while (i < 10); |
| + return v; |
| + } |
| + return f().then((v) { fail("didn't throw"); }, |
| + onError: (e) { expect(e, equals("err")); }); |
| + }); |
| + |
| + test("await err in test", () { |
| + f() async { |
| + int v = 0; |
| + int i = 0; |
| + do { |
| + v += 10; |
| + i += 10; |
| + } while (i < await new Future.error("err")); |
| + return v; |
| + } |
| + return f().then((v) { fail("didn't throw"); }, |
| + onError: (e) { expect(e, equals("err")); }); |
| + }); |
| + |
| + test("break before await", () { |
| + f() async { |
| + int v = 0; |
| + int i = 0; |
| + do { |
| + if (i == 2) break; |
| + v += await new Future.value(42); |
| + i += 1; |
| + } while (i < 10); |
| + return v; |
| + } |
| + return f().then((v) { |
| + expect(v, equals(42 * 2)); |
| + }); |
| + }); |
| + |
| + test("break after await", () { |
| + f() async { |
| + int v = 0; |
| + int i = 0; |
| + do { |
| + v += await new Future.value(42); |
| + if (i == 2) break; |
| + i += 1; |
| + } while (i < 10); |
| + return v; |
| + } |
| + return f().then((v) { |
| + expect(v, equals(42 * 3)); |
| + }); |
| + }); |
| + |
| + test("continue before await", () { |
| + f() async { |
| + int v = 0; |
| + int i = 0; |
| + do { |
| + i += 1; |
| + if (i == 2) continue; |
| + v += await new Future.value(42); |
| + } while (i < 10); |
| + return v; |
| + } |
| + return f().then((v) { |
| + expect(v, equals(42 * 9)); |
| + }); |
| + }); |
| + |
| + test("continue after await", () { |
| + f() async { |
| + int v = 0; |
| + int i = 0; |
| + do { |
| + i += 1; |
| + int j = await new Future.value(42); |
| + if (i == 2) continue; |
| + v += j; |
| + } while (i < 10); |
| + return v; |
| + } |
| + return f().then((v) { |
| + expect(v, equals(42 * 9)); |
| + }); |
| + }); |
| + }); |
| + |
| + group("for-in", () { |
| + test("await in for-in", () { |
| + f() async { |
| + var v = 0; |
| + for (var fut in [1, 2, 3].map((v) => new Future.value(v))) { |
| + v += await fut; |
| + } |
| + return v; |
| + } |
| + return f().then((v) { |
| + expect(v, equals(6)); |
| + }); |
| + }); |
| + |
| + test("await in for-in iterable", () { |
| + f() async { |
| + var v = 0; |
| + for (var i in await new Future.value([1, 2, 3])) { |
| + v += i; |
| + } |
| + return v; |
| + } |
| + return f().then((v) { |
| + expect(v, equals(6)); |
| + }); |
| + }); |
| + |
| + test("await err in for-in", () { |
| + f() async { |
| + var v = 0; |
| + for (var fut in [1, 2, 3].map((v) => (v != 1) |
| + ? new Future.value(v) |
| + : new Future.error("err"))) { |
| + v += await fut; |
| + } |
| + return v; |
| + } |
| + return f().then((v) { fail("didn't throw"); }, |
| + onError: (e) { expect(e, equals("err")); }); |
| + }); |
| + |
| + test("await err in for-in iterable", () { |
| + f() async { |
| + var v = 0; |
| + for (var i in await new Future.error("err")) { |
| + v += i; |
| + } |
| + return v; |
| + } |
| + return f().then((v) { fail("didn't throw"); }, |
| + onError: (e) { expect(e, equals("err")); }); |
| + }); |
| + |
| + test("break before await in for-in", () { |
| + f() async { |
| + var v = 0; |
| + for (var fut in [1, 2, 3].map((v) => new Future.value(v))) { |
| + if (v == 3) break; |
| + v += await fut; |
| + } |
| + return v; |
| + } |
| + return f().then((v) { |
| + expect(v, equals(3)); |
| + }); |
| + }); |
| + }); |
| + |
| + group("try-catch", () { |
| + test("try-no-catch", () { |
| + f() async { |
| + try { |
| + return await id(42); |
| + } catch(e) { |
| + return 37; |
| + } |
| + } |
| + return expect42(f()); |
| + }); |
| + |
| + test("await in body", () { |
| + f() async { |
| + try { |
| + await new Future.error(42); |
| + } catch(e) { |
| + return e; |
| + } |
| + } |
| + return expect42(f()); |
| + }); |
| + |
| + test("throw before await in body", () { |
| + int i = id(0); |
| + f() async { |
| + try { |
| + if (i >= 0) throw id(42); |
| + return await new Future.value(10); |
| + } catch(e) { |
| + return e; |
| + } |
| + } |
| + return expect42(f()); |
| + }); |
| + |
| + test("try-catch await in catch", () { |
| + f() async { |
| + try { |
| + throw id(42); |
| + } catch(e) { |
| + return await new Future.value(e); |
| + } |
| + } |
| + return expect42(f()); |
| + }); |
| + |
| + test("try-catch await error in catch", () { |
| + f() async { |
| + try { |
| + throw id(42); |
| + } catch(e) { |
| + await new Future.error("err"); |
| + } |
| + } |
| + return f().then((v) { fail("didn't throw"); }, |
| + onError: (e) { expect(e, equals("err")); }); |
| + }); |
| + |
| + test("try-catch-rethrow", () { |
| + f() async { |
| + try { |
| + await new Future.error("err"); |
| + } catch(e) { |
| + if (e == id(42)) return; |
| + rethrow; |
| + } |
| + } |
| + return f().then((v) { fail("didn't throw"); }, |
| + onError: (e) { expect(e, equals("err")); }); |
| + }); |
| + }); |
| + |
| + group("try-finally", () { |
| + test("await in body", () { |
| + f() async { |
| + try { |
| + return await new Future.value(42); |
| + } finally { |
| + // Don't do anything. |
| + } |
| + } |
| + return expect42(f()); |
| + }); |
| + |
| + test("await in finally", () { |
| + var x = 0; |
| + f() async { |
| + try { |
| + return id(42); |
| + } finally { |
| + x = await new Future.value(37); |
| + } |
| + } |
| + return f().then((v) { |
| + expect(v, equals(42)); |
| + expect(x, equals(37)); |
| + }); |
| + }); |
| + |
| + test("await err in body", () { |
| + f() async { |
| + try { |
| + return await new Future.error("err"); |
| + } finally { |
| + // Don't do anything. |
| + } |
| + } |
| + return f().then((v) { fail("didn't throw"); }, |
| + onError: (e) { expect(e, equals("err")); }); |
| + }); |
| + |
| + test("await err in finally", () { |
| + f() async { |
| + try { |
| + return id(42); |
| + } finally { |
| + await new Future.error("err"); |
| + } |
| + } |
| + return f().then((v) { fail("didn't throw"); }, |
| + onError: (e) { expect(e, equals("err")); }); |
| + }); |
| + |
| + test("await err in both", () { |
| + f() async { |
| + try { |
| + await new Future.error("not err"); |
| + } finally { |
| + await new Future.error("err"); |
| + } |
| + } |
| + return f().then((v) { fail("didn't throw"); }, |
| + onError: (e) { expect(e, equals("err")); }); |
| + }); |
| + |
| + test("await err in body, override in finally", () { |
| + f() async { |
| + try { |
| + return await new Future.error("err"); |
| + } finally { |
| + return id(42); |
| + } |
| + } |
| + return expect42(f()); |
| + }); |
| + |
| + // test("await in body, override in finally", () { |
| + // f() async { |
| + // label: try { |
| + // return await new Future.value(37); |
| + // } finally { |
| + // break label; |
| + // } |
| + // return id(42); |
| + // } |
| + // return expect42(f()); |
| + // }); |
| + |
| + test("await, override in finally", () { |
| + var x = 0; |
| + f() async { |
| + label: try { |
| + return 87; |
| + } finally { |
| + x = await new Future.value(37); |
| + break label; |
| + } |
| + return id(42); |
| + } |
| + return f().then((v) { |
| + expect(v, equals(42)); |
| + expect(x, equals(37)); |
| + }); |
| + }); |
| + |
| + test("throw in body, await, override in finally 3", () { |
| + var x = 0; |
| + f() async { |
| + label: try { |
| + throw "err"; |
| + } finally { |
| + x = await new Future.value(37); |
| + break label; |
| + } |
| + return id(42); |
| + } |
| + return f().then((v) { |
| + expect(v, equals(42)); |
| + expect(x, equals(37)); |
| + }); |
| + }); |
| + |
| + // test("await err in body, override in finally 2", () { |
| + // f() async { |
| + // label: try { |
| + // return await new Future.error("err"); |
| + // } finally { |
| + // break label; |
| + // } |
| + // return id(42); |
| + // } |
| + // return expect42(f()); |
| + // }); |
| + |
| + test("await in body, no-exit in finally", () { |
| + f() async { |
| + for (int i = 0; i < 10; i++) { |
| + try { |
| + return await i; |
| + } finally { |
| + continue; |
| + } |
| + } |
| + return id(42); |
| + } |
| + return expect42(f()); |
| + }); |
| + |
| + test("no-exit after await in finally", () { |
| + f() async { |
| + int i = 0; |
| + for (; i < 10; i++) { |
| + try { |
| + break; |
| + } finally { |
| + await new Future.value(42); |
| + continue; |
| + } |
| + } |
| + return id(i); |
| + } |
| + return f().then((v) { |
| + expect(v, equals(10)); |
| + }); |
| + }); |
| + |
| + test("exit after continue, await in finally", () { |
| + f() async { |
| + int i = 0; |
| + for (; i < 10; i++) { |
| + try { |
| + continue; |
| + } finally { |
| + await new Future.value(42); |
| + break; |
| + } |
| + } |
| + return id(i); |
| + } |
| + return f().then((v) { |
| + expect(v, equals(0)); |
| + }); |
| + }); |
| + |
| + test("no-exit before await in finally 2", () { |
| + f() async { |
| + for (int i = 0; i < 10; i++) { |
| + try { |
| + return i; |
| + } finally { |
| + if (i >= 0) continue; |
| + await new Future.value(42); |
| + } |
| + } |
| + return id(42); |
| + } |
| + return expect42(f()); |
| + }); |
| + |
| + test("no-exit after await in finally", () { |
| + f() async { |
| + for (int i = 0; i < 10; i++) { |
| + try { |
| + return i; |
| + } finally { |
| + await new Future.value(42); |
| + continue; |
| + } |
| + } |
| + return id(42); |
| + } |
| + return expect42(f()); |
| + }); |
| + |
| + test("nested finallies", () { |
| + var x = 0; |
| + f() async { |
| + try { |
| + try { |
| + return 42; |
| + } finally { |
| + x = await new Future.value(37); |
| + } |
| + } finally { |
| + x += await new Future.value(37); |
| + } |
| + } |
| + return f().then((v) { |
| + expect(v, equals(42)); |
| + expect(x, equals(74)); |
| + }); |
| + }); |
| + |
| + // test("nested finallies 2", () { |
| + // var x = 0; |
| + // f() async { |
| + // label: try { |
| + // try { |
| + // break label; |
| + // } finally { |
| + // x = await new Future.value(37); |
| + // } |
| + // } finally { |
| + // x += await new Future.value(37); |
| + // } |
| + // return 42; |
| + // } |
| + // return f().then((v) { |
| + // expect(v, equals(42)); |
| + // expect(x, equals(74)); |
| + // }); |
| + // }); |
| + |
| + // test("nested finallies 3", () { |
| + // var x = 0; |
| + // f() async { |
| + // label: try { |
| + // try { |
| + // break label; |
| + // } finally { |
| + // return await new Future.value(42); |
| + // } |
| + // } finally { |
| + // break label; |
| + // } |
| + // return 42; |
| + // } |
| + // return expect42(f()); |
| + // }); |
| + |
| + test("nested finallies, throw", () { |
| + var x = 0; |
| + f() async { |
| + try { |
| + try { |
| + throw "err"; |
| + } finally { |
| + x = await new Future.value(37); |
| + } |
| + } finally { |
| + x += await new Future.value(37); |
| + } |
| + } |
| + return f().then((v) { fail("didn't throw"); }, |
| + onError: (e) { |
| + expect(e, equals("err")); |
| + expect(x, equals(2 * 37)); |
| + }); |
| + }); |
| + }); |
| + |
| + group("try-catch-finally", () { |
| + test("await in body", () { |
| + f() async { |
| + try { |
| + return await new Future.value(42); |
| + } catch (e) { |
| + throw null; |
| + } finally { |
| + if (id(42) == id(10)) return 10; |
| + } |
| + } |
| + return expect42(f()); |
| + }); |
| + |
| + test("await in catch, not hit", () { |
| + f() async { |
| + try { |
| + return id(42); |
| + } catch (e) { |
| + await new Future.error("err"); |
| + } finally { |
| + if (id(42) == id(10)) return 10; |
| + } |
| + } |
| + return expect42(f()); |
| + }); |
| + |
| + test("await in catch, hit", () { |
| + f() async { |
| + try { |
| + return throw id(42); |
| + } catch (e) { |
| + return await new Future.value(e); |
| + } finally { |
| + if (id(42) == id(10)) return 10; |
| + } |
| + } |
| + return expect42(f()); |
| + }); |
| + |
| + test("await in finally", () { |
| + var x = 0; |
| + f() async { |
| + try { |
| + return id(42); |
| + } catch (e) { |
| + throw null; |
| + } finally { |
| + x = await new Future.value(37); |
| + if (id(42) == id(10)) return 10; |
| + } |
| + } |
| + return f().then((v) { |
| + expect(v, equals(42)); |
| + expect(x, equals(37)); |
| + }); |
| + }); |
| + }); |
| + |
| + group("switch", () { |
| + test("await in expression", () { |
| + f(v) async { |
| + switch (await new Future.value(v)) { |
| + case 1: return 1; |
| + case 2: return 42; |
| + default: return 3; |
| + } |
| + return null; |
| + } |
| + return expect42(f(2)); |
| + }); |
| + |
| + test("await err in expression", () { |
| + f(v) async { |
| + switch (await new Future.error("err")) { |
| + case 1: return 1; |
| + case 2: return 42; |
| + default: return 3; |
| + } |
| + return null; |
| + } |
| + return throwsErr(f(2)); |
| + }); |
| + |
| + test("await in case", () { |
| + f(v) async { |
| + switch (v) { |
| + case 1: return 1; |
| + case 2: return await new Future.value(42); |
| + default: return 3; |
| + } |
| + return null; |
| + } |
| + return expect42(f(2)); |
| + }); |
| + |
| + test("await err in case", () { |
| + f(v) async { |
| + switch (v) { |
| + case 1: return 1; |
| + case 2: return await new Future.error("err"); |
| + default: return 3; |
| + } |
| + return null; |
| + } |
| + return throwsErr(f(2)); |
| + }); |
| + |
| + test("continue before await in case", () { |
| + f(v) async { |
| + switch (v) { |
| + label: |
| + case 1: return 42; |
| + case 2: |
| + if (v <= 2) continue label; |
| + return await new Future.value(10); |
| + default: return 3; |
| + } |
| + return null; |
| + } |
| + return expect42(f(2)); |
| + }); |
| + |
| + test("continue after await in case", () { |
| + f(v) async { |
| + switch (v) { |
| + label: |
| + case 1: return 42; |
| + case 2: |
| + await new Future.value(10); |
| + continue label; |
| + default: return 3; |
| + } |
| + return null; |
| + } |
| + return expect42(f(2)); |
| + }); |
| + }); |
| + |
| + group("if", () { |
| + test("await in test", () { |
| + f(v) async { |
| + if (await new Future.value(v)) { |
| + return 42; |
| + } else { |
| + return 37; |
| + } |
| + } |
| + return expect42(f(true)); |
| + }); |
| + |
| + test("await err in test", () { |
| + f(v) async { |
| + if (await new Future.error("err")) { |
| + return 42; |
| + } else { |
| + return 37; |
| + } |
| + } |
| + return throwsErr(f(true)); |
| + }); |
| + |
| + test("await in then", () { |
| + f(v) async { |
| + if (v) { |
| + return await new Future.value(42); |
| + } |
| + return 37; |
| + } |
| + return expect42(f(true)); |
| + }); |
| + |
| + test("await err in then", () { |
| + f(v) async { |
| + if (v) { |
| + return await new Future.error("err"); |
| + } |
| + return 37; |
| + } |
| + return throwsErr(f(true)); |
| + }); |
| + |
| + test("await in then with else", () { |
| + f(v) async { |
| + if (v) { |
| + return await new Future.value(42); |
| + } else { |
| + return 87; |
| + } |
| + return 37; |
| + } |
| + return expect42(f(true)); |
| + }); |
| + |
| + test("await err in then with else", () { |
| + f(v) async { |
| + if (v) { |
| + return await new Future.error("err"); |
| + } else { |
| + return 87; |
| + } |
| + return 37; |
| + } |
| + return throwsErr(f(true)); |
| + }); |
| + |
| + test("await in else", () { |
| + f(v) async { |
| + if (v) { |
| + return 37; |
| + } else { |
| + return await new Future.value(42); |
| + } |
| + return 87; |
| + } |
| + return expect42(f(false)); |
| + }); |
| + |
| + test("await err in else", () { |
| + f(v) async { |
| + if (v) { |
| + return 37; |
| + } else { |
| + return await new Future.error("err"); |
| + } |
| + return 87; |
| + } |
| + return throwsErr(f(false)); |
| + }); |
| + |
| + test("await in else-if test", () { |
| + f(v) async { |
| + if (v) { |
| + return 37; |
| + } else if (!await new Future.value(v)) { |
| + return 42; |
| + } else { |
| + return 37; |
| + } |
| + return 87; |
| + } |
| + return expect42(f(false)); |
| + }); |
| + |
| + test("await in else-if then", () { |
| + f(v) async { |
| + if (v) { |
| + return 37; |
| + } else if (!v) { |
| + return await new Future.value(42); |
| + } else { |
| + return 37; |
| + } |
| + return 87; |
| + } |
| + return expect42(f(false)); |
| + }); |
| + }); |
| + |
| + group("conditional operator", () { |
| + test("await in test", () { |
| + f(v) async { |
| + return (await new Future.value(v)) ? 42 : 37; |
| + } |
| + return expect42(f(true)); |
| + }); |
| + |
| + test("await err in test", () { |
| + f(v) async { |
| + return (await new Future.error("err")) ? 42 : 37; |
| + } |
| + return throwsErr(f(true)); |
| + }); |
| + |
| + test("await in then", () { |
| + f(v) async { |
| + return v ? (await new Future.value(42)) : 37; |
| + } |
| + return expect42(f(true)); |
| + }); |
| + |
| + test("await err in then", () { |
| + f(v) async { |
| + return v ? (await new Future.error("err")) : 37; |
| + } |
| + return throwsErr(f(true)); |
| + }); |
| + |
| + test("await in else", () { |
| + f(v) async { |
| + return v ? 37 : (await new Future.value(42)); |
| + } |
| + return expect42(f(false)); |
| + }); |
| + |
| + test("await err in else", () { |
| + f(v) async { |
| + return v ? 37 : (await new Future.error("err")); |
| + } |
| + return throwsErr(f(false)); |
| + }); |
| + }); |
| + |
| + group("async declarations", () { |
| + var f42 = new Future.value(42); |
| + |
| + // Top-level declarations or local declarations in top-level functions. |
| + test("topMethod", () { |
| + return expect42(topMethod(f42)); |
| + }); |
| + |
| + test("topArrowMethod", () { |
| + return expect42(topArrowMethod(f42)); |
| + }); |
| + |
| + test("topGetter", () { |
| + return expect42(topGetter); |
| + }); |
| + |
| + test("topArrowGetter", () { |
| + return expect42(topArrowGetter); |
| + }); |
| + |
| + test("topLocal", () { |
| + return expect42(topLocal(f42)); |
| + }); |
| + |
| + test("topArrowLocal", () { |
| + return expect42(topArrowLocal(f42)); |
| + }); |
| + |
| + test("topExpression", () { |
| + return expect42(topExpression(f42)); |
| + }); |
| + |
| + test("topArrowExpression", () { |
| + return expect42(topArrowExpression(f42)); |
| + }); |
| + |
| + test("topVarExpression", () { |
| + return expect42(topVarExpression(f42)); |
| + }); |
| + |
| + test("topVarArrowExpression", () { |
| + return expect42(topVarArrowExpression(f42)); |
| + }); |
| + |
| + // Static declarations or local declarations in static functions. |
| + test("staticMethod", () { |
| + return expect42(Async.staticMethod(f42)); |
| + }); |
| + |
| + test("staticArrowMethod", () { |
| + return expect42(Async.staticArrowMethod(f42)); |
| + }); |
| + |
| + test("staticGetter", () { |
| + return expect42(Async.staticGetter); |
| + }); |
| + |
| + test("staticArrowGetter", () { |
| + return expect42(Async.staticArrowGetter); |
| + }); |
| + |
| + test("staticLocal", () { |
| + return expect42(Async.staticLocal(f42)); |
| + }); |
| + |
| + test("staticArrowLocal", () { |
| + return expect42(Async.staticArrowLocal(f42)); |
| + }); |
| + |
| + test("staticExpression", () { |
| + return expect42(Async.staticExpression(f42)); |
| + }); |
| + |
| + test("staticArrowExpression", () { |
| + return expect42(Async.staticArrowExpression(f42)); |
| + }); |
| + |
| + test("staticVarExpression", () { |
| + return expect42(Async.staticVarExpression(f42)); |
| + }); |
| + |
| + test("staticVarArrowExpression", () { |
| + return expect42(Async.staticVarArrowExpression(f42)); |
| + }); |
| + |
| + // Instance declarations or local declarations in instance functions. |
| + var async = new Async(); |
| + |
| + test("instanceMethod", () { |
| + return expect42(async.instanceMethod(f42)); |
| + }); |
| + |
| + test("instanceArrowMethod", () { |
| + return expect42(async.instanceArrowMethod(f42)); |
| + }); |
| + |
| + test("instanceGetter", () { |
| + return expect42(async.instanceGetter); |
| + }); |
| + |
| + test("instanceArrowGetter", () { |
| + return expect42(async.instanceArrowGetter); |
| + }); |
| + |
| + test("instanceLocal", () { |
| + return expect42(async.instanceLocal(f42)); |
| + }); |
| + |
| + test("instanceArrowLocal", () { |
| + return expect42(async.instanceArrowLocal(f42)); |
| + }); |
| + |
| + test("instanceExpression", () { |
| + return expect42(async.instanceExpression(f42)); |
| + }); |
| + |
| + test("instanceArrowExpression", () { |
| + return expect42(async.instanceArrowExpression(f42)); |
| + }); |
| + |
| + test("instanceVarExpression", () { |
| + return expect42(async.instanceVarExpression(f42)); |
| + }); |
| + |
| + test("instanceVarArrowExpression", () { |
| + return expect42(async.instanceVarArrowExpression(f42)); |
| + }); |
| + |
| + // Local functions in constructor initializer list. |
| + test("initializerExpression", () { |
| + var async = new Async.initializer(f42); |
| + return expect42(async.initValue); |
| + }); |
| + |
| + test("initializerArrowExpression", () { |
| + var async = new Async.initializerArrow(f42); |
| + return expect42(async.initValue); |
| + }); |
| + |
| + test("async in async", () { |
| + return expect42(asyncInAsync(f42)); |
| + }); |
| + |
| + test("sync in async", () { |
| + return expect42(syncInAsync(f42)); |
| + }); |
| + |
| + test("async in sync", () { |
| + return expect42(asyncInSync(f42)); |
| + }); |
| + |
| + // Equality and identity. |
| + test("Identical and equals", () { |
| + expect(async.instanceMethod, equals(async.instanceMethod)); |
| + expect(Async.staticMethod, same(Async.staticMethod)); |
| + expect(topMethod, same(topMethod)); |
| + }); |
| + }); |
| + |
| + group("await expression", () { |
| + const c42 = 42; |
| + final v42 = 42; |
| + |
| + test("local variable", () { |
| + var l42 = 42; |
| + f() async { |
| + return await l42; |
| + } |
| + return expect42(f()); |
| + }); |
| + |
| + test("parameter", () { |
| + f(p) async { |
| + return await p; |
| + } |
| + return expect42(f(42)); |
| + }); |
| + |
| + test("final local variable", () { |
| + f() async { |
| + return await v42; |
| + } |
| + return expect42(f()); |
| + }); |
| + |
| + test("const local variable", () { |
| + f() async { |
| + return await c42; |
| + } |
| + return expect42(f()); |
| + }); |
| + |
| + test("unary prefix operator", () { |
| + f() async { |
| + return -await -42; |
| + } |
| + return expect42(f()); |
| + }); |
| + |
| + test("suffix operator", () { |
| + f() async { |
| + var v = [42]; |
| + return await v[0]; |
| + } |
| + return expect42(f()); |
| + }); |
| + |
| + // http://dartbug.com/22634 |
| + // test("unary postfix operator", () { |
| + // f() async { |
| + // var x = 42; |
| + // return await x++; |
| + // } |
| + // return expect42(f()); |
| + // }); |
| + |
| + // test("suffix operator + increment", () { |
| + // f() async { |
| + // var v = [42]; |
| + // return await v[0]++; |
| + // } |
| + // return expect42(f()); |
| + // }); |
| + |
| + test("unary pre-increment operator", () { |
| + f() async { |
| + var x = 41; |
| + return await ++x; |
| + } |
| + return expect42(f()); |
| + }); |
| + |
| + test("suffix operator + pre-increment", () { |
| + f() async { |
| + var v = [41]; |
| + return await ++v[0]; |
| + } |
| + return expect42(f()); |
| + }); |
| + |
| + test("assignment operator", () { |
| + f() async { |
| + var x = 37; |
| + return await (x = 42); |
| + } |
| + return expect42(f()); |
| + }); |
| + |
| + test("assignment-op operator", () { |
| + f() async { |
| + var x = 37; |
| + return await (x += 5); |
| + } |
| + return expect42(f()); |
| + }); |
| + |
| + test("binary operator", () { |
| + f() async { |
| + return await (10 + 11) + await (10 + 11); |
| + } |
| + return expect42(f()); |
| + }); |
| + |
| + test("ternary operator", () { |
| + f(v) async { |
| + return await ((v == 10) ? new Future.value(42) : 37); |
| + } |
| + return expect42(f(10)); |
| + }); |
| + |
| + test("top-level function call", () { |
| + f() async { |
| + return await topMethod(42); |
| + } |
| + return expect42(f()); |
| + }); |
| + |
| + test("static function call", () { |
| + f() async { |
| + return await Async.staticMethod(42); |
| + } |
| + return expect42(f()); |
| + }); |
| + |
| + test("instance function call", () { |
| + f() async { |
| + var a = new Async(); |
| + return await a.instanceMethod(42); |
| + } |
| + return expect42(f()); |
| + }); |
| + |
| + test("top-level function call w/ await", () { |
| + f() async { |
| + return await topMethod(await 42); |
| + } |
| + return expect42(f()); |
| + }); |
| + |
| + test("static function call w/ await", () { |
| + f() async { |
| + return await Async.staticMethod(await 42); |
| + } |
| + return expect42(f()); |
| + }); |
| + |
| + test("instance function call w/ await", () { |
| + f() async { |
| + var a = new Async(); |
| + return await a.instanceMethod(await 42); |
| + } |
| + return expect42(f()); |
| + }); |
| + |
| + test("top-level getter call", () { |
| + f() async { |
| + return await topGetter; |
| + } |
| + return expect42(f()); |
| + }); |
| + |
| + test("static getter call", () { |
| + f() async { |
| + return await Async.staticGetter; |
| + } |
| + return expect42(f()); |
| + }); |
| + |
| + test("top-level getter call", () { |
| + f() async { |
| + var a = new Async(); |
| + return await a.instanceGetter; |
| + } |
| + return expect42(f()); |
| + }); |
| + }); |
| + |
| + group("syntax", () { |
| + test("async as variable", () { |
| + // Valid identifiers outside of async function. |
| + var async = 42; |
| + expect(async, equals(42)); |
| + }); |
| + |
| + test("await as variable", () { |
| + // Valid identifiers outside of async function. |
| + var await = 42; |
| + expect(await, equals(42)); |
| + }); |
| + |
| + test("yield as variable", () { |
| + // Valid identifiers outside of async function. |
| + var yield = 42; |
| + expect(yield, equals(42)); |
| + }); |
| + }); |
| +} |
| + |
| + |
| +// Attempt to obfuscates value to avoid too much constant folding. |
| +id(v) { |
| + try { |
| + if (v != null) throw v; |
| + } catch (e) { |
| + return e; |
| + } |
| + return null; |
| +} |
| + |
| +// Create a stream for testing "async for-in". |
| +Stream mkStream() { |
| + var c; |
| + int i = 0; |
| + next() { |
| + c.add(i++); |
| + if (i == 10) { |
| + c.close(); |
| + } else { |
| + scheduleMicrotask(next); |
| + } |
| + } |
| + c = new StreamController(onListen: () { |
| + scheduleMicrotask(next); |
| + }); |
| + return c.stream; |
| +} |
| + |
| +// Check that future contains the error "err". |
| +Future throwsErr(Future future) { |
| + return future.then((v) { fail("didn't throw"); }, |
| + onError: (e) { expect(e, equals("err")); }); |
| +} |
| + |
| +// Check that future contains the value 42. |
| +Future expect42(Future future) { |
| + return future.then((v) { |
| + expect(v, equals(42)); |
| + }); |
| +} |
| + |
| + |
| +// Various async declarations. |
| + |
| +Future topMethod(f) async { return await f; } |
| + |
| +Future topArrowMethod(f) async => await f; |
| + |
| +Future get topGetter async { |
| + return await new Future.value(42); |
| +} |
| + |
| +// Future get topArrowGetter async => await new Future.value(42); |
| + |
| +Future topLocal(f) { |
| + local() async { return await f; } |
| + return local(); |
| +} |
| + |
| +Future topArrowLocal(f) { |
| + local() async => await f; |
| + return local(); |
| +} |
| + |
| +Future topExpression(f) { |
| + return () async { return await f; } (); |
| +} |
| + |
| +Future topArrowExpression(f) { |
| + return (() async => await f) (); |
| +} |
| + |
| +var topVarExpression = (f) async { return await f; }; |
| + |
| +var topVarArrowExpression = (f) async => await f; |
| + |
| +class Async { |
| + var initValue; |
| + Async(); |
| + |
| + Async.initializer(f) : initValue = (() async { return await f; } ()); |
| + |
| + Async.initializerArrow(f) : initValue = ((() async => await f) ()); |
| + |
| + /* static */ |
| + static Future staticMethod(f) async { return await f; } |
| + |
| + static Future staticArrowMethod(f) async => await f; |
| + |
| + static Future get staticGetter async { |
| + return await new Future.value(42); |
| + } |
| + |
| + // static Future get staticArrowGetter async => await new Future.value(42); |
| + |
| + static Future staticLocal(f) { |
| + local() async { return await f; } |
| + return local(); |
| + } |
| + |
| + static Future staticArrowLocal(f) { |
| + local() async => await f; |
| + return local(); |
| + } |
| + |
| + static Future staticExpression(f) { |
| + return () async { return await f; } (); |
| + } |
| + |
| + static Future staticArrowExpression(f) { |
| + return (() async => await f) (); |
| + } |
| + |
| + static var staticVarExpression = (f) async { return await f; }; |
| + |
| + static var staticVarArrowExpression = (f) async => await f; |
| + |
| + /* instance */ |
| + Future instanceMethod(f) async { return await f; } |
| + |
| + Future instanceArrowMethod(f) async => await f; |
| + |
| + Future get instanceGetter async { |
| + return await new Future.value(42); |
| + } |
| + |
| + // Future get instanceArrowGetter async => await new Future.value(42); |
| + |
| + Future instanceLocal(f) { |
| + local() async { return await f; } |
| + return local(); |
| + } |
| + |
| + Future instanceArrowLocal(f) { |
| + local() async => await f; |
| + return local(); |
| + } |
| + |
| + Future instanceExpression(f) { |
| + return () async { return await f; } (); |
| + } |
| + |
| + Future instanceArrowExpression(f) { |
| + return (() async => await f) (); |
| + } |
| + |
| + var instanceVarExpression = (f) async { return await f; }; |
| + |
| + var instanceVarArrowExpression = (f) async => await f; |
| +} |
| + |
| +Future asyncInAsync(f) async { |
| + inner(f) async { |
| + return await f; |
| + } |
| + return await inner(f); |
| +} |
| + |
| +Future asyncInSync(f) { |
| + inner(f) async { |
| + return await f; |
| + } |
| + return inner(f); |
| +} |
| + |
| +Future syncInAsync(f) async { |
| + inner(f) { |
| + return f; |
| + } |
| + return await inner(f); |
| +} |
| + |
| +/** |
| + * A non-standard implementation of Future with a value. |
| + */ |
| +class FakeValueFuture implements Future { |
| + final _value; |
| + FakeValueFuture(this._value); |
| + Future then(callback(value), {Function onError}) { |
| + return new Future.microtask(() => callback(_value)); |
| + } |
| + Future whenComplete(callback()) { |
| + return new Future.microtask(() { callback(); }); |
| + } |
| + Future catchError(Function onError, [bool test(error)]) => this; |
|
sigurdm
2015/03/03 14:13:10
Also test needs to be named parameter
|
| + Stream asStream() => (new StreamController()..add(_value)..close()).stream; |
| + Future timeout(Duration duration, {onTimeout}) => this; |
| +} |
| + |
| +typedef BinaryFunction(a, b); |
| + |
| +/** |
| + * A non-standard implementation of Future with an error. |
| + */ |
| +class FakeErrorFuture implements Future { |
| + final _error; |
| + FakeErrorFuture(this._error); |
| + Future then(callback(value), {Function onError}) { |
| + if (onError != null) { |
| + if (onError is BinaryFunction) { |
| + return new Future.microtask(() => onError(_error, null)); |
| + } |
| + return new Future.microtask(() => onError(_error)); |
| + } |
| + return this; |
| + } |
| + Future whenComplete(callback()) { |
| + return new Future.microtask(() { callback(); }).then((_) => this); |
| + } |
| + Future catchError(Function onError, [bool test(error)]) { |
| + return new Future.microtask(() { |
| + if (test != null && !test(_error)) return this; |
| + if (onError is BinaryFunction) { |
| + return onError(_error, null); |
| + } |
| + return onError(_error); |
| + }); |
| + } |
| + Stream asStream() => |
| + (new StreamController()..addError(_error)..close()).stream; |
| + Future timeout(Duration duration, {onTimeout}) => this; |
| +} |