mirror of
https://github.com/dart-lang/sdk
synced 2024-11-02 12:24:24 +00:00
Chaining of setup/teardown.
Review URL: https://codereview.chromium.org//14092004 git-svn-id: https://dart.googlecode.com/svn/branches/bleeding_edge/dart@21819 260f80e4-7a28-3924-810f-c04153c831b5
This commit is contained in:
parent
1e92447b78
commit
f435c7f836
5 changed files with 120 additions and 75 deletions
|
@ -32,6 +32,9 @@ webdriver/test/webdriver_test: Skip
|
|||
unittest/test/unittest_test: Pass, Fail, Crash # Bug in v8, http://dartbug.com/9407
|
||||
|
||||
|
||||
[ $compiler == dart2js && $runtime == d8 ]
|
||||
unittest/test/unittest_test: Pass, Fail # http://dartbug.com/10109
|
||||
|
||||
[$compiler == dart2dart]
|
||||
*: Skip
|
||||
|
||||
|
|
|
@ -79,46 +79,6 @@ void main() {
|
|||
test('test 2', () => expect(onExceptionRun, isTrue));
|
||||
}, passing: ['test 2']);
|
||||
|
||||
expectTestsPass("setUp doesn't apply to child groups", () {
|
||||
var setUpRun = false;
|
||||
setUp(() {
|
||||
setUpRun = true;
|
||||
currentSchedule.onComplete.schedule(() {
|
||||
setUpRun = false;
|
||||
});
|
||||
});
|
||||
|
||||
test('outer', () {
|
||||
expect(setUpRun, isTrue);
|
||||
});
|
||||
|
||||
group('group', () {
|
||||
test('inner', () {
|
||||
expect(setUpRun, isFalse);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
expectTestsPass("setUp doesn't apply to parent groups", () {
|
||||
var setUpRun = false;
|
||||
group('group', () {
|
||||
setUp(() {
|
||||
setUpRun = true;
|
||||
currentSchedule.onComplete.schedule(() {
|
||||
setUpRun = false;
|
||||
});
|
||||
});
|
||||
|
||||
test('inner', () {
|
||||
expect(setUpRun, isTrue);
|
||||
});
|
||||
});
|
||||
|
||||
test('outer', () {
|
||||
expect(setUpRun, isFalse);
|
||||
});
|
||||
});
|
||||
|
||||
expectTestsPass("setUp doesn't apply to sibling groups", () {
|
||||
var setUpRun = false;
|
||||
group('group 1', () {
|
||||
|
@ -140,4 +100,4 @@ void main() {
|
|||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
|
@ -61,9 +61,9 @@ class TestCase {
|
|||
Completer _testComplete;
|
||||
|
||||
TestCase._internal(this.id, this.description, this.testFunction)
|
||||
: currentGroup = _currentGroup,
|
||||
setUp = _testSetup,
|
||||
tearDown = _testTeardown;
|
||||
: currentGroup = _currentContext.groupName,
|
||||
setUp = _currentContext.testSetup,
|
||||
tearDown = _currentContext.testTeardown;
|
||||
|
||||
bool get isComplete => !enabled || result != null;
|
||||
|
||||
|
|
|
@ -205,12 +205,6 @@ void set unittestConfiguration(Configuration value) {
|
|||
void logMessage(String message) =>
|
||||
_config.onLogMessage(currentTestCase, message);
|
||||
|
||||
/**
|
||||
* Description text of the current test group. If multiple groups are nested,
|
||||
* this will contain all of their text concatenated.
|
||||
*/
|
||||
String _currentGroup = '';
|
||||
|
||||
/** Separator used between group names and test names. */
|
||||
String groupSep = ' ';
|
||||
|
||||
|
@ -219,11 +213,29 @@ final List<TestCase> _testCases = new List<TestCase>();
|
|||
/** Tests executed in this suite. */
|
||||
final List<TestCase> testCases = new UnmodifiableListView<TestCase>(_testCases);
|
||||
|
||||
/** Setup function called before each test in a group */
|
||||
Function _testSetup;
|
||||
/**
|
||||
* Setup and teardown functions for a group and its parents, the latter
|
||||
* for chaining.
|
||||
*/
|
||||
class GroupContext {
|
||||
/** Setup function called before each test in a group. */
|
||||
Function testSetup = null;
|
||||
|
||||
/** Teardown function called after each test in a group */
|
||||
Function _testTeardown;
|
||||
/** Teardown function called after each test in a group. */
|
||||
Function testTeardown = null;
|
||||
|
||||
/** Setup and teardown functions of parent group, for chaining. */
|
||||
Function parentSetup = null;
|
||||
Function parentTeardown = null;
|
||||
|
||||
/**
|
||||
* Description text of the current test group. If multiple groups are nested,
|
||||
* this will contain all of their text concatenated.
|
||||
*/
|
||||
String groupName = '';
|
||||
}
|
||||
|
||||
GroupContext _currentContext = new GroupContext();
|
||||
|
||||
int _currentTestCaseIndex = 0;
|
||||
|
||||
|
@ -596,46 +608,55 @@ Function protectAsync2(Function callback, {String id}) {
|
|||
*/
|
||||
void group(String description, void body()) {
|
||||
ensureInitialized();
|
||||
// Groups can be nested, so we need to preserve the current
|
||||
// settings for test setup/teardown. We use a local copy here so we
|
||||
// can nest multiple levels; we also have the global parent variables
|
||||
// which are used for chaining.
|
||||
var oldContext = _currentContext;
|
||||
_currentContext = new GroupContext();
|
||||
_currentContext.testSetup = _currentContext.parentSetup =
|
||||
oldContext.testSetup;
|
||||
_currentContext.testTeardown = _currentContext.parentTeardown =
|
||||
oldContext.testTeardown;
|
||||
|
||||
// Concatenate the new group.
|
||||
final parentGroup = _currentGroup;
|
||||
if (_currentGroup != '') {
|
||||
if (oldContext.groupName != '') {
|
||||
// Add a space.
|
||||
_currentGroup = '$_currentGroup$groupSep$description';
|
||||
_currentContext.groupName = '${oldContext.groupName}$groupSep$description';
|
||||
} else {
|
||||
// The first group.
|
||||
_currentGroup = description;
|
||||
_currentContext.groupName = description;
|
||||
}
|
||||
|
||||
// Groups can be nested, so we need to preserve the current
|
||||
// settings for test setup/teardown.
|
||||
Function parentSetup = _testSetup;
|
||||
Function parentTeardown = _testTeardown;
|
||||
|
||||
try {
|
||||
_testSetup = null;
|
||||
_testTeardown = null;
|
||||
body();
|
||||
} catch (e, trace) {
|
||||
var stack = (trace == null) ? '' : ': ${trace.toString()}';
|
||||
_uncaughtErrorMessage = "${e.toString()}$stack";
|
||||
} finally {
|
||||
// Now that the group is over, restore the previous one.
|
||||
_currentGroup = parentGroup;
|
||||
_testSetup = parentSetup;
|
||||
_testTeardown = parentTeardown;
|
||||
_currentContext = oldContext;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Register a [setUp] function for a test [group]. This function will
|
||||
* be called before each test in the group is run. Note that if groups
|
||||
* are nested only the most locally scoped [setUpTest] function will be run.
|
||||
* be called before each test in the group is run.
|
||||
* [setUp] and [tearDown] should be called within the [group] before any
|
||||
* calls to [test]. The [setupTest] function can be asynchronous; in this
|
||||
* case it must return a [Future].
|
||||
*/
|
||||
void setUp(Function setupTest) {
|
||||
_testSetup = setupTest;
|
||||
var parent = _currentContext.parentSetup;
|
||||
_currentContext.testSetup = () {
|
||||
var f = parent == null ? null : parent();
|
||||
if (f is Future) {
|
||||
return f.then((_) => setupTest());
|
||||
} else {
|
||||
return setupTest();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -647,7 +668,19 @@ void setUp(Function setupTest) {
|
|||
* case it must return a [Future].
|
||||
*/
|
||||
void tearDown(Function teardownTest) {
|
||||
_testTeardown = teardownTest;
|
||||
var parent = _currentContext.parentTeardown;
|
||||
_currentContext.testTeardown = () {
|
||||
var f = teardownTest();
|
||||
if (parent == null) return f;
|
||||
if (f is Future) {
|
||||
// TODO(gram): as _parentTeardown is a global, do we need
|
||||
// to first take a local copy so the value is fixed at the
|
||||
// point that tearDown is called?
|
||||
return f.then((_) => parent());
|
||||
} else {
|
||||
return parent();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/** Advance to the next test case. */
|
||||
|
@ -712,7 +745,7 @@ void filterTests(testFilter) {
|
|||
void runTests() {
|
||||
_ensureInitialized(false);
|
||||
_currentTestCaseIndex = 0;
|
||||
_currentGroup = '';
|
||||
_currentContext = new GroupContext();
|
||||
|
||||
// If we are soloing a test, remove all the others.
|
||||
if (_soloTest != null) {
|
||||
|
@ -811,8 +844,9 @@ void _completeTests() {
|
|||
}
|
||||
|
||||
String _fullSpec(String spec) {
|
||||
if (spec == null) return '$_currentGroup';
|
||||
return _currentGroup != '' ? '$_currentGroup$groupSep$spec' : spec;
|
||||
var group = '${_currentContext.groupName}';
|
||||
if (spec == null) return group;
|
||||
return group != '' ? '$group$groupSep$spec' : spec;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -68,6 +68,26 @@ class TestConfiguration extends Configuration {
|
|||
}
|
||||
}
|
||||
|
||||
makeDelayedSetup(index, s) => () {
|
||||
return new Future.delayed(new Duration(milliseconds:1), () {
|
||||
s.write('l$index U ');
|
||||
});
|
||||
};
|
||||
|
||||
makeDelayedTeardown(index, s) => () {
|
||||
return new Future.delayed(new Duration(milliseconds:1), () {
|
||||
s.write('l$index D ');
|
||||
});
|
||||
};
|
||||
|
||||
makeImmediateSetup(index, s) => () {
|
||||
s.write('l$index U ');
|
||||
};
|
||||
|
||||
makeImmediateTeardown(index, s) => () {
|
||||
s.write('l$index D ');
|
||||
};
|
||||
|
||||
runTest() {
|
||||
port.receive((String testName, sendport) {
|
||||
var testConfig = new TestConfiguration(sendport);
|
||||
|
@ -299,6 +319,31 @@ runTest() {
|
|||
});
|
||||
} else if (testName == 'runTests without tests') {
|
||||
runTests();
|
||||
} else if (testName == 'nested groups setup/teardown') {
|
||||
StringBuffer s = new StringBuffer();
|
||||
group('level 1', () {
|
||||
setUp(makeDelayedSetup(1, s));
|
||||
group('level 2', () {
|
||||
setUp(makeImmediateSetup(2, s));
|
||||
tearDown(makeDelayedTeardown(2, s));
|
||||
group('level 3', () {
|
||||
group('level 4', () {
|
||||
setUp(makeDelayedSetup(4, s));
|
||||
tearDown(makeImmediateTeardown(4, s));
|
||||
group('level 5', () {
|
||||
setUp(makeImmediateSetup(5, s));
|
||||
group('level 6', () {
|
||||
tearDown(makeDelayedTeardown(6, s));
|
||||
test('inner', () {});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
test('after nest', () {
|
||||
expect(s.toString(), "l1 U l2 U l4 U l5 U l6 D l4 D l2 D ");
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
@ -355,7 +400,10 @@ main() {
|
|||
'foo6'),
|
||||
'testCases immutable':
|
||||
buildStatusString(1, 0, 0, 'testCases immutable'),
|
||||
'runTests without tests': buildStatusString(0, 0, 0, null)
|
||||
'runTests without tests': buildStatusString(0, 0, 0, null),
|
||||
'nested groups setup/teardown':
|
||||
buildStatusString(2, 0, 0,
|
||||
'level 1 level 2 level 3 level 4 level 5 level 6 inner::after nest')
|
||||
};
|
||||
|
||||
tests.forEach((String name, String expected) {
|
||||
|
|
Loading…
Reference in a new issue