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

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

Powered by Google App Engine
This is Rietveld 408576698