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

Unified 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 side-by-side diff with in-line comments
Download patch
Index: pkg/unittest/lib/unittest.dart
diff --git a/pkg/unittest/lib/unittest.dart b/pkg/unittest/lib/unittest.dart
index 05eca70f9fcc558fda37b68ee17d2ea35d2c2d3b..4cdbacfe62d920b57255a9d3024b09d4374b08ab 100644
--- a/pkg/unittest/lib/unittest.dart
+++ b/pkg/unittest/lib/unittest.dart
@@ -151,8 +151,29 @@ part 'src/simple_configuration.dart';
part 'src/group_context.dart';
part 'src/spread_args_helper.dart';
part 'src/test_case.dart';
+part 'src/test_environment.dart';
-Configuration _config;
+const Symbol _TEST_ENVIRONMENT = #test_environment;
+
+final _TestEnvironment _defaultEnvironment = new _TestEnvironment();
+
+/**
+ * Internal getter for the current unittest config.
+ */
+_TestEnvironment get _environment {
+ var environment = Zone.current[_TEST_ENVIRONMENT];
+ if (environment == null) {
+ return _defaultEnvironment;
+ }
+ return environment;
+}
+
+// Convenience getter/setter for the current environment's config.
+Configuration get _config => _environment.config;
+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.
+
+// Convenience getter for the current environment's test cases.
+List<TestCase> get _testCases => _environment.testCases;
/// [Configuration] used by the unittest library. Note that if a
/// configuration has not been set, calling this getter will create
@@ -184,48 +205,20 @@ void logMessage(String message) =>
/// Separator used between group names and test names.
String groupSep = ' ';
-final List<TestCase> _testCases = new List<TestCase>();
-
/// Tests executed in this suite.
-final List<TestCase> testCases = new UnmodifiableListView<TestCase>(_testCases);
+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.
/// Interval (in msecs) after which synchronous tests will insert an async
/// delay to allow DOM or other updates.
const int BREATH_INTERVAL = 200;
-/// The set of tests to run can be restricted by using [solo_test] and
-/// [solo_group].
-/// As groups can be nested we use a counter to keep track of the nest level
-/// of soloing, and a flag to tell if we have seen any solo tests.
-int _soloNestingLevel = 0;
-bool _soloTestSeen = false;
-
-// We use a 'dummy' context for the top level to eliminate null
-// checks when querying the context. This allows us to easily
-// support top-level setUp/tearDown functions as well.
-final _rootContext = new _GroupContext();
-_GroupContext _currentContext = _rootContext;
-
-/// Represents the index of the currently running test case
-/// == -1 implies the test system is not running
-/// == [number of test cases] is a short-lived state flagging that the last test
-/// has completed
-int _currentTestCaseIndex = -1;
-
/// [TestCase] currently being executed.
TestCase get currentTestCase =>
- (_currentTestCaseIndex >= 0 && _currentTestCaseIndex < testCases.length)
- ? testCases[_currentTestCaseIndex]
+ (_environment.currentTestCaseIndex >= 0 &&
+ _environment.currentTestCaseIndex < testCases.length)
+ ? testCases[_environment.currentTestCaseIndex]
: null;
-/// Whether the framework is in an initialized state.
-bool _initialized = false;
-
-String _uncaughtErrorMessage = null;
-
-/// Time since we last gave non-sync code a chance to be scheduled.
-int _lastBreath = new DateTime.now().millisecondsSinceEpoch;
-
/* Test case result strings. */
// TODO(gram) we should change these constants to use a different string
// (so that writing 'FAIL' in the middle of a test doesn't
@@ -244,7 +237,7 @@ const ERROR = 'error';
void test(String spec, TestFunction body) {
_requireNotRunning();
ensureInitialized();
- if (!_soloTestSeen || _soloNestingLevel > 0) {
+ if (!_environment.soloTestSeen || _environment.soloNestingLevel > 0) {
var testcase = new TestCase._internal(testCases.length + 1, _fullSpec(spec),
body);
_testCases.add(testcase);
@@ -271,16 +264,16 @@ void skip_test(String spec, TestFunction body) {}
void solo_test(String spec, TestFunction body) {
_requireNotRunning();
ensureInitialized();
- if (!_soloTestSeen) {
- _soloTestSeen = true;
+ if (!_environment.soloTestSeen) {
+ _environment.soloTestSeen = true;
// This is the first solo-ed test. Discard all tests up to now.
_testCases.clear();
}
- ++_soloNestingLevel;
+ ++_environment.soloNestingLevel;
try {
test(spec, body);
} finally {
- --_soloNestingLevel;
+ --_environment.soloNestingLevel;
}
}
@@ -317,15 +310,15 @@ Function expectAsyncUntil(Function callback, bool isDone(), {String id}) =>
void group(String description, void body()) {
ensureInitialized();
_requireNotRunning();
- _currentContext = new _GroupContext(_currentContext, description);
+ _environment.currentContext = new _GroupContext(_environment.currentContext, description);
try {
body();
} catch (e, trace) {
var stack = (trace == null) ? '' : ': ${trace.toString()}';
- _uncaughtErrorMessage = "${e.toString()}$stack";
+ _environment.uncaughtErrorMessage = "${e.toString()}$stack";
} finally {
// Now that the group is over, restore the previous one.
- _currentContext = _currentContext.parent;
+ _environment.currentContext = _environment.currentContext.parent;
}
}
@@ -336,16 +329,16 @@ void skip_group(String description, void body()) {}
void solo_group(String description, void body()) {
_requireNotRunning();
ensureInitialized();
- if (!_soloTestSeen) {
- _soloTestSeen = true;
+ if (!_environment.soloTestSeen) {
+ _environment.soloTestSeen = true;
// This is the first solo-ed group. Discard all tests up to now.
_testCases.clear();
}
- ++_soloNestingLevel;
+ ++_environment.soloNestingLevel;
try {
group(description, body);
} finally {
- --_soloNestingLevel;
+ --_environment.soloNestingLevel;
}
}
@@ -356,7 +349,7 @@ void solo_group(String description, void body()) {
/// case it must return a [Future].
void setUp(Function setupTest) {
_requireNotRunning();
- _currentContext.testSetup = setupTest;
+ _environment.currentContext.testSetup = setupTest;
}
/// Register a [tearDown] function for a test [group]. This function will
@@ -367,12 +360,12 @@ void setUp(Function setupTest) {
/// case it must return a [Future].
void tearDown(Function teardownTest) {
_requireNotRunning();
- _currentContext.testTeardown = teardownTest;
+ _environment.currentContext.testTeardown = teardownTest;
}
/// Advance to the next test case.
void _nextTestCase() {
- _currentTestCaseIndex++;
+ _environment.currentTestCaseIndex++;
_runTest();
}
@@ -385,7 +378,7 @@ void handleExternalError(e, String message, [stack]) {
if (currentTestCase != null) {
currentTestCase._error(msg, stack);
} else {
- _uncaughtErrorMessage = "$msg: $stack";
+ _environment.uncaughtErrorMessage = "$msg: $stack";
}
}
@@ -409,7 +402,7 @@ void filterTests(testFilter) {
void runTests() {
_requireNotRunning();
_ensureInitialized(false);
- _currentTestCaseIndex = 0;
+ _environment.currentTestCaseIndex = 0;
_config.onStart();
_runTest();
}
@@ -431,11 +424,11 @@ void _registerException(TestCase testCase, e, [trace]) {
/// Runs the next test.
void _runTest() {
- if (_currentTestCaseIndex >= testCases.length) {
- assert(_currentTestCaseIndex == testCases.length);
+ if (_environment.currentTestCaseIndex >= testCases.length) {
+ assert(_environment.currentTestCaseIndex == testCases.length);
_completeTests();
} else {
- var testCase = testCases[_currentTestCaseIndex];
+ var testCase = testCases[_environment.currentTestCaseIndex];
Future f = runZoned(testCase._run, onError: (error, stack) {
// TODO(kevmoo) Do a better job of flagging these are async errors.
// https://code.google.com/p/dart/issues/detail?id=16530
@@ -459,8 +452,8 @@ void _runTest() {
f.whenComplete(() {
if (timer != null) timer.cancel();
var now = new DateTime.now().millisecondsSinceEpoch;
- if ((now - _lastBreath) >= BREATH_INTERVAL) {
- _lastBreath = now;
+ if ((now - _environment.lastBreath) >= BREATH_INTERVAL) {
+ _environment.lastBreath = now;
Timer.run(_nextTestCase);
} else {
scheduleMicrotask(_nextTestCase); // Schedule the next test.
@@ -471,7 +464,7 @@ void _runTest() {
/// Publish results on the page and notify controller.
void _completeTests() {
- if (!_initialized) return;
+ if (!_environment.initialized) return;
int passed = 0;
int failed = 0;
int errors = 0;
@@ -483,15 +476,16 @@ void _completeTests() {
case ERROR: errors++; break;
}
}
- _config.onSummary(passed, failed, errors, testCases, _uncaughtErrorMessage);
+ _config.onSummary(passed, failed, errors, testCases,
+ _environment.uncaughtErrorMessage);
_config.onDone(passed > 0 && failed == 0 && errors == 0 &&
- _uncaughtErrorMessage == null);
- _initialized = false;
- _currentTestCaseIndex = -1;
+ _environment.uncaughtErrorMessage == null);
+ _environment.initialized = false;
+ _environment.currentTestCaseIndex = -1;
}
String _fullSpec(String spec) {
- var group = '${_currentContext.fullName}';
+ var group = '${_environment.currentContext.fullName}';
if (spec == null) return group;
return group != '' ? '$group$groupSep$spec' : spec;
}
@@ -502,14 +496,14 @@ void ensureInitialized() {
}
void _ensureInitialized(bool configAutoStart) {
- if (_initialized) {
+ if (_environment.initialized) {
return;
}
- _initialized = true;
+ _environment.initialized = true;
// Hook our async guard into the matcher library.
wrapAsync = (f, [id]) => expectAsync(f, id: id);
- _uncaughtErrorMessage = null;
+ _environment.uncaughtErrorMessage = null;
unittestConfiguration.onInit();
@@ -558,7 +552,14 @@ bool formatStacks = true;
bool filterStacks = true;
void _requireNotRunning() {
- if (_currentTestCaseIndex != -1) {
+ if (_environment.currentTestCaseIndex != -1) {
throw new StateError('Not allowed when tests are running.');
}
}
+
+/// Method to support multiple invocations of the unittest library in the same
+/// 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.
+dynamic withTestEnvironment(callback()) {
+ return runZoned(callback,
+ zoneValues: <Symbol, Object>{_TEST_ENVIRONMENT: new _TestEnvironment()});
+}

Powered by Google App Engine
This is Rietveld 408576698