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 |