[flutter_tools] ensure generated entrypoint matches test and web entrypoint language version (#59291)
Ensure that the language version of the test/web generated entrypoint matches the language version of the test file to run, or the overall package language version if no annotation is provided.
This commit is contained in:
parent
584fd5f913
commit
958f7c5b55
@ -544,7 +544,7 @@ Future<void> _runAddToAppLifeCycleTests() async {
|
|||||||
|
|
||||||
Future<void> _runFrameworkTests() async {
|
Future<void> _runFrameworkTests() async {
|
||||||
final bq.BigqueryApi bigqueryApi = await _getBigqueryApi();
|
final bq.BigqueryApi bigqueryApi = await _getBigqueryApi();
|
||||||
final List<String> nullSafetyOptions = <String>['--enable-experiment=non-nullable', '--no-sound-null-safety'];
|
final List<String> nullSafetyOptions = <String>['--enable-experiment=non-nullable'];
|
||||||
final List<String> trackWidgetCreationAlternatives = <String>['--track-widget-creation', '--no-track-widget-creation'];
|
final List<String> trackWidgetCreationAlternatives = <String>['--track-widget-creation', '--no-track-widget-creation'];
|
||||||
|
|
||||||
Future<void> runWidgets() async {
|
Future<void> runWidgets() async {
|
||||||
|
@ -2,11 +2,9 @@
|
|||||||
// Use of this source code is governed by a BSD-style license that can be
|
// Use of this source code is governed by a BSD-style license that can be
|
||||||
// found in the LICENSE file.
|
// found in the LICENSE file.
|
||||||
|
|
||||||
// @dart=2.9
|
// @dart=2.8
|
||||||
import 'package:flutter_test/flutter_test.dart';
|
import 'package:flutter_test/flutter_test.dart';
|
||||||
|
|
||||||
String? x;
|
|
||||||
|
|
||||||
void main() {
|
void main() {
|
||||||
testWidgets('trivial', (WidgetTester tester) async {
|
testWidgets('trivial', (WidgetTester tester) async {
|
||||||
expect(true, true);
|
expect(true, true);
|
||||||
|
@ -23,6 +23,7 @@ import '../base/utils.dart';
|
|||||||
import '../build_info.dart';
|
import '../build_info.dart';
|
||||||
import '../cache.dart';
|
import '../cache.dart';
|
||||||
import '../convert.dart';
|
import '../convert.dart';
|
||||||
|
import '../dart/language_version.dart';
|
||||||
import '../dart/pub.dart';
|
import '../dart/pub.dart';
|
||||||
import '../devfs.dart';
|
import '../devfs.dart';
|
||||||
import '../device.dart';
|
import '../device.dart';
|
||||||
@ -581,6 +582,10 @@ class _ResidentWebRunner extends ResidentWebRunner {
|
|||||||
}
|
}
|
||||||
|
|
||||||
final String entrypoint = <String>[
|
final String entrypoint = <String>[
|
||||||
|
determineLanguageVersion(
|
||||||
|
globals.fs.file(mainUri),
|
||||||
|
packageConfig[flutterProject.manifest.appName],
|
||||||
|
),
|
||||||
'// Flutter web bootstrap script for $importedEntrypoint.',
|
'// Flutter web bootstrap script for $importedEntrypoint.',
|
||||||
'',
|
'',
|
||||||
"import 'dart:ui' as ui;",
|
"import 'dart:ui' as ui;",
|
||||||
|
68
packages/flutter_tools/lib/src/dart/language_version.dart
Normal file
68
packages/flutter_tools/lib/src/dart/language_version.dart
Normal file
@ -0,0 +1,68 @@
|
|||||||
|
// Copyright 2014 The Flutter Authors. All rights reserved.
|
||||||
|
// Use of this source code is governed by a BSD-style license that can be
|
||||||
|
// found in the LICENSE file.
|
||||||
|
|
||||||
|
import 'package:file/file.dart';
|
||||||
|
import 'package:package_config/package_config.dart';
|
||||||
|
|
||||||
|
final RegExp _languageVersion = RegExp(r'\/\/\s*@dart');
|
||||||
|
final RegExp _declarationEnd = RegExp('(import)|(library)|(part)');
|
||||||
|
const String _blockCommentStart = '/*';
|
||||||
|
const String _blockCommentEnd = '*/';
|
||||||
|
|
||||||
|
/// Attempts to read the language version of a dart [file], returning
|
||||||
|
/// the entire comment.
|
||||||
|
///
|
||||||
|
/// If this is not present, falls back to the language version defined in
|
||||||
|
/// [package]. If [package] is not provided and there is no
|
||||||
|
/// language version header, returns `null`. This does not specifically check
|
||||||
|
/// for language declarations other than library, part, or import.
|
||||||
|
///
|
||||||
|
/// The specification for the language version tag is defined at:
|
||||||
|
/// https://github.com/dart-lang/language/blob/master/accepted/future-releases/language-versioning/feature-specification.md#individual-library-language-version-override
|
||||||
|
String determineLanguageVersion(File file, Package package) {
|
||||||
|
int blockCommentDepth = 0;
|
||||||
|
for (final String line in file.readAsLinesSync()) {
|
||||||
|
final String trimmedLine = line.trim();
|
||||||
|
if (trimmedLine.isEmpty) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
// Check for the start or end of a block comment. Within a block
|
||||||
|
// comment, all language version declarations are ignored. Block
|
||||||
|
// comments can be nested, and the start or end may occur on
|
||||||
|
// the same line. This does not handle the case of invalid
|
||||||
|
// block comment combinations like `*/ /*` since that will cause
|
||||||
|
// a compilation error anyway.
|
||||||
|
bool sawBlockComment = false;
|
||||||
|
final int startMatches = _blockCommentStart.allMatches(trimmedLine).length;
|
||||||
|
final int endMatches = _blockCommentEnd.allMatches(trimmedLine).length;
|
||||||
|
if (startMatches > 0) {
|
||||||
|
blockCommentDepth += startMatches;
|
||||||
|
sawBlockComment = true;
|
||||||
|
}
|
||||||
|
if (endMatches > 0) {
|
||||||
|
blockCommentDepth -= endMatches;
|
||||||
|
sawBlockComment = true;
|
||||||
|
}
|
||||||
|
if (blockCommentDepth != 0 || sawBlockComment) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
// Check for a match with the language version.
|
||||||
|
final Match match = _languageVersion.matchAsPrefix(trimmedLine);
|
||||||
|
if (match != null) {
|
||||||
|
return trimmedLine;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check for a declaration which ends the search for a language
|
||||||
|
// version.
|
||||||
|
if (_declarationEnd.matchAsPrefix(trimmedLine) != null) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// If the language version cannot be found, use the package version.
|
||||||
|
if (package != null) {
|
||||||
|
return '// @dart = ${package.languageVersion}';
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
@ -5,14 +5,14 @@
|
|||||||
import 'dart:async';
|
import 'dart:async';
|
||||||
|
|
||||||
import 'package:meta/meta.dart';
|
import 'package:meta/meta.dart';
|
||||||
|
import 'package:package_config/package_config.dart';
|
||||||
import 'package:stream_channel/stream_channel.dart';
|
import 'package:stream_channel/stream_channel.dart';
|
||||||
import 'package:vm_service/vm_service.dart' as vm_service;
|
|
||||||
|
|
||||||
import 'package:test_api/src/backend/suite_platform.dart'; // ignore: implementation_imports
|
import 'package:test_api/src/backend/suite_platform.dart'; // ignore: implementation_imports
|
||||||
|
import 'package:test_core/src/runner/environment.dart'; // ignore: implementation_imports
|
||||||
|
import 'package:test_core/src/runner/plugin/platform_helpers.dart'; // ignore: implementation_imports
|
||||||
import 'package:test_core/src/runner/runner_suite.dart'; // ignore: implementation_imports
|
import 'package:test_core/src/runner/runner_suite.dart'; // ignore: implementation_imports
|
||||||
import 'package:test_core/src/runner/suite.dart'; // ignore: implementation_imports
|
import 'package:test_core/src/runner/suite.dart'; // ignore: implementation_imports
|
||||||
import 'package:test_core/src/runner/plugin/platform_helpers.dart'; // ignore: implementation_imports
|
import 'package:vm_service/vm_service.dart' as vm_service;
|
||||||
import 'package:test_core/src/runner/environment.dart'; // ignore: implementation_imports
|
|
||||||
|
|
||||||
import '../base/common.dart';
|
import '../base/common.dart';
|
||||||
import '../base/file_system.dart';
|
import '../base/file_system.dart';
|
||||||
@ -20,6 +20,7 @@ import '../base/io.dart';
|
|||||||
import '../build_info.dart';
|
import '../build_info.dart';
|
||||||
import '../compile.dart';
|
import '../compile.dart';
|
||||||
import '../convert.dart';
|
import '../convert.dart';
|
||||||
|
import '../dart/language_version.dart';
|
||||||
import '../dart/package_map.dart';
|
import '../dart/package_map.dart';
|
||||||
import '../globals.dart' as globals;
|
import '../globals.dart' as globals;
|
||||||
import '../project.dart';
|
import '../project.dart';
|
||||||
@ -151,7 +152,7 @@ String generateTestBootstrap({
|
|||||||
@required InternetAddress host,
|
@required InternetAddress host,
|
||||||
File testConfigFile,
|
File testConfigFile,
|
||||||
bool updateGoldens = false,
|
bool updateGoldens = false,
|
||||||
bool nullSafety = false,
|
String languageVersionHeader = '',
|
||||||
}) {
|
}) {
|
||||||
assert(testUrl != null);
|
assert(testUrl != null);
|
||||||
assert(host != null);
|
assert(host != null);
|
||||||
@ -164,6 +165,7 @@ String generateTestBootstrap({
|
|||||||
|
|
||||||
final StringBuffer buffer = StringBuffer();
|
final StringBuffer buffer = StringBuffer();
|
||||||
buffer.write('''
|
buffer.write('''
|
||||||
|
$languageVersionHeader
|
||||||
import 'dart:async';
|
import 'dart:async';
|
||||||
import 'dart:convert'; // ignore: dart_convert_import
|
import 'dart:convert'; // ignore: dart_convert_import
|
||||||
import 'dart:io'; // ignore: dart_io_import
|
import 'dart:io'; // ignore: dart_io_import
|
||||||
@ -181,17 +183,11 @@ import '$testUrl' as test;
|
|||||||
import '${Uri.file(testConfigFile.path)}' as test_config;
|
import '${Uri.file(testConfigFile.path)}' as test_config;
|
||||||
''');
|
''');
|
||||||
}
|
}
|
||||||
// This type is sensitive to the non-nullable experiment.
|
|
||||||
final String beforeLoadTypedef = nullSafety
|
|
||||||
? 'Future<dynamic> Function()?'
|
|
||||||
: 'Future<dynamic> Function()';
|
|
||||||
buffer.write('''
|
buffer.write('''
|
||||||
|
|
||||||
/// Returns a serialized test suite.
|
/// Returns a serialized test suite.
|
||||||
StreamChannel<dynamic> serializeSuite(Function getMain(),
|
StreamChannel<dynamic> serializeSuite(Function getMain()) {
|
||||||
{bool hidePrints = true, $beforeLoadTypedef beforeLoad}) {
|
return RemoteListener.start(getMain);
|
||||||
return RemoteListener.start(getMain,
|
|
||||||
hidePrints: hidePrints, beforeLoad: beforeLoad);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Capture any top-level errors (mostly lazy syntax errors, since other are
|
/// Capture any top-level errors (mostly lazy syntax errors, since other are
|
||||||
@ -402,11 +398,17 @@ class FlutterPlatform extends PlatformPlugin {
|
|||||||
@visibleForTesting
|
@visibleForTesting
|
||||||
Future<HttpServer> bind(InternetAddress host, int port) => HttpServer.bind(host, port);
|
Future<HttpServer> bind(InternetAddress host, int port) => HttpServer.bind(host, port);
|
||||||
|
|
||||||
|
PackageConfig _packageConfig;
|
||||||
|
|
||||||
Future<_AsyncError> _startTest(
|
Future<_AsyncError> _startTest(
|
||||||
String testPath,
|
String testPath,
|
||||||
StreamChannel<dynamic> controller,
|
StreamChannel<dynamic> controller,
|
||||||
int ourTestCount,
|
int ourTestCount,
|
||||||
) async {
|
) async {
|
||||||
|
_packageConfig ??= await loadPackageConfigWithLogging(
|
||||||
|
globals.fs.file(globalPackagesPath),
|
||||||
|
logger: globals.logger,
|
||||||
|
);
|
||||||
globals.printTrace('test $ourTestCount: starting test $testPath');
|
globals.printTrace('test $ourTestCount: starting test $testPath');
|
||||||
|
|
||||||
_AsyncError outOfBandError; // error that we couldn't send to the harness that we need to send via our future
|
_AsyncError outOfBandError; // error that we couldn't send to the harness that we need to send via our future
|
||||||
@ -748,15 +750,20 @@ class FlutterPlatform extends PlatformPlugin {
|
|||||||
Uri testUrl,
|
Uri testUrl,
|
||||||
}) {
|
}) {
|
||||||
assert(testUrl.scheme == 'file');
|
assert(testUrl.scheme == 'file');
|
||||||
|
final File file = globals.fs.file(testUrl);
|
||||||
return generateTestBootstrap(
|
return generateTestBootstrap(
|
||||||
testUrl: testUrl,
|
testUrl: testUrl,
|
||||||
testConfigFile: findTestConfigFile(globals.fs.file(testUrl)),
|
testConfigFile: findTestConfigFile(globals.fs.file(testUrl)),
|
||||||
host: host,
|
host: host,
|
||||||
updateGoldens: updateGoldens,
|
updateGoldens: updateGoldens,
|
||||||
nullSafety: extraFrontEndOptions?.contains('--enable-experiment=non-nullable') ?? false,
|
languageVersionHeader: determineLanguageVersion(
|
||||||
|
file,
|
||||||
|
_packageConfig[flutterProject?.manifest?.appName],
|
||||||
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
File _cachedFontConfig;
|
File _cachedFontConfig;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
|
@ -0,0 +1,228 @@
|
|||||||
|
// Copyright 2014 The Flutter Authors. All rights reserved.
|
||||||
|
// Use of this source code is governed by a BSD-style license that can be
|
||||||
|
// found in the LICENSE file.
|
||||||
|
|
||||||
|
import 'package:file/memory.dart';
|
||||||
|
import 'package:flutter_tools/src/base/file_system.dart';
|
||||||
|
import 'package:flutter_tools/src/dart/language_version.dart';
|
||||||
|
import 'package:package_config/package_config.dart';
|
||||||
|
|
||||||
|
import '../../src/common.dart';
|
||||||
|
|
||||||
|
void main() {
|
||||||
|
testWithoutContext('detects language version in comment', () {
|
||||||
|
final FileSystem fileSystem = MemoryFileSystem.test();
|
||||||
|
final File file = fileSystem.file('example.dart')
|
||||||
|
..writeAsStringSync('''
|
||||||
|
// Some license
|
||||||
|
|
||||||
|
// @dart = 2.9
|
||||||
|
''');
|
||||||
|
|
||||||
|
expect(determineLanguageVersion(file, null), '// @dart = 2.9');
|
||||||
|
});
|
||||||
|
|
||||||
|
testWithoutContext('detects technically invalid language version', () {
|
||||||
|
final FileSystem fileSystem = MemoryFileSystem.test();
|
||||||
|
final File file = fileSystem.file('example.dart')
|
||||||
|
..writeAsStringSync('''
|
||||||
|
// Some license
|
||||||
|
|
||||||
|
// @dart
|
||||||
|
''');
|
||||||
|
|
||||||
|
expect(determineLanguageVersion(file, null), '// @dart');
|
||||||
|
});
|
||||||
|
|
||||||
|
testWithoutContext('detects language version with leading whitespace', () {
|
||||||
|
final FileSystem fileSystem = MemoryFileSystem.test();
|
||||||
|
final File file = fileSystem.file('example.dart')
|
||||||
|
..writeAsStringSync('''
|
||||||
|
// Some license
|
||||||
|
|
||||||
|
// @dart = 2.9
|
||||||
|
''');
|
||||||
|
|
||||||
|
expect(determineLanguageVersion(file, null), '// @dart = 2.9');
|
||||||
|
});
|
||||||
|
|
||||||
|
testWithoutContext('detects language version with tabs', () {
|
||||||
|
final FileSystem fileSystem = MemoryFileSystem.test();
|
||||||
|
final File file = fileSystem.file('example.dart')
|
||||||
|
..writeAsStringSync('''
|
||||||
|
// Some license
|
||||||
|
|
||||||
|
//\t@dart = 2.9
|
||||||
|
''');
|
||||||
|
|
||||||
|
expect(determineLanguageVersion(file, null), '//\t@dart = 2.9');
|
||||||
|
});
|
||||||
|
|
||||||
|
testWithoutContext('detects language version with tons of whitespace', () {
|
||||||
|
final FileSystem fileSystem = MemoryFileSystem.test();
|
||||||
|
final File file = fileSystem.file('example.dart')
|
||||||
|
..writeAsStringSync('''
|
||||||
|
// Some license
|
||||||
|
|
||||||
|
// @dart = 23
|
||||||
|
''');
|
||||||
|
|
||||||
|
expect(determineLanguageVersion(file, null), '// @dart = 23');
|
||||||
|
});
|
||||||
|
|
||||||
|
testWithoutContext('does not detect language version in dartdoc', () {
|
||||||
|
final FileSystem fileSystem = MemoryFileSystem.test();
|
||||||
|
final File file = fileSystem.file('example.dart')
|
||||||
|
..writeAsStringSync('''
|
||||||
|
// Some license
|
||||||
|
|
||||||
|
/// @dart = 2.9
|
||||||
|
''');
|
||||||
|
|
||||||
|
expect(determineLanguageVersion(file, null), null);
|
||||||
|
});
|
||||||
|
|
||||||
|
testWithoutContext('does not detect language version in block comment', () {
|
||||||
|
final FileSystem fileSystem = MemoryFileSystem.test();
|
||||||
|
final File file = fileSystem.file('example.dart')
|
||||||
|
..writeAsStringSync('''
|
||||||
|
// Some license
|
||||||
|
|
||||||
|
/*
|
||||||
|
// @dart = 2.9
|
||||||
|
*/
|
||||||
|
''');
|
||||||
|
|
||||||
|
expect(determineLanguageVersion(file, null), null);
|
||||||
|
});
|
||||||
|
|
||||||
|
testWithoutContext('does not detect language version in nested block comment', () {
|
||||||
|
final FileSystem fileSystem = MemoryFileSystem.test();
|
||||||
|
final File file = fileSystem.file('example.dart')
|
||||||
|
..writeAsStringSync('''
|
||||||
|
// Some license
|
||||||
|
|
||||||
|
/*
|
||||||
|
/*
|
||||||
|
// @dart = 2.9
|
||||||
|
*/
|
||||||
|
*/
|
||||||
|
''');
|
||||||
|
|
||||||
|
expect(determineLanguageVersion(file, null), null);
|
||||||
|
});
|
||||||
|
|
||||||
|
testWithoutContext('detects language version after nested block comment', () {
|
||||||
|
final FileSystem fileSystem = MemoryFileSystem.test();
|
||||||
|
final File file = fileSystem.file('example.dart')
|
||||||
|
..writeAsStringSync('''
|
||||||
|
// Some license
|
||||||
|
|
||||||
|
/* /*
|
||||||
|
*/
|
||||||
|
*/
|
||||||
|
// @dart = 2.9
|
||||||
|
''');
|
||||||
|
|
||||||
|
expect(determineLanguageVersion(file, null), '// @dart = 2.9');
|
||||||
|
});
|
||||||
|
|
||||||
|
testWithoutContext('does not crash with unbalanced opening block comments', () {
|
||||||
|
final FileSystem fileSystem = MemoryFileSystem.test();
|
||||||
|
final File file = fileSystem.file('example.dart')
|
||||||
|
..writeAsStringSync('''
|
||||||
|
// Some license
|
||||||
|
|
||||||
|
/*
|
||||||
|
/*
|
||||||
|
*/
|
||||||
|
// @dart = 2.9
|
||||||
|
''');
|
||||||
|
|
||||||
|
expect(determineLanguageVersion(file, null), null);
|
||||||
|
});
|
||||||
|
|
||||||
|
testWithoutContext('does not crash with unbalanced closing block comments', () {
|
||||||
|
final FileSystem fileSystem = MemoryFileSystem.test();
|
||||||
|
final File file = fileSystem.file('example.dart')
|
||||||
|
..writeAsStringSync('''
|
||||||
|
// Some license
|
||||||
|
|
||||||
|
/*
|
||||||
|
*/
|
||||||
|
*/
|
||||||
|
// @dart = 2.9
|
||||||
|
''');
|
||||||
|
|
||||||
|
expect(determineLanguageVersion(file, null), null);
|
||||||
|
});
|
||||||
|
|
||||||
|
testWithoutContext('does not detect language version in single line block comment', () {
|
||||||
|
final FileSystem fileSystem = MemoryFileSystem.test();
|
||||||
|
final File file = fileSystem.file('example.dart')
|
||||||
|
..writeAsStringSync('''
|
||||||
|
// Some license
|
||||||
|
|
||||||
|
/* // @dart = 2.9 */
|
||||||
|
''');
|
||||||
|
|
||||||
|
expect(determineLanguageVersion(file, null), null);
|
||||||
|
});
|
||||||
|
|
||||||
|
testWithoutContext('does not detect language version after import declaration', () {
|
||||||
|
final FileSystem fileSystem = MemoryFileSystem.test();
|
||||||
|
final File file = fileSystem.file('example.dart')
|
||||||
|
..writeAsStringSync('''
|
||||||
|
// Some license
|
||||||
|
|
||||||
|
import 'dart:ui' as ui;
|
||||||
|
|
||||||
|
// @dart = 2.9
|
||||||
|
''');
|
||||||
|
|
||||||
|
expect(determineLanguageVersion(file, null), null);
|
||||||
|
});
|
||||||
|
|
||||||
|
testWithoutContext('does not detect language version after part declaration', () {
|
||||||
|
final FileSystem fileSystem = MemoryFileSystem.test();
|
||||||
|
final File file = fileSystem.file('example.dart')
|
||||||
|
..writeAsStringSync('''
|
||||||
|
// Some license
|
||||||
|
|
||||||
|
part of 'foo.dart';
|
||||||
|
|
||||||
|
// @dart = 2.9
|
||||||
|
''');
|
||||||
|
|
||||||
|
expect(determineLanguageVersion(file, null), null);
|
||||||
|
});
|
||||||
|
|
||||||
|
testWithoutContext('does not detect language version after library declaration', () {
|
||||||
|
final FileSystem fileSystem = MemoryFileSystem.test();
|
||||||
|
final File file = fileSystem.file('example.dart')
|
||||||
|
..writeAsStringSync('''
|
||||||
|
// Some license
|
||||||
|
|
||||||
|
library funstuff;
|
||||||
|
|
||||||
|
// @dart = 2.9
|
||||||
|
''');
|
||||||
|
|
||||||
|
expect(determineLanguageVersion(file, null), null);
|
||||||
|
});
|
||||||
|
|
||||||
|
testWithoutContext('looks up language version from package if not found in file', () {
|
||||||
|
final FileSystem fileSystem = MemoryFileSystem.test();
|
||||||
|
final File file = fileSystem.file('example.dart')
|
||||||
|
..writeAsStringSync('''
|
||||||
|
// Some license
|
||||||
|
''');
|
||||||
|
final Package package = Package(
|
||||||
|
'foo',
|
||||||
|
Uri.parse('file://foo/'),
|
||||||
|
languageVersion: LanguageVersion(2, 7),
|
||||||
|
);
|
||||||
|
|
||||||
|
expect(determineLanguageVersion(file, package), '// @dart = 2.7');
|
||||||
|
});
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user