OLD | NEW |
1 // Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2014, 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 /// A test library for testing test libraries? We must go deeper. | 5 /// A test library for testing test libraries? We must go deeper. |
6 /// | 6 /// |
7 /// Since unit testing code tends to use a lot of global state, it can be tough | 7 /// Since unit testing code tends to use a lot of global state, it can be tough |
8 /// to test. This library manages it by running each test case in a child | 8 /// to test. This library manages it by running each test case in a child |
9 /// isolate, then reporting the results back to the parent isolate. | 9 /// isolate, then reporting the results back to the parent isolate. |
10 library metatest; | 10 library metatest; |
11 | 11 |
12 import 'dart:async'; | 12 import 'dart:async'; |
13 import 'dart:isolate'; | |
14 | 13 |
15 // TODO(nweiz): Stop importing from src when dart-lang/test#48 is fixed. | 14 // TODO(nweiz): Stop importing from src when dart-lang/test#48 is fixed. |
16 import 'package:test/src/backend/declarer.dart'; | 15 import 'package:test/src/backend/declarer.dart'; |
17 import 'package:test/src/backend/live_test.dart'; | 16 import 'package:test/src/backend/live_test.dart'; |
18 import 'package:test/src/backend/state.dart'; | 17 import 'package:test/src/backend/state.dart'; |
19 import 'package:test/src/backend/suite.dart'; | 18 import 'package:test/src/backend/suite.dart'; |
20 import 'package:test/src/runner/engine.dart'; | 19 import 'package:test/src/runner/engine.dart'; |
21 import 'package:test/test.dart'; | 20 import 'package:test/test.dart'; |
22 | 21 |
23 /// Declares a test with the given [description] and [body]. | 22 /// Declares a test with the given [description] and [body]. |
24 /// | 23 /// |
25 /// [body] corresponds to the `main` method of a test file. By default, this | 24 /// [body] corresponds to the `main` method of a test file. By default, this |
26 /// expects that all tests defined in [body] pass, but if [passing] is passed, | 25 /// expects that all tests defined in [body] pass, but if [passing] is passed, |
27 /// only tests listed there are expected to pass. | 26 /// only tests listed there are expected to pass. |
28 void expectTestsPass(String description, void body(), {List<String> passing}) { | 27 void expectTestsPass(String description, void body(), {List<String> passing, |
| 28 String testOn, Timeout timeout, skip, Map<String, dynamic> onPlatform}) { |
29 _setUpTest(description, body, (liveTests) { | 29 _setUpTest(description, body, (liveTests) { |
30 if (passing == null) { | 30 if (passing == null) { |
31 if (liveTests.any( | 31 if (liveTests.any( |
32 (liveTest) => liveTest.state.result != Result.success)) { | 32 (liveTest) => liveTest.state.result != Result.success)) { |
33 fail('Expected all tests to pass, but some failed:\n' | 33 fail('Expected all tests to pass, but some failed:\n' |
34 '${_summarizeTests(liveTests)}'); | 34 '${_summarizeTests(liveTests)}'); |
35 } | 35 } |
36 return; | 36 return; |
37 } | 37 } |
38 | 38 |
39 var shouldPass = new Set.from(passing); | 39 var shouldPass = new Set.from(passing); |
40 var didPass = new Set.from(liveTests | 40 var didPass = new Set.from(liveTests |
41 .where((liveTest) => liveTest.state.result == Result.success) | 41 .where((liveTest) => liveTest.state.result == Result.success) |
42 .map((liveTest) => liveTest.test.name)); | 42 .map((liveTest) => liveTest.test.name)); |
43 | 43 |
44 if (!shouldPass.containsAll(didPass) || | 44 if (!shouldPass.containsAll(didPass) || |
45 !didPass.containsAll(shouldPass)) { | 45 !didPass.containsAll(shouldPass)) { |
46 stringify(tests) => '{${tests.map((t) => '"$t"').join(', ')}}'; | 46 stringify(tests) => '{${tests.map((t) => '"$t"').join(', ')}}'; |
47 | 47 |
48 fail('Expected exactly ${stringify(shouldPass)} to pass, but ' | 48 fail('Expected exactly ${stringify(shouldPass)} to pass, but ' |
49 '${stringify(didPass)} passed.\n' | 49 '${stringify(didPass)} passed.\n' |
50 '${_summarizeTests(liveTests)}'); | 50 '${_summarizeTests(liveTests)}'); |
51 } | 51 } |
52 }); | 52 }, testOn: testOn, timeout: timeout, skip: skip, onPlatform: onPlatform); |
53 } | 53 } |
54 | 54 |
55 /// Asserts that all tests defined by [body] fail. | 55 /// Asserts that all tests defined by [body] fail. |
56 /// | 56 /// |
57 /// [body] corresponds to the `main` method of a test file. | 57 /// [body] corresponds to the `main` method of a test file. |
58 void expectTestsFail(String description, body()) { | 58 void expectTestsFail(String description, body(), {String testOn, |
59 expectTestsPass(description, body, passing: []); | 59 Timeout timeout, skip, Map<String, dynamic> onPlatform}) { |
| 60 expectTestsPass(description, body, passing: [], testOn: testOn, |
| 61 timeout: timeout, skip: skip, onPlatform: onPlatform); |
60 } | 62 } |
61 | 63 |
62 /// Sets up a test with the given [description] and [body]. After the test runs, | 64 /// Sets up a test with the given [description] and [body]. After the test runs, |
63 /// calls [validate] with the result map. | 65 /// calls [validate] with the result map. |
64 void _setUpTest(String description, void body(), | 66 void _setUpTest(String description, void body(), |
65 void validate(List<LiveTest> liveTests)) { | 67 void validate(List<LiveTest> liveTests), {String testOn, Timeout timeout, |
| 68 skip, Map<String, dynamic> onPlatform}) { |
66 test(description, () async { | 69 test(description, () async { |
67 var declarer = new Declarer(); | 70 var declarer = new Declarer(); |
68 runZoned(body, zoneValues: {#test.declarer: declarer}); | 71 runZoned(body, zoneValues: {#test.declarer: declarer}); |
69 | 72 |
70 var engine = new Engine.withSuites([new Suite(declarer.tests)]); | 73 var engine = new Engine.withSuites([new Suite(declarer.tests)]); |
71 for (var test in engine.liveTests) { | 74 for (var test in engine.liveTests) { |
72 test.onPrint.listen(print); | 75 test.onPrint.listen(print); |
73 } | 76 } |
74 await engine.run(); | 77 await engine.run(); |
75 | 78 |
76 validate(engine.liveTests); | 79 validate(engine.liveTests); |
77 }); | 80 }, testOn: testOn, timeout: timeout, skip: skip, onPlatform: onPlatform); |
78 } | 81 } |
79 | 82 |
80 /// Returns a string description of the test run descibed by [liveTests]. | 83 /// Returns a string description of the test run descibed by [liveTests]. |
81 String _summarizeTests(List<LiveTest> liveTests) { | 84 String _summarizeTests(List<LiveTest> liveTests) { |
82 var buffer = new StringBuffer(); | 85 var buffer = new StringBuffer(); |
83 for (var liveTest in liveTests) { | 86 for (var liveTest in liveTests) { |
84 buffer.writeln("${liveTest.state.result}: ${liveTest.test.name}"); | 87 buffer.writeln("${liveTest.state.result}: ${liveTest.test.name}"); |
85 for (var error in liveTest.errors) { | 88 for (var error in liveTest.errors) { |
86 buffer.writeln(error.error); | 89 buffer.writeln(error.error); |
87 if (error.stackTrace != null) buffer.writeln(error.stackTrace); | 90 if (error.stackTrace != null) buffer.writeln(error.stackTrace); |
88 } | 91 } |
89 } | 92 } |
90 return buffer.toString(); | 93 return buffer.toString(); |
91 } | 94 } |
OLD | NEW |