From 1ab38789964ea60e937aba901a044addeca519ab Mon Sep 17 00:00:00 2001 From: Jonah Williams Date: Mon, 27 Apr 2020 14:47:43 -0700 Subject: [PATCH] [flutter_tools] support --enable-experiment in flutter test (#55564) Support --enable-experiment in flutter test (for flutter_tester). Required minor change for null safety. --- dev/bots/test.dart | 3 +++ .../non_nullable/analysis_options.yaml | 1 + .../non_nullable/test/test_test.dart | 14 ++++++++++ .../flutter_tools/bin/fuchsia_tester.dart | 1 + .../flutter_tools/lib/src/commands/test.dart | 3 +++ .../lib/src/test/flutter_platform.dart | 14 ++++++++-- .../lib/src/test/flutter_web_platform.dart | 2 +- .../flutter_tools/lib/src/test/runner.dart | 3 +++ .../lib/src/test/test_compiler.dart | 3 +++ .../commands.shard/hermetic/test_test.dart | 1 + .../general.shard/flutter_platform_test.dart | 26 ++++++++++++++++--- .../general.shard/test_compiler_test.dart | 2 +- 12 files changed, 65 insertions(+), 8 deletions(-) create mode 100644 dev/integration_tests/non_nullable/test/test_test.dart diff --git a/dev/bots/test.dart b/dev/bots/test.dart index a640536f15..3847e20380 100644 --- a/dev/bots/test.dart +++ b/dev/bots/test.dart @@ -480,6 +480,9 @@ Future _runFrameworkTests() async { await _runFlutterTest(path.join(flutterRoot, 'packages', 'flutter_localizations'), tableData: bigqueryApi?.tabledata); await _runFlutterTest(path.join(flutterRoot, 'packages', 'flutter_test'), tableData: bigqueryApi?.tabledata); await _runFlutterTest(path.join(flutterRoot, 'packages', 'fuchsia_remote_debug_protocol'), tableData: bigqueryApi?.tabledata); + await _runFlutterTest(path.join(flutterRoot, 'dev', 'integration_tests', 'non_nullable'), + options: ['--enable-experiment=non-nullable'], + ); await _runFlutterTest( path.join(flutterRoot, 'dev', 'tracing_tests'), options: ['--enable-vmservice'], diff --git a/dev/integration_tests/non_nullable/analysis_options.yaml b/dev/integration_tests/non_nullable/analysis_options.yaml index 2388a77af4..6bfd4556b2 100644 --- a/dev/integration_tests/non_nullable/analysis_options.yaml +++ b/dev/integration_tests/non_nullable/analysis_options.yaml @@ -3,3 +3,4 @@ analyzer: exclude: - lib/main.dart + - test/test_test.dart diff --git a/dev/integration_tests/non_nullable/test/test_test.dart b/dev/integration_tests/non_nullable/test/test_test.dart new file mode 100644 index 0000000000..1a89396455 --- /dev/null +++ b/dev/integration_tests/non_nullable/test/test_test.dart @@ -0,0 +1,14 @@ +// 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. + +// @dart=2.9 +import 'package:flutter_test/flutter_test.dart'; + +String? x; + +void main() { + testWidgets('trivial', (WidgetTester tester) async { + expect(true, true); + }); +} diff --git a/packages/flutter_tools/bin/fuchsia_tester.dart b/packages/flutter_tools/bin/fuchsia_tester.dart index fb032bfb7f..53fecaed23 100644 --- a/packages/flutter_tools/bin/fuchsia_tester.dart +++ b/packages/flutter_tools/bin/fuchsia_tester.dart @@ -155,6 +155,7 @@ Future run(List args) async { concurrency: math.max(1, globals.platform.numberOfProcessors - 2), icudtlPath: globals.fs.path.absolute(argResults[_kOptionIcudtl] as String), coverageDirectory: coverageDirectory, + dartExperiments: [], ); if (collector != null) { diff --git a/packages/flutter_tools/lib/src/commands/test.dart b/packages/flutter_tools/lib/src/commands/test.dart index ea5ee53b9f..31642bf654 100644 --- a/packages/flutter_tools/lib/src/commands/test.dart +++ b/packages/flutter_tools/lib/src/commands/test.dart @@ -129,6 +129,7 @@ class TestCommand extends FlutterCommand { 'The vmservice will be enabled no matter what in those cases.' ); usesTrackWidgetCreation(verboseHelp: verboseHelp); + addEnableExperimentation(hide: !verboseHelp); } /// The interface for starting and configuring the tester. @@ -171,6 +172,7 @@ class TestCommand extends FlutterCommand { final String tags = stringArg('tags'); final String excludeTags = stringArg('exclude-tags'); final FlutterProject flutterProject = FlutterProject.current(); + final List dartExperiments = stringsArg(FlutterOptions.kEnableExperiment); if (buildTestAssets && flutterProject.manifest.assets.isNotEmpty) { await _buildTestAsset(); @@ -276,6 +278,7 @@ class TestCommand extends FlutterCommand { flutterProject: flutterProject, web: stringArg('platform') == 'chrome', randomSeed: stringArg('test-randomize-ordering-seed'), + dartExperiments: dartExperiments, ); if (collector != null) { diff --git a/packages/flutter_tools/lib/src/test/flutter_platform.dart b/packages/flutter_tools/lib/src/test/flutter_platform.dart index a27e406abd..c612b2a990 100644 --- a/packages/flutter_tools/lib/src/test/flutter_platform.dart +++ b/packages/flutter_tools/lib/src/test/flutter_platform.dart @@ -87,6 +87,7 @@ FlutterPlatform installHook({ FlutterProject flutterProject, String icudtlPath, PlatformPluginRegistration platformPluginRegistration, + @required List dartExperiments, }) { assert(testWrapper != null); assert(enableObservatory || (!startPaused && observatoryPort == null)); @@ -119,6 +120,7 @@ FlutterPlatform installHook({ projectRootDirectory: projectRootDirectory, flutterProject: flutterProject, icudtlPath: icudtlPath, + dartExperiments: dartExperiments, ); platformPluginRegistration(platform); return platform; @@ -144,6 +146,7 @@ String generateTestBootstrap({ @required InternetAddress host, File testConfigFile, bool updateGoldens = false, + @required bool nullSafety, }) { assert(testUrl != null); assert(host != null); @@ -173,11 +176,15 @@ 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 Function()?' + : 'Future Function()'; buffer.write(''' /// Returns a serialized test suite. StreamChannel serializeSuite(Function getMain(), - {bool hidePrints = true, Future beforeLoad()}) { + {bool hidePrints = true, $beforeLoadTypedef beforeLoad}) { return RemoteListener.start(getMain, hidePrints: hidePrints, beforeLoad: beforeLoad); } @@ -259,6 +266,7 @@ class FlutterPlatform extends PlatformPlugin { this.projectRootDirectory, this.flutterProject, this.icudtlPath, + @required this.dartExperiments, }) : assert(shellPath != null); final String shellPath; @@ -279,6 +287,7 @@ class FlutterPlatform extends PlatformPlugin { final Uri projectRootDirectory; final FlutterProject flutterProject; final String icudtlPath; + final List dartExperiments; Directory fontsDirectory; @@ -447,7 +456,7 @@ class FlutterPlatform extends PlatformPlugin { if (precompiledDillPath == null && precompiledDillFiles == null) { // Lazily instantiate compiler so it is built only if it is actually used. - compiler ??= TestCompiler(buildMode, trackWidgetCreation, flutterProject); + compiler ??= TestCompiler(buildMode, trackWidgetCreation, flutterProject, dartExperiments); mainDart = await compiler.compile(globals.fs.file(mainDart).uri); if (mainDart == null) { @@ -739,6 +748,7 @@ class FlutterPlatform extends PlatformPlugin { testConfigFile: findTestConfigFile(globals.fs.file(testUrl)), host: host, updateGoldens: updateGoldens, + nullSafety: dartExperiments.contains('non-nullable'), ); } diff --git a/packages/flutter_tools/lib/src/test/flutter_web_platform.dart b/packages/flutter_tools/lib/src/test/flutter_web_platform.dart index 9ba5dad731..d8ff9851ba 100644 --- a/packages/flutter_tools/lib/src/test/flutter_web_platform.dart +++ b/packages/flutter_tools/lib/src/test/flutter_web_platform.dart @@ -75,7 +75,7 @@ class FlutterWebPlatform extends PlatformPlugin { _testGoldenComparator = TestGoldenComparator( shellPath, - () => TestCompiler(BuildMode.debug, false, flutterProject), + () => TestCompiler(BuildMode.debug, false, flutterProject, []), ); } diff --git a/packages/flutter_tools/lib/src/test/runner.dart b/packages/flutter_tools/lib/src/test/runner.dart index 8df2eff329..cd7a6b4e42 100644 --- a/packages/flutter_tools/lib/src/test/runner.dart +++ b/packages/flutter_tools/lib/src/test/runner.dart @@ -51,6 +51,7 @@ abstract class FlutterTestRunner { Directory coverageDirectory, bool web = false, String randomSeed, + @required List dartExperiments, }); } @@ -84,6 +85,7 @@ class _FlutterTestRunnerImpl implements FlutterTestRunner { Directory coverageDirectory, bool web = false, String randomSeed, + @required List dartExperiments, }) async { // Configure package:test to use the Flutter engine for child processes. final String shellPath = globals.artifacts.getArtifactPath(Artifact.flutterTester); @@ -175,6 +177,7 @@ class _FlutterTestRunnerImpl implements FlutterTestRunner { projectRootDirectory: globals.fs.currentDirectory.uri, flutterProject: flutterProject, icudtlPath: icudtlPath, + dartExperiments: dartExperiments, ); // Make the global packages path absolute. diff --git a/packages/flutter_tools/lib/src/test/test_compiler.dart b/packages/flutter_tools/lib/src/test/test_compiler.dart index c6c5bc7dcb..2cac29073c 100644 --- a/packages/flutter_tools/lib/src/test/test_compiler.dart +++ b/packages/flutter_tools/lib/src/test/test_compiler.dart @@ -42,6 +42,7 @@ class TestCompiler { this.buildMode, this.trackWidgetCreation, this.flutterProject, + this.dartExperiments, ) : testFilePath = getKernelPathForTransformerOptions( globals.fs.path.join(flutterProject.directory.path, getBuildDirectory(), 'testfile.dill'), trackWidgetCreation: trackWidgetCreation, @@ -65,6 +66,7 @@ class TestCompiler { final BuildMode buildMode; final bool trackWidgetCreation; final String testFilePath; + final List dartExperiments; ResidentCompiler compiler; @@ -104,6 +106,7 @@ class TestCompiler { unsafePackageSerialization: false, dartDefines: const [], packagesPath: globalPackagesPath, + experimentalFlags: dartExperiments, ); if (flutterProject.hasBuilders) { return CodeGeneratingResidentCompiler.create( diff --git a/packages/flutter_tools/test/commands.shard/hermetic/test_test.dart b/packages/flutter_tools/test/commands.shard/hermetic/test_test.dart index a8830a058a..3a4972b806 100644 --- a/packages/flutter_tools/test/commands.shard/hermetic/test_test.dart +++ b/packages/flutter_tools/test/commands.shard/hermetic/test_test.dart @@ -184,6 +184,7 @@ class FakeFlutterTestRunner implements FlutterTestRunner { Directory coverageDirectory, bool web = false, String randomSeed, + @override List dartExperiments, }) async { lastEnableObservatoryValue = enableObservatory; return exitCode; diff --git a/packages/flutter_tools/test/general.shard/flutter_platform_test.dart b/packages/flutter_tools/test/general.shard/flutter_platform_test.dart index 6a0a98bd5e..a5a6dc6788 100644 --- a/packages/flutter_tools/test/general.shard/flutter_platform_test.dart +++ b/packages/flutter_tools/test/general.shard/flutter_platform_test.dart @@ -17,15 +17,29 @@ import '../src/context.dart'; void main() { group('FlutterPlatform', () { - testUsingContext('ensureConfiguration throws an error if an explicitObservatoryPort is specified and more than one test file', () async { - final FlutterPlatform flutterPlatform = FlutterPlatform(buildMode: BuildMode.debug, shellPath: '/', explicitObservatoryPort: 1234); + testUsingContext('ensureConfiguration throws an error if an ' + 'explicitObservatoryPort is specified and more than one test file', () async { + final FlutterPlatform flutterPlatform = FlutterPlatform( + buildMode: BuildMode.debug, + shellPath: '/', + explicitObservatoryPort: 1234, + dartExperiments: [], + ); flutterPlatform.loadChannel('test1.dart', MockSuitePlatform()); + expect(() => flutterPlatform.loadChannel('test2.dart', MockSuitePlatform()), throwsToolExit()); }); - testUsingContext('ensureConfiguration throws an error if a precompiled entrypoint is specified and more that one test file', () { - final FlutterPlatform flutterPlatform = FlutterPlatform(buildMode: BuildMode.debug, shellPath: '/', precompiledDillPath: 'example.dill'); + testUsingContext('ensureConfiguration throws an error if a precompiled ' + 'entrypoint is specified and more that one test file', () { + final FlutterPlatform flutterPlatform = FlutterPlatform( + buildMode: BuildMode.debug, + shellPath: '/', + precompiledDillPath: 'example.dill', + dartExperiments: [], + ); flutterPlatform.loadChannel('test1.dart', MockSuitePlatform()); + expect(() => flutterPlatform.loadChannel('test2.dart', MockSuitePlatform()), throwsToolExit()); }); @@ -99,6 +113,7 @@ void main() { shellPath: 'abc', enableObservatory: false, startPaused: true, + dartExperiments: [], ), throwsAssertionError); expect(() => installHook( @@ -107,6 +122,7 @@ void main() { enableObservatory: false, startPaused: false, observatoryPort: 123, + dartExperiments: [], ), throwsAssertionError); FlutterPlatform capturedPlatform; @@ -127,6 +143,7 @@ void main() { observatoryPort: 200, serverType: InternetAddressType.IPv6, icudtlPath: 'ghi', + dartExperiments: [], platformPluginRegistration: (FlutterPlatform platform) { capturedPlatform = platform; }); @@ -175,6 +192,7 @@ class TestFlutterPlatform extends FlutterPlatform { startPaused: false, enableObservatory: false, buildTestAssets: false, + dartExperiments: [], ); @override diff --git a/packages/flutter_tools/test/general.shard/test_compiler_test.dart b/packages/flutter_tools/test/general.shard/test_compiler_test.dart index 4a27324c44..3cf2507f0c 100644 --- a/packages/flutter_tools/test/general.shard/test_compiler_test.dart +++ b/packages/flutter_tools/test/general.shard/test_compiler_test.dart @@ -96,7 +96,7 @@ class FakeTestCompiler extends TestCompiler { bool trackWidgetCreation, FlutterProject flutterProject, this.residentCompiler, - ) : super(buildMode, trackWidgetCreation, flutterProject); + ) : super(buildMode, trackWidgetCreation, flutterProject, []); final MockResidentCompiler residentCompiler;