diff --git a/packages/flutter_tools/bin/fuchsia_tester.dart b/packages/flutter_tools/bin/fuchsia_tester.dart index c0017d25a5..49392494a8 100644 --- a/packages/flutter_tools/bin/fuchsia_tester.dart +++ b/packages/flutter_tools/bin/fuchsia_tester.dart @@ -16,6 +16,7 @@ import 'package:flutter_tools/src/cache.dart'; import 'package:flutter_tools/src/context_runner.dart'; import 'package:flutter_tools/src/device.dart'; import 'package:flutter_tools/src/globals.dart' as globals; +import 'package:flutter_tools/src/isolated/native_assets/test/native_assets.dart'; import 'package:flutter_tools/src/project.dart'; import 'package:flutter_tools/src/reporting/reporting.dart'; import 'package:flutter_tools/src/test/coverage_collector.dart'; @@ -153,6 +154,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, + nativeAssetsBuilder: const TestCompilerNativeAssetsBuilderImpl(), ); if (collector != null) { diff --git a/packages/flutter_tools/lib/executable.dart b/packages/flutter_tools/lib/executable.dart index a1894b0f7c..8e7aef0585 100644 --- a/packages/flutter_tools/lib/executable.dart +++ b/packages/flutter_tools/lib/executable.dart @@ -50,6 +50,8 @@ import 'src/globals.dart' as globals; // Files in `isolated` are intentionally excluded from google3 tooling. import 'src/isolated/build_targets.dart'; import 'src/isolated/mustache_template.dart'; +import 'src/isolated/native_assets/native_assets.dart'; +import 'src/isolated/native_assets/test/native_assets.dart'; import 'src/isolated/resident_web_runner.dart'; import 'src/pre_run_validator.dart'; import 'src/project_validator.dart'; @@ -177,6 +179,7 @@ List generateCommands({ platform: globals.platform, processInfo: globals.processInfo, fileSystem: globals.fs, + nativeAssetsBuilder: const HotRunnerNativeAssetsBuilderImpl(), ), BuildCommand( artifacts: globals.artifacts!, @@ -237,10 +240,17 @@ List generateCommands({ platform: globals.platform, featureFlags: featureFlags, ), - RunCommand(verboseHelp: verboseHelp), + RunCommand( + verboseHelp: verboseHelp, + nativeAssetsBuilder: const HotRunnerNativeAssetsBuilderImpl(), + ), ScreenshotCommand(fs: globals.fs), ShellCompletionCommand(), - TestCommand(verboseHelp: verboseHelp, verbose: verbose), + TestCommand( + verboseHelp: verboseHelp, + verbose: verbose, + nativeAssetsBuilder: const TestCompilerNativeAssetsBuilderImpl(), + ), UpgradeCommand(verboseHelp: verboseHelp), SymbolizeCommand( stdio: globals.stdio, diff --git a/packages/flutter_tools/lib/src/build_system/targets/native_assets.dart b/packages/flutter_tools/lib/src/build_system/targets/native_assets.dart index 45e999fd5c..967546e14a 100644 --- a/packages/flutter_tools/lib/src/build_system/targets/native_assets.dart +++ b/packages/flutter_tools/lib/src/build_system/targets/native_assets.dart @@ -7,18 +7,18 @@ import 'package:native_assets_cli/native_assets_cli_internal.dart' show Asset; import 'package:package_config/package_config_types.dart'; import '../../android/gradle_utils.dart'; -import '../../android/native_assets.dart'; import '../../base/common.dart'; import '../../base/file_system.dart'; import '../../base/platform.dart'; import '../../build_info.dart'; import '../../dart/package_map.dart'; -import '../../ios/native_assets.dart'; -import '../../linux/native_assets.dart'; -import '../../macos/native_assets.dart'; +import '../../isolated/native_assets/android/native_assets.dart'; +import '../../isolated/native_assets/ios/native_assets.dart'; +import '../../isolated/native_assets/linux/native_assets.dart'; +import '../../isolated/native_assets/macos/native_assets.dart'; +import '../../isolated/native_assets/native_assets.dart'; +import '../../isolated/native_assets/windows/native_assets.dart'; import '../../macos/xcode.dart'; -import '../../native_assets.dart'; -import '../../windows/native_assets.dart'; import '../build_system.dart'; import '../depfile.dart'; import '../exceptions.dart'; diff --git a/packages/flutter_tools/lib/src/commands/attach.dart b/packages/flutter_tools/lib/src/commands/attach.dart index c5a875db79..9ff56ebde2 100644 --- a/packages/flutter_tools/lib/src/commands/attach.dart +++ b/packages/flutter_tools/lib/src/commands/attach.dart @@ -71,6 +71,7 @@ class AttachCommand extends FlutterCommand { required Platform platform, required ProcessInfo processInfo, required FileSystem fileSystem, + HotRunnerNativeAssetsBuilder? nativeAssetsBuilder, }) : _hotRunnerFactory = hotRunnerFactory ?? HotRunnerFactory(), _stdio = stdio, _logger = logger, @@ -78,7 +79,8 @@ class AttachCommand extends FlutterCommand { _signals = signals, _platform = platform, _processInfo = processInfo, - _fileSystem = fileSystem { + _fileSystem = fileSystem, + _nativeAssetsBuilder = nativeAssetsBuilder { addBuildModeFlags(verboseHelp: verboseHelp, defaultToRelease: false, excludeRelease: true); usesTargetOption(); usesPortOptions(verboseHelp: verboseHelp); @@ -150,6 +152,7 @@ class AttachCommand extends FlutterCommand { final Platform _platform; final ProcessInfo _processInfo; final FileSystem _fileSystem; + final HotRunnerNativeAssetsBuilder? _nativeAssetsBuilder; @override final String name = 'attach'; @@ -416,6 +419,7 @@ known, it can be explicitly provided to attach via the command-line, e.g. device: device, flutterProject: flutterProject, usesIpv6: usesIpv6, + nativeAssetsBuilder: _nativeAssetsBuilder, ); late AppInstance app; try { @@ -449,6 +453,7 @@ known, it can be explicitly provided to attach via the command-line, e.g. device: device, flutterProject: flutterProject, usesIpv6: usesIpv6, + nativeAssetsBuilder: _nativeAssetsBuilder, ); final Completer onAppStart = Completer.sync(); TerminalHandler? terminalHandler; @@ -505,6 +510,7 @@ known, it can be explicitly provided to attach via the command-line, e.g. required Device device, required FlutterProject flutterProject, required bool usesIpv6, + required HotRunnerNativeAssetsBuilder? nativeAssetsBuilder, }) async { final BuildInfo buildInfo = await getBuildInfo(); @@ -539,6 +545,7 @@ known, it can be explicitly provided to attach via the command-line, e.g. ipv6: usesIpv6, flutterProject: flutterProject, nativeAssetsYamlFile: stringArg(FlutterOptions.kNativeAssetsYamlFile), + nativeAssetsBuilder: _nativeAssetsBuilder, analytics: analytics, ) : ColdRunner( @@ -573,6 +580,7 @@ class HotRunnerFactory { bool ipv6 = false, FlutterProject? flutterProject, String? nativeAssetsYamlFile, + required HotRunnerNativeAssetsBuilder? nativeAssetsBuilder, required Analytics analytics, }) => HotRunner( devices, @@ -586,6 +594,7 @@ class HotRunnerFactory { stayResident: stayResident, ipv6: ipv6, nativeAssetsYamlFile: nativeAssetsYamlFile, + nativeAssetsBuilder: nativeAssetsBuilder, analytics: analytics, ); } diff --git a/packages/flutter_tools/lib/src/commands/daemon.dart b/packages/flutter_tools/lib/src/commands/daemon.dart index 435cf7eeac..05bac1d14e 100644 --- a/packages/flutter_tools/lib/src/commands/daemon.dart +++ b/packages/flutter_tools/lib/src/commands/daemon.dart @@ -654,6 +654,7 @@ class AppDomain extends Domain { bool machine = true, String? userIdentifier, bool enableDevTools = true, + required HotRunnerNativeAssetsBuilder? nativeAssetsBuilder, }) async { if (!await device.supportsRuntimeMode(options.buildInfo.mode)) { throw Exception( @@ -705,6 +706,7 @@ class AppDomain extends Domain { hostIsIde: true, machine: machine, analytics: globals.analytics, + nativeAssetsBuilder: nativeAssetsBuilder, ); } else { runner = ColdRunner( diff --git a/packages/flutter_tools/lib/src/commands/run.dart b/packages/flutter_tools/lib/src/commands/run.dart index 16fbf80606..ceccfbd939 100644 --- a/packages/flutter_tools/lib/src/commands/run.dart +++ b/packages/flutter_tools/lib/src/commands/run.dart @@ -334,7 +334,11 @@ abstract class RunCommandBase extends FlutterCommand with DeviceBasedDevelopment } class RunCommand extends RunCommandBase { - RunCommand({ bool verboseHelp = false }) : super(verboseHelp: verboseHelp) { + RunCommand({ + bool verboseHelp = false, + HotRunnerNativeAssetsBuilder? nativeAssetsBuilder, + }) : _nativeAssetsBuilder = nativeAssetsBuilder, + super(verboseHelp: verboseHelp) { requiresPubspecYaml(); usesFilesystemOptions(hide: !verboseHelp); usesExtraDartFlagOptions(verboseHelp: verboseHelp); @@ -418,6 +422,8 @@ class RunCommand extends RunCommandBase { ); } + final HotRunnerNativeAssetsBuilder? _nativeAssetsBuilder; + @override final String name = 'run'; @@ -660,6 +666,7 @@ class RunCommand extends RunCommandBase { ipv6: ipv6 ?? false, analytics: globals.analytics, nativeAssetsYamlFile: stringArg(FlutterOptions.kNativeAssetsYamlFile), + nativeAssetsBuilder: _nativeAssetsBuilder, ); } else if (webMode) { return webRunnerFactory!.createWebRunner( @@ -733,6 +740,7 @@ class RunCommand extends RunCommandBase { ipv6: ipv6 ?? false, userIdentifier: userIdentifier, enableDevTools: boolArg(FlutterCommand.kEnableDevTools), + nativeAssetsBuilder: _nativeAssetsBuilder, ); } on Exception catch (error) { throwToolExit(error.toString()); diff --git a/packages/flutter_tools/lib/src/commands/test.dart b/packages/flutter_tools/lib/src/commands/test.dart index 2bed07aa13..63e3fddf1b 100644 --- a/packages/flutter_tools/lib/src/commands/test.dart +++ b/packages/flutter_tools/lib/src/commands/test.dart @@ -18,6 +18,7 @@ import '../runner/flutter_command.dart'; import '../test/coverage_collector.dart'; import '../test/event_printer.dart'; import '../test/runner.dart'; +import '../test/test_compiler.dart'; import '../test/test_time_recorder.dart'; import '../test/test_wrapper.dart'; import '../test/watcher.dart'; @@ -63,6 +64,7 @@ class TestCommand extends FlutterCommand with DeviceBasedDevelopmentArtifacts { this.testWrapper = const TestWrapper(), this.testRunner = const FlutterTestRunner(), this.verbose = false, + this.nativeAssetsBuilder, }) { requiresPubspecYaml(); usesPubOption(); @@ -237,6 +239,8 @@ class TestCommand extends FlutterCommand with DeviceBasedDevelopmentArtifacts { /// Interface for running the tester process. final FlutterTestRunner testRunner; + final TestCompilerNativeAssetsBuilder? nativeAssetsBuilder; + final bool verbose; @visibleForTesting @@ -504,6 +508,7 @@ class TestCommand extends FlutterCommand with DeviceBasedDevelopmentArtifacts { integrationTestDevice: integrationTestDevice, integrationTestUserIdentifier: stringArg(FlutterOptions.kDeviceUser), testTimeRecorder: testTimeRecorder, + nativeAssetsBuilder: nativeAssetsBuilder, ); testTimeRecorder?.stop(TestTimePhases.TestRunner, testRunnerTimeRecorderStopwatch!); diff --git a/packages/flutter_tools/lib/src/isolated/native_assets/README.md b/packages/flutter_tools/lib/src/isolated/native_assets/README.md new file mode 100644 index 0000000000..d775029fdc --- /dev/null +++ b/packages/flutter_tools/lib/src/isolated/native_assets/README.md @@ -0,0 +1,4 @@ +The directory structure in here mirrors the directory structure in lib/src/. + +The native assets feature lives in lib/src/isolated/ because this code is not +used in other build systems. diff --git a/packages/flutter_tools/lib/src/android/native_assets.dart b/packages/flutter_tools/lib/src/isolated/native_assets/android/native_assets.dart similarity index 97% rename from packages/flutter_tools/lib/src/android/native_assets.dart rename to packages/flutter_tools/lib/src/isolated/native_assets/android/native_assets.dart index 91fbc6f89b..c2b40011c7 100644 --- a/packages/flutter_tools/lib/src/android/native_assets.dart +++ b/packages/flutter_tools/lib/src/isolated/native_assets/android/native_assets.dart @@ -4,17 +4,17 @@ import 'package:native_assets_builder/native_assets_builder.dart' show BuildResult, DryRunResult; -import 'package:native_assets_cli/native_assets_cli_internal.dart' - hide BuildMode; import 'package:native_assets_cli/native_assets_cli_internal.dart' as native_assets_cli; +import 'package:native_assets_cli/native_assets_cli_internal.dart' + hide BuildMode; -import '../base/common.dart'; -import '../base/file_system.dart'; -import '../build_info.dart'; -import '../globals.dart' as globals; +import '../../../android/android_sdk.dart'; +import '../../../base/common.dart'; +import '../../../base/file_system.dart'; +import '../../../build_info.dart'; +import '../../../globals.dart' as globals; import '../native_assets.dart'; -import 'android_sdk.dart'; /// Dry run the native builds. /// diff --git a/packages/flutter_tools/lib/src/ios/native_assets.dart b/packages/flutter_tools/lib/src/isolated/native_assets/ios/native_assets.dart similarity index 98% rename from packages/flutter_tools/lib/src/ios/native_assets.dart rename to packages/flutter_tools/lib/src/isolated/native_assets/ios/native_assets.dart index 5327ca7280..24e1beb78d 100644 --- a/packages/flutter_tools/lib/src/ios/native_assets.dart +++ b/packages/flutter_tools/lib/src/isolated/native_assets/ios/native_assets.dart @@ -9,9 +9,9 @@ import 'package:native_assets_cli/native_assets_cli_internal.dart' import 'package:native_assets_cli/native_assets_cli_internal.dart' as native_assets_cli; -import '../base/file_system.dart'; -import '../build_info.dart'; -import '../globals.dart' as globals; +import '../../../base/file_system.dart'; +import '../../../build_info.dart'; +import '../../../globals.dart' as globals; import '../macos/native_assets_host.dart'; import '../native_assets.dart'; diff --git a/packages/flutter_tools/lib/src/linux/native_assets.dart b/packages/flutter_tools/lib/src/isolated/native_assets/linux/native_assets.dart similarity index 94% rename from packages/flutter_tools/lib/src/linux/native_assets.dart rename to packages/flutter_tools/lib/src/isolated/native_assets/linux/native_assets.dart index 7b8bb0fc48..47c6d57216 100644 --- a/packages/flutter_tools/lib/src/linux/native_assets.dart +++ b/packages/flutter_tools/lib/src/isolated/native_assets/linux/native_assets.dart @@ -5,11 +5,11 @@ import 'package:native_assets_cli/native_assets_cli_internal.dart' hide BuildMode; -import '../base/common.dart'; -import '../base/file_system.dart'; -import '../base/io.dart'; -import '../build_info.dart'; -import '../globals.dart' as globals; +import '../../../base/common.dart'; +import '../../../base/file_system.dart'; +import '../../../base/io.dart'; +import '../../../build_info.dart'; +import '../../../globals.dart' as globals; import '../native_assets.dart'; /// Dry run the native builds. diff --git a/packages/flutter_tools/lib/src/macos/native_assets.dart b/packages/flutter_tools/lib/src/isolated/native_assets/macos/native_assets.dart similarity index 99% rename from packages/flutter_tools/lib/src/macos/native_assets.dart rename to packages/flutter_tools/lib/src/isolated/native_assets/macos/native_assets.dart index eb609c04ee..c68a8f8d2a 100644 --- a/packages/flutter_tools/lib/src/macos/native_assets.dart +++ b/packages/flutter_tools/lib/src/isolated/native_assets/macos/native_assets.dart @@ -9,9 +9,9 @@ import 'package:native_assets_cli/native_assets_cli_internal.dart' import 'package:native_assets_cli/native_assets_cli_internal.dart' as native_assets_cli; -import '../base/file_system.dart'; -import '../build_info.dart'; -import '../globals.dart' as globals; +import '../../../base/file_system.dart'; +import '../../../build_info.dart'; +import '../../../globals.dart' as globals; import '../native_assets.dart'; import 'native_assets_host.dart'; diff --git a/packages/flutter_tools/lib/src/macos/native_assets_host.dart b/packages/flutter_tools/lib/src/isolated/native_assets/macos/native_assets_host.dart similarity index 96% rename from packages/flutter_tools/lib/src/macos/native_assets_host.dart rename to packages/flutter_tools/lib/src/isolated/native_assets/macos/native_assets_host.dart index e86ea7e474..b0bfb0e7e7 100644 --- a/packages/flutter_tools/lib/src/macos/native_assets_host.dart +++ b/packages/flutter_tools/lib/src/isolated/native_assets/macos/native_assets_host.dart @@ -7,12 +7,12 @@ import 'package:native_assets_cli/native_assets_cli_internal.dart' hide BuildMode; -import '../base/common.dart'; -import '../base/file_system.dart'; -import '../base/io.dart'; -import '../build_info.dart'; -import '../convert.dart'; -import '../globals.dart' as globals; +import '../../../base/common.dart'; +import '../../../base/file_system.dart'; +import '../../../base/io.dart'; +import '../../../build_info.dart'; +import '../../../convert.dart'; +import '../../../globals.dart' as globals; /// Create an `Info.plist` in [target] for a framework with a single dylib. /// diff --git a/packages/flutter_tools/lib/src/native_assets.dart b/packages/flutter_tools/lib/src/isolated/native_assets/native_assets.dart similarity index 95% rename from packages/flutter_tools/lib/src/native_assets.dart rename to packages/flutter_tools/lib/src/isolated/native_assets/native_assets.dart index 4c132224b7..99dc6f6780 100644 --- a/packages/flutter_tools/lib/src/native_assets.dart +++ b/packages/flutter_tools/lib/src/isolated/native_assets/native_assets.dart @@ -5,25 +5,28 @@ // Logic for native assets shared between all host OSes. import 'package:logging/logging.dart' as logging; -import 'package:native_assets_builder/native_assets_builder.dart' hide NativeAssetsBuildRunner; -import 'package:native_assets_builder/native_assets_builder.dart' as native_assets_builder show NativeAssetsBuildRunner; +import 'package:native_assets_builder/native_assets_builder.dart' + as native_assets_builder show NativeAssetsBuildRunner; +import 'package:native_assets_builder/native_assets_builder.dart' + hide NativeAssetsBuildRunner; import 'package:native_assets_cli/native_assets_cli_internal.dart'; import 'package:package_config/package_config_types.dart'; +import '../../base/common.dart'; +import '../../base/file_system.dart'; +import '../../base/logger.dart'; +import '../../base/platform.dart'; +import '../../build_info.dart' as build_info; +import '../../cache.dart'; +import '../../features.dart'; +import '../../globals.dart' as globals; +import '../../resident_runner.dart'; +import '../../run_hot.dart'; import 'android/native_assets.dart'; -import 'base/common.dart'; -import 'base/file_system.dart'; -import 'base/logger.dart'; -import 'base/platform.dart'; -import 'build_info.dart' as build_info; -import 'cache.dart'; -import 'features.dart'; -import 'globals.dart' as globals; import 'ios/native_assets.dart'; import 'linux/native_assets.dart'; import 'macos/native_assets.dart'; import 'macos/native_assets_host.dart'; -import 'resident_runner.dart'; import 'windows/native_assets.dart'; /// Programmatic API to be used by Dart launchers to invoke native builds. @@ -310,6 +313,32 @@ Uri nativeAssetsBuildUri(Uri projectUri, OS os) { return projectUri.resolve('$buildDir/native_assets/$os/'); } +class HotRunnerNativeAssetsBuilderImpl implements HotRunnerNativeAssetsBuilder { + const HotRunnerNativeAssetsBuilderImpl(); + + @override + Future dryRun({ + required Uri projectUri, + required FileSystem fileSystem, + required List flutterDevices, + required PackageConfig packageConfig, + required Logger logger, + }) async { + final NativeAssetsBuildRunner buildRunner = NativeAssetsBuildRunnerImpl( + projectUri, + packageConfig, + fileSystem, + globals.logger, + ); + return dryRunNativeAssets( + projectUri: projectUri, + fileSystem: fileSystem, + buildRunner: buildRunner, + flutterDevices: flutterDevices, + ); + } +} + /// Gets the native asset id to dylib mapping to embed in the kernel file. /// /// Run hot compiles a kernel file that is pushed to the device after hot diff --git a/packages/flutter_tools/lib/src/isolated/native_assets/test/native_assets.dart b/packages/flutter_tools/lib/src/isolated/native_assets/test/native_assets.dart new file mode 100644 index 0000000000..206f1afa42 --- /dev/null +++ b/packages/flutter_tools/lib/src/isolated/native_assets/test/native_assets.dart @@ -0,0 +1,80 @@ +// 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. + +// Logic for native assets shared between all host OSes. + +import '../../../base/os.dart'; +import '../../../base/platform.dart'; +import '../../../build_info.dart'; +import '../../../globals.dart' as globals; +import '../../../project.dart'; +import '../../../test/test_compiler.dart'; +import '../linux/native_assets.dart'; +import '../macos/native_assets.dart'; +import '../native_assets.dart'; +import '../windows/native_assets.dart'; + +class TestCompilerNativeAssetsBuilderImpl + implements TestCompilerNativeAssetsBuilder { + const TestCompilerNativeAssetsBuilderImpl(); + + @override + Future build(BuildInfo buildInfo) => + testCompilerBuildNativeAssets(buildInfo); +} + +Future testCompilerBuildNativeAssets(BuildInfo buildInfo) async { + Uri? nativeAssetsYaml; + if (!buildInfo.buildNativeAssets) { + nativeAssetsYaml = null; + } else { + final Uri projectUri = FlutterProject.current().directory.uri; + final NativeAssetsBuildRunner buildRunner = NativeAssetsBuildRunnerImpl( + projectUri, + buildInfo.packageConfig, + globals.fs, + globals.logger, + ); + if (globals.platform.isMacOS) { + (nativeAssetsYaml, _) = await buildNativeAssetsMacOS( + buildMode: buildInfo.mode, + projectUri: projectUri, + flutterTester: true, + fileSystem: globals.fs, + buildRunner: buildRunner, + ); + } else if (globals.platform.isLinux) { + (nativeAssetsYaml, _) = await buildNativeAssetsLinux( + buildMode: buildInfo.mode, + projectUri: projectUri, + flutterTester: true, + fileSystem: globals.fs, + buildRunner: buildRunner, + ); + } else if (globals.platform.isWindows) { + final TargetPlatform targetPlatform; + if (globals.os.hostPlatform == HostPlatform.windows_x64) { + targetPlatform = TargetPlatform.windows_x64; + } else { + targetPlatform = TargetPlatform.windows_arm64; + } + (nativeAssetsYaml, _) = await buildNativeAssetsWindows( + buildMode: buildInfo.mode, + targetPlatform: targetPlatform, + projectUri: projectUri, + flutterTester: true, + fileSystem: globals.fs, + buildRunner: buildRunner, + ); + } else { + await ensureNoNativeAssetsOrOsIsSupported( + projectUri, + const LocalPlatform().operatingSystem, + globals.fs, + buildRunner, + ); + } + } + return nativeAssetsYaml; +} diff --git a/packages/flutter_tools/lib/src/windows/native_assets.dart b/packages/flutter_tools/lib/src/isolated/native_assets/windows/native_assets.dart similarity index 93% rename from packages/flutter_tools/lib/src/windows/native_assets.dart rename to packages/flutter_tools/lib/src/isolated/native_assets/windows/native_assets.dart index 1c8579918a..77e8b5350b 100644 --- a/packages/flutter_tools/lib/src/windows/native_assets.dart +++ b/packages/flutter_tools/lib/src/isolated/native_assets/windows/native_assets.dart @@ -5,11 +5,11 @@ import 'package:native_assets_cli/native_assets_cli_internal.dart' hide BuildMode; -import '../base/file_system.dart'; -import '../build_info.dart'; -import '../globals.dart' as globals; +import '../../../base/file_system.dart'; +import '../../../build_info.dart'; +import '../../../globals.dart' as globals; +import '../../../windows/visual_studio.dart'; import '../native_assets.dart'; -import 'visual_studio.dart'; /// Dry run the native builds. /// @@ -66,7 +66,6 @@ Future<(Uri? nativeAssetsYaml, List dependencies)> ); } - Future cCompilerConfigWindows() async { final VisualStudio visualStudio = VisualStudio( fileSystem: globals.fs, diff --git a/packages/flutter_tools/lib/src/run_hot.dart b/packages/flutter_tools/lib/src/run_hot.dart index 5f7cc6aa71..17a212d6a2 100644 --- a/packages/flutter_tools/lib/src/run_hot.dart +++ b/packages/flutter_tools/lib/src/run_hot.dart @@ -22,7 +22,6 @@ import 'dart/package_map.dart'; import 'devfs.dart'; import 'device.dart'; import 'globals.dart' as globals; -import 'native_assets.dart'; import 'project.dart'; import 'reporting/reporting.dart'; import 'resident_runner.dart'; @@ -93,13 +92,13 @@ class HotRunner extends ResidentRunner { StopwatchFactory stopwatchFactory = const StopwatchFactory(), ReloadSourcesHelper reloadSourcesHelper = defaultReloadSourcesHelper, ReassembleHelper reassembleHelper = _defaultReassembleHelper, - NativeAssetsBuildRunner? buildRunner, + HotRunnerNativeAssetsBuilder? nativeAssetsBuilder, String? nativeAssetsYamlFile, required Analytics analytics, }) : _stopwatchFactory = stopwatchFactory, _reloadSourcesHelper = reloadSourcesHelper, _reassembleHelper = reassembleHelper, - _buildRunner = buildRunner, + _nativeAssetsBuilder = nativeAssetsBuilder, _nativeAssetsYamlFile = nativeAssetsYamlFile, _analytics = analytics, super( @@ -139,7 +138,7 @@ class HotRunner extends ResidentRunner { String? _sdkName; bool? _emulator; - NativeAssetsBuildRunner? _buildRunner; + final HotRunnerNativeAssetsBuilder? _nativeAssetsBuilder; final String? _nativeAssetsYamlFile; String? flavor; @@ -374,17 +373,12 @@ class HotRunner extends ResidentRunner { nativeAssetsYaml = globals.fs.path.toUri(_nativeAssetsYamlFile); } else { final Uri projectUri = Uri.directory(projectRootPath); - _buildRunner ??= NativeAssetsBuildRunnerImpl( - projectUri, - debuggingOptions.buildInfo.packageConfig, - fileSystem, - globals.logger, - ); - nativeAssetsYaml = await dryRunNativeAssets( + nativeAssetsYaml = await _nativeAssetsBuilder?.dryRun( projectUri: projectUri, fileSystem: fileSystem, - buildRunner: _buildRunner!, flutterDevices: flutterDevices, + logger: logger, + packageConfig: debuggingOptions.buildInfo.packageConfig, ); } @@ -1728,3 +1722,15 @@ class ReasonForCancelling { return '$message.\nTry performing a hot restart instead.'; } } + +/// An interface to enable overriding native assets build logic in other +/// build systems. +abstract class HotRunnerNativeAssetsBuilder { + Future dryRun({ + required Uri projectUri, + required FileSystem fileSystem, + required List flutterDevices, + required PackageConfig packageConfig, + required Logger logger, + }); +} diff --git a/packages/flutter_tools/lib/src/test/flutter_platform.dart b/packages/flutter_tools/lib/src/test/flutter_platform.dart index 25f2651636..6db7437071 100644 --- a/packages/flutter_tools/lib/src/test/flutter_platform.dart +++ b/packages/flutter_tools/lib/src/test/flutter_platform.dart @@ -69,6 +69,7 @@ FlutterPlatform installHook({ String? integrationTestUserIdentifier, TestTimeRecorder? testTimeRecorder, UriConverter? uriConverter, + TestCompilerNativeAssetsBuilder? nativeAssetsBuilder, }) { assert(enableVmService || enableObservatory || (!debuggingOptions.startPaused && debuggingOptions.hostVmServicePort == null)); @@ -99,6 +100,7 @@ FlutterPlatform installHook({ integrationTestUserIdentifier: integrationTestUserIdentifier, testTimeRecorder: testTimeRecorder, uriConverter: uriConverter, + nativeAssetsBuilder: nativeAssetsBuilder, ); platformPluginRegistration(platform); return platform; @@ -291,6 +293,7 @@ class FlutterPlatform extends PlatformPlugin { this.integrationTestUserIdentifier, this.testTimeRecorder, this.uriConverter, + this.nativeAssetsBuilder, }); final String shellPath; @@ -307,6 +310,7 @@ class FlutterPlatform extends PlatformPlugin { final FlutterProject? flutterProject; final String? icudtlPath; final TestTimeRecorder? testTimeRecorder; + final TestCompilerNativeAssetsBuilder? nativeAssetsBuilder; // This can be used by internal projects that require custom logic for converting package: URIs to local paths. final UriConverter? uriConverter; @@ -465,7 +469,13 @@ class FlutterPlatform extends PlatformPlugin { // running this with a debugger attached. Initialize the resident // compiler in this case. if (debuggingOptions.startPaused) { - compiler ??= TestCompiler(debuggingOptions.buildInfo, flutterProject, precompiledDillPath: precompiledDillPath, testTimeRecorder: testTimeRecorder); + compiler ??= TestCompiler( + debuggingOptions.buildInfo, + flutterProject, + precompiledDillPath: precompiledDillPath, + testTimeRecorder: testTimeRecorder, + nativeAssetsBuilder: nativeAssetsBuilder, + ); final Uri uri = globals.fs.file(path).uri; // Trigger a compilation to initialize the resident compiler. unawaited(compiler!.compile(uri)); @@ -487,7 +497,12 @@ class FlutterPlatform extends PlatformPlugin { // Integration test device takes care of the compilation. if (integrationTestDevice == null) { // Lazily instantiate compiler so it is built only if it is actually used. - compiler ??= TestCompiler(debuggingOptions.buildInfo, flutterProject, testTimeRecorder: testTimeRecorder); + compiler ??= TestCompiler( + debuggingOptions.buildInfo, + flutterProject, + testTimeRecorder: testTimeRecorder, + nativeAssetsBuilder: nativeAssetsBuilder, + ); mainDart = await compiler!.compile(globals.fs.file(mainDart).uri); if (mainDart == null) { diff --git a/packages/flutter_tools/lib/src/test/runner.dart b/packages/flutter_tools/lib/src/test/runner.dart index ab3082269f..c652e53804 100644 --- a/packages/flutter_tools/lib/src/test/runner.dart +++ b/packages/flutter_tools/lib/src/test/runner.dart @@ -12,6 +12,7 @@ import '../web/chrome.dart'; import '../web/memory_fs.dart'; import 'flutter_platform.dart' as loader; import 'flutter_web_platform.dart'; +import 'test_compiler.dart'; import 'test_time_recorder.dart'; import 'test_wrapper.dart'; import 'watcher.dart'; @@ -53,6 +54,7 @@ abstract class FlutterTestRunner { Device? integrationTestDevice, String? integrationTestUserIdentifier, TestTimeRecorder? testTimeRecorder, + TestCompilerNativeAssetsBuilder? nativeAssetsBuilder, }); } @@ -91,6 +93,7 @@ class _FlutterTestRunnerImpl implements FlutterTestRunner { Device? integrationTestDevice, String? integrationTestUserIdentifier, TestTimeRecorder? testTimeRecorder, + TestCompilerNativeAssetsBuilder? nativeAssetsBuilder, }) async { // Configure package:test to use the Flutter engine for child processes. final String shellPath = globals.artifacts!.getArtifactPath(Artifact.flutterTester); @@ -210,6 +213,7 @@ class _FlutterTestRunnerImpl implements FlutterTestRunner { integrationTestDevice: integrationTestDevice, integrationTestUserIdentifier: integrationTestUserIdentifier, testTimeRecorder: testTimeRecorder, + nativeAssetsBuilder: nativeAssetsBuilder, ); try { diff --git a/packages/flutter_tools/lib/src/test/test_compiler.dart b/packages/flutter_tools/lib/src/test/test_compiler.dart index 5d1cd9732a..bed5675b58 100644 --- a/packages/flutter_tools/lib/src/test/test_compiler.dart +++ b/packages/flutter_tools/lib/src/test/test_compiler.dart @@ -10,18 +10,12 @@ import 'package:meta/meta.dart'; import '../artifacts.dart'; import '../base/file_system.dart'; -import '../base/os.dart' show HostPlatform; -import '../base/platform.dart'; import '../build_info.dart'; import '../bundle.dart'; import '../compile.dart'; import '../flutter_plugins.dart'; import '../globals.dart' as globals; -import '../linux/native_assets.dart'; -import '../macos/native_assets.dart'; -import '../native_assets.dart'; import '../project.dart'; -import '../windows/native_assets.dart'; import 'test_time_recorder.dart'; /// A request to the [TestCompiler] for recompilation. @@ -51,9 +45,11 @@ class TestCompiler { /// If [testTimeRecorder] is passed, times will be recorded in it. TestCompiler( this.buildInfo, - this.flutterProject, - { String? precompiledDillPath, this.testTimeRecorder } - ) : testFilePath = precompiledDillPath ?? globals.fs.path.join( + this.flutterProject, { + String? precompiledDillPath, + this.testTimeRecorder, + TestCompilerNativeAssetsBuilder? nativeAssetsBuilder, + }) : testFilePath = precompiledDillPath ?? globals.fs.path.join( flutterProject!.directory.path, getBuildDirectory(), 'test_cache', @@ -62,7 +58,8 @@ class TestCompiler { dartDefines: buildInfo.dartDefines, extraFrontEndOptions: buildInfo.extraFrontEndOptions, )), - shouldCopyDillFile = precompiledDillPath == null { + shouldCopyDillFile = precompiledDillPath == null, + _nativeAssetsBuilder = nativeAssetsBuilder { // Compiler maintains and updates single incremental dill file. // Incremental compilation requests done for each test copy that file away // for independent execution. @@ -83,6 +80,7 @@ class TestCompiler { final String testFilePath; final bool shouldCopyDillFile; final TestTimeRecorder? testTimeRecorder; + final TestCompilerNativeAssetsBuilder? _nativeAssetsBuilder; ResidentCompiler? compiler; @@ -170,57 +168,7 @@ class TestCompiler { invalidatedRegistrantFiles.add(flutterProject!.dartPluginRegistrant.absolute.uri); } - Uri? nativeAssetsYaml; - if (!buildInfo.buildNativeAssets) { - nativeAssetsYaml = null; - } else { - final Uri projectUri = FlutterProject.current().directory.uri; - final NativeAssetsBuildRunner buildRunner = NativeAssetsBuildRunnerImpl( - projectUri, - buildInfo.packageConfig, - globals.fs, - globals.logger, - ); - if (globals.platform.isMacOS) { - (nativeAssetsYaml, _) = await buildNativeAssetsMacOS( - buildMode: buildInfo.mode, - projectUri: projectUri, - flutterTester: true, - fileSystem: globals.fs, - buildRunner: buildRunner, - ); - } else if (globals.platform.isLinux) { - (nativeAssetsYaml, _) = await buildNativeAssetsLinux( - buildMode: buildInfo.mode, - projectUri: projectUri, - flutterTester: true, - fileSystem: globals.fs, - buildRunner: buildRunner, - ); - } else if (globals.platform.isWindows) { - final TargetPlatform targetPlatform; - if (globals.os.hostPlatform == HostPlatform.windows_x64) { - targetPlatform = TargetPlatform.windows_x64; - } else { - targetPlatform = TargetPlatform.windows_arm64; - } - (nativeAssetsYaml, _) = await buildNativeAssetsWindows( - buildMode: buildInfo.mode, - targetPlatform: targetPlatform, - projectUri: projectUri, - flutterTester: true, - fileSystem: globals.fs, - buildRunner: buildRunner, - ); - } else { - await ensureNoNativeAssetsOrOsIsSupported( - projectUri, - const LocalPlatform().operatingSystem, - globals.fs, - buildRunner, - ); - } - } + final Uri? nativeAssetsYaml = await _nativeAssetsBuilder?.build(buildInfo); final CompilerOutput? compilerOutput = await compiler!.recompile( request.mainUri, @@ -270,3 +218,9 @@ class TestCompiler { } } } + +/// An interface to enable overriding native assets build logic in other +/// build systems. +abstract class TestCompilerNativeAssetsBuilder { + Future build(BuildInfo buildInfo); +} diff --git a/packages/flutter_tools/test/commands.shard/hermetic/attach_test.dart b/packages/flutter_tools/test/commands.shard/hermetic/attach_test.dart index f9e40d61d5..33629ec668 100644 --- a/packages/flutter_tools/test/commands.shard/hermetic/attach_test.dart +++ b/packages/flutter_tools/test/commands.shard/hermetic/attach_test.dart @@ -1203,6 +1203,7 @@ class FakeHotRunnerFactory extends Fake implements HotRunnerFactory { FlutterProject? flutterProject, Analytics? analytics, String? nativeAssetsYamlFile, + HotRunnerNativeAssetsBuilder? nativeAssetsBuilder, }) { if (_artifactTester != null) { for (final FlutterDevice device in devices) { diff --git a/packages/flutter_tools/test/commands.shard/hermetic/run_test.dart b/packages/flutter_tools/test/commands.shard/hermetic/run_test.dart index 96d944944b..47951c7b90 100644 --- a/packages/flutter_tools/test/commands.shard/hermetic/run_test.dart +++ b/packages/flutter_tools/test/commands.shard/hermetic/run_test.dart @@ -29,6 +29,7 @@ import 'package:flutter_tools/src/macos/macos_ipad_device.dart'; import 'package:flutter_tools/src/project.dart'; import 'package:flutter_tools/src/reporting/reporting.dart'; import 'package:flutter_tools/src/resident_runner.dart'; +import 'package:flutter_tools/src/run_hot.dart'; import 'package:flutter_tools/src/runner/flutter_command.dart'; import 'package:flutter_tools/src/vmservice.dart'; import 'package:test/fake.dart'; @@ -1578,6 +1579,7 @@ class CapturingAppDomain extends AppDomain { String? userIdentifier, bool enableDevTools = true, String? flavor, + HotRunnerNativeAssetsBuilder? nativeAssetsBuilder, }) async { this.userIdentifier = userIdentifier; this.enableDevTools = enableDevTools; 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 378c9815ab..b92e30bac7 100644 --- a/packages/flutter_tools/test/commands.shard/hermetic/test_test.dart +++ b/packages/flutter_tools/test/commands.shard/hermetic/test_test.dart @@ -18,6 +18,7 @@ import 'package:flutter_tools/src/project.dart'; import 'package:flutter_tools/src/runner/flutter_command.dart'; import 'package:flutter_tools/src/test/coverage_collector.dart'; import 'package:flutter_tools/src/test/runner.dart'; +import 'package:flutter_tools/src/test/test_compiler.dart'; import 'package:flutter_tools/src/test/test_device.dart'; import 'package:flutter_tools/src/test/test_time_recorder.dart'; import 'package:flutter_tools/src/test/test_wrapper.dart'; @@ -1105,6 +1106,7 @@ class FakeFlutterTestRunner implements FlutterTestRunner { Device? integrationTestDevice, String? integrationTestUserIdentifier, TestTimeRecorder? testTimeRecorder, + TestCompilerNativeAssetsBuilder? nativeAssetsBuilder, }) async { lastEnableVmServiceValue = enableVmService; lastDebuggingOptionsValue = debuggingOptions; diff --git a/packages/flutter_tools/test/general.shard/hot_shared.dart b/packages/flutter_tools/test/general.shard/hot_shared.dart new file mode 100644 index 0000000000..e97ec6b9f1 --- /dev/null +++ b/packages/flutter_tools/test/general.shard/hot_shared.dart @@ -0,0 +1,231 @@ +// 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:flutter_tools/src/application_package.dart'; +import 'package:flutter_tools/src/asset.dart'; +import 'package:flutter_tools/src/build_info.dart'; +import 'package:flutter_tools/src/build_system/tools/shader_compiler.dart'; +import 'package:flutter_tools/src/compile.dart'; +import 'package:flutter_tools/src/devfs.dart'; +import 'package:flutter_tools/src/device.dart'; +import 'package:flutter_tools/src/project.dart'; +import 'package:flutter_tools/src/resident_runner.dart'; +import 'package:flutter_tools/src/run_hot.dart'; +import 'package:flutter_tools/src/vmservice.dart'; +import 'package:package_config/package_config.dart'; +import 'package:test/fake.dart'; +import 'package:vm_service/vm_service.dart' as vm_service; + +class FakeDevFs extends Fake implements DevFS { + @override + Future destroy() async { } + + @override + List sources = []; + + @override + DateTime? lastCompiled; + + @override + PackageConfig? lastPackageConfig; + + @override + Set assetPathsToEvict = {}; + + @override + Set shaderPathsToEvict= {}; + + @override + Set scenePathsToEvict= {}; + + @override + Uri? baseUri; +} + +class FakeDevice extends Fake implements Device { + FakeDevice({ + TargetPlatform targetPlatform = TargetPlatform.tester, + }) : _targetPlatform = targetPlatform; + + final TargetPlatform _targetPlatform; + + bool disposed = false; + + @override + bool isSupported() => true; + + @override + bool supportsHotReload = true; + + @override + bool supportsHotRestart = true; + + @override + bool supportsFlutterExit = true; + + @override + Future get targetPlatform async => _targetPlatform; + + @override + Future get sdkNameAndVersion async => 'Tester'; + + @override + Future get isLocalEmulator async => false; + + @override + String get name => 'Fake Device'; + + @override + Future stopApp( + ApplicationPackage? app, { + String? userIdentifier, + }) async { + return true; + } + + @override + Future dispose() async { + disposed = true; + } +} + +class FakeFlutterDevice extends Fake implements FlutterDevice { + FakeFlutterDevice(this.device); + + bool stoppedEchoingDeviceLog = false; + late Future Function() updateDevFSReportCallback; + + @override + final FakeDevice device; + + @override + Future stopEchoingDeviceLog() async { + stoppedEchoingDeviceLog = true; + } + + @override + DevFS? devFS = FakeDevFs(); + + @override + FlutterVmService get vmService => FakeFlutterVmService(); + + @override + ResidentCompiler? generator; + + @override + Future updateDevFS({ + Uri? mainUri, + String? target, + AssetBundle? bundle, + DateTime? firstBuildTime, + bool bundleFirstUpload = false, + bool bundleDirty = false, + bool fullRestart = false, + String? projectRootPath, + String? pathToReload, + required String dillOutputPath, + required List invalidatedFiles, + required PackageConfig packageConfig, + }) => updateDevFSReportCallback(); + + @override + TargetPlatform? get targetPlatform => device._targetPlatform; +} + +class TestFlutterDevice extends FlutterDevice { + TestFlutterDevice({ + required Device device, + required this.exception, + required ResidentCompiler generator, + }) : super(device, buildInfo: BuildInfo.debug, generator: generator, developmentShaderCompiler: const FakeShaderCompiler()); + + /// The exception to throw when the connect method is called. + final Exception exception; + + @override + Future connect({ + ReloadSources? reloadSources, + Restart? restart, + CompileExpression? compileExpression, + GetSkSLMethod? getSkSLMethod, + FlutterProject? flutterProject, + PrintStructuredErrorLogMethod? printStructuredErrorLogMethod, + bool disableServiceAuthCodes = false, + bool enableDds = true, + bool cacheStartupProfile = false, + bool? ipv6 = false, + int? hostVmServicePort, + int? ddsPort, + bool allowExistingDdsInstance = false, + }) async { + throw exception; + } +} + +class TestHotRunnerConfig extends HotRunnerConfig { + TestHotRunnerConfig({this.successfulHotRestartSetup, this.successfulHotReloadSetup}); + bool? successfulHotRestartSetup; + bool? successfulHotReloadSetup; + bool shutdownHookCalled = false; + bool updateDevFSCompleteCalled = false; + + @override + Future setupHotRestart() async { + assert(successfulHotRestartSetup != null, 'setupHotRestart is not expected to be called in this test.'); + return successfulHotRestartSetup; + } + + @override + Future setupHotReload() async { + assert(successfulHotReloadSetup != null, 'setupHotReload is not expected to be called in this test.'); + return successfulHotReloadSetup; + } + + @override + void updateDevFSComplete() { + updateDevFSCompleteCalled = true; + } + + @override + Future runPreShutdownOperations() async { + shutdownHookCalled = true; + } +} + +class FakeResidentCompiler extends Fake implements ResidentCompiler { + @override + void accept() {} +} + +class FakeFlutterVmService extends Fake implements FlutterVmService { + @override + vm_service.VmService get service => FakeVmService(); + + @override + Future> getFlutterViews({bool returnEarly = false, Duration delay = const Duration(milliseconds: 50)}) async { + return []; + } +} + +class FakeVmService extends Fake implements vm_service.VmService { + @override + Future getVM() async => FakeVm(); +} + +class FakeVm extends Fake implements vm_service.VM { + @override + List get isolates => []; +} + +class FakeShaderCompiler implements DevelopmentShaderCompiler { + const FakeShaderCompiler(); + + @override + void configureCompiler(TargetPlatform? platform) { } + + @override + Future recompileShader(DevFSContent inputShader) { + throw UnimplementedError(); + } +} diff --git a/packages/flutter_tools/test/general.shard/hot_test.dart b/packages/flutter_tools/test/general.shard/hot_test.dart index 4668402c68..b6510e0836 100644 --- a/packages/flutter_tools/test/general.shard/hot_test.dart +++ b/packages/flutter_tools/test/general.shard/hot_test.dart @@ -3,37 +3,25 @@ // found in the LICENSE file. import 'package:file/memory.dart'; -import 'package:flutter_tools/src/application_package.dart'; import 'package:flutter_tools/src/artifacts.dart'; -import 'package:flutter_tools/src/asset.dart'; import 'package:flutter_tools/src/base/file_system.dart'; import 'package:flutter_tools/src/base/io.dart'; import 'package:flutter_tools/src/base/platform.dart'; import 'package:flutter_tools/src/build_info.dart'; -import 'package:flutter_tools/src/build_system/tools/shader_compiler.dart'; -import 'package:flutter_tools/src/compile.dart'; import 'package:flutter_tools/src/devfs.dart'; import 'package:flutter_tools/src/device.dart'; -import 'package:flutter_tools/src/features.dart'; -import 'package:flutter_tools/src/project.dart'; import 'package:flutter_tools/src/reporting/reporting.dart'; import 'package:flutter_tools/src/resident_devtools_handler.dart'; import 'package:flutter_tools/src/resident_runner.dart'; import 'package:flutter_tools/src/run_hot.dart'; import 'package:flutter_tools/src/vmservice.dart'; -import 'package:native_assets_cli/native_assets_cli_internal.dart' - hide BuildMode, Target; -import 'package:native_assets_cli/native_assets_cli_internal.dart' - as native_assets_cli; -import 'package:package_config/package_config.dart'; -import 'package:test/fake.dart'; import 'package:unified_analytics/unified_analytics.dart'; import 'package:vm_service/vm_service.dart' as vm_service; import '../src/common.dart'; import '../src/context.dart'; import '../src/fakes.dart'; -import 'fake_native_assets_build_runner.dart'; +import 'hot_shared.dart'; void main() { group('validateReloadReport', () { @@ -625,352 +613,4 @@ void main() { expect(flutterDevice2.stoppedEchoingDeviceLog, true); }); }); - - group('native assets', () { - late TestHotRunnerConfig testingConfig; - late FileSystem fileSystem; - late FakeAnalytics fakeAnalytics; - - setUp(() { - fileSystem = MemoryFileSystem.test(); - testingConfig = TestHotRunnerConfig( - successfulHotRestartSetup: true, - ); - fakeAnalytics = getInitializedFakeAnalyticsInstance( - fs: fileSystem, - fakeFlutterVersion: FakeFlutterVersion(), - ); - }); - testUsingContext('native assets restart', () async { - final FakeDevice device = FakeDevice(); - final FakeFlutterDevice fakeFlutterDevice = FakeFlutterDevice(device); - final List devices = [ - fakeFlutterDevice, - ]; - - fakeFlutterDevice.updateDevFSReportCallback = () async => UpdateFSReport( - success: true, - invalidatedSourcesCount: 6, - syncedBytes: 8, - scannedSourcesCount: 16, - compileDuration: const Duration(seconds: 16), - transferDuration: const Duration(seconds: 32), - ); - - (fakeFlutterDevice.devFS! as FakeDevFs).baseUri = Uri.parse('file:///base_uri'); - - final FakeNativeAssetsBuildRunner buildRunner = FakeNativeAssetsBuildRunner( - packagesWithNativeAssetsResult: [ - Package('bar', fileSystem.currentDirectory.uri), - ], - dryRunResult: FakeNativeAssetsBuilderResult( - assets: [ - Asset( - id: 'package:bar/bar.dart', - linkMode: LinkMode.dynamic, - target: native_assets_cli.Target.macOSArm64, - path: AssetAbsolutePath(Uri.file('bar.dylib')), - ), - ], - ), - ); - - final HotRunner hotRunner = HotRunner( - devices, - debuggingOptions: DebuggingOptions.disabled(BuildInfo.debug), - target: 'main.dart', - devtoolsHandler: createNoOpHandler, - buildRunner: buildRunner, - analytics: fakeAnalytics, - ); - final OperationResult result = await hotRunner.restart(fullRestart: true); - expect(result.isOk, true); - // Hot restart does not require rerunning anything for native assets. - // The previous native assets mapping should be used. - expect(buildRunner.buildInvocations, 0); - expect(buildRunner.dryRunInvocations, 0); - expect(buildRunner.hasPackageConfigInvocations, 0); - expect(buildRunner.packagesWithNativeAssetsInvocations, 0); - }, overrides: { - HotRunnerConfig: () => testingConfig, - Artifacts: () => Artifacts.test(), - FileSystem: () => fileSystem, - Platform: () => FakePlatform(), - ProcessManager: () => FakeProcessManager.empty(), - FeatureFlags: () => TestFeatureFlags(isNativeAssetsEnabled: true, isMacOSEnabled: true), - }); - - testUsingContext('native assets run unsupported', () async { - final FakeDevice device = FakeDevice(targetPlatform: TargetPlatform.fuchsia_arm64); - final FakeFlutterDevice fakeFlutterDevice = FakeFlutterDevice(device); - final List devices = [ - fakeFlutterDevice, - ]; - - fakeFlutterDevice.updateDevFSReportCallback = () async => UpdateFSReport( - success: true, - invalidatedSourcesCount: 6, - syncedBytes: 8, - scannedSourcesCount: 16, - compileDuration: const Duration(seconds: 16), - transferDuration: const Duration(seconds: 32), - ); - - (fakeFlutterDevice.devFS! as FakeDevFs).baseUri = Uri.parse('file:///base_uri'); - - final FakeNativeAssetsBuildRunner buildRunner = FakeNativeAssetsBuildRunner( - packagesWithNativeAssetsResult: [ - Package('bar', fileSystem.currentDirectory.uri), - ], - dryRunResult: FakeNativeAssetsBuilderResult( - assets: [ - Asset( - id: 'package:bar/bar.dart', - linkMode: LinkMode.dynamic, - target: native_assets_cli.Target.macOSArm64, - path: AssetAbsolutePath(Uri.file('bar.dylib')), - ), - ], - ), - ); - - final HotRunner hotRunner = HotRunner( - devices, - debuggingOptions: DebuggingOptions.disabled(BuildInfo.debug), - target: 'main.dart', - devtoolsHandler: createNoOpHandler, - buildRunner: buildRunner, - analytics: fakeAnalytics, - ); - expect( - () => hotRunner.run(), - throwsToolExit( message: - 'Package(s) bar require the native assets feature. ' - 'This feature has not yet been implemented for `TargetPlatform.fuchsia_arm64`. ' - 'For more info see https://github.com/flutter/flutter/issues/129757.', - ) - ); - - }, overrides: { - HotRunnerConfig: () => testingConfig, - Artifacts: () => Artifacts.test(), - FileSystem: () => fileSystem, - Platform: () => FakePlatform(), - ProcessManager: () => FakeProcessManager.empty(), - FeatureFlags: () => TestFeatureFlags(isNativeAssetsEnabled: true, isMacOSEnabled: true), - }); - }); -} - -class FakeDevFs extends Fake implements DevFS { - @override - Future destroy() async { } - - @override - List sources = []; - - @override - DateTime? lastCompiled; - - @override - PackageConfig? lastPackageConfig; - - @override - Set assetPathsToEvict = {}; - - @override - Set shaderPathsToEvict= {}; - - @override - Set scenePathsToEvict= {}; - - @override - Uri? baseUri; -} - -class FakeDevice extends Fake implements Device { - FakeDevice({ - TargetPlatform targetPlatform = TargetPlatform.tester, - }) : _targetPlatform = targetPlatform; - - final TargetPlatform _targetPlatform; - - bool disposed = false; - - @override - bool isSupported() => true; - - @override - bool supportsHotReload = true; - - @override - bool supportsHotRestart = true; - - @override - bool supportsFlutterExit = true; - - @override - Future get targetPlatform async => _targetPlatform; - - @override - Future get sdkNameAndVersion async => 'Tester'; - - @override - Future get isLocalEmulator async => false; - - @override - String get name => 'Fake Device'; - - @override - Future stopApp( - ApplicationPackage? app, { - String? userIdentifier, - }) async { - return true; - } - - @override - Future dispose() async { - disposed = true; - } -} - -class FakeFlutterDevice extends Fake implements FlutterDevice { - FakeFlutterDevice(this.device); - - bool stoppedEchoingDeviceLog = false; - late Future Function() updateDevFSReportCallback; - - @override - final FakeDevice device; - - @override - Future stopEchoingDeviceLog() async { - stoppedEchoingDeviceLog = true; - } - - @override - DevFS? devFS = FakeDevFs(); - - @override - FlutterVmService get vmService => FakeFlutterVmService(); - - @override - ResidentCompiler? generator; - - @override - Future updateDevFS({ - Uri? mainUri, - String? target, - AssetBundle? bundle, - DateTime? firstBuildTime, - bool bundleFirstUpload = false, - bool bundleDirty = false, - bool fullRestart = false, - String? projectRootPath, - String? pathToReload, - required String dillOutputPath, - required List invalidatedFiles, - required PackageConfig packageConfig, - }) => updateDevFSReportCallback(); - - @override - TargetPlatform? get targetPlatform => device._targetPlatform; -} - -class TestFlutterDevice extends FlutterDevice { - TestFlutterDevice({ - required Device device, - required this.exception, - required ResidentCompiler generator, - }) : super(device, buildInfo: BuildInfo.debug, generator: generator, developmentShaderCompiler: const FakeShaderCompiler()); - - /// The exception to throw when the connect method is called. - final Exception exception; - - @override - Future connect({ - ReloadSources? reloadSources, - Restart? restart, - CompileExpression? compileExpression, - GetSkSLMethod? getSkSLMethod, - FlutterProject? flutterProject, - PrintStructuredErrorLogMethod? printStructuredErrorLogMethod, - bool disableServiceAuthCodes = false, - bool enableDds = true, - bool cacheStartupProfile = false, - bool? ipv6 = false, - int? hostVmServicePort, - int? ddsPort, - bool allowExistingDdsInstance = false, - }) async { - throw exception; - } -} - -class TestHotRunnerConfig extends HotRunnerConfig { - TestHotRunnerConfig({this.successfulHotRestartSetup, this.successfulHotReloadSetup}); - bool? successfulHotRestartSetup; - bool? successfulHotReloadSetup; - bool shutdownHookCalled = false; - bool updateDevFSCompleteCalled = false; - - @override - Future setupHotRestart() async { - assert(successfulHotRestartSetup != null, 'setupHotRestart is not expected to be called in this test.'); - return successfulHotRestartSetup; - } - - @override - Future setupHotReload() async { - assert(successfulHotReloadSetup != null, 'setupHotReload is not expected to be called in this test.'); - return successfulHotReloadSetup; - } - - @override - void updateDevFSComplete() { - updateDevFSCompleteCalled = true; - } - - @override - Future runPreShutdownOperations() async { - shutdownHookCalled = true; - } -} - -class FakeResidentCompiler extends Fake implements ResidentCompiler { - @override - void accept() {} -} - -class FakeFlutterVmService extends Fake implements FlutterVmService { - @override - vm_service.VmService get service => FakeVmService(); - - @override - Future> getFlutterViews({bool returnEarly = false, Duration delay = const Duration(milliseconds: 50)}) async { - return []; - } -} - -class FakeVmService extends Fake implements vm_service.VmService { - @override - Future getVM() async => FakeVm(); -} - -class FakeVm extends Fake implements vm_service.VM { - @override - List get isolates => []; -} - -class FakeShaderCompiler implements DevelopmentShaderCompiler { - const FakeShaderCompiler(); - - @override - void configureCompiler(TargetPlatform? platform) { } - - @override - Future recompileShader(DevFSContent inputShader) { - throw UnimplementedError(); - } } diff --git a/packages/flutter_tools/test/general.shard/android/native_assets_test.dart b/packages/flutter_tools/test/general.shard/isolated/android/native_assets_test.dart similarity index 98% rename from packages/flutter_tools/test/general.shard/android/native_assets_test.dart rename to packages/flutter_tools/test/general.shard/isolated/android/native_assets_test.dart index 43c2955946..6391d4c59b 100644 --- a/packages/flutter_tools/test/general.shard/android/native_assets_test.dart +++ b/packages/flutter_tools/test/general.shard/isolated/android/native_assets_test.dart @@ -5,7 +5,6 @@ import 'package:file/file.dart'; import 'package:file/memory.dart'; import 'package:file_testing/file_testing.dart'; -import 'package:flutter_tools/src/android/native_assets.dart'; import 'package:flutter_tools/src/artifacts.dart'; import 'package:flutter_tools/src/base/common.dart'; import 'package:flutter_tools/src/base/file_system.dart'; @@ -15,15 +14,16 @@ import 'package:flutter_tools/src/build_info.dart'; import 'package:flutter_tools/src/build_system/build_system.dart'; import 'package:flutter_tools/src/features.dart'; import 'package:flutter_tools/src/globals.dart' as globals; +import 'package:flutter_tools/src/isolated/native_assets/android/native_assets.dart'; import 'package:native_assets_cli/native_assets_cli_internal.dart' as native_assets_cli; import 'package:native_assets_cli/native_assets_cli_internal.dart' hide BuildMode, Target; import 'package:package_config/package_config_types.dart'; -import '../../src/common.dart'; -import '../../src/context.dart'; -import '../../src/fakes.dart'; +import '../../../src/common.dart'; +import '../../../src/context.dart'; +import '../../../src/fakes.dart'; import '../fake_native_assets_build_runner.dart'; void main() { diff --git a/packages/flutter_tools/test/general.shard/build_system/targets/native_assets_test.dart b/packages/flutter_tools/test/general.shard/isolated/build_system/targets/native_assets_test.dart similarity index 97% rename from packages/flutter_tools/test/general.shard/build_system/targets/native_assets_test.dart rename to packages/flutter_tools/test/general.shard/isolated/build_system/targets/native_assets_test.dart index baa6d7df37..077a624abf 100644 --- a/packages/flutter_tools/test/general.shard/build_system/targets/native_assets_test.dart +++ b/packages/flutter_tools/test/general.shard/isolated/build_system/targets/native_assets_test.dart @@ -12,14 +12,14 @@ import 'package:flutter_tools/src/build_system/build_system.dart'; import 'package:flutter_tools/src/build_system/exceptions.dart'; import 'package:flutter_tools/src/build_system/targets/native_assets.dart'; import 'package:flutter_tools/src/features.dart'; -import 'package:flutter_tools/src/native_assets.dart'; +import 'package:flutter_tools/src/isolated/native_assets/native_assets.dart'; import 'package:native_assets_cli/native_assets_cli_internal.dart' as native_assets_cli; import 'package:package_config/package_config.dart' show Package; -import '../../../src/common.dart'; -import '../../../src/context.dart'; -import '../../../src/fakes.dart'; +import '../../../../src/common.dart'; +import '../../../../src/context.dart'; +import '../../../../src/fakes.dart'; import '../../fake_native_assets_build_runner.dart'; void main() { diff --git a/packages/flutter_tools/test/general.shard/fake_native_assets_build_runner.dart b/packages/flutter_tools/test/general.shard/isolated/fake_native_assets_build_runner.dart similarity index 78% rename from packages/flutter_tools/test/general.shard/fake_native_assets_build_runner.dart rename to packages/flutter_tools/test/general.shard/isolated/fake_native_assets_build_runner.dart index fa1e8cf0e3..afc7c23638 100644 --- a/packages/flutter_tools/test/general.shard/fake_native_assets_build_runner.dart +++ b/packages/flutter_tools/test/general.shard/isolated/fake_native_assets_build_runner.dart @@ -2,7 +2,11 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -import 'package:flutter_tools/src/native_assets.dart'; +import 'package:file/src/interface/file_system.dart'; +import 'package:flutter_tools/src/base/logger.dart'; +import 'package:flutter_tools/src/isolated/native_assets/native_assets.dart'; +import 'package:flutter_tools/src/resident_runner.dart'; +import 'package:flutter_tools/src/run_hot.dart'; import 'package:native_assets_builder/native_assets_builder.dart' as native_assets_builder; import 'package:native_assets_cli/native_assets_cli_internal.dart'; @@ -95,3 +99,25 @@ final class FakeNativeAssetsBuilderResult @override final bool success; } + +class FakeHotRunnerNativeAssetsBuilder implements HotRunnerNativeAssetsBuilder { + FakeHotRunnerNativeAssetsBuilder(this.buildRunner); + + final NativeAssetsBuildRunner buildRunner; + + @override + Future dryRun({ + required Uri projectUri, + required FileSystem fileSystem, + required List flutterDevices, + required PackageConfig packageConfig, + required Logger logger, + }) { + return dryRunNativeAssets( + projectUri: projectUri, + fileSystem: fileSystem, + buildRunner: buildRunner, + flutterDevices: flutterDevices, + ); + } +} diff --git a/packages/flutter_tools/test/general.shard/isolated/hot_test.dart b/packages/flutter_tools/test/general.shard/isolated/hot_test.dart new file mode 100644 index 0000000000..03957db464 --- /dev/null +++ b/packages/flutter_tools/test/general.shard/isolated/hot_test.dart @@ -0,0 +1,164 @@ +// 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/artifacts.dart'; +import 'package:flutter_tools/src/base/file_system.dart'; +import 'package:flutter_tools/src/base/platform.dart'; +import 'package:flutter_tools/src/build_info.dart'; +import 'package:flutter_tools/src/devfs.dart'; +import 'package:flutter_tools/src/device.dart'; +import 'package:flutter_tools/src/features.dart'; +import 'package:flutter_tools/src/resident_devtools_handler.dart'; +import 'package:flutter_tools/src/resident_runner.dart'; +import 'package:flutter_tools/src/run_hot.dart'; +import 'package:native_assets_cli/native_assets_cli_internal.dart' + hide BuildMode, Target; +import 'package:native_assets_cli/native_assets_cli_internal.dart' + as native_assets_cli; +import 'package:package_config/package_config.dart'; +import 'package:unified_analytics/unified_analytics.dart'; + +import '../../src/common.dart'; +import '../../src/context.dart'; +import '../../src/fakes.dart'; +import '../hot_shared.dart'; +import 'fake_native_assets_build_runner.dart'; + +void main() { + group('native assets', () { + late TestHotRunnerConfig testingConfig; + late FileSystem fileSystem; + late FakeAnalytics fakeAnalytics; + + setUp(() { + fileSystem = MemoryFileSystem.test(); + testingConfig = TestHotRunnerConfig( + successfulHotRestartSetup: true, + ); + fakeAnalytics = getInitializedFakeAnalyticsInstance( + fs: fileSystem, + fakeFlutterVersion: FakeFlutterVersion(), + ); + }); + testUsingContext('native assets restart', () async { + final FakeDevice device = FakeDevice(); + final FakeFlutterDevice fakeFlutterDevice = FakeFlutterDevice(device); + final List devices = [ + fakeFlutterDevice, + ]; + + fakeFlutterDevice.updateDevFSReportCallback = () async => UpdateFSReport( + success: true, + invalidatedSourcesCount: 6, + syncedBytes: 8, + scannedSourcesCount: 16, + compileDuration: const Duration(seconds: 16), + transferDuration: const Duration(seconds: 32), + ); + + (fakeFlutterDevice.devFS! as FakeDevFs).baseUri = Uri.parse('file:///base_uri'); + + final FakeNativeAssetsBuildRunner buildRunner = FakeNativeAssetsBuildRunner( + packagesWithNativeAssetsResult: [ + Package('bar', fileSystem.currentDirectory.uri), + ], + dryRunResult: FakeNativeAssetsBuilderResult( + assets: [ + Asset( + id: 'package:bar/bar.dart', + linkMode: LinkMode.dynamic, + target: native_assets_cli.Target.macOSArm64, + path: AssetAbsolutePath(Uri.file('bar.dylib')), + ), + ], + ), + ); + + final HotRunner hotRunner = HotRunner( + devices, + debuggingOptions: DebuggingOptions.disabled(BuildInfo.debug), + target: 'main.dart', + devtoolsHandler: createNoOpHandler, + nativeAssetsBuilder: FakeHotRunnerNativeAssetsBuilder(buildRunner), + analytics: fakeAnalytics, + ); + final OperationResult result = await hotRunner.restart(fullRestart: true); + expect(result.isOk, true); + // Hot restart does not require rerunning anything for native assets. + // The previous native assets mapping should be used. + expect(buildRunner.buildInvocations, 0); + expect(buildRunner.dryRunInvocations, 0); + expect(buildRunner.hasPackageConfigInvocations, 0); + expect(buildRunner.packagesWithNativeAssetsInvocations, 0); + }, overrides: { + HotRunnerConfig: () => testingConfig, + Artifacts: () => Artifacts.test(), + FileSystem: () => fileSystem, + Platform: () => FakePlatform(), + ProcessManager: () => FakeProcessManager.empty(), + FeatureFlags: () => TestFeatureFlags(isNativeAssetsEnabled: true, isMacOSEnabled: true), + }); + + testUsingContext('native assets run unsupported', () async { + final FakeDevice device = FakeDevice(targetPlatform: TargetPlatform.fuchsia_arm64); + final FakeFlutterDevice fakeFlutterDevice = FakeFlutterDevice(device); + final List devices = [ + fakeFlutterDevice, + ]; + + fakeFlutterDevice.updateDevFSReportCallback = () async => UpdateFSReport( + success: true, + invalidatedSourcesCount: 6, + syncedBytes: 8, + scannedSourcesCount: 16, + compileDuration: const Duration(seconds: 16), + transferDuration: const Duration(seconds: 32), + ); + + (fakeFlutterDevice.devFS! as FakeDevFs).baseUri = Uri.parse('file:///base_uri'); + + final FakeNativeAssetsBuildRunner buildRunner = FakeNativeAssetsBuildRunner( + packagesWithNativeAssetsResult: [ + Package('bar', fileSystem.currentDirectory.uri), + ], + dryRunResult: FakeNativeAssetsBuilderResult( + assets: [ + Asset( + id: 'package:bar/bar.dart', + linkMode: LinkMode.dynamic, + target: native_assets_cli.Target.macOSArm64, + path: AssetAbsolutePath(Uri.file('bar.dylib')), + ), + ], + ), + ); + + final HotRunner hotRunner = HotRunner( + devices, + debuggingOptions: DebuggingOptions.disabled(BuildInfo.debug), + target: 'main.dart', + devtoolsHandler: createNoOpHandler, + nativeAssetsBuilder: FakeHotRunnerNativeAssetsBuilder(buildRunner), + analytics: fakeAnalytics, + ); + expect( + () => hotRunner.run(), + throwsToolExit( message: + 'Package(s) bar require the native assets feature. ' + 'This feature has not yet been implemented for `TargetPlatform.fuchsia_arm64`. ' + 'For more info see https://github.com/flutter/flutter/issues/129757.', + ) + ); + + }, overrides: { + HotRunnerConfig: () => testingConfig, + Artifacts: () => Artifacts.test(), + FileSystem: () => fileSystem, + Platform: () => FakePlatform(), + ProcessManager: () => FakeProcessManager.empty(), + FeatureFlags: () => TestFeatureFlags(isNativeAssetsEnabled: true, isMacOSEnabled: true), + }); + }); +} diff --git a/packages/flutter_tools/test/general.shard/ios/native_assets_test.dart b/packages/flutter_tools/test/general.shard/isolated/ios/native_assets_test.dart similarity index 98% rename from packages/flutter_tools/test/general.shard/ios/native_assets_test.dart rename to packages/flutter_tools/test/general.shard/isolated/ios/native_assets_test.dart index 95d0bfc265..b365dcb77a 100644 --- a/packages/flutter_tools/test/general.shard/ios/native_assets_test.dart +++ b/packages/flutter_tools/test/general.shard/isolated/ios/native_assets_test.dart @@ -13,16 +13,16 @@ import 'package:flutter_tools/src/build_info.dart'; import 'package:flutter_tools/src/build_system/build_system.dart'; import 'package:flutter_tools/src/features.dart'; import 'package:flutter_tools/src/globals.dart' as globals; -import 'package:flutter_tools/src/ios/native_assets.dart'; +import 'package:flutter_tools/src/isolated/native_assets/ios/native_assets.dart'; import 'package:native_assets_cli/native_assets_cli_internal.dart' hide BuildMode, Target; import 'package:native_assets_cli/native_assets_cli_internal.dart' as native_assets_cli; import 'package:package_config/package_config_types.dart'; -import '../../src/common.dart'; -import '../../src/context.dart'; -import '../../src/fakes.dart'; +import '../../../src/common.dart'; +import '../../../src/context.dart'; +import '../../../src/fakes.dart'; import '../fake_native_assets_build_runner.dart'; void main() { diff --git a/packages/flutter_tools/test/general.shard/linux/native_assets_test.dart b/packages/flutter_tools/test/general.shard/isolated/linux/native_assets_test.dart similarity index 98% rename from packages/flutter_tools/test/general.shard/linux/native_assets_test.dart rename to packages/flutter_tools/test/general.shard/isolated/linux/native_assets_test.dart index bf7296ea8f..6806919da0 100644 --- a/packages/flutter_tools/test/general.shard/linux/native_assets_test.dart +++ b/packages/flutter_tools/test/general.shard/isolated/linux/native_assets_test.dart @@ -15,17 +15,17 @@ import 'package:flutter_tools/src/build_system/build_system.dart'; import 'package:flutter_tools/src/dart/package_map.dart'; import 'package:flutter_tools/src/features.dart'; import 'package:flutter_tools/src/globals.dart' as globals; -import 'package:flutter_tools/src/linux/native_assets.dart'; -import 'package:flutter_tools/src/native_assets.dart'; +import 'package:flutter_tools/src/isolated/native_assets/linux/native_assets.dart'; +import 'package:flutter_tools/src/isolated/native_assets/native_assets.dart'; import 'package:native_assets_cli/native_assets_cli_internal.dart' hide BuildMode, Target; import 'package:native_assets_cli/native_assets_cli_internal.dart' as native_assets_cli; import 'package:package_config/package_config_types.dart'; -import '../../src/common.dart'; -import '../../src/context.dart'; -import '../../src/fakes.dart'; +import '../../../src/common.dart'; +import '../../../src/context.dart'; +import '../../../src/fakes.dart'; import '../fake_native_assets_build_runner.dart'; void main() { diff --git a/packages/flutter_tools/test/general.shard/macos/native_assets_host_test.dart b/packages/flutter_tools/test/general.shard/isolated/macos/native_assets_host_test.dart similarity index 94% rename from packages/flutter_tools/test/general.shard/macos/native_assets_host_test.dart rename to packages/flutter_tools/test/general.shard/isolated/macos/native_assets_host_test.dart index 4df6c6362d..ad8898ce1b 100644 --- a/packages/flutter_tools/test/general.shard/macos/native_assets_host_test.dart +++ b/packages/flutter_tools/test/general.shard/isolated/macos/native_assets_host_test.dart @@ -2,9 +2,9 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -import 'package:flutter_tools/src/macos/native_assets_host.dart'; +import 'package:flutter_tools/src/isolated/native_assets/macos/native_assets_host.dart'; -import '../../src/common.dart'; +import '../../../src/common.dart'; void main() { test('framework name', () { diff --git a/packages/flutter_tools/test/general.shard/macos/native_assets_test.dart b/packages/flutter_tools/test/general.shard/isolated/macos/native_assets_test.dart similarity index 98% rename from packages/flutter_tools/test/general.shard/macos/native_assets_test.dart rename to packages/flutter_tools/test/general.shard/isolated/macos/native_assets_test.dart index c934d42af2..8006ac03c5 100644 --- a/packages/flutter_tools/test/general.shard/macos/native_assets_test.dart +++ b/packages/flutter_tools/test/general.shard/isolated/macos/native_assets_test.dart @@ -13,17 +13,17 @@ import 'package:flutter_tools/src/build_system/build_system.dart'; import 'package:flutter_tools/src/dart/package_map.dart'; import 'package:flutter_tools/src/features.dart'; import 'package:flutter_tools/src/globals.dart' as globals; -import 'package:flutter_tools/src/macos/native_assets.dart'; -import 'package:flutter_tools/src/native_assets.dart'; +import 'package:flutter_tools/src/isolated/native_assets/macos/native_assets.dart'; +import 'package:flutter_tools/src/isolated/native_assets/native_assets.dart'; import 'package:native_assets_cli/native_assets_cli_internal.dart' hide BuildMode, Target; import 'package:native_assets_cli/native_assets_cli_internal.dart' as native_assets_cli; import 'package:package_config/package_config_types.dart'; -import '../../src/common.dart'; -import '../../src/context.dart'; -import '../../src/fakes.dart'; +import '../../../src/common.dart'; +import '../../../src/context.dart'; +import '../../../src/fakes.dart'; import '../fake_native_assets_build_runner.dart'; void main() { diff --git a/packages/flutter_tools/test/general.shard/isolated/resident_runner_test.dart b/packages/flutter_tools/test/general.shard/isolated/resident_runner_test.dart new file mode 100644 index 0000000000..b67c0e5ff4 --- /dev/null +++ b/packages/flutter_tools/test/general.shard/isolated/resident_runner_test.dart @@ -0,0 +1,121 @@ +// 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:flutter_tools/src/build_info.dart'; +import 'package:flutter_tools/src/device.dart'; +import 'package:flutter_tools/src/features.dart'; +import 'package:flutter_tools/src/globals.dart' as globals; +import 'package:flutter_tools/src/resident_devtools_handler.dart'; +import 'package:flutter_tools/src/resident_runner.dart'; +import 'package:flutter_tools/src/run_hot.dart'; +import 'package:unified_analytics/unified_analytics.dart'; + +import '../../src/common.dart'; +import '../../src/context.dart'; +import '../../src/fake_vm_services.dart'; +import '../../src/fakes.dart'; +import '../../src/testbed.dart'; +import '../resident_runner_helpers.dart'; +import 'fake_native_assets_build_runner.dart'; + +void main() { + late Testbed testbed; + late FakeFlutterDevice flutterDevice; + late FakeDevFS devFS; + late ResidentRunner residentRunner; + late FakeDevice device; + late FakeAnalytics fakeAnalytics; + FakeVmServiceHost? fakeVmServiceHost; + + setUp(() { + testbed = Testbed(setup: () { + fakeAnalytics = getInitializedFakeAnalyticsInstance( + fs: globals.fs, + fakeFlutterVersion: FakeFlutterVersion(), + ); + + globals.fs.file('.packages') + .writeAsStringSync('\n'); + globals.fs.file(globals.fs.path.join('build', 'app.dill')) + ..createSync(recursive: true) + ..writeAsStringSync('ABC'); + residentRunner = HotRunner( + [ + flutterDevice, + ], + stayResident: false, + debuggingOptions: DebuggingOptions.enabled(BuildInfo.debug), + target: 'main.dart', + devtoolsHandler: createNoOpHandler, + analytics: fakeAnalytics, + ); + }); + device = FakeDevice(); + devFS = FakeDevFS(); + flutterDevice = FakeFlutterDevice() + ..testUri = testUri + ..vmServiceHost = (() => fakeVmServiceHost) + ..device = device + ..devFS = devFS; + }); + + testUsingContext( + 'use the nativeAssetsYamlFile when provided', + () => testbed.run(() async { + final FakeDevice device = FakeDevice( + targetPlatform: TargetPlatform.darwin, + sdkNameAndVersion: 'Macos', + ); + final FakeResidentCompiler residentCompiler = FakeResidentCompiler(); + final FakeFlutterDevice flutterDevice = FakeFlutterDevice() + ..testUri = testUri + ..vmServiceHost = (() => fakeVmServiceHost) + ..device = device + ..devFS = devFS + ..targetPlatform = TargetPlatform.darwin + ..generator = residentCompiler; + + fakeVmServiceHost = FakeVmServiceHost(requests: [ + listViews, + listViews, + ]); + globals.fs + .file(globals.fs.path.join('lib', 'main.dart')) + .createSync(recursive: true); + final FakeNativeAssetsBuildRunner buildRunner = FakeNativeAssetsBuildRunner(); + residentRunner = HotRunner( + [ + flutterDevice, + ], + stayResident: false, + debuggingOptions: DebuggingOptions.enabled(const BuildInfo( + BuildMode.debug, + '', + treeShakeIcons: false, + trackWidgetCreation: true, + )), + target: 'main.dart', + devtoolsHandler: createNoOpHandler, + nativeAssetsBuilder: FakeHotRunnerNativeAssetsBuilder(buildRunner), + analytics: fakeAnalytics, + nativeAssetsYamlFile: 'foo.yaml', + ); + + final int? result = await residentRunner.run(); + expect(result, 0); + + expect(buildRunner.buildInvocations, 0); + expect(buildRunner.dryRunInvocations, 0); + expect(buildRunner.hasPackageConfigInvocations, 0); + expect(buildRunner.packagesWithNativeAssetsInvocations, 0); + + expect(residentCompiler.recompileCalled, true); + expect(residentCompiler.receivedNativeAssetsYaml, globals.fs.path.toUri('foo.yaml')); + }), + overrides: { + ProcessManager: () => FakeProcessManager.any(), + FeatureFlags: () => TestFeatureFlags(isNativeAssetsEnabled: true, isMacOSEnabled: true), + }); +} diff --git a/packages/flutter_tools/test/general.shard/windows/native_assets_test.dart b/packages/flutter_tools/test/general.shard/isolated/windows/native_assets_test.dart similarity index 98% rename from packages/flutter_tools/test/general.shard/windows/native_assets_test.dart rename to packages/flutter_tools/test/general.shard/isolated/windows/native_assets_test.dart index 7226fa2396..15c8d587f3 100644 --- a/packages/flutter_tools/test/general.shard/windows/native_assets_test.dart +++ b/packages/flutter_tools/test/general.shard/isolated/windows/native_assets_test.dart @@ -14,17 +14,17 @@ import 'package:flutter_tools/src/build_system/build_system.dart'; import 'package:flutter_tools/src/dart/package_map.dart'; import 'package:flutter_tools/src/features.dart'; import 'package:flutter_tools/src/globals.dart' as globals; -import 'package:flutter_tools/src/native_assets.dart'; -import 'package:flutter_tools/src/windows/native_assets.dart'; +import 'package:flutter_tools/src/isolated/native_assets/native_assets.dart'; +import 'package:flutter_tools/src/isolated/native_assets/windows/native_assets.dart'; import 'package:native_assets_cli/native_assets_cli_internal.dart' hide BuildMode, Target; import 'package:native_assets_cli/native_assets_cli_internal.dart' as native_assets_cli; import 'package:package_config/package_config_types.dart'; -import '../../src/common.dart'; -import '../../src/context.dart'; -import '../../src/fakes.dart'; +import '../../../src/common.dart'; +import '../../../src/context.dart'; +import '../../../src/fakes.dart'; import '../fake_native_assets_build_runner.dart'; void main() { diff --git a/packages/flutter_tools/test/general.shard/resident_runner_helpers.dart b/packages/flutter_tools/test/general.shard/resident_runner_helpers.dart new file mode 100644 index 0000000000..918685bf1f --- /dev/null +++ b/packages/flutter_tools/test/general.shard/resident_runner_helpers.dart @@ -0,0 +1,529 @@ +// 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 'dart:async'; + +import 'package:dds/dds.dart' as dds; +import 'package:flutter_tools/src/application_package.dart'; +import 'package:flutter_tools/src/asset.dart'; +import 'package:flutter_tools/src/base/dds.dart'; +import 'package:flutter_tools/src/base/file_system.dart'; +import 'package:flutter_tools/src/build_info.dart'; +import 'package:flutter_tools/src/build_system/tools/scene_importer.dart'; +import 'package:flutter_tools/src/build_system/tools/shader_compiler.dart'; +import 'package:flutter_tools/src/compile.dart'; +import 'package:flutter_tools/src/devfs.dart'; +import 'package:flutter_tools/src/device.dart'; +import 'package:flutter_tools/src/device_port_forwarder.dart'; +import 'package:flutter_tools/src/project.dart'; +import 'package:flutter_tools/src/resident_runner.dart'; +import 'package:flutter_tools/src/run_cold.dart'; +import 'package:flutter_tools/src/run_hot.dart'; +import 'package:flutter_tools/src/vmservice.dart'; +import 'package:package_config/package_config.dart'; +import 'package:test/fake.dart'; +import 'package:vm_service/vm_service.dart' as vm_service; + +import '../src/fake_vm_services.dart'; + +final vm_service.Event fakeUnpausedEvent = vm_service.Event( + kind: vm_service.EventKind.kResume, + timestamp: 0 +); + +final vm_service.Event fakePausedEvent = vm_service.Event( + kind: vm_service.EventKind.kPauseException, + timestamp: 0 +); + +final vm_service.Isolate fakeUnpausedIsolate = vm_service.Isolate( + id: '1', + pauseEvent: fakeUnpausedEvent, + breakpoints: [], + extensionRPCs: [], + libraries: [ + vm_service.LibraryRef( + id: '1', + uri: 'file:///hello_world/main.dart', + name: '', + ), + ], + livePorts: 0, + name: 'test', + number: '1', + pauseOnExit: false, + runnable: true, + startTime: 0, + isSystemIsolate: false, + isolateFlags: [], +); + +final vm_service.Isolate fakePausedIsolate = vm_service.Isolate( + id: '1', + pauseEvent: fakePausedEvent, + breakpoints: [ + vm_service.Breakpoint( + breakpointNumber: 123, + id: 'test-breakpoint', + location: vm_service.SourceLocation( + tokenPos: 0, + script: vm_service.ScriptRef(id: 'test-script', uri: 'foo.dart'), + ), + enabled: true, + resolved: true, + ), + ], + libraries: [], + livePorts: 0, + name: 'test', + number: '1', + pauseOnExit: false, + runnable: true, + startTime: 0, + isSystemIsolate: false, + isolateFlags: [], +); + +final vm_service.VM fakeVM = vm_service.VM( + isolates: [fakeUnpausedIsolate], + pid: 1, + hostCPU: '', + isolateGroups: [], + targetCPU: '', + startTime: 0, + name: 'dart', + architectureBits: 64, + operatingSystem: '', + version: '', + systemIsolateGroups: [], + systemIsolates: [], +); + +final FlutterView fakeFlutterView = FlutterView( + id: 'a', + uiIsolate: fakeUnpausedIsolate, +); + +final FakeVmServiceRequest listViews = FakeVmServiceRequest( + method: kListViewsMethod, + jsonResponse: { + 'views': [ + fakeFlutterView.toJson(), + ], + }, +); + +const FakeVmServiceRequest setAssetBundlePath = FakeVmServiceRequest( + method: '_flutter.setAssetBundlePath', + args: { + 'viewId': 'a', + 'assetDirectory': 'build/flutter_assets', + 'isolateId': '1', + } +); + +const FakeVmServiceRequest evict = FakeVmServiceRequest( + method: 'ext.flutter.evict', + args: { + 'value': 'asset', + 'isolateId': '1', + } +); + +const FakeVmServiceRequest evictShader = FakeVmServiceRequest( + method: 'ext.ui.window.reinitializeShader', + args: { + 'assetKey': 'foo.frag', + 'isolateId': '1', + } +); + +final Uri testUri = Uri.parse('foo://bar'); + +// This implements [dds.DartDevelopmentService], not the [DartDevelopmentService] +// interface from package:flutter_tools. +class FakeDartDevelopmentService extends Fake implements dds.DartDevelopmentService { + @override + Future get done => Future.value(); + + @override + Uri? get uri => null; +} + +class FakeDartDevelopmentServiceException implements dds.DartDevelopmentServiceException { + FakeDartDevelopmentServiceException({this.message = defaultMessage}); + + @override + final int errorCode = dds.DartDevelopmentServiceException.existingDdsInstanceError; + + @override + final String message; + static const String defaultMessage = 'A DDS instance is already connected at http://localhost:8181'; +} + +class TestFlutterDevice extends FlutterDevice { + TestFlutterDevice(super.device, { Stream? vmServiceUris }) + : _vmServiceUris = vmServiceUris, super(buildInfo: BuildInfo.debug, developmentShaderCompiler: const FakeShaderCompiler()); + + final Stream? _vmServiceUris; + + @override + Stream get vmServiceUris => _vmServiceUris!; +} + +class ThrowingForwardingFileSystem extends ForwardingFileSystem { + ThrowingForwardingFileSystem(super.delegate); + + @override + File file(dynamic path) { + if (path == 'foo') { + throw const FileSystemException(); + } + return delegate.file(path); + } +} + +class FakeFlutterDevice extends Fake implements FlutterDevice { + FakeVmServiceHost? Function()? vmServiceHost; + Uri? testUri; + UpdateFSReport report = UpdateFSReport( + success: true, + invalidatedSourcesCount: 1, + ); + Exception? reportError; + Exception? runColdError; + int runHotCode = 0; + int runColdCode = 0; + + @override + ResidentCompiler? generator; + + @override + DevelopmentShaderCompiler get developmentShaderCompiler => const FakeShaderCompiler(); + + @override + TargetPlatform targetPlatform = TargetPlatform.android; + + @override + Stream get vmServiceUris => Stream.value(testUri); + + @override + FlutterVmService? get vmService => vmServiceHost?.call()?.vmService; + + DevFS? _devFS; + + @override + DevFS? get devFS => _devFS; + + @override + set devFS(DevFS? value) { } + + @override + Device? device; + + @override + Future stopEchoingDeviceLog() async { } + + @override + Future initLogReader() async { } + + @override + Future setupDevFS(String fsName, Directory rootDirectory) async { + return testUri!; + } + + @override + Future runHot({required HotRunner hotRunner, String? route}) async { + return runHotCode; + } + + @override + Future runCold({required ColdRunner coldRunner, String? route}) async { + if (runColdError != null) { + throw runColdError!; + } + return runColdCode; + } + + @override + Future connect({ + ReloadSources? reloadSources, + Restart? restart, + CompileExpression? compileExpression, + GetSkSLMethod? getSkSLMethod, + FlutterProject? flutterProject, + PrintStructuredErrorLogMethod? printStructuredErrorLogMethod, + int? hostVmServicePort, + int? ddsPort, + bool disableServiceAuthCodes = false, + bool enableDds = true, + bool cacheStartupProfile = false, + required bool allowExistingDdsInstance, + bool ipv6 = false, + }) async { } + + @override + Future updateDevFS({ + required Uri mainUri, + String? target, + AssetBundle? bundle, + DateTime? firstBuildTime, + bool bundleFirstUpload = false, + bool bundleDirty = false, + bool fullRestart = false, + String? projectRootPath, + required String pathToReload, + required String dillOutputPath, + required List invalidatedFiles, + required PackageConfig packageConfig, + }) async { + if (reportError != null) { + throw reportError!; + } + return report; + } + + @override + Future updateReloadStatus(bool wasReloadSuccessful) async { } +} + +class FakeDelegateFlutterDevice extends FlutterDevice { + FakeDelegateFlutterDevice( + super.device, + BuildInfo buildInfo, + ResidentCompiler residentCompiler, + this.fakeDevFS, + ) : super(buildInfo: buildInfo, generator: residentCompiler, developmentShaderCompiler: const FakeShaderCompiler()); + + @override + Future connect({ + ReloadSources? reloadSources, + Restart? restart, + bool enableDds = true, + bool cacheStartupProfile = false, + bool disableServiceAuthCodes = false, + bool ipv6 = false, + CompileExpression? compileExpression, + GetSkSLMethod? getSkSLMethod, + FlutterProject? flutterProject, + int? hostVmServicePort, + int? ddsPort, + PrintStructuredErrorLogMethod? printStructuredErrorLogMethod, + bool allowExistingDdsInstance = false, + }) async { } + + + final DevFS fakeDevFS; + + @override + DevFS? get devFS => fakeDevFS; + + @override + set devFS(DevFS? value) {} +} + +class FakeResidentCompiler extends Fake implements ResidentCompiler { + CompilerOutput? nextOutput; + bool didSuppressErrors = false; + Uri? receivedNativeAssetsYaml; + bool recompileCalled = false; + + @override + Future recompile( + Uri mainUri, + List? invalidatedFiles, { + required String outputPath, + required PackageConfig packageConfig, + String? projectRootPath, + required FileSystem fs, + bool suppressErrors = false, + bool checkDartPluginRegistry = false, + File? dartPluginRegistrant, + Uri? nativeAssetsYaml, + }) async { + recompileCalled = true; + receivedNativeAssetsYaml = nativeAssetsYaml; + didSuppressErrors = suppressErrors; + return nextOutput ?? const CompilerOutput('foo.dill', 0, []); + } + + @override + void accept() { } + + @override + void reset() { } +} + +class FakeProjectFileInvalidator extends Fake implements ProjectFileInvalidator { + @override + Future findInvalidated({ + required DateTime? lastCompiled, + required List urisToMonitor, + required String packagesPath, + required PackageConfig packageConfig, + bool asyncScanning = false, + }) async { + return InvalidationResult( + packageConfig: packageConfig, + uris: [Uri.parse('file:///hello_world/main.dart'), + ]); + } +} + +class FakeDevice extends Fake implements Device { + FakeDevice({ + String sdkNameAndVersion = 'Android', + TargetPlatform targetPlatform = TargetPlatform.android_arm, + bool isLocalEmulator = false, + this.supportsHotRestart = true, + this.supportsScreenshot = true, + this.supportsFlutterExit = true, + }) : _isLocalEmulator = isLocalEmulator, + _targetPlatform = targetPlatform, + _sdkNameAndVersion = sdkNameAndVersion; + + final bool _isLocalEmulator; + final TargetPlatform _targetPlatform; + final String _sdkNameAndVersion; + + bool disposed = false; + bool appStopped = false; + bool failScreenshot = false; + + @override + bool supportsHotRestart; + + @override + bool supportsScreenshot; + + @override + bool supportsFlutterExit; + + @override + PlatformType get platformType => _targetPlatform == TargetPlatform.web_javascript + ? PlatformType.web + : PlatformType.android; + + @override + Future get sdkNameAndVersion async => _sdkNameAndVersion; + + @override + Future get targetPlatform async => _targetPlatform; + + @override + Future get isLocalEmulator async => _isLocalEmulator; + + @override + String get name => 'FakeDevice'; + + @override + late DartDevelopmentService dds; + + @override + Future dispose() async { + disposed = true; + } + + @override + Future stopApp(ApplicationPackage? app, {String? userIdentifier}) async { + appStopped = true; + return true; + } + + @override + Future takeScreenshot(File outputFile) async { + if (failScreenshot) { + throw Exception(); + } + outputFile.writeAsBytesSync(List.generate(1024, (int i) => i)); + } + + @override + FutureOr getLogReader({ + ApplicationPackage? app, + bool includePastLogs = false, + }) => NoOpDeviceLogReader(name); + + @override + DevicePortForwarder portForwarder = const NoOpDevicePortForwarder(); +} + +class FakeDevFS extends Fake implements DevFS { + @override + DateTime? lastCompiled = DateTime(2000); + + @override + PackageConfig? lastPackageConfig = PackageConfig.empty; + + @override + List sources = []; + + @override + Uri baseUri = Uri(); + + @override + Future destroy() async { } + + @override + Set assetPathsToEvict = {}; + + @override + Set shaderPathsToEvict = {}; + + @override + Set scenePathsToEvict = {}; + + @override + bool didUpdateFontManifest = false; + + UpdateFSReport nextUpdateReport = UpdateFSReport(success: true); + + @override + bool hasSetAssetDirectory = false; + + @override + Future create() async { + return Uri(); + } + + @override + void resetLastCompiled() { + lastCompiled = null; + } + + @override + Future update({ + required Uri mainUri, + required ResidentCompiler generator, + required bool trackWidgetCreation, + required String pathToReload, + required List invalidatedFiles, + required PackageConfig packageConfig, + required String dillOutputPath, + required DevelopmentShaderCompiler shaderCompiler, + DevelopmentSceneImporter? sceneImporter, + DevFSWriter? devFSWriter, + String? target, + AssetBundle? bundle, + DateTime? firstBuildTime, + bool bundleFirstUpload = false, + bool fullRestart = false, + String? projectRootPath, + File? dartPluginRegistrant, + }) async { + return nextUpdateReport; + } +} + +class FakeShaderCompiler implements DevelopmentShaderCompiler { + const FakeShaderCompiler(); + + @override + void configureCompiler(TargetPlatform? platform) { } + + @override + Future recompileShader(DevFSContent inputShader) { + throw UnimplementedError(); + } +} diff --git a/packages/flutter_tools/test/general.shard/resident_runner_test.dart b/packages/flutter_tools/test/general.shard/resident_runner_test.dart index 547c9b7e9c..8c30e0a0a1 100644 --- a/packages/flutter_tools/test/general.shard/resident_runner_test.dart +++ b/packages/flutter_tools/test/general.shard/resident_runner_test.dart @@ -7,9 +7,7 @@ import 'dart:async'; import 'package:dds/dds.dart' as dds; import 'package:file/memory.dart'; import 'package:file_testing/file_testing.dart'; -import 'package:flutter_tools/src/application_package.dart'; import 'package:flutter_tools/src/artifacts.dart'; -import 'package:flutter_tools/src/asset.dart'; import 'package:flutter_tools/src/base/command_help.dart'; import 'package:flutter_tools/src/base/common.dart'; import 'package:flutter_tools/src/base/dds.dart'; @@ -18,14 +16,10 @@ import 'package:flutter_tools/src/base/io.dart' as io; import 'package:flutter_tools/src/base/logger.dart'; import 'package:flutter_tools/src/base/platform.dart'; import 'package:flutter_tools/src/build_info.dart'; -import 'package:flutter_tools/src/build_system/build_system.dart'; -import 'package:flutter_tools/src/build_system/tools/scene_importer.dart'; -import 'package:flutter_tools/src/build_system/tools/shader_compiler.dart'; import 'package:flutter_tools/src/compile.dart'; import 'package:flutter_tools/src/convert.dart'; import 'package:flutter_tools/src/devfs.dart'; import 'package:flutter_tools/src/device.dart'; -import 'package:flutter_tools/src/device_port_forwarder.dart'; import 'package:flutter_tools/src/features.dart'; import 'package:flutter_tools/src/globals.dart' as globals; import 'package:flutter_tools/src/project.dart'; @@ -36,12 +30,6 @@ import 'package:flutter_tools/src/run_cold.dart'; import 'package:flutter_tools/src/run_hot.dart'; import 'package:flutter_tools/src/version.dart'; import 'package:flutter_tools/src/vmservice.dart'; -import 'package:native_assets_cli/native_assets_cli_internal.dart' - hide BuildMode, Target; -import 'package:native_assets_cli/native_assets_cli_internal.dart' - as native_assets_cli; -import 'package:package_config/package_config.dart'; -import 'package:test/fake.dart'; import 'package:unified_analytics/src/enums.dart'; import 'package:unified_analytics/unified_analytics.dart'; import 'package:vm_service/vm_service.dart' as vm_service; @@ -51,121 +39,8 @@ import '../src/context.dart'; import '../src/fake_vm_services.dart'; import '../src/fakes.dart'; import '../src/testbed.dart'; -import 'fake_native_assets_build_runner.dart'; - -final vm_service.Event fakeUnpausedEvent = vm_service.Event( - kind: vm_service.EventKind.kResume, - timestamp: 0 -); - -final vm_service.Event fakePausedEvent = vm_service.Event( - kind: vm_service.EventKind.kPauseException, - timestamp: 0 -); - -final vm_service.Isolate fakeUnpausedIsolate = vm_service.Isolate( - id: '1', - pauseEvent: fakeUnpausedEvent, - breakpoints: [], - extensionRPCs: [], - libraries: [ - vm_service.LibraryRef( - id: '1', - uri: 'file:///hello_world/main.dart', - name: '', - ), - ], - livePorts: 0, - name: 'test', - number: '1', - pauseOnExit: false, - runnable: true, - startTime: 0, - isSystemIsolate: false, - isolateFlags: [], -); - -final vm_service.Isolate fakePausedIsolate = vm_service.Isolate( - id: '1', - pauseEvent: fakePausedEvent, - breakpoints: [ - vm_service.Breakpoint( - breakpointNumber: 123, - id: 'test-breakpoint', - location: vm_service.SourceLocation( - tokenPos: 0, - script: vm_service.ScriptRef(id: 'test-script', uri: 'foo.dart'), - ), - enabled: true, - resolved: true, - ), - ], - libraries: [], - livePorts: 0, - name: 'test', - number: '1', - pauseOnExit: false, - runnable: true, - startTime: 0, - isSystemIsolate: false, - isolateFlags: [], -); - -final vm_service.VM fakeVM = vm_service.VM( - isolates: [fakeUnpausedIsolate], - pid: 1, - hostCPU: '', - isolateGroups: [], - targetCPU: '', - startTime: 0, - name: 'dart', - architectureBits: 64, - operatingSystem: '', - version: '', - systemIsolateGroups: [], - systemIsolates: [], -); - -final FlutterView fakeFlutterView = FlutterView( - id: 'a', - uiIsolate: fakeUnpausedIsolate, -); - -final FakeVmServiceRequest listViews = FakeVmServiceRequest( - method: kListViewsMethod, - jsonResponse: { - 'views': [ - fakeFlutterView.toJson(), - ], - }, -); - -const FakeVmServiceRequest setAssetBundlePath = FakeVmServiceRequest( - method: '_flutter.setAssetBundlePath', - args: { - 'viewId': 'a', - 'assetDirectory': 'build/flutter_assets', - 'isolateId': '1', - } -); - -const FakeVmServiceRequest evict = FakeVmServiceRequest( - method: 'ext.flutter.evict', - args: { - 'value': 'asset', - 'isolateId': '1', - } -); - -const FakeVmServiceRequest evictShader = FakeVmServiceRequest( - method: 'ext.ui.window.reinitializeShader', - args: { - 'assetKey': 'foo.frag', - 'isolateId': '1', - } -); - -final Uri testUri = Uri.parse('foo://bar'); +import 'isolated/fake_native_assets_build_runner.dart'; +import 'resident_runner_helpers.dart'; void main() { late Testbed testbed; @@ -205,7 +80,7 @@ void main() { ..testUri = testUri ..vmServiceHost = (() => fakeVmServiceHost) ..device = device - .._devFS = devFS; + ..devFS = devFS; }); testUsingContext('ResidentRunner can attach to device successfully', () => testbed.run(() async { @@ -471,7 +346,7 @@ void main() { connectionInfoCompleter: futureConnectionInfo, )); await futureAppStart.future; - flutterDevice._devFS = null; + flutterDevice.devFS = null; final OperationResult result = await residentRunner.restart(); expect(result.fatal, false); @@ -2437,88 +2312,6 @@ flutter: expect(fakeVmServiceHost!.hasRemainingExpectations, false); })); - testUsingContext( - 'native assets', - () => testbed.run(() async { - final FileSystem fileSystem = globals.fs; - final Environment environment = Environment.test( - fileSystem.currentDirectory, - inputs: {}, - artifacts: Artifacts.test(), - processManager: FakeProcessManager.empty(), - fileSystem: fileSystem, - logger: BufferLogger.test(), - ); - final Uri projectUri = environment.projectDir.uri; - - final FakeDevice device = FakeDevice( - targetPlatform: TargetPlatform.darwin, - sdkNameAndVersion: 'Macos', - ); - final FakeResidentCompiler residentCompiler = FakeResidentCompiler(); - final FakeFlutterDevice flutterDevice = FakeFlutterDevice() - ..testUri = testUri - ..vmServiceHost = (() => fakeVmServiceHost) - ..device = device - .._devFS = devFS - ..targetPlatform = TargetPlatform.darwin - ..generator = residentCompiler; - - fakeVmServiceHost = FakeVmServiceHost(requests: [ - listViews, - listViews, - ]); - globals.fs - .file(globals.fs.path.join('lib', 'main.dart')) - .createSync(recursive: true); - final FakeNativeAssetsBuildRunner buildRunner = FakeNativeAssetsBuildRunner( - packagesWithNativeAssetsResult: [ - Package('bar', projectUri), - ], - dryRunResult: FakeNativeAssetsBuilderResult( - assets: [ - Asset( - id: 'package:bar/bar.dart', - linkMode: LinkMode.dynamic, - target: native_assets_cli.Target.macOSArm64, - path: AssetAbsolutePath(Uri.file('bar.dylib')), - ), - ], - ), - ); - residentRunner = HotRunner( - [ - flutterDevice, - ], - stayResident: false, - debuggingOptions: DebuggingOptions.enabled(const BuildInfo( - BuildMode.debug, - '', - treeShakeIcons: false, - trackWidgetCreation: true, - )), - target: 'main.dart', - devtoolsHandler: createNoOpHandler, - buildRunner: buildRunner, - analytics: fakeAnalytics, - ); - - final int? result = await residentRunner.run(); - expect(result, 0); - - expect(buildRunner.buildInvocations, 0); - expect(buildRunner.dryRunInvocations, 1); - expect(buildRunner.hasPackageConfigInvocations, 1); - expect(buildRunner.packagesWithNativeAssetsInvocations, 1); - - expect(residentCompiler.recompileCalled, true); - expect(residentCompiler.receivedNativeAssetsYaml.toString(), endsWith('native_assets/macos/native_assets.yaml')); - }), - overrides: { - ProcessManager: () => FakeProcessManager.any(), - FeatureFlags: () => TestFeatureFlags(isNativeAssetsEnabled: true, isMacOSEnabled: true), - }); - testUsingContext( 'use the nativeAssetsYamlFile when provided', () => testbed.run(() async { @@ -2531,7 +2324,7 @@ flutter: ..testUri = testUri ..vmServiceHost = (() => fakeVmServiceHost) ..device = device - .._devFS = devFS + ..devFS = devFS ..targetPlatform = TargetPlatform.darwin ..generator = residentCompiler; @@ -2556,7 +2349,7 @@ flutter: )), target: 'main.dart', devtoolsHandler: createNoOpHandler, - buildRunner: buildRunner, + nativeAssetsBuilder: FakeHotRunnerNativeAssetsBuilder(buildRunner), analytics: fakeAnalytics, nativeAssetsYamlFile: 'foo.yaml', ); @@ -2577,390 +2370,3 @@ flutter: FeatureFlags: () => TestFeatureFlags(isNativeAssetsEnabled: true, isMacOSEnabled: true), }); } - -// This implements [dds.DartDevelopmentService], not the [DartDevelopmentService] -// interface from package:flutter_tools. -class FakeDartDevelopmentService extends Fake implements dds.DartDevelopmentService { - @override - Future get done => Future.value(); - - @override - Uri? get uri => null; -} - -class FakeDartDevelopmentServiceException implements dds.DartDevelopmentServiceException { - FakeDartDevelopmentServiceException({this.message = defaultMessage}); - - @override - final int errorCode = dds.DartDevelopmentServiceException.existingDdsInstanceError; - - @override - final String message; - static const String defaultMessage = 'A DDS instance is already connected at http://localhost:8181'; -} - -class TestFlutterDevice extends FlutterDevice { - TestFlutterDevice(super.device, { Stream? vmServiceUris }) - : _vmServiceUris = vmServiceUris, super(buildInfo: BuildInfo.debug, developmentShaderCompiler: const FakeShaderCompiler()); - - final Stream? _vmServiceUris; - - @override - Stream get vmServiceUris => _vmServiceUris!; -} - -class ThrowingForwardingFileSystem extends ForwardingFileSystem { - ThrowingForwardingFileSystem(super.delegate); - - @override - File file(dynamic path) { - if (path == 'foo') { - throw const FileSystemException(); - } - return delegate.file(path); - } -} - -class FakeFlutterDevice extends Fake implements FlutterDevice { - FakeVmServiceHost? Function()? vmServiceHost; - Uri? testUri; - UpdateFSReport report = UpdateFSReport( - success: true, - invalidatedSourcesCount: 1, - ); - Exception? reportError; - Exception? runColdError; - int runHotCode = 0; - int runColdCode = 0; - - @override - ResidentCompiler? generator; - - @override - DevelopmentShaderCompiler get developmentShaderCompiler => const FakeShaderCompiler(); - - @override - TargetPlatform targetPlatform = TargetPlatform.android; - - @override - Stream get vmServiceUris => Stream.value(testUri); - - @override - FlutterVmService? get vmService => vmServiceHost?.call()?.vmService; - - DevFS? _devFS; - - @override - DevFS? get devFS => _devFS; - - @override - set devFS(DevFS? value) { } - - @override - Device? device; - - @override - Future stopEchoingDeviceLog() async { } - - @override - Future initLogReader() async { } - - @override - Future setupDevFS(String fsName, Directory rootDirectory) async { - return testUri!; - } - - @override - Future runHot({required HotRunner hotRunner, String? route}) async { - return runHotCode; - } - - @override - Future runCold({required ColdRunner coldRunner, String? route}) async { - if (runColdError != null) { - throw runColdError!; - } - return runColdCode; - } - - @override - Future connect({ - ReloadSources? reloadSources, - Restart? restart, - CompileExpression? compileExpression, - GetSkSLMethod? getSkSLMethod, - FlutterProject? flutterProject, - PrintStructuredErrorLogMethod? printStructuredErrorLogMethod, - int? hostVmServicePort, - int? ddsPort, - bool disableServiceAuthCodes = false, - bool enableDds = true, - bool cacheStartupProfile = false, - required bool allowExistingDdsInstance, - bool ipv6 = false, - }) async { } - - @override - Future updateDevFS({ - required Uri mainUri, - String? target, - AssetBundle? bundle, - DateTime? firstBuildTime, - bool bundleFirstUpload = false, - bool bundleDirty = false, - bool fullRestart = false, - String? projectRootPath, - required String pathToReload, - required String dillOutputPath, - required List invalidatedFiles, - required PackageConfig packageConfig, - }) async { - if (reportError != null) { - throw reportError!; - } - return report; - } - - @override - Future updateReloadStatus(bool wasReloadSuccessful) async { } -} - -class FakeDelegateFlutterDevice extends FlutterDevice { - FakeDelegateFlutterDevice( - super.device, - BuildInfo buildInfo, - ResidentCompiler residentCompiler, - this.fakeDevFS, - ) : super(buildInfo: buildInfo, generator: residentCompiler, developmentShaderCompiler: const FakeShaderCompiler()); - - @override - Future connect({ - ReloadSources? reloadSources, - Restart? restart, - bool enableDds = true, - bool cacheStartupProfile = false, - bool disableServiceAuthCodes = false, - bool ipv6 = false, - CompileExpression? compileExpression, - GetSkSLMethod? getSkSLMethod, - FlutterProject? flutterProject, - int? hostVmServicePort, - int? ddsPort, - PrintStructuredErrorLogMethod? printStructuredErrorLogMethod, - bool allowExistingDdsInstance = false, - }) async { } - - - final DevFS fakeDevFS; - - @override - DevFS? get devFS => fakeDevFS; - - @override - set devFS(DevFS? value) {} -} - -class FakeResidentCompiler extends Fake implements ResidentCompiler { - CompilerOutput? nextOutput; - bool didSuppressErrors = false; - Uri? receivedNativeAssetsYaml; - bool recompileCalled = false; - - @override - Future recompile( - Uri mainUri, - List? invalidatedFiles, { - required String outputPath, - required PackageConfig packageConfig, - String? projectRootPath, - required FileSystem fs, - bool suppressErrors = false, - bool checkDartPluginRegistry = false, - File? dartPluginRegistrant, - Uri? nativeAssetsYaml, - }) async { - recompileCalled = true; - receivedNativeAssetsYaml = nativeAssetsYaml; - didSuppressErrors = suppressErrors; - return nextOutput ?? const CompilerOutput('foo.dill', 0, []); - } - - @override - void accept() { } - - @override - void reset() { } -} - -class FakeProjectFileInvalidator extends Fake implements ProjectFileInvalidator { - @override - Future findInvalidated({ - required DateTime? lastCompiled, - required List urisToMonitor, - required String packagesPath, - required PackageConfig packageConfig, - bool asyncScanning = false, - }) async { - return InvalidationResult( - packageConfig: packageConfig, - uris: [Uri.parse('file:///hello_world/main.dart'), - ]); - } -} - -class FakeDevice extends Fake implements Device { - FakeDevice({ - String sdkNameAndVersion = 'Android', - TargetPlatform targetPlatform = TargetPlatform.android_arm, - bool isLocalEmulator = false, - this.supportsHotRestart = true, - this.supportsScreenshot = true, - this.supportsFlutterExit = true, - }) : _isLocalEmulator = isLocalEmulator, - _targetPlatform = targetPlatform, - _sdkNameAndVersion = sdkNameAndVersion; - - final bool _isLocalEmulator; - final TargetPlatform _targetPlatform; - final String _sdkNameAndVersion; - - bool disposed = false; - bool appStopped = false; - bool failScreenshot = false; - - @override - bool supportsHotRestart; - - @override - bool supportsScreenshot; - - @override - bool supportsFlutterExit; - - @override - PlatformType get platformType => _targetPlatform == TargetPlatform.web_javascript - ? PlatformType.web - : PlatformType.android; - - @override - Future get sdkNameAndVersion async => _sdkNameAndVersion; - - @override - Future get targetPlatform async => _targetPlatform; - - @override - Future get isLocalEmulator async => _isLocalEmulator; - - @override - String get name => 'FakeDevice'; - - @override - late DartDevelopmentService dds; - - @override - Future dispose() async { - disposed = true; - } - - @override - Future stopApp(ApplicationPackage? app, {String? userIdentifier}) async { - appStopped = true; - return true; - } - - @override - Future takeScreenshot(File outputFile) async { - if (failScreenshot) { - throw Exception(); - } - outputFile.writeAsBytesSync(List.generate(1024, (int i) => i)); - } - - @override - FutureOr getLogReader({ - ApplicationPackage? app, - bool includePastLogs = false, - }) => NoOpDeviceLogReader(name); - - @override - DevicePortForwarder portForwarder = const NoOpDevicePortForwarder(); -} - -class FakeDevFS extends Fake implements DevFS { - @override - DateTime? lastCompiled = DateTime(2000); - - @override - PackageConfig? lastPackageConfig = PackageConfig.empty; - - @override - List sources = []; - - @override - Uri baseUri = Uri(); - - @override - Future destroy() async { } - - @override - Set assetPathsToEvict = {}; - - @override - Set shaderPathsToEvict = {}; - - @override - Set scenePathsToEvict = {}; - - @override - bool didUpdateFontManifest = false; - - UpdateFSReport nextUpdateReport = UpdateFSReport(success: true); - - @override - bool hasSetAssetDirectory = false; - - @override - Future create() async { - return Uri(); - } - - @override - void resetLastCompiled() { - lastCompiled = null; - } - - @override - Future update({ - required Uri mainUri, - required ResidentCompiler generator, - required bool trackWidgetCreation, - required String pathToReload, - required List invalidatedFiles, - required PackageConfig packageConfig, - required String dillOutputPath, - required DevelopmentShaderCompiler shaderCompiler, - DevelopmentSceneImporter? sceneImporter, - DevFSWriter? devFSWriter, - String? target, - AssetBundle? bundle, - DateTime? firstBuildTime, - bool bundleFirstUpload = false, - bool fullRestart = false, - String? projectRootPath, - File? dartPluginRegistrant, - }) async { - return nextUpdateReport; - } -} - -class FakeShaderCompiler implements DevelopmentShaderCompiler { - const FakeShaderCompiler(); - - @override - void configureCompiler(TargetPlatform? platform) { } - - @override - Future recompileShader(DevFSContent inputShader) { - throw UnimplementedError(); - } -} diff --git a/packages/flutter_tools/test/integration.shard/native_assets_test.dart b/packages/flutter_tools/test/integration.shard/isolated/native_assets_test.dart similarity index 99% rename from packages/flutter_tools/test/integration.shard/native_assets_test.dart rename to packages/flutter_tools/test/integration.shard/isolated/native_assets_test.dart index 99a7a87846..505f4fdadc 100644 --- a/packages/flutter_tools/test/integration.shard/native_assets_test.dart +++ b/packages/flutter_tools/test/integration.shard/isolated/native_assets_test.dart @@ -21,9 +21,9 @@ import 'package:flutter_tools/src/base/logger.dart'; import 'package:flutter_tools/src/base/os.dart'; import 'package:native_assets_cli/native_assets_cli_internal.dart'; -import '../src/common.dart'; -import 'test_utils.dart' show ProcessResultMatcher, fileSystem, platform; -import 'transition_test_utils.dart'; +import '../../src/common.dart'; +import '../test_utils.dart' show ProcessResultMatcher, fileSystem, platform; +import '../transition_test_utils.dart'; final String hostOs = platform.operatingSystem;