OLD | NEW |
1 // Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file | 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 | 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. | 3 // BSD-style license that can be found in the LICENSE file. |
4 | 4 |
5 import 'dart:async'; | 5 import 'dart:async'; |
6 import 'dart:isolate'; | 6 import 'dart:isolate'; |
7 | 7 |
8 import 'package:unittest/src/declarer.dart'; | |
9 import 'package:unittest/src/invoker.dart'; | 8 import 'package:unittest/src/invoker.dart'; |
10 import 'package:unittest/src/isolate_test.dart'; | 9 import 'package:unittest/src/isolate_test.dart'; |
11 import 'package:unittest/src/live_test.dart'; | 10 import 'package:unittest/src/live_test.dart'; |
| 11 import 'package:unittest/src/remote_exception.dart'; |
12 import 'package:unittest/src/state.dart'; | 12 import 'package:unittest/src/state.dart'; |
13 import 'package:unittest/src/suite.dart'; | 13 import 'package:unittest/src/suite.dart'; |
14 import 'package:unittest/src/vm_listener.dart'; | 14 import 'package:unittest/src/vm_listener.dart'; |
15 import 'package:unittest/unittest.dart'; | 15 import 'package:unittest/unittest.dart'; |
16 | 16 |
17 import 'utils.dart'; | 17 import 'utils.dart'; |
18 | 18 |
19 /// The current declarer. | |
20 Declarer get _declarer => Zone.current[#unittest.declarer]; | |
21 | |
22 /// An isolate that's been spun up for the current test. | 19 /// An isolate that's been spun up for the current test. |
23 /// | 20 /// |
24 /// This is tracked so that it can be killed once the test is done. | 21 /// This is tracked so that it can be killed once the test is done. |
25 Isolate _isolate; | 22 Isolate _isolate; |
26 | 23 |
27 /// A live test that's running for the current test. | 24 /// A live test that's running for the current test. |
28 /// | 25 /// |
29 /// This is tracked so that it can be closed once the test is done. | 26 /// This is tracked so that it can be closed once the test is done. |
30 LiveTest _liveTest; | 27 LiveTest _liveTest; |
31 | 28 |
32 void main() { | 29 void main() { |
33 tearDown(() { | 30 tearDown(() { |
34 if (_isolate != null) _isolate.kill(Isolate.IMMEDIATE); | 31 if (_isolate != null) _isolate.kill(Isolate.IMMEDIATE); |
35 _isolate = null; | 32 _isolate = null; |
36 | 33 |
37 if (_liveTest != null) _liveTest.close(); | 34 if (_liveTest != null) _liveTest.close(); |
38 _liveTest = null; | 35 _liveTest = null; |
39 }); | 36 }); |
40 | 37 |
41 test("sends a list of available tests on startup", () { | 38 test("sends a list of available tests on startup", () { |
42 return _spawnIsolate(_successfulTests).then((receivePort) { | 39 return _spawnIsolate(_successfulTests).then((receivePort) { |
43 return receivePort.first; | 40 return receivePort.first; |
44 }).then((tests) { | 41 }).then((response) { |
| 42 expect(response, containsPair("type", "success")); |
| 43 expect(response, contains("tests")); |
| 44 |
| 45 var tests = response["tests"]; |
45 expect(tests, hasLength(3)); | 46 expect(tests, hasLength(3)); |
46 expect(tests[0], containsPair("name", "successful 1")); | 47 expect(tests[0], containsPair("name", "successful 1")); |
47 expect(tests[1], containsPair("name", "successful 2")); | 48 expect(tests[1], containsPair("name", "successful 2")); |
48 expect(tests[2], containsPair("name", "successful 3")); | 49 expect(tests[2], containsPair("name", "successful 3")); |
49 }); | 50 }); |
50 }); | 51 }); |
51 | 52 |
| 53 test("sends an error response if loading fails", () { |
| 54 return _spawnIsolate(_loadError).then((receivePort) { |
| 55 return receivePort.first; |
| 56 }).then((response) { |
| 57 expect(response, containsPair("type", "error")); |
| 58 expect(response, contains("error")); |
| 59 |
| 60 var error = RemoteException.deserialize(response["error"]).error; |
| 61 expect(error.message, equals("oh no")); |
| 62 expect(error.type, equals("String")); |
| 63 }); |
| 64 }); |
| 65 |
| 66 test("sends an error response on a NoSuchMethodError", () { |
| 67 return _spawnIsolate(_noSuchMethodError).then((receivePort) { |
| 68 return receivePort.first; |
| 69 }).then((response) { |
| 70 expect(response, containsPair("type", "loadException")); |
| 71 expect(response, |
| 72 containsPair("message", "No top-level main() function defined.")); |
| 73 }); |
| 74 }); |
| 75 |
| 76 test("sends an error response on non-function main", () { |
| 77 return _spawnIsolate(_nonFunction).then((receivePort) { |
| 78 return receivePort.first; |
| 79 }).then((response) { |
| 80 expect(response, containsPair("type", "loadException")); |
| 81 expect(response, |
| 82 containsPair("message", "Top-level main getter is not a function.")); |
| 83 }); |
| 84 }); |
| 85 |
| 86 test("sends an error response on wrong-arity main", () { |
| 87 return _spawnIsolate(_wrongArity).then((receivePort) { |
| 88 return receivePort.first; |
| 89 }).then((response) { |
| 90 expect(response, containsPair("type", "loadException")); |
| 91 expect( |
| 92 response, |
| 93 containsPair( |
| 94 "message", |
| 95 "Top-level main() function takes arguments.")); |
| 96 }); |
| 97 }); |
| 98 |
52 group("in a successful test", () { | 99 group("in a successful test", () { |
53 test("the state changes from pending to running to complete", () { | 100 test("the state changes from pending to running to complete", () { |
54 return _isolateTest(_successfulTests).then((liveTest) { | 101 return _isolateTest(_successfulTests).then((liveTest) { |
55 liveTest.onError.listen(expectAsync((_) {}, count: 0)); | 102 liveTest.onError.listen(expectAsync((_) {}, count: 0)); |
56 | 103 |
57 expect(liveTest.state, | 104 expect(liveTest.state, |
58 equals(const State(Status.pending, Result.success))); | 105 equals(const State(Status.pending, Result.success))); |
59 | 106 |
60 var future = liveTest.run(); | 107 var future = liveTest.run(); |
61 | 108 |
(...skipping 149 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
211 }); | 258 }); |
212 } | 259 } |
213 | 260 |
214 /// Loads the first test defined in [entryPoint] in another isolate. | 261 /// Loads the first test defined in [entryPoint] in another isolate. |
215 /// | 262 /// |
216 /// This test will be automatically closed when the test is finished. | 263 /// This test will be automatically closed when the test is finished. |
217 Future<LiveTest> _isolateTest(void entryPoint(SendPort sendPort)) { | 264 Future<LiveTest> _isolateTest(void entryPoint(SendPort sendPort)) { |
218 return _spawnIsolate(entryPoint).then((receivePort) { | 265 return _spawnIsolate(entryPoint).then((receivePort) { |
219 return receivePort.first; | 266 return receivePort.first; |
220 }).then((response) { | 267 }).then((response) { |
221 var testMap = response.first; | 268 expect(response, containsPair("type", "success")); |
| 269 |
| 270 var testMap = response["tests"].first; |
222 var test = new IsolateTest(testMap["name"], testMap["sendPort"]); | 271 var test = new IsolateTest(testMap["name"], testMap["sendPort"]); |
223 var suite = new Suite("suite", [test]); | 272 var suite = new Suite("suite", [test]); |
224 _liveTest = test.load(suite); | 273 _liveTest = test.load(suite); |
225 return _liveTest; | 274 return _liveTest; |
226 }); | 275 }); |
227 } | 276 } |
228 | 277 |
229 /// Spawns an isolate from [entryPoint], sends it a new [SendPort], and returns | 278 /// Spawns an isolate from [entryPoint], sends it a new [SendPort], and returns |
230 /// the corresponding [ReceivePort]. | 279 /// the corresponding [ReceivePort]. |
231 /// | 280 /// |
232 /// This isolate will be automatically killed when the test is finished. | 281 /// This isolate will be automatically killed when the test is finished. |
233 Future<ReceivePort> _spawnIsolate(void entryPoint(SendPort sendPort)) { | 282 Future<ReceivePort> _spawnIsolate(void entryPoint(SendPort sendPort)) { |
234 var receivePort = new ReceivePort(); | 283 var receivePort = new ReceivePort(); |
235 return Isolate.spawn(entryPoint, receivePort.sendPort).then((isolate) { | 284 return Isolate.spawn(entryPoint, receivePort.sendPort).then((isolate) { |
236 _isolate = isolate; | 285 _isolate = isolate; |
237 return receivePort; | 286 return receivePort; |
238 }); | 287 }); |
239 } | 288 } |
240 | 289 |
| 290 /// An isolate entrypoint that throws immediately. |
| 291 void _loadError(SendPort sendPort) => |
| 292 VmListener.start(sendPort, () => () => throw 'oh no'); |
| 293 |
| 294 /// An isolate entrypoint that throws a NoSuchMethodError. |
| 295 void _noSuchMethodError(SendPort sendPort) { |
| 296 return VmListener.start(sendPort, () => |
| 297 throw new NoSuchMethodError(null, #main, [], {})); |
| 298 } |
| 299 |
| 300 /// An isolate entrypoint that returns a non-function. |
| 301 void _nonFunction(SendPort sendPort) => |
| 302 VmListener.start(sendPort, () => null); |
| 303 |
| 304 /// An isolate entrypoint that returns a function with the wrong arity. |
| 305 void _wrongArity(SendPort sendPort) => |
| 306 VmListener.start(sendPort, () => (_) {}); |
| 307 |
241 /// An isolate entrypoint that defines three tests that succeed. | 308 /// An isolate entrypoint that defines three tests that succeed. |
242 void _successfulTests(SendPort sendPort) { | 309 void _successfulTests(SendPort sendPort) { |
243 VmListener.start(sendPort, () { | 310 VmListener.start(sendPort, () => () { |
244 _declarer.test("successful 1", () {}); | 311 test("successful 1", () {}); |
245 _declarer.test("successful 2", () {}); | 312 test("successful 2", () {}); |
246 _declarer.test("successful 3", () {}); | 313 test("successful 3", () {}); |
247 }); | 314 }); |
248 } | 315 } |
249 | 316 |
250 /// An isolate entrypoint that defines a test that fails. | 317 /// An isolate entrypoint that defines a test that fails. |
251 void _failingTest(SendPort sendPort) { | 318 void _failingTest(SendPort sendPort) { |
252 VmListener.start(sendPort, () { | 319 VmListener.start(sendPort, () => () { |
253 _declarer.test("failure", () => throw new TestFailure('oh no')); | 320 test("failure", () => throw new TestFailure('oh no')); |
254 }); | 321 }); |
255 } | 322 } |
256 | 323 |
257 /// An isolate entrypoint that defines a test that fails after succeeding. | 324 /// An isolate entrypoint that defines a test that fails after succeeding. |
258 void _failAfterSucceedTest(SendPort sendPort) { | 325 void _failAfterSucceedTest(SendPort sendPort) { |
259 VmListener.start(sendPort, () { | 326 VmListener.start(sendPort, () => () { |
260 _declarer.test("fail after succeed", () { | 327 test("fail after succeed", () { |
261 pumpEventQueue().then((_) { | 328 pumpEventQueue().then((_) { |
262 throw new TestFailure('oh no'); | 329 throw new TestFailure('oh no'); |
263 }); | 330 }); |
264 }); | 331 }); |
265 }); | 332 }); |
266 } | 333 } |
267 | 334 |
268 /// An isolate entrypoint that defines a test that fails multiple times. | 335 /// An isolate entrypoint that defines a test that fails multiple times. |
269 void _multiFailTest(SendPort sendPort) { | 336 void _multiFailTest(SendPort sendPort) { |
270 VmListener.start(sendPort, () { | 337 VmListener.start(sendPort, () => () { |
271 _declarer.test("multiple failures", () { | 338 test("multiple failures", () { |
272 Invoker.current.addOutstandingCallback(); | 339 Invoker.current.addOutstandingCallback(); |
273 new Future(() => throw new TestFailure("one")); | 340 new Future(() => throw new TestFailure("one")); |
274 new Future(() => throw new TestFailure("two")); | 341 new Future(() => throw new TestFailure("two")); |
275 new Future(() => throw new TestFailure("three")); | 342 new Future(() => throw new TestFailure("three")); |
276 new Future(() => throw new TestFailure("four")); | 343 new Future(() => throw new TestFailure("four")); |
277 }); | 344 }); |
278 }); | 345 }); |
279 } | 346 } |
280 | 347 |
281 /// An isolate entrypoint that defines a test that errors. | 348 /// An isolate entrypoint that defines a test that errors. |
282 void _errorTest(SendPort sendPort) { | 349 void _errorTest(SendPort sendPort) { |
283 VmListener.start(sendPort, () { | 350 VmListener.start(sendPort, () => () { |
284 _declarer.test("error", () => throw 'oh no'); | 351 test("error", () => throw 'oh no'); |
285 }); | 352 }); |
286 } | 353 } |
287 | 354 |
288 /// An isolate entrypoint that defines a test that errors after succeeding. | 355 /// An isolate entrypoint that defines a test that errors after succeeding. |
289 void _errorAfterSucceedTest(SendPort sendPort) { | 356 void _errorAfterSucceedTest(SendPort sendPort) { |
290 VmListener.start(sendPort, () { | 357 VmListener.start(sendPort, () => () { |
291 _declarer.test("error after succeed", () { | 358 test("error after succeed", () { |
292 pumpEventQueue().then((_) => throw 'oh no'); | 359 pumpEventQueue().then((_) => throw 'oh no'); |
293 }); | 360 }); |
294 }); | 361 }); |
295 } | 362 } |
296 | 363 |
297 /// An isolate entrypoint that defines a test that errors multiple times. | 364 /// An isolate entrypoint that defines a test that errors multiple times. |
298 void _multiErrorTest(SendPort sendPort) { | 365 void _multiErrorTest(SendPort sendPort) { |
299 VmListener.start(sendPort, () { | 366 VmListener.start(sendPort, () => () { |
300 _declarer.test("multiple errors", () { | 367 test("multiple errors", () { |
301 Invoker.current.addOutstandingCallback(); | 368 Invoker.current.addOutstandingCallback(); |
302 new Future(() => throw "one"); | 369 new Future(() => throw "one"); |
303 new Future(() => throw "two"); | 370 new Future(() => throw "two"); |
304 new Future(() => throw "three"); | 371 new Future(() => throw "three"); |
305 new Future(() => throw "four"); | 372 new Future(() => throw "four"); |
306 }); | 373 }); |
307 }); | 374 }); |
308 } | 375 } |
OLD | NEW |