OLD | NEW |
(Empty) | |
| 1 part of unittest; |
| 2 |
| 3 const _PLACE_HOLDER = const _ArgPlaceHolder(); |
| 4 |
| 5 /// Used to track unused positional args. |
| 6 class _ArgPlaceHolder { |
| 7 const _ArgPlaceHolder(); |
| 8 } |
| 9 |
| 10 /// Simulates spread arguments using named arguments. |
| 11 class _SpreadArgsHelper { |
| 12 final Function callback; |
| 13 final int minExpectedCalls; |
| 14 final int maxExpectedCalls; |
| 15 final Function isDone; |
| 16 final String id; |
| 17 final String reason; |
| 18 int actualCalls = 0; |
| 19 final TestCase testCase; |
| 20 bool complete; |
| 21 |
| 22 _SpreadArgsHelper(Function callback, int minExpected, int maxExpected, |
| 23 String id, String reason, {bool isDone()}) |
| 24 : this.callback = callback, |
| 25 minExpectedCalls = minExpected, |
| 26 maxExpectedCalls = (maxExpected == 0 && minExpected > 0) |
| 27 ? minExpected |
| 28 : maxExpected, |
| 29 this.isDone = isDone, |
| 30 this.reason = reason == null ? '' : '\n$reason', |
| 31 this.testCase = currentTestCase, |
| 32 this.id = _makeCallbackId(id, callback) { |
| 33 ensureInitialized(); |
| 34 if (testCase == null) { |
| 35 throw new StateError("No valid test. Did you forget to run your test " |
| 36 "inside a call to test()?"); |
| 37 } |
| 38 |
| 39 if (isDone != null || minExpected > 0) { |
| 40 testCase._callbackFunctionsOutstanding++; |
| 41 complete = false; |
| 42 } else { |
| 43 complete = true; |
| 44 } |
| 45 } |
| 46 |
| 47 static String _makeCallbackId(String id, Function callback) { |
| 48 // Try to create a reasonable id. |
| 49 if (id != null) { |
| 50 return "$id "; |
| 51 } else { |
| 52 // If the callback is not an anonymous closure, try to get the |
| 53 // name. |
| 54 var fname = callback.toString(); |
| 55 var prefix = "Function '"; |
| 56 var pos = fname.indexOf(prefix); |
| 57 if (pos > 0) { |
| 58 pos += prefix.length; |
| 59 var epos = fname.indexOf("'", pos); |
| 60 if (epos > 0) { |
| 61 return "${fname.substring(pos, epos)} "; |
| 62 } |
| 63 } |
| 64 } |
| 65 return ''; |
| 66 } |
| 67 |
| 68 bool shouldCallBack() { |
| 69 ++actualCalls; |
| 70 if (testCase.isComplete) { |
| 71 // Don't run if the test is done. We don't throw here as this is not |
| 72 // the current test, but we do mark the old test as having an error |
| 73 // if it previously passed. |
| 74 if (testCase.result == PASS) { |
| 75 testCase._error( |
| 76 'Callback ${id}called ($actualCalls) after test case ' |
| 77 '${testCase.description} has already been marked as ' |
| 78 '${testCase.result}.$reason'); |
| 79 } |
| 80 return false; |
| 81 } else if (maxExpectedCalls >= 0 && actualCalls > maxExpectedCalls) { |
| 82 throw new TestFailure('Callback ${id}called more times than expected ' |
| 83 '($maxExpectedCalls).$reason'); |
| 84 } |
| 85 return true; |
| 86 } |
| 87 |
| 88 void after() { |
| 89 if (!complete) { |
| 90 if (minExpectedCalls > 0 && actualCalls < minExpectedCalls) return; |
| 91 if (isDone != null && !isDone()) return; |
| 92 |
| 93 // Mark this callback as complete and remove it from the testcase |
| 94 // oustanding callback count; if that hits zero the testcase is done. |
| 95 complete = true; |
| 96 testCase._markCallbackComplete(); |
| 97 } |
| 98 } |
| 99 |
| 100 /// Returns a function that has as many required + positional arguments as |
| 101 /// [callback] (up to a total of 6). |
| 102 /// |
| 103 /// Optional positional arguments are supported by using const place-holders |
| 104 Function get func { |
| 105 if (callback is _Func6) return _max6; |
| 106 if (callback is _Func5) return _max5; |
| 107 if (callback is _Func4) return _max4; |
| 108 if (callback is _Func3) return _max3; |
| 109 if (callback is _Func2) return _max2; |
| 110 if (callback is _Func1) return _max1; |
| 111 if (callback is _Func0) return _max0; |
| 112 |
| 113 throw new ArgumentError( |
| 114 'The callback argument has more than 6 required arguments'); |
| 115 } |
| 116 |
| 117 /// This indirection is critical. It ensures the returned function has an |
| 118 /// argument count of zero. |
| 119 _max0() => _max6(); |
| 120 |
| 121 _max1([a0 = _PLACE_HOLDER]) => _max6(a0); |
| 122 |
| 123 _max2([a0 = _PLACE_HOLDER, a1 = _PLACE_HOLDER]) => _max6(a0, a1); |
| 124 |
| 125 _max3([a0 = _PLACE_HOLDER, a1 = _PLACE_HOLDER, a2 = _PLACE_HOLDER]) => |
| 126 _max6(a0, a1, a2); |
| 127 |
| 128 _max4([a0 = _PLACE_HOLDER, a1 = _PLACE_HOLDER, a2 = _PLACE_HOLDER, |
| 129 a3 = _PLACE_HOLDER]) => _max6(a0, a1, a2, a3); |
| 130 |
| 131 _max5([a0 = _PLACE_HOLDER, a1 = _PLACE_HOLDER, a2 = _PLACE_HOLDER, |
| 132 a3 = _PLACE_HOLDER, a4 = _PLACE_HOLDER]) => _max6(a0, a1, a2, a3, a4); |
| 133 |
| 134 _max6([a0 = _PLACE_HOLDER, a1 = _PLACE_HOLDER, a2 = _PLACE_HOLDER, |
| 135 a3 = _PLACE_HOLDER, a4 = _PLACE_HOLDER, a5 = _PLACE_HOLDER]) { |
| 136 var args = [a0, a1, a2, a3, a4, a5]; |
| 137 args.removeWhere((a) => a == _PLACE_HOLDER); |
| 138 |
| 139 return _guardAsync( |
| 140 () { |
| 141 if (shouldCallBack()) { |
| 142 return Function.apply(callback, args); |
| 143 } |
| 144 }, |
| 145 after, testCase); |
| 146 } |
| 147 |
| 148 _guardAsync(Function tryBody, Function finallyBody, TestCase testCase) { |
| 149 assert(testCase != null); |
| 150 try { |
| 151 return tryBody(); |
| 152 } catch (e, trace) { |
| 153 _registerException(testCase, e, trace); |
| 154 } finally { |
| 155 if (finallyBody != null) finallyBody(); |
| 156 } |
| 157 } |
| 158 } |
| 159 |
| 160 typedef _Func0(); |
| 161 typedef _Func1(a); |
| 162 typedef _Func2(a, b); |
| 163 typedef _Func3(a, b, c); |
| 164 typedef _Func4(a, b, c, d); |
| 165 typedef _Func5(a, b, c, d, e); |
| 166 typedef _Func6(a, b, c, d, e, f); |
OLD | NEW |