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

Side by Side Diff: lib/src/backend/declarer.dart

Issue 1379203002: Refactor groups to pipe them through to the runner. (Closed) Base URL: git@github.com:dart-lang/test@master
Patch Set: Test fixes Created 5 years, 2 months 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
« no previous file with comments | « no previous file | lib/src/backend/group.dart » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file 1 // Copyright (c) 2015, 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 library test.backend.declarer; 5 library test.backend.declarer;
6 6
7 import 'dart:collection'; 7 import 'dart:async';
8 8
9 import '../frontend/timeout.dart'; 9 import '../frontend/timeout.dart';
10 import '../utils.dart';
10 import 'group.dart'; 11 import 'group.dart';
11 import 'invoker.dart'; 12 import 'invoker.dart';
12 import 'metadata.dart'; 13 import 'metadata.dart';
13 import 'test.dart'; 14 import 'suite_entry.dart';
14 15
15 /// A class that manages the state of tests as they're declared. 16 /// A class that manages the state of tests as they're declared.
16 /// 17 ///
17 /// This is in charge of tracking the current group, set-up, and tear-down 18 /// A nested tree of Declarers tracks the current group, set-up, and tear-down
18 /// functions. It produces a list of runnable [tests]. 19 /// functions. Each Declarer in the tree corresponds to a group. This tree is
20 /// tracked by a zone-scoped "current" Declarer; the current declarer can be set
21 /// for a block using [Declarer.declare], and it can be accessed using
22 /// [Declarer.current].
19 class Declarer { 23 class Declarer {
20 /// The current group. 24 /// The parent declarer, or `null` if this corresponds to the root group.
21 var _group = new Group.root(); 25 final Declarer _parent;
22 26
23 /// The list of tests that have been defined. 27 /// The name of the current test group, including the name of any parent group s.
kevmoo 2015/10/02 18:27:21 long line
nweiz 2015/10/02 20:56:54 Done.
24 List<Test> get tests => new UnmodifiableListView<Test>(_tests); 28 ///
25 final _tests = new List<Test>(); 29 /// This is `null` if this is the root group.
30 final String _name;
26 31
27 Declarer(); 32 /// The metadata for this group, including the metadata of any parent groups
33 /// and of the test suite.
34 final Metadata _metadata;
28 35
29 /// Defines a test case with the given description and body. 36 /// The set-up functions for this group.
30 void test(String description, body(), {String testOn, Timeout timeout, 37 final _setUps = new List<AsyncFunction>();
31 skip, Map<String, dynamic> onPlatform}) {
32 // TODO(nweiz): Once tests have begun running, throw an error if [test] is
33 // called.
34 var prefix = _group.description;
35 if (prefix != null) description = "$prefix $description";
36 38
37 var metadata = _group.metadata.merge(new Metadata.parse( 39 /// The tear-down functions for this group.
40 final _tearDowns = new List<AsyncFunction>();
41
42 /// The children of this group, either tests or sub-groups.
43 final _entries = new List<SuiteEntry>();
44
45 /// Whether [build] has been called for this declarer.
46 bool _built = false;
47
48 /// The current zone-scoped declarer.
49 static Declarer get current => Zone.current[#test.declarer];
50
51 /// Creates a new declarer for the root group.
52 ///
53 /// This is the implicit group that exists outside of any calls to `group()`.
54 /// [metadata] should be the suite's metadata, if available.
55 Declarer([Metadata metadata])
56 : this._(null, null, metadata == null ? new Metadata() : metadata);
57
58 Declarer._(this._parent, this._name, this._metadata);
59
60 /// Runs [body] with this declarer as [Declarer.current].
61 ///
62 /// Returns the return value of [body].
63 declare(body()) => runZoned(body, zoneValues: {#test.declarer: this});
64
65 /// Defines a test case with the given name and body.
66 void test(String name, body(), {String testOn, Timeout timeout, skip,
67 Map<String, dynamic> onPlatform}) {
68 if (_built) {
69 throw new StateError("Can't call test() once tests have begun running.");
70 }
71
72 var metadata = _metadata.merge(new Metadata.parse(
38 testOn: testOn, timeout: timeout, skip: skip, onPlatform: onPlatform)); 73 testOn: testOn, timeout: timeout, skip: skip, onPlatform: onPlatform));
39 74
40 var group = _group; 75 _entries.add(new LocalTest(_prefix(name), metadata, () {
41 _tests.add(new LocalTest(description, metadata, () {
42 // TODO(nweiz): It might be useful to throw an error here if a test starts 76 // TODO(nweiz): It might be useful to throw an error here if a test starts
43 // running while other tests from the same declarer are also running, 77 // running while other tests from the same declarer are also running,
44 // since they might share closurized state. 78 // since they might share closurized state.
45 79
46 // TODO(nweiz): Use async/await here once issue 23497 has been fixed in 80 // TODO(nweiz): Use async/await here once issue 23497 has been fixed in
47 // two stable versions. 81 // two stable versions.
48 return Invoker.current.waitForOutstandingCallbacks(() { 82 return Invoker.current.waitForOutstandingCallbacks(() {
49 return group.runSetUps().then((_) => body()); 83 return _runSetUps().then((_) => body());
50 }).then((_) => group.runTearDowns()); 84 }).then((_) => _runTearDowns());
51 })); 85 }));
52 } 86 }
53 87
54 /// Creates a group of tests. 88 /// Creates a group of tests.
55 void group(String description, void body(), {String testOn, 89 void group(String name, void body(), {String testOn, Timeout timeout, skip,
56 Timeout timeout, skip, Map<String, dynamic> onPlatform}) { 90 Map<String, dynamic> onPlatform}) {
57 var oldGroup = _group; 91 if (_built) {
92 throw new StateError("Can't call group() once tests have begun running.");
93 }
58 94
59 var metadata = new Metadata.parse( 95 var metadata = _metadata.merge(new Metadata.parse(
60 testOn: testOn, timeout: timeout, skip: skip, onPlatform: onPlatform); 96 testOn: testOn, timeout: timeout, skip: skip, onPlatform: onPlatform));
61 97
62 // Don' load the tests for a skipped group. 98 // Don't load the tests for a skipped group.
63 if (metadata.skip) { 99 if (metadata.skip) {
64 _tests.add(new LocalTest(description, metadata, () {})); 100 _entries.add(new Group(name, metadata, []));
65 return; 101 return;
66 } 102 }
67 103
68 _group = new Group(oldGroup, description, metadata); 104 var declarer = new Declarer._(this, _prefix(name), metadata);
69 try { 105 declarer.declare(body);
70 body(); 106 _entries.add(new Group(declarer._name, metadata, declarer.build()));
71 } finally {
72 _group = oldGroup;
73 }
74 } 107 }
75 108
76 /// Registers a function to be run before tests. 109 /// Returns [name] prefixed with this declarer's group name.
110 String _prefix(String name) => _name == null ? name : "$_name $name";
111
112 /// Registers a function to be run before each test in this group.
77 void setUp(callback()) { 113 void setUp(callback()) {
78 _group.setUps.add(callback); 114 if (_built) {
115 throw new StateError("Can't call setUp() once tests have begun running.");
116 }
117
118 _setUps.add(callback);
79 } 119 }
80 120
81 /// Registers a function to be run after tests. 121 /// Registers a function to be run after each test in this group.
82 void tearDown(callback()) { 122 void tearDown(callback()) {
83 _group.tearDowns.add(callback); 123 if (_built) {
124 throw new StateError(
125 "Can't call tearDown() once tests have begun running.");
126 }
127
128 _tearDowns.add(callback);
129 }
130
131 /// Finalizes and returns the tests and groups being declared.
132 List<SuiteEntry> build() {
133 if (_built) {
134 throw new StateError("Can't call Declarer.build() more than once.");
135 }
136
137 _built = true;
138 return _entries.toList();
139 }
140
141 /// Run the set-up functions for this and any parent groups.
142 ///
143 /// If no set-up functions are declared, this returns a [Future] that
144 /// completes immediately.
145 Future _runSetUps() {
146 // TODO(nweiz): Use async/await here once issue 23497 has been fixed in two
147 // stable versions.
148 if (_parent != null) {
149 return _parent._runSetUps().then((_) {
150 return Future.forEach(_setUps, (setUp) => setUp());
151 });
152 }
153
154 return Future.forEach(_setUps, (setUp) => setUp());
155 }
156
157 /// Run the tear-up functions for this and any parent groups.
158 ///
159 /// If no set-up functions are declared, this returns a [Future] that
160 /// completes immediately.
161 ///
162 /// This should only be called within a test.
163 Future _runTearDowns() {
164 return Invoker.current.unclosable(() {
165 var tearDowns = [];
166 for (var declarer = this; declarer != null; declarer = declarer._parent) {
167 tearDowns.addAll(declarer._tearDowns.reversed);
168 }
169
170 return Future.forEach(tearDowns, _errorsDontStopTest);
171 });
172 }
173
174 /// Runs [body] with special error-handling behavior.
175 ///
176 /// Errors emitted [body] will still cause the current test to fail, but they
177 /// won't cause it to *stop*. In particular, they won't remove any outstanding
178 /// callbacks registered outside of [body].
179 Future _errorsDontStopTest(body()) {
180 var completer = new Completer();
181
182 Invoker.current.addOutstandingCallback();
183 Invoker.current.waitForOutstandingCallbacks(() {
184 new Future.sync(body).whenComplete(completer.complete);
185 }).then((_) => Invoker.current.removeOutstandingCallback());
186
187 return completer.future;
84 } 188 }
85 } 189 }
OLDNEW
« no previous file with comments | « no previous file | lib/src/backend/group.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698