Skip to content

Commit 6a5faf3

Browse files
committed
Switch to 'test', add different support for 'solo'.
[email protected], [email protected] BUG= Review URL: https://codereview.chromium.org/2388073004 .
1 parent 1630a63 commit 6a5faf3

3 files changed

Lines changed: 164 additions & 51 deletions

File tree

CHANGELOG.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,12 @@
11
# Changelog
22

3+
## 0.1.0
4+
5+
- Switched from 'package:unittest' to 'package:test'.
6+
- Since 'package:test' does not define 'solo_test', in order to keep
7+
this functionality, `defineReflectiveSuite` must be used to wrap
8+
all `defineReflectiveTests` invocations.
9+
310
## 0.0.4
411

512
- Added @failingTest, @assertFailingTest and @soloTest annotations.

lib/test_reflective_loader.dart

Lines changed: 155 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ import 'dart:async';
88
@MirrorsUsed(metaTargets: 'ReflectiveTest')
99
import 'dart:mirrors';
1010

11-
import 'package:unittest/unittest.dart';
11+
import 'package:test/test.dart' as test_package;
1212

1313
/**
1414
* A marker annotation used to annotate overridden test methods (so we cannot
@@ -30,10 +30,14 @@ const _FailingTest failingTest = const _FailingTest();
3030
const ReflectiveTest reflectiveTest = const ReflectiveTest();
3131

3232
/**
33-
* Test classes annotated with this annotation are run using [solo_group].
33+
* A marker annotation used to annotate "solo" groups and tests.
3434
*/
3535
const _SoloTest soloTest = const _SoloTest();
3636

37+
final List<_Group> _currentGroups = <_Group>[];
38+
int _currentSuiteLevel = 0;
39+
String _currentSuiteName = null;
40+
3741
/**
3842
* Is `true` the application is running in the checked mode.
3943
*/
@@ -46,11 +50,34 @@ final bool _isCheckedMode = () {
4650
}
4751
}();
4852

53+
/**
54+
* Run the [define] function parameter that calls [defineReflectiveTests] to
55+
* add normal and "solo" tests, and also calls [defineReflectiveSuite] to
56+
* create embedded suites. If the current suite is the top-level one, perform
57+
* check for "solo" groups and tests, and run all or only "solo" items.
58+
*/
59+
void defineReflectiveSuite(void define(), {String name}) {
60+
String groupName = _currentSuiteName;
61+
_currentSuiteLevel++;
62+
try {
63+
_currentSuiteName = _combineNames(_currentSuiteName, name);
64+
define();
65+
} finally {
66+
_currentSuiteName = groupName;
67+
_currentSuiteLevel--;
68+
}
69+
_addTestsIfTopLevelSuite();
70+
}
71+
4972
/**
5073
* Runs test methods existing in the given [type].
5174
*
52-
* Methods with names starting with `test` are run using [test] function.
53-
* Methods with names starting with `solo_test` are run using [solo_test] function.
75+
* If there is a "solo" test method in the top-level suite, only "solo" methods
76+
* are run.
77+
*
78+
* If there is a "solo" test type, only its test methods are run.
79+
*
80+
* Otherwise all tests methods of all test types are run.
5481
*
5582
* Each method is run with a new instance of [type].
5683
* So, [type] should have a default constructor.
@@ -65,56 +92,105 @@ final bool _isCheckedMode = () {
6592
void defineReflectiveTests(Type type) {
6693
ClassMirror classMirror = reflectClass(type);
6794
if (!classMirror.metadata.any((InstanceMirror annotation) =>
68-
annotation.type.reflectedType == ReflectiveTest)) {
95+
annotation.type.reflectedType == ReflectiveTest)) {
6996
String name = MirrorSystem.getName(classMirror.qualifiedName);
7097
throw new Exception('Class $name must have annotation "@reflectiveTest" '
7198
'in order to be run by runReflectiveTests.');
7299
}
73-
void runMembers() {
74-
classMirror.instanceMembers
75-
.forEach((Symbol symbol, MethodMirror memberMirror) {
76-
// we need only methods
77-
if (memberMirror is! MethodMirror || !memberMirror.isRegularMethod) {
78-
return;
79-
}
80-
String memberName = MirrorSystem.getName(symbol);
81-
// test_
82-
if (memberName.startsWith('test_')) {
83-
test(memberName, () {
84-
if (_hasFailingTestAnnotation(memberMirror) ||
85-
_isCheckedMode && _hasAssertFailingTestAnnotation(memberMirror)) {
86-
return _runFailingTest(classMirror, symbol);
87-
} else {
88-
return _runTest(classMirror, symbol);
89-
}
90-
});
91-
return;
92-
}
93-
// solo_test_
94-
if (memberName.startsWith('solo_test_')) {
95-
solo_test(memberName, () {
96-
return _runTest(classMirror, symbol);
97-
});
98-
}
99-
// fail_test_
100-
if (memberName.startsWith('fail_')) {
101-
test(memberName, () {
102-
return _runFailingTest(classMirror, symbol);
103-
});
104-
}
105-
// solo_fail_test_
106-
if (memberName.startsWith('solo_fail_')) {
107-
solo_test(memberName, () {
100+
101+
_Group group;
102+
{
103+
bool isSolo = _hasAnnotationInstance(classMirror, soloTest);
104+
String className = MirrorSystem.getName(classMirror.simpleName);
105+
group = new _Group(isSolo, _combineNames(_currentSuiteName, className));
106+
_currentGroups.add(group);
107+
}
108+
109+
classMirror.instanceMembers
110+
.forEach((Symbol symbol, MethodMirror memberMirror) {
111+
// we need only methods
112+
if (memberMirror is! MethodMirror || !memberMirror.isRegularMethod) {
113+
return;
114+
}
115+
// prepare information about the method
116+
String memberName = MirrorSystem.getName(symbol);
117+
bool isSolo = memberName.startsWith('solo_') ||
118+
_hasAnnotationInstance(memberMirror, soloTest);
119+
// test_
120+
if (memberName.startsWith('test_')) {
121+
group.addTest(isSolo, memberName, () {
122+
if (_hasFailingTestAnnotation(memberMirror) ||
123+
_isCheckedMode && _hasAssertFailingTestAnnotation(memberMirror)) {
108124
return _runFailingTest(classMirror, symbol);
109-
});
125+
} else {
126+
return _runTest(classMirror, symbol);
127+
}
128+
});
129+
return;
130+
}
131+
// solo_test_
132+
if (memberName.startsWith('solo_test_')) {
133+
group.addTest(true, memberName, () {
134+
return _runTest(classMirror, symbol);
135+
});
136+
}
137+
// fail_test_
138+
if (memberName.startsWith('fail_')) {
139+
group.addTest(isSolo, memberName, () {
140+
return _runFailingTest(classMirror, symbol);
141+
});
142+
}
143+
// solo_fail_test_
144+
if (memberName.startsWith('solo_fail_')) {
145+
group.addTest(true, memberName, () {
146+
return _runFailingTest(classMirror, symbol);
147+
});
148+
}
149+
});
150+
151+
// Support for the case of missing enclosing [defineReflectiveSuite].
152+
_addTestsIfTopLevelSuite();
153+
}
154+
155+
/**
156+
* If the current suite is the top-level one, add tests to the `test` package.
157+
*/
158+
void _addTestsIfTopLevelSuite() {
159+
if (_currentSuiteLevel == 0) {
160+
void runTests({bool allGroups, bool allTests}) {
161+
for (_Group group in _currentGroups) {
162+
if (allGroups || group.isSolo) {
163+
for (_Test test in group.tests) {
164+
if (allTests || test.isSolo) {
165+
test_package.test(test.name, test.function);
166+
}
167+
}
168+
}
110169
}
111-
});
170+
}
171+
172+
if (_currentGroups.any((g) => g.hasSoloTest)) {
173+
runTests(allGroups: true, allTests: false);
174+
} else if (_currentGroups.any((g) => g.isSolo)) {
175+
runTests(allGroups: false, allTests: true);
176+
} else {
177+
runTests(allGroups: true, allTests: true);
178+
}
179+
_currentGroups.clear();
112180
}
113-
String className = MirrorSystem.getName(classMirror.simpleName);
114-
if (_hasAnnotationInstance(classMirror, soloTest)) {
115-
solo_group(className, runMembers);
181+
}
182+
183+
/**
184+
* Return the combination of the [base] and [addition] names.
185+
* If any other two is `null`, then the other one is returned.
186+
*/
187+
String _combineNames(String base, String addition) {
188+
if (base == null) {
189+
return addition;
190+
} else if (addition == null) {
191+
return base;
116192
} else {
117-
group(className, runMembers);
193+
return '$base | $addition';
118194
}
119195
}
120196

@@ -153,7 +229,7 @@ Future _invokeSymbolIfExists(InstanceMirror instanceMirror, Symbol symbol) {
153229
*/
154230
Future _runFailingTest(ClassMirror classMirror, Symbol symbol) {
155231
return new Future(() => _runTest(classMirror, symbol)).then((_) {
156-
fail('Test passed - expected to fail.');
232+
test_package.fail('Test passed - expected to fail.');
157233
}, onError: (_) {});
158234
}
159235

@@ -164,6 +240,8 @@ _runTest(ClassMirror classMirror, Symbol symbol) {
164240
.whenComplete(() => _invokeSymbolIfExists(instanceMirror, #tearDown));
165241
}
166242

243+
typedef _TestFunction();
244+
167245
/**
168246
* A marker annotation used to instruct dart2js to keep reflection information
169247
* for the annotated classes.
@@ -190,9 +268,37 @@ class _FailingTest {
190268
}
191269

192270
/**
193-
* A marker annotation used to annotate a test class to run it using
194-
* [solo_group].
271+
* Information about a type based test group.
272+
*/
273+
class _Group {
274+
final bool isSolo;
275+
final String name;
276+
final List<_Test> tests = <_Test>[];
277+
278+
_Group(this.isSolo, this.name);
279+
280+
bool get hasSoloTest => tests.any((test) => test.isSolo);
281+
282+
void addTest(bool isSolo, String name, _TestFunction function) {
283+
String fullName = _combineNames(this.name, name);
284+
tests.add(new _Test(isSolo, fullName, function));
285+
}
286+
}
287+
288+
/**
289+
* A marker annotation used to annotate "solo" groups and tests.
195290
*/
196291
class _SoloTest {
197292
const _SoloTest();
198293
}
294+
295+
/**
296+
* Information about a test.
297+
*/
298+
class _Test {
299+
final bool isSolo;
300+
final String name;
301+
final _TestFunction function;
302+
303+
_Test(this.isSolo, this.name, this.function);
304+
}

pubspec.yaml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
name: test_reflective_loader
2-
version: 0.0.4
2+
version: 0.1.0
33
description: Support for discovering tests and test suites using reflection.
44
author: Dart Team <[email protected]>
55
homepage: https://github.com/dart-lang/test_reflective_loader
@@ -8,4 +8,4 @@ environment:
88
sdk: '>=1.0.0 <2.0.0'
99

1010
dev_dependencies:
11-
unittest: '>=0.9.0 <0.12.0'
11+
test: ^0.12.0

0 commit comments

Comments
 (0)