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

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

Issue 1400743002: Add support for setUpAll and tearDownAll. (Closed) Base URL: git@github.com:dart-lang/test@master
Patch Set: 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 | « CHANGELOG.md ('k') | 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:async'; 7 import 'dart:async';
8 8
9 import '../frontend/timeout.dart'; 9 import '../frontend/timeout.dart';
10 import '../utils.dart'; 10 import '../utils.dart';
11 import 'group.dart'; 11 import 'group.dart';
12 import 'group_entry.dart';
12 import 'invoker.dart'; 13 import 'invoker.dart';
13 import 'metadata.dart'; 14 import 'metadata.dart';
14 import 'group_entry.dart'; 15 import 'test.dart';
15 16
16 /// A class that manages the state of tests as they're declared. 17 /// A class that manages the state of tests as they're declared.
17 /// 18 ///
18 /// A nested tree of Declarers tracks the current group, set-up, and tear-down 19 /// A nested tree of Declarers tracks the current group, set-up, and tear-down
19 /// functions. Each Declarer in the tree corresponds to a group. This tree is 20 /// 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 /// 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 /// for a block using [Declarer.declare], and it can be accessed using
22 /// [Declarer.current]. 23 /// [Declarer.current].
23 class Declarer { 24 class Declarer {
24 /// The parent declarer, or `null` if this corresponds to the root group. 25 /// The parent declarer, or `null` if this corresponds to the root group.
25 final Declarer _parent; 26 final Declarer _parent;
26 27
27 /// The name of the current test group, including the name of any parent 28 /// The name of the current test group, including the name of any parent
28 /// groups. 29 /// groups.
29 /// 30 ///
30 /// This is `null` if this is the root group. 31 /// This is `null` if this is the root group.
31 final String _name; 32 final String _name;
32 33
33 /// The metadata for this group, including the metadata of any parent groups 34 /// The metadata for this group, including the metadata of any parent groups
34 /// and of the test suite. 35 /// and of the test suite.
35 final Metadata _metadata; 36 final Metadata _metadata;
36 37
37 /// The set-up functions for this group. 38 /// The set-up functions to run for each test in this group.
38 final _setUps = new List<AsyncFunction>(); 39 final _setUps = new List<AsyncFunction>();
39 40
40 /// The tear-down functions for this group. 41 /// The tear-down functions to run for each test in this group.
41 final _tearDowns = new List<AsyncFunction>(); 42 final _tearDowns = new List<AsyncFunction>();
42 43
44 /// The set-up functions to run once for this group.
45 final _setUpAlls = new List<AsyncFunction>();
46
47 /// The tear-down functions to run once for this group.
48 final _tearDownAlls = new List<AsyncFunction>();
49
43 /// The children of this group, either tests or sub-groups. 50 /// The children of this group, either tests or sub-groups.
44 final _entries = new List<GroupEntry>(); 51 final _entries = new List<GroupEntry>();
45 52
46 /// Whether [build] has been called for this declarer. 53 /// Whether [build] has been called for this declarer.
47 bool _built = false; 54 bool _built = false;
48 55
49 /// The current zone-scoped declarer. 56 /// The current zone-scoped declarer.
50 static Declarer get current => Zone.current[#test.declarer]; 57 static Declarer get current => Zone.current[#test.declarer];
51 58
52 /// Creates a new declarer for the root group. 59 /// Creates a new declarer for the root group.
53 /// 60 ///
54 /// This is the implicit group that exists outside of any calls to `group()`. 61 /// This is the implicit group that exists outside of any calls to `group()`.
55 /// If [metadata] is passed, it's used as the metadata for the implicit root 62 /// If [metadata] is passed, it's used as the metadata for the implicit root
56 /// group. 63 /// group.
57 Declarer([Metadata metadata]) 64 Declarer([Metadata metadata])
58 : this._(null, null, metadata == null ? new Metadata() : metadata); 65 : this._(null, null, metadata == null ? new Metadata() : metadata);
59 66
60 Declarer._(this._parent, this._name, this._metadata); 67 Declarer._(this._parent, this._name, this._metadata);
61 68
62 /// Runs [body] with this declarer as [Declarer.current]. 69 /// Runs [body] with this declarer as [Declarer.current].
63 /// 70 ///
64 /// Returns the return value of [body]. 71 /// Returns the return value of [body].
65 declare(body()) => runZoned(body, zoneValues: {#test.declarer: this}); 72 declare(body()) => runZoned(body, zoneValues: {#test.declarer: this});
66 73
67 /// Defines a test case with the given name and body. 74 /// Defines a test case with the given name and body.
68 void test(String name, body(), {String testOn, Timeout timeout, skip, 75 void test(String name, body(), {String testOn, Timeout timeout, skip,
69 Map<String, dynamic> onPlatform}) { 76 Map<String, dynamic> onPlatform}) {
70 if (_built) { 77 _checkNotBuilt("test");
71 throw new StateError("Can't call test() once tests have begun running.");
72 }
73 78
74 var metadata = _metadata.merge(new Metadata.parse( 79 var metadata = _metadata.merge(new Metadata.parse(
75 testOn: testOn, timeout: timeout, skip: skip, onPlatform: onPlatform)); 80 testOn: testOn, timeout: timeout, skip: skip, onPlatform: onPlatform));
76 81
77 _entries.add(new LocalTest(_prefix(name), metadata, () { 82 _entries.add(new LocalTest(_prefix(name), metadata, () {
78 // TODO(nweiz): It might be useful to throw an error here if a test starts 83 // TODO(nweiz): It might be useful to throw an error here if a test starts
79 // running while other tests from the same declarer are also running, 84 // running while other tests from the same declarer are also running,
80 // since they might share closurized state. 85 // since they might share closurized state.
81 86
82 // TODO(nweiz): Use async/await here once issue 23497 has been fixed in 87 // TODO(nweiz): Use async/await here once issue 23497 has been fixed in
83 // two stable versions. 88 // two stable versions.
84 return Invoker.current.waitForOutstandingCallbacks(() { 89 return Invoker.current.waitForOutstandingCallbacks(() {
85 return _runSetUps().then((_) => body()); 90 return _runSetUps().then((_) => body());
86 }).then((_) => _runTearDowns()); 91 }).then((_) => _runTearDowns());
87 })); 92 }));
88 } 93 }
89 94
90 /// Creates a group of tests. 95 /// Creates a group of tests.
91 void group(String name, void body(), {String testOn, Timeout timeout, skip, 96 void group(String name, void body(), {String testOn, Timeout timeout, skip,
92 Map<String, dynamic> onPlatform}) { 97 Map<String, dynamic> onPlatform}) {
93 if (_built) { 98 _checkNotBuilt("group");
94 throw new StateError("Can't call group() once tests have begun running.");
95 }
96 99
97 var metadata = _metadata.merge(new Metadata.parse( 100 var metadata = _metadata.merge(new Metadata.parse(
98 testOn: testOn, timeout: timeout, skip: skip, onPlatform: onPlatform)); 101 testOn: testOn, timeout: timeout, skip: skip, onPlatform: onPlatform));
99 102
100 // Don't load the tests for a skipped group. 103 // Don't load the tests for a skipped group.
101 if (metadata.skip) { 104 if (metadata.skip) {
102 _entries.add(new Group(name, [], metadata: metadata)); 105 _entries.add(new Group(name, [], metadata: metadata));
103 return; 106 return;
104 } 107 }
105 108
106 var declarer = new Declarer._(this, _prefix(name), metadata); 109 var declarer = new Declarer._(this, _prefix(name), metadata);
107 declarer.declare(body); 110 declarer.declare(body);
108 _entries.add(declarer.build()); 111 _entries.add(declarer.build());
109 } 112 }
110 113
111 /// Returns [name] prefixed with this declarer's group name. 114 /// Returns [name] prefixed with this declarer's group name.
112 String _prefix(String name) => _name == null ? name : "$_name $name"; 115 String _prefix(String name) => _name == null ? name : "$_name $name";
113 116
114 /// Registers a function to be run before each test in this group. 117 /// Registers a function to be run before each test in this group.
115 void setUp(callback()) { 118 void setUp(callback()) {
116 if (_built) { 119 _checkNotBuilt("setUp");
117 throw new StateError("Can't call setUp() once tests have begun running.");
118 }
119
120 _setUps.add(callback); 120 _setUps.add(callback);
121 } 121 }
122 122
123 /// Registers a function to be run after each test in this group. 123 /// Registers a function to be run after each test in this group.
124 void tearDown(callback()) { 124 void tearDown(callback()) {
125 if (_built) { 125 _checkNotBuilt("tearDown");
126 throw new StateError( 126 _tearDowns.add(callback);
127 "Can't call tearDown() once tests have begun running."); 127 }
128 }
129 128
130 _tearDowns.add(callback); 129 /// Registers a function to be run once before all tests.
130 void setUpAll(callback()) {
131 _checkNotBuilt("setUpAll");
132 _setUpAlls.add(callback);
133 }
134
135 /// Registers a function to be run once after all tests.
136 void tearDownAll(callback()) {
137 _checkNotBuilt("tearDownAll");
138 _tearDownAlls.add(callback);
131 } 139 }
132 140
133 /// Finalizes and returns the group being declared. 141 /// Finalizes and returns the group being declared.
134 Group build() { 142 Group build() {
135 if (_built) { 143 _checkNotBuilt("build");
136 throw new StateError("Can't call Declarer.build() more than once.");
137 }
138 144
139 _built = true; 145 _built = true;
140 return new Group(_name, _entries.toList(), metadata: _metadata); 146 return new Group(_name, _entries.toList(),
147 metadata: _metadata,
148 setUpAll: _setUpAll,
149 tearDownAll: _tearDownAll);
150 }
151
152 /// Throws a [StateError] if [build] has been called.
153 ///
154 /// [name] should be the name of the method being called.
155 void _checkNotBuilt(String name) {
156 if (!_built) return;
157 throw new StateError("Can't call $name() once tests have begun running.");
141 } 158 }
142 159
143 /// Run the set-up functions for this and any parent groups. 160 /// Run the set-up functions for this and any parent groups.
144 /// 161 ///
145 /// If no set-up functions are declared, this returns a [Future] that 162 /// If no set-up functions are declared, this returns a [Future] that
146 /// completes immediately. 163 /// completes immediately.
147 Future _runSetUps() { 164 Future _runSetUps() {
148 // TODO(nweiz): Use async/await here once issue 23497 has been fixed in two 165 // TODO(nweiz): Use async/await here once issue 23497 has been fixed in two
149 // stable versions. 166 // stable versions.
150 if (_parent != null) { 167 if (_parent != null) {
(...skipping 15 matching lines...) Expand all
166 return Invoker.current.unclosable(() { 183 return Invoker.current.unclosable(() {
167 var tearDowns = []; 184 var tearDowns = [];
168 for (var declarer = this; declarer != null; declarer = declarer._parent) { 185 for (var declarer = this; declarer != null; declarer = declarer._parent) {
169 tearDowns.addAll(declarer._tearDowns.reversed); 186 tearDowns.addAll(declarer._tearDowns.reversed);
170 } 187 }
171 188
172 return Future.forEach(tearDowns, _errorsDontStopTest); 189 return Future.forEach(tearDowns, _errorsDontStopTest);
173 }); 190 });
174 } 191 }
175 192
193 /// Returns a [Test] that runs the callbacks in [_setUpAll].
194 Test get _setUpAll {
195 if (_setUpAlls.isEmpty) return null;
196
197 return new LocalTest(_prefix("(setUpAll)"), _metadata, () {
198 return Future.forEach(_setUpAlls, (setUp) => setUp());
199 });
200 }
201
202 /// Returns a [Test] that runs the callbacks in [_tearDownAll].
203 Test get _tearDownAll {
204 if (_tearDownAlls.isEmpty) return null;
205
206 return new LocalTest(_prefix("(tearDownAll)"), _metadata, () {
207 return Invoker.current.unclosable(() {
208 return Future.forEach(_tearDownAlls.reversed, _errorsDontStopTest);
209 });
210 });
211 }
212
176 /// Runs [body] with special error-handling behavior. 213 /// Runs [body] with special error-handling behavior.
177 /// 214 ///
178 /// Errors emitted [body] will still cause the current test to fail, but they 215 /// Errors emitted [body] will still cause the current test to fail, but they
179 /// won't cause it to *stop*. In particular, they won't remove any outstanding 216 /// won't cause it to *stop*. In particular, they won't remove any outstanding
180 /// callbacks registered outside of [body]. 217 /// callbacks registered outside of [body].
181 Future _errorsDontStopTest(body()) { 218 Future _errorsDontStopTest(body()) {
182 var completer = new Completer(); 219 var completer = new Completer();
183 220
184 Invoker.current.addOutstandingCallback(); 221 Invoker.current.addOutstandingCallback();
185 Invoker.current.waitForOutstandingCallbacks(() { 222 Invoker.current.waitForOutstandingCallbacks(() {
186 new Future.sync(body).whenComplete(completer.complete); 223 new Future.sync(body).whenComplete(completer.complete);
187 }).then((_) => Invoker.current.removeOutstandingCallback()); 224 }).then((_) => Invoker.current.removeOutstandingCallback());
188 225
189 return completer.future; 226 return completer.future;
190 } 227 }
191 } 228 }
OLDNEW
« no previous file with comments | « CHANGELOG.md ('k') | lib/src/backend/group.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698