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

Side by Side Diff: lib/src/runner.dart

Issue 1490973003: Clean up the warning for unknown tags. (Closed) Base URL: git@github.com:dart-lang/test@master
Patch Set: Created 5 years 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/runner/load_suite.dart » ('j') | test/runner/tag_test.dart » ('J')
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.runner; 5 library test.runner;
6 6
7 import 'dart:async'; 7 import 'dart:async';
8 import 'dart:io'; 8 import 'dart:io';
9 9
10 import 'package:async/async.dart'; 10 import 'package:async/async.dart';
11 11
12 import 'backend/group.dart';
13 import 'backend/group_entry.dart';
14 import 'backend/test.dart';
12 import 'backend/test_platform.dart'; 15 import 'backend/test_platform.dart';
13 import 'runner/application_exception.dart'; 16 import 'runner/application_exception.dart';
14 import 'runner/configuration.dart'; 17 import 'runner/configuration.dart';
15 import 'runner/engine.dart'; 18 import 'runner/engine.dart';
16 import 'runner/load_exception.dart'; 19 import 'runner/load_exception.dart';
17 import 'runner/load_suite.dart'; 20 import 'runner/load_suite.dart';
18 import 'runner/loader.dart'; 21 import 'runner/loader.dart';
19 import 'runner/reporter.dart'; 22 import 'runner/reporter.dart';
20 import 'runner/reporter/compact.dart'; 23 import 'runner/reporter/compact.dart';
21 import 'runner/reporter/expanded.dart'; 24 import 'runner/reporter/expanded.dart';
(...skipping 16 matching lines...) Expand all
38 41
39 /// The engine that runs the test suites. 42 /// The engine that runs the test suites.
40 final Engine _engine; 43 final Engine _engine;
41 44
42 /// The reporter that's emitting the test runner's results. 45 /// The reporter that's emitting the test runner's results.
43 final Reporter _reporter; 46 final Reporter _reporter;
44 47
45 /// The subscription to the stream returned by [_loadSuites]. 48 /// The subscription to the stream returned by [_loadSuites].
46 StreamSubscription _suiteSubscription; 49 StreamSubscription _suiteSubscription;
47 50
51 /// The set of suite paths for which [_warnForUnknownTags] has already been
52 /// called.
53 ///
54 /// This is used to avoid printing duplicate warnings when a suite is loaded
55 /// on multiple platforms.
56 final _tagWarningSuites = new Set<String>();
57
48 /// The memoizer for ensuring [close] only runs once. 58 /// The memoizer for ensuring [close] only runs once.
49 final _closeMemo = new AsyncMemoizer(); 59 final _closeMemo = new AsyncMemoizer();
50 bool get _closed => _closeMemo.hasRun; 60 bool get _closed => _closeMemo.hasRun;
51 61
52 /// Creates a new runner based on [configuration]. 62 /// Creates a new runner based on [configuration].
53 factory Runner(Configuration config) { 63 factory Runner(Configuration config) {
54 var loader = new Loader(config); 64 var loader = new Loader(config);
55 var engine = new Engine(concurrency: config.concurrency); 65 var engine = new Engine(concurrency: config.concurrency);
56 66
57 var reporter; 67 var reporter;
(...skipping 105 matching lines...) Expand 10 before | Expand all | Expand 10 after
163 return mergeStreams(_config.paths.map((path) { 173 return mergeStreams(_config.paths.map((path) {
164 if (new Directory(path).existsSync()) return _loader.loadDir(path); 174 if (new Directory(path).existsSync()) return _loader.loadDir(path);
165 if (new File(path).existsSync()) return _loader.loadFile(path); 175 if (new File(path).existsSync()) return _loader.loadFile(path);
166 176
167 return new Stream.fromIterable([ 177 return new Stream.fromIterable([
168 new LoadSuite("loading $path", () => 178 new LoadSuite("loading $path", () =>
169 throw new LoadException(path, 'Does not exist.')) 179 throw new LoadException(path, 'Does not exist.'))
170 ]); 180 ]);
171 })).map((loadSuite) { 181 })).map((loadSuite) {
172 return loadSuite.changeSuite((suite) { 182 return loadSuite.changeSuite((suite) {
183 _warnForUnknownTags(suite);
184
173 return suite.filter((test) { 185 return suite.filter((test) {
174 // Warn if any test has tags that don't appear on the command line.
175 //
176 // TODO(nweiz): Only print this once per test, even if it's run on
177 // multiple runners.
178 //
179 // TODO(nweiz): If groups or suites are tagged, don't print this for
180 // every test they contain.
181 //
182 // TODO(nweiz): Print this as part of the test's output so it's easy
183 // to associate with the correct test.
184 var specifiedTags = _config.tags.union(_config.excludeTags);
185 var unrecognizedTags = test.metadata.tags.difference(specifiedTags);
186 if (unrecognizedTags.isNotEmpty) {
187 // Pause the reporter while we print to ensure that we don't
188 // interfere with its output.
189 _reporter.pause();
190 warn(
191 'Unknown ${pluralize('tag', unrecognizedTags.length)} '
192 '${toSentence(unrecognizedTags)} in test "${test.name}".',
193 color: _config.color);
194 _reporter.resume();
195 }
196
197 // Skip any tests that don't match the given pattern. 186 // Skip any tests that don't match the given pattern.
198 if (_config.pattern != null && !test.name.contains(_config.pattern)) { 187 if (_config.pattern != null && !test.name.contains(_config.pattern)) {
199 return false; 188 return false;
200 } 189 }
201 190
202 // If the user provided tags, skip tests that don't match all of them. 191 // If the user provided tags, skip tests that don't match all of them.
203 if (!_config.tags.isEmpty && 192 if (!_config.tags.isEmpty &&
204 !test.metadata.tags.containsAll(_config.tags)) { 193 !test.metadata.tags.containsAll(_config.tags)) {
205 return false; 194 return false;
206 } 195 }
207 196
208 // Skip tests that do match any tags the user wants to exclude. 197 // Skip tests that do match any tags the user wants to exclude.
209 if (_config.excludeTags.intersection(test.metadata.tags).isNotEmpty) { 198 if (_config.excludeTags.intersection(test.metadata.tags).isNotEmpty) {
210 return false; 199 return false;
211 } 200 }
212 201
213 return true; 202 return true;
214 }); 203 });
215 }); 204 });
216 }); 205 });
217 } 206 }
218 207
208 /// Prints a warning for any unknown tags referenced in [suite] or its
209 /// children.
210 void _warnForUnknownTags(Suite suite) {
kevmoo 2015/12/02 04:57:01 missing an import containing Suite
nweiz 2015/12/02 22:21:16 Done.
211 if (_tagWarningSuites.contains(suite.path)) return;
212 _tagWarningSuites.add(suite.path);
213
214 var unknownTags = _collectUnknownTags(suite);
215 if (unknownTags.isEmpty) return;
216
217 var yellow = _config.color ? '\u001b[33m' : '';
218 var bold = _config.color ? '\u001b[1m' : '';
219 var noColor = _config.color ? '\u001b[0m' : '';
220
221 var buffer = new StringBuffer()
222 ..write("${yellow}Warning:$noColor ")
223 ..write(unknownTags.length == 1 ? "A tag was " : "Tags were ")
224 ..write("used that ")
225 ..write(unknownTags.length == 1 ? "wasn't " : "weren't ")
226 ..writeln("specified on the command line.");
227
228 unknownTags.forEach((tag, entries) {
229 buffer.write(" $bold$tag$noColor was used in");
230
231 if (entries.length == 1) {
232 buffer.writeln(" ${_entryDescription(entries.single)}");
233 return;
234 }
235
236 buffer.write(":");
237 for (var entry in entries) {
238 buffer.write("\n ${_entryDescription(entry)}");
239 }
240 buffer.writeln();
241 });
242
243 print(buffer.toString());
244 }
245
246 /// Collects all tags used by [suite] or its children that aren't also passed
247 /// on the command line.
248 ///
249 /// This returns a map from tag names to lists of entries that use those tags.
250 Map<String, List<GroupEntry>> _collectUnknownTags(Suite suite) {
251 var knownTags = _config.tags.union(_config.excludeTags);
252 var unknownTags = {};
253 var currentTags = new Set();
254
255 collect(entry) {
256 var newTags = new Set();
257 for (var unknownTag in entry.metadata.tags.difference(knownTags)) {
258 if (currentTags.contains(unknownTag)) continue;
259 unknownTags.putIfAbsent(unknownTag, () => []).add(entry);
260 newTags.add(unknownTag);
261 }
262
263 if (entry is! Group) return;
264
265 currentTags.addAll(newTags);
266 for (var child in entry.entries) {
267 collect(child);
268 }
269 currentTags.removeAll(newTags);
270 }
271
272 collect(suite.group);
273 return unknownTags;
274 }
275
276 /// Returns a human-readable description of [entry], including its type.
277 String _entryDescription(GroupEntry entry) {
278 if (entry is Test) return 'the test "${entry.name}"';
279 if (entry.name != null) return 'the group "${entry.name}"';
280 return 'the suite itself';
281 }
282
219 /// Loads each suite in [suites] in order, pausing after load for platforms 283 /// Loads each suite in [suites] in order, pausing after load for platforms
220 /// that support debugging. 284 /// that support debugging.
221 Future<bool> _loadThenPause(Stream<LoadSuite> suites) async { 285 Future<bool> _loadThenPause(Stream<LoadSuite> suites) async {
222 if (_config.platforms.contains(TestPlatform.vm)) { 286 if (_config.platforms.contains(TestPlatform.vm)) {
223 warn("Debugging is currently unsupported on the Dart VM.", 287 warn("Debugging is currently unsupported on the Dart VM.",
224 color: _config.color); 288 color: _config.color);
225 } 289 }
226 290
227 _suiteSubscription = suites.asyncMap((loadSuite) async { 291 _suiteSubscription = suites.asyncMap((loadSuite) async {
228 // Make the underlying suite null so that the engine doesn't start running 292 // Make the underlying suite null so that the engine doesn't start running
(...skipping 69 matching lines...) Expand 10 before | Expand all | Expand 10 after
298 362
299 await inCompletionOrder([ 363 await inCompletionOrder([
300 suite.environment.displayPause(), 364 suite.environment.displayPause(),
301 cancelableNext(stdinLines) 365 cancelableNext(stdinLines)
302 ]).first; 366 ]).first;
303 } finally { 367 } finally {
304 _reporter.resume(); 368 _reporter.resume();
305 } 369 }
306 } 370 }
307 } 371 }
OLDNEW
« no previous file with comments | « no previous file | lib/src/runner/load_suite.dart » ('j') | test/runner/tag_test.dart » ('J')

Powered by Google App Engine
This is Rietveld 408576698