OLD | NEW |
---|---|
(Empty) | |
1 // Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file | |
2 // for details. All rights reserved. Use of this source code is governed by a | |
3 // BSD-style license that can be found in the LICENSE file. | |
4 | |
5 import 'dart:async'; | |
6 import 'dart:collection'; | |
7 | |
8 import 'package:fake_async/fake_async.dart'; | |
9 import 'package:unittest/src/invoker.dart'; | |
10 import 'package:unittest/src/live_test.dart'; | |
11 import 'package:unittest/src/state.dart'; | |
12 import 'package:unittest/src/suite.dart'; | |
13 import 'package:unittest/unittest.dart'; | |
14 | |
15 import 'utils.dart'; | |
16 | |
17 // The last state change detected via [expectStates]. | |
18 State lastState; | |
kevmoo
2015/02/11 00:35:09
If things are not used by another lib, make them p
nweiz
2015/02/11 02:07:06
Done.
| |
19 | |
20 void main() { | |
21 var suite; | |
22 setUp(() { | |
23 lastState = null; | |
24 suite = new Suite("suite", []); | |
25 }); | |
26 | |
27 group("Invoker.current", () { | |
28 test("returns null outside of a test body", () { | |
29 expect(Invoker.current, isNull); | |
30 }); | |
31 | |
32 test("returns the current invoker in a test body", () { | |
33 var invoker; | |
34 var liveTest = new LocalTest("test", () { | |
35 invoker = Invoker.current; | |
36 }).load(suite); | |
37 liveTest.onError.listen(expectAsync((_) {}, count: 0)); | |
38 | |
39 return liveTest.run().then((_) { | |
40 expect(invoker.liveTest, equals(liveTest)); | |
41 }); | |
42 }); | |
43 | |
44 test("returns the current invoker in a test body after the test completes", | |
45 () { | |
46 var status; | |
47 var completer = new Completer(); | |
48 var liveTest = new LocalTest("test", () { | |
49 // Use [new Future] in particular to wait longer than a microtask for | |
50 // the test to complete. | |
51 new Future(() { | |
52 status = Invoker.current.liveTest.state.status; | |
53 completer.complete(Invoker.current); | |
54 }); | |
55 }).load(suite); | |
56 liveTest.onError.listen(expectAsync((_) {}, count: 0)); | |
57 | |
58 expect(liveTest.run(), completes); | |
59 return completer.future.then((invoker) { | |
60 expect(invoker.liveTest, equals(liveTest)); | |
61 expect(status, equals(Status.complete)); | |
62 }); | |
63 }); | |
64 | |
65 test("returns the current invoker in a tearDown body", () { | |
66 var invoker; | |
67 var liveTest = new LocalTest("test", () {}, tearDown: () { | |
68 invoker = Invoker.current; | |
69 }).load(suite); | |
70 liveTest.onError.listen(expectAsync((_) {}, count: 0)); | |
71 | |
72 return liveTest.run().then((_) { | |
73 expect(invoker.liveTest, equals(liveTest)); | |
74 }); | |
75 }); | |
76 | |
77 test("returns the current invoker in a tearDown body after the test " | |
78 "completes", () { | |
79 var status; | |
80 var completer = new Completer(); | |
81 var liveTest = new LocalTest("test", () {}, tearDown: () { | |
82 // Use [new Future] in particular to wait longer than a microtask for | |
83 // the test to complete. | |
84 new Future(() { | |
85 status = Invoker.current.liveTest.state.status; | |
86 completer.complete(Invoker.current); | |
87 }); | |
88 }).load(suite); | |
89 liveTest.onError.listen(expectAsync((_) {}, count: 0)); | |
90 | |
91 expect(liveTest.run(), completes); | |
92 return completer.future.then((invoker) { | |
93 expect(invoker.liveTest, equals(liveTest)); | |
94 expect(status, equals(Status.complete)); | |
95 }); | |
96 }); | |
97 }); | |
98 | |
99 group("in a successful test,", () { | |
100 test("the state changes from pending to running to complete", () { | |
101 var stateInTest; | |
102 var stateInTearDown; | |
103 var liveTest; | |
104 liveTest = new LocalTest("test", () { | |
105 stateInTest = liveTest.state; | |
106 }, tearDown: () { | |
107 stateInTearDown = liveTest.state; | |
108 }).load(suite); | |
109 liveTest.onError.listen(expectAsync((_) {}, count: 0)); | |
110 | |
111 expect(liveTest.state.status, equals(Status.pending)); | |
112 expect(liveTest.state.result, equals(Result.success)); | |
113 | |
114 var future = liveTest.run(); | |
115 | |
116 expect(liveTest.state.status, equals(Status.running)); | |
117 expect(liveTest.state.result, equals(Result.success)); | |
118 | |
119 return future.then((_) { | |
120 expect(stateInTest.status, equals(Status.running)); | |
121 expect(stateInTest.result, equals(Result.success)); | |
122 | |
123 expect(stateInTearDown.status, equals(Status.running)); | |
124 expect(stateInTearDown.result, equals(Result.success)); | |
125 | |
126 expect(liveTest.state.status, equals(Status.complete)); | |
127 expect(liveTest.state.result, equals(Result.success)); | |
128 }); | |
129 }); | |
130 | |
131 test("onStateChange fires for each state change", () { | |
132 var liveTest = new LocalTest("test", () {}).load(suite); | |
133 liveTest.onError.listen(expectAsync((_) {}, count: 0)); | |
134 | |
135 var first = true; | |
136 liveTest.onStateChange.listen(expectAsync((state) { | |
137 if (first) { | |
138 expect(state.status, equals(Status.running)); | |
139 first = false; | |
140 } else { | |
141 expect(state.status, equals(Status.complete)); | |
142 } | |
143 expect(state.result, equals(Result.success)); | |
144 }, count: 2, max: 2)); | |
145 | |
146 return liveTest.run(); | |
147 }); | |
148 | |
149 test("onComplete completes once the test body and tearDown are done", () { | |
150 var testRun = false; | |
151 var tearDownRun = false; | |
152 var liveTest = new LocalTest("test", () { | |
153 testRun = true; | |
154 }, tearDown: () { | |
155 tearDownRun = true; | |
156 }).load(suite); | |
157 | |
158 expect(liveTest.onComplete.then((_) { | |
159 expect(testRun, isTrue); | |
160 expect(tearDownRun, isTrue); | |
161 }), completes); | |
162 | |
163 return liveTest.run(); | |
164 }); | |
165 }); | |
166 | |
167 group("in a test with failures,", () { | |
168 test("a synchronous throw is reported and causes the test to fail", () { | |
169 var liveTest = new LocalTest("test", () { | |
170 throw new TestFailure('oh no'); | |
171 }).load(suite); | |
172 | |
173 expectSingleFailure(liveTest); | |
174 return liveTest.run(); | |
175 }); | |
176 | |
177 test("a synchronous reported failure causes the test to fail", () { | |
178 var liveTest = new LocalTest("test", () { | |
179 Invoker.current.handleError(new TestFailure("oh no")); | |
180 }).load(suite); | |
181 | |
182 expectSingleFailure(liveTest); | |
183 return liveTest.run(); | |
184 }); | |
185 | |
186 test("a failure reported asynchronously during the test causes it to fail", | |
187 () { | |
188 var liveTest = new LocalTest("test", () { | |
189 Invoker.current.addOutstandingCallback(); | |
190 new Future(() => Invoker.current.handleError(new TestFailure("oh no"))); | |
191 }).load(suite); | |
192 | |
193 expectSingleFailure(liveTest); | |
194 return liveTest.run(); | |
195 }); | |
196 | |
197 test("a failure thrown asynchronously during the test causes it to fail", | |
198 () { | |
199 var liveTest = new LocalTest("test", () { | |
200 Invoker.current.addOutstandingCallback(); | |
201 new Future(() => throw new TestFailure("oh no")); | |
202 }).load(suite); | |
203 | |
204 expectSingleFailure(liveTest); | |
205 return liveTest.run(); | |
206 }); | |
207 | |
208 test("a failure reported asynchronously after the test causes it to error", | |
209 () { | |
210 var liveTest = new LocalTest("test", () { | |
211 new Future(() => Invoker.current.handleError(new TestFailure("oh no"))); | |
212 }).load(suite); | |
213 | |
214 expectStates(liveTest, [ | |
215 const State(Status.running, Result.success), | |
216 const State(Status.complete, Result.success), | |
217 const State(Status.complete, Result.failure), | |
218 const State(Status.complete, Result.error) | |
219 ]); | |
220 | |
221 expectErrors(liveTest, [(error) { | |
222 expect(lastState, equals(const State(Status.complete, Result.failure))); | |
223 expect(error, isTestFailure("oh no")); | |
224 }, (error) { | |
225 expect(lastState, equals(const State(Status.complete, Result.error))); | |
226 expect(error, equals( | |
227 "This test failed after it had already completed. Make sure to " | |
228 "use [expectAsync]\n" | |
229 "or the [completes] matcher when testing async code.")); | |
230 }]); | |
231 | |
232 return liveTest.run(); | |
233 }); | |
234 | |
235 test("multiple asynchronous failures are reported", () { | |
236 var liveTest = new LocalTest("test", () { | |
237 Invoker.current.addOutstandingCallback(); | |
238 new Future(() => throw new TestFailure("one")); | |
239 new Future(() => throw new TestFailure("two")); | |
240 new Future(() => throw new TestFailure("three")); | |
241 new Future(() => throw new TestFailure("four")); | |
242 }).load(suite); | |
243 | |
244 expectStates(liveTest, [ | |
245 const State(Status.running, Result.success), | |
246 const State(Status.complete, Result.failure) | |
247 ]); | |
248 | |
249 expectErrors(liveTest, [(error) { | |
250 expect(lastState.status, equals(Status.complete)); | |
251 expect(error, isTestFailure("one")); | |
252 }, (error) { | |
253 expect(error, isTestFailure("two")); | |
254 }, (error) { | |
255 expect(error, isTestFailure("three")); | |
256 }, (error) { | |
257 expect(error, isTestFailure("four")); | |
258 }]); | |
259 | |
260 return liveTest.run(); | |
261 }); | |
262 | |
263 test("a failure after an error doesn't change the state of the test", () { | |
264 var liveTest = new LocalTest("test", () { | |
265 new Future(() => throw new TestFailure("fail")); | |
266 throw "error"; | |
267 }).load(suite); | |
268 | |
269 expectStates(liveTest, [ | |
270 const State(Status.running, Result.success), | |
271 const State(Status.complete, Result.error) | |
272 ]); | |
273 | |
274 expectErrors(liveTest, [(error) { | |
275 expect(lastState, equals(const State(Status.complete, Result.error))); | |
276 expect(error, equals("error")); | |
277 }, (error) { | |
278 expect(error, isTestFailure("fail")); | |
279 }]); | |
280 | |
281 return liveTest.run(); | |
282 }); | |
283 | |
284 test("tearDown is run after an asynchronous failure", () { | |
285 var stateDuringTearDown; | |
286 var liveTest; | |
287 liveTest = new LocalTest("test", () { | |
288 Invoker.current.addOutstandingCallback(); | |
289 new Future(() => throw new TestFailure("oh no")); | |
290 }, tearDown: () { | |
291 stateDuringTearDown = liveTest.state; | |
292 }).load(suite); | |
293 | |
294 expectSingleFailure(liveTest); | |
295 return liveTest.run().then((_) { | |
296 expect(stateDuringTearDown, | |
297 equals(const State(Status.complete, Result.failure))); | |
298 }); | |
299 }); | |
300 }); | |
301 | |
302 group("in a test with errors,", () { | |
303 test("a synchronous throw is reported and causes the test to error", () { | |
304 var liveTest = new LocalTest("test", () { | |
305 throw 'oh no'; | |
306 }).load(suite); | |
307 | |
308 expectSingleError(liveTest); | |
309 return liveTest.run(); | |
310 }); | |
311 | |
312 test("a synchronous reported error causes the test to error", () { | |
313 var liveTest = new LocalTest("test", () { | |
314 Invoker.current.handleError("oh no"); | |
315 }).load(suite); | |
316 | |
317 expectSingleError(liveTest); | |
318 return liveTest.run(); | |
319 }); | |
320 | |
321 test("an error reported asynchronously during the test causes it to error", | |
322 () { | |
323 var liveTest = new LocalTest("test", () { | |
324 Invoker.current.addOutstandingCallback(); | |
325 new Future(() => Invoker.current.handleError("oh no")); | |
326 }).load(suite); | |
327 | |
328 expectSingleError(liveTest); | |
329 return liveTest.run(); | |
330 }); | |
331 | |
332 test("an error thrown asynchronously during the test causes it to error", | |
333 () { | |
334 var liveTest = new LocalTest("test", () { | |
335 Invoker.current.addOutstandingCallback(); | |
336 new Future(() => throw "oh no"); | |
337 }).load(suite); | |
338 | |
339 expectSingleError(liveTest); | |
340 return liveTest.run(); | |
341 }); | |
342 | |
343 test("an error reported asynchronously after the test causes it to error", | |
344 () { | |
345 var liveTest = new LocalTest("test", () { | |
346 new Future(() => Invoker.current.handleError("oh no")); | |
347 }).load(suite); | |
348 | |
349 expectStates(liveTest, [ | |
350 const State(Status.running, Result.success), | |
351 const State(Status.complete, Result.success), | |
352 const State(Status.complete, Result.error) | |
353 ]); | |
354 | |
355 expectErrors(liveTest, [(error) { | |
356 expect(lastState, equals(const State(Status.complete, Result.error))); | |
357 expect(error, equals("oh no")); | |
358 }, (error) { | |
359 expect(error, equals( | |
360 "This test failed after it had already completed. Make sure to " | |
361 "use [expectAsync]\n" | |
362 "or the [completes] matcher when testing async code.")); | |
363 }]); | |
364 | |
365 return liveTest.run(); | |
366 }); | |
367 | |
368 test("multiple asynchronous errors are reported", () { | |
369 var liveTest = new LocalTest("test", () { | |
370 Invoker.current.addOutstandingCallback(); | |
371 new Future(() => throw "one"); | |
372 new Future(() => throw "two"); | |
373 new Future(() => throw "three"); | |
374 new Future(() => throw "four"); | |
375 }).load(suite); | |
376 | |
377 expectStates(liveTest, [ | |
378 const State(Status.running, Result.success), | |
379 const State(Status.complete, Result.error) | |
380 ]); | |
381 | |
382 expectErrors(liveTest, [(error) { | |
383 expect(lastState.status, equals(Status.complete)); | |
384 expect(error, equals("one")); | |
385 }, (error) { | |
386 expect(error, equals("two")); | |
387 }, (error) { | |
388 expect(error, equals("three")); | |
389 }, (error) { | |
390 expect(error, equals("four")); | |
391 }]); | |
392 | |
393 return liveTest.run(); | |
394 }); | |
395 | |
396 test("an error after a failure changes the state of the test", () { | |
397 var liveTest = new LocalTest("test", () { | |
398 new Future(() => throw "error"); | |
399 throw new TestFailure("fail"); | |
400 }).load(suite); | |
401 | |
402 expectStates(liveTest, [ | |
403 const State(Status.running, Result.success), | |
404 const State(Status.complete, Result.failure), | |
405 const State(Status.complete, Result.error) | |
406 ]); | |
407 | |
408 expectErrors(liveTest, [(error) { | |
409 expect(lastState, equals(const State(Status.complete, Result.failure))); | |
410 expect(error, isTestFailure("fail")); | |
411 }, (error) { | |
412 expect(lastState, equals(const State(Status.complete, Result.error))); | |
413 expect(error, equals("error")); | |
414 }]); | |
415 | |
416 return liveTest.run(); | |
417 }); | |
418 | |
419 test("tearDown is run after an asynchronous error", () { | |
420 var stateDuringTearDown; | |
421 var liveTest; | |
422 liveTest = new LocalTest("test", () { | |
423 Invoker.current.addOutstandingCallback(); | |
424 new Future(() => throw "oh no"); | |
425 }, tearDown: () { | |
426 stateDuringTearDown = liveTest.state; | |
427 }).load(suite); | |
428 | |
429 expectSingleError(liveTest); | |
430 return liveTest.run().then((_) { | |
431 expect(stateDuringTearDown, | |
432 equals(const State(Status.complete, Result.error))); | |
433 }); | |
434 }); | |
435 }); | |
436 | |
437 test("a test doesn't complete until there are no outstanding callbacks", | |
438 () { | |
439 var outstandingCallbackRemoved = false; | |
440 var liveTest = new LocalTest("test", () { | |
441 Invoker.current.addOutstandingCallback(); | |
442 | |
443 // Pump the event queue to make sure the test isn't coincidentally | |
444 // completing after the outstanding callback is removed. | |
445 pumpEventQueue().then((_) { | |
446 outstandingCallbackRemoved = true; | |
447 Invoker.current.removeOutstandingCallback(); | |
448 }); | |
449 }).load(suite); | |
450 | |
451 liveTest.onError.listen(expectAsync((_) {}, count: 0)); | |
452 | |
453 return liveTest.run().then((_) { | |
454 expect(outstandingCallbackRemoved, isTrue); | |
455 }); | |
456 }); | |
457 | |
458 test("a test's tearDown isn't run until there are no outstanding callbacks", | |
459 () { | |
460 var outstandingCallbackRemoved = false; | |
461 var outstandingCallbackRemovedBeforeTeardown = false; | |
462 var liveTest = new LocalTest("test", () { | |
463 Invoker.current.addOutstandingCallback(); | |
464 pumpEventQueue().then((_) { | |
465 outstandingCallbackRemoved = true; | |
466 Invoker.current.removeOutstandingCallback(); | |
467 }); | |
468 }, tearDown: () { | |
469 outstandingCallbackRemovedBeforeTeardown = outstandingCallbackRemoved; | |
470 }).load(suite); | |
471 | |
472 liveTest.onError.listen(expectAsync((_) {}, count: 0)); | |
473 | |
474 return liveTest.run().then((_) { | |
475 expect(outstandingCallbackRemovedBeforeTeardown, isTrue); | |
476 }); | |
477 }); | |
478 | |
479 test("a test times out after 30 seconds", () { | |
480 new FakeAsync().run((async) { | |
481 var liveTest = new LocalTest("test", () { | |
482 Invoker.current.addOutstandingCallback(); | |
483 }).load(suite); | |
484 | |
485 expectStates(liveTest, [ | |
486 const State(Status.running, Result.success), | |
487 const State(Status.complete, Result.error) | |
488 ]); | |
489 | |
490 expectErrors(liveTest, [(error) { | |
491 expect(lastState.status, equals(Status.complete)); | |
492 expect(error, new isInstanceOf<TimeoutException>()); | |
493 }]); | |
494 | |
495 liveTest.run(); | |
496 async.elapse(new Duration(seconds: 30)); | |
497 }); | |
498 }); | |
499 } | |
500 | |
501 /// Asserts that exactly [states] will be emitted via [liveTest.onStateChange]. | |
502 /// | |
503 /// The most recent emitted state is stored in [lastState]. | |
504 void expectStates(LiveTest liveTest, Iterable<State> states) { | |
kevmoo
2015/02/11 00:35:09
Make these helpers private
nweiz
2015/02/11 02:07:06
Done.
| |
505 states = new Queue.from(states); | |
kevmoo
2015/02/11 01:18:28
Don't change the type of the var – the analyzer bo
nweiz
2015/02/11 02:07:06
Done.
| |
506 liveTest.onStateChange.listen(expectAsync((state) { | |
507 lastState = state; | |
508 expect(state, equals(states.removeFirst())); | |
509 }, count: states.length, max: states.length)); | |
510 } | |
511 | |
512 /// Asserts that errors will be emitted via [liveTest.onError] that match | |
513 /// [validators], in order. | |
514 void expectErrors(LiveTest liveTest, Iterable<Function> validators) { | |
515 validators = new Queue.from(validators); | |
kevmoo
2015/02/11 01:18:28
Don't change the type of the var – the analyzer bo
nweiz
2015/02/11 02:07:06
Done.
| |
516 liveTest.onError.listen(expectAsync((error) { | |
517 validators.removeFirst()(error.error); | |
518 }, count: validators.length, max: validators.length)); | |
519 } | |
520 | |
521 /// Asserts that [liveTest] will have a single failure with message `"oh no"`. | |
522 void expectSingleFailure(LiveTest liveTest) { | |
523 expectStates(liveTest, [ | |
524 const State(Status.running, Result.success), | |
525 const State(Status.complete, Result.failure) | |
526 ]); | |
527 | |
528 expectErrors(liveTest, [(error) { | |
529 expect(lastState.status, equals(Status.complete)); | |
530 expect(error, isTestFailure("oh no")); | |
531 }]); | |
532 } | |
533 | |
534 /// Asserts that [liveTest] will have a single error, the string `"oh no"`. | |
535 void expectSingleError(LiveTest liveTest) { | |
536 expectStates(liveTest, [ | |
537 const State(Status.running, Result.success), | |
538 const State(Status.complete, Result.error) | |
539 ]); | |
540 | |
541 expectErrors(liveTest, [(error) { | |
542 expect(lastState.status, equals(Status.complete)); | |
543 expect(error, equals("oh no")); | |
544 }]); | |
545 } | |
OLD | NEW |