diff --git a/lib/src/spread_args_helper.dart b/lib/src/spread_args_helper.dart index 41411b93780f4f2d68f4f6941dad6186b668f4f4..b3021eb26ca499e1252cd7471bfd346484f599ef 100644 --- a/lib/src/spread_args_helper.dart +++ b/lib/src/spread_args_helper.dart @@ -1,5 +1,12 @@ part of unittest; +const _PLACE_HOLDER = const _ArgPlaceHolder(); + +/// Used to track unused positional args. +class _ArgPlaceHolder { + const _ArgPlaceHolder(); +} + /** Simulates spread arguments using named arguments. */ // TODO(sigmund): remove this class and simply use a closure with named // arguments (if still applicable). @@ -14,7 +21,7 @@ class _SpreadArgsHelper { bool complete; _SpreadArgsHelper(Function callback, int minExpected, int maxExpected, - Function isDone, String id) + String id, {bool isDone()}) : this.callback = callback, minExpectedCalls = minExpected, maxExpectedCalls = (maxExpected == 0 && minExpected > 0) @@ -90,31 +97,49 @@ class _SpreadArgsHelper { } } - invoke0() { - return _guardAsync( - () { - if (shouldCallBack()) { - return callback(); - } - }, - after, testCase); - } + /// Returns a function that has as many required + positional arguments as + /// [callback] (up to a total of 6). + /// + /// Optional positional arguments are supported by using const place-holders + Function get func { + if (callback is _Func6) return _max6; + if (callback is _Func5) return _max5; + if (callback is _Func4) return _max4; + if (callback is _Func3) return _max3; + if (callback is _Func2) return _max2; + if (callback is _Func1) return _max1; + if (callback is _Func0) return _max0; - invoke1(arg1) { - return _guardAsync( - () { - if (shouldCallBack()) { - return callback(arg1); - } - }, - after, testCase); + throw new ArgumentError( + 'The callback argument has more than 6 required arguments'); } - invoke2(arg1, arg2) { + /// This indirection is critical. It ensures the returned function has an + /// argument count of zero. + _max0() => _max6(); + + _max1([a0 = _PLACE_HOLDER]) => _max6(a0); + + _max2([a0 = _PLACE_HOLDER, a1 = _PLACE_HOLDER]) => _max6(a0, a1); + + _max3([a0 = _PLACE_HOLDER, a1 = _PLACE_HOLDER, a2 = _PLACE_HOLDER]) => + _max6(a0, a1, a2); + + _max4([a0 = _PLACE_HOLDER, a1 = _PLACE_HOLDER, a2 = _PLACE_HOLDER, + a3 = _PLACE_HOLDER]) => _max6(a0, a1, a2, a3); + + _max5([a0 = _PLACE_HOLDER, a1 = _PLACE_HOLDER, a2 = _PLACE_HOLDER, + a3 = _PLACE_HOLDER, a4 = _PLACE_HOLDER]) => _max6(a0, a1, a2, a3, a4); + + _max6([a0 = _PLACE_HOLDER, a1 = _PLACE_HOLDER, a2 = _PLACE_HOLDER, + a3 = _PLACE_HOLDER, a4 = _PLACE_HOLDER, a5 = _PLACE_HOLDER]) { + var args = [a0, a1, a2, a3, a4, a5]; + args.removeWhere((a) => a == _PLACE_HOLDER); + return _guardAsync( () { if (shouldCallBack()) { - return callback(arg1, arg2); + return Function.apply(callback, args); } }, after, testCase); @@ -131,3 +156,11 @@ class _SpreadArgsHelper { } } } + +typedef _Func0(); +typedef _Func1(a); +typedef _Func2(a, b); +typedef _Func3(a, b, c); +typedef _Func4(a, b, c, d); +typedef _Func5(a, b, c, d, e); +typedef _Func6(a, b, c, d, e, f); diff --git a/lib/unittest.dart b/lib/unittest.dart index da95faecc9f03ca1ef539d431f88a8372c0f7b85..9add42c8b1bb6928ae3d3ebb81d4c20faac0975c 100644 --- a/lib/unittest.dart +++ b/lib/unittest.dart @@ -325,22 +325,8 @@ void solo_test(String spec, TestFunction body) { * bound. */ Function expectAsync(Function callback, - {int count: 1, int max: 0, String id}) { - var minArgs = _minArgs(callback); - - switch(minArgs) { - case 0: - return new _SpreadArgsHelper(callback, count, max, null, id).invoke0; - case 1: - return new _SpreadArgsHelper(callback, count, max, null, id).invoke1; - case 2: - return new _SpreadArgsHelper(callback, count, max, null, id).invoke2; - default: - // _minArgs throws an argument exception if the arg count is > 2. - // this is just for paranoia - throw new StateError('Should never get here'); - } -} + {int count: 1, int max: 0, String id}) => + new _SpreadArgsHelper(callback, count, max, id).func; /** * *Deprecated* @@ -382,22 +368,8 @@ Function expectAsync2(Function callback, * identify the callback in error messages (for example if it is called * after the test case is complete). */ -Function expectAsyncUntil(Function callback, Function isDone, {String id}) { - var minArgs = _minArgs(callback); - - switch(minArgs) { - case 0: - return new _SpreadArgsHelper(callback, 0, -1, isDone, id).invoke0; - case 1: - return new _SpreadArgsHelper(callback, 0, -1, isDone, id).invoke1; - case 2: - return new _SpreadArgsHelper(callback, 0, -1, isDone, id).invoke2; - default: - // _minArgs throws an argument exception if the arg count is > 2. - // this is just for paranoia - throw new StateError('Should never get here'); - } -} +Function expectAsyncUntil(Function callback, bool isDone(), {String id}) => + new _SpreadArgsHelper(callback, 0, -1, id, isDone: isDone).func; /** * *Deprecated* @@ -770,18 +742,3 @@ Trace _getTrace(stack) { return frame.package != 'unittest' || frame.member != 'TestCase._runTest'; })).terse.foldFrames((frame) => frame.package == 'unittest' || frame.isCore); } - -typedef _Func0(); -typedef _Func1(a); -typedef _Func2(a, b); - -/** - * Throws an [ArgumentError] if the callback has more than 2 required arguments. - */ -int _minArgs(Function callback) { - if (callback is _Func0) return 0; - if (callback is _Func1) return 1; - if (callback is _Func2) return 2; - throw new ArgumentError( - 'The callback argument has more than 2 required arguments.'); -} diff --git a/test/missing_tick_test.dart b/test/missing_tick_test.dart index 92ab8914704d7eac0c2491d2fbf3d1c307990fdb..19c5b8946ebf00754d92cbce4a43e308cadb1f14 100644 --- a/test/missing_tick_test.dart +++ b/test/missing_tick_test.dart @@ -10,7 +10,7 @@ main() { config.timeout = const Duration(seconds: 2); group('Broken', () { test('test that should time out', () { - expectAsync0(() {}); + expectAsync(() {}); }); }); } diff --git a/test/test_utils.dart b/test/test_utils.dart index de783bedcf09abf5b13449ad96ef732a592f9b73..783f71ba91839e7310c9a119de5fb3e36d5906c2 100644 --- a/test/test_utils.dart +++ b/test/test_utils.dart @@ -36,7 +36,7 @@ void shouldFail(value, Matcher matcher, expected, {bool isAsync: false}) { if (expected is String) { expect(errorString, equalsIgnoringWhitespace(expected)); } else { - expect(errorString.replaceAll('\n',''), expected); + expect(errorString.replaceAll('\n', ''), expected); } } diff --git a/test/unittest_async_exception_test.dart b/test/unittest_async_exception_test.dart index 34298b7d275502227fa80a1d3a0ce6c024e465d3..cc351169debb8aee01d16c735e75e39e843541ba 100644 --- a/test/unittest_async_exception_test.dart +++ b/test/unittest_async_exception_test.dart @@ -13,8 +13,8 @@ var testName = 'async exception test'; var testFunction = (_) { test(testName, () { - expectAsync0(() {}); - _defer(() => guardAsync(() { throw "error!"; })); + expectAsync(() {}); + _defer(() { throw "error!"; }); }); }; diff --git a/test/unittest_async_setup_teardown_test.dart b/test/unittest_async_setup_teardown_test.dart index a73efc8e4b97c7174918f6b722aebf7ff4c7234d..067dbf951208a6e0bef895f968dbf3bda08224ef 100644 --- a/test/unittest_async_setup_teardown_test.dart +++ b/test/unittest_async_setup_teardown_test.dart @@ -19,7 +19,7 @@ var testFunction = (_) { tearDown(() { return new Future.value(0); }); - test('foo1', (){}); + test('foo1', () {}); }); group('good setup/bad teardown', () { setUp(() { @@ -28,7 +28,7 @@ var testFunction = (_) { tearDown(() { return new Future.error("Failed to complete tearDown"); }); - test('foo2', (){}); + test('foo2', () {}); }); group('bad setup/good teardown', () { setUp(() { @@ -37,7 +37,7 @@ var testFunction = (_) { tearDown(() { return new Future.value(0); }); - test('foo3', (){}); + test('foo3', () {}); }); group('bad setup/bad teardown', () { setUp(() { @@ -46,7 +46,7 @@ var testFunction = (_) { tearDown(() { return new Future.error("Failed to complete tearDown"); }); - test('foo4', (){}); + test('foo4', () {}); }); // The next test is just to make sure we make steady progress // through the tests. diff --git a/test/unittest_completion_test.dart b/test/unittest_completion_test.dart index 843f9d06b2155db2b314659d40725339ad2c8362..037dee1e2a2f53821387d416d57cf5085cd4061f 100644 --- a/test/unittest_completion_test.dart +++ b/test/unittest_completion_test.dart @@ -14,7 +14,7 @@ var testName = 'completion test'; var testFunction = (TestConfiguration testConfig) { test(testName, () { var _callback; - _callback = expectAsyncUntil0(() { + _callback = expectAsyncUntil(() { if (++testConfig.count < 10) { _defer(_callback); } diff --git a/test/unittest_correct_callback_test.dart b/test/unittest_correct_callback_test.dart index cd52ba060a13f5f8563b4f7edffcd1a52c6ef491..43b40eab2672f7fea8fc9a5dd61acdba1da52481 100644 --- a/test/unittest_correct_callback_test.dart +++ b/test/unittest_correct_callback_test.dart @@ -13,7 +13,7 @@ var testName = 'correct callback test'; var testFunction = (TestConfiguration testConfig) { test(testName, - () =>_defer(expectAsync0((){ ++testConfig.count;}))); + () =>_defer(expectAsync((){ ++testConfig.count;}))); }; var expected = buildStatusString(1, 0, 0, testName, count: 1); diff --git a/test/unittest_excess_callback_test.dart b/test/unittest_excess_callback_test.dart index f3876b518f69c487a76cb65fbd3f1609110dcd0f..76a3a9ee0949f0ae409c7ced0b4584fdd24f8d2f 100644 --- a/test/unittest_excess_callback_test.dart +++ b/test/unittest_excess_callback_test.dart @@ -13,9 +13,9 @@ var testName = 'excess callback test'; var testFunction = (TestConfiguration testConfig) { test(testName, () { - var _callback0 = expectAsync0(() => ++testConfig.count); - var _callback1 = expectAsync0(() => ++testConfig.count); - var _callback2 = expectAsync0(() { + var _callback0 = expectAsync(() => ++testConfig.count); + var _callback1 = expectAsync(() => ++testConfig.count); + var _callback2 = expectAsync(() { _callback1(); _callback1(); _callback0(); diff --git a/test/unittest_expect_async_args_test.dart b/test/unittest_expect_async_args_test.dart new file mode 100644 index 0000000000000000000000000000000000000000..0fd7517584f9022cbb3cb2b108cf6bade02b0b66 --- /dev/null +++ b/test/unittest_expect_async_args_test.dart @@ -0,0 +1,37 @@ +// 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. + +library unittestTest; + +import 'dart:isolate'; +import 'dart:async'; +import 'package:unittest/unittest.dart'; + +part 'unittest_test_utils.dart'; + +var testFunction = (TestConfiguration testConfig) { + List<int> _getArgs([a = 0, b = 0, c = 0, d = 0, e = 0, f = 0]) { + testConfig.count++; + return [a, b, c, d, e, f]; + } + + test('expect async args', () { + expect(expectAsync(_getArgs)(), [0, 0, 0, 0, 0, 0]); + expect(expectAsync(_getArgs)(5), [5, 0, 0, 0, 0, 0]); + expect(expectAsync(_getArgs)(1, 2, 3, 4, 5, 6), [1, 2, 3, 4, 5, 6]); + }); + + test('invoked with too many args', () { + expectAsync(_getArgs)(1, 2, 3, 4, 5, 6, 7); + }); + + test('created with too many args', () { + expectAsync((a1, a2, a3, a4, a5, a6, a7) { + testConfig.count++; + })(); + }); +}; + +final expected = startsWith('1:0:2:3:3:::null:expect async args::' + 'invoked with too many args:Test failed:'); diff --git a/test/unittest_expect_async_test.dart b/test/unittest_expect_async_test.dart new file mode 100644 index 0000000000000000000000000000000000000000..a8bbde5f412a76a728e3a4157df477e59bb436be --- /dev/null +++ b/test/unittest_expect_async_test.dart @@ -0,0 +1,95 @@ +// 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. + +library unittestTest; +import 'dart:isolate'; +import 'dart:async'; +import 'package:unittest/unittest.dart'; + +part 'unittest_test_utils.dart'; + +var testFunction = (TestConfiguration testConfig) { + test('expectAsync zero params', () { + _defer(expectAsync(() { + ++testConfig.count; + })); + }); + + test('expectAsync 1 param', () { + var func = expectAsync((arg) { + expect(arg, 0); + ++testConfig.count; + }); + _defer(() => func(0)); + }); + + test('expectAsync 2 param', () { + var func = expectAsync((arg0, arg1) { + expect(arg0, 0); + expect(arg1, 1); + ++testConfig.count; + }); + _defer(() => func(0, 1)); + }); + + test('single arg to Future.catchError', () { + var func = expectAsync((error) { + expect(error, isStateError); + ++testConfig.count; + }); + + new Future(() { + throw new StateError('test'); + }).catchError(func); + }); + + test('2 args to Future.catchError', () { + var func = expectAsync((error, stack) { + expect(error, isStateError); + expect(stack is StackTrace, isTrue); + ++testConfig.count; + }); + + new Future(() { + throw new StateError('test'); + }).catchError(func); + }); + + test('zero of two optional positional args', () { + var func = expectAsync(([arg0 = true, arg1 = true]) { + expect(arg0, isTrue); + expect(arg1, isTrue); + ++testConfig.count; + }); + + _defer(() => func()); + }); + + test('one of two optional positional args', () { + var func = expectAsync(([arg0 = true, arg1 = true]) { + expect(arg0, isFalse); + expect(arg1, isTrue); + ++testConfig.count; + }); + + _defer(() => func(false)); + }); + + test('two of two optional positional args', () { + var func = expectAsync(([arg0 = true, arg1 = true]) { + expect(arg0, isFalse); + expect(arg1, isNull); + ++testConfig.count; + }); + + _defer(() => func(false, null)); + }); +}; + +final expected = '8:0:0:8:8:::null:expectAsync zero params:' + ':expectAsync 1 param::expectAsync 2 param:' + ':single arg to Future.catchError::2 args to Future.catchError:' + ':zero of two optional positional args:' + ':one of two optional positional args:' + ':two of two optional positional args:'; diff --git a/test/unittest_late_exception_test.dart b/test/unittest_late_exception_test.dart index 7a5c3e61cbdb86ddfad33eb31649c6ff00c1a6f2..c80de1263329dab9e81ad440aceee9b8036db5b5 100644 --- a/test/unittest_late_exception_test.dart +++ b/test/unittest_late_exception_test.dart @@ -14,11 +14,11 @@ var testName = 'late exception test'; var testFunction = (_) { var f; test('testOne', () { - f = expectAsync0(() {}); + f = expectAsync(() {}); _defer(f); }); test('testTwo', () { - _defer(expectAsync0(() { f(); })); + _defer(expectAsync(() { f(); })); }); }; diff --git a/test/unittest_middle_exception_test.dart b/test/unittest_middle_exception_test.dart index d405500c57d05476bbd634172ccb99aab6034427..ba7751470b30046bbe22f6dd27f360ce13fb44e3 100644 --- a/test/unittest_middle_exception_test.dart +++ b/test/unittest_middle_exception_test.dart @@ -15,7 +15,7 @@ var testFunction = (_) { test('testOne', () { expect(true, isTrue); }); test('testTwo', () { expect(true, isFalse); }); test('testThree', () { - var done = expectAsync0((){}); + var done = expectAsync(() {}); _defer(() { expect(true, isTrue); done(); diff --git a/test/unittest_protect_async_test.dart b/test/unittest_protect_async_test.dart index 12ded3cecd0b03be67db1b7e7ac18ba92969f018..15d339484d8f3cd63499a0fae0a02a90f8ab2a2e 100644 --- a/test/unittest_protect_async_test.dart +++ b/test/unittest_protect_async_test.dart @@ -11,23 +11,23 @@ part 'unittest_test_utils.dart'; var testFunction = (_) { test('protectAsync0', () { - var protected = protectAsync0(() { + var protected = () { throw new StateError('error during protectAsync0'); - }); + }; new Future(protected); }); test('protectAsync1', () { - var protected = protectAsync1((arg) { + var protected = (arg) { throw new StateError('error during protectAsync1: $arg'); - }); + }; new Future(() => protected('one arg')); }); test('protectAsync2', () { - var protected = protectAsync2((arg1, arg2) { + var protected = (arg1, arg2) { throw new StateError('error during protectAsync2: $arg1, $arg2'); - }); + }; new Future(() => protected('arg1', 'arg2')); }); diff --git a/test/unittest_test_returning_future_test.dart b/test/unittest_test_returning_future_test.dart index a74a8db55479d6522cbfc9feceb136aeea82fc4a..83c4a5d3673d734333a3bb71b7a7c16f1f4b11ed 100644 --- a/test/unittest_test_returning_future_test.dart +++ b/test/unittest_test_returning_future_test.dart @@ -21,8 +21,8 @@ var testFunction = (_) { // I had a situation where either worked fine on their own, and // error/fail worked, but fail/error would time out. test("error1", () { - var callback = expectAsync0((){}); - var excesscallback = expectAsync0((){}); + var callback = expectAsync(() {}); + var excesscallback = expectAsync(() {}); return _defer(() { excesscallback(); excesscallback(); @@ -36,8 +36,8 @@ var testFunction = (_) { }); }); test("error2", () { - var callback = expectAsync0((){}); - var excesscallback = expectAsync0((){}); + var callback = expectAsync(() {}); + var excesscallback = expectAsync(() {}); return _defer(() { excesscallback(); excesscallback(); diff --git a/test/unittest_test_returning_future_using_runasync_test.dart b/test/unittest_test_returning_future_using_runasync_test.dart index 98f276b825f04a9d3b8d856f1266f0ea612247b4..e5fc304d7168b80a52c06d0f9512f35a1f5d14f2 100644 --- a/test/unittest_test_returning_future_using_runasync_test.dart +++ b/test/unittest_test_returning_future_using_runasync_test.dart @@ -15,58 +15,48 @@ var testFunction = (_) { test("successful", () { return _defer(() { scheduleMicrotask(() { - guardAsync(() { - expect(true, true); - }); + expect(true, true); }); }); }); test("fail1", () { - var callback = expectAsync0((){}); + var callback = expectAsync(() {}); return _defer(() { scheduleMicrotask(() { - guardAsync(() { - expect(true, false); - callback(); - }); + expect(true, false); + callback(); }); }); }); test('error1', () { - var callback = expectAsync0((){}); - var excesscallback = expectAsync0((){}); + var callback = expectAsync(() {}); + var excesscallback = expectAsync(() {}); return _defer(() { scheduleMicrotask(() { - guardAsync(() { - excesscallback(); - excesscallback(); - callback(); - }); + excesscallback(); + excesscallback(); + callback(); }); }); }); test("fail2", () { - var callback = expectAsync0((){}); + var callback = expectAsync(() {}); return _defer(() { scheduleMicrotask(() { - guardAsync(() { - fail('failure'); - callback(); - }); + fail('failure'); + callback(); }); }); }); test('error2', () { - var callback = expectAsync0((){}); - var excesscallback = expectAsync0((){}); + var callback = expectAsync(() {}); + var excesscallback = expectAsync(() {}); return _defer(() { scheduleMicrotask(() { - guardAsync(() { - excesscallback(); - excesscallback(); - excesscallback(); - callback(); - }); + excesscallback(); + excesscallback(); + excesscallback(); + callback(); }); }); }); diff --git a/test/unittest_test_utils.dart b/test/unittest_test_utils.dart index adb9823f366111179ed0b6bc437ebc8ba7b23de9..8385a1b7b767eea7d4a658943fead7473dc7f382 100644 --- a/test/unittest_test_utils.dart +++ b/test/unittest_test_utils.dart @@ -16,7 +16,7 @@ String buildStatusString(int passed, int failed, int errors, String message: ''}) { var totalTests = 0; var testDetails = new StringBuffer(); - if(results == null) { + if (results == null) { // no op assert(message == ''); } else if (results is String) { @@ -44,7 +44,7 @@ class TestConfiguration extends Configuration { final SendPort _port; String _result; - TestConfiguration(this._port) : super.blank(); + TestConfiguration(this._port): super.blank(); void onSummary(int passed, int failed, int errors, List<TestCase> results, String uncaughtError) { @@ -88,6 +88,6 @@ main() { var replyPort = new ReceivePort(); Isolate.spawn(runTestInIsolate, replyPort.sendPort); replyPort.first.then((String msg) { - expect(msg.trim(), equals(expected)); + expect(msg.trim(), expected); }); }