Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright (c) 2011, 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 part of unittest; |
| 6 | 6 |
| 7 /** | 7 /** |
| 8 * testcase.dart: this file is sourced by unittest.dart. It defines [TestCase] | 8 * Represents the state for an individual unit test. |
| 9 * and assumes unittest defines the type [TestFunction]. | 9 * |
| 10 * Create by calling [test] or [solo_test]. | |
| 10 */ | 11 */ |
| 11 | |
| 12 /** Summarizes information about a single test case. */ | |
| 13 class TestCase { | 12 class TestCase { |
| 14 /** Identifier for this test. */ | 13 /** Identifier for this test. */ |
| 15 final int id; | 14 final int id; |
| 16 | 15 |
| 17 /** A description of what the test is specifying. */ | 16 /** A description of what the test is specifying. */ |
| 18 final String description; | 17 final String description; |
| 19 | 18 |
| 20 /** The setup function to call before the test, if any. */ | 19 /** The setup function to call before the test, if any. */ |
| 21 Function _setUp; | 20 final Function _setUp; |
| 22 | |
| 23 Function get setUp => _setUp; | |
| 24 set setUp(Function value) => _setUp = value; | |
| 25 | 21 |
| 26 /** The teardown function to call after the test, if any. */ | 22 /** The teardown function to call after the test, if any. */ |
| 27 Function _tearDown; | 23 final Function _tearDown; |
| 28 | |
| 29 Function get tearDown => _tearDown; | |
| 30 set tearDown(Function value) => _tearDown = value; | |
| 31 | 24 |
| 32 /** The body of the test case. */ | 25 /** The body of the test case. */ |
| 33 TestFunction test; | 26 final TestFunction _test; |
| 34 | 27 |
| 35 /** | 28 /** |
| 36 * Remaining number of callbacks functions that must reach a 'done' state | 29 * Remaining number of callbacks functions that must reach a 'done' state |
| 37 * to wait for before the test completes. | 30 * to wait for before the test completes. |
| 38 */ | 31 */ |
| 39 int callbackFunctionsOutstanding; | 32 int _callbackFunctionsOutstanding = 0; |
| 40 | 33 |
| 34 String _message = ''; | |
| 41 /** Error or failure message. */ | 35 /** Error or failure message. */ |
| 42 String message = ''; | 36 String get message => _message; |
| 43 | 37 |
| 38 String _result; | |
| 44 /** | 39 /** |
| 45 * One of [PASS], [FAIL], [ERROR], or [null] if the test hasn't run yet. | 40 * One of [PASS], [FAIL], [ERROR], or [null] if the test hasn't run yet. |
| 46 */ | 41 */ |
| 47 String result; | 42 String get result => _result; |
| 48 | 43 |
| 49 /** Stack trace associated with this test, or null if it succeeded. */ | 44 String _stackTrace; |
| 50 String stackTrace; | 45 /** Stack trace associated with this test, or [null] if it succeeded. */ |
| 46 String get stackTrace => _stackTrace; | |
| 51 | 47 |
| 52 /** The group (or groups) under which this test is running. */ | 48 /** The group (or groups) under which this test is running. */ |
| 53 final String currentGroup; | 49 final String currentGroup; |
| 54 | 50 |
| 55 DateTime startTime; | 51 DateTime _startTime; |
| 52 DateTime get startTime => _startTime; | |
| 56 | 53 |
| 57 Duration runningTime; | 54 Duration _runningTime; |
| 55 Duration get runningTime => _runningTime; | |
| 58 | 56 |
| 59 bool enabled = true; | 57 bool _enabled = true; |
| 58 bool get enabled => _enabled; | |
| 60 | 59 |
| 61 bool _doneTeardown = false; | 60 bool _doneTeardown = false; |
| 62 | 61 |
| 63 Completer _testComplete; | 62 Completer _testComplete; |
| 64 | 63 |
| 65 TestCase(this.id, this.description, this.test, | 64 TestCase._internal(this.id, this.description, this._test) |
| 66 this.callbackFunctionsOutstanding) | |
| 67 : currentGroup = _currentGroup, | 65 : currentGroup = _currentGroup, |
| 68 _setUp = _testSetup, | 66 _setUp = _testSetup, |
| 69 _tearDown = _testTeardown; | 67 _tearDown = _testTeardown; |
| 70 | 68 |
| 71 bool get isComplete => !enabled || result != null; | 69 bool get isComplete => !enabled || result != null; |
| 72 | 70 |
| 73 void _prepTest() { | 71 void _prepTest() { |
| 74 _config.onTestStart(this); | 72 _config.onTestStart(this); |
| 75 startTime = new DateTime.now(); | 73 _startTime = new DateTime.now(); |
| 76 runningTime = null; | 74 _runningTime = null; |
| 77 } | 75 } |
| 78 | 76 |
| 79 Future _runTest() { | 77 Future _runTest() { |
| 80 _prepTest(); | 78 _prepTest(); |
| 81 // Increment/decrement callbackFunctionsOutstanding to prevent | 79 // Increment/decrement callbackFunctionsOutstanding to prevent |
| 82 // synchronous 'async' callbacks from causing the test to be | 80 // synchronous 'async' callbacks from causing the test to be |
| 83 // marked as complete before the body is completely executed. | 81 // marked as complete before the body is completely executed. |
| 84 ++callbackFunctionsOutstanding; | 82 ++_callbackFunctionsOutstanding; |
| 85 var f = test(); | 83 var f = _test(); |
| 86 --callbackFunctionsOutstanding; | 84 --_callbackFunctionsOutstanding; |
| 87 if (f is Future) { | 85 if (f is Future) { |
| 88 f.then((_) => _finishTest()) | 86 f.then((_) => _finishTest()) |
| 89 .catchError((e) => fail("${e.error}")); | 87 .catchError((e) => fail("${e.error}")); |
| 90 return f; | 88 return f; |
| 91 } else { | 89 } else { |
| 92 _finishTest(); | 90 _finishTest(); |
| 93 return null; | 91 return null; |
| 94 } | 92 } |
| 95 } | 93 } |
| 96 | 94 |
| 97 void _finishTest() { | 95 void _finishTest() { |
| 98 if (result == null && callbackFunctionsOutstanding == 0) { | 96 if (result == null && _callbackFunctionsOutstanding == 0) { |
| 99 pass(); | 97 _pass(); |
| 100 } | 98 } |
| 101 } | 99 } |
| 102 | 100 |
| 103 /** | 101 /** |
| 104 * Perform any associated [setUp] function and run the test. Returns | 102 * Perform any associated [_setUp] function and run the test. Returns |
| 105 * a [Future] that can be used to schedule the next test. If the test runs | 103 * a [Future] that can be used to schedule the next test. If the test runs |
| 106 * to completion synchronously, or is disabled, we return null, to | 104 * to completion synchronously, or is disabled, null is returned, to |
| 107 * tell unittest to schedule the next test immediately. | 105 * tell unittest to schedule the next test immediately. |
| 108 */ | 106 */ |
| 109 Future run() { | 107 Future _run() { |
| 110 if (!enabled) return null; | 108 if (!enabled) return null; |
| 111 | 109 |
| 112 result = stackTrace = null; | 110 _result = _stackTrace = null; |
| 113 message = ''; | 111 _message = ''; |
| 114 _doneTeardown = false; | 112 _doneTeardown = false; |
| 115 var rtn = _setUp == null ? null : _setUp(); | 113 var rtn = _setUp == null ? null : _setUp(); |
| 116 if (rtn is Future) { | 114 if (rtn is Future) { |
| 117 rtn.then((_) => _runTest()) | 115 rtn.then((_) => _runTest()) |
| 118 .catchError((e) { | 116 .catchError((e) { |
| 119 _prepTest(); | 117 _prepTest(); |
| 120 // Calling error() will result in the tearDown being done. | 118 // Calling error() will result in the tearDown being done. |
| 121 // One could debate whether tearDown should be done after | 119 // One could debate whether tearDown should be done after |
| 122 // a failed setUp. There is no right answer, but doing it | 120 // a failed setUp. There is no right answer, but doing it |
| 123 // seems to be the more conservative approach, because | 121 // seems to be the more conservative approach, because |
| 124 // unittest will not stop at a test failure. | 122 // unittest will not stop at a test failure. |
| 125 error("$description: Test setup failed: ${e.error}"); | 123 _error("$description: Test setup failed: ${e.error}"); |
| 126 }); | 124 }); |
| 127 } else { | 125 } else { |
| 128 var f = _runTest(); | 126 var f = _runTest(); |
| 129 if (f != null) { | 127 if (f != null) { |
| 130 return f; | 128 return f; |
| 131 } | 129 } |
| 132 } | 130 } |
| 133 if (result == null) { // Not complete. | 131 if (result == null) { // Not complete. |
| 134 _testComplete = new Completer(); | 132 _testComplete = new Completer(); |
| 135 return _testComplete.future; | 133 return _testComplete.future; |
| 136 } | 134 } |
| 137 return null; | 135 return null; |
| 138 } | 136 } |
| 139 | 137 |
| 140 void _notifyComplete() { | 138 void _notifyComplete() { |
| 141 if (_testComplete != null) { | 139 if (_testComplete != null) { |
| 142 _testComplete.complete(this); | 140 _testComplete.complete(this); |
| 143 _testComplete = null; | 141 _testComplete = null; |
| 144 } | 142 } |
| 145 } | 143 } |
| 146 | 144 |
| 147 // Set the results, notify the config, and return true if this | 145 // Set the results, notify the config, and return true if this |
| 148 // is the first time the result is being set. | 146 // is the first time the result is being set. |
| 149 void _setResult(String testResult, String messageText, String stack) { | 147 void _setResult(String testResult, String messageText, String stack) { |
| 150 message = messageText; | 148 _message = messageText; |
| 151 stackTrace = stack; | 149 _stackTrace = stack; |
| 152 if (result == null) { | 150 if (result == null) { |
| 153 result = testResult; | 151 _result = testResult; |
| 154 _config.onTestResult(this); | 152 _config.onTestResult(this); |
| 155 } else { | 153 } else { |
| 156 result = testResult; | 154 _result = testResult; |
| 157 _config.onTestResultChanged(this); | 155 _config.onTestResultChanged(this); |
| 158 } | 156 } |
| 159 } | 157 } |
| 160 | 158 |
| 161 void _complete(String testResult, | 159 void _complete(String testResult, |
| 162 [String messageText = '', | 160 [String messageText = '', |
| 163 String stack = '']) { | 161 String stack = '']) { |
| 164 if (runningTime == null) { | 162 if (runningTime == null) { |
| 165 // TODO(gram): currently the duration measurement code is blocked | 163 // TODO(gram): currently the duration measurement code is blocked |
| 166 // by issue 4437. When that is fixed replace the line below with: | 164 // by issue 4437. When that is fixed replace the line below with: |
| 167 // runningTime = new DateTime.now().difference(startTime); | 165 // runningTime = |
| 168 runningTime = new Duration(milliseconds: 0); | 166 _runningTime = new Duration(milliseconds: 0); |
| 169 } | 167 } |
| 170 _setResult(testResult, messageText, stack); | 168 _setResult(testResult, messageText, stack); |
| 171 if (!_doneTeardown) { | 169 if (!_doneTeardown) { |
| 172 _doneTeardown = true; | 170 _doneTeardown = true; |
| 173 if (_tearDown != null) { | 171 if (_tearDown != null) { |
| 174 var rtn = _tearDown(); | 172 var rtn = _tearDown(); |
| 175 if (rtn is Future) { | 173 if (rtn is Future) { |
| 176 rtn.then((_) { | 174 rtn.then((_) { |
| 177 _notifyComplete(); | 175 _notifyComplete(); |
| 178 }) | 176 }) |
| 179 .catchError((e) { | 177 .catchError((e) { |
| 180 // We don't call fail() as that will potentially result in | 178 // We don't call fail() as that will potentially result in |
| 181 // spurious messages like 'test failed more than once'. | 179 // spurious messages like 'test failed more than once'. |
| 182 _setResult(ERROR, "$description: Test teardown failed: ${e.error}", | 180 _setResult(ERROR, "$description: Test teardown failed: ${e.error}", |
| 183 e.stackTrace.toString()); | 181 e.stackTrace.toString()); |
| 184 _notifyComplete(); | 182 _notifyComplete(); |
| 185 }); | 183 }); |
| 186 return; | 184 return; |
| 187 } | 185 } |
| 188 } | 186 } |
| 189 } | 187 } |
| 190 _notifyComplete(); | 188 _notifyComplete(); |
| 191 } | 189 } |
| 192 | 190 |
| 193 void pass() { | 191 void _pass() { |
| 194 _complete(PASS); | 192 _complete(PASS); |
| 195 } | 193 } |
| 196 | 194 |
| 197 void fail(String messageText, [String stack = '']) { | 195 void _fail(String messageText, [String stack = '']) { |
| 198 if (result != null) { | 196 if (result != null) { |
|
gram
2013/03/05 18:07:41
I know that somewhere I have seen code like curren
| |
| 199 String newMessage = (result == PASS) | 197 String newMessage = (result == PASS) |
| 200 ? 'Test failed after initially passing: $messageText' | 198 ? 'Test failed after initially passing: $messageText' |
| 201 : 'Test failed more than once: $messageText'; | 199 : 'Test failed more than once: $messageText'; |
| 202 // TODO(gram): Should we combine the stack with the old one? | 200 // TODO(gram): Should we combine the stack with the old one? |
| 203 _complete(ERROR, newMessage, stack); | 201 _complete(ERROR, newMessage, stack); |
| 204 } else { | 202 } else { |
| 205 _complete(FAIL, messageText, stack); | 203 _complete(FAIL, messageText, stack); |
| 206 } | 204 } |
| 207 } | 205 } |
| 208 | 206 |
| 209 void error(String messageText, [String stack = '']) { | 207 void _error(String messageText, [String stack = '']) { |
| 210 _complete(ERROR, messageText, stack); | 208 _complete(ERROR, messageText, stack); |
| 211 } | 209 } |
| 212 | 210 |
| 213 void markCallbackComplete() { | 211 void _markCallbackComplete() { |
| 214 if (--callbackFunctionsOutstanding == 0 && !isComplete) { | 212 if (--_callbackFunctionsOutstanding == 0 && !isComplete) { |
| 215 pass(); | 213 _pass(); |
| 216 } | 214 } |
| 217 } | 215 } |
| 218 } | 216 } |
| OLD | NEW |