Skip to content

Commit c2f712c

Browse files
authored
Add language version comments to bootstrap files (#1240) (#1267)
* Add language version comments to bootstrap files (#1240) - Adds a nullable `languageVersionComment` field to `Metadata` - Adds a utility to get a language comment that matches the root packages version - Adds explicit language version comments to all bootstrap files ensuring the versions matches that of the test (note this assumes tests live in the root package) - Clean up the handling of serving bootstrap dart files in the browser platform which had diverged and was serving the wrong content.
1 parent 64cef5a commit c2f712c

14 files changed

Lines changed: 195 additions & 50 deletions

File tree

‎pkgs/test/CHANGELOG.md‎

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,8 @@
1+
## 1.15.0
2+
3+
* Update bootstrapping logic to ensure the bootstrap library has
4+
the same language version as the test.
5+
16
## 1.14.7
27

38
* Support the latest `package:coverage`.

‎pkgs/test/lib/src/runner/browser/platform.dart‎

Lines changed: 12 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -164,23 +164,6 @@ class BrowserPlatform extends PlatformPlugin
164164
shelf.Response _wrapperHandler(shelf.Request request) {
165165
var path = p.fromUri(request.url);
166166

167-
if (path.endsWith('.browser_test.dart')) {
168-
var testPath = p.basename(p.withoutExtension(p.withoutExtension(path)));
169-
return shelf.Response.ok('''
170-
import "package:stream_channel/stream_channel.dart";
171-
172-
import "package:test_core/src/runner/plugin/remote_platform_helpers.dart";
173-
import "package:test/src/runner/browser/post_message_channel.dart";
174-
175-
import "$testPath" as test;
176-
177-
void main() {
178-
var channel = serializeSuite(() => test.main, hidePrints: false);
179-
postMessageChannel().pipe(channel);
180-
}
181-
''', headers: {'Content-Type': 'application/dart'});
182-
}
183-
184167
if (path.endsWith('.html')) {
185168
var test = p.withoutExtension(path) + '.dart';
186169
var scriptBase = htmlEscape.convert(p.basename(test));
@@ -379,18 +362,27 @@ class BrowserPlatform extends PlatformPlugin
379362
return _compileFutures.putIfAbsent(dartPath, () async {
380363
var dir = Directory(_compiledDir).createTempSync('test_').path;
381364
var jsPath = p.join(dir, p.basename(dartPath) + '.browser_test.dart.js');
382-
383-
await _compilers.compile('''
365+
var bootstrapContent = '''
366+
${suiteConfig.metadata.languageVersionComment ?? await rootPackageLanguageVersionComment}
384367
import "package:test/src/bootstrap/browser.dart";
385368
386369
import "${p.toUri(p.absolute(dartPath))}" as test;
387370
388371
void main() {
389372
internalBootstrapBrowserTest(() => test.main);
390373
}
391-
''', jsPath, suiteConfig);
374+
''';
375+
376+
await _compilers.compile(bootstrapContent, jsPath, suiteConfig);
392377
if (_closed) return;
393378

379+
var bootstrapUrl = p.toUri(p.relative(dartPath, from: _root)).path +
380+
'.browser_test.dart';
381+
_jsHandler.add(bootstrapUrl, (request) {
382+
return shelf.Response.ok(bootstrapContent,
383+
headers: {'Content-Type': 'application/dart'});
384+
});
385+
394386
var jsUrl = p.toUri(p.relative(dartPath, from: _root)).path +
395387
'.browser_test.dart.js';
396388
_jsHandler.add(jsUrl, (request) {

‎pkgs/test/lib/src/runner/node/platform.dart‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -153,6 +153,7 @@ class NodePlatform extends PlatformPlugin
153153
var dir = Directory(_compiledDir).createTempSync('test_').path;
154154
var jsPath = p.join(dir, p.basename(testPath) + '.node_test.dart.js');
155155
await _compilers.compile('''
156+
${suiteConfig.metadata.languageVersionComment ?? await rootPackageLanguageVersionComment}
156157
import "package:test/src/bootstrap/node.dart";
157158
158159
import "${p.toUri(p.absolute(testPath))}" as test;

‎pkgs/test/pubspec.yaml‎

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
name: test
2-
version: 1.14.7
2+
version: 1.15.0
33
description: A full featured library for writing and running Dart tests.
44
homepage: https://github.com/dart-lang/test/blob/master/pkgs/test
55

@@ -33,8 +33,8 @@ dependencies:
3333
webkit_inspection_protocol: ">=0.5.0 <0.8.0"
3434
yaml: ^2.0.0
3535
# Use an exact version until the test_api and test_core package are stable.
36-
test_api: 0.2.16
37-
test_core: 0.3.7
36+
test_api: 0.2.17
37+
test_core: 0.3.8
3838

3939
dev_dependencies:
4040
fake_async: ^1.0.0

‎pkgs/test/test/io.dart‎

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -69,10 +69,13 @@ Future<TestProcess> runTest(Iterable<String> args,
6969
String fileReporter,
7070
int concurrency,
7171
Map<String, String> environment,
72-
bool forwardStdio = false}) async {
72+
bool forwardStdio = false,
73+
String packageConfig,
74+
Iterable<String> vmArgs}) async {
7375
concurrency ??= 1;
7476

7577
var allArgs = [
78+
...?vmArgs,
7679
p.absolute(p.join(await packageDir, 'bin/test.dart')),
7780
'--concurrency=$concurrency',
7881
if (reporter != null) '--reporter=$reporter',
@@ -86,18 +89,23 @@ Future<TestProcess> runTest(Iterable<String> args,
8689
return await runDart(allArgs,
8790
environment: environment,
8891
description: 'dart bin/test.dart',
89-
forwardStdio: forwardStdio);
92+
forwardStdio: forwardStdio,
93+
packageConfig: packageConfig);
9094
}
9195

9296
/// Runs Dart.
97+
///
98+
/// If [packageConfig] is provided then that is passed for the `--packages`
99+
/// arg, otherwise the current isolate config is passed.
93100
Future<TestProcess> runDart(Iterable<String> args,
94101
{Map<String, String> environment,
95102
String description,
96-
bool forwardStdio = false}) async {
103+
bool forwardStdio = false,
104+
String packageConfig}) async {
97105
var allArgs = <String>[
98106
...Platform.executableArguments.where((arg) =>
99107
!arg.startsWith('--package-root=') && !arg.startsWith('--packages=')),
100-
'--packages=${await Isolate.packageConfig}',
108+
'--packages=${packageConfig ?? await Isolate.packageConfig}',
101109
...args
102110
];
103111

‎pkgs/test/test/runner/runner_test.dart‎

Lines changed: 83 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,14 @@
44

55
@TestOn('vm')
66

7+
import 'dart:convert';
78
import 'dart:io';
9+
import 'dart:isolate';
810
import 'dart:math' as math;
911

12+
import 'package:package_config/package_config.dart';
13+
import 'package:path/path.dart' as p;
14+
1015
import 'package:test/test.dart';
1116
import 'package:test_core/src/util/exit_codes.dart' as exit_codes;
1217
import 'package:test_descriptor/test_descriptor.dart' as d;
@@ -696,4 +701,82 @@ void main(List<String> args) async {
696701
await test.shouldExit(0);
697702
});
698703
});
704+
705+
group('nnbd', () {
706+
final _testContents = '''
707+
import 'package:test/test.dart';
708+
import 'opted_in.dart';
709+
710+
void main() {
711+
test("success", () {
712+
foo = true;
713+
expect(foo, true);
714+
});
715+
}''';
716+
717+
setUp(() async {
718+
await d.file('opted_in.dart', '''
719+
// @dart=2.9
720+
bool? foo;''').create();
721+
});
722+
723+
test('nnbd can be enabled in deps', () async {
724+
await d.file('test.dart', '''
725+
// @dart=2.8
726+
$_testContents''').create();
727+
var test = await runTest(['test.dart'],
728+
packageConfig: (await Isolate.packageConfig).path,
729+
vmArgs: ['--enable-experiment=non-nullable']);
730+
731+
expect(test.stdout, emitsThrough(contains('+1: All tests passed!')));
732+
await test.shouldExit(0);
733+
});
734+
735+
test('sound null safety is enabled if the entrypoint opts in', () async {
736+
await d.file('test.dart', '''
737+
// @dart=2.9
738+
$_testContents''').create();
739+
var test = await runTest(['test.dart'],
740+
packageConfig: (await Isolate.packageConfig).path,
741+
vmArgs: ['--enable-experiment=non-nullable']);
742+
743+
expect(
744+
test.stdout,
745+
containsInOrder([
746+
'Unable to spawn isolate:',
747+
'Error: A library can\'t opt out of non-nullable by default, when in nnbd-strong mode.'
748+
]));
749+
await test.shouldExit(1);
750+
});
751+
752+
test('sound null safety is enabled if the package is opted in', () async {
753+
var currentPackageConfig =
754+
await loadPackageConfigUri(await Isolate.packageConfig);
755+
var newPackageConfig = PackageConfig([
756+
...currentPackageConfig.packages,
757+
Package('example', Uri.file('${d.sandbox}/'),
758+
languageVersion: LanguageVersion(2, 9),
759+
// TODO: https://github.com/dart-lang/package_config/issues/81
760+
packageUriRoot: Uri.file('${d.sandbox}/')),
761+
]);
762+
763+
await d.file('test.dart', _testContents).create();
764+
await d
765+
.file('package_config.json',
766+
jsonEncode(PackageConfig.toJson(newPackageConfig)))
767+
.create();
768+
769+
var test = await runTest(['test.dart'],
770+
packageConfig: p.join(d.sandbox, 'package_config.json'),
771+
vmArgs: ['--enable-experiment=non-nullable']);
772+
773+
expect(
774+
test.stdout,
775+
containsInOrder([
776+
'Unable to spawn isolate:',
777+
'Error: A library can\'t opt out of non-nullable by default, when in nnbd-strong mode.'
778+
]));
779+
await test.shouldExit(1);
780+
});
781+
});
699782
}

‎pkgs/test_api/CHANGELOG.md‎

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,8 @@
1+
## 0.2.17
2+
3+
* Add `languageVersionComment` on the `MetaData` class. This should only be
4+
presen for test suites.
5+
16
## 0.2.16
27

38
* Deprecate `LiveTestController.liveTest`, the `LiveTestController` instance now

‎pkgs/test_api/lib/src/backend/metadata.dart‎

Lines changed: 25 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,11 @@ class Metadata {
6868
/// resolved when the metadata is constructed.
6969
final Map<BooleanSelector, Metadata> forTag;
7070

71+
/// The language version comment, if one is present.
72+
///
73+
/// Only available for test suites and not individual tests.
74+
final String languageVersionComment;
75+
7176
/// Parses a user-provided map into the value for [onPlatform].
7277
static Map<PlatformSelector, Metadata> _parseOnPlatform(
7378
Map<String, dynamic> onPlatform) {
@@ -147,7 +152,8 @@ class Metadata {
147152
String skipReason,
148153
Iterable<String> tags,
149154
Map<PlatformSelector, Metadata> onPlatform,
150-
Map<BooleanSelector, Metadata> forTag}) {
155+
Map<BooleanSelector, Metadata> forTag,
156+
String languageVersionComment}) {
151157
// Returns metadata without forTag resolved at all.
152158
Metadata _unresolved() => Metadata._(
153159
testOn: testOn,
@@ -159,7 +165,8 @@ class Metadata {
159165
skipReason: skipReason,
160166
tags: tags,
161167
onPlatform: onPlatform,
162-
forTag: forTag);
168+
forTag: forTag,
169+
languageVersionComment: languageVersionComment);
163170

164171
// If there's no tag-specific metadata, or if none of it applies, just
165172
// return the metadata as-is.
@@ -193,7 +200,8 @@ class Metadata {
193200
int retry,
194201
Iterable<String> tags,
195202
Map<PlatformSelector, Metadata> onPlatform,
196-
Map<BooleanSelector, Metadata> forTag})
203+
Map<BooleanSelector, Metadata> forTag,
204+
this.languageVersionComment})
197205
: testOn = testOn ?? PlatformSelector.all,
198206
timeout = timeout ?? const Timeout.factor(1),
199207
_skip = skip,
@@ -220,7 +228,8 @@ class Metadata {
220228
bool chainStackTraces,
221229
int retry,
222230
Map<String, dynamic> onPlatform,
223-
tags})
231+
tags,
232+
this.languageVersionComment})
224233
: testOn = testOn == null
225234
? PlatformSelector.all
226235
: PlatformSelector.parse(testOn),
@@ -261,7 +270,8 @@ class Metadata {
261270
},
262271
forTag = (serialized['forTag'] as Map).map((key, nested) => MapEntry(
263272
BooleanSelector.parse(key as String),
264-
Metadata.deserialize(nested)));
273+
Metadata.deserialize(nested))),
274+
languageVersionComment = serialized['languageVersionComment'] as String;
265275

266276
/// Deserializes timeout from the format returned by [_serializeTimeout].
267277
static Timeout _deserializeTimeout(serialized) {
@@ -314,7 +324,9 @@ class Metadata {
314324
onPlatform: mergeMaps(onPlatform, other.onPlatform,
315325
value: (metadata1, metadata2) => metadata1.merge(metadata2)),
316326
forTag: mergeMaps(forTag, other.forTag,
317-
value: (metadata1, metadata2) => metadata1.merge(metadata2)));
327+
value: (metadata1, metadata2) => metadata1.merge(metadata2)),
328+
languageVersionComment:
329+
other.languageVersionComment ?? languageVersionComment);
318330

319331
/// Returns a copy of [this] with the given fields changed.
320332
Metadata change(
@@ -327,7 +339,8 @@ class Metadata {
327339
String skipReason,
328340
Map<PlatformSelector, Metadata> onPlatform,
329341
Set<String> tags,
330-
Map<BooleanSelector, Metadata> forTag}) {
342+
Map<BooleanSelector, Metadata> forTag,
343+
String languageVersionComment}) {
331344
testOn ??= this.testOn;
332345
timeout ??= this.timeout;
333346
skip ??= _skip;
@@ -338,6 +351,7 @@ class Metadata {
338351
onPlatform ??= this.onPlatform;
339352
tags ??= this.tags;
340353
forTag ??= this.forTag;
354+
languageVersionComment ??= this.languageVersionComment;
341355
return Metadata(
342356
testOn: testOn,
343357
timeout: timeout,
@@ -348,7 +362,8 @@ class Metadata {
348362
onPlatform: onPlatform,
349363
tags: tags,
350364
forTag: forTag,
351-
retry: retry);
365+
retry: retry,
366+
languageVersionComment: languageVersionComment);
352367
}
353368

354369
/// Returns a copy of [this] with all platform-specific metadata from
@@ -384,7 +399,8 @@ class Metadata {
384399
'tags': tags.toList(),
385400
'onPlatform': serializedOnPlatform,
386401
'forTag': forTag.map((selector, metadata) =>
387-
MapEntry(selector.toString(), metadata.serialize()))
402+
MapEntry(selector.toString(), metadata.serialize())),
403+
'languageVersionComment': languageVersionComment,
388404
};
389405
}
390406

‎pkgs/test_api/pubspec.yaml‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
name: test_api
2-
version: 0.2.16
2+
version: 0.2.17
33
description: A library for writing Dart tests.
44
homepage: https://github.com/dart-lang/test/blob/master/pkgs/test_api
55

‎pkgs/test_core/CHANGELOG.md‎

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,10 @@
1+
## 0.3.8
2+
3+
* Update vm bootstrapping logic to ensure the bootstrap library has the same
4+
language version as the test.
5+
* Populate `languageVersionComment` in the `Metadata` returned from
6+
`parseMetadata`.
7+
18
## 0.3.7
29

310
* Support the latest `package:coverage`.

0 commit comments

Comments
 (0)