Merge branch 'master' into top-level-equals
diff --git a/pkgs/checks/lib/checks.dart b/pkgs/checks/lib/checks.dart
index db8b18e..a390e75 100644
--- a/pkgs/checks/lib/checks.dart
+++ b/pkgs/checks/lib/checks.dart
@@ -7,7 +7,7 @@
export 'src/extensions/async.dart'
show FutureChecks, StreamChecks, WithQueueExtension;
export 'src/extensions/core.dart'
- show BoolChecks, ComparableChecks, CoreChecks, NullableChecks;
+ show BoolChecks, ComparableChecks, CoreChecks, NullableChecks, equals;
export 'src/extensions/function.dart' show FunctionChecks;
export 'src/extensions/iterable.dart' show IterableChecks;
export 'src/extensions/map.dart' show MapChecks;
diff --git a/pkgs/checks/lib/src/extensions/async.dart b/pkgs/checks/lib/src/extensions/async.dart
index 1fd360b..8f2f073 100644
--- a/pkgs/checks/lib/src/extensions/async.dart
+++ b/pkgs/checks/lib/src/extensions/async.dart
@@ -230,8 +230,8 @@
///
/// ```dart
/// await check(someStream).withQueue.inOrder([
- /// (s) => s.emits((e) => e.equals(0)),
- /// (s) => s.emits((e) => e.equals(1)),
+ /// (s) => s.emits(equals(0)),
+ /// (s) => s.emits(equals(1)),
// ]);
/// ```
///
diff --git a/pkgs/checks/lib/src/extensions/core.dart b/pkgs/checks/lib/src/extensions/core.dart
index 6212f91..da1eac1 100644
--- a/pkgs/checks/lib/src/extensions/core.dart
+++ b/pkgs/checks/lib/src/extensions/core.dart
@@ -102,6 +102,19 @@
}
}
+/// Returns a [Condition] checking that the actual value is equal to [expected]
+/// by operator `==`.
+///
+/// This is a shortcut for `(Subject<T> it) => it..equals(expected)`.
+Condition<T> equals<T>(T expected) => (Subject<T> subject) {
+ if (subject is Subject<String> && expected is String) {
+ // String specializes `equals` with a better failure
+ (subject as Subject<String>).equals(expected);
+ } else {
+ subject.equals(expected);
+ }
+ };
+
extension BoolChecks on Subject<bool> {
void isTrue() {
context.expect(
diff --git a/pkgs/checks/test/describe_test.dart b/pkgs/checks/test/describe_test.dart
index d117a7b..fedd620 100644
--- a/pkgs/checks/test/describe_test.dart
+++ b/pkgs/checks/test/describe_test.dart
@@ -12,7 +12,7 @@
check(describe((_) {})).isEmpty();
});
test('includes condition clauses', () {
- check(describe((it) => it.equals(1))).deepEquals([' equals <1>']);
+ check(describe(equals(1))).deepEquals([' equals <1>']);
});
test('includes nested clauses', () {
check(describe<String>((it) => it.length.equals(1))).deepEquals([
diff --git a/pkgs/checks/test/extensions/async_test.dart b/pkgs/checks/test/extensions/async_test.dart
index 43ba5d7..3484fb2 100644
--- a/pkgs/checks/test/extensions/async_test.dart
+++ b/pkgs/checks/test/extensions/async_test.dart
@@ -16,11 +16,11 @@
group('FutureChecks', () {
group('completes', () {
test('succeeds for a future that completes to a value', () async {
- await check(_futureSuccess()).completes((it) => it.equals(42));
+ await check(_futureSuccess()).completes(equals(42));
});
test('rejects futures which complete as errors', () async {
await check(_futureFail()).isRejectedByAsync(
- (it) => it.completes((it) => it.equals(1)),
+ (it) => it.completes(equals(1)),
actual: ['a future that completes as an error'],
which: ['threw <UnimplementedError> at:', 'fake trace'],
);
@@ -29,7 +29,7 @@
await check((Subject<Future> it) => it.completes())
.hasAsyncDescriptionWhich(
(it) => it.deepEquals([' completes to a value']));
- await check((Subject<Future> it) => it.completes((it) => it.equals(42)))
+ await check((Subject<Future> it) => it.completes(equals(42)))
.hasAsyncDescriptionWhich((it) => it.deepEquals([
' completes to a value that:',
' equals <42>',
@@ -127,7 +127,7 @@
group('StreamChecks', () {
group('emits', () {
test('succeeds for a stream that emits a value', () async {
- await check(_countingStream(5)).emits((it) => it.equals(0));
+ await check(_countingStream(5)).emits(equals(0));
});
test('fails for a stream that closes without emitting', () async {
await check(_countingStream(0)).isRejectedByAsync(
@@ -147,8 +147,7 @@
await check((Subject<StreamQueue<void>> it) => it.emits())
.hasAsyncDescriptionWhich(
(it) => it.deepEquals([' emits a value']));
- await check((Subject<StreamQueue<int>> it) =>
- it.emits((it) => it.equals(42)))
+ await check((Subject<StreamQueue<int>> it) => it.emits(equals(42)))
.hasAsyncDescriptionWhich((it) => it.deepEquals([
' emits a value that:',
' equals <42>',
@@ -209,26 +208,26 @@
test('uses a transaction', () async {
final queue = _countingStream(1);
await softCheckAsync<StreamQueue<int>>(queue, (it) => it.emitsError());
- await check(queue).emits((it) => it.equals(0));
+ await check(queue).emits(equals(0));
});
});
group('emitsThrough', () {
test('succeeds for a stream that eventuall emits a matching value',
() async {
- await check(_countingStream(5)).emitsThrough((it) => it.equals(4));
+ await check(_countingStream(5)).emitsThrough(equals(4));
});
test('fails for a stream that closes without emitting a matching value',
() async {
await check(_countingStream(4)).isRejectedByAsync(
- (it) => it.emitsThrough((it) => it.equals(5)),
+ (it) => it.emitsThrough(equals(5)),
actual: ['a stream'],
which: ['ended after emitting 4 elements with none matching'],
);
});
test('can be described', () async {
- await check((Subject<StreamQueue<int>> it) =>
- it.emitsThrough((it) => it.equals(42)))
+ await check(
+ (Subject<StreamQueue<int>> it) => it.emitsThrough(equals(42)))
.hasAsyncDescriptionWhich((it) => it.deepEquals([
' emits any values then emits a value that:',
' equals <42>'
@@ -236,24 +235,22 @@
});
test('uses a transaction', () async {
final queue = _countingStream(1);
- await softCheckAsync(
- queue,
- (Subject<StreamQueue<int>> it) =>
- it.emitsThrough((it) => it.equals(42)));
- check(queue).emits((it) => it.equals(0));
+ await softCheckAsync(queue,
+ (Subject<StreamQueue<int>> it) => it.emitsThrough(equals(42)));
+ check(queue).emits(equals(0));
});
test('consumes events', () async {
final queue = _countingStream(3);
- await check(queue).emitsThrough((it) => it.equals(1));
- await check(queue).emits((it) => it.equals(2));
+ await check(queue).emitsThrough(equals(1));
+ await check(queue).emits(equals(2));
});
});
group('emitsInOrder', () {
test('succeeds for happy case', () async {
await check(_countingStream(2)).inOrder([
- (it) => it.emits((it) => it.equals(0)),
- (it) => it.emits((it) => it.equals(1)),
+ (it) => it.emits(equals(0)),
+ (it) => it.emits(equals(1)),
(it) => it.isDone(),
]);
});
@@ -270,8 +267,7 @@
});
test('nestes the report for deep failures', () async {
await check(_countingStream(2)).isRejectedByAsync(
- (it) => it.inOrder(
- [(it) => it.emits(), (it) => it.emits((it) => it.equals(2))]),
+ (it) => it.inOrder([(it) => it.emits(), (it) => it.emits(equals(2))]),
actual: ['a stream'],
which: [
'satisfied 1 conditions then',
@@ -294,21 +290,21 @@
await softCheckAsync<StreamQueue<int>>(
queue,
(it) => it.inOrder([
- (it) => it.emits((it) => it.equals(0)),
- (it) => it.emits((it) => it.equals(1)),
- (it) => it.emits((it) => it.equals(42)),
+ (it) => it.emits(equals(0)),
+ (it) => it.emits(equals(1)),
+ (it) => it.emits(equals(42)),
]));
await check(queue).inOrder([
- (it) => it.emits((it) => it.equals(0)),
- (it) => it.emits((it) => it.equals(1)),
- (it) => it.emits((it) => it.equals(2)),
+ (it) => it.emits(equals(0)),
+ (it) => it.emits(equals(1)),
+ (it) => it.emits(equals(2)),
(it) => it.isDone(),
]);
});
test('consumes events', () async {
final queue = _countingStream(3);
await check(queue).inOrder([(it) => it.emits(), (it) => it.emits()]);
- await check(queue).emits((it) => it.equals(2));
+ await check(queue).emits(equals(2));
});
});
@@ -316,18 +312,17 @@
test(
'succeeds for a stream that closes without emitting a matching value',
() async {
- await check(_countingStream(5)).neverEmits((it) => it.equals(5));
+ await check(_countingStream(5)).neverEmits(equals(5));
});
test('fails for a stream that emits a matching value', () async {
await check(_countingStream(6)).isRejectedByAsync(
- (it) => it.neverEmits((it) => it.equals(5)),
+ (it) => it.neverEmits(equals(5)),
actual: ['a stream'],
which: ['emitted <5>', 'following 5 other items'],
);
});
test('can be described', () async {
- await check((Subject<StreamQueue<int>> it) =>
- it.neverEmits((it) => it.equals(42)))
+ await check((Subject<StreamQueue<int>> it) => it.neverEmits(equals(42)))
.hasAsyncDescriptionWhich((it) => it.deepEquals([
' never emits a value that:',
' equals <42>',
@@ -336,10 +331,10 @@
test('uses a transaction', () async {
final queue = _countingStream(2);
await softCheckAsync<StreamQueue<int>>(
- queue, (it) => it.neverEmits((it) => it.equals(1)));
+ queue, (it) => it.neverEmits(equals(1)));
await check(queue).inOrder([
- (it) => it.emits((it) => it.equals(0)),
- (it) => it.emits((it) => it.equals(1)),
+ (it) => it.emits(equals(0)),
+ (it) => it.emits(equals(1)),
(it) => it.isDone(),
]);
});
@@ -347,31 +342,30 @@
group('mayEmit', () {
test('succeeds for a stream that emits a matching value', () async {
- await check(_countingStream(1)).mayEmit((it) => it.equals(0));
+ await check(_countingStream(1)).mayEmit(equals(0));
});
test('succeeds for a stream that emits an error', () async {
- await check(_countingStream(1, errorAt: 0))
- .mayEmit((it) => it.equals(0));
+ await check(_countingStream(1, errorAt: 0)).mayEmit(equals(0));
});
test('succeeds for a stream that closes', () async {
- await check(_countingStream(0)).mayEmit((it) => it.equals(42));
+ await check(_countingStream(0)).mayEmit(equals(42));
});
test('consumes a matching event', () async {
final queue = _countingStream(2);
await softCheckAsync<StreamQueue<int>>(
- queue, (it) => it.mayEmit((it) => it.equals(0)));
- await check(queue).emits((it) => it.equals(1));
+ queue, (it) => it.mayEmit(equals(0)));
+ await check(queue).emits(equals(1));
});
test('does not consume a non-matching event', () async {
final queue = _countingStream(2);
await softCheckAsync<StreamQueue<int>>(
- queue, (it) => it.mayEmit((it) => it.equals(1)));
- await check(queue).emits((it) => it.equals(0));
+ queue, (it) => it.mayEmit(equals(1)));
+ await check(queue).emits(equals(0));
});
test('does not consume an error', () async {
final queue = _countingStream(1, errorAt: 0);
await softCheckAsync<StreamQueue<int>>(
- queue, (it) => it.mayEmit((it) => it.equals(0)));
+ queue, (it) => it.mayEmit(equals(0)));
await check(queue).emitsError<UnimplementedError>(
(it) => it.has((e) => e.message, 'message').equals('Error at 1'));
});
@@ -379,31 +373,30 @@
group('mayEmitMultiple', () {
test('succeeds for a stream that emits a matching value', () async {
- await check(_countingStream(1)).mayEmitMultiple((it) => it.equals(0));
+ await check(_countingStream(1)).mayEmitMultiple(equals(0));
});
test('succeeds for a stream that emits an error', () async {
- await check(_countingStream(1, errorAt: 0))
- .mayEmitMultiple((it) => it.equals(0));
+ await check(_countingStream(1, errorAt: 0)).mayEmitMultiple(equals(0));
});
test('succeeds for a stream that closes', () async {
- await check(_countingStream(0)).mayEmitMultiple((it) => it.equals(42));
+ await check(_countingStream(0)).mayEmitMultiple(equals(42));
});
test('consumes matching events', () async {
final queue = _countingStream(3);
await softCheckAsync<StreamQueue<int>>(
queue, (it) => it.mayEmitMultiple((it) => it.isLessThan(2)));
- await check(queue).emits((it) => it.equals(2));
+ await check(queue).emits(equals(2));
});
test('consumes no events if no events match', () async {
final queue = _countingStream(2);
await softCheckAsync<StreamQueue<int>>(
queue, (it) => it.mayEmitMultiple((it) => it.isLessThan(0)));
- await check(queue).emits((it) => it.equals(0));
+ await check(queue).emits(equals(0));
});
test('does not consume an error', () async {
final queue = _countingStream(1, errorAt: 0);
await softCheckAsync<StreamQueue<int>>(
- queue, (it) => it.mayEmitMultiple((it) => it.equals(0)));
+ queue, (it) => it.mayEmitMultiple(equals(0)));
await check(queue).emitsError<UnimplementedError>(
(it) => it.has((e) => e.message, 'message').equals('Error at 1'));
});
@@ -428,7 +421,7 @@
test('uses a transaction', () async {
final queue = _countingStream(1);
await softCheckAsync<StreamQueue<int>>(queue, (it) => it.isDone());
- await check(queue).emits((it) => it.equals(0));
+ await check(queue).emits(equals(0));
});
test('can be described', () async {
await check((Subject<StreamQueue<int>> it) => it.isDone())
@@ -438,16 +431,14 @@
group('emitsAnyOf', () {
test('succeeds for a stream that matches one condition', () async {
- await check(_countingStream(1)).anyOf([
- (it) => it.emits((it) => it.equals(42)),
- (it) => it.emits((it) => it.equals(0))
- ]);
+ await check(_countingStream(1))
+ .anyOf([(it) => it.emits(equals(42)), (it) => it.emits(equals(0))]);
});
test('fails for a stream that matches no conditions', () async {
await check(_countingStream(0)).isRejectedByAsync(
(it) => it.anyOf([
(it) => it.emits(),
- (it) => it.emitsThrough((it) => it.equals(1)),
+ (it) => it.emitsThrough(equals(1)),
]),
actual: [
'a stream'
@@ -463,8 +454,8 @@
test('includes nested details for nested failures', () async {
await check(_countingStream(1)).isRejectedByAsync(
(it) => it.anyOf([
- (it) => it.emits((it) => it.equals(42)),
- (it) => it.emitsThrough((it) => it.equals(10)),
+ (it) => it.emits(equals(42)),
+ (it) => it.emitsThrough(equals(10)),
]),
actual: [
'a stream'
@@ -490,18 +481,16 @@
await softCheckAsync<StreamQueue<int>>(
queue,
(it) => it.anyOf([
- (it) => it.emits((it) => it.equals(10)),
- (it) => it.emitsThrough((it) => it.equals(42)),
+ (it) => it.emits(equals(10)),
+ (it) => it.emitsThrough(equals(42)),
]));
- await check(queue).emits((it) => it.equals(0));
+ await check(queue).emits(equals(0));
});
test('consumes events', () async {
final queue = _countingStream(3);
- await check(queue).anyOf([
- (it) => it.emits((it) => it.equals(1)),
- (it) => it.emitsThrough((it) => it.equals(1))
- ]);
- await check(queue).emits((it) => it.equals(2));
+ await check(queue).anyOf(
+ [(it) => it.emits(equals(1)), (it) => it.emitsThrough(equals(1))]);
+ await check(queue).emits(equals(2));
});
});
});
diff --git a/pkgs/checks/test/extensions/iterable_test.dart b/pkgs/checks/test/extensions/iterable_test.dart
index 3d31a81..73c0881 100644
--- a/pkgs/checks/test/extensions/iterable_test.dart
+++ b/pkgs/checks/test/extensions/iterable_test.dart
@@ -66,8 +66,8 @@
.isRejectedBy((it) => it.contains(2), which: ['does not contain <2>']);
});
test('any', () {
- check(_testIterable).any((it) => it.equals(1));
- check(_testIterable).isRejectedBy((it) => it.any((it) => it.equals(2)),
+ check(_testIterable).any(equals(1));
+ check(_testIterable).isRejectedBy((it) => it.any(equals(2)),
which: ['Contains no matching element']);
});
@@ -152,14 +152,14 @@
group('unorderedMatches', () {
test('success for happy case', () {
- check(_testIterable).unorderedMatches(
- _testIterable.toList().reversed.map((i) => (it) => it.equals(i)));
+ check(_testIterable)
+ .unorderedMatches(_testIterable.toList().reversed.map(equals));
});
test('reports unmatched elements', () {
check(_testIterable).isRejectedBy(
- (it) => it.unorderedMatches(_testIterable
- .followedBy([42, 100]).map((i) => (it) => it.equals(i))),
+ (it) => it.unorderedMatches(
+ _testIterable.followedBy([42, 100]).map(equals)),
which: [
'has no element matching the condition at index 2:',
' equals <42>',
@@ -169,8 +169,7 @@
test('reports unexpected elements', () {
check(_testIterable.followedBy([42, 100])).isRejectedBy(
- (it) => it
- .unorderedMatches(_testIterable.map((i) => (it) => it.equals(i))),
+ (it) => it.unorderedMatches(_testIterable.map(equals)),
which: [
'has an unmatched element at index 2: <42>',
'and 1 other unmatched elements'
diff --git a/pkgs/checks/test/extensions/map_test.dart b/pkgs/checks/test/extensions/map_test.dart
index 99d1b4f..1b2684c 100644
--- a/pkgs/checks/test/extensions/map_test.dart
+++ b/pkgs/checks/test/extensions/map_test.dart
@@ -83,9 +83,9 @@
});
});
test('containsKeyThat', () {
- check(_testMap).containsKeyThat((it) => it.equals('a'));
+ check(_testMap).containsKeyThat(equals('a'));
check(_testMap).isRejectedBy(
- (it) => it.containsKeyThat((it) => it.equals('c')),
+ (it) => it.containsKeyThat(equals('c')),
which: ['Contains no matching key'],
);
});
@@ -109,9 +109,9 @@
});
});
test('containsValueThat', () {
- check(_testMap).containsValueThat((it) => it.equals(1));
+ check(_testMap).containsValueThat(equals(1));
check(_testMap).isRejectedBy(
- (it) => it.containsValueThat((it) => it.equals(3)),
+ (it) => it.containsValueThat(equals(3)),
which: ['Contains no matching value'],
);
});