Skip to content

Commit 5d0a9e3

Browse files
authored
Extensible reporters and test platforms (#588)
Adding hooks for new reporters and test platforms. These hooks are not intended to be a part of the external API and thus are aptly documented.
1 parent 25cd363 commit 5d0a9e3

File tree

8 files changed

+106
-48
lines changed

8 files changed

+106
-48
lines changed

lib/src/backend/test_platform.dart

Lines changed: 36 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@
22
// for details. All rights reserved. Use of this source code is governed by a
33
// BSD-style license that can be found in the LICENSE file.
44

5+
import 'dart:collection';
6+
57
// TODO(nweiz): support pluggable platforms.
68
/// An enum of all platforms on which tests can run.
79
class TestPlatform {
@@ -44,16 +46,8 @@ class TestPlatform {
4446
isBrowser: true, isJS: true);
4547

4648
/// A list of all instances of [TestPlatform].
47-
static const List<TestPlatform> all = const [
48-
vm,
49-
dartium,
50-
contentShell,
51-
chrome,
52-
phantomJS,
53-
firefox,
54-
safari,
55-
internetExplorer
56-
];
49+
static final UnmodifiableListView<TestPlatform> all =
50+
new UnmodifiableListView<TestPlatform>(_allPlatforms);
5751

5852
/// Finds a platform by its identifier string.
5953
///
@@ -92,3 +86,35 @@ class TestPlatform {
9286

9387
String toString() => name;
9488
}
89+
90+
final List<TestPlatform> _allPlatforms = [
91+
TestPlatform.vm,
92+
TestPlatform.dartium,
93+
TestPlatform.contentShell,
94+
TestPlatform.chrome,
95+
TestPlatform.phantomJS,
96+
TestPlatform.firefox,
97+
TestPlatform.safari,
98+
TestPlatform.internetExplorer
99+
];
100+
101+
/// **Do not call this function without express permission from the test package
102+
/// authors**.
103+
///
104+
/// This constructs and globally registers a new TestPlatform with the provided
105+
/// details.
106+
TestPlatform registerTestPlatform(String name, String identifier,
107+
{bool isDartVM: false,
108+
bool isBrowser: false,
109+
bool isJS: false,
110+
bool isBlink: false,
111+
bool isHeadless: false}) {
112+
var platform = new TestPlatform._(name, identifier,
113+
isDartVM: isDartVM,
114+
isBrowser: isBrowser,
115+
isJS: isJS,
116+
isBlink: isBlink,
117+
isHeadless: isHeadless);
118+
_allPlatforms.add(platform);
119+
return platform;
120+
}

lib/src/runner.dart

Lines changed: 3 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ import 'backend/test.dart';
1616
import 'backend/test_platform.dart';
1717
import 'runner/application_exception.dart';
1818
import 'runner/configuration.dart';
19+
import 'runner/configuration/reporters.dart';
1920
import 'runner/debugger.dart';
2021
import 'runner/engine.dart';
2122
import 'runner/load_exception.dart';
@@ -69,26 +70,8 @@ class Runner {
6970
factory Runner(Configuration config) => config.asCurrent(() {
7071
var engine = new Engine(concurrency: config.concurrency);
7172

72-
var reporter;
73-
switch (config.reporter) {
74-
case "expanded":
75-
reporter = ExpandedReporter.watch(engine,
76-
color: config.color,
77-
printPath: config.paths.length > 1 ||
78-
new Directory(config.paths.single).existsSync(),
79-
printPlatform: config.suiteDefaults.platforms.length > 1);
80-
break;
81-
82-
case "compact":
83-
reporter = CompactReporter.watch(engine);
84-
break;
85-
86-
case "json":
87-
reporter = JsonReporter.watch(engine);
88-
break;
89-
}
90-
91-
return new Runner._(engine, reporter);
73+
var reporterDetails = allReporters[config.reporter];
74+
return new Runner._(engine, reporterDetails.factory(config, engine));
9275
});
9376

9477
Runner._(this._engine, this._reporter);

lib/src/runner/configuration.dart

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ import '../frontend/timeout.dart';
1616
import '../util/io.dart';
1717
import 'configuration/args.dart' as args;
1818
import 'configuration/load.dart';
19+
import 'configuration/reporters.dart';
1920
import 'configuration/suite.dart';
2021
import 'configuration/values.dart';
2122

lib/src/runner/configuration/args.dart

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ import 'package:boolean_selector/boolean_selector.dart';
1010
import '../../backend/test_platform.dart';
1111
import '../../frontend/timeout.dart';
1212
import '../configuration.dart';
13+
import 'reporters.dart';
1314
import 'values.dart';
1415

1516
/// The parser used to parse the command-line arguments.
@@ -92,17 +93,18 @@ final ArgParser _parser = (() {
9293
'debuggability.',
9394
defaultsTo: true);
9495

96+
var reporterDescriptions = <String, String>{};
97+
for (var reporter in allReporters.keys) {
98+
reporterDescriptions[reporter] = allReporters[reporter].description;
99+
}
100+
95101
parser.addSeparator("======== Output");
96102
parser.addOption("reporter",
97103
abbr: 'r',
98104
help: 'The runner used to print test results.',
99105
defaultsTo: defaultReporter,
100-
allowed: allReporters,
101-
allowedHelp: {
102-
'compact': 'A single line, updated continuously.',
103-
'expanded': 'A separate line for each update.',
104-
'json': 'A machine-readable format (see https://goo.gl/gBsV1a).'
105-
});
106+
allowed: reporterDescriptions.keys.toList(),
107+
allowedHelp: reporterDescriptions);
106108
parser.addFlag("verbose-trace",
107109
negatable: false,
108110
help: 'Whether to emit stack traces with core library frames.');

lib/src/runner/configuration/load.dart

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ import '../../utils.dart';
1919
import '../../util/io.dart';
2020
import '../configuration.dart';
2121
import '../configuration/suite.dart';
22-
import 'values.dart';
22+
import 'reporters.dart';
2323

2424
/// Loads configuration information from a YAML file at [path].
2525
///
@@ -176,7 +176,7 @@ class _ConfigurationLoader {
176176
var runSkipped = _getBool("run_skipped");
177177

178178
var reporter = _getString("reporter");
179-
if (reporter != null && !allReporters.contains(reporter)) {
179+
if (reporter != null && !allReporters.keys.contains(reporter)) {
180180
_error('Unknown reporter "$reporter".', "reporter");
181181
}
182182

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
// Copyright (c) 2017, the Dart project authors. Please see the AUTHORS file
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.
4+
5+
import 'dart:io';
6+
import 'dart:collection';
7+
8+
import '../engine.dart';
9+
import '../configuration.dart';
10+
import '../reporter.dart';
11+
import '../reporter/compact.dart';
12+
import '../reporter/expanded.dart';
13+
import '../reporter/json.dart';
14+
import '../../util/io.dart';
15+
16+
/// Constructs a reporter for the provided engine with the provided
17+
/// configuration.
18+
typedef Reporter ReporterFactory(Configuration configuration, Engine engine);
19+
20+
/// Container for a reporter description and corresponding factory.
21+
class ReporterDetails {
22+
final String description;
23+
final ReporterFactory factory;
24+
ReporterDetails(this.description, this.factory);
25+
}
26+
27+
/// All reporters and their corresponding details.
28+
final UnmodifiableMapView<String, ReporterDetails> allReporters =
29+
new UnmodifiableMapView<String, ReporterDetails>(_allReporters);
30+
31+
final _allReporters = <String, ReporterDetails>{
32+
"expanded": new ReporterDetails(
33+
"A separate line for each update.",
34+
(config, engine) => ExpandedReporter.watch(engine,
35+
color: config.color,
36+
printPath: config.paths.length > 1 ||
37+
new Directory(config.paths.single).existsSync(),
38+
printPlatform: config.suiteDefaults.platforms.length > 1)),
39+
"compact": new ReporterDetails("A single line, updated continuously.",
40+
(_, engine) => CompactReporter.watch(engine)),
41+
"json": new ReporterDetails(
42+
"A machine-readable format (see https://goo.gl/gBsV1a).",
43+
(_, engine) => JsonReporter.watch(engine)),
44+
};
45+
46+
final defaultReporter =
47+
inTestTests ? 'expanded' : (Platform.isWindows ? 'expanded' : 'compact');
48+
49+
/// **Do not call this function without express permission from the test package
50+
/// authors**.
51+
///
52+
/// This globally registers a reporter.
53+
void registerReporter(String name, ReporterDetails reporterDetails) {
54+
_allReporters[name] = reporterDetails;
55+
}

lib/src/runner/configuration/values.dart

Lines changed: 0 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -7,21 +7,12 @@ import 'dart:math' as math;
77

88
import 'package:glob/glob.dart';
99

10-
import '../../util/io.dart';
11-
1210
/// The default number of test suites to run at once.
1311
///
1412
/// This defaults to half the available processors, since presumably some of
1513
/// them will be used for the OS and other processes.
1614
final defaultConcurrency = math.max(1, Platform.numberOfProcessors ~/ 2);
1715

18-
/// The reporters supported by the test runner.
19-
const allReporters = const ["compact", "expanded", "json"];
20-
21-
/// The default reporter.
22-
final defaultReporter =
23-
inTestTests ? 'expanded' : (Platform.isWindows ? 'expanded' : 'compact');
24-
2516
/// The default filename pattern.
2617
///
2718
/// This is stored here so that we don't have to recompile it multiple times.

test/runner/configuration/configuration_test.dart

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ import 'package:path/path.dart' as p;
77
import 'package:test/test.dart';
88

99
import 'package:test/src/runner/configuration.dart';
10-
import 'package:test/src/runner/configuration/values.dart';
10+
import 'package:test/src/runner/configuration/reporters.dart';
1111
import 'package:test/src/util/io.dart';
1212

1313
void main() {

0 commit comments

Comments
 (0)