| 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 |