Skip to content

Commit 4f9a06e

Browse files
authored
#1363. Yield each tests updated to the current specification (#1374)
Authored by @sgrekhov. Yield-each tests updated and new ones added; some delays replaced by `await null;`; do not to rely on delays, but use a completer (to avoid having flakiness during high loads, and in general to avoid depending on scheduling order and timing).
1 parent 93635ba commit 4f9a06e

30 files changed

+1302
-666
lines changed
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
// Copyright (c) 2016, the Dart project authors. Please see the AUTHORS file
2+
// for details. All rights reserved. Use of this source code is governed by a
3+
// BSD-style license that can be found in the LICENSE file.
4+
5+
/// @assertion If `m` is marked `async*`, then:
6+
/// • It is a dynamic error if the class of o does not implement `Stream<T>`.
7+
/// Otherwise
8+
/// • The nearest enclosing asynchronous for loop, if any, is paused.
9+
/// • The `o` stream is listened to, creating a subscription `s`, and for each
10+
/// event `x`, or error `e` with stack trace `t`, of `s`:
11+
/// – If the stream `u` associated with `m` has been paused, then execution
12+
/// of `m` is suspended until `u` is resumed or canceled.
13+
/// – If the stream `u` associated with `m` has been canceled, then `s` is
14+
/// canceled by evaluating `await v.cancel()` where `v` is a fresh variable
15+
/// referencing the stream subscription `s`. Then, if the cancel completed
16+
/// normally, the stream execution of `s` returns without an object.
17+
/// – Otherwise, `x`, or `e` with `t`, are added to the stream associated
18+
/// with `m` in the order they appear in `o`. Note that a dynamic error
19+
/// occurs if `x` is added and the dynamic type of `x` is not a subtype of
20+
/// the element type of said stream. The function `m` may suspend.
21+
/// • If the stream `o` is done, execution of `s` completes normally.
22+
///
23+
/// @description Check that dynamic error occurs if the class of `o` does not
24+
/// implement `Stream<T>`.
25+
///
26+
/// @issue #25634 - the test assumes that dynamic error is added to the stream.
27+
/// @author [email protected]
28+
29+
import 'dart:async';
30+
import '../../../../Utils/expect.dart';
31+
32+
Stream<int> generator() async* {
33+
dynamic a = 'a';
34+
yield* a;
35+
}
36+
37+
main() {
38+
asyncStart();
39+
generator().listen((_) {}, onError: (e) {
40+
Expect.isTrue(e is Error);
41+
asyncEnd();
42+
});
43+
}
Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
// Copyright (c) 2022, the Dart project authors. Please see the AUTHORS file
2+
// for details. All rights reserved. Use of this source code is governed by a
3+
// BSD-style license that can be found in the LICENSE file.
4+
5+
/// @assertion If `m` is marked `async*`, then:
6+
/// • It is a dynamic error if the class of o does not implement `Stream<T>`.
7+
/// Otherwise
8+
/// • The nearest enclosing asynchronous for loop, if any, is paused.
9+
/// • The `o` stream is listened to, creating a subscription `s`, and for each
10+
/// event `x`, or error `e` with stack trace `t`, of `s`:
11+
/// – If the stream `u` associated with `m` has been paused, then execution
12+
/// of `m` is suspended until `u` is resumed or canceled.
13+
/// – If the stream `u` associated with `m` has been canceled, then `s` is
14+
/// canceled by evaluating `await v.cancel()` where `v` is a fresh variable
15+
/// referencing the stream subscription `s`. Then, if the cancel completed
16+
/// normally, the stream execution of `s` returns without an object.
17+
/// – Otherwise, `x`, or `e` with `t`, are added to the stream associated
18+
/// with `m` in the order they appear in `o`. Note that a dynamic error
19+
/// occurs if `x` is added and the dynamic type of `x` is not a subtype of
20+
/// the element type of said stream. The function `m` may suspend.
21+
/// • If the stream `o` is done, execution of `s` completes normally.
22+
///
23+
/// @description Check that if there is an enclosing asynchronous for loop, it
24+
/// is paused
25+
///
26+
/// @author [email protected]
27+
28+
import 'dart:async';
29+
import '../../../../Utils/expect.dart';
30+
31+
Stream<Object> generator(Stream<int> input1, Stream<String> input2) async* {
32+
await for (var v in input1) {
33+
yield v;
34+
if (v == 2) {
35+
yield* input2;
36+
}
37+
}
38+
}
39+
40+
Future test() async {
41+
List log = [];
42+
Stream<String> input2 = Stream<String>.fromIterable(['a', 'b', 'c']);
43+
StreamController<int> sc = new StreamController<int>();
44+
Stream<Object> s = generator(sc.stream, input2);
45+
StreamSubscription<Object> ss = s.listen((Object o) {
46+
log.add(o);
47+
if (o is String) {
48+
Expect.isTrue(sc.isPaused);
49+
}
50+
}, onDone: () {
51+
Expect.listEquals([1, 2, 'a', 'b', 'c', 3], log);
52+
asyncEnd();
53+
});
54+
sc.add(1);
55+
await null;
56+
sc.add(2);
57+
await null;
58+
sc.add(3);
59+
await null;
60+
ss.resume();
61+
await sc.close();
62+
}
63+
64+
main() {
65+
asyncStart();
66+
test();
67+
}
Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
// Copyright (c) 2016, the Dart project authors. Please see the AUTHORS file
2+
// for details. All rights reserved. Use of this source code is governed by a
3+
// BSD-style license that can be found in the LICENSE file.
4+
5+
/// @assertion If `m` is marked `async*`, then:
6+
/// • It is a dynamic error if the class of o does not implement `Stream<T>`.
7+
/// Otherwise
8+
/// • The nearest enclosing asynchronous for loop, if any, is paused.
9+
/// • The `o` stream is listened to, creating a subscription `s`, and for each
10+
/// event `x`, or error `e` with stack trace `t`, of `s`:
11+
/// – If the stream `u` associated with `m` has been paused, then execution
12+
/// of `m` is suspended until `u` is resumed or canceled.
13+
/// – If the stream `u` associated with `m` has been canceled, then `s` is
14+
/// canceled by evaluating `await v.cancel()` where `v` is a fresh variable
15+
/// referencing the stream subscription `s`. Then, if the cancel completed
16+
/// normally, the stream execution of `s` returns without an object.
17+
/// – Otherwise, `x`, or `e` with `t`, are added to the stream associated
18+
/// with `m` in the order they appear in `o`. Note that a dynamic error
19+
/// occurs if `x` is added and the dynamic type of `x` is not a subtype of
20+
/// the element type of said stream. The function `m` may suspend.
21+
/// • If the stream `o` is done, execution of `s` completes normally.
22+
///
23+
/// @description Check that if the stream `u` associated with `m` has been
24+
/// paused, then execution of `m` is suspended until `u` is resumed. Using
25+
/// `StreamController` as input data supplier.
26+
///
27+
/// @author [email protected]
28+
/// @issue 42584
29+
30+
import 'dart:async';
31+
import '../../../../Utils/expect.dart';
32+
33+
Stream<int> generator(Stream<int> input) async* {
34+
yield* input;
35+
}
36+
37+
Future test() async {
38+
List log = [];
39+
StreamController<int> sc = new StreamController<int>();
40+
Stream<int> s = generator(sc.stream);
41+
StreamSubscription<int> ss = s.listen((int i) {
42+
log.add(i);
43+
}, onDone: () {
44+
Expect.listEquals(['a', 'b', 'c', 1, 2, 3], log);
45+
asyncEnd();
46+
});
47+
ss.pause();
48+
sc.add(1);
49+
await null;
50+
log.add('a');
51+
sc.add(2);
52+
await null;
53+
log.add('b');
54+
sc.add(3);
55+
await null;
56+
log.add('c');
57+
ss.resume();
58+
await sc.close();
59+
}
60+
61+
main() {
62+
asyncStart();
63+
test();
64+
}
Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
// Copyright (c) 2016, the Dart project authors. Please see the AUTHORS file
2+
// for details. All rights reserved. Use of this source code is governed by a
3+
// BSD-style license that can be found in the LICENSE file.
4+
5+
/// @assertion If `m` is marked `async*`, then:
6+
/// • It is a dynamic error if the class of o does not implement `Stream<T>`.
7+
/// Otherwise
8+
/// • The nearest enclosing asynchronous for loop, if any, is paused.
9+
/// • The `o` stream is listened to, creating a subscription `s`, and for each
10+
/// event `x`, or error `e` with stack trace `t`, of `s`:
11+
/// – If the stream `u` associated with `m` has been paused, then execution
12+
/// of `m` is suspended until `u` is resumed or canceled.
13+
/// – If the stream `u` associated with `m` has been canceled, then `s` is
14+
/// canceled by evaluating `await v.cancel()` where `v` is a fresh variable
15+
/// referencing the stream subscription `s`. Then, if the cancel completed
16+
/// normally, the stream execution of `s` returns without an object.
17+
/// – Otherwise, `x`, or `e` with `t`, are added to the stream associated
18+
/// with `m` in the order they appear in `o`. Note that a dynamic error
19+
/// occurs if `x` is added and the dynamic type of `x` is not a subtype of
20+
/// the element type of said stream. The function `m` may suspend.
21+
/// • If the stream `o` is done, execution of `s` completes normally.
22+
///
23+
/// @description Check that if the stream `u` associated with `m` has been
24+
/// paused, then execution of `m` is suspended until `u` is resumed. Using
25+
/// `Completer` to control generator execution before `yield*` statement.
26+
///
27+
/// @author [email protected]
28+
29+
import 'dart:async';
30+
import '../../../../Utils/expect.dart';
31+
32+
Stream<int> generator(Stream<int> input, Future startTrigger) async* {
33+
await startTrigger;
34+
yield* input;
35+
}
36+
37+
Future test() async {
38+
List log = [];
39+
Completer c = new Completer();
40+
Stream<int> s = generator(new Stream.fromIterable([1, 2, 3]), c.future);
41+
StreamSubscription<int> ss = s.listen((int i) {
42+
log.add(i);
43+
}, onDone: () {
44+
Expect.listEquals(['a', 'b', 'c', 1, 2, 3], log);
45+
asyncEnd();
46+
});
47+
ss.pause();
48+
c.complete(); // Return control to yield*
49+
log.add('a');
50+
await null;
51+
log.add('b');
52+
await null;
53+
log.add('c');
54+
ss.resume();
55+
}
56+
57+
main() {
58+
asyncStart();
59+
test();
60+
}
Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
// Copyright (c) 2016, the Dart project authors. Please see the AUTHORS file
2+
// for details. All rights reserved. Use of this source code is governed by a
3+
// BSD-style license that can be found in the LICENSE file.
4+
5+
/// @assertion If `m` is marked `async*`, then:
6+
/// • It is a dynamic error if the class of o does not implement `Stream<T>`.
7+
/// Otherwise
8+
/// • The nearest enclosing asynchronous for loop, if any, is paused.
9+
/// • The `o` stream is listened to, creating a subscription `s`, and for each
10+
/// event `x`, or error `e` with stack trace `t`, of `s`:
11+
/// – If the stream `u` associated with `m` has been paused, then execution
12+
/// of `m` is suspended until `u` is resumed or canceled.
13+
/// – If the stream `u` associated with `m` has been canceled, then `s` is
14+
/// canceled by evaluating `await v.cancel()` where `v` is a fresh variable
15+
/// referencing the stream subscription `s`. Then, if the cancel completed
16+
/// normally, the stream execution of `s` returns without an object.
17+
/// – Otherwise, `x`, or `e` with `t`, are added to the stream associated
18+
/// with `m` in the order they appear in `o`. Note that a dynamic error
19+
/// occurs if `x` is added and the dynamic type of `x` is not a subtype of
20+
/// the element type of said stream. The function `m` may suspend.
21+
/// • If the stream `o` is done, execution of `s` completes normally.
22+
///
23+
/// @description Check that if the stream `u` associated with `m` has been
24+
/// paused, then execution of `m` is suspended until `u` is cancelled. Using
25+
/// `StreamController` as input data supplier.
26+
///
27+
/// @author [email protected]
28+
29+
import 'dart:async';
30+
import '../../../../Utils/expect.dart';
31+
32+
Stream<int> generator(Stream<int> input) async* {
33+
yield* input;
34+
}
35+
36+
Future test() async {
37+
List log = [];
38+
StreamController<int> sc = new StreamController<int>();
39+
Stream<int> s = generator(sc.stream);
40+
StreamSubscription<int> ss = s.listen((int i) {
41+
log.add(i);
42+
});
43+
ss.pause();
44+
sc.add(1);
45+
await null;
46+
log.add('a');
47+
sc.add(2);
48+
await null;
49+
log.add('b');
50+
sc.add(3);
51+
await null;
52+
log.add('c');
53+
await ss.cancel();
54+
await sc.close();
55+
Expect.listEquals(['a', 'b', 'c'], log);
56+
}
57+
58+
main() {
59+
asyncStart();
60+
test().then((_) => asyncEnd());
61+
}
Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
// Copyright (c) 2016, the Dart project authors. Please see the AUTHORS file
2+
// for details. All rights reserved. Use of this source code is governed by a
3+
// BSD-style license that can be found in the LICENSE file.
4+
5+
/// @assertion If `m` is marked `async*`, then:
6+
/// • It is a dynamic error if the class of o does not implement `Stream<T>`.
7+
/// Otherwise
8+
/// • The nearest enclosing asynchronous for loop, if any, is paused.
9+
/// • The `o` stream is listened to, creating a subscription `s`, and for each
10+
/// event `x`, or error `e` with stack trace `t`, of `s`:
11+
/// – If the stream `u` associated with `m` has been paused, then execution
12+
/// of `m` is suspended until `u` is resumed or canceled.
13+
/// – If the stream `u` associated with `m` has been canceled, then `s` is
14+
/// canceled by evaluating `await v.cancel()` where `v` is a fresh variable
15+
/// referencing the stream subscription `s`. Then, if the cancel completed
16+
/// normally, the stream execution of `s` returns without an object.
17+
/// – Otherwise, `x`, or `e` with `t`, are added to the stream associated
18+
/// with `m` in the order they appear in `o`. Note that a dynamic error
19+
/// occurs if `x` is added and the dynamic type of `x` is not a subtype of
20+
/// the element type of said stream. The function `m` may suspend.
21+
/// • If the stream `o` is done, execution of `s` completes normally.
22+
///
23+
/// @description Check that if the stream `u` associated with `m` has been
24+
/// paused, then execution of `m` is suspended until `u` is cancelled. Using
25+
/// `Completer` to control generator execution before `yield*` statement.
26+
///
27+
/// @author [email protected]
28+
29+
import 'dart:async';
30+
import '../../../../Utils/expect.dart';
31+
32+
Stream<int> generator(Stream<int> input, Future startTrigger) async* {
33+
await startTrigger;
34+
yield* input;
35+
}
36+
37+
Future test() async {
38+
List log = [];
39+
Completer c = new Completer();
40+
Stream<int> s = generator(new Stream.fromIterable([1, 2, 3]), c.future);
41+
StreamSubscription<int> ss = s.listen((int i) {
42+
log.add(i);
43+
});
44+
ss.pause();
45+
c.complete(); // pass control to yield*
46+
log.add('a');
47+
await null;
48+
log.add('b');
49+
await null;
50+
log.add('c');
51+
await ss.cancel();
52+
Expect.listEquals(['a', 'b', 'c'], log);
53+
}
54+
55+
main() {
56+
asyncStart();
57+
test().then((_) => asyncEnd());
58+
}

0 commit comments

Comments
 (0)