| // 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; |
| |
| const ONE_MS = 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 defVal}); |
| |
| Duration durationMs(delay) { |
| return delay == null ? Duration.zero : ONE_MS * delay; |
| } |
| |
| Future runLater(void action(), [int delay = 0]) { |
| asyncStart(); |
| return new Future.delayed(durationMs(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 co19 issue #423 |
| /// 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++; |
| // print("asyncStart"); |
| } |
| |
| void asyncMultiStart(int delta) { |
| // print("asyncMultiStart $delta"); |
| _asyncCounter += delta; |
| } |
| |
| void asyncEnd() { |
| // print("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 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's 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 the Future, that may be used for test cleanup via method |
| /// whenComplete(). If checks are passed, the returned future completes |
| /// the same way as supplied one. Otherwise, the returned future completes |
| /// with error. |
| static Future<T> value<T>(T expected, Future<T> future, [String? reason = null]) { |
| if (reason == null){ |
| reason = StackTrace.current.toString(); |
| } |
| asyncStart(); |
| return future.then((T value){ |
| if (expected is List) { |
| Expect.listEquals(expected, value, reason); |
| } else if (expected is Set) { |
| Expect.setEquals(expected, value as Iterable<Object?>, reason); |
| } else { |
| Expect.equals(expected, value, reason); |
| } |
| asyncEnd(); |
| return value; |
| }); |
| } |
| |
| |
| /// Checks whether the given future completes with expected error. |
| /// Returns the Future, that may be used for test cleanup via method |
| /// whenComplete(). If checks are passed, the returned future completes |
| /// the same way as supplied one. Otherwise, the returned future completes |
| /// with error. |
| static Future<T?> error<T>(Object error, Future<T> future, [String? reason = null]) { |
| if (reason == null){ |
| reason = StackTrace.current.toString(); |
| } |
| asyncStart(); |
| return future.then( |
| (_) { |
| Expect.fail("The future is expected to complete with error $reason"); |
| return future; |
| }, |
| onError: (e) { |
| // print("On error called"); |
| if (error is Function) { |
| Expect.isTrue(Function.apply(error, [e]), reason); |
| } else { |
| Expect.equals(error, e, reason); |
| } |
| 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 = null]) { |
| if (reason == null){ |
| reason = StackTrace.current.toString(); |
| } |
| Completer<bool> completer = new Completer<bool>(); |
| List<T> actual = []; |
| asyncStart(); |
| stream.listen( |
| (T value) { |
| actual.add(value); |
| }, |
| onDone: () { |
| Expect.listEquals(data, actual, reason); |
| 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 = null]) { |
| if (reason == null){ |
| 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, reason); |
| Expect.listEquals(errors, actualErrors, reason); |
| asyncEnd(); |
| completer.complete(true); |
| } |
| ); |
| return completer.future; |
| } |
| } |