fb29d0e96d
This allows to break a circular dependency between package:expect and package:async_helper, which will simplify the support for modular tests using package:modular_test. Change-Id: Ie48723d3f35d51a8fbe622e0158450e8104fe3f5 Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/102140 Reviewed-by: Johnni Winther <johnniwinther@google.com>
258 lines
6.7 KiB
Dart
258 lines
6.7 KiB
Dart
// Copyright (c) 2013, 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 Stream.fromIterable.
|
|
|
|
import 'dart:async';
|
|
|
|
import 'package:async_helper/async_helper.dart';
|
|
import 'package:expect/expect.dart';
|
|
import 'package:async_helper/async_minitest.dart';
|
|
|
|
import 'event_helper.dart';
|
|
|
|
// Tests that various typed iterables that do not throw creates
|
|
// suitable streams.
|
|
void iterableTest<T>(Iterable<T> iterable) {
|
|
asyncStart();
|
|
List<T> expected = iterable.toList();
|
|
Stream<T> stream = new Stream<T>.fromIterable(iterable);
|
|
var events = <T>[];
|
|
stream.listen(events.add, onDone: () {
|
|
Expect.listEquals(expected, events, "fromIterable $iterable");
|
|
asyncEnd();
|
|
});
|
|
}
|
|
|
|
main() {
|
|
asyncStart();
|
|
|
|
iterableTest<Object>(<Object>[]);
|
|
iterableTest<Null>(<Null>[]);
|
|
iterableTest<Object>(<int>[1]);
|
|
iterableTest<Object>(<Object>[1, "two", true, null]);
|
|
iterableTest<int>(<int>[1, 2, 3, 4]);
|
|
iterableTest<String>(<String>["one", "two", "three", "four"]);
|
|
iterableTest<int>(new Iterable<int>.generate(1000, (i) => i));
|
|
iterableTest<String>(
|
|
new Iterable<int>.generate(1000, (i) => i).map((i) => "$i"));
|
|
|
|
Iterable<int> iter = new Iterable.generate(25, (i) => i * 2);
|
|
|
|
{
|
|
// Test that the stream's .toList works.
|
|
asyncStart();
|
|
new Stream.fromIterable(iter).toList().then((actual) {
|
|
List expected = iter.toList();
|
|
Expect.equals(25, expected.length);
|
|
Expect.listEquals(expected, actual);
|
|
asyncEnd();
|
|
});
|
|
}
|
|
|
|
{
|
|
// Test that the stream's .map works.
|
|
asyncStart();
|
|
new Stream.fromIterable(iter).map((i) => i * 3).toList().then((actual) {
|
|
List expected = iter.map((i) => i * 3).toList();
|
|
Expect.listEquals(expected, actual);
|
|
asyncEnd();
|
|
});
|
|
}
|
|
|
|
{
|
|
// Test that pause works.
|
|
asyncStart();
|
|
int ctr = 0;
|
|
|
|
var stream = new Stream<int>.fromIterable(iter.map((x) {
|
|
ctr++;
|
|
return x;
|
|
}));
|
|
|
|
StreamSubscription subscription;
|
|
var actual = [];
|
|
subscription = stream.listen((int value) {
|
|
actual.add(value);
|
|
// Do a 10 ms pause during the playback of the iterable.
|
|
Duration duration = const Duration(milliseconds: 10);
|
|
if (value == 20) {
|
|
asyncStart();
|
|
int beforeCtr = ctr;
|
|
subscription.pause(new Future.delayed(duration, () {}).whenComplete(() {
|
|
Expect.equals(beforeCtr, ctr);
|
|
asyncEnd();
|
|
}));
|
|
}
|
|
}, onDone: () {
|
|
Expect.listEquals(iter.toList(), actual);
|
|
asyncEnd();
|
|
});
|
|
}
|
|
|
|
{
|
|
// Test that you can't listen twice..
|
|
Stream stream = new Stream.fromIterable(iter);
|
|
stream.listen((x) {}).cancel();
|
|
Expect.throws<StateError>(() => stream.listen((x) {}));
|
|
}
|
|
|
|
{
|
|
// Regression test for http://dartbug.com/14332.
|
|
// This should succeed.
|
|
var from = new Stream.fromIterable([1, 2, 3, 4, 5]);
|
|
|
|
var c = new StreamController();
|
|
var sink = c.sink;
|
|
|
|
asyncStart(2);
|
|
|
|
// if this goes first, test failed (hanged). Swapping addStream and toList
|
|
// made failure go away.
|
|
sink.addStream(from).then((_) {
|
|
c.close();
|
|
asyncEnd();
|
|
});
|
|
|
|
c.stream.toList().then((x) {
|
|
Expect.listEquals([1, 2, 3, 4, 5], x);
|
|
asyncEnd();
|
|
});
|
|
}
|
|
|
|
{
|
|
// Regression test for issue 14334 (#2)
|
|
var from = new Stream.fromIterable([1, 2, 3, 4, 5]);
|
|
|
|
// odd numbers as data events, even numbers as error events
|
|
from = from.map((x) => x.isOdd ? x : throw x);
|
|
|
|
var c = new StreamController();
|
|
|
|
asyncStart();
|
|
|
|
var data = [], errors = [];
|
|
c.stream.listen(data.add, onError: errors.add, onDone: () {
|
|
Expect.listEquals([1, 3, 5], data);
|
|
Expect.listEquals([2, 4], errors);
|
|
asyncEnd();
|
|
});
|
|
c.addStream(from).then((_) {
|
|
c.close();
|
|
});
|
|
}
|
|
|
|
{
|
|
// Example from issue http://dartbug.com/33431.
|
|
asyncStart();
|
|
var asyncStarStream = () async* {
|
|
yield 1;
|
|
yield 2;
|
|
throw "bad";
|
|
}();
|
|
collectEvents(asyncStarStream).then((events2) {
|
|
Expect.listEquals(["value", 1, "value", 2, "error", "bad"], events2);
|
|
asyncEnd();
|
|
});
|
|
|
|
Iterable<int> throwingIterable() sync* {
|
|
yield 1;
|
|
yield 2;
|
|
throw "bad";
|
|
}
|
|
|
|
// Sanity check behavior.
|
|
var it = throwingIterable().iterator;
|
|
Expect.isTrue(it.moveNext());
|
|
Expect.equals(1, it.current);
|
|
Expect.isTrue(it.moveNext());
|
|
Expect.equals(2, it.current);
|
|
Expect.throws(it.moveNext, (e) => e == "bad");
|
|
|
|
asyncStart();
|
|
var syncStarStream = new Stream<int>.fromIterable(throwingIterable());
|
|
collectEvents(syncStarStream).then((events1) {
|
|
Expect.listEquals(["value", 1, "value", 2, "error", "bad"], events1);
|
|
asyncEnd();
|
|
});
|
|
}
|
|
|
|
{
|
|
// Test error behavior. Changed when fixing issue 33431.
|
|
// Iterable where "current" throws for third value, moveNext on fifth call.
|
|
var m = new MockIterable<int>((n) {
|
|
return n != 5 || (throw "moveNext");
|
|
}, (n) {
|
|
return n != 3 ? n : throw "current";
|
|
});
|
|
asyncStart();
|
|
collectEvents(new Stream<int>.fromIterable(m)).then((events) {
|
|
// Error on "current" does not stop iteration.
|
|
// Error on "moveNext" does.
|
|
Expect.listEquals([
|
|
"value",
|
|
1,
|
|
"value",
|
|
2,
|
|
"error",
|
|
"current",
|
|
"value",
|
|
4,
|
|
"error",
|
|
"moveNext"
|
|
], events);
|
|
asyncEnd();
|
|
});
|
|
}
|
|
|
|
asyncEnd();
|
|
}
|
|
|
|
// Collects value and error events in a list.
|
|
// Value events preceeded by "value", error events by "error".
|
|
// Completes on done event.
|
|
Future<List<Object>> collectEvents(Stream<Object> stream) {
|
|
var c = new Completer<List<Object>>();
|
|
var events = <Object>[];
|
|
stream.listen((value) {
|
|
events..add("value")..add(value);
|
|
}, onError: (error) {
|
|
events..add("error")..add(error);
|
|
}, onDone: () {
|
|
c.complete(events);
|
|
});
|
|
return c.future;
|
|
}
|
|
|
|
// Mock iterable.
|
|
// A `MockIterable<T>(f1, f2)` calls `f1` on `moveNext` calls with incrementing
|
|
// values starting from 1. Calls `f2` on `current` access, with the same integer
|
|
// as the most recent `f1` call.
|
|
class MockIterable<T> extends Iterable<T> {
|
|
final bool Function(int) _onMoveNext;
|
|
final T Function(int) _onCurrent;
|
|
|
|
MockIterable(this._onMoveNext, this._onCurrent);
|
|
|
|
Iterator<T> get iterator => MockIterator(_onMoveNext, _onCurrent);
|
|
}
|
|
|
|
class MockIterator<T> implements Iterator<T> {
|
|
final bool Function(int) _onMoveNext;
|
|
final T Function(int) _onCurrent;
|
|
|
|
int _counter = 0;
|
|
|
|
MockIterator(this._onMoveNext, this._onCurrent);
|
|
|
|
bool moveNext() {
|
|
_counter += 1;
|
|
return _onMoveNext(_counter);
|
|
}
|
|
|
|
T get current {
|
|
return _onCurrent(_counter);
|
|
}
|
|
}
|