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

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: review feedback 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 _TEST_ENVIRONMENT = #test_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[_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; }
kevmoo 2014/11/11 21:27:53 var -> Configuration
wibling 2014/11/12 10:33:46 Done.
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
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);
kevmoo 2014/11/11 21:27:53 Put a read-only property on _TestEnvironment - may
wibling 2014/11/12 10:33:46 Done.
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 &&
218 ? testCases[_currentTestCaseIndex] 218 _environment.currentTestCaseIndex < testCases.length)
219 ? testCases[_environment.currentTestCaseIndex]
219 : null; 220 : null;
220 221
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. */ 222 /* Test case result strings. */
230 // TODO(gram) we should change these constants to use a different string 223 // 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 224 // (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 225 // imply that the test fails). We can't do it without also changing
233 // the testrunner and test.dart though. 226 // the testrunner and test.dart though.
234 /// Result string for a passing test case. 227 /// Result string for a passing test case.
235 const PASS = 'pass'; 228 const PASS = 'pass';
236 /// Result string for a failing test case. 229 /// Result string for a failing test case.
237 const FAIL = 'fail'; 230 const FAIL = 'fail';
238 /// Result string for an test case with an error. 231 /// Result string for an test case with an error.
239 const ERROR = 'error'; 232 const ERROR = 'error';
240 233
241 /// Creates a new test case with the given description and body. The 234 /// Creates a new test case with the given description and body. The
242 /// description will include the descriptions of any surrounding group() 235 /// description will include the descriptions of any surrounding group()
243 /// calls. 236 /// calls.
244 void test(String spec, TestFunction body) { 237 void test(String spec, TestFunction body) {
245 _requireNotRunning(); 238 _requireNotRunning();
246 ensureInitialized(); 239 ensureInitialized();
247 if (!_soloTestSeen || _soloNestingLevel > 0) { 240 if (!_environment.soloTestSeen || _environment.soloNestingLevel > 0) {
248 var testcase = new TestCase._internal(testCases.length + 1, _fullSpec(spec), 241 var testcase = new TestCase._internal(testCases.length + 1, _fullSpec(spec),
249 body); 242 body);
250 _testCases.add(testcase); 243 _testCases.add(testcase);
251 } 244 }
252 } 245 }
253 246
254 /// Convenience function for skipping a test. 247 /// Convenience function for skipping a test.
255 void skip_test(String spec, TestFunction body) {} 248 void skip_test(String spec, TestFunction body) {}
256 249
257 /// Creates a new test case with the given description and body. The 250 /// Creates a new test case with the given description and body. The
258 /// description will include the descriptions of any surrounding group() 251 /// description will include the descriptions of any surrounding group()
259 /// calls. 252 /// calls.
260 /// 253 ///
261 /// If we use [solo_test] (or [solo_group]) instead of test, then all non-solo 254 /// 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 255 /// 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 256 /// 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 257 /// [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 258 /// 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 259 /// file, all tests that are not inside a [solo_group] will be disabled unless
267 /// they are [solo_test]s. 260 /// they are [solo_test]s.
268 /// 261 ///
269 /// [skip_test] and [skip_group] take precedence over soloing, by virtue of the 262 /// [skip_test] and [skip_group] take precedence over soloing, by virtue of the
270 /// fact that they are effectively no-ops. 263 /// fact that they are effectively no-ops.
271 void solo_test(String spec, TestFunction body) { 264 void solo_test(String spec, TestFunction body) {
272 _requireNotRunning(); 265 _requireNotRunning();
273 ensureInitialized(); 266 ensureInitialized();
274 if (!_soloTestSeen) { 267 if (!_environment.soloTestSeen) {
275 _soloTestSeen = true; 268 _environment.soloTestSeen = true;
276 // This is the first solo-ed test. Discard all tests up to now. 269 // This is the first solo-ed test. Discard all tests up to now.
277 _testCases.clear(); 270 _testCases.clear();
278 } 271 }
279 ++_soloNestingLevel; 272 ++_environment.soloNestingLevel;
280 try { 273 try {
281 test(spec, body); 274 test(spec, body);
282 } finally { 275 } finally {
283 --_soloNestingLevel; 276 --_environment.soloNestingLevel;
284 } 277 }
285 } 278 }
286 279
287 /// Indicate that [callback] is expected to be called a [count] number of times 280 /// 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 281 /// (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 282 /// specified [count] times before it continues with the following test. Using
290 /// [expectAsync] will also ensure that errors that occur within [callback] are 283 /// [expectAsync] will also ensure that errors that occur within [callback] are
291 /// tracked and reported. [callback] should take 0 positional arguments (named 284 /// tracked and reported. [callback] should take 0 positional arguments (named
292 /// arguments are not supported). [id] can be used to provide more 285 /// arguments are not supported). [id] can be used to provide more
293 /// descriptive error messages if the callback is called more often than 286 /// descriptive error messages if the callback is called more often than
(...skipping 16 matching lines...) Expand all
310 /// identify the callback in error messages (for example if it is called 303 /// identify the callback in error messages (for example if it is called
311 /// after the test case is complete). 304 /// after the test case is complete).
312 Function expectAsyncUntil(Function callback, bool isDone(), {String id}) => 305 Function expectAsyncUntil(Function callback, bool isDone(), {String id}) =>
313 new _SpreadArgsHelper(callback, 0, -1, id, isDone: isDone).func; 306 new _SpreadArgsHelper(callback, 0, -1, id, isDone: isDone).func;
314 307
315 /// Creates a new named group of tests. Calls to group() or test() within the 308 /// 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. 309 /// body of the function passed to this will inherit this group's description.
317 void group(String description, void body()) { 310 void group(String description, void body()) {
318 ensureInitialized(); 311 ensureInitialized();
319 _requireNotRunning(); 312 _requireNotRunning();
320 _currentContext = new _GroupContext(_currentContext, description); 313 _environment.currentContext = new _GroupContext(_environment.currentContext, d escription);
321 try { 314 try {
322 body(); 315 body();
323 } catch (e, trace) { 316 } catch (e, trace) {
324 var stack = (trace == null) ? '' : ': ${trace.toString()}'; 317 var stack = (trace == null) ? '' : ': ${trace.toString()}';
325 _uncaughtErrorMessage = "${e.toString()}$stack"; 318 _environment.uncaughtErrorMessage = "${e.toString()}$stack";
326 } finally { 319 } finally {
327 // Now that the group is over, restore the previous one. 320 // Now that the group is over, restore the previous one.
328 _currentContext = _currentContext.parent; 321 _environment.currentContext = _environment.currentContext.parent;
329 } 322 }
330 } 323 }
331 324
332 /// Like [skip_test], but for groups. 325 /// Like [skip_test], but for groups.
333 void skip_group(String description, void body()) {} 326 void skip_group(String description, void body()) {}
334 327
335 /// Like [solo_test], but for groups. 328 /// Like [solo_test], but for groups.
336 void solo_group(String description, void body()) { 329 void solo_group(String description, void body()) {
337 _requireNotRunning(); 330 _requireNotRunning();
338 ensureInitialized(); 331 ensureInitialized();
339 if (!_soloTestSeen) { 332 if (!_environment.soloTestSeen) {
340 _soloTestSeen = true; 333 _environment.soloTestSeen = true;
341 // This is the first solo-ed group. Discard all tests up to now. 334 // This is the first solo-ed group. Discard all tests up to now.
342 _testCases.clear(); 335 _testCases.clear();
343 } 336 }
344 ++_soloNestingLevel; 337 ++_environment.soloNestingLevel;
345 try { 338 try {
346 group(description, body); 339 group(description, body);
347 } finally { 340 } finally {
348 --_soloNestingLevel; 341 --_environment.soloNestingLevel;
349 } 342 }
350 } 343 }
351 344
352 /// Register a [setUp] function for a test [group]. This function will 345 /// Register a [setUp] function for a test [group]. This function will
353 /// be called before each test in the group is run. 346 /// be called before each test in the group is run.
354 /// [setUp] and [tearDown] should be called within the [group] before any 347 /// [setUp] and [tearDown] should be called within the [group] before any
355 /// calls to [test]. The [setupTest] function can be asynchronous; in this 348 /// calls to [test]. The [setupTest] function can be asynchronous; in this
356 /// case it must return a [Future]. 349 /// case it must return a [Future].
357 void setUp(Function setupTest) { 350 void setUp(Function setupTest) {
358 _requireNotRunning(); 351 _requireNotRunning();
359 _currentContext.testSetup = setupTest; 352 _environment.currentContext.testSetup = setupTest;
360 } 353 }
361 354
362 /// Register a [tearDown] function for a test [group]. This function will 355 /// 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 356 /// 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. 357 /// are nested only the most locally scoped [teardownTest] function will be run.
365 /// [setUp] and [tearDown] should be called within the [group] before any 358 /// [setUp] and [tearDown] should be called within the [group] before any
366 /// calls to [test]. The [teardownTest] function can be asynchronous; in this 359 /// calls to [test]. The [teardownTest] function can be asynchronous; in this
367 /// case it must return a [Future]. 360 /// case it must return a [Future].
368 void tearDown(Function teardownTest) { 361 void tearDown(Function teardownTest) {
369 _requireNotRunning(); 362 _requireNotRunning();
370 _currentContext.testTeardown = teardownTest; 363 _environment.currentContext.testTeardown = teardownTest;
371 } 364 }
372 365
373 /// Advance to the next test case. 366 /// Advance to the next test case.
374 void _nextTestCase() { 367 void _nextTestCase() {
375 _currentTestCaseIndex++; 368 _environment.currentTestCaseIndex++;
376 _runTest(); 369 _runTest();
377 } 370 }
378 371
379 /// Handle errors that happen outside the tests. 372 /// Handle errors that happen outside the tests.
380 // TODO(vsm): figure out how to expose the stack trace here 373 // TODO(vsm): figure out how to expose the stack trace here
381 // Currently e.message works in dartium, but not in dartc. 374 // Currently e.message works in dartium, but not in dartc.
382 void handleExternalError(e, String message, [stack]) { 375 void handleExternalError(e, String message, [stack]) {
383 var msg = '$message\nCaught $e'; 376 var msg = '$message\nCaught $e';
384 377
385 if (currentTestCase != null) { 378 if (currentTestCase != null) {
386 currentTestCase._error(msg, stack); 379 currentTestCase._error(msg, stack);
387 } else { 380 } else {
388 _uncaughtErrorMessage = "$msg: $stack"; 381 _environment.uncaughtErrorMessage = "$msg: $stack";
389 } 382 }
390 } 383 }
391 384
392 /// Filter the tests. [testFilter] can be a [RegExp], a [String] or a 385 /// Filter the tests. [testFilter] can be a [RegExp], a [String] or a
393 /// predicate function. This is different to enabling/disabling tests 386 /// predicate function. This is different to enabling/disabling tests
394 /// in that it removes the tests completely. 387 /// in that it removes the tests completely.
395 void filterTests(testFilter) { 388 void filterTests(testFilter) {
396 var filterFunction; 389 var filterFunction;
397 if (testFilter is String) { 390 if (testFilter is String) {
398 RegExp re = new RegExp(testFilter); 391 RegExp re = new RegExp(testFilter);
399 filterFunction = (t) => re.hasMatch(t.description); 392 filterFunction = (t) => re.hasMatch(t.description);
400 } else if (testFilter is RegExp) { 393 } else if (testFilter is RegExp) {
401 filterFunction = (t) => testFilter.hasMatch(t.description); 394 filterFunction = (t) => testFilter.hasMatch(t.description);
402 } else if (testFilter is Function) { 395 } else if (testFilter is Function) {
403 filterFunction = testFilter; 396 filterFunction = testFilter;
404 } 397 }
405 _testCases.retainWhere(filterFunction); 398 _testCases.retainWhere(filterFunction);
406 } 399 }
407 400
408 /// Runs all queued tests, one at a time. 401 /// Runs all queued tests, one at a time.
409 void runTests() { 402 void runTests() {
410 _requireNotRunning(); 403 _requireNotRunning();
411 _ensureInitialized(false); 404 _ensureInitialized(false);
412 _currentTestCaseIndex = 0; 405 _environment.currentTestCaseIndex = 0;
413 _config.onStart(); 406 _config.onStart();
414 _runTest(); 407 _runTest();
415 } 408 }
416 409
417 /// Registers that an exception was caught for the current test. 410 /// Registers that an exception was caught for the current test.
418 void registerException(e, [trace]) { 411 void registerException(e, [trace]) {
419 _registerException(currentTestCase, e, trace); 412 _registerException(currentTestCase, e, trace);
420 } 413 }
421 414
422 /// Registers that an exception was caught for the current test. 415 /// Registers that an exception was caught for the current test.
423 void _registerException(TestCase testCase, e, [trace]) { 416 void _registerException(TestCase testCase, e, [trace]) {
424 String message = (e is TestFailure) ? e.message : 'Caught $e'; 417 String message = (e is TestFailure) ? e.message : 'Caught $e';
425 if (testCase.result == null) { 418 if (testCase.result == null) {
426 testCase._fail(message, trace); 419 testCase._fail(message, trace);
427 } else { 420 } else {
428 testCase._error(message, trace); 421 testCase._error(message, trace);
429 } 422 }
430 } 423 }
431 424
432 /// Runs the next test. 425 /// Runs the next test.
433 void _runTest() { 426 void _runTest() {
434 if (_currentTestCaseIndex >= testCases.length) { 427 if (_environment.currentTestCaseIndex >= testCases.length) {
435 assert(_currentTestCaseIndex == testCases.length); 428 assert(_environment.currentTestCaseIndex == testCases.length);
436 _completeTests(); 429 _completeTests();
437 } else { 430 } else {
438 var testCase = testCases[_currentTestCaseIndex]; 431 var testCase = testCases[_environment.currentTestCaseIndex];
439 Future f = runZoned(testCase._run, onError: (error, stack) { 432 Future f = runZoned(testCase._run, onError: (error, stack) {
440 // TODO(kevmoo) Do a better job of flagging these are async errors. 433 // TODO(kevmoo) Do a better job of flagging these are async errors.
441 // https://code.google.com/p/dart/issues/detail?id=16530 434 // https://code.google.com/p/dart/issues/detail?id=16530
442 _registerException(testCase, error, stack); 435 _registerException(testCase, error, stack);
443 }); 436 });
444 437
445 var timeout = unittestConfiguration.timeout; 438 var timeout = unittestConfiguration.timeout;
446 439
447 Timer timer; 440 Timer timer;
448 if (timeout != null) { 441 if (timeout != null) {
449 try { 442 try {
450 timer = new Timer(timeout, () { 443 timer = new Timer(timeout, () {
451 testCase._error("Test timed out after ${timeout.inSeconds} seconds."); 444 testCase._error("Test timed out after ${timeout.inSeconds} seconds.");
452 _nextTestCase(); 445 _nextTestCase();
453 }); 446 });
454 } on UnsupportedError catch (e) { 447 } on UnsupportedError catch (e) {
455 if (e.message != "Timer greater than 0.") rethrow; 448 if (e.message != "Timer greater than 0.") rethrow;
456 // Support running on d8 and jsshell which don't support timers. 449 // Support running on d8 and jsshell which don't support timers.
457 } 450 }
458 } 451 }
459 f.whenComplete(() { 452 f.whenComplete(() {
460 if (timer != null) timer.cancel(); 453 if (timer != null) timer.cancel();
461 var now = new DateTime.now().millisecondsSinceEpoch; 454 var now = new DateTime.now().millisecondsSinceEpoch;
462 if ((now - _lastBreath) >= BREATH_INTERVAL) { 455 if ((now - _environment.lastBreath) >= BREATH_INTERVAL) {
463 _lastBreath = now; 456 _environment.lastBreath = now;
464 Timer.run(_nextTestCase); 457 Timer.run(_nextTestCase);
465 } else { 458 } else {
466 scheduleMicrotask(_nextTestCase); // Schedule the next test. 459 scheduleMicrotask(_nextTestCase); // Schedule the next test.
467 } 460 }
468 }); 461 });
469 } 462 }
470 } 463 }
471 464
472 /// Publish results on the page and notify controller. 465 /// Publish results on the page and notify controller.
473 void _completeTests() { 466 void _completeTests() {
474 if (!_initialized) return; 467 if (!_environment.initialized) return;
475 int passed = 0; 468 int passed = 0;
476 int failed = 0; 469 int failed = 0;
477 int errors = 0; 470 int errors = 0;
478 471
479 for (TestCase t in testCases) { 472 for (TestCase t in testCases) {
480 switch (t.result) { 473 switch (t.result) {
481 case PASS: passed++; break; 474 case PASS: passed++; break;
482 case FAIL: failed++; break; 475 case FAIL: failed++; break;
483 case ERROR: errors++; break; 476 case ERROR: errors++; break;
484 } 477 }
485 } 478 }
486 _config.onSummary(passed, failed, errors, testCases, _uncaughtErrorMessage); 479 _config.onSummary(passed, failed, errors, testCases,
480 _environment.uncaughtErrorMessage);
487 _config.onDone(passed > 0 && failed == 0 && errors == 0 && 481 _config.onDone(passed > 0 && failed == 0 && errors == 0 &&
488 _uncaughtErrorMessage == null); 482 _environment.uncaughtErrorMessage == null);
489 _initialized = false; 483 _environment.initialized = false;
490 _currentTestCaseIndex = -1; 484 _environment.currentTestCaseIndex = -1;
491 } 485 }
492 486
493 String _fullSpec(String spec) { 487 String _fullSpec(String spec) {
494 var group = '${_currentContext.fullName}'; 488 var group = '${_environment.currentContext.fullName}';
495 if (spec == null) return group; 489 if (spec == null) return group;
496 return group != '' ? '$group$groupSep$spec' : spec; 490 return group != '' ? '$group$groupSep$spec' : spec;
497 } 491 }
498 492
499 /// Lazily initializes the test library if not already initialized. 493 /// Lazily initializes the test library if not already initialized.
500 void ensureInitialized() { 494 void ensureInitialized() {
501 _ensureInitialized(true); 495 _ensureInitialized(true);
502 } 496 }
503 497
504 void _ensureInitialized(bool configAutoStart) { 498 void _ensureInitialized(bool configAutoStart) {
505 if (_initialized) { 499 if (_environment.initialized) {
506 return; 500 return;
507 } 501 }
508 _initialized = true; 502 _environment.initialized = true;
509 // Hook our async guard into the matcher library. 503 // Hook our async guard into the matcher library.
510 wrapAsync = (f, [id]) => expectAsync(f, id: id); 504 wrapAsync = (f, [id]) => expectAsync(f, id: id);
511 505
512 _uncaughtErrorMessage = null; 506 _environment.uncaughtErrorMessage = null;
513 507
514 unittestConfiguration.onInit(); 508 unittestConfiguration.onInit();
515 509
516 if (configAutoStart && _config.autoStart) { 510 if (configAutoStart && _config.autoStart) {
517 // Immediately queue the suite up. It will run after a timeout (i.e. after 511 // Immediately queue the suite up. It will run after a timeout (i.e. after
518 // main() has returned). 512 // main() has returned).
519 scheduleMicrotask(runTests); 513 scheduleMicrotask(runTests);
520 } 514 }
521 } 515 }
522 516
(...skipping 28 matching lines...) Expand all
551 /// exception stacks. 545 /// exception stacks.
552 /// 546 ///
553 /// Useful to disable when debugging unittest or matcher customizations. 547 /// Useful to disable when debugging unittest or matcher customizations.
554 bool formatStacks = true; 548 bool formatStacks = true;
555 549
556 /// A flag that controls whether we try to filter out irrelevant frames from 550 /// A flag that controls whether we try to filter out irrelevant frames from
557 /// the stack trace. Requires formatStacks to be set. 551 /// the stack trace. Requires formatStacks to be set.
558 bool filterStacks = true; 552 bool filterStacks = true;
559 553
560 void _requireNotRunning() { 554 void _requireNotRunning() {
561 if (_currentTestCaseIndex != -1) { 555 if (_environment.currentTestCaseIndex != -1) {
562 throw new StateError('Not allowed when tests are running.'); 556 throw new StateError('Not allowed when tests are running.');
563 } 557 }
564 } 558 }
559
560 /// Method to support multiple invocations of the unittest library in the same
561 /// application instance.
kevmoo 2014/11/11 21:27:53 Include more details here. When would this be use
wibling 2014/11/12 10:33:46 Done.
562 dynamic withTestEnvironment(callback()) {
563 return runZoned(callback,
564 zoneValues: <Symbol, Object>{_TEST_ENVIRONMENT: new _TestEnvironment()});
565 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698