Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(761)

Side by Side Diff: pkg/unittest/lib/unittest.dart

Issue 709903004: Enhance the Dart unittest library to support multiple invocations in the same application run. (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Created 6 years, 1 month ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
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
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 _UNITTEST_ENVIRONMENT = #unittest.environment;
157
158 final _TestEnvironment _defaultEnvironment = new _TestEnvironment();
159
160 /**
161 * Internal getter for the current unittest config.
162 */
163 _TestEnvironment get _environment {
164 var environment = Zone.current[_UNITTEST_ENVIRONMENT];
165 if (environment == null)
166 return _defaultEnvironment;
167 return environment;
168 }
169
170 // Convenience getter for the current environment's config.
171 Configuration get _config => _environment.config;
172
173 // Convenience setter for the current environment's config.
174 void set _config(Configuration config) {
175 _environment.config = config;
176 }
177
178 // Convenience getter for the current environment's test cases.
179 List<TestCase> get _testCases => _environment.testCases;
156 180
157 /// [Configuration] used by the unittest library. 181 /// [Configuration] used by the unittest library.
158 /// 182 ///
159 /// Note that if a configuration has not been set, calling this getter will 183 /// Note that if a configuration has not been set, calling this getter will
160 /// create a default configuration. 184 /// create a default configuration.
161 Configuration get unittestConfiguration { 185 Configuration get unittestConfiguration {
162 if (_config == null) { 186 if (_config == null) {
163 _config = new Configuration(); 187 _config = new Configuration();
164 } 188 }
165 return _config; 189 return _config;
(...skipping 12 matching lines...) Expand all
178 } 202 }
179 203
180 /// Can be called by tests to log status. Tests should use this 204 /// Can be called by tests to log status. Tests should use this
181 /// instead of [print]. 205 /// instead of [print].
182 void logMessage(String message) => 206 void logMessage(String message) =>
183 _config.onLogMessage(currentTestCase, message); 207 _config.onLogMessage(currentTestCase, message);
184 208
185 /// Separator used between group names and test names. 209 /// Separator used between group names and test names.
186 String groupSep = ' '; 210 String groupSep = ' ';
187 211
188 final List<TestCase> _testCases = new List<TestCase>();
189
190 /// Tests executed in this suite. 212 /// Tests executed in this suite.
191 final List<TestCase> testCases = new UnmodifiableListView<TestCase>(_testCases); 213 final List<TestCase> testCases =
nweiz 2014/11/17 23:02:55 This should be a getter, not a field. As a field i
wibling 2014/11/18 10:16:49 Thanks for catching this. I missed that when chang
214 new UnmodifiableListView<TestCase>(_environment.testCases);
192 215
193 /// Interval (in msecs) after which synchronous tests will insert an async 216 /// Interval (in msecs) after which synchronous tests will insert an async
194 /// delay to allow DOM or other updates. 217 /// delay to allow DOM or other updates.
195 const int BREATH_INTERVAL = 200; 218 const int BREATH_INTERVAL = 200;
196 219
197 /// The set of tests to run can be restricted by using [solo_test] and
198 /// [solo_group].
199 /// As groups can be nested we use a counter to keep track of the nest level
200 /// of soloing, and a flag to tell if we have seen any solo tests.
201 int _soloNestingLevel = 0;
202 bool _soloTestSeen = false;
203
204 // We use a 'dummy' context for the top level to eliminate null
205 // checks when querying the context. This allows us to easily
206 // support top-level setUp/tearDown functions as well.
207 final _rootContext = new _GroupContext();
208 _GroupContext _currentContext = _rootContext;
209
210 /// Represents the index of the currently running test case
211 /// == -1 implies the test system is not running
212 /// == [number of test cases] is a short-lived state flagging that the last test
213 /// has completed
214 int _currentTestCaseIndex = -1;
215
216 /// [TestCase] currently being executed. 220 /// [TestCase] currently being executed.
217 TestCase get currentTestCase => 221 TestCase get currentTestCase =>
218 (_currentTestCaseIndex >= 0 && _currentTestCaseIndex < testCases.length) 222 (_environment.currentTestCaseIndex >= 0 &&
219 ? testCases[_currentTestCaseIndex] 223 _environment.currentTestCaseIndex < testCases.length)
224 ? testCases[_environment.currentTestCaseIndex]
220 : null; 225 : null;
221 226
222 /// Whether the framework is in an initialized state.
223 bool _initialized = false;
224
225 String _uncaughtErrorMessage = null;
226
227 /// Time since we last gave non-sync code a chance to be scheduled.
228 int _lastBreath = new DateTime.now().millisecondsSinceEpoch;
229
230 /* Test case result strings. */ 227 /* Test case result strings. */
231 // TODO(gram) we should change these constants to use a different string 228 // TODO(gram) we should change these constants to use a different string
232 // (so that writing 'FAIL' in the middle of a test doesn't 229 // (so that writing 'FAIL' in the middle of a test doesn't
233 // imply that the test fails). We can't do it without also changing 230 // imply that the test fails). We can't do it without also changing
234 // the testrunner and test.dart though. 231 // the testrunner and test.dart though.
235 /// Result string for a passing test case. 232 /// Result string for a passing test case.
236 const PASS = 'pass'; 233 const PASS = 'pass';
237 /// Result string for a failing test case. 234 /// Result string for a failing test case.
238 const FAIL = 'fail'; 235 const FAIL = 'fail';
239 /// Result string for an test case with an error. 236 /// Result string for an test case with an error.
240 const ERROR = 'error'; 237 const ERROR = 'error';
241 238
242 /// Creates a new test case with the given description and body. The 239 /// Creates a new test case with the given description and body. The
243 /// description will include the descriptions of any surrounding group() 240 /// description will include the descriptions of any surrounding group()
244 /// calls. 241 /// calls.
245 void test(String spec, TestFunction body) { 242 void test(String spec, TestFunction body) {
246 _requireNotRunning(); 243 _requireNotRunning();
247 ensureInitialized(); 244 ensureInitialized();
248 if (!_soloTestSeen || _soloNestingLevel > 0) { 245 if (!_environment.soloTestSeen || _environment.soloNestingLevel > 0) {
249 var testcase = new TestCase._internal(testCases.length + 1, _fullSpec(spec), 246 var testcase = new TestCase._internal(testCases.length + 1, _fullSpec(spec),
250 body); 247 body);
251 _testCases.add(testcase); 248 _testCases.add(testcase);
252 } 249 }
253 } 250 }
254 251
255 /// Convenience function for skipping a test. 252 /// Convenience function for skipping a test.
256 void skip_test(String spec, TestFunction body) {} 253 void skip_test(String spec, TestFunction body) {}
257 254
258 /// Creates a new test case with the given description and body. The 255 /// Creates a new test case with the given description and body. The
259 /// description will include the descriptions of any surrounding group() 256 /// description will include the descriptions of any surrounding group()
260 /// calls. 257 /// calls.
261 /// 258 ///
262 /// If we use [solo_test] (or [solo_group]) instead of test, then all non-solo 259 /// If we use [solo_test] (or [solo_group]) instead of test, then all non-solo
263 /// tests will be disabled. Note that if we use [solo_group], all tests in 260 /// tests will be disabled. Note that if we use [solo_group], all tests in
264 /// the group will be enabled, regardless of whether they use [test] or 261 /// the group will be enabled, regardless of whether they use [test] or
265 /// [solo_test], or whether they are in a nested [group] vs [solo_group]. Put 262 /// [solo_test], or whether they are in a nested [group] vs [solo_group]. Put
266 /// another way, if there are any calls to [solo_test] or [solo_group] in a test 263 /// another way, if there are any calls to [solo_test] or [solo_group] in a test
267 /// file, all tests that are not inside a [solo_group] will be disabled unless 264 /// file, all tests that are not inside a [solo_group] will be disabled unless
268 /// they are [solo_test]s. 265 /// they are [solo_test]s.
269 /// 266 ///
270 /// [skip_test] and [skip_group] take precedence over soloing, by virtue of the 267 /// [skip_test] and [skip_group] take precedence over soloing, by virtue of the
271 /// fact that they are effectively no-ops. 268 /// fact that they are effectively no-ops.
272 void solo_test(String spec, TestFunction body) { 269 void solo_test(String spec, TestFunction body) {
273 _requireNotRunning(); 270 _requireNotRunning();
274 ensureInitialized(); 271 ensureInitialized();
275 if (!_soloTestSeen) { 272 if (!_environment.soloTestSeen) {
276 _soloTestSeen = true; 273 _environment.soloTestSeen = true;
277 // This is the first solo-ed test. Discard all tests up to now. 274 // This is the first solo-ed test. Discard all tests up to now.
278 _testCases.clear(); 275 _testCases.clear();
279 } 276 }
280 ++_soloNestingLevel; 277 ++_environment.soloNestingLevel;
281 try { 278 try {
282 test(spec, body); 279 test(spec, body);
283 } finally { 280 } finally {
284 --_soloNestingLevel; 281 --_environment.soloNestingLevel;
285 } 282 }
286 } 283 }
287 284
288 /// Indicate that [callback] is expected to be called a [count] number of times 285 /// Indicate that [callback] is expected to be called a [count] number of times
289 /// (by default 1). 286 /// (by default 1).
290 /// 287 ///
291 /// The unittest framework will wait for the callback to run the 288 /// The unittest framework will wait for the callback to run the
292 /// specified [count] times before it continues with the following test. Using 289 /// specified [count] times before it continues with the following test. Using
293 /// [expectAsync] will also ensure that errors that occur within [callback] are 290 /// [expectAsync] will also ensure that errors that occur within [callback] are
294 /// tracked and reported. [callback] should take 0 positional arguments (named 291 /// tracked and reported. [callback] should take 0 positional arguments (named
(...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after
328 {String id, String reason}) => 325 {String id, String reason}) =>
329 new _SpreadArgsHelper(callback, 0, -1, id, reason, isDone: isDone).func; 326 new _SpreadArgsHelper(callback, 0, -1, id, reason, isDone: isDone).func;
330 327
331 /// Creates a new named group of tests. 328 /// Creates a new named group of tests.
332 /// 329 ///
333 /// Calls to group() or test() within the body of the function passed to this 330 /// Calls to group() or test() within the body of the function passed to this
334 /// named group will inherit this group's description. 331 /// named group will inherit this group's description.
335 void group(String description, void body()) { 332 void group(String description, void body()) {
336 ensureInitialized(); 333 ensureInitialized();
337 _requireNotRunning(); 334 _requireNotRunning();
338 _currentContext = new _GroupContext(_currentContext, description); 335 _environment.currentContext =
336 new _GroupContext(_environment.currentContext, description);
339 try { 337 try {
340 body(); 338 body();
341 } catch (e, trace) { 339 } catch (e, trace) {
342 var stack = (trace == null) ? '' : ': ${trace.toString()}'; 340 var stack = (trace == null) ? '' : ': ${trace.toString()}';
343 _uncaughtErrorMessage = "${e.toString()}$stack"; 341 _environment.uncaughtErrorMessage = "${e.toString()}$stack";
344 } finally { 342 } finally {
345 // Now that the group is over, restore the previous one. 343 // Now that the group is over, restore the previous one.
346 _currentContext = _currentContext.parent; 344 _environment.currentContext = _environment.currentContext.parent;
347 } 345 }
348 } 346 }
349 347
350 /// Like [skip_test], but for groups. 348 /// Like [skip_test], but for groups.
351 void skip_group(String description, void body()) {} 349 void skip_group(String description, void body()) {}
352 350
353 /// Like [solo_test], but for groups. 351 /// Like [solo_test], but for groups.
354 void solo_group(String description, void body()) { 352 void solo_group(String description, void body()) {
355 _requireNotRunning(); 353 _requireNotRunning();
356 ensureInitialized(); 354 ensureInitialized();
357 if (!_soloTestSeen) { 355 if (!_environment.soloTestSeen) {
358 _soloTestSeen = true; 356 _environment.soloTestSeen = true;
359 // This is the first solo-ed group. Discard all tests up to now. 357 // This is the first solo-ed group. Discard all tests up to now.
360 _testCases.clear(); 358 _testCases.clear();
361 } 359 }
362 ++_soloNestingLevel; 360 ++_environment.soloNestingLevel;
363 try { 361 try {
364 group(description, body); 362 group(description, body);
365 } finally { 363 } finally {
366 --_soloNestingLevel; 364 --_environment.soloNestingLevel;
367 } 365 }
368 } 366 }
369 367
370 /// Register a [setUp] function for a test [group]. 368 /// Register a [setUp] function for a test [group].
371 /// 369 ///
372 /// This function will be called before each test in the group is run. 370 /// This function will be called before each test in the group is run.
373 /// [setUp] and [tearDown] should be called within the [group] before any 371 /// [setUp] and [tearDown] should be called within the [group] before any
374 /// calls to [test]. The [setupTest] function can be asynchronous; in this 372 /// calls to [test]. The [setupTest] function can be asynchronous; in this
375 /// case it must return a [Future]. 373 /// case it must return a [Future].
376 void setUp(Function setupTest) { 374 void setUp(Function setupTest) {
377 _requireNotRunning(); 375 _requireNotRunning();
378 _currentContext.testSetup = setupTest; 376 _environment.currentContext.testSetup = setupTest;
379 } 377 }
380 378
381 /// Register a [tearDown] function for a test [group]. 379 /// Register a [tearDown] function for a test [group].
382 /// 380 ///
383 /// This function will be called after each test in the group is run. 381 /// This function will be called after each test in the group is run.
384 /// 382 ///
385 /// Note that if groups are nested only the most locally scoped [teardownTest] 383 /// Note that if groups are nested only the most locally scoped [teardownTest]
386 /// function will be run. [setUp] and [tearDown] should be called within the 384 /// function will be run. [setUp] and [tearDown] should be called within the
387 /// [group] before any calls to [test]. The [teardownTest] function can be 385 /// [group] before any calls to [test]. The [teardownTest] function can be
388 /// asynchronous; in this case it must return a [Future]. 386 /// asynchronous; in this case it must return a [Future].
389 void tearDown(Function teardownTest) { 387 void tearDown(Function teardownTest) {
390 _requireNotRunning(); 388 _requireNotRunning();
391 _currentContext.testTeardown = teardownTest; 389 _environment.currentContext.testTeardown = teardownTest;
392 } 390 }
393 391
394 /// Advance to the next test case. 392 /// Advance to the next test case.
395 void _nextTestCase() { 393 void _nextTestCase() {
396 _currentTestCaseIndex++; 394 _environment.currentTestCaseIndex++;
397 _runTest(); 395 _runTest();
398 } 396 }
399 397
400 /// Handle errors that happen outside the tests. 398 /// Handle errors that happen outside the tests.
401 // TODO(vsm): figure out how to expose the stack trace here 399 // TODO(vsm): figure out how to expose the stack trace here
402 // Currently e.message works in dartium, but not in dartc. 400 // Currently e.message works in dartium, but not in dartc.
403 void handleExternalError(e, String message, [stack]) { 401 void handleExternalError(e, String message, [stack]) {
404 var msg = '$message\nCaught $e'; 402 var msg = '$message\nCaught $e';
405 403
406 if (currentTestCase != null) { 404 if (currentTestCase != null) {
407 currentTestCase._error(msg, stack); 405 currentTestCase._error(msg, stack);
408 } else { 406 } else {
409 _uncaughtErrorMessage = "$msg: $stack"; 407 _environment.uncaughtErrorMessage = "$msg: $stack";
410 } 408 }
411 } 409 }
412 410
413 /// Filter the tests by [testFilter]. 411 /// Filter the tests by [testFilter].
414 /// 412 ///
415 /// [testFilter] can be a [RegExp], a [String] or a 413 /// [testFilter] can be a [RegExp], a [String] or a
416 /// predicate function. This is different from enabling or disabling tests 414 /// predicate function. This is different from enabling or disabling tests
417 /// in that it removes the tests completely. 415 /// in that it removes the tests completely.
418 void filterTests(testFilter) { 416 void filterTests(testFilter) {
419 var filterFunction; 417 var filterFunction;
420 if (testFilter is String) { 418 if (testFilter is String) {
421 RegExp re = new RegExp(testFilter); 419 RegExp re = new RegExp(testFilter);
422 filterFunction = (t) => re.hasMatch(t.description); 420 filterFunction = (t) => re.hasMatch(t.description);
423 } else if (testFilter is RegExp) { 421 } else if (testFilter is RegExp) {
424 filterFunction = (t) => testFilter.hasMatch(t.description); 422 filterFunction = (t) => testFilter.hasMatch(t.description);
425 } else if (testFilter is Function) { 423 } else if (testFilter is Function) {
426 filterFunction = testFilter; 424 filterFunction = testFilter;
427 } 425 }
428 _testCases.retainWhere(filterFunction); 426 _testCases.retainWhere(filterFunction);
429 } 427 }
430 428
431 /// Runs all queued tests, one at a time. 429 /// Runs all queued tests, one at a time.
432 void runTests() { 430 void runTests() {
433 _requireNotRunning(); 431 _requireNotRunning();
434 _ensureInitialized(false); 432 _ensureInitialized(false);
435 _currentTestCaseIndex = 0; 433 _environment.currentTestCaseIndex = 0;
436 _config.onStart(); 434 _config.onStart();
437 _runTest(); 435 _runTest();
438 } 436 }
439 437
440 /// Registers that an exception was caught for the current test. 438 /// Registers that an exception was caught for the current test.
441 void registerException(e, [trace]) { 439 void registerException(e, [trace]) {
442 _registerException(currentTestCase, e, trace); 440 _registerException(currentTestCase, e, trace);
443 } 441 }
444 442
445 /// Registers that an exception was caught for the current test. 443 /// Registers that an exception was caught for the current test.
446 void _registerException(TestCase testCase, e, [trace]) { 444 void _registerException(TestCase testCase, e, [trace]) {
447 String message = (e is TestFailure) ? e.message : 'Caught $e'; 445 String message = (e is TestFailure) ? e.message : 'Caught $e';
448 if (testCase.result == null) { 446 if (testCase.result == null) {
449 testCase._fail(message, trace); 447 testCase._fail(message, trace);
450 } else { 448 } else {
451 testCase._error(message, trace); 449 testCase._error(message, trace);
452 } 450 }
453 } 451 }
454 452
455 /// Runs the next test. 453 /// Runs the next test.
456 void _runTest() { 454 void _runTest() {
457 if (_currentTestCaseIndex >= testCases.length) { 455 if (_environment.currentTestCaseIndex >= testCases.length) {
458 assert(_currentTestCaseIndex == testCases.length); 456 assert(_environment.currentTestCaseIndex == testCases.length);
459 _completeTests(); 457 _completeTests();
460 } else { 458 } else {
461 var testCase = testCases[_currentTestCaseIndex]; 459 var testCase = testCases[_environment.currentTestCaseIndex];
462 Future f = runZoned(testCase._run, onError: (error, stack) { 460 Future f = runZoned(testCase._run, onError: (error, stack) {
463 // TODO(kevmoo) Do a better job of flagging these are async errors. 461 // TODO(kevmoo) Do a better job of flagging these are async errors.
464 // https://code.google.com/p/dart/issues/detail?id=16530 462 // https://code.google.com/p/dart/issues/detail?id=16530
465 _registerException(testCase, error, stack); 463 _registerException(testCase, error, stack);
466 }); 464 });
467 465
468 var timeout = unittestConfiguration.timeout; 466 var timeout = unittestConfiguration.timeout;
469 467
470 Timer timer; 468 Timer timer;
471 if (timeout != null) { 469 if (timeout != null) {
472 try { 470 try {
473 timer = new Timer(timeout, () { 471 timer = new Timer(timeout, () {
474 testCase._error("Test timed out after ${timeout.inSeconds} seconds."); 472 testCase._error("Test timed out after ${timeout.inSeconds} seconds.");
475 _nextTestCase(); 473 _nextTestCase();
476 }); 474 });
477 } on UnsupportedError catch (e) { 475 } on UnsupportedError catch (e) {
478 if (e.message != "Timer greater than 0.") rethrow; 476 if (e.message != "Timer greater than 0.") rethrow;
479 // Support running on d8 and jsshell which don't support timers. 477 // Support running on d8 and jsshell which don't support timers.
480 } 478 }
481 } 479 }
482 f.whenComplete(() { 480 f.whenComplete(() {
483 if (timer != null) timer.cancel(); 481 if (timer != null) timer.cancel();
484 var now = new DateTime.now().millisecondsSinceEpoch; 482 var now = new DateTime.now().millisecondsSinceEpoch;
485 if ((now - _lastBreath) >= BREATH_INTERVAL) { 483 if ((now - _environment.lastBreath) >= BREATH_INTERVAL) {
486 _lastBreath = now; 484 _environment.lastBreath = now;
487 Timer.run(_nextTestCase); 485 Timer.run(_nextTestCase);
488 } else { 486 } else {
489 scheduleMicrotask(_nextTestCase); // Schedule the next test. 487 scheduleMicrotask(_nextTestCase); // Schedule the next test.
490 } 488 }
491 }); 489 });
492 } 490 }
493 } 491 }
494 492
495 /// Publish results on the page and notify controller. 493 /// Publish results on the page and notify controller.
496 void _completeTests() { 494 void _completeTests() {
497 if (!_initialized) return; 495 if (!_environment.initialized) return;
498 int passed = 0; 496 int passed = 0;
499 int failed = 0; 497 int failed = 0;
500 int errors = 0; 498 int errors = 0;
501 499
502 for (TestCase t in testCases) { 500 for (TestCase t in testCases) {
503 switch (t.result) { 501 switch (t.result) {
504 case PASS: passed++; break; 502 case PASS: passed++; break;
505 case FAIL: failed++; break; 503 case FAIL: failed++; break;
506 case ERROR: errors++; break; 504 case ERROR: errors++; break;
507 } 505 }
508 } 506 }
509 _config.onSummary(passed, failed, errors, testCases, _uncaughtErrorMessage); 507 _config.onSummary(passed, failed, errors, testCases,
508 _environment.uncaughtErrorMessage);
510 _config.onDone(passed > 0 && failed == 0 && errors == 0 && 509 _config.onDone(passed > 0 && failed == 0 && errors == 0 &&
511 _uncaughtErrorMessage == null); 510 _environment.uncaughtErrorMessage == null);
512 _initialized = false; 511 _environment.initialized = false;
513 _currentTestCaseIndex = -1; 512 _environment.currentTestCaseIndex = -1;
514 } 513 }
515 514
516 String _fullSpec(String spec) { 515 String _fullSpec(String spec) {
517 var group = '${_currentContext.fullName}'; 516 var group = '${_environment.currentContext.fullName}';
518 if (spec == null) return group; 517 if (spec == null) return group;
519 return group != '' ? '$group$groupSep$spec' : spec; 518 return group != '' ? '$group$groupSep$spec' : spec;
520 } 519 }
521 520
522 /// Lazily initializes the test library if not already initialized. 521 /// Lazily initializes the test library if not already initialized.
523 void ensureInitialized() { 522 void ensureInitialized() {
524 _ensureInitialized(true); 523 _ensureInitialized(true);
525 } 524 }
526 525
527 void _ensureInitialized(bool configAutoStart) { 526 void _ensureInitialized(bool configAutoStart) {
528 if (_initialized) { 527 if (_environment.initialized) {
529 return; 528 return;
530 } 529 }
531 _initialized = true; 530 _environment.initialized = true;
532 // Hook our async guard into the matcher library. 531 // Hook our async guard into the matcher library.
533 wrapAsync = (f, [id]) => expectAsync(f, id: id); 532 wrapAsync = (f, [id]) => expectAsync(f, id: id);
534 533
535 _uncaughtErrorMessage = null; 534 _environment.uncaughtErrorMessage = null;
536 535
537 unittestConfiguration.onInit(); 536 unittestConfiguration.onInit();
538 537
539 if (configAutoStart && _config.autoStart) { 538 if (configAutoStart && _config.autoStart) {
540 // Immediately queue the suite up. It will run after a timeout (i.e. after 539 // Immediately queue the suite up. It will run after a timeout (i.e. after
541 // main() has returned). 540 // main() has returned).
542 scheduleMicrotask(runTests); 541 scheduleMicrotask(runTests);
543 } 542 }
544 } 543 }
545 544
(...skipping 30 matching lines...) Expand all
576 /// Useful to disable when debugging unittest or matcher customizations. 575 /// Useful to disable when debugging unittest or matcher customizations.
577 bool formatStacks = true; 576 bool formatStacks = true;
578 577
579 /// A flag that controls whether we try to filter out irrelevant frames from 578 /// A flag that controls whether we try to filter out irrelevant frames from
580 /// the stack trace. 579 /// the stack trace.
581 /// 580 ///
582 /// Requires [formatStacks] to be set. 581 /// Requires [formatStacks] to be set.
583 bool filterStacks = true; 582 bool filterStacks = true;
584 583
585 void _requireNotRunning() { 584 void _requireNotRunning() {
586 if (_currentTestCaseIndex != -1) { 585 if (_environment.currentTestCaseIndex != -1) {
587 throw new StateError('Not allowed when tests are running.'); 586 throw new StateError('Not allowed when tests are running.');
588 } 587 }
589 } 588 }
589
590 /// Method to create a test environment running in its own zone scope.
591 ///
592 /// This allows for multiple invocations of the unittest library in the same
593 /// application instance.
594 /// This is useful when, for example, creating a test runner application which
595 /// needs to create a new pristine test environment on each invocation to run
596 /// a given set of test.
597 dynamic withTestEnvironment(callback()) {
598 return runZoned(callback,
599 zoneValues: {_UNITTEST_ENVIRONMENT: new _TestEnvironment()});
600 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698