| OLD | NEW |
| 1 // Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2013, 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 part of unittest; | 5 library unittest.test_case; |
| 6 | 6 |
| 7 /// Represents the state for an individual unit test. | 7 import '../unittest.dart'; |
| 8 /// | 8 |
| 9 /// Create by calling [test] or [solo_test]. | 9 /// An individual unit test. |
| 10 class TestCase { | 10 abstract class TestCase { |
| 11 /// Identifier for this test. | 11 /// A unique numeric identifier for this test case. |
| 12 final int id; | 12 int get id; |
| 13 | 13 |
| 14 /// A description of what the test is specifying. | 14 /// A description of what the test is specifying. |
| 15 final String description; | 15 String get description; |
| 16 | 16 |
| 17 /// The setup function to call before the test, if any. | 17 /// The error or failure message for the tests. |
| 18 Function _setUp; | 18 /// |
| 19 /// Initially an empty string. |
| 20 String get message; |
| 19 | 21 |
| 20 /// The teardown function to call after the test, if any. | 22 /// The result of the test case. |
| 21 Function _tearDown; | 23 /// |
| 22 | 24 /// If the test case has is completed, this will be one of [PASS], [FAIL], or |
| 23 /// The body of the test case. | 25 /// [ERROR]. Otherwise, it will be `null`. |
| 24 TestFunction _testFunction; | 26 String get result; |
| 25 | |
| 26 /// Remaining number of callbacks functions that must reach a 'done' state | |
| 27 /// to wait for before the test completes. | |
| 28 int _callbackFunctionsOutstanding = 0; | |
| 29 | |
| 30 String _message = ''; | |
| 31 /// Error or failure message. | |
| 32 String get message => _message; | |
| 33 | |
| 34 String _result; | |
| 35 /// One of [PASS], [FAIL], [ERROR], or [:null:] if the test hasn't run yet. | |
| 36 String get result => _result; | |
| 37 | 27 |
| 38 /// Returns whether this test case passed. | 28 /// Returns whether this test case passed. |
| 39 bool get passed => _result == PASS; | 29 bool get passed; |
| 40 | 30 |
| 41 StackTrace _stackTrace; | 31 /// The stack trace for the error that caused this test case to fail, or |
| 42 /// Stack trace associated with this test, or [:null:] if it succeeded. | 32 /// `null` if it succeeded. |
| 43 StackTrace get stackTrace => _stackTrace; | 33 StackTrace get stackTrace; |
| 44 | 34 |
| 45 /// The group (or groups) under which this test is running. | 35 /// The name of the group within which this test is running. |
| 46 final String currentGroup; | 36 String get currentGroup; |
| 47 | 37 |
| 48 DateTime _startTime; | 38 /// The time the test case started running. |
| 49 DateTime get startTime => _startTime; | 39 /// |
| 40 /// `null` if the test hasn't yet begun running. |
| 41 DateTime get startTime; |
| 50 | 42 |
| 51 Duration _runningTime; | 43 /// The amount of time the test case took. |
| 52 Duration get runningTime => _runningTime; | 44 /// |
| 45 /// `null` if the test hasn't finished running. |
| 46 Duration get runningTime; |
| 53 | 47 |
| 54 bool _enabled = true; | 48 /// Whether this test is enabled. |
| 49 /// |
| 50 /// Disabled tests won't be run. |
| 51 bool get enabled; |
| 55 | 52 |
| 56 bool get enabled => _enabled; | 53 /// Whether this test case has finished running. |
| 57 | |
| 58 bool _doneTeardown = false; | |
| 59 | |
| 60 Completer _testComplete; | |
| 61 | |
| 62 TestCase._internal(this.id, this.description, this._testFunction) | |
| 63 : currentGroup = _environment.currentContext.fullName, | |
| 64 _setUp = _environment.currentContext.testSetup, | |
| 65 _tearDown = _environment.currentContext.testTeardown; | |
| 66 | |
| 67 bool get isComplete => !enabled || result != null; | 54 bool get isComplete => !enabled || result != null; |
| 68 | |
| 69 Function _errorHandler(String stage) => (e, stack) { | |
| 70 if (stack == null && e is Error) { | |
| 71 stack = e.stackTrace; | |
| 72 } | |
| 73 if (result == null || result == PASS) { | |
| 74 if (e is TestFailure) { | |
| 75 _fail("$e", stack); | |
| 76 } else { | |
| 77 _error("$stage failed: Caught $e", stack); | |
| 78 } | |
| 79 } | |
| 80 }; | |
| 81 | |
| 82 /// Perform any associated [_setUp] function and run the test. Returns | |
| 83 /// a [Future] that can be used to schedule the next test. If the test runs | |
| 84 /// to completion synchronously, or is disabled, null is returned, to | |
| 85 /// tell unittest to schedule the next test immediately. | |
| 86 Future _run() { | |
| 87 if (!enabled) return new Future.value(); | |
| 88 | |
| 89 _result = _stackTrace = null; | |
| 90 _message = ''; | |
| 91 | |
| 92 // Avoid calling [new Future] to avoid issue 11911. | |
| 93 return new Future.value().then((_) { | |
| 94 if (_setUp != null) return _setUp(); | |
| 95 }).catchError(_errorHandler('Setup')).then((_) { | |
| 96 // Skip the test if setup failed. | |
| 97 if (result != null) return new Future.value(); | |
| 98 _config.onTestStart(this); | |
| 99 _startTime = new DateTime.now(); | |
| 100 _runningTime = null; | |
| 101 ++_callbackFunctionsOutstanding; | |
| 102 var testReturn = _testFunction(); | |
| 103 // If _testFunction() returned a future, we want to wait for it like we | |
| 104 // would a callback, so if a failure occurs while waiting, we can abort. | |
| 105 if (testReturn is Future) { | |
| 106 ++_callbackFunctionsOutstanding; | |
| 107 testReturn.catchError(_errorHandler('Test')) | |
| 108 .whenComplete(_markCallbackComplete); | |
| 109 } | |
| 110 }).catchError(_errorHandler('Test')).then((_) { | |
| 111 _markCallbackComplete(); | |
| 112 if (result == null) { | |
| 113 // Outstanding callbacks exist; we need to return a Future. | |
| 114 _testComplete = new Completer(); | |
| 115 return _testComplete.future.whenComplete(() { | |
| 116 if (_tearDown != null) { | |
| 117 return _tearDown(); | |
| 118 } | |
| 119 }).catchError(_errorHandler('Teardown')); | |
| 120 } else if (_tearDown != null) { | |
| 121 return _tearDown(); | |
| 122 } | |
| 123 }).catchError(_errorHandler('Teardown')).whenComplete(() { | |
| 124 _setUp = null; | |
| 125 _tearDown = null; | |
| 126 _testFunction = null; | |
| 127 }); | |
| 128 } | |
| 129 | |
| 130 // Set the results, notify the config, and return true if this | |
| 131 // is the first time the result is being set. | |
| 132 void _setResult(String testResult, String messageText, StackTrace stack) { | |
| 133 _message = messageText; | |
| 134 _stackTrace = getTrace(stack, formatStacks, filterStacks); | |
| 135 if (_stackTrace == null) _stackTrace = stack; | |
| 136 if (result == null) { | |
| 137 _result = testResult; | |
| 138 _config.onTestResult(this); | |
| 139 } else { | |
| 140 _result = testResult; | |
| 141 _config.onTestResultChanged(this); | |
| 142 } | |
| 143 } | |
| 144 | |
| 145 void _complete(String testResult, [String messageText = '', | |
| 146 StackTrace stack]) { | |
| 147 if (runningTime == null) { | |
| 148 // The startTime can be `null` if an error happened during setup. In this | |
| 149 // case we simply report a running time of 0. | |
| 150 if (startTime != null) { | |
| 151 _runningTime = new DateTime.now().difference(startTime); | |
| 152 } else { | |
| 153 _runningTime = const Duration(seconds: 0); | |
| 154 } | |
| 155 } | |
| 156 _setResult(testResult, messageText, stack); | |
| 157 if (_testComplete != null) { | |
| 158 var t = _testComplete; | |
| 159 _testComplete = null; | |
| 160 t.complete(this); | |
| 161 } | |
| 162 } | |
| 163 | |
| 164 void _pass() { | |
| 165 _complete(PASS); | |
| 166 } | |
| 167 | |
| 168 void _fail(String messageText, [StackTrace stack]) { | |
| 169 if (result != null) { | |
| 170 String newMessage = (result == PASS) | |
| 171 ? 'Test failed after initially passing: $messageText' | |
| 172 : 'Test failed more than once: $messageText'; | |
| 173 // TODO(gram): Should we combine the stack with the old one? | |
| 174 _complete(ERROR, newMessage, stack); | |
| 175 } else { | |
| 176 _complete(FAIL, messageText, stack); | |
| 177 } | |
| 178 } | |
| 179 | |
| 180 void _error(String messageText, [StackTrace stack]) { | |
| 181 _complete(ERROR, messageText, stack); | |
| 182 } | |
| 183 | |
| 184 void _markCallbackComplete() { | |
| 185 if (--_callbackFunctionsOutstanding == 0 && !isComplete) { | |
| 186 _pass(); | |
| 187 } | |
| 188 } | |
| 189 | |
| 190 String toString() => _result != null ? "$description: $result" : description; | |
| 191 } | 55 } |
| OLD | NEW |