| // 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. | |
| import 'dart:async'; | |
| import 'package:async/async.dart'; | |
| import 'package:term_glyph/term_glyph.dart' as glyph; | |
| import 'package:test/test.dart'; | |
| import 'utils_new.dart'; | |
| void main() { | |
| setUpAll(() { | |
| glyph.ascii = true; | |
| }); | |
| late Stream stream; | |
| late StreamQueue queue; | |
| late Stream errorStream; | |
| late StreamQueue errorQueue; | |
| setUp(() { | |
| stream = Stream.fromIterable([1, 2, 3, 4, 5]); | |
| queue = StreamQueue(Stream.fromIterable([1, 2, 3, 4, 5])); | |
| errorStream = Stream.fromFuture(Future.error('oh no!', StackTrace.current)); | |
| errorQueue = StreamQueue( | |
| Stream.fromFuture(Future.error('oh no!', StackTrace.current)), | |
| ); | |
| }); | |
| group('emits()', () { | |
| test('matches the first event of a Stream', () { | |
| expect(stream, emits(1)); | |
| }); | |
| test('rejects the first event of a Stream', () { | |
| expect( | |
| expectLater(stream, emits(2)), | |
| throwsTestFailure( | |
| allOf([ | |
| startsWith('Expected: should emit an event that <2>\n'), | |
| endsWith( | |
| ' Which: emitted * 1\n' | |
| ' * 2\n' | |
| ' * 3\n' | |
| ' * 4\n' | |
| ' * 5\n' | |
| ' x Stream closed.\n', | |
| ), | |
| ]), | |
| ), | |
| ); | |
| }); | |
| test('matches and consumes the next event of a StreamQueue', () { | |
| expect(queue, emits(1)); | |
| expect(queue.next, completion(equals(2))); | |
| expect(queue, emits(3)); | |
| expect(queue.next, completion(equals(4))); | |
| }); | |
| test('rejects and does not consume the first event of a StreamQueue', () { | |
| expect( | |
| expectLater(queue, emits(2)), | |
| throwsTestFailure( | |
| allOf([ | |
| startsWith('Expected: should emit an event that <2>\n'), | |
| endsWith( | |
| ' Which: emitted * 1\n' | |
| ' * 2\n' | |
| ' * 3\n' | |
| ' * 4\n' | |
| ' * 5\n' | |
| ' x Stream closed.\n', | |
| ), | |
| ]), | |
| ), | |
| ); | |
| expect(queue, emits(1)); | |
| }); | |
| test('rejects an empty stream', () { | |
| expect( | |
| expectLater(const Stream<Never>.empty(), emits(1)), | |
| throwsTestFailure( | |
| allOf([ | |
| startsWith('Expected: should emit an event that <1>\n'), | |
| endsWith(' Which: emitted x Stream closed.\n'), | |
| ]), | |
| ), | |
| ); | |
| }); | |
| test('forwards a stream error', () { | |
| expect(expectLater(errorStream, emits(1)), throwsA('oh no!')); | |
| }); | |
| test('wraps a normal matcher', () { | |
| expect(queue, emits(lessThan(5))); | |
| expect( | |
| expectLater(queue, emits(greaterThan(5))), | |
| throwsTestFailure(anything), | |
| ); | |
| }); | |
| test('returns a StreamMatcher as-is', () { | |
| expect(queue, emits(emitsThrough(4))); | |
| expect(queue, emits(5)); | |
| }); | |
| }); | |
| group('emitsDone', () { | |
| test('succeeds for an empty stream', () { | |
| expect(const Stream<Never>.empty(), emitsDone); | |
| }); | |
| test('fails for a stream with events', () { | |
| expect( | |
| expectLater(stream, emitsDone), | |
| throwsTestFailure( | |
| allOf([ | |
| startsWith('Expected: should be done\n'), | |
| endsWith( | |
| ' Which: emitted * 1\n' | |
| ' * 2\n' | |
| ' * 3\n' | |
| ' * 4\n' | |
| ' * 5\n' | |
| ' x Stream closed.\n', | |
| ), | |
| ]), | |
| ), | |
| ); | |
| }); | |
| }); | |
| group('emitsError()', () { | |
| test('consumes a matching error', () { | |
| expect(errorQueue, emitsError('oh no!')); | |
| expect(errorQueue.hasNext, completion(isFalse)); | |
| }); | |
| test('fails for a non-matching error', () { | |
| expect( | |
| expectLater(errorStream, emitsError('oh heck')), | |
| throwsTestFailure( | |
| allOf([ | |
| startsWith("Expected: should emit an error that 'oh heck'\n"), | |
| contains(' Which: emitted ! oh no!\n'), | |
| contains( | |
| ' x Stream closed.\n' | |
| " which threw 'oh no!'\n" | |
| ' stack ', | |
| ), | |
| endsWith( | |
| ' which is different.\n' | |
| ' Expected: oh heck\n' | |
| ' Actual: oh no!\n' | |
| ' ^\n' | |
| ' Differ at offset 3\n', | |
| ), | |
| ]), | |
| ), | |
| ); | |
| }); | |
| test('fails for a stream with events', () { | |
| expect( | |
| expectLater(stream, emitsDone), | |
| throwsTestFailure( | |
| allOf([ | |
| startsWith('Expected: should be done\n'), | |
| endsWith( | |
| ' Which: emitted * 1\n' | |
| ' * 2\n' | |
| ' * 3\n' | |
| ' * 4\n' | |
| ' * 5\n' | |
| ' x Stream closed.\n', | |
| ), | |
| ]), | |
| ), | |
| ); | |
| }); | |
| }); | |
| group('mayEmit()', () { | |
| test('consumes a matching event', () { | |
| expect(queue, mayEmit(1)); | |
| expect(queue, emits(2)); | |
| }); | |
| test('allows a non-matching event', () { | |
| expect(queue, mayEmit('fish')); | |
| expect(queue, emits(1)); | |
| }); | |
| }); | |
| group('emitsAnyOf()', () { | |
| test('consumes an event that matches a matcher', () { | |
| expect(queue, emitsAnyOf([2, 1, 3])); | |
| expect(queue, emits(2)); | |
| }); | |
| test('consumes as many events as possible', () { | |
| expect( | |
| queue, | |
| emitsAnyOf([ | |
| 1, | |
| emitsInOrder([1, 2]), | |
| emitsInOrder([1, 2, 3]), | |
| ]), | |
| ); | |
| expect(queue, emits(4)); | |
| }); | |
| test('fails if no matchers match', () { | |
| expect( | |
| expectLater(stream, emitsAnyOf([2, 3, 4])), | |
| throwsTestFailure( | |
| allOf([ | |
| startsWith( | |
| 'Expected: should do one of the following:\n' | |
| ' * emit an event that <2>\n' | |
| ' * emit an event that <3>\n' | |
| ' * emit an event that <4>\n', | |
| ), | |
| endsWith( | |
| ' Which: emitted * 1\n' | |
| ' * 2\n' | |
| ' * 3\n' | |
| ' * 4\n' | |
| ' * 5\n' | |
| ' x Stream closed.\n' | |
| ' which failed all options:\n' | |
| ' * failed to emit an event that <2>\n' | |
| ' * failed to emit an event that <3>\n' | |
| ' * failed to emit an event that <4>\n', | |
| ), | |
| ]), | |
| ), | |
| ); | |
| }); | |
| test('allows an error if any matcher matches', () { | |
| expect(errorStream, emitsAnyOf([1, 2, emitsError('oh no!')])); | |
| }); | |
| test('rethrows an error if no matcher matches', () { | |
| expect( | |
| expectLater(errorStream, emitsAnyOf([1, 2, 3])), | |
| throwsA('oh no!'), | |
| ); | |
| }); | |
| }); | |
| group('emitsInOrder()', () { | |
| test('consumes matching events', () { | |
| expect(queue, emitsInOrder([1, 2, emitsThrough(4)])); | |
| expect(queue, emits(5)); | |
| }); | |
| test("fails if the matchers don't match in order", () { | |
| expect( | |
| expectLater(queue, emitsInOrder([1, 3, 2])), | |
| throwsTestFailure( | |
| allOf([ | |
| startsWith( | |
| 'Expected: should do the following in order:\n' | |
| ' * emit an event that <1>\n' | |
| ' * emit an event that <3>\n' | |
| ' * emit an event that <2>\n', | |
| ), | |
| endsWith( | |
| ' Which: emitted * 1\n' | |
| ' * 2\n' | |
| ' * 3\n' | |
| ' * 4\n' | |
| ' * 5\n' | |
| ' x Stream closed.\n' | |
| " which didn't emit an event that <3>\n", | |
| ), | |
| ]), | |
| ), | |
| ); | |
| }); | |
| }); | |
| group('emitsThrough()', () { | |
| test('consumes events including those matching the matcher', () { | |
| expect(queue, emitsThrough(emitsInOrder([3, 4]))); | |
| expect(queue, emits(5)); | |
| }); | |
| test('consumes the entire queue with emitsDone', () { | |
| expect(queue, emitsThrough(emitsDone)); | |
| expect(queue.hasNext, completion(isFalse)); | |
| }); | |
| test('fails if the queue never matches the matcher', () { | |
| expect( | |
| expectLater(queue, emitsThrough(6)), | |
| throwsTestFailure( | |
| allOf([ | |
| startsWith('Expected: should eventually emit an event that <6>\n'), | |
| endsWith( | |
| ' Which: emitted * 1\n' | |
| ' * 2\n' | |
| ' * 3\n' | |
| ' * 4\n' | |
| ' * 5\n' | |
| ' x Stream closed.\n' | |
| ' which never did emit an event that <6>\n', | |
| ), | |
| ]), | |
| ), | |
| ); | |
| }); | |
| }); | |
| group('mayEmitMultiple()', () { | |
| test('consumes multiple instances of the given matcher', () { | |
| expect(queue, mayEmitMultiple(lessThan(3))); | |
| expect(queue, emits(3)); | |
| }); | |
| test('consumes zero instances of the given matcher', () { | |
| expect(queue, mayEmitMultiple(6)); | |
| expect(queue, emits(1)); | |
| }); | |
| test("doesn't rethrow errors", () { | |
| expect(errorQueue, mayEmitMultiple(1)); | |
| expect(errorQueue, emitsError('oh no!')); | |
| }); | |
| }); | |
| group('neverEmits()', () { | |
| test('succeeds if the event never matches', () { | |
| expect(queue, neverEmits(6)); | |
| expect(queue, emits(1)); | |
| }); | |
| test('fails if the event matches', () { | |
| expect( | |
| expectLater(stream, neverEmits(4)), | |
| throwsTestFailure( | |
| allOf([ | |
| startsWith('Expected: should never emit an event that <4>\n'), | |
| endsWith( | |
| ' Which: emitted * 1\n' | |
| ' * 2\n' | |
| ' * 3\n' | |
| ' * 4\n' | |
| ' * 5\n' | |
| ' x Stream closed.\n' | |
| ' which after 3 events did emit an event that <4>\n', | |
| ), | |
| ]), | |
| ), | |
| ); | |
| }); | |
| test('fails if emitsDone matches', () { | |
| expect( | |
| expectLater(stream, neverEmits(emitsDone)), | |
| throwsTestFailure(anything), | |
| ); | |
| }); | |
| test("doesn't rethrow errors", () { | |
| expect(errorQueue, neverEmits(6)); | |
| expect(errorQueue, emitsError('oh no!')); | |
| }); | |
| }); | |
| group('emitsInAnyOrder()', () { | |
| test('consumes events that match in any order', () { | |
| expect(queue, emitsInAnyOrder([3, 1, 2])); | |
| expect(queue, emits(4)); | |
| }); | |
| test("fails if the events don't match in any order", () { | |
| expect( | |
| expectLater(stream, emitsInAnyOrder([4, 1, 2])), | |
| throwsTestFailure( | |
| allOf([ | |
| startsWith( | |
| 'Expected: should do the following in any order:\n' | |
| ' * emit an event that <4>\n' | |
| ' * emit an event that <1>\n' | |
| ' * emit an event that <2>\n', | |
| ), | |
| endsWith( | |
| ' Which: emitted * 1\n' | |
| ' * 2\n' | |
| ' * 3\n' | |
| ' * 4\n' | |
| ' * 5\n' | |
| ' x Stream closed.\n', | |
| ), | |
| ]), | |
| ), | |
| ); | |
| }); | |
| test("doesn't rethrow if some ordering matches", () { | |
| expect(errorQueue, emitsInAnyOrder([emitsDone, emitsError('oh no!')])); | |
| }); | |
| test('rethrows if no ordering matches', () { | |
| expect( | |
| expectLater(errorQueue, emitsInAnyOrder([1, emitsError('oh no!')])), | |
| throwsA('oh no!'), | |
| ); | |
| }); | |
| }); | |
| test('A custom StreamController doesn\'t hang on close', () async { | |
| var controller = StreamController<void>(); | |
| var done = expectLater(controller.stream, emits(null)); | |
| controller.add(null); | |
| await done; | |
| await controller.close(); | |
| }); | |
| } |