| // 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. |
| |
| part of 'expect.dart'; |
| |
| const oneMillisecond = const Duration(milliseconds: 1); |
| |
| typedef CreateStreamFunction = Stream<T> Function<T>(Iterable<T> values); |
| typedef CreateStreamWithErrorsFunction = |
| Stream<T> Function<T>(Iterable<T> values, |
| {bool Function(T element)? isError, required T defaultValue}); |
| |
| Duration durationInMilliseconds(delay) { |
| return delay == null ? Duration.zero : oneMillisecond * delay; |
| } |
| |
| Future runLater(void action(), [int delay = 0]) { |
| asyncStart(); |
| return Future.delayed(durationInMilliseconds(delay), () { |
| action(); |
| asyncEnd(); |
| }); |
| } |
| |
| Future runAfter(Future f, void action()) { |
| asyncStart(); |
| return f.whenComplete((){ |
| action(); |
| asyncEnd(); |
| }); |
| } |
| |
| /// Let the test driver know the test is asynchronous and continues after the |
| /// method main() exits. |
| /// See http://code.google.com/p/co19/issues/detail?id=423 |
| |
| Completer _completer = new Completer(); |
| Future asyncCompleted = _completer.future; |
| |
| int _asyncTestStart() { |
| print("unittest-suite-wait-for-done"); |
| return 0; |
| } |
| |
| int _asyncCounter=_asyncTestStart(); |
| |
| void asyncStart() { |
| _asyncCounter++; |
| } |
| |
| void asyncMultiStart(int delta) { |
| _asyncCounter += delta; |
| } |
| |
| void asyncEnd() { |
| Expect.isFalse(_asyncCounter == 0, "asyncEnd: _asyncCounter==0"); |
| _asyncCounter--; |
| if (_asyncCounter == 0) { |
| print("unittest-suite-success"); |
| _completer.complete(null); |
| } |
| } |
| |
| /*----------------------------*/ |
| |
| class Sync2<T> { |
| Function fire; |
| bool firstPut = false, secondPut = false; |
| T? val1, val2; |
| |
| Sync2(this.fire); |
| |
| void put1(T val) { |
| val1 = val; |
| firstPut = true; |
| if (secondPut) { |
| fire(val1, val2); |
| } |
| } |
| |
| void put2(T val) { |
| val2 = val; |
| secondPut = true; |
| if (firstPut) { |
| fire(val1, val2); |
| } |
| } |
| } |
| /*----------------------------*/ |
| |
| /// [asyncTest] is intended for executing tests with asynchronous nature. |
| /// |
| /// If [setup] is provided, it will be executed first in order to prepare |
| /// necessary environment for the test (i.e. create some files, start some |
| /// services, etc). The [setup] may return some value, which will be passed to |
| /// [test] and to [cleanup]. |
| /// |
| /// [test] is the main test code. It should return [Future] instance, which |
| /// completes when test is over. The future may complete with error, in this |
| /// case the whole test will fail. |
| /// |
| /// If [cleanup] is provided it will be executed after [Future] returned by |
| /// [test] is completed. [cleanup] is always called, regardless of test status. |
| void asyncTest<T>(Future test(T? value), {required Future<T> setup(), |
| required void cleanup(T? value)}) { |
| asyncStart(); |
| Future<T?> setupFuture = setup(); |
| setupFuture.then((T? setupValue) { |
| test(setupValue) |
| .then((_) => asyncEnd()) |
| .whenComplete(() { |
| cleanup(setupValue); |
| }); |
| }); |
| } |
| |
| /// [AsyncExpect] is intended for async test to ease checking [Future] |
| /// completion value and checking Stream content. |
| class AsyncExpect { |
| |
| /// Checks whether the given future completes with expected value. |
| /// |
| /// Returns [Future], that may be used for test cleanup via method |
| /// [whenComplete]. If checks are passed, the returned future completes the |
| /// same way as a supplied one. Otherwise, the returned future completes with |
| /// error. |
| static Future<T> value<T>( |
| T expected, Future<T> future, [String? reason]) { |
| String msg = reason ?? StackTrace.current.toString(); |
| asyncStart(); |
| return future.then((T value){ |
| if (expected is List) { |
| Expect.listEquals(expected, value, msg); |
| } else if (expected is Set) { |
| Expect.setEquals(expected, value as Iterable<Object?>, msg); |
| } else { |
| Expect.equals(expected, value, msg); |
| } |
| asyncEnd(); |
| return value; |
| }); |
| } |
| |
| |
| /// Checks whether the given future completes with expected error. |
| /// |
| /// Returns [Future], that may be used for test cleanup via method |
| /// [whenComplete]. If checks are passed, the returned future completes the |
| /// same way as a supplied one. Otherwise, the returned future completes |
| /// with error. |
| static Future<T?> error<T>( |
| Object error, Future<T> future, [String? reason]) { |
| String msg = reason ?? StackTrace.current.toString(); |
| asyncStart(); |
| return future.then( |
| (_) { |
| Expect.fail("The future is expected to complete with error $msg"); |
| return future; |
| }, |
| onError: (e) { |
| if (error is Function) { |
| Expect.isTrue(Function.apply(error, [e]), msg); |
| } else { |
| Expect.equals(error, e, msg); |
| } |
| asyncEnd(); |
| return null; |
| } |
| ); |
| } |
| |
| /// Checks whether the given stream contains expected data events. |
| /// Any error in the stream is unexpected and wil fail the test. |
| static Future<bool> data<T>( |
| List<T> data, Stream<T> stream, [String? reason]) { |
| String msg = reason ?? StackTrace.current.toString(); |
| Completer<bool> completer = Completer<bool>(); |
| List<T> actual = []; |
| asyncStart(); |
| stream.listen( |
| (T value) { |
| actual.add(value); |
| }, |
| onDone: () { |
| Expect.listEquals(data, actual, msg); |
| asyncEnd(); |
| completer.complete(true); |
| } |
| ); |
| return completer.future; |
| } |
| |
| /// Checks whether the given stream contains expected data and error events. |
| static Future<bool> events<T> |
| (List<T> data, List errors, Stream<T> stream, [String? reason]) { |
| String msg = reason ?? StackTrace.current.toString(); |
| Completer<bool> completer = new Completer<bool>(); |
| List<T> actualData = []; |
| List actualErrors = []; |
| asyncStart(); |
| stream.listen( |
| (T value) { |
| actualData.add(value); |
| }, |
| onError: (error) { |
| actualErrors.add(error); |
| }, |
| onDone: () { |
| Expect.listEquals(data, actualData, msg); |
| Expect.listEquals(errors, actualErrors, msg); |
| asyncEnd(); |
| completer.complete(true); |
| } |
| ); |
| return completer.future; |
| } |
| } |