Chromium Code Reviews| 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 /// Support for writing Dart unit tests. | 5 /// Support for writing Dart unit tests. |
| 6 /// | 6 /// |
| 7 /// For information on installing and importing this library, see the | 7 /// For information on installing and importing this library, see the |
| 8 /// [unittest package on pub.dartlang.org] | 8 /// [unittest package on pub.dartlang.org] |
| 9 /// (http://pub.dartlang.org/packages/unittest). | 9 /// (http://pub.dartlang.org/packages/unittest). |
| 10 /// | 10 /// |
| (...skipping 133 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 144 | 144 |
| 145 import 'src/utils.dart'; | 145 import 'src/utils.dart'; |
| 146 | 146 |
| 147 import 'src/configuration.dart'; | 147 import 'src/configuration.dart'; |
| 148 export 'src/configuration.dart'; | 148 export 'src/configuration.dart'; |
| 149 | 149 |
| 150 part 'src/simple_configuration.dart'; | 150 part 'src/simple_configuration.dart'; |
| 151 part 'src/group_context.dart'; | 151 part 'src/group_context.dart'; |
| 152 part 'src/spread_args_helper.dart'; | 152 part 'src/spread_args_helper.dart'; |
| 153 part 'src/test_case.dart'; | 153 part 'src/test_case.dart'; |
| 154 part 'src/test_environment.dart'; | |
| 154 | 155 |
| 155 Configuration _config; | 156 const Symbol _TEST_ENVIRONMENT = #test_environment; |
| 157 | |
| 158 TestEnvironment _defaultEnvironment = new TestEnvironment(); | |
|
kustermann
2014/11/10 11:37:37
Make this final.
wibling
2014/11/11 12:18:54
Done.
| |
| 159 | |
| 160 /** | |
| 161 * Internal getter for the current unittest config. | |
| 162 */ | |
| 163 TestEnvironment get _environment { | |
| 164 var environment = Zone.current[_TEST_ENVIRONMENT]; | |
| 165 if (environment == null) { | |
| 166 return _defaultEnvironment; | |
| 167 } | |
| 168 return environment; | |
| 169 } | |
| 170 | |
| 171 // Convenience getter/setter for the current environment's config. | |
| 172 Configuration get _config => _environment.config; | |
| 173 void set _config(var config) { _environment.config = config; } | |
| 174 | |
| 175 // Convenience getter for the current environment's test cases. | |
| 176 List<TestCase> get _testCases => _environment.testCases; | |
| 156 | 177 |
| 157 /// [Configuration] used by the unittest library. Note that if a | 178 /// [Configuration] used by the unittest library. Note that if a |
| 158 /// configuration has not been set, calling this getter will create | 179 /// configuration has not been set, calling this getter will create |
| 159 /// a default configuration. | 180 /// a default configuration. |
| 160 Configuration get unittestConfiguration { | 181 Configuration get unittestConfiguration { |
| 161 if (_config == null) { | 182 if (_config == null) { |
| 162 _config = new Configuration(); | 183 _config = new Configuration(); |
| 163 } | 184 } |
| 164 return _config; | 185 return _config; |
| 165 } | 186 } |
| (...skipping 11 matching lines...) Expand all Loading... | |
| 177 } | 198 } |
| 178 | 199 |
| 179 /// Can be called by tests to log status. Tests should use this | 200 /// Can be called by tests to log status. Tests should use this |
| 180 /// instead of [print]. | 201 /// instead of [print]. |
| 181 void logMessage(String message) => | 202 void logMessage(String message) => |
| 182 _config.onLogMessage(currentTestCase, message); | 203 _config.onLogMessage(currentTestCase, message); |
| 183 | 204 |
| 184 /// Separator used between group names and test names. | 205 /// Separator used between group names and test names. |
| 185 String groupSep = ' '; | 206 String groupSep = ' '; |
| 186 | 207 |
| 187 final List<TestCase> _testCases = new List<TestCase>(); | |
| 188 | |
| 189 /// Tests executed in this suite. | 208 /// Tests executed in this suite. |
| 190 final List<TestCase> testCases = new UnmodifiableListView<TestCase>(_testCases); | 209 List<TestCase> get testCases => new UnmodifiableListView<TestCase>(_testCases); |
| 191 | 210 |
| 192 /// Interval (in msecs) after which synchronous tests will insert an async | 211 /// Interval (in msecs) after which synchronous tests will insert an async |
| 193 /// delay to allow DOM or other updates. | 212 /// delay to allow DOM or other updates. |
| 194 const int BREATH_INTERVAL = 200; | 213 const int BREATH_INTERVAL = 200; |
| 195 | 214 |
| 196 /// The set of tests to run can be restricted by using [solo_test] and | |
| 197 /// [solo_group]. | |
| 198 /// As groups can be nested we use a counter to keep track of the nest level | |
| 199 /// of soloing, and a flag to tell if we have seen any solo tests. | |
| 200 int _soloNestingLevel = 0; | |
| 201 bool _soloTestSeen = false; | |
| 202 | |
| 203 // We use a 'dummy' context for the top level to eliminate null | |
| 204 // checks when querying the context. This allows us to easily | |
| 205 // support top-level setUp/tearDown functions as well. | |
| 206 final _rootContext = new _GroupContext(); | |
| 207 _GroupContext _currentContext = _rootContext; | |
| 208 | |
| 209 /// Represents the index of the currently running test case | |
| 210 /// == -1 implies the test system is not running | |
| 211 /// == [number of test cases] is a short-lived state flagging that the last test | |
| 212 /// has completed | |
| 213 int _currentTestCaseIndex = -1; | |
| 214 | |
| 215 /// [TestCase] currently being executed. | 215 /// [TestCase] currently being executed. |
| 216 TestCase get currentTestCase => | 216 TestCase get currentTestCase => |
| 217 (_currentTestCaseIndex >= 0 && _currentTestCaseIndex < testCases.length) | 217 (_environment.currentTestCaseIndex >= 0 && _environment.currentTestCaseIndex < testCases.length) |
|
kustermann
2014/11/10 11:37:37
long line
wibling
2014/11/11 12:18:54
Done.
| |
| 218 ? testCases[_currentTestCaseIndex] | 218 ? testCases[_environment.currentTestCaseIndex] |
| 219 : null; | 219 : null; |
| 220 | 220 |
| 221 /// Whether the framework is in an initialized state. | |
| 222 bool _initialized = false; | |
| 223 | |
| 224 String _uncaughtErrorMessage = null; | |
| 225 | |
| 226 /// Time since we last gave non-sync code a chance to be scheduled. | |
| 227 int _lastBreath = new DateTime.now().millisecondsSinceEpoch; | |
| 228 | |
| 229 /* Test case result strings. */ | 221 /* Test case result strings. */ |
| 230 // TODO(gram) we should change these constants to use a different string | 222 // TODO(gram) we should change these constants to use a different string |
| 231 // (so that writing 'FAIL' in the middle of a test doesn't | 223 // (so that writing 'FAIL' in the middle of a test doesn't |
| 232 // imply that the test fails). We can't do it without also changing | 224 // imply that the test fails). We can't do it without also changing |
| 233 // the testrunner and test.dart though. | 225 // the testrunner and test.dart though. |
| 234 /// Result string for a passing test case. | 226 /// Result string for a passing test case. |
| 235 const PASS = 'pass'; | 227 const PASS = 'pass'; |
| 236 /// Result string for a failing test case. | 228 /// Result string for a failing test case. |
| 237 const FAIL = 'fail'; | 229 const FAIL = 'fail'; |
| 238 /// Result string for an test case with an error. | 230 /// Result string for an test case with an error. |
| 239 const ERROR = 'error'; | 231 const ERROR = 'error'; |
| 240 | 232 |
| 241 /// Creates a new test case with the given description and body. The | 233 /// Creates a new test case with the given description and body. The |
| 242 /// description will include the descriptions of any surrounding group() | 234 /// description will include the descriptions of any surrounding group() |
| 243 /// calls. | 235 /// calls. |
| 244 void test(String spec, TestFunction body) { | 236 void test(String spec, TestFunction body) { |
| 245 _requireNotRunning(); | 237 _requireNotRunning(); |
| 246 ensureInitialized(); | 238 ensureInitialized(); |
| 247 if (!_soloTestSeen || _soloNestingLevel > 0) { | 239 if (!_environment.soloTestSeen || _environment.soloNestingLevel > 0) { |
| 248 var testcase = new TestCase._internal(testCases.length + 1, _fullSpec(spec), | 240 var testcase = new TestCase._internal(testCases.length + 1, _fullSpec(spec), |
| 249 body); | 241 body); |
| 250 _testCases.add(testcase); | 242 _testCases.add(testcase); |
| 251 } | 243 } |
| 252 } | 244 } |
| 253 | 245 |
| 254 /// Convenience function for skipping a test. | 246 /// Convenience function for skipping a test. |
| 255 void skip_test(String spec, TestFunction body) {} | 247 void skip_test(String spec, TestFunction body) {} |
| 256 | 248 |
| 257 /// Creates a new test case with the given description and body. The | 249 /// Creates a new test case with the given description and body. The |
| 258 /// description will include the descriptions of any surrounding group() | 250 /// description will include the descriptions of any surrounding group() |
| 259 /// calls. | 251 /// calls. |
| 260 /// | 252 /// |
| 261 /// If we use [solo_test] (or [solo_group]) instead of test, then all non-solo | 253 /// If we use [solo_test] (or [solo_group]) instead of test, then all non-solo |
| 262 /// tests will be disabled. Note that if we use [solo_group], all tests in | 254 /// tests will be disabled. Note that if we use [solo_group], all tests in |
| 263 /// the group will be enabled, regardless of whether they use [test] or | 255 /// the group will be enabled, regardless of whether they use [test] or |
| 264 /// [solo_test], or whether they are in a nested [group] vs [solo_group]. Put | 256 /// [solo_test], or whether they are in a nested [group] vs [solo_group]. Put |
| 265 /// another way, if there are any calls to [solo_test] or [solo_group] in a test | 257 /// another way, if there are any calls to [solo_test] or [solo_group] in a test |
| 266 /// file, all tests that are not inside a [solo_group] will be disabled unless | 258 /// file, all tests that are not inside a [solo_group] will be disabled unless |
| 267 /// they are [solo_test]s. | 259 /// they are [solo_test]s. |
| 268 /// | 260 /// |
| 269 /// [skip_test] and [skip_group] take precedence over soloing, by virtue of the | 261 /// [skip_test] and [skip_group] take precedence over soloing, by virtue of the |
| 270 /// fact that they are effectively no-ops. | 262 /// fact that they are effectively no-ops. |
| 271 void solo_test(String spec, TestFunction body) { | 263 void solo_test(String spec, TestFunction body) { |
| 272 _requireNotRunning(); | 264 _requireNotRunning(); |
| 273 ensureInitialized(); | 265 ensureInitialized(); |
| 274 if (!_soloTestSeen) { | 266 if (!_environment.soloTestSeen) { |
| 275 _soloTestSeen = true; | 267 _environment.soloTestSeen = true; |
| 276 // This is the first solo-ed test. Discard all tests up to now. | 268 // This is the first solo-ed test. Discard all tests up to now. |
| 277 _testCases.clear(); | 269 _testCases.clear(); |
| 278 } | 270 } |
| 279 ++_soloNestingLevel; | 271 ++_environment.soloNestingLevel; |
| 280 try { | 272 try { |
| 281 test(spec, body); | 273 test(spec, body); |
| 282 } finally { | 274 } finally { |
| 283 --_soloNestingLevel; | 275 --_environment.soloNestingLevel; |
| 284 } | 276 } |
| 285 } | 277 } |
| 286 | 278 |
| 287 /// Indicate that [callback] is expected to be called a [count] number of times | 279 /// Indicate that [callback] is expected to be called a [count] number of times |
| 288 /// (by default 1). The unittest framework will wait for the callback to run the | 280 /// (by default 1). The unittest framework will wait for the callback to run the |
| 289 /// specified [count] times before it continues with the following test. Using | 281 /// specified [count] times before it continues with the following test. Using |
| 290 /// [expectAsync] will also ensure that errors that occur within [callback] are | 282 /// [expectAsync] will also ensure that errors that occur within [callback] are |
| 291 /// tracked and reported. [callback] should take 0 positional arguments (named | 283 /// tracked and reported. [callback] should take 0 positional arguments (named |
| 292 /// arguments are not supported). [id] can be used to provide more | 284 /// arguments are not supported). [id] can be used to provide more |
| 293 /// descriptive error messages if the callback is called more often than | 285 /// descriptive error messages if the callback is called more often than |
| (...skipping 16 matching lines...) Expand all Loading... | |
| 310 /// identify the callback in error messages (for example if it is called | 302 /// identify the callback in error messages (for example if it is called |
| 311 /// after the test case is complete). | 303 /// after the test case is complete). |
| 312 Function expectAsyncUntil(Function callback, bool isDone(), {String id}) => | 304 Function expectAsyncUntil(Function callback, bool isDone(), {String id}) => |
| 313 new _SpreadArgsHelper(callback, 0, -1, id, isDone: isDone).func; | 305 new _SpreadArgsHelper(callback, 0, -1, id, isDone: isDone).func; |
| 314 | 306 |
| 315 /// Creates a new named group of tests. Calls to group() or test() within the | 307 /// Creates a new named group of tests. Calls to group() or test() within the |
| 316 /// body of the function passed to this will inherit this group's description. | 308 /// body of the function passed to this will inherit this group's description. |
| 317 void group(String description, void body()) { | 309 void group(String description, void body()) { |
| 318 ensureInitialized(); | 310 ensureInitialized(); |
| 319 _requireNotRunning(); | 311 _requireNotRunning(); |
| 320 _currentContext = new _GroupContext(_currentContext, description); | 312 _environment.currentContext = new _GroupContext(_environment.currentContext, d escription); |
| 321 try { | 313 try { |
| 322 body(); | 314 body(); |
| 323 } catch (e, trace) { | 315 } catch (e, trace) { |
| 324 var stack = (trace == null) ? '' : ': ${trace.toString()}'; | 316 var stack = (trace == null) ? '' : ': ${trace.toString()}'; |
| 325 _uncaughtErrorMessage = "${e.toString()}$stack"; | 317 _environment.uncaughtErrorMessage = "${e.toString()}$stack"; |
| 326 } finally { | 318 } finally { |
| 327 // Now that the group is over, restore the previous one. | 319 // Now that the group is over, restore the previous one. |
| 328 _currentContext = _currentContext.parent; | 320 _environment.currentContext = _environment.currentContext.parent; |
| 329 } | 321 } |
| 330 } | 322 } |
| 331 | 323 |
| 332 /// Like [skip_test], but for groups. | 324 /// Like [skip_test], but for groups. |
| 333 void skip_group(String description, void body()) {} | 325 void skip_group(String description, void body()) {} |
| 334 | 326 |
| 335 /// Like [solo_test], but for groups. | 327 /// Like [solo_test], but for groups. |
| 336 void solo_group(String description, void body()) { | 328 void solo_group(String description, void body()) { |
| 337 _requireNotRunning(); | 329 _requireNotRunning(); |
| 338 ensureInitialized(); | 330 ensureInitialized(); |
| 339 if (!_soloTestSeen) { | 331 if (!_environment.soloTestSeen) { |
| 340 _soloTestSeen = true; | 332 _environment.soloTestSeen = true; |
| 341 // This is the first solo-ed group. Discard all tests up to now. | 333 // This is the first solo-ed group. Discard all tests up to now. |
| 342 _testCases.clear(); | 334 _testCases.clear(); |
| 343 } | 335 } |
| 344 ++_soloNestingLevel; | 336 ++_environment.soloNestingLevel; |
| 345 try { | 337 try { |
| 346 group(description, body); | 338 group(description, body); |
| 347 } finally { | 339 } finally { |
| 348 --_soloNestingLevel; | 340 --_environment.soloNestingLevel; |
| 349 } | 341 } |
| 350 } | 342 } |
| 351 | 343 |
| 352 /// Register a [setUp] function for a test [group]. This function will | 344 /// Register a [setUp] function for a test [group]. This function will |
| 353 /// be called before each test in the group is run. | 345 /// be called before each test in the group is run. |
| 354 /// [setUp] and [tearDown] should be called within the [group] before any | 346 /// [setUp] and [tearDown] should be called within the [group] before any |
| 355 /// calls to [test]. The [setupTest] function can be asynchronous; in this | 347 /// calls to [test]. The [setupTest] function can be asynchronous; in this |
| 356 /// case it must return a [Future]. | 348 /// case it must return a [Future]. |
| 357 void setUp(Function setupTest) { | 349 void setUp(Function setupTest) { |
| 358 _requireNotRunning(); | 350 _requireNotRunning(); |
| 359 _currentContext.testSetup = setupTest; | 351 _environment.currentContext.testSetup = setupTest; |
| 360 } | 352 } |
| 361 | 353 |
| 362 /// Register a [tearDown] function for a test [group]. This function will | 354 /// Register a [tearDown] function for a test [group]. This function will |
| 363 /// be called after each test in the group is run. Note that if groups | 355 /// be called after each test in the group is run. Note that if groups |
| 364 /// are nested only the most locally scoped [teardownTest] function will be run. | 356 /// are nested only the most locally scoped [teardownTest] function will be run. |
| 365 /// [setUp] and [tearDown] should be called within the [group] before any | 357 /// [setUp] and [tearDown] should be called within the [group] before any |
| 366 /// calls to [test]. The [teardownTest] function can be asynchronous; in this | 358 /// calls to [test]. The [teardownTest] function can be asynchronous; in this |
| 367 /// case it must return a [Future]. | 359 /// case it must return a [Future]. |
| 368 void tearDown(Function teardownTest) { | 360 void tearDown(Function teardownTest) { |
| 369 _requireNotRunning(); | 361 _requireNotRunning(); |
| 370 _currentContext.testTeardown = teardownTest; | 362 _environment.currentContext.testTeardown = teardownTest; |
| 371 } | 363 } |
| 372 | 364 |
| 373 /// Advance to the next test case. | 365 /// Advance to the next test case. |
| 374 void _nextTestCase() { | 366 void _nextTestCase() { |
| 375 _currentTestCaseIndex++; | 367 _environment.currentTestCaseIndex++; |
| 376 _runTest(); | 368 _runTest(); |
| 377 } | 369 } |
| 378 | 370 |
| 379 /// Handle errors that happen outside the tests. | 371 /// Handle errors that happen outside the tests. |
| 380 // TODO(vsm): figure out how to expose the stack trace here | 372 // TODO(vsm): figure out how to expose the stack trace here |
| 381 // Currently e.message works in dartium, but not in dartc. | 373 // Currently e.message works in dartium, but not in dartc. |
| 382 void handleExternalError(e, String message, [stack]) { | 374 void handleExternalError(e, String message, [stack]) { |
| 383 var msg = '$message\nCaught $e'; | 375 var msg = '$message\nCaught $e'; |
| 384 | 376 |
| 385 if (currentTestCase != null) { | 377 if (currentTestCase != null) { |
| 386 currentTestCase._error(msg, stack); | 378 currentTestCase._error(msg, stack); |
| 387 } else { | 379 } else { |
| 388 _uncaughtErrorMessage = "$msg: $stack"; | 380 _environment.uncaughtErrorMessage = "$msg: $stack"; |
| 389 } | 381 } |
| 390 } | 382 } |
| 391 | 383 |
| 392 /// Filter the tests. [testFilter] can be a [RegExp], a [String] or a | 384 /// Filter the tests. [testFilter] can be a [RegExp], a [String] or a |
| 393 /// predicate function. This is different to enabling/disabling tests | 385 /// predicate function. This is different to enabling/disabling tests |
| 394 /// in that it removes the tests completely. | 386 /// in that it removes the tests completely. |
| 395 void filterTests(testFilter) { | 387 void filterTests(testFilter) { |
| 396 var filterFunction; | 388 var filterFunction; |
| 397 if (testFilter is String) { | 389 if (testFilter is String) { |
| 398 RegExp re = new RegExp(testFilter); | 390 RegExp re = new RegExp(testFilter); |
| 399 filterFunction = (t) => re.hasMatch(t.description); | 391 filterFunction = (t) => re.hasMatch(t.description); |
| 400 } else if (testFilter is RegExp) { | 392 } else if (testFilter is RegExp) { |
| 401 filterFunction = (t) => testFilter.hasMatch(t.description); | 393 filterFunction = (t) => testFilter.hasMatch(t.description); |
| 402 } else if (testFilter is Function) { | 394 } else if (testFilter is Function) { |
| 403 filterFunction = testFilter; | 395 filterFunction = testFilter; |
| 404 } | 396 } |
| 405 _testCases.retainWhere(filterFunction); | 397 _testCases.retainWhere(filterFunction); |
| 406 } | 398 } |
| 407 | 399 |
| 408 /// Runs all queued tests, one at a time. | 400 /// Runs all queued tests, one at a time. |
| 409 void runTests() { | 401 void runTests() { |
| 410 _requireNotRunning(); | 402 _requireNotRunning(); |
| 411 _ensureInitialized(false); | 403 _ensureInitialized(false); |
| 412 _currentTestCaseIndex = 0; | 404 _environment.currentTestCaseIndex = 0; |
| 413 _config.onStart(); | 405 _config.onStart(); |
| 414 _runTest(); | 406 _runTest(); |
| 415 } | 407 } |
| 416 | 408 |
| 417 /// Registers that an exception was caught for the current test. | 409 /// Registers that an exception was caught for the current test. |
| 418 void registerException(e, [trace]) { | 410 void registerException(e, [trace]) { |
| 419 _registerException(currentTestCase, e, trace); | 411 _registerException(currentTestCase, e, trace); |
| 420 } | 412 } |
| 421 | 413 |
| 422 /// Registers that an exception was caught for the current test. | 414 /// Registers that an exception was caught for the current test. |
| 423 void _registerException(TestCase testCase, e, [trace]) { | 415 void _registerException(TestCase testCase, e, [trace]) { |
| 424 String message = (e is TestFailure) ? e.message : 'Caught $e'; | 416 String message = (e is TestFailure) ? e.message : 'Caught $e'; |
| 425 if (testCase.result == null) { | 417 if (testCase.result == null) { |
| 426 testCase._fail(message, trace); | 418 testCase._fail(message, trace); |
| 427 } else { | 419 } else { |
| 428 testCase._error(message, trace); | 420 testCase._error(message, trace); |
| 429 } | 421 } |
| 430 } | 422 } |
| 431 | 423 |
| 432 /// Runs the next test. | 424 /// Runs the next test. |
| 433 void _runTest() { | 425 void _runTest() { |
| 434 if (_currentTestCaseIndex >= testCases.length) { | 426 if (_environment.currentTestCaseIndex >= testCases.length) { |
| 435 assert(_currentTestCaseIndex == testCases.length); | 427 assert(_environment.currentTestCaseIndex == testCases.length); |
| 436 _completeTests(); | 428 _completeTests(); |
| 437 } else { | 429 } else { |
| 438 var testCase = testCases[_currentTestCaseIndex]; | 430 var testCase = testCases[_environment.currentTestCaseIndex]; |
| 439 Future f = runZoned(testCase._run, onError: (error, stack) { | 431 Future f = runZoned(testCase._run, onError: (error, stack) { |
| 440 // TODO(kevmoo) Do a better job of flagging these are async errors. | 432 // TODO(kevmoo) Do a better job of flagging these are async errors. |
| 441 // https://code.google.com/p/dart/issues/detail?id=16530 | 433 // https://code.google.com/p/dart/issues/detail?id=16530 |
| 442 _registerException(testCase, error, stack); | 434 _registerException(testCase, error, stack); |
| 443 }); | 435 }); |
| 444 | 436 |
| 445 var timeout = unittestConfiguration.timeout; | 437 var timeout = unittestConfiguration.timeout; |
| 446 | 438 |
| 447 Timer timer; | 439 Timer timer; |
| 448 if (timeout != null) { | 440 if (timeout != null) { |
| 449 try { | 441 try { |
| 450 timer = new Timer(timeout, () { | 442 timer = new Timer(timeout, () { |
| 451 testCase._error("Test timed out after ${timeout.inSeconds} seconds."); | 443 testCase._error("Test timed out after ${timeout.inSeconds} seconds."); |
| 452 _nextTestCase(); | 444 _nextTestCase(); |
| 453 }); | 445 }); |
| 454 } on UnsupportedError catch (e) { | 446 } on UnsupportedError catch (e) { |
| 455 if (e.message != "Timer greater than 0.") rethrow; | 447 if (e.message != "Timer greater than 0.") rethrow; |
| 456 // Support running on d8 and jsshell which don't support timers. | 448 // Support running on d8 and jsshell which don't support timers. |
| 457 } | 449 } |
| 458 } | 450 } |
| 459 f.whenComplete(() { | 451 f.whenComplete(() { |
| 460 if (timer != null) timer.cancel(); | 452 if (timer != null) timer.cancel(); |
| 461 var now = new DateTime.now().millisecondsSinceEpoch; | 453 var now = new DateTime.now().millisecondsSinceEpoch; |
| 462 if ((now - _lastBreath) >= BREATH_INTERVAL) { | 454 if ((now - _environment.lastBreath) >= BREATH_INTERVAL) { |
| 463 _lastBreath = now; | 455 _environment.lastBreath = now; |
| 464 Timer.run(_nextTestCase); | 456 Timer.run(_nextTestCase); |
| 465 } else { | 457 } else { |
| 466 scheduleMicrotask(_nextTestCase); // Schedule the next test. | 458 scheduleMicrotask(_nextTestCase); // Schedule the next test. |
| 467 } | 459 } |
| 468 }); | 460 }); |
| 469 } | 461 } |
| 470 } | 462 } |
| 471 | 463 |
| 472 /// Publish results on the page and notify controller. | 464 /// Publish results on the page and notify controller. |
| 473 void _completeTests() { | 465 void _completeTests() { |
| 474 if (!_initialized) return; | 466 if (!_environment.initialized) return; |
| 475 int passed = 0; | 467 int passed = 0; |
| 476 int failed = 0; | 468 int failed = 0; |
| 477 int errors = 0; | 469 int errors = 0; |
| 478 | 470 |
| 479 for (TestCase t in testCases) { | 471 for (TestCase t in testCases) { |
| 480 switch (t.result) { | 472 switch (t.result) { |
| 481 case PASS: passed++; break; | 473 case PASS: passed++; break; |
| 482 case FAIL: failed++; break; | 474 case FAIL: failed++; break; |
| 483 case ERROR: errors++; break; | 475 case ERROR: errors++; break; |
| 484 } | 476 } |
| 485 } | 477 } |
| 486 _config.onSummary(passed, failed, errors, testCases, _uncaughtErrorMessage); | 478 _config.onSummary(passed, failed, errors, testCases, _environment.uncaughtErro rMessage); |
|
kustermann
2014/11/10 11:37:37
long line
wibling
2014/11/11 12:18:54
Done.
| |
| 487 _config.onDone(passed > 0 && failed == 0 && errors == 0 && | 479 _config.onDone(passed > 0 && failed == 0 && errors == 0 && |
| 488 _uncaughtErrorMessage == null); | 480 _environment.uncaughtErrorMessage == null); |
| 489 _initialized = false; | 481 _environment.initialized = false; |
| 490 _currentTestCaseIndex = -1; | 482 _environment.currentTestCaseIndex = -1; |
| 491 } | 483 } |
| 492 | 484 |
| 493 String _fullSpec(String spec) { | 485 String _fullSpec(String spec) { |
| 494 var group = '${_currentContext.fullName}'; | 486 var group = '${_environment.currentContext.fullName}'; |
| 495 if (spec == null) return group; | 487 if (spec == null) return group; |
| 496 return group != '' ? '$group$groupSep$spec' : spec; | 488 return group != '' ? '$group$groupSep$spec' : spec; |
| 497 } | 489 } |
| 498 | 490 |
| 499 /// Lazily initializes the test library if not already initialized. | 491 /// Lazily initializes the test library if not already initialized. |
| 500 void ensureInitialized() { | 492 void ensureInitialized() { |
| 501 _ensureInitialized(true); | 493 _ensureInitialized(true); |
| 502 } | 494 } |
| 503 | 495 |
| 504 void _ensureInitialized(bool configAutoStart) { | 496 void _ensureInitialized(bool configAutoStart) { |
| 505 if (_initialized) { | 497 if (_environment.initialized) { |
| 506 return; | 498 return; |
| 507 } | 499 } |
| 508 _initialized = true; | 500 _environment.initialized = true; |
| 509 // Hook our async guard into the matcher library. | 501 // Hook our async guard into the matcher library. |
| 510 wrapAsync = (f, [id]) => expectAsync(f, id: id); | 502 wrapAsync = (f, [id]) => expectAsync(f, id: id); |
| 511 | 503 |
| 512 _uncaughtErrorMessage = null; | 504 _environment.uncaughtErrorMessage = null; |
| 513 | 505 |
| 514 unittestConfiguration.onInit(); | 506 unittestConfiguration.onInit(); |
| 515 | 507 |
| 516 if (configAutoStart && _config.autoStart) { | 508 if (configAutoStart && _config.autoStart) { |
| 517 // Immediately queue the suite up. It will run after a timeout (i.e. after | 509 // Immediately queue the suite up. It will run after a timeout (i.e. after |
| 518 // main() has returned). | 510 // main() has returned). |
| 519 scheduleMicrotask(runTests); | 511 scheduleMicrotask(runTests); |
| 520 } | 512 } |
| 521 } | 513 } |
| 522 | 514 |
| (...skipping 28 matching lines...) Expand all Loading... | |
| 551 /// exception stacks. | 543 /// exception stacks. |
| 552 /// | 544 /// |
| 553 /// Useful to disable when debugging unittest or matcher customizations. | 545 /// Useful to disable when debugging unittest or matcher customizations. |
| 554 bool formatStacks = true; | 546 bool formatStacks = true; |
| 555 | 547 |
| 556 /// A flag that controls whether we try to filter out irrelevant frames from | 548 /// A flag that controls whether we try to filter out irrelevant frames from |
| 557 /// the stack trace. Requires formatStacks to be set. | 549 /// the stack trace. Requires formatStacks to be set. |
| 558 bool filterStacks = true; | 550 bool filterStacks = true; |
| 559 | 551 |
| 560 void _requireNotRunning() { | 552 void _requireNotRunning() { |
| 561 if (_currentTestCaseIndex != -1) { | 553 if (_environment.currentTestCaseIndex != -1) { |
| 562 throw new StateError('Not allowed when tests are running.'); | 554 throw new StateError('Not allowed when tests are running.'); |
| 563 } | 555 } |
| 564 } | 556 } |
| 557 | |
| 558 /// Method to support multiple invocations of the unittest library in the same | |
| 559 /// application instance. | |
| 560 dynamic withTestEnvironment(callback()) { | |
| 561 print("Creating new test env!"); | |
|
kustermann
2014/11/10 11:37:37
left-over print?
wibling
2014/11/11 12:18:54
Indeed:) Removed.
| |
| 562 return runZoned(callback, | |
| 563 zoneValues: <Symbol, Object>{_TEST_ENVIRONMENT: new TestEnvironment()}, | |
| 564 onError: (error, stack) => print("$error\nStack:\n$stack")); | |
|
kustermann
2014/11/10 11:37:37
Maybe there is a better way then printing the erro
wibling
2014/11/11 12:18:54
I removed the onError handler and used the default
| |
| 565 } | |
| OLD | NEW |