Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(267)

Unified Diff: pkg/unittest/lib/unittest.dart

Issue 12366004: When we have excess callbacks, throw instead of calling error() so that we (Closed) Base URL: http://dart.googlecode.com/svn/branches/bleeding_edge/dart/
Patch Set: Created 7 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « pkg/unittest/lib/src/test_case.dart ('k') | pkg/unittest/test/unittest_test.dart » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: pkg/unittest/lib/unittest.dart
===================================================================
--- pkg/unittest/lib/unittest.dart (revision 19267)
+++ pkg/unittest/lib/unittest.dart (working copy)
@@ -218,7 +218,13 @@
/** Current test being executed. */
int _currentTest = 0;
+TestCase _currentTestCase;
+TestCase get currentTestCase =>
+ (_currentTest >= 0 && _currentTest < _tests.length)
+ ? _tests[_currentTest]
+ : null;
+
/** Whether the framework is in an initialized state. */
bool _initialized = false;
@@ -287,18 +293,27 @@
// TODO(sigmund): remove this class and simply use a closure with named
// arguments (if still applicable).
class _SpreadArgsHelper {
- Function _callback;
- int _expectedCalls;
- int _actualCalls = 0;
- int _testNum;
- TestCase _testCase;
- Function _shouldCallBack;
- Function _isDone;
- String _id;
- static const _sentinel = const _Sentinel();
+ final Function callback;
+ final int minExpectedCalls;
+ final int maxExpectedCalls;
+ final Function isDone;
+ final int testNum;
+ final String id;
+ int actualCalls = 0;
+ TestCase testCase;
+ bool complete;
+ static const sentinel = const _Sentinel();
- _init(Function callback, Function shouldCallBack, Function isDone,
- [expectedCalls = 0]) {
+ _SpreadArgsHelper(Function callback, int minExpected, int maxExpected,
+ Function isDone, String id)
+ : this.callback = callback,
+ minExpectedCalls = minExpected,
+ maxExpectedCalls = (maxExpected == 0 && minExpected > 0)
+ ? minExpected
+ : maxExpected,
+ this.isDone = isDone,
+ testNum = _currentTest,
+ this.id = _makeCallbackId(id, callback) {
ensureInitialized();
if (!(_currentTest >= 0 &&
_currentTest < _tests.length &&
@@ -309,138 +324,124 @@
assert(_currentTest >= 0 &&
_currentTest < _tests.length &&
_tests[_currentTest] != null);
- _callback = callback;
- _shouldCallBack = shouldCallBack;
- _isDone = isDone;
- _expectedCalls = expectedCalls;
- _testNum = _currentTest;
- _testCase = _tests[_currentTest];
- if (expectedCalls > 0) {
- _testCase.callbackFunctionsOutstanding++;
+ testCase = _tests[_currentTest];
+ if (isDone != null || minExpected > 0) {
+ testCase.callbackFunctionsOutstanding++;
+ complete = false;
+ } else {
+ complete = true;
}
- _id = '';
- // If the callback is not an anonymous closure, try to get the
- // name.
- var fname = callback.toString();
- var prefix = "Function '";
- var pos = fname.indexOf(prefix);
- if (pos > 0) {
- pos += prefix.length;
- var epos = fname.indexOf("'", pos);
- if (epos > 0) {
- _id = "${fname.substring(pos, epos)} ";
- }
- }
}
- _SpreadArgsHelper(callback, shouldCallBack, isDone) {
- _init(callback, shouldCallBack, isDone);
- }
-
- _SpreadArgsHelper.fixedCallCount(callback, expectedCalls, id) {
- _init(callback, _checkCallCount, _allCallsDone, expectedCalls);
+ static _makeCallbackId(String id, Function callback) {
+ // Try to create a reasonable id.
if (id != null) {
- _id = "$id ";
+ return "$id ";
+ } else {
+ // If the callback is not an anonymous closure, try to get the
+ // name.
+ var fname = callback.toString();
+ var prefix = "Function '";
+ var pos = fname.indexOf(prefix);
+ if (pos > 0) {
+ pos += prefix.length;
+ var epos = fname.indexOf("'", pos);
+ if (epos > 0) {
+ return "${fname.substring(pos, epos)} ";
+ }
+ }
}
+ return '';
}
- _SpreadArgsHelper.variableCallCount(callback, isDone) {
- _init(callback, _always, isDone, 1);
- }
-
- _SpreadArgsHelper.optionalCalls(callback) {
- _init(callback, _always, () => false, 0);
- }
-
- _after() {
- if (_isDone()) {
- _handleCallbackFunctionComplete(_testNum, _id);
+ shouldCallBack() {
+ ++actualCalls;
+ if (testCase.isComplete) {
+ // Don't run if the test is done. We don't throw here as this is not
+ // the current test, but we do mark the old test as having an error
+ // if it previously passed.
+ if (testCase.result == PASS) {
+ testCase.error(
+ 'Callback ${id}called after test case ${testCase.description} '
+ 'has already been marked as done.', '');
+ }
+ return false;
+ } else if (maxExpectedCalls >= 0 && actualCalls > maxExpectedCalls) {
+ throw new TestFailure('Callback ${id}called more times than expected '
+ '($maxExpectedCalls).');
}
+ return true;
}
- _allCallsDone() => _actualCalls == _expectedCalls;
+ after() {
+ if (!complete) {
+ if (minExpectedCalls > 0 && actualCalls < minExpectedCalls) return;
+ if (isDone != null && !isDone()) return;
- _always() {
- // Always run except if the test is done.
- if (_testCase.isComplete) {
- _testCase.error(
- 'Callback ${_id}called after already being marked '
- 'as done ($_actualCalls).',
- '');
- return false;
- } else {
- return true;
+ // Mark this callback as complete and remove it from the testcase
+ // oustanding callback count; if that hits zero the testcase is done.
+ complete = true;
+ if (--testCase.callbackFunctionsOutstanding == 0 &&
+ !testCase.isComplete) {
+ testCase.pass();
+ }
}
}
- invoke([arg0 = _sentinel, arg1 = _sentinel, arg2 = _sentinel,
- arg3 = _sentinel, arg4 = _sentinel]) {
+ invoke([arg0 = sentinel, arg1 = sentinel, arg2 = sentinel,
+ arg3 = sentinel, arg4 = sentinel]) {
return guardAsync(() {
- ++_actualCalls;
- if (!_shouldCallBack()) {
+ if (!shouldCallBack()) {
return;
- } else if (arg0 == _sentinel) {
- return _callback();
- } else if (arg1 == _sentinel) {
- return _callback(arg0);
- } else if (arg2 == _sentinel) {
- return _callback(arg0, arg1);
- } else if (arg3 == _sentinel) {
- return _callback(arg0, arg1, arg2);
- } else if (arg4 == _sentinel) {
- return _callback(arg0, arg1, arg2, arg3);
+ } else if (arg0 == sentinel) {
+ return callback();
+ } else if (arg1 == sentinel) {
+ return callback(arg0);
+ } else if (arg2 == sentinel) {
+ return callback(arg0, arg1);
+ } else if (arg3 == sentinel) {
+ return callback(arg0, arg1, arg2);
+ } else if (arg4 == sentinel) {
+ return callback(arg0, arg1, arg2, arg3);
} else {
- _testCase.error(
+ testCase.error(
'unittest lib does not support callbacks with more than'
' 4 arguments.',
'');
}
},
- _after, _testNum);
+ after, testNum);
}
invoke0() {
return guardAsync(
() {
- ++_actualCalls;
- if (_shouldCallBack()) {
- return _callback();
+ if (shouldCallBack()) {
+ return callback();
}
},
- _after, _testNum);
+ after, testNum);
}
invoke1(arg1) {
return guardAsync(
() {
- ++_actualCalls;
- if (_shouldCallBack()) {
- return _callback(arg1);
+ if (shouldCallBack()) {
+ return callback(arg1);
}
},
- _after, _testNum);
+ after, testNum);
}
invoke2(arg1, arg2) {
return guardAsync(
() {
- ++_actualCalls;
- if (_shouldCallBack()) {
- return _callback(arg1, arg2);
+ if (shouldCallBack()) {
+ return callback(arg1, arg2);
}
},
- _after, _testNum);
+ after, testNum);
}
-
- /** Returns false if we exceded the number of expected calls. */
- bool _checkCallCount() {
- if (_actualCalls > _expectedCalls) {
- _testCase.error('Callback ${_id}called more times than expected '
- '($_actualCalls > $_expectedCalls).', '');
- return false;
- }
- return true;
- }
}
/**
@@ -453,9 +454,9 @@
* to provide more descriptive error messages if the callback is called more
* often than expected.
*/
-Function _expectAsync(Function callback, {int count: 1, String id}) {
- return new _SpreadArgsHelper.
- fixedCallCount(callback, count, id).invoke;
+Function _expectAsync(Function callback,
+ {int count: 1, int max: 0, String id}) {
+ return new _SpreadArgsHelper(callback, count, max, null, id).invoke;
}
/**
@@ -466,26 +467,31 @@
* tracked and reported. [callback] should take 0 positional arguments (named
* arguments are not supported). [id] can be used to provide more
* descriptive error messages if the callback is called more often than
- * expected.
+ * expected. [max] can be used to specify an upper bound on the number of
+ * calls; if this is exceeded the test will fail (or be marked as in error if
+ * it was already complete). A value of 0 for [max] (the default) will set
+ * the upper bound to the same value as [count]; i.e. the callback should be
+ * called exactly [count] times. A value of -1 for [max] will mean no upper
+ * bound.
*/
// TODO(sigmund): deprecate this API when issue 2706 is fixed.
-Function expectAsync0(Function callback, {int count: 1, String id}) {
- return new _SpreadArgsHelper.
- fixedCallCount(callback, count, id).invoke0;
+Function expectAsync0(Function callback,
+ {int count: 1, int max: 0, String id}) {
+ return new _SpreadArgsHelper(callback, count, max, null, id).invoke0;
}
/** Like [expectAsync0] but [callback] should take 1 positional argument. */
// TODO(sigmund): deprecate this API when issue 2706 is fixed.
-Function expectAsync1(Function callback, {int count: 1, String id}) {
- return new _SpreadArgsHelper.
- fixedCallCount(callback, count, id).invoke1;
+Function expectAsync1(Function callback,
+ {int count: 1, int max: 0, String id}) {
+ return new _SpreadArgsHelper(callback, count, max, null, id).invoke1;
}
/** Like [expectAsync0] but [callback] should take 2 positional arguments. */
// TODO(sigmund): deprecate this API when issue 2706 is fixed.
-Function expectAsync2(Function callback, {int count: 1, String id}) {
- return new _SpreadArgsHelper.
- fixedCallCount(callback, count, id).invoke2;
+Function expectAsync2(Function callback,
+ {int count: 1, int max: 0, String id}) {
+ return new _SpreadArgsHelper(callback, count, max, null, id).invoke2;
}
/**
@@ -494,10 +500,12 @@
* when it returns true will it continue with the following test. Using
* [expectAsyncUntil] will also ensure that errors that occur within
* [callback] are tracked and reported. [callback] should take between 0 and
- * 4 positional arguments (named arguments are not supported).
+ * 4 positional arguments (named arguments are not supported). [id] can be
+ * used to identify the callback in error messages (for example if it is called
+ * after the test case is complete).
*/
-Function _expectAsyncUntil(Function callback, Function isDone) {
- return new _SpreadArgsHelper.variableCallCount(callback, isDone).invoke;
+Function _expectAsyncUntil(Function callback, Function isDone, {String id}) {
+ return new _SpreadArgsHelper(callback, 0, -1, isDone, id).invoke;
}
/**
@@ -506,27 +514,29 @@
* when it returns true will it continue with the following test. Using
* [expectAsyncUntil0] will also ensure that errors that occur within
* [callback] are tracked and reported. [callback] should take 0 positional
- * arguments (named arguments are not supported).
+ * arguments (named arguments are not supported). [id] can be used to
+ * identify the callback in error messages (for example if it is called
+ * after the test case is complete).
*/
// TODO(sigmund): deprecate this API when issue 2706 is fixed.
-Function expectAsyncUntil0(Function callback, Function isDone) {
- return new _SpreadArgsHelper.variableCallCount(callback, isDone).invoke0;
+Function expectAsyncUntil0(Function callback, Function isDone, {String id}) {
+ return new _SpreadArgsHelper(callback, 0, -1, isDone, id).invoke0;
}
/**
* Like [expectAsyncUntil0] but [callback] should take 1 positional argument.
*/
// TODO(sigmund): deprecate this API when issue 2706 is fixed.
-Function expectAsyncUntil1(Function callback, Function isDone) {
- return new _SpreadArgsHelper.variableCallCount(callback, isDone).invoke1;
+Function expectAsyncUntil1(Function callback, Function isDone, {String id}) {
+ return new _SpreadArgsHelper(callback, 0, -1, isDone, id).invoke1;
}
/**
* Like [expectAsyncUntil0] but [callback] should take 2 positional arguments.
*/
// TODO(sigmund): deprecate this API when issue 2706 is fixed.
-Function expectAsyncUntil2(Function callback, Function isDone) {
- return new _SpreadArgsHelper.variableCallCount(callback, isDone).invoke2;
+Function expectAsyncUntil2(Function callback, Function isDone, {String id}) {
+ return new _SpreadArgsHelper(callback, 0, -1, isDone, id).invoke2;
}
/**
@@ -535,10 +545,11 @@
* test. This is thus similar to expectAsync0. Use it to wrap any callbacks that
* might optionally be called but may never be called during the test.
* [callback] should take between 0 and 4 positional arguments (named arguments
- * are not supported).
+ * are not supported). [id] can be used to identify the callback in error
+ * messages (for example if it is called after the test case is complete).
*/
-Function _protectAsync(Function callback) {
- return new _SpreadArgsHelper.optionalCalls(callback).invoke;
+Function _protectAsync(Function callback, {String id}) {
+ return new _SpreadArgsHelper(callback, 0, -1, null, id).invoke;
}
/**
@@ -547,27 +558,28 @@
* test. This is thus similar to expectAsync0. Use it to wrap any callbacks that
* might optionally be called but may never be called during the test.
* [callback] should take 0 positional arguments (named arguments are not
- * supported).
+ * supported). [id] can be used to identify the callback in error
+ * messages (for example if it is called after the test case is complete).
*/
// TODO(sigmund): deprecate this API when issue 2706 is fixed.
-Function protectAsync0(Function callback) {
- return new _SpreadArgsHelper.optionalCalls(callback).invoke0;
+Function protectAsync0(Function callback, {String id}) {
+ return new _SpreadArgsHelper(callback, 0, -1, null, id).invoke0;
}
/**
* Like [protectAsync0] but [callback] should take 1 positional argument.
*/
// TODO(sigmund): deprecate this API when issue 2706 is fixed.
-Function protectAsync1(Function callback) {
- return new _SpreadArgsHelper.optionalCalls(callback).invoke1;
+Function protectAsync1(Function callback, {String id}) {
+ return new _SpreadArgsHelper(callback, 0, -1, null, id).invoke1;
}
/**
* Like [protectAsync0] but [callback] should take 2 positional arguments.
*/
// TODO(sigmund): deprecate this API when issue 2706 is fixed.
-Function protectAsync2(Function callback) {
- return new _SpreadArgsHelper.optionalCalls(callback).invoke2;
+Function protectAsync2(Function callback, {String id}) {
+ return new _SpreadArgsHelper(callback, 0, -1, null, id).invoke2;
}
/**
@@ -630,38 +642,6 @@
_testTeardown = teardownTest;
}
-/**
- * Called when one of the callback functions is done with all expected
- * calls.
- */
-void _handleCallbackFunctionComplete(testNum, [id = '']) {
- // TODO (gram): we defer this to give the nextBatch recursive
- // stack a chance to unwind. This is a temporary hack but
- // really a bunch of code here needs to be fixed. We have a
- // single array that is being iterated through by nextBatch(),
- // which is recursively invoked in the case of async tests that
- // run synchronously. Bad things can then happen.
- _defer(() {
- if (_currentTest != testNum) {
- if (_tests[testNum].result == PASS) {
- _tests[testNum].error("${id}Unexpected extra callbacks", '');
- }
- } else if (_currentTest < _tests.length) {
- final testCase = _tests[_currentTest];
- --testCase.callbackFunctionsOutstanding;
- if (testCase.callbackFunctionsOutstanding < 0) {
- // TODO(gram): Check: Can this even happen?
- testCase.error(
- 'More calls to _handleCallbackFunctionComplete() than expected.',
- '');
- } else if (testCase.callbackFunctionsOutstanding == 0 &&
- !testCase.isComplete) {
- testCase.pass();
- }
- }
- });
-}
-
/** Advance to the next test case. */
void _nextTestCase() {
_defer(() {
@@ -671,14 +651,6 @@
}
/**
- * Temporary hack: expose old API.
- * TODO(gram) remove this when WebKit tests are working with new framework
- */
-void callbackDone() {
- _handleCallbackFunctionComplete(_currentTest);
-}
-
-/**
* Utility function that can be used to notify the test framework that an
* error was caught outside of this library.
*/
@@ -772,11 +744,11 @@
*/
_registerException(testNum, e, [trace]) {
trace = trace == null ? '' : trace.toString();
+ String message = (e is TestFailure) ? e.message : 'Caught $e';
if (_tests[testNum].result == null) {
- String message = (e is TestFailure) ? e.message : 'Caught $e';
_tests[testNum].fail(message, trace);
} else {
- _tests[testNum].error('Caught $e', trace);
+ _tests[testNum].error(message, trace);
}
}
« no previous file with comments | « pkg/unittest/lib/src/test_case.dart ('k') | pkg/unittest/test/unittest_test.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698