[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 {
|
||||
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'];
|
||||
|
||||
Future<void> runWidgets() async {
|
||||
|
@ -2,11 +2,9 @@
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
// @dart=2.9
|
||||
// @dart=2.8
|
||||
import 'package:flutter_test/flutter_test.dart';
|
||||
|
||||
String? x;
|
||||
|
||||
void main() {
|
||||
testWidgets('trivial', (WidgetTester tester) async {
|
||||
expect(true, true);
|
||||
|
@ -23,6 +23,7 @@ import '../base/utils.dart';
|
||||
import '../build_info.dart';
|
||||
import '../cache.dart';
|
||||
import '../convert.dart';
|
||||
import '../dart/language_version.dart';
|
||||
import '../dart/pub.dart';
|
||||
import '../devfs.dart';
|
||||
import '../device.dart';
|
||||
@ -581,6 +582,10 @@ class _ResidentWebRunner extends ResidentWebRunner {
|
||||
}
|
||||
|
||||
final String entrypoint = <String>[
|
||||
determineLanguageVersion(
|
||||
globals.fs.file(mainUri),
|
||||
packageConfig[flutterProject.manifest.appName],
|
||||
),
|
||||
'// Flutter web bootstrap script for $importedEntrypoint.',
|
||||
'',
|
||||
"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 'package:meta/meta.dart';
|
||||
import 'package:package_config/package_config.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_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/suite.dart'; // ignore: implementation_imports
|
||||
import 'package:test_core/src/runner/plugin/platform_helpers.dart'; // ignore: implementation_imports
|
||||
import 'package:test_core/src/runner/environment.dart'; // ignore: implementation_imports
|
||||
import 'package:vm_service/vm_service.dart' as vm_service;
|
||||
|
||||
import '../base/common.dart';
|
||||
import '../base/file_system.dart';
|
||||
@ -20,6 +20,7 @@ import '../base/io.dart';
|
||||
import '../build_info.dart';
|
||||
import '../compile.dart';
|
||||
import '../convert.dart';
|
||||
import '../dart/language_version.dart';
|
||||
import '../dart/package_map.dart';
|
||||
import '../globals.dart' as globals;
|
||||
import '../project.dart';
|
||||
@ -151,7 +152,7 @@ String generateTestBootstrap({
|
||||
@required InternetAddress host,
|
||||
File testConfigFile,
|
||||
bool updateGoldens = false,
|
||||
bool nullSafety = false,
|
||||
String languageVersionHeader = '',
|
||||
}) {
|
||||
assert(testUrl != null);
|
||||
assert(host != null);
|
||||
@ -164,6 +165,7 @@ String generateTestBootstrap({
|
||||
|
||||
final StringBuffer buffer = StringBuffer();
|
||||
buffer.write('''
|
||||
$languageVersionHeader
|
||||
import 'dart:async';
|
||||
import 'dart:convert'; // ignore: dart_convert_import
|
||||
import 'dart:io'; // ignore: dart_io_import
|
||||
@ -181,17 +183,11 @@ import '$testUrl' as test;
|
||||
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('''
|
||||
|
||||
/// Returns a serialized test suite.
|
||||
StreamChannel<dynamic> serializeSuite(Function getMain(),
|
||||
{bool hidePrints = true, $beforeLoadTypedef beforeLoad}) {
|
||||
return RemoteListener.start(getMain,
|
||||
hidePrints: hidePrints, beforeLoad: beforeLoad);
|
||||
StreamChannel<dynamic> serializeSuite(Function getMain()) {
|
||||
return RemoteListener.start(getMain);
|
||||
}
|
||||
|
||||
/// Capture any top-level errors (mostly lazy syntax errors, since other are
|
||||
@ -402,11 +398,17 @@ class FlutterPlatform extends PlatformPlugin {
|
||||
@visibleForTesting
|
||||
Future<HttpServer> bind(InternetAddress host, int port) => HttpServer.bind(host, port);
|
||||
|
||||
PackageConfig _packageConfig;
|
||||
|
||||
Future<_AsyncError> _startTest(
|
||||
String testPath,
|
||||
StreamChannel<dynamic> controller,
|
||||
int ourTestCount,
|
||||
) async {
|
||||
_packageConfig ??= await loadPackageConfigWithLogging(
|
||||
globals.fs.file(globalPackagesPath),
|
||||
logger: globals.logger,
|
||||
);
|
||||
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
|
||||
@ -748,15 +750,20 @@ class FlutterPlatform extends PlatformPlugin {
|
||||
Uri testUrl,
|
||||
}) {
|
||||
assert(testUrl.scheme == 'file');
|
||||
final File file = globals.fs.file(testUrl);
|
||||
return generateTestBootstrap(
|
||||
testUrl: testUrl,
|
||||
testConfigFile: findTestConfigFile(globals.fs.file(testUrl)),
|
||||
host: host,
|
||||
updateGoldens: updateGoldens,
|
||||
nullSafety: extraFrontEndOptions?.contains('--enable-experiment=non-nullable') ?? false,
|
||||
languageVersionHeader: determineLanguageVersion(
|
||||
file,
|
||||
_packageConfig[flutterProject?.manifest?.appName],
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
File _cachedFontConfig;
|
||||
|
||||
@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