diff --git a/packages/flutter_tools/lib/executable.dart b/packages/flutter_tools/lib/executable.dart index 8d3517bae9b..2515f94425f 100644 --- a/packages/flutter_tools/lib/executable.dart +++ b/packages/flutter_tools/lib/executable.dart @@ -93,7 +93,7 @@ Future main(List args) async { DevicesCommand(), DoctorCommand(verbose: verbose), DowngradeCommand(), - DriveCommand(), + DriveCommand(verboseHelp: verboseHelp), EmulatorsCommand(), FormatCommand(), GenerateCommand(), diff --git a/packages/flutter_tools/lib/src/commands/drive.dart b/packages/flutter_tools/lib/src/commands/drive.dart index b086b0e03c4..6e2b638cf2c 100644 --- a/packages/flutter_tools/lib/src/commands/drive.dart +++ b/packages/flutter_tools/lib/src/commands/drive.dart @@ -50,9 +50,11 @@ import 'run.dart'; /// successful the exit code will be `0`. Otherwise, you will see a non-zero /// exit code. class DriveCommand extends RunCommandBase { - DriveCommand() { + DriveCommand({ + bool verboseHelp = false, + }) { requiresPubspecYaml(); - + addEnableExperimentation(hide: !verboseHelp); argParser ..addFlag('keep-app-running', defaultsTo: null, @@ -322,7 +324,18 @@ $ex } try { - await testRunner([testFile], environment); + await testRunner( + [ + if (buildInfo.dartExperiments.isNotEmpty) + '--enable-experiment=${buildInfo.dartExperiments.join(',')}', + if (buildInfo.nullSafetyMode == NullSafetyMode.sound) + '--sound-null-safety', + if (buildInfo.nullSafetyMode == NullSafetyMode.unsound) + '--no-sound-null-safety', + testFile, + ], + environment, + ); } on Exception catch (error, stackTrace) { if (error is ToolExit) { rethrow; diff --git a/packages/flutter_tools/test/commands.shard/hermetic/drive_test.dart b/packages/flutter_tools/test/commands.shard/hermetic/drive_test.dart index e0242ad7e1c..d3689c04d35 100644 --- a/packages/flutter_tools/test/commands.shard/hermetic/drive_test.dart +++ b/packages/flutter_tools/test/commands.shard/hermetic/drive_test.dart @@ -205,7 +205,7 @@ void main() { return LaunchResult.succeeded(); }); testRunner = expectAsync2((List testArgs, Map environment) async { - expect(testArgs, [testFile]); + expect(testArgs, ['--no-sound-null-safety', testFile]); // VM_SERVICE_URL is not set by drive command arguments expect(environment, { 'VM_SERVICE_URL': 'null', @@ -273,6 +273,90 @@ void main() { ProcessManager: () => FakeProcessManager.any(), }); + testUsingContext('enable experiment', () async { + final MockAndroidDevice mockDevice = MockAndroidDevice(); + applyDdsMocks(mockDevice); + testDeviceManager.addDevice(mockDevice); + + final String testApp = globals.fs.path.join(tempDir.path, 'test', 'e2e.dart'); + final String testFile = globals.fs.path.join(tempDir.path, 'test_driver', 'e2e_test.dart'); + + appStarter = expectAsync2((DriveCommand command, Uri webUri) async { + return LaunchResult.succeeded(); + }); + testRunner = expectAsync2((List testArgs, Map environment) async { + expect( + testArgs, + [ + '--enable-experiment=experiment1,experiment2', + '--no-sound-null-safety', + testFile, + ] + ); + }); + appStopper = expectAsync1((DriveCommand command) async { + return true; + }); + + final MemoryFileSystem memFs = fs; + await memFs.file(testApp).writeAsString('main() {}'); + await memFs.file(testFile).writeAsString('main() {}'); + + final List args = [ + 'drive', + '--target=$testApp', + '--no-pub', + '--enable-experiment=experiment1', + '--enable-experiment=experiment2', + ]; + await createTestCommandRunner(command).run(args); + expect(testLogger.errorText, isEmpty); + }, overrides: { + FileSystem: () => fs, + ProcessManager: () => FakeProcessManager.any(), + }); + + testUsingContext('sound null safety', () async { + final MockAndroidDevice mockDevice = MockAndroidDevice(); + applyDdsMocks(mockDevice); + testDeviceManager.addDevice(mockDevice); + + final String testApp = globals.fs.path.join(tempDir.path, 'test', 'e2e.dart'); + final String testFile = globals.fs.path.join(tempDir.path, 'test_driver', 'e2e_test.dart'); + + appStarter = expectAsync2((DriveCommand command, Uri webUri) async { + return LaunchResult.succeeded(); + }); + testRunner = expectAsync2((List testArgs, Map environment) async { + expect( + testArgs, + [ + '--sound-null-safety', + testFile, + ] + ); + }); + appStopper = expectAsync1((DriveCommand command) async { + return true; + }); + + final MemoryFileSystem memFs = fs; + await memFs.file(testApp).writeAsString('main() {}'); + await memFs.file(testFile).writeAsString('main() {}'); + + final List args = [ + 'drive', + '--target=$testApp', + '--no-pub', + '--sound-null-safety', + ]; + await createTestCommandRunner(command).run(args); + expect(testLogger.errorText, isEmpty); + }, overrides: { + FileSystem: () => fs, + ProcessManager: () => FakeProcessManager.any(), + }); + group('findTargetDevice', () { testUsingContext('uses specified device', () async { testDeviceManager.specifiedDeviceId = '123';