blob: 03a06650c2de9c87e2bdeb613bf8c3fe1cccbacf [file] [log] [blame]
// Copyright (c) 2017, 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.
// @dart = 2.9
import 'dart:async';
import "package:expect/expect.dart";
import "package:async_helper/async_helper.dart";
class A {
const A();
}
class B extends A {
const B();
}
main() {
asyncStart();
// Correct behavior.
for (var eq in [null, (a, b) => a == b]) {
checkStream(mkSingleStream, eq, "single");
checkBroadcastStream(mkBroadcastStream, eq, "broadcast");
checkBroadcastStream(
() => mkSingleStream().asBroadcastStream(), eq, "asBroadcast");
}
// Regression test. Multiple listens on the same broadcast distinct stream.
var stream = mkBroadcastStream().distinct();
expectStream(stream, [1, 2, 3, 2], "broadcast.distinct#1");
expectStream(stream, [1, 2, 3, 2], "broadcast.distinct#2");
// Doesn't ignore equality.
expectStream(
new Stream.fromIterable([1, 2, 1, 3, 3]).distinct((a, b) => false),
[1, 2, 1, 3, 3],
"kFalse");
expectStream(
new Stream.fromIterable([1, 2, 1, 3, 3]).distinct((a, b) => true),
[1],
"kTrue");
expectStream(
new Stream.fromIterable([1, 2, 1, 3, 3]).distinct((a, b) => a != b),
[1, 1],
"neq");
expectStream(
new Stream.fromIterable([1, 2, 1, 3, 3]).distinct((a, b) => 2 == b),
[1, 1, 3, 3],
"is2");
// Forwards errors as errors.
expectStream(
new Stream.fromIterable([1, "E1", 2, "E2", 2, 3])
.map((v) => (v is String) ? (throw v) : v) // Make strings errors.
.distinct()
.transform(reifyErrors),
[1, "[E1]", 2, "[E2]", 3],
"errors");
// Equality throwing acts like error.
expectStream(
new Stream.fromIterable([1, "E1", 1, 2, "E2", 3])
.distinct((a, b) => (b is String) ? (throw b) : (a == b))
.transform(reifyErrors),
[1, "[E1]", 2, "[E2]", 3],
"eq-throws");
// Operator== throwing acts like error.
expectStream(
new Stream.fromIterable([1, 1, 2, 2, 1, 3])
.map((v) => new T(v))
.distinct()
.transform(reifyErrors.cast<T, dynamic>())
.map((v) => v is T ? v.value : "$v"),
[1, "[2]", "[2]", 3],
"==-throws");
asyncEnd();
}
checkStream(mkStream, eq, name) {
expectStream(mkStream().distinct(eq), [1, 2, 3, 2], "$name.distinct");
expectStream(mkStream().expand((e) => [e, e]).distinct(eq), [1, 2, 3, 2],
"$name.expand.distinct");
expectStream(mkStream().where((x) => x != 3).distinct(eq), [1, 2],
"$name.where.distinct");
}
checkBroadcastStream(mkStream, eq, name) {
var stream = mkStream();
// Run all the tests, multiple times each.
checkStream(() => stream, eq, "$name#1");
checkStream(() => stream, eq, "$name#2");
}
mkSingleStream() async* {
yield 1;
yield 2;
yield 3;
yield 2;
}
mkBroadcastStream() {
var c = new StreamController.broadcast();
c.onListen = () {
c.addStream(mkSingleStream()).whenComplete(c.close);
};
return c.stream;
}
expectStream(stream, list, [name]) {
asyncStart();
return stream.toList().then((events) {
Expect.listEquals(list, events, name);
asyncEnd();
});
}
// Class where operator== throws.
class T {
final int value;
T(this.value);
int get hashCode => value.hashCode;
bool operator ==(Object other) =>
other is T && ((other.value == 2) ? throw 2 : (value == other.value));
}
StreamTransformer reifyErrors =
new StreamTransformer.fromHandlers(handleError: (e, s, sink) {
sink.add("[$e]");
});