// 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:file/memory.dart'; import 'package:flutter_tools/src/application_package.dart'; import 'package:flutter_tools/src/artifacts.dart'; import 'package:flutter_tools/src/base/file_system.dart'; 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/bundle.dart'; import 'package:flutter_tools/src/bundle_builder.dart'; import 'package:flutter_tools/src/cache.dart'; import 'package:flutter_tools/src/device.dart'; import 'package:flutter_tools/src/preview_device.dart'; import 'package:flutter_tools/src/project.dart'; import 'package:meta/meta.dart'; import 'package:test/fake.dart'; import '../src/common.dart'; import '../src/context.dart'; import '../src/fakes.dart'; void main() { String? flutterRootBackup; late MemoryFileSystem fs; late File previewBinary; setUp(() { fs = MemoryFileSystem.test(style: FileSystemStyle.windows); Cache.flutterRoot = r'C:\path\to\flutter'; previewBinary = fs.file('${Cache.flutterRoot}\\bin\\cache\\artifacts\\flutter_preview\\flutter_preview.exe'); previewBinary.createSync(recursive: true); flutterRootBackup = Cache.flutterRoot; }); tearDown(() { Cache.flutterRoot = flutterRootBackup; }); testWithoutContext('PreviewDevice defaults', () async { final PreviewDevice device = PreviewDevice( artifacts: Artifacts.test(), fileSystem: fs, processManager: FakeProcessManager.any(), previewBinary: previewBinary, logger: BufferLogger.test(), ); expect(await device.isLocalEmulator, false); expect(device.name, 'preview'); expect(await device.sdkNameAndVersion, 'preview'); expect(await device.targetPlatform, TargetPlatform.windows_x64); expect(device.category, Category.desktop); expect(device.ephemeral, false); expect(device.id, 'preview'); expect(device.isSupported(), true); expect(device.isSupportedForProject(FakeFlutterProject()), true); expect(await device.isLatestBuildInstalled(FakeApplicationPackage()), false); expect(await device.isAppInstalled(FakeApplicationPackage()), false); expect(await device.uninstallApp(FakeApplicationPackage()), true); }); testUsingContext('Can build a simulator app', () async { final Completer completer = Completer(); final BufferLogger logger = BufferLogger.test(); final PreviewDevice device = PreviewDevice( artifacts: Artifacts.test(), fileSystem: fs, previewBinary: previewBinary, processManager: FakeProcessManager.list([ FakeCommand( command: const [ r'C:\.tmp_rand0\flutter_preview.rand0\flutter_preview.exe', ], stdout: 'The Dart VM service is listening on http://127.0.0.1:64494/fZ_B2N6JRwY=/\n', completer: completer, ), ]), logger: logger, builderFactory: () => FakeBundleBuilder(fs), ); final Directory previewDeviceCacheDir = fs .directory('Artifact.windowsDesktopPath.TargetPlatform.windows_x64.debug') ..createSync(recursive: true); previewDeviceCacheDir.childFile('flutter_windows.dll').writeAsStringSync('1010101'); previewDeviceCacheDir.childFile('icudtl.dat').writeAsStringSync('1010101'); final LaunchResult result = await device.startApp( FakeApplicationPackage(), debuggingOptions: DebuggingOptions.enabled(BuildInfo.debug), ); expect(result.started, true); expect(result.vmServiceUri, Uri.parse('http://127.0.0.1:64494/fZ_B2N6JRwY=/')); }); group('PreviewDeviceDiscovery', () { late Artifacts artifacts; late ProcessManager processManager; final FakePlatform windowsPlatform = FakePlatform(operatingSystem: 'windows'); final FakePlatform macPlatform = FakePlatform(operatingSystem: 'macos'); final FakePlatform linuxPlatform = FakePlatform(); final TestFeatureFlags featureFlags = TestFeatureFlags(isPreviewDeviceEnabled: true); setUp(() { artifacts = Artifacts.test(fileSystem: fs); processManager = FakeProcessManager.empty(); }); testWithoutContext('PreviewDeviceDiscovery on linux', () async { final PreviewDeviceDiscovery discovery = PreviewDeviceDiscovery( artifacts: artifacts, fileSystem: fs, logger: BufferLogger.test(), processManager: processManager, platform: linuxPlatform, featureFlags: featureFlags, ); final List devices = await discovery.devices(); expect(devices, isEmpty); }); testWithoutContext('PreviewDeviceDiscovery on macOS', () async { final PreviewDeviceDiscovery discovery = PreviewDeviceDiscovery( artifacts: artifacts, fileSystem: fs, logger: BufferLogger.test(), processManager: processManager, platform: macPlatform, featureFlags: featureFlags, ); final List devices = await discovery.devices(); expect(devices, isEmpty); }); testWithoutContext('PreviewDeviceDiscovery on Windows returns preview when binary exists', () async { // ensure Flutter preview binary exists in cache. fs.file(artifacts.getArtifactPath(Artifact.flutterPreviewDevice)).writeAsBytesSync([1, 0, 0, 1]); final PreviewDeviceDiscovery discovery = PreviewDeviceDiscovery( artifacts: artifacts, fileSystem: fs, logger: BufferLogger.test(), processManager: processManager, platform: windowsPlatform, featureFlags: featureFlags, ); final List devices = await discovery.devices(); expect(devices, hasLength(1)); final Device previewDevice = devices.first; expect(previewDevice, isA()); }); testWithoutContext('PreviewDeviceDiscovery on Windows returns nothing when binary does not exist', () async { final PreviewDeviceDiscovery discovery = PreviewDeviceDiscovery( artifacts: artifacts, fileSystem: fs, logger: BufferLogger.test(), processManager: processManager, platform: windowsPlatform, featureFlags: featureFlags, ); final List devices = await discovery.devices(); expect(devices, isEmpty); }); }); } class FakeFlutterProject extends Fake implements FlutterProject { } class FakeApplicationPackage extends Fake implements ApplicationPackage { } class FakeBundleBuilder extends Fake implements BundleBuilder { FakeBundleBuilder(this.fileSystem); final FileSystem fileSystem; @override Future build({ required TargetPlatform platform, required BuildInfo buildInfo, FlutterProject? project, String? mainPath, String manifestPath = defaultManifestPath, String? applicationKernelFilePath, String? depfilePath, String? assetDirPath, bool buildNativeAssets = true, @visibleForTesting BuildSystem? buildSystem }) async { final Directory assetDirectory = fileSystem .directory(assetDirPath) .childDirectory('flutter_assets') ..createSync(recursive: true); assetDirectory.childFile('kernel_blob.bin').createSync(); } }