// 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/base/file_system.dart'; import 'package:flutter_tools/src/base/logger.dart'; import 'package:flutter_tools/src/base/os.dart'; import 'package:flutter_tools/src/build_info.dart'; import 'package:flutter_tools/src/desktop_device.dart'; import 'package:flutter_tools/src/device.dart'; import 'package:flutter_tools/src/project.dart'; import 'package:meta/meta.dart'; import 'package:mockito/mockito.dart'; import 'package:process/process.dart'; import '../src/common.dart'; import '../src/context.dart'; void main() { group('Basic info', () { testWithoutContext('Category is desktop', () async { final FakeDesktopDevice device = setUpDesktopDevice(); expect(device.category, Category.desktop); }); testWithoutContext('Not an emulator', () async { final FakeDesktopDevice device = setUpDesktopDevice(); expect(await device.isLocalEmulator, false); expect(await device.emulatorId, null); }); testWithoutContext('Uses OS name as SDK name', () async { final FakeDesktopDevice device = setUpDesktopDevice(); expect(await device.sdkNameAndVersion, 'Example'); }); }); group('Install', () { testWithoutContext('Install checks always return true', () async { final FakeDesktopDevice device = setUpDesktopDevice(); expect(await device.isAppInstalled(null), true); expect(await device.isLatestBuildInstalled(null), true); expect(device.category, Category.desktop); }); testWithoutContext('Install and uninstall are no-ops that report success', () async { final FakeDesktopDevice device = setUpDesktopDevice(); final FakeAppplicationPackage package = FakeAppplicationPackage(); expect(await device.uninstallApp(package), true); expect(await device.isAppInstalled(package), true); expect(await device.isLatestBuildInstalled(package), true); expect(await device.installApp(package), true); expect(await device.isAppInstalled(package), true); expect(await device.isLatestBuildInstalled(package), true); expect(device.category, Category.desktop); }); }); group('Starting and stopping application', () { testWithoutContext('Stop without start is a successful no-op', () async { final FakeDesktopDevice device = setUpDesktopDevice(); final FakeAppplicationPackage package = FakeAppplicationPackage(); expect(await device.stopApp(package), true); }); testWithoutContext('Can run from prebuilt application', () async { final FileSystem fileSystem = MemoryFileSystem.test(); final Completer completer = Completer(); final FakeProcessManager processManager = FakeProcessManager.list([ FakeCommand( command: const ['null'], stdout: 'Observatory listening on http://127.0.0.1/0\n', completer: completer, ), ]); final FakeDesktopDevice device = setUpDesktopDevice(processManager: processManager, fileSystem: fileSystem); final String executableName = device.executablePathForDevice(null, BuildMode.debug); fileSystem.file(executableName).writeAsStringSync('\n'); final FakeAppplicationPackage package = FakeAppplicationPackage(); final LaunchResult result = await device.startApp(package, prebuiltApplication: true); expect(result.started, true); expect(result.observatoryUri, Uri.parse('http://127.0.0.1/0')); }); testWithoutContext('Null executable path fails gracefully', () async { final BufferLogger logger = BufferLogger.test(); final DesktopDevice device = setUpDesktopDevice(nullExecutablePathForDevice: true, logger: logger); final FakeAppplicationPackage package = FakeAppplicationPackage(); final LaunchResult result = await device.startApp(package, prebuiltApplication: true); expect(result.started, false); expect(logger.errorText, contains('Unable to find executable to run')); }); testWithoutContext('stopApp kills process started by startApp', () async { final Completer completer = Completer(); final FakeProcessManager processManager = FakeProcessManager.list([ FakeCommand( command: const ['null'], stdout: 'Observatory listening on http://127.0.0.1/0\n', completer: completer, ), ]); final FakeDesktopDevice device = setUpDesktopDevice(processManager: processManager); final FakeAppplicationPackage package = FakeAppplicationPackage(); final LaunchResult result = await device.startApp(package, prebuiltApplication: true); expect(result.started, true); expect(await device.stopApp(package), true); }); }); testWithoutContext('Port forwarder is a no-op', () async { final FakeDesktopDevice device = setUpDesktopDevice(); final DevicePortForwarder portForwarder = device.portForwarder; final int result = await portForwarder.forward(2); expect(result, 2); expect(portForwarder.forwardedPorts.isEmpty, true); }); } FakeDesktopDevice setUpDesktopDevice({ FileSystem fileSystem, Logger logger, ProcessManager processManager, OperatingSystemUtils operatingSystemUtils, bool nullExecutablePathForDevice = false, }) { return FakeDesktopDevice( fileSystem: fileSystem ?? MemoryFileSystem.test(), logger: logger ?? BufferLogger.test(), processManager: processManager ?? FakeProcessManager.any(), operatingSystemUtils: operatingSystemUtils ?? FakeOperatingSystemUtils(), nullExecutablePathForDevice: nullExecutablePathForDevice, ); } /// A trivial subclass of DesktopDevice for testing the shared functionality. class FakeDesktopDevice extends DesktopDevice { FakeDesktopDevice({ @required ProcessManager processManager, @required Logger logger, @required FileSystem fileSystem, @required OperatingSystemUtils operatingSystemUtils, this.nullExecutablePathForDevice, }) : super( 'dummy', platformType: PlatformType.linux, ephemeral: false, processManager: processManager, logger: logger, fileSystem: fileSystem, operatingSystemUtils: operatingSystemUtils, ); /// The [mainPath] last passed to [buildForDevice]. String lastBuiltMainPath; /// The [buildInfo] last passed to [buildForDevice]. BuildInfo lastBuildInfo; final bool nullExecutablePathForDevice; @override String get name => 'dummy'; @override Future get targetPlatform async => TargetPlatform.tester; @override bool isSupported() => true; @override bool isSupportedForProject(FlutterProject flutterProject) => true; @override Future buildForDevice( ApplicationPackage package, { String mainPath, BuildInfo buildInfo, }) async { lastBuiltMainPath = mainPath; lastBuildInfo = buildInfo; } // Dummy implementation that just returns the build mode name. @override String executablePathForDevice(ApplicationPackage package, BuildMode buildMode) { if (nullExecutablePathForDevice) { return null; } return buildMode == null ? 'null' : getNameForBuildMode(buildMode); } } class FakeAppplicationPackage extends Fake implements ApplicationPackage {} class FakeOperatingSystemUtils extends Fake implements OperatingSystemUtils { @override String get name => 'Example'; }