blob: dbb2239b0199f86c663258fb0d78ff4a8fe7b3fe [file] [log] [blame]
// 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';
Future<int> gee(int i) async {
return await i;
}
Stream<int> 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);
}
ZoneCallback<R> registerCallback<R>(
Zone self, ZoneDelegate parent, Zone zone, R f()) {
var oldDepth = depth;
increaseDepth();
return parent.registerCallback(zone, () {
depth = oldDepth;
return f();
});
}
ZoneUnaryCallback<R, T> registerUnaryCallback<R, T>(
Zone self, ZoneDelegate parent, Zone zone, R f(T arg)) {
var oldDepth = depth;
increaseDepth();
return parent.registerUnaryCallback(zone, (x) {
depth = oldDepth;
return f(x);
});
}
ZoneBinaryCallback<R, T1, T2> registerBinaryCallback<R, T1, T2>(
Zone self, ZoneDelegate parent, Zone zone, R f(T1 arg1, T2 arg2)) {
var oldDepth = depth;
increaseDepth();
return parent.registerBinaryCallback(zone, (x, y) {
depth = oldDepth;
return f(x, y);
});
}
void 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());
}