Index: tests/lib_strong/async/async_await_zones_test.dart |
diff --git a/tests/lib_strong/async/async_await_zones_test.dart b/tests/lib_strong/async/async_await_zones_test.dart |
new file mode 100644 |
index 0000000000000000000000000000000000000000..210b05dee778929c0d7d3f3757afd3146e927214 |
--- /dev/null |
+++ b/tests/lib_strong/async/async_await_zones_test.dart |
@@ -0,0 +1,142 @@ |
+// 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. |
+ |
+// Test that async functions don't zone-register their callbacks for each |
+// await. Async functions should register their callback once in the beginning |
+// and then reuse it for all awaits in their body. |
+// This has two advantages: it is faster, when there are several awaits (on |
+// the Future class from dart:async), and it avoids zone-nesting when tracing |
+// stacktraces. |
+// See http://dartbug.com/23394 for more information. |
+ |
+import 'dart:async'; |
+import 'package:expect/expect.dart'; |
+import 'package:async_helper/async_helper.dart'; |
+ |
+gee(i) async { |
+ return await i; |
+} |
+ |
+bar() async* { |
+ var i = 0; |
+ while (true) yield await gee(i++); |
+} |
+ |
+ |
+awaitForTest() async { |
+ var sum = 0; |
+ await for (var x in bar().take(100)) { |
+ sum += x; |
+ } |
+ Expect.equals(4950, sum); |
+} |
+ |
+awaitTest() async { |
+ await null; |
+ await null; |
+ await null; |
+ await null; |
+ await null; |
+ await null; |
+ await null; |
+ await null; |
+ await null; |
+ await null; |
+ await null; |
+ await null; |
+ await null; |
+ await null; |
+ await null; |
+ await null; |
+ await null; |
+ await null; |
+ await null; |
+ await null; |
+ await null; |
+ await null; |
+ await null; |
+ await null; |
+ await null; |
+ await null; |
+ await null; |
+ await null; |
+ await null; |
+ await null; |
+ await null; |
+ await null; |
+ await null; |
+ await null; |
+ await null; |
+ await null; |
+ await null; |
+ await null; |
+ await null; |
+ await null; |
+ return await 499; |
+} |
+ |
+runTests() async { |
+ await awaitTest(); |
+ await awaitForTest(); |
+} |
+ |
+var depth = 0; |
+ |
+var depthIncreases = 0; |
+ |
+increaseDepth() { |
+ depthIncreases++; |
+ depth++; |
+ // The async/await code should not register callbacks recursively in the |
+ // then-calls. As such the depth should never grow too much. We don't want |
+ // to commit to a specific value, since implementations still have some |
+ // room in how async/await is implemented, but 20 should be safe. |
+ Expect.isTrue(depth < 20); |
+} |
+ |
+registerCallback(Zone self, ZoneDelegate parent, Zone zone, f) { |
+ var oldDepth = depth; |
+ increaseDepth(); |
+ return parent.registerCallback(zone, () { |
+ depth = oldDepth; |
+ return f(); |
+ }); |
+} |
+registerUnaryCallback(Zone self, ZoneDelegate parent, Zone zone, f) { |
+ var oldDepth = depth; |
+ increaseDepth(); |
+ return parent.registerUnaryCallback(zone, (x) { |
+ depth = oldDepth; |
+ return f(x); |
+ }); |
+} |
+registerBinaryCallback(Zone self, ZoneDelegate parent, Zone zone, f) { |
+ var oldDepth = depth; |
+ increaseDepth(); |
+ return parent.registerBinaryCallback(zone, (x, y) { |
+ depth = oldDepth; |
+ return f(x, y); |
+ }); |
+} |
+ |
+sm(Zone self, ZoneDelegate parent, Zone zone, f) { |
+ var oldDepth = depth; |
+ increaseDepth(); |
+ return parent.scheduleMicrotask(zone, () { |
+ depth = oldDepth; |
+ return f(); |
+ }); |
+} |
+ |
+main() { |
+ asyncStart(); |
+ var desc = new ZoneSpecification( |
+ registerCallback: registerCallback, |
+ registerUnaryCallback: registerUnaryCallback, |
+ registerBinaryCallback: registerBinaryCallback, |
+ scheduleMicrotask: sm |
+ ); |
+ var future = runZoned(runTests, zoneSpecification: desc); |
+ future.then((_) => asyncEnd()); |
+} |