Unverified Commit 8a31a3a2 authored by Christopher Fujino's avatar Christopher Fujino Committed by GitHub

Flutter preview device (#135639)

Fixes https://github.com/flutter/flutter/issues/130277

This PR does two things:

1. introduce a hidden `flutter build _preview` command, that will build a debug windows desktop app and copy it into the SDK's binary cache. This command is only intended to be run during packaging.
2. introduce a new device type, called `PreviewDevice`, which relies on the prebuilt desktop debug app from step 1, copies it into the target app's assets build folder, and then hot reloads their dart code into it.
parent 492b6f7d
...@@ -173,9 +173,11 @@ List<FlutterCommand> generateCommands({ ...@@ -173,9 +173,11 @@ List<FlutterCommand> generateCommands({
fileSystem: globals.fs, fileSystem: globals.fs,
), ),
BuildCommand( BuildCommand(
artifacts: globals.artifacts!,
fileSystem: globals.fs, fileSystem: globals.fs,
buildSystem: globals.buildSystem, buildSystem: globals.buildSystem,
osUtils: globals.os, osUtils: globals.os,
processUtils: globals.processUtils,
verboseHelp: verboseHelp, verboseHelp: verboseHelp,
androidSdk: globals.androidSdk, androidSdk: globals.androidSdk,
logger: globals.logger, logger: globals.logger,
......
...@@ -69,6 +69,9 @@ enum Artifact { ...@@ -69,6 +69,9 @@ enum Artifact {
/// The location of file generators. /// The location of file generators.
flutterToolsFileGenerators, flutterToolsFileGenerators,
/// Pre-built desktop debug app.
flutterPreviewDevice,
} }
/// A subset of [Artifact]s that are platform and build mode independent /// A subset of [Artifact]s that are platform and build mode independent
...@@ -213,6 +216,8 @@ String? _artifactToFileName(Artifact artifact, Platform hostPlatform, [ BuildMod ...@@ -213,6 +216,8 @@ String? _artifactToFileName(Artifact artifact, Platform hostPlatform, [ BuildMod
return 'const_finder.dart.snapshot'; return 'const_finder.dart.snapshot';
case Artifact.flutterToolsFileGenerators: case Artifact.flutterToolsFileGenerators:
return ''; return '';
case Artifact.flutterPreviewDevice:
return 'flutter_preview$exe';
} }
} }
...@@ -573,6 +578,7 @@ class CachedArtifacts implements Artifacts { ...@@ -573,6 +578,7 @@ class CachedArtifacts implements Artifacts {
case Artifact.windowsCppClientWrapper: case Artifact.windowsCppClientWrapper:
case Artifact.windowsDesktopPath: case Artifact.windowsDesktopPath:
case Artifact.flutterToolsFileGenerators: case Artifact.flutterToolsFileGenerators:
case Artifact.flutterPreviewDevice:
return _getHostArtifactPath(artifact, platform, mode); return _getHostArtifactPath(artifact, platform, mode);
} }
} }
...@@ -612,6 +618,7 @@ class CachedArtifacts implements Artifacts { ...@@ -612,6 +618,7 @@ class CachedArtifacts implements Artifacts {
case Artifact.windowsCppClientWrapper: case Artifact.windowsCppClientWrapper:
case Artifact.windowsDesktopPath: case Artifact.windowsDesktopPath:
case Artifact.flutterToolsFileGenerators: case Artifact.flutterToolsFileGenerators:
case Artifact.flutterPreviewDevice:
return _getHostArtifactPath(artifact, platform, mode); return _getHostArtifactPath(artifact, platform, mode);
} }
} }
...@@ -663,6 +670,7 @@ class CachedArtifacts implements Artifacts { ...@@ -663,6 +670,7 @@ class CachedArtifacts implements Artifacts {
case Artifact.windowsCppClientWrapper: case Artifact.windowsCppClientWrapper:
case Artifact.windowsDesktopPath: case Artifact.windowsDesktopPath:
case Artifact.flutterToolsFileGenerators: case Artifact.flutterToolsFileGenerators:
case Artifact.flutterPreviewDevice:
return _getHostArtifactPath(artifact, platform, mode); return _getHostArtifactPath(artifact, platform, mode);
} }
} }
...@@ -745,6 +753,9 @@ class CachedArtifacts implements Artifacts { ...@@ -745,6 +753,9 @@ class CachedArtifacts implements Artifacts {
throw StateError('Artifact $artifact not available for platform $platform.'); throw StateError('Artifact $artifact not available for platform $platform.');
case Artifact.flutterToolsFileGenerators: case Artifact.flutterToolsFileGenerators:
return _getFileGeneratorsPath(); return _getFileGeneratorsPath();
case Artifact.flutterPreviewDevice:
assert(platform == TargetPlatform.windows_x64);
return _cache.getArtifactDirectory('flutter_preview').childFile('flutter_preview.exe').path;
} }
} }
...@@ -1016,6 +1027,8 @@ class CachedLocalEngineArtifacts implements Artifacts { ...@@ -1016,6 +1027,8 @@ class CachedLocalEngineArtifacts implements Artifacts {
return _fileSystem.path.join(_getDartSdkPath(), 'bin', 'utils', artifactFileName); return _fileSystem.path.join(_getDartSdkPath(), 'bin', 'utils', artifactFileName);
case Artifact.flutterToolsFileGenerators: case Artifact.flutterToolsFileGenerators:
return _getFileGeneratorsPath(); return _getFileGeneratorsPath();
case Artifact.flutterPreviewDevice:
throw UnimplementedError('The preview device is not supported with local engine builds');
} }
} }
...@@ -1118,7 +1131,6 @@ class CachedLocalWebSdkArtifacts implements Artifacts { ...@@ -1118,7 +1131,6 @@ class CachedLocalWebSdkArtifacts implements Artifacts {
_platform = platform, _platform = platform,
_operatingSystemUtils = operatingSystemUtils; _operatingSystemUtils = operatingSystemUtils;
final Artifacts _parent; final Artifacts _parent;
final String _webSdkPath; final String _webSdkPath;
final FileSystem _fileSystem; final FileSystem _fileSystem;
...@@ -1169,6 +1181,7 @@ class CachedLocalWebSdkArtifacts implements Artifacts { ...@@ -1169,6 +1181,7 @@ class CachedLocalWebSdkArtifacts implements Artifacts {
case Artifact.fontSubset: case Artifact.fontSubset:
case Artifact.constFinder: case Artifact.constFinder:
case Artifact.flutterToolsFileGenerators: case Artifact.flutterToolsFileGenerators:
case Artifact.flutterPreviewDevice:
break; break;
} }
} }
......
...@@ -5,11 +5,14 @@ ...@@ -5,11 +5,14 @@
import 'package:meta/meta.dart'; import 'package:meta/meta.dart';
import '../android/android_sdk.dart'; import '../android/android_sdk.dart';
import '../artifacts.dart';
import '../base/file_system.dart'; import '../base/file_system.dart';
import '../base/logger.dart'; import '../base/logger.dart';
import '../base/os.dart'; import '../base/os.dart';
import '../base/process.dart';
import '../build_info.dart'; import '../build_info.dart';
import '../build_system/build_system.dart'; import '../build_system/build_system.dart';
import '../cache.dart';
import '../commands/build_linux.dart'; import '../commands/build_linux.dart';
import '../commands/build_macos.dart'; import '../commands/build_macos.dart';
import '../commands/build_windows.dart'; import '../commands/build_windows.dart';
...@@ -21,15 +24,18 @@ import 'build_bundle.dart'; ...@@ -21,15 +24,18 @@ import 'build_bundle.dart';
import 'build_ios.dart'; import 'build_ios.dart';
import 'build_ios_framework.dart'; import 'build_ios_framework.dart';
import 'build_macos_framework.dart'; import 'build_macos_framework.dart';
import 'build_preview.dart';
import 'build_web.dart'; import 'build_web.dart';
class BuildCommand extends FlutterCommand { class BuildCommand extends FlutterCommand {
BuildCommand({ BuildCommand({
required Artifacts artifacts,
required FileSystem fileSystem, required FileSystem fileSystem,
required BuildSystem buildSystem, required BuildSystem buildSystem,
required OperatingSystemUtils osUtils, required OperatingSystemUtils osUtils,
required Logger logger, required Logger logger,
required AndroidSdk? androidSdk, required AndroidSdk? androidSdk,
required ProcessUtils processUtils,
bool verboseHelp = false, bool verboseHelp = false,
}){ }){
_addSubcommand( _addSubcommand(
...@@ -67,6 +73,14 @@ class BuildCommand extends FlutterCommand { ...@@ -67,6 +73,14 @@ class BuildCommand extends FlutterCommand {
verboseHelp: verboseHelp verboseHelp: verboseHelp
)); ));
_addSubcommand(BuildWindowsCommand(logger: logger, verboseHelp: verboseHelp)); _addSubcommand(BuildWindowsCommand(logger: logger, verboseHelp: verboseHelp));
_addSubcommand(BuildPreviewCommand(
artifacts: artifacts,
flutterRoot: Cache.flutterRoot!,
fs: fileSystem,
logger: logger,
processUtils: processUtils,
verboseHelp: verboseHelp,
));
} }
void _addSubcommand(BuildSubCommand command) { void _addSubcommand(BuildSubCommand command) {
...@@ -90,14 +104,15 @@ class BuildCommand extends FlutterCommand { ...@@ -90,14 +104,15 @@ class BuildCommand extends FlutterCommand {
abstract class BuildSubCommand extends FlutterCommand { abstract class BuildSubCommand extends FlutterCommand {
BuildSubCommand({ BuildSubCommand({
required Logger logger, required this.logger,
required bool verboseHelp required bool verboseHelp
}): _logger = logger { }) {
requiresPubspecYaml(); requiresPubspecYaml();
usesFatalWarningsOption(verboseHelp: verboseHelp); usesFatalWarningsOption(verboseHelp: verboseHelp);
} }
final Logger _logger; @protected
final Logger logger;
@override @override
bool get reportNullSafety => true; bool get reportNullSafety => true;
...@@ -111,15 +126,15 @@ abstract class BuildSubCommand extends FlutterCommand { ...@@ -111,15 +126,15 @@ abstract class BuildSubCommand extends FlutterCommand {
@protected @protected
void displayNullSafetyMode(BuildInfo buildInfo) { void displayNullSafetyMode(BuildInfo buildInfo) {
if (buildInfo.nullSafetyMode != NullSafetyMode.sound) { if (buildInfo.nullSafetyMode != NullSafetyMode.sound) {
_logger.printStatus(''); logger.printStatus('');
_logger.printStatus( logger.printStatus(
'Building without sound null safety ⚠️', 'Building without sound null safety ⚠️',
emphasis: true, emphasis: true,
); );
_logger.printStatus( logger.printStatus(
'Dart 3 will only support sound null safety, see https://dart.dev/null-safety', 'Dart 3 will only support sound null safety, see https://dart.dev/null-safety',
); );
} }
_logger.printStatus(''); logger.printStatus('');
} }
} }
// 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/file.dart';
import '../artifacts.dart';
import '../base/common.dart';
import '../base/io.dart';
import '../base/process.dart';
import '../build_info.dart';
import '../cache.dart';
import '../globals.dart' as globals;
import '../project.dart';
import '../runner/flutter_command.dart' show FlutterCommandResult;
import '../windows/build_windows.dart';
import 'build.dart';
class BuildPreviewCommand extends BuildSubCommand {
BuildPreviewCommand({
required super.logger,
required bool verboseHelp,
required this.fs,
required this.flutterRoot,
required this.processUtils,
required this.artifacts,
}) : super(verboseHelp: verboseHelp) {
addCommonDesktopBuildOptions(verboseHelp: verboseHelp);
}
@override
final String name = '_preview';
@override
final bool hidden = true;
@override
Future<Set<DevelopmentArtifact>> get requiredArtifacts async => <DevelopmentArtifact>{
DevelopmentArtifact.windows,
};
@override
final String description = 'Build Flutter preview (desktop) app.';
final FileSystem fs;
final String flutterRoot;
final ProcessUtils processUtils;
final Artifacts artifacts;
static const BuildInfo buildInfo = BuildInfo(
BuildMode.debug,
null, // no flavor
// users may add icons later
treeShakeIcons: false,
);
@override
void requiresPubspecYaml() {}
static const String appName = 'flutter_preview';
@override
Future<FlutterCommandResult> runCommand() async {
if (!globals.platform.isWindows) {
throwToolExit('"build _preview" is currently only supported on Windows hosts.');
}
final Directory targetDir = fs.systemTempDirectory.createTempSync('flutter-build-preview');
try {
final FlutterProject flutterProject = await _createProject(targetDir);
await buildWindows(
flutterProject.windows,
buildInfo,
);
final File previewDevice = targetDir
.childDirectory(getWindowsBuildDirectory(TargetPlatform.windows_x64))
.childDirectory('runner')
.childDirectory('Debug')
.childFile('$appName.exe');
if (!previewDevice.existsSync()) {
throw StateError('Preview device not found at ${previewDevice.absolute.path}');
}
final String newPath = artifacts.getArtifactPath(Artifact.flutterPreviewDevice);
fs.file(newPath).parent.createSync(recursive: true);
previewDevice.copySync(newPath);
return FlutterCommandResult.success();
} finally {
try {
targetDir.deleteSync(recursive: true);
} on FileSystemException catch (exception) {
logger.printError('Failed to delete ${targetDir.path}\n\n$exception');
}
}
}
Future<FlutterProject> _createProject(Directory targetDir) async {
final List<String> cmd = <String>[
fs.path.join(flutterRoot, 'bin', 'flutter.bat'),
'create',
'--empty',
'--project-name',
'flutter_preview',
targetDir.path,
];
final RunResult result = await processUtils.run(
cmd,
allowReentrantFlutter: true,
);
if (result.exitCode != 0) {
final StringBuffer buffer = StringBuffer('${cmd.join(' ')} exited with code ${result.exitCode}\n');
buffer.writeln('stdout:\n${result.stdout}\n');
buffer.writeln('stderr:\n${result.stderr}');
throw ProcessException(cmd.first, cmd.sublist(1), buffer.toString(), result.exitCode);
}
return FlutterProject.fromDirectory(targetDir);
}
}
...@@ -53,6 +53,9 @@ abstract class FeatureFlags { ...@@ -53,6 +53,9 @@ abstract class FeatureFlags {
/// Whether native assets compilation and bundling is enabled. /// Whether native assets compilation and bundling is enabled.
bool get isNativeAssetsEnabled => false; bool get isNativeAssetsEnabled => false;
/// Whether native assets compilation and bundling is enabled.
bool get isPreviewDeviceEnabled => true;
/// Whether a particular feature is enabled for the current channel. /// Whether a particular feature is enabled for the current channel.
/// ///
/// Prefer using one of the specific getters above instead of this API. /// Prefer using one of the specific getters above instead of this API.
...@@ -72,6 +75,7 @@ const List<Feature> allFeatures = <Feature>[ ...@@ -72,6 +75,7 @@ const List<Feature> allFeatures = <Feature>[
flutterWebWasm, flutterWebWasm,
cliAnimation, cliAnimation,
nativeAssets, nativeAssets,
previewDevice,
]; ];
/// All current Flutter feature flags that can be configured. /// All current Flutter feature flags that can be configured.
...@@ -172,6 +176,19 @@ const Feature nativeAssets = Feature( ...@@ -172,6 +176,19 @@ const Feature nativeAssets = Feature(
), ),
); );
/// Enable Flutter preview prebuilt device.
const Feature previewDevice = Feature(
name: 'Flutter preview prebuilt device',
configSetting: 'enable-flutter-preview',
environmentOverride: 'FLUTTER_PREVIEW_DEVICE',
master: FeatureChannelSetting(
available: true,
),
beta: FeatureChannelSetting(
available: true,
),
);
/// A [Feature] is a process for conditionally enabling tool features. /// A [Feature] is a process for conditionally enabling tool features.
/// ///
/// All settings are optional, and if not provided will generally default to /// All settings are optional, and if not provided will generally default to
......
...@@ -27,6 +27,7 @@ import 'macos/macos_device.dart'; ...@@ -27,6 +27,7 @@ import 'macos/macos_device.dart';
import 'macos/macos_ipad_device.dart'; import 'macos/macos_ipad_device.dart';
import 'macos/macos_workflow.dart'; import 'macos/macos_workflow.dart';
import 'macos/xcdevice.dart'; import 'macos/xcdevice.dart';
import 'preview_device.dart';
import 'tester/flutter_tester.dart'; import 'tester/flutter_tester.dart';
import 'version.dart'; import 'version.dart';
import 'web/web_device.dart'; import 'web/web_device.dart';
...@@ -104,6 +105,14 @@ class FlutterDeviceManager extends DeviceManager { ...@@ -104,6 +105,14 @@ class FlutterDeviceManager extends DeviceManager {
fileSystem: fileSystem, fileSystem: fileSystem,
operatingSystemUtils: operatingSystemUtils, operatingSystemUtils: operatingSystemUtils,
), ),
PreviewDeviceDiscovery(
platform: platform,
artifacts: artifacts,
fileSystem: fileSystem,
logger: logger,
processManager: processManager,
featureFlags: featureFlags,
),
LinuxDevices( LinuxDevices(
platform: platform, platform: platform,
featureFlags: featureFlags, featureFlags: featureFlags,
......
...@@ -58,6 +58,9 @@ class FlutterFeatureFlags implements FeatureFlags { ...@@ -58,6 +58,9 @@ class FlutterFeatureFlags implements FeatureFlags {
@override @override
bool get isNativeAssetsEnabled => isEnabled(nativeAssets); bool get isNativeAssetsEnabled => isEnabled(nativeAssets);
@override
bool get isPreviewDeviceEnabled => isEnabled(previewDevice);
@override @override
bool isEnabled(Feature feature) { bool isEnabled(Feature feature) {
final String currentChannel = _flutterVersion.channel; final String currentChannel = _flutterVersion.channel;
......
...@@ -8,17 +8,18 @@ import 'package:meta/meta.dart'; ...@@ -8,17 +8,18 @@ import 'package:meta/meta.dart';
import 'package:process/process.dart'; import 'package:process/process.dart';
import 'application_package.dart'; import 'application_package.dart';
import 'artifacts.dart';
import 'base/file_system.dart'; import 'base/file_system.dart';
import 'base/io.dart'; import 'base/io.dart';
import 'base/logger.dart'; import 'base/logger.dart';
import 'base/platform.dart'; import 'base/platform.dart';
import 'build_info.dart'; import 'build_info.dart';
import 'bundle_builder.dart'; import 'bundle_builder.dart';
import 'cache.dart';
import 'desktop_device.dart'; import 'desktop_device.dart';
import 'devfs.dart'; import 'devfs.dart';
import 'device.dart'; import 'device.dart';
import 'device_port_forwarder.dart'; import 'device_port_forwarder.dart';
import 'features.dart';
import 'project.dart'; import 'project.dart';
import 'protocol_discovery.dart'; import 'protocol_discovery.dart';
...@@ -28,30 +29,99 @@ BundleBuilder _defaultBundleBuilder() { ...@@ -28,30 +29,99 @@ BundleBuilder _defaultBundleBuilder() {
return BundleBuilder(); return BundleBuilder();
} }
class PreviewDeviceDiscovery extends DeviceDiscovery {
PreviewDeviceDiscovery({
required Platform platform,
required Artifacts artifacts,
required FileSystem fileSystem,
required Logger logger,
required ProcessManager processManager,
required FeatureFlags featureFlags,
}) : _artifacts = artifacts,
_logger = logger,
_processManager = processManager,
_fileSystem = fileSystem,
_platform = platform,
_features = featureFlags;
final Platform _platform;
final Artifacts _artifacts;
final Logger _logger;
final ProcessManager _processManager;
final FileSystem _fileSystem;
final FeatureFlags _features;
@override
bool get canListAnything => _platform.isWindows;
@override
bool get supportsPlatform => _platform.isWindows;
@override
List<String> get wellKnownIds => <String>['preview'];
@override
Future<List<Device>> devices({
Duration? timeout,
DeviceDiscoveryFilter? filter,
}) async {
final File previewBinary = _fileSystem.file(_artifacts.getArtifactPath(Artifact.flutterPreviewDevice));
if (!previewBinary.existsSync()) {
return const <Device>[];
}
final PreviewDevice device = PreviewDevice(
artifacts: _artifacts,
fileSystem: _fileSystem,
logger: _logger,
processManager: _processManager,
previewBinary: previewBinary,
);
final bool matchesRequirements;
if (!_features.isPreviewDeviceEnabled) {
matchesRequirements = false;
} else if (filter == null) {
matchesRequirements = true;
} else {
matchesRequirements = await filter.matchesRequirements(device);
}
return <Device>[
if (matchesRequirements)
device,
];
}
@override
Future<List<Device>> discoverDevices({
Duration? timeout,
DeviceDiscoveryFilter? filter,
}) {
return devices();
}
}
/// A device type that runs a prebuilt desktop binary alongside a locally compiled kernel file. /// A device type that runs a prebuilt desktop binary alongside a locally compiled kernel file.
///
/// This could be used to support debug local development without plugins on machines that
/// have not completed the SDK setup. These features are not fully implemented and the
/// device is not currently discoverable.
class PreviewDevice extends Device { class PreviewDevice extends Device {
PreviewDevice({ PreviewDevice({
required Platform platform,
required ProcessManager processManager, required ProcessManager processManager,
required Logger logger, required Logger logger,
required FileSystem fileSystem, required FileSystem fileSystem,
required Artifacts artifacts,
required File previewBinary,
@visibleForTesting BundleBuilderFactory builderFactory = _defaultBundleBuilder, @visibleForTesting BundleBuilderFactory builderFactory = _defaultBundleBuilder,
}) : _platform = platform, }) : _previewBinary = previewBinary,
_processManager = processManager, _processManager = processManager,
_logger = logger, _logger = logger,
_fileSystem = fileSystem, _fileSystem = fileSystem,
_bundleBuilderFactory = builderFactory, _bundleBuilderFactory = builderFactory,
_artifacts = artifacts,
super('preview', ephemeral: false, category: Category.desktop, platformType: PlatformType.custom); super('preview', ephemeral: false, category: Category.desktop, platformType: PlatformType.custom);
final Platform _platform;
final ProcessManager _processManager; final ProcessManager _processManager;
final Logger _logger; final Logger _logger;
final FileSystem _fileSystem; final FileSystem _fileSystem;
final BundleBuilderFactory _bundleBuilderFactory; final BundleBuilderFactory _bundleBuilderFactory;
final Artifacts _artifacts;
final File _previewBinary;
@override @override
void clearLogs() { } void clearLogs() { }
...@@ -116,7 +186,7 @@ class PreviewDevice extends Device { ...@@ -116,7 +186,7 @@ class PreviewDevice extends Device {
await _bundleBuilderFactory().build( await _bundleBuilderFactory().build(
buildInfo: debuggingOptions.buildInfo, buildInfo: debuggingOptions.buildInfo,
mainPath: mainPath, mainPath: mainPath,
platform: TargetPlatform.tester, platform: TargetPlatform.windows_x64,
assetDirPath: getAssetBuildDirectory(), assetDirPath: getAssetBuildDirectory(),
); );
copyDirectory(_fileSystem.directory( copyDirectory(_fileSystem.directory(
...@@ -128,13 +198,18 @@ class PreviewDevice extends Device { ...@@ -128,13 +198,18 @@ class PreviewDevice extends Device {
} }
// Merge with precompiled executable. // Merge with precompiled executable.
final Directory precompiledDirectory = _fileSystem.directory(_fileSystem.path.join(Cache.flutterRoot!, 'artifacts_temp', 'Debug')); final String copiedPreviewBinaryPath = assetDirectory.childFile(_previewBinary.basename).path;
copyDirectory(precompiledDirectory, assetDirectory); _previewBinary.copySync(copiedPreviewBinaryPath);
final String windowsPath = _artifacts
.getArtifactPath(Artifact.windowsDesktopPath, platform: TargetPlatform.windows_x64, mode: BuildMode.debug);
final File windowsDll = _fileSystem.file(_fileSystem.path.join(windowsPath, 'flutter_windows.dll'));
final File icu = _fileSystem.file(_fileSystem.path.join(windowsPath, 'icudtl.dat'));
windowsDll.copySync(assetDirectory.childFile('flutter_windows.dll').path);
icu.copySync(assetDirectory.childDirectory('data').childFile('icudtl.dat').path);
final Process process = await _processManager.start( final Process process = await _processManager.start(
<String>[ <String>[copiedPreviewBinaryPath],
assetDirectory.childFile('splash').path,
],
); );
_process = process; _process = process;
_logReader.initializeProcess(process); _logReader.initializeProcess(process);
...@@ -169,10 +244,7 @@ class PreviewDevice extends Device { ...@@ -169,10 +244,7 @@ class PreviewDevice extends Device {
@override @override
Future<TargetPlatform> get targetPlatform async { Future<TargetPlatform> get targetPlatform async {
if (_platform.isWindows) { return TargetPlatform.windows_x64;
return TargetPlatform.windows_x64;
}
return TargetPlatform.tester;
} }
@override @override
......
...@@ -56,9 +56,10 @@ Future<void> buildWindows(WindowsProject windowsProject, BuildInfo buildInfo, { ...@@ -56,9 +56,10 @@ Future<void> buildWindows(WindowsProject windowsProject, BuildInfo buildInfo, {
// TODO(pbo-linaro): Add support for windows-arm64 platform, https://github.com/flutter/flutter/issues/129807 // TODO(pbo-linaro): Add support for windows-arm64 platform, https://github.com/flutter/flutter/issues/129807
const TargetPlatform targetPlatform = TargetPlatform.windows_x64; const TargetPlatform targetPlatform = TargetPlatform.windows_x64;
final Directory buildDirectory = globals.fs.directory( final Directory buildDirectory = globals.fs.directory(globals.fs.path.join(
getWindowsBuildDirectory(targetPlatform) projectPath,
); getWindowsBuildDirectory(targetPlatform),
));
final List<ProjectMigrator> migrators = <ProjectMigrator>[ final List<ProjectMigrator> migrators = <ProjectMigrator>[
CmakeCustomCommandMigration(windowsProject, globals.logger), CmakeCustomCommandMigration(windowsProject, globals.logger),
......
...@@ -5,11 +5,13 @@ ...@@ -5,11 +5,13 @@
import 'package:args/command_runner.dart'; import 'package:args/command_runner.dart';
import 'package:file/memory.dart'; import 'package:file/memory.dart';
import 'package:flutter_tools/src/android/android_sdk.dart'; import 'package:flutter_tools/src/android/android_sdk.dart';
import 'package:flutter_tools/src/artifacts.dart';
import 'package:flutter_tools/src/base/common.dart'; import 'package:flutter_tools/src/base/common.dart';
import 'package:flutter_tools/src/base/file_system.dart'; import 'package:flutter_tools/src/base/file_system.dart';
import 'package:flutter_tools/src/base/logger.dart'; import 'package:flutter_tools/src/base/logger.dart';
import 'package:flutter_tools/src/base/os.dart'; import 'package:flutter_tools/src/base/os.dart';
import 'package:flutter_tools/src/base/platform.dart'; import 'package:flutter_tools/src/base/platform.dart';
import 'package:flutter_tools/src/base/process.dart';
import 'package:flutter_tools/src/build_info.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/build_system.dart';
import 'package:flutter_tools/src/cache.dart'; import 'package:flutter_tools/src/cache.dart';
...@@ -30,7 +32,6 @@ import '../../src/test_build_system.dart'; ...@@ -30,7 +32,6 @@ import '../../src/test_build_system.dart';
import '../../src/test_flutter_command_runner.dart'; import '../../src/test_flutter_command_runner.dart';
class FakeXcodeProjectInterpreterWithBuildSettings extends FakeXcodeProjectInterpreter { class FakeXcodeProjectInterpreterWithBuildSettings extends FakeXcodeProjectInterpreter {
FakeXcodeProjectInterpreterWithBuildSettings({this.productBundleIdentifier, this.developmentTeam = 'abc'}); FakeXcodeProjectInterpreterWithBuildSettings({this.productBundleIdentifier, this.developmentTeam = 'abc'});
@override @override
...@@ -69,6 +70,10 @@ final Platform notMacosPlatform = FakePlatform( ...@@ -69,6 +70,10 @@ final Platform notMacosPlatform = FakePlatform(
void main() { void main() {
late FileSystem fileSystem; late FileSystem fileSystem;
late TestUsage usage; late TestUsage usage;
late BufferLogger logger;
late FakeProcessManager processManager;
late ProcessUtils processUtils;
late Artifacts artifacts;
setUpAll(() { setUpAll(() {
Cache.disableLocking(); Cache.disableLocking();
...@@ -76,7 +81,14 @@ void main() { ...@@ -76,7 +81,14 @@ void main() {
setUp(() { setUp(() {
fileSystem = MemoryFileSystem.test(); fileSystem = MemoryFileSystem.test();
artifacts = Artifacts.test(fileSystem: fileSystem);
usage = TestUsage(); usage = TestUsage();
logger = BufferLogger.test();
processManager = FakeProcessManager.empty();
processUtils = ProcessUtils(
logger: logger,
processManager: processManager,
);
}); });
// Sets up the minimal mock project files necessary to look like a Flutter project. // Sets up the minimal mock project files necessary to look like a Flutter project.
...@@ -192,10 +204,12 @@ void main() { ...@@ -192,10 +204,12 @@ void main() {
testUsingContext('ios build fails when there is no ios project', () async { testUsingContext('ios build fails when there is no ios project', () async {
final BuildCommand command = BuildCommand( final BuildCommand command = BuildCommand(
artifacts: artifacts,
androidSdk: FakeAndroidSdk(), androidSdk: FakeAndroidSdk(),
buildSystem: TestBuildSystem.all(BuildResult(success: true)), buildSystem: TestBuildSystem.all(BuildResult(success: true)),
fileSystem: MemoryFileSystem.test(), fileSystem: fileSystem,
logger: BufferLogger.test(), logger: logger,
processUtils: processUtils,
osUtils: FakeOperatingSystemUtils(), osUtils: FakeOperatingSystemUtils(),
); );
createCoreMockProjectFiles(); createCoreMockProjectFiles();
...@@ -206,16 +220,18 @@ void main() { ...@@ -206,16 +220,18 @@ void main() {
}, overrides: <Type, Generator>{ }, overrides: <Type, Generator>{
Platform: () => macosPlatform, Platform: () => macosPlatform,
FileSystem: () => fileSystem, FileSystem: () => fileSystem,
ProcessManager: () => FakeProcessManager.any(), ProcessManager: () => processManager,
XcodeProjectInterpreter: () => FakeXcodeProjectInterpreterWithBuildSettings(), XcodeProjectInterpreter: () => FakeXcodeProjectInterpreterWithBuildSettings(),
}); });
testUsingContext('ios build fails in debug with code analysis', () async { testUsingContext('ios build fails in debug with code analysis', () async {
final BuildCommand command = BuildCommand( final BuildCommand command = BuildCommand(
artifacts: artifacts,
androidSdk: FakeAndroidSdk(), androidSdk: FakeAndroidSdk(),
buildSystem: TestBuildSystem.all(BuildResult(success: true)), buildSystem: TestBuildSystem.all(BuildResult(success: true)),
fileSystem: MemoryFileSystem.test(), fileSystem: fileSystem,
logger: BufferLogger.test(), logger: logger,
processUtils: processUtils,
osUtils: FakeOperatingSystemUtils(), osUtils: FakeOperatingSystemUtils(),
); );
createCoreMockProjectFiles(); createCoreMockProjectFiles();
...@@ -226,16 +242,18 @@ void main() { ...@@ -226,16 +242,18 @@ void main() {
}, overrides: <Type, Generator>{ }, overrides: <Type, Generator>{
Platform: () => macosPlatform, Platform: () => macosPlatform,
FileSystem: () => fileSystem, FileSystem: () => fileSystem,
ProcessManager: () => FakeProcessManager.any(), ProcessManager: () => processManager,
XcodeProjectInterpreter: () => FakeXcodeProjectInterpreterWithBuildSettings(), XcodeProjectInterpreter: () => FakeXcodeProjectInterpreterWithBuildSettings(),
}); });
testUsingContext('ios build fails on non-macOS platform', () async { testUsingContext('ios build fails on non-macOS platform', () async {
final BuildCommand command = BuildCommand( final BuildCommand command = BuildCommand(
artifacts: artifacts,
androidSdk: FakeAndroidSdk(), androidSdk: FakeAndroidSdk(),
buildSystem: TestBuildSystem.all(BuildResult(success: true)), buildSystem: TestBuildSystem.all(BuildResult(success: true)),
fileSystem: MemoryFileSystem.test(), fileSystem: fileSystem,
logger: BufferLogger.test(), logger: logger,
processUtils: processUtils,
osUtils: FakeOperatingSystemUtils(), osUtils: FakeOperatingSystemUtils(),
); );
fileSystem.file('pubspec.yaml').createSync(); fileSystem.file('pubspec.yaml').createSync();
...@@ -250,169 +268,175 @@ void main() { ...@@ -250,169 +268,175 @@ void main() {
}, overrides: <Type, Generator>{ }, overrides: <Type, Generator>{
Platform: () => notMacosPlatform, Platform: () => notMacosPlatform,
FileSystem: () => fileSystem, FileSystem: () => fileSystem,
ProcessManager: () => FakeProcessManager.any(), ProcessManager: () => processManager,
XcodeProjectInterpreter: () => FakeXcodeProjectInterpreterWithBuildSettings(), XcodeProjectInterpreter: () => FakeXcodeProjectInterpreterWithBuildSettings(),
}); });
testUsingContext('ios build invokes xcode build', () async { testUsingContext('ios build invokes xcode build', () async {
final BuildCommand command = BuildCommand( final BuildCommand command = BuildCommand(
artifacts: artifacts,
androidSdk: FakeAndroidSdk(), androidSdk: FakeAndroidSdk(),
buildSystem: TestBuildSystem.all(BuildResult(success: true)), buildSystem: TestBuildSystem.all(BuildResult(success: true)),
fileSystem: MemoryFileSystem.test(), fileSystem: fileSystem,
logger: BufferLogger.test(), logger: logger,
processUtils: processUtils,
osUtils: FakeOperatingSystemUtils(), osUtils: FakeOperatingSystemUtils(),
); );
createMinimalMockProjectFiles(); createMinimalMockProjectFiles();
processManager.addCommands(<FakeCommand>[
xattrCommand,
setUpFakeXcodeBuildHandler(onRun: () {
fileSystem.directory('build/ios/Release-iphoneos/Runner.app').createSync(recursive: true);
}),
setUpRsyncCommand(),
]);
await createTestCommandRunner(command).run( await createTestCommandRunner(command).run(
const <String>['build', 'ios', '--no-pub'] const <String>['build', 'ios', '--no-pub']
); );
expect(testLogger.statusText, contains('build/ios/iphoneos/Runner.app')); expect(testLogger.statusText, contains('build/ios/iphoneos/Runner.app'));
}, overrides: <Type, Generator>{ }, overrides: <Type, Generator>{
FileSystem: () => fileSystem, FileSystem: () => fileSystem,
ProcessManager: () => FakeProcessManager.list(<FakeCommand>[ ProcessManager: () => processManager,
xattrCommand,
setUpFakeXcodeBuildHandler(onRun: () {
fileSystem.directory('build/ios/Release-iphoneos/Runner.app').createSync(recursive: true);
}),
setUpRsyncCommand(),
]),
Platform: () => macosPlatform, Platform: () => macosPlatform,
XcodeProjectInterpreter: () => FakeXcodeProjectInterpreterWithBuildSettings(), XcodeProjectInterpreter: () => FakeXcodeProjectInterpreterWithBuildSettings(),
}); });
testUsingContext('ios build invokes xcode build with renamed xcodeproj and xcworkspace', () async { testUsingContext('ios build invokes xcode build with renamed xcodeproj and xcworkspace', () async {
final BuildCommand command = BuildCommand( final BuildCommand command = BuildCommand(
artifacts: artifacts,
androidSdk: FakeAndroidSdk(), androidSdk: FakeAndroidSdk(),
buildSystem: TestBuildSystem.all(BuildResult(success: true)), buildSystem: TestBuildSystem.all(BuildResult(success: true)),
fileSystem: MemoryFileSystem.test(),
logger: BufferLogger.test(),
osUtils: FakeOperatingSystemUtils(), osUtils: FakeOperatingSystemUtils(),
fileSystem: fileSystem,
logger: logger,
processUtils: processUtils,
); );
processManager.addCommands(<FakeCommand>[
xattrCommand,
setUpFakeXcodeBuildHandler(customNaming: true, onRun: () {
fileSystem.directory('build/ios/Release-iphoneos/Runner.app').createSync(recursive: true);
}),
setUpRsyncCommand(),
]);
fileSystem.directory(fileSystem.path.join('ios', 'RenamedProj.xcodeproj')).createSync(recursive: true); fileSystem.directory(fileSystem.path.join('ios', 'RenamedProj.xcodeproj')).createSync(recursive: true);
fileSystem.directory(fileSystem.path.join('ios', 'RenamedWorkspace.xcworkspace')).createSync(recursive: true); fileSystem.directory(fileSystem.path.join('ios', 'RenamedWorkspace.xcworkspace')).createSync(recursive: true);
fileSystem.file(fileSystem.path.join('ios', 'RenamedProj.xcodeproj', 'project.pbxproj')).createSync(); fileSystem.file(fileSystem.path.join('ios', 'RenamedProj.xcodeproj', 'project.pbxproj')).createSync();
createCoreMockProjectFiles(); createCoreMockProjectFiles();
await createTestCommandRunner(command).run( await createTestCommandRunner(command).run(
const <String>['build', 'ios', '--no-pub'] const <String>['build', 'ios', '--no-pub']
); );
expect(testLogger.statusText, contains('build/ios/iphoneos/Runner.app')); expect(testLogger.statusText, contains('build/ios/iphoneos/Runner.app'));
}, overrides: <Type, Generator>{ }, overrides: <Type, Generator>{
FileSystem: () => fileSystem, FileSystem: () => fileSystem,
ProcessManager: () => FakeProcessManager.list(<FakeCommand>[ ProcessManager: () => processManager,
xattrCommand,
setUpFakeXcodeBuildHandler(customNaming: true, onRun: () {
fileSystem.directory('build/ios/Release-iphoneos/Runner.app').createSync(recursive: true);
}),
setUpRsyncCommand(),
]),
Platform: () => macosPlatform, Platform: () => macosPlatform,
XcodeProjectInterpreter: () => FakeXcodeProjectInterpreterWithBuildSettings(), XcodeProjectInterpreter: () => FakeXcodeProjectInterpreterWithBuildSettings(),
}); });
testUsingContext('ios build invokes xcode build with device ID', () async { testUsingContext('ios build invokes xcode build with device ID', () async {
final BuildCommand command = BuildCommand( final BuildCommand command = BuildCommand(
artifacts: artifacts,
androidSdk: FakeAndroidSdk(), androidSdk: FakeAndroidSdk(),
buildSystem: TestBuildSystem.all(BuildResult(success: true)), buildSystem: TestBuildSystem.all(BuildResult(success: true)),
fileSystem: MemoryFileSystem.test(), fileSystem: fileSystem,
logger: BufferLogger.test(), logger: logger,
processUtils: processUtils,
osUtils: FakeOperatingSystemUtils(), osUtils: FakeOperatingSystemUtils(),
); );
processManager.addCommands(<FakeCommand>[
xattrCommand,
setUpFakeXcodeBuildHandler(deviceId: '1234', onRun: () {
fileSystem.directory('build/ios/Release-iphoneos/Runner.app').createSync(recursive: true);
}),
setUpRsyncCommand(),
]);
createMinimalMockProjectFiles(); createMinimalMockProjectFiles();
await createTestCommandRunner(command).run( await createTestCommandRunner(command).run(
const <String>['build', 'ios', '--no-pub', '--device-id', '1234'] const <String>['build', 'ios', '--no-pub', '--device-id', '1234'],
); );
expect(testLogger.statusText, contains('build/ios/iphoneos/Runner.app')); expect(testLogger.statusText, contains('build/ios/iphoneos/Runner.app'));
}, overrides: <Type, Generator>{ }, overrides: <Type, Generator>{
FileSystem: () => fileSystem, FileSystem: () => fileSystem,
ProcessManager: () => FakeProcessManager.list(<FakeCommand>[ ProcessManager: () => processManager,
xattrCommand,
setUpFakeXcodeBuildHandler(deviceId: '1234', onRun: () {
fileSystem.directory('build/ios/Release-iphoneos/Runner.app').createSync(recursive: true);
}),
setUpRsyncCommand(),
]),
Platform: () => macosPlatform, Platform: () => macosPlatform,
XcodeProjectInterpreter: () => FakeXcodeProjectInterpreterWithBuildSettings(), XcodeProjectInterpreter: () => FakeXcodeProjectInterpreterWithBuildSettings(),
}); });
testUsingContext('ios simulator build invokes xcode build', () async { testUsingContext('ios simulator build invokes xcode build', () async {
final BuildCommand command = BuildCommand( final BuildCommand command = BuildCommand(
artifacts: artifacts,
androidSdk: FakeAndroidSdk(), androidSdk: FakeAndroidSdk(),
buildSystem: TestBuildSystem.all(BuildResult(success: true)), buildSystem: TestBuildSystem.all(BuildResult(success: true)),
fileSystem: MemoryFileSystem.test(), fileSystem: fileSystem,
logger: BufferLogger.test(), logger: logger,
processUtils: processUtils,
osUtils: FakeOperatingSystemUtils(), osUtils: FakeOperatingSystemUtils(),
); );
processManager.addCommands(<FakeCommand>[
xattrCommand,
setUpFakeXcodeBuildHandler(simulator: true, onRun: () {
fileSystem.directory('build/ios/Debug-iphonesimulator/Runner.app').createSync(recursive: true);
}),
setUpRsyncCommand(),
]);
createMinimalMockProjectFiles(); createMinimalMockProjectFiles();
await createTestCommandRunner(command).run( await createTestCommandRunner(command).run(
const <String>['build', 'ios', '--simulator', '--no-pub'] const <String>['build', 'ios', '--simulator', '--no-pub'],
); );
}, overrides: <Type, Generator>{ }, overrides: <Type, Generator>{
FileSystem: () => fileSystem, FileSystem: () => fileSystem,
ProcessManager: () => FakeProcessManager.list(<FakeCommand>[ ProcessManager: () => processManager,
xattrCommand,
setUpFakeXcodeBuildHandler(simulator: true, onRun: () {
fileSystem.directory('build/ios/Debug-iphonesimulator/Runner.app').createSync(recursive: true);
}),
setUpRsyncCommand(),
]),
Platform: () => macosPlatform, Platform: () => macosPlatform,
XcodeProjectInterpreter: () => FakeXcodeProjectInterpreterWithBuildSettings(), XcodeProjectInterpreter: () => FakeXcodeProjectInterpreterWithBuildSettings(),
}); });
testUsingContext('ios build invokes xcode build with verbosity', () async { testUsingContext('ios build invokes xcode build with verbosity', () async {
final BuildCommand command = BuildCommand( final BuildCommand command = BuildCommand(
artifacts: artifacts,
androidSdk: FakeAndroidSdk(), androidSdk: FakeAndroidSdk(),
buildSystem: TestBuildSystem.all(BuildResult(success: true)), buildSystem: TestBuildSystem.all(BuildResult(success: true)),
fileSystem: MemoryFileSystem.test(), fileSystem: fileSystem,
logger: BufferLogger.test(), logger: logger,
processUtils: processUtils,
osUtils: FakeOperatingSystemUtils(), osUtils: FakeOperatingSystemUtils(),
); );
createMinimalMockProjectFiles(); createMinimalMockProjectFiles();
processManager.addCommands(<FakeCommand>[
await createTestCommandRunner(command).run(
const <String>['build', 'ios', '--no-pub', '-v']
);
}, overrides: <Type, Generator>{
FileSystem: () => fileSystem,
ProcessManager: () => FakeProcessManager.list(<FakeCommand>[
xattrCommand, xattrCommand,
setUpFakeXcodeBuildHandler(verbose: true, onRun: () { setUpFakeXcodeBuildHandler(verbose: true, onRun: () {
fileSystem.directory('build/ios/Release-iphoneos/Runner.app').createSync(recursive: true); fileSystem.directory('build/ios/Release-iphoneos/Runner.app').createSync(recursive: true);
}), }),
setUpRsyncCommand(), setUpRsyncCommand(),
]), ]);
await createTestCommandRunner(command).run(
const <String>['build', 'ios', '--no-pub', '-v'],
);
}, overrides: <Type, Generator>{
FileSystem: () => fileSystem,
ProcessManager: () => processManager,
Platform: () => macosPlatform, Platform: () => macosPlatform,
XcodeProjectInterpreter: () => FakeXcodeProjectInterpreterWithBuildSettings(), XcodeProjectInterpreter: () => FakeXcodeProjectInterpreterWithBuildSettings(),
}); });
testUsingContext('Performs code size analysis and sends analytics', () async { testUsingContext('Performs code size analysis and sends analytics', () async {
final BuildCommand command = BuildCommand( final BuildCommand command = BuildCommand(
artifacts: artifacts,
androidSdk: FakeAndroidSdk(), androidSdk: FakeAndroidSdk(),
buildSystem: TestBuildSystem.all(BuildResult(success: true)), buildSystem: TestBuildSystem.all(BuildResult(success: true)),
fileSystem: MemoryFileSystem.test(), fileSystem: fileSystem,
logger: BufferLogger.test(), logger: logger,
processUtils: processUtils,
osUtils: FakeOperatingSystemUtils(), osUtils: FakeOperatingSystemUtils(),
); );
createMinimalMockProjectFiles(); processManager.addCommands(<FakeCommand>[
await createTestCommandRunner(command).run(
const <String>['build', 'ios', '--no-pub', '--analyze-size']
);
expect(testLogger.statusText, contains('A summary of your iOS bundle analysis can be found at'));
expect(testLogger.statusText, contains('dart devtools --appSizeBase='));
expect(usage.events, contains(
const TestUsageEvent('code-size-analysis', 'ios'),
));
}, overrides: <Type, Generator>{
FileSystem: () => fileSystem,
ProcessManager: () => FakeProcessManager.list(<FakeCommand>[
xattrCommand, xattrCommand,
setUpFakeXcodeBuildHandler(onRun: () { setUpFakeXcodeBuildHandler(onRun: () {
fileSystem.directory('build/ios/Release-iphoneos/Runner.app').createSync(recursive: true); fileSystem.directory('build/ios/Release-iphoneos/Runner.app').createSync(recursive: true);
...@@ -434,7 +458,22 @@ void main() { ...@@ -434,7 +458,22 @@ void main() {
setUpRsyncCommand(onRun: () => fileSystem.file('build/ios/iphoneos/Runner.app/Frameworks/App.framework/App') setUpRsyncCommand(onRun: () => fileSystem.file('build/ios/iphoneos/Runner.app/Frameworks/App.framework/App')
..createSync(recursive: true) ..createSync(recursive: true)
..writeAsBytesSync(List<int>.generate(10000, (int index) => 0))), ..writeAsBytesSync(List<int>.generate(10000, (int index) => 0))),
]), ]);
createMinimalMockProjectFiles();
await createTestCommandRunner(command).run(
const <String>['build', 'ios', '--no-pub', '--analyze-size']
);
expect(logger.statusText, contains('A summary of your iOS bundle analysis can be found at'));
expect(logger.statusText, contains('dart devtools --appSizeBase='));
expect(usage.events, contains(
const TestUsageEvent('code-size-analysis', 'ios'),
));
}, overrides: <Type, Generator>{
FileSystem: () => fileSystem,
Logger: () => logger,
ProcessManager: () => processManager,
Platform: () => macosPlatform, Platform: () => macosPlatform,
FileSystemUtils: () => FileSystemUtils(fileSystem: fileSystem, platform: macosPlatform), FileSystemUtils: () => FileSystemUtils(fileSystem: fileSystem, platform: macosPlatform),
Usage: () => usage, Usage: () => usage,
...@@ -461,11 +500,13 @@ void main() { ...@@ -461,11 +500,13 @@ void main() {
testUsingContext('Sends an analytics event when Impeller is enabled', () async { testUsingContext('Sends an analytics event when Impeller is enabled', () async {
final BuildCommand command = BuildCommand( final BuildCommand command = BuildCommand(
artifacts: artifacts,
androidSdk: FakeAndroidSdk(), androidSdk: FakeAndroidSdk(),
buildSystem: TestBuildSystem.all(BuildResult(success: true)), buildSystem: TestBuildSystem.all(BuildResult(success: true)),
fileSystem: MemoryFileSystem.test(), fileSystem: MemoryFileSystem.test(),
logger: BufferLogger.test(), logger: BufferLogger.test(),
osUtils: FakeOperatingSystemUtils(), osUtils: FakeOperatingSystemUtils(),
processUtils: processUtils,
); );
createMinimalMockProjectFiles(); createMinimalMockProjectFiles();
...@@ -504,11 +545,13 @@ void main() { ...@@ -504,11 +545,13 @@ void main() {
testUsingContext('Sends an analytics event when Impeller is disabled', () async { testUsingContext('Sends an analytics event when Impeller is disabled', () async {
final BuildCommand command = BuildCommand( final BuildCommand command = BuildCommand(
artifacts: artifacts,
androidSdk: FakeAndroidSdk(), androidSdk: FakeAndroidSdk(),
buildSystem: TestBuildSystem.all(BuildResult(success: true)), buildSystem: TestBuildSystem.all(BuildResult(success: true)),
fileSystem: fileSystem, fileSystem: fileSystem,
logger: BufferLogger.test(), logger: BufferLogger.test(),
osUtils: FakeOperatingSystemUtils(), osUtils: FakeOperatingSystemUtils(),
processUtils: processUtils,
); );
createMinimalMockProjectFiles(); createMinimalMockProjectFiles();
...@@ -570,12 +613,22 @@ void main() { ...@@ -570,12 +613,22 @@ void main() {
group('xcresults device', () { group('xcresults device', () {
testUsingContext('Trace error if xcresult is empty.', () async { testUsingContext('Trace error if xcresult is empty.', () async {
final BuildCommand command = BuildCommand( final BuildCommand command = BuildCommand(
artifacts: artifacts,
androidSdk: FakeAndroidSdk(), androidSdk: FakeAndroidSdk(),
buildSystem: TestBuildSystem.all(BuildResult(success: true)), buildSystem: TestBuildSystem.all(BuildResult(success: true)),
fileSystem: MemoryFileSystem.test(), fileSystem: fileSystem,
logger: BufferLogger.test(), logger: logger,
processUtils: processUtils,
osUtils: FakeOperatingSystemUtils(), osUtils: FakeOperatingSystemUtils(),
); );
processManager.addCommands(<FakeCommand>[
xattrCommand,
setUpFakeXcodeBuildHandler(exitCode: 1, onRun: () {
fileSystem.systemTempDirectory.childDirectory(_xcBundleDirectoryPath).createSync();
}),
setUpXCResultCommand(),
setUpRsyncCommand(),
]);
createMinimalMockProjectFiles(); createMinimalMockProjectFiles();
...@@ -584,29 +637,34 @@ void main() { ...@@ -584,29 +637,34 @@ void main() {
throwsToolExit(), throwsToolExit(),
); );
expect(testLogger.traceText, contains('xcresult parser: Unrecognized top level json format.')); expect(logger.traceText, contains('xcresult parser: Unrecognized top level json format.'));
}, overrides: <Type, Generator>{ }, overrides: <Type, Generator>{
FileSystem: () => fileSystem, FileSystem: () => fileSystem,
ProcessManager: () => FakeProcessManager.list(<FakeCommand>[ Logger: () => logger,
xattrCommand, ProcessManager: () => processManager,
setUpFakeXcodeBuildHandler(exitCode: 1, onRun: () {
fileSystem.systemTempDirectory.childDirectory(_xcBundleDirectoryPath).createSync();
}),
setUpXCResultCommand(),
setUpRsyncCommand(),
]),
Platform: () => macosPlatform, Platform: () => macosPlatform,
XcodeProjectInterpreter: () => FakeXcodeProjectInterpreterWithBuildSettings(), XcodeProjectInterpreter: () => FakeXcodeProjectInterpreterWithBuildSettings(),
}); });
testUsingContext('Display xcresult issues on console if parsed, suppress Xcode output', () async { testUsingContext('Display xcresult issues on console if parsed, suppress Xcode output', () async {
final BuildCommand command = BuildCommand( final BuildCommand command = BuildCommand(
artifacts: artifacts,
androidSdk: FakeAndroidSdk(), androidSdk: FakeAndroidSdk(),
buildSystem: TestBuildSystem.all(BuildResult(success: true)), buildSystem: TestBuildSystem.all(BuildResult(success: true)),
fileSystem: MemoryFileSystem.test(), fileSystem: fileSystem,
logger: BufferLogger.test(), logger: logger,
processUtils: processUtils,
osUtils: FakeOperatingSystemUtils(), osUtils: FakeOperatingSystemUtils(),
); );
processManager.addCommands(<FakeCommand>[
xattrCommand,
setUpFakeXcodeBuildHandler(exitCode: 1, onRun: () {
fileSystem.systemTempDirectory.childDirectory(_xcBundleDirectoryPath).createSync();
}, stdout: 'Lots of spew from Xcode',
),
setUpXCResultCommand(stdout: kSampleResultJsonWithIssues),
setUpRsyncCommand(),
]);
createMinimalMockProjectFiles(); createMinimalMockProjectFiles();
...@@ -615,33 +673,36 @@ void main() { ...@@ -615,33 +673,36 @@ void main() {
throwsToolExit(), throwsToolExit(),
); );
expect(testLogger.errorText, contains("Use of undeclared identifier 'asdas'")); expect(logger.errorText, contains("Use of undeclared identifier 'asdas'"));
expect(testLogger.errorText, contains('/Users/m/Projects/test_create/ios/Runner/AppDelegate.m:7:56')); expect(logger.errorText, contains('/Users/m/Projects/test_create/ios/Runner/AppDelegate.m:7:56'));
expect(testLogger.statusText, isNot(contains("Xcode's output"))); expect(logger.statusText, isNot(contains("Xcode's output")));
expect(testLogger.statusText, isNot(contains('Lots of spew from Xcode'))); expect(logger.statusText, isNot(contains('Lots of spew from Xcode')));
}, overrides: <Type, Generator>{ }, overrides: <Type, Generator>{
FileSystem: () => fileSystem, FileSystem: () => fileSystem,
ProcessManager: () => FakeProcessManager.list(<FakeCommand>[ Logger: () => logger,
xattrCommand, ProcessManager: () => processManager,
setUpFakeXcodeBuildHandler(exitCode: 1, onRun: () {
fileSystem.systemTempDirectory.childDirectory(_xcBundleDirectoryPath).createSync();
}, stdout: 'Lots of spew from Xcode',
),
setUpXCResultCommand(stdout: kSampleResultJsonWithIssues),
setUpRsyncCommand(),
]),
Platform: () => macosPlatform, Platform: () => macosPlatform,
XcodeProjectInterpreter: () => FakeXcodeProjectInterpreterWithBuildSettings(), XcodeProjectInterpreter: () => FakeXcodeProjectInterpreterWithBuildSettings(),
}); });
testUsingContext('Do not display xcresult issues that needs to be discarded.', () async { testUsingContext('Do not display xcresult issues that needs to be discarded.', () async {
final BuildCommand command = BuildCommand( final BuildCommand command = BuildCommand(
artifacts: artifacts,
androidSdk: FakeAndroidSdk(), androidSdk: FakeAndroidSdk(),
buildSystem: TestBuildSystem.all(BuildResult(success: true)), buildSystem: TestBuildSystem.all(BuildResult(success: true)),
fileSystem: MemoryFileSystem.test(), fileSystem: fileSystem,
logger: BufferLogger.test(), logger: logger,
processUtils: processUtils,
osUtils: FakeOperatingSystemUtils(), osUtils: FakeOperatingSystemUtils(),
); );
processManager.addCommands(<FakeCommand>[
xattrCommand,
setUpFakeXcodeBuildHandler(exitCode: 1, onRun: () {
fileSystem.systemTempDirectory.childDirectory(_xcBundleDirectoryPath).createSync();
}),
setUpXCResultCommand(stdout: kSampleResultJsonWithIssuesToBeDiscarded),
setUpRsyncCommand(),
]);
createMinimalMockProjectFiles(); createMinimalMockProjectFiles();
...@@ -650,32 +711,34 @@ void main() { ...@@ -650,32 +711,34 @@ void main() {
throwsToolExit(), throwsToolExit(),
); );
expect(testLogger.errorText, contains("Use of undeclared identifier 'asdas'")); expect(logger.errorText, contains("Use of undeclared identifier 'asdas'"));
expect(testLogger.errorText, contains('/Users/m/Projects/test_create/ios/Runner/AppDelegate.m:7:56')); expect(logger.errorText, contains('/Users/m/Projects/test_create/ios/Runner/AppDelegate.m:7:56'));
expect(testLogger.errorText, isNot(contains('Command PhaseScriptExecution failed with a nonzero exit code'))); expect(logger.errorText, isNot(contains('Command PhaseScriptExecution failed with a nonzero exit code')));
expect(testLogger.warningText, isNot(contains("The iOS deployment target 'IPHONEOS_DEPLOYMENT_TARGET' is set to 8.0, but the range of supported deployment target versions is 9.0 to 14.0.99."))); expect(logger.warningText, isNot(contains("The iOS deployment target 'IPHONEOS_DEPLOYMENT_TARGET' is set to 8.0, but the range of supported deployment target versions is 9.0 to 14.0.99.")));
}, overrides: <Type, Generator>{ }, overrides: <Type, Generator>{
FileSystem: () => fileSystem, FileSystem: () => fileSystem,
ProcessManager: () => FakeProcessManager.list(<FakeCommand>[ Logger: () => logger,
xattrCommand, ProcessManager: () => processManager,
setUpFakeXcodeBuildHandler(exitCode: 1, onRun: () {
fileSystem.systemTempDirectory.childDirectory(_xcBundleDirectoryPath).createSync();
}),
setUpXCResultCommand(stdout: kSampleResultJsonWithIssuesToBeDiscarded),
setUpRsyncCommand(),
]),
Platform: () => macosPlatform, Platform: () => macosPlatform,
XcodeProjectInterpreter: () => FakeXcodeProjectInterpreterWithBuildSettings(), XcodeProjectInterpreter: () => FakeXcodeProjectInterpreterWithBuildSettings(),
}); });
testUsingContext('Trace if xcresult bundle does not exist.', () async { testUsingContext('Trace if xcresult bundle does not exist.', () async {
final BuildCommand command = BuildCommand( final BuildCommand command = BuildCommand(
artifacts: artifacts,
androidSdk: FakeAndroidSdk(), androidSdk: FakeAndroidSdk(),
buildSystem: TestBuildSystem.all(BuildResult(success: true)), buildSystem: TestBuildSystem.all(BuildResult(success: true)),
fileSystem: MemoryFileSystem.test(), fileSystem: fileSystem,
logger: BufferLogger.test(), logger: logger,
processUtils: processUtils,
osUtils: FakeOperatingSystemUtils(), osUtils: FakeOperatingSystemUtils(),
); );
processManager.addCommands(<FakeCommand>[
xattrCommand,
setUpFakeXcodeBuildHandler(exitCode: 1),
setUpXCResultCommand(stdout: kSampleResultJsonWithIssues),
setUpRsyncCommand(),
]);
createMinimalMockProjectFiles(); createMinimalMockProjectFiles();
...@@ -687,24 +750,29 @@ void main() { ...@@ -687,24 +750,29 @@ void main() {
expect(testLogger.traceText, contains('The xcresult bundle are not generated. Displaying xcresult is disabled.')); expect(testLogger.traceText, contains('The xcresult bundle are not generated. Displaying xcresult is disabled.'));
}, overrides: <Type, Generator>{ }, overrides: <Type, Generator>{
FileSystem: () => fileSystem, FileSystem: () => fileSystem,
ProcessManager: () => FakeProcessManager.list(<FakeCommand>[ ProcessManager: () => processManager,
xattrCommand,
setUpFakeXcodeBuildHandler(exitCode: 1),
setUpXCResultCommand(stdout: kSampleResultJsonWithIssues),
setUpRsyncCommand(),
]),
Platform: () => macosPlatform, Platform: () => macosPlatform,
XcodeProjectInterpreter: () => FakeXcodeProjectInterpreterWithBuildSettings(), XcodeProjectInterpreter: () => FakeXcodeProjectInterpreterWithBuildSettings(),
}); });
testUsingContext('Extra error message for provision profile issue in xcresult bundle.', () async { testUsingContext('Extra error message for provision profile issue in xcresult bundle.', () async {
final BuildCommand command = BuildCommand( final BuildCommand command = BuildCommand(
artifacts: artifacts,
androidSdk: FakeAndroidSdk(), androidSdk: FakeAndroidSdk(),
buildSystem: TestBuildSystem.all(BuildResult(success: true)), buildSystem: TestBuildSystem.all(BuildResult(success: true)),
fileSystem: MemoryFileSystem.test(), fileSystem: fileSystem,
logger: BufferLogger.test(), logger: logger,
processUtils: processUtils,
osUtils: FakeOperatingSystemUtils(), osUtils: FakeOperatingSystemUtils(),
); );
processManager.addCommands(<FakeCommand>[
xattrCommand,
setUpFakeXcodeBuildHandler(exitCode: 1, onRun: () {
fileSystem.systemTempDirectory.childDirectory(_xcBundleDirectoryPath).createSync();
}),
setUpXCResultCommand(stdout: kSampleResultJsonWithProvisionIssue),
setUpRsyncCommand(),
]);
createMinimalMockProjectFiles(); createMinimalMockProjectFiles();
...@@ -713,33 +781,40 @@ void main() { ...@@ -713,33 +781,40 @@ void main() {
throwsToolExit(), throwsToolExit(),
); );
expect(testLogger.errorText, contains('Some Provisioning profile issue.')); expect(logger.errorText, contains('Some Provisioning profile issue.'));
expect(testLogger.errorText, contains('It appears that there was a problem signing your application prior to installation on the device.')); expect(logger.errorText, contains('It appears that there was a problem signing your application prior to installation on the device.'));
expect(testLogger.errorText, contains('Verify that the Bundle Identifier in your project is your signing id in Xcode')); expect(logger.errorText, contains('Verify that the Bundle Identifier in your project is your signing id in Xcode'));
expect(testLogger.errorText, contains('open ios/Runner.xcworkspace')); expect(logger.errorText, contains('open ios/Runner.xcworkspace'));
expect(testLogger.errorText, contains("Also try selecting 'Product > Build' to fix the problem.")); expect(logger.errorText, contains("Also try selecting 'Product > Build' to fix the problem."));
}, overrides: <Type, Generator>{ }, overrides: <Type, Generator>{
FileSystem: () => fileSystem, FileSystem: () => fileSystem,
ProcessManager: () => FakeProcessManager.list(<FakeCommand>[ Logger: () => logger,
xattrCommand, ProcessManager: () => processManager,
setUpFakeXcodeBuildHandler(exitCode: 1, onRun: () {
fileSystem.systemTempDirectory.childDirectory(_xcBundleDirectoryPath).createSync();
}),
setUpXCResultCommand(stdout: kSampleResultJsonWithProvisionIssue),
setUpRsyncCommand(),
]),
Platform: () => macosPlatform, Platform: () => macosPlatform,
XcodeProjectInterpreter: () => FakeXcodeProjectInterpreterWithBuildSettings(), XcodeProjectInterpreter: () => FakeXcodeProjectInterpreterWithBuildSettings(),
}); });
testUsingContext('Display xcresult issues with no provisioning profile.', () async { testUsingContext('Display xcresult issues with no provisioning profile.', () async {
final BuildCommand command = BuildCommand( final BuildCommand command = BuildCommand(
artifacts: artifacts,
androidSdk: FakeAndroidSdk(), androidSdk: FakeAndroidSdk(),
buildSystem: TestBuildSystem.all(BuildResult(success: true)), buildSystem: TestBuildSystem.all(BuildResult(success: true)),
fileSystem: MemoryFileSystem.test(), fileSystem: fileSystem,
logger: BufferLogger.test(), logger: logger,
processUtils: processUtils,
osUtils: FakeOperatingSystemUtils(), osUtils: FakeOperatingSystemUtils(),
); );
processManager.addCommands(<FakeCommand>[
xattrCommand,
setUpFakeXcodeBuildHandler(
exitCode: 1,
onRun: () {
fileSystem.systemTempDirectory.childDirectory(_xcBundleDirectoryPath).createSync();
}
),
setUpXCResultCommand(stdout: kSampleResultJsonWithNoProvisioningProfileIssue),
setUpRsyncCommand(),
]);
createMinimalMockProjectFiles(); createMinimalMockProjectFiles();
...@@ -748,33 +823,34 @@ void main() { ...@@ -748,33 +823,34 @@ void main() {
throwsToolExit(), throwsToolExit(),
); );
expect(testLogger.errorText, contains('Runner requires a provisioning profile. Select a provisioning profile in the Signing & Capabilities editor')); expect(logger.errorText, contains('Runner requires a provisioning profile. Select a provisioning profile in the Signing & Capabilities editor'));
expect(testLogger.errorText, contains(noProvisioningProfileInstruction)); expect(logger.errorText, contains(noProvisioningProfileInstruction));
}, overrides: <Type, Generator>{ }, overrides: <Type, Generator>{
FileSystem: () => fileSystem, FileSystem: () => fileSystem,
ProcessManager: () => FakeProcessManager.list(<FakeCommand>[ Logger: () => logger,
xattrCommand, ProcessManager: () => processManager,
setUpFakeXcodeBuildHandler(
exitCode: 1,
onRun: () {
fileSystem.systemTempDirectory.childDirectory(_xcBundleDirectoryPath).createSync();
}
),
setUpXCResultCommand(stdout: kSampleResultJsonWithNoProvisioningProfileIssue),
setUpRsyncCommand(),
]),
Platform: () => macosPlatform, Platform: () => macosPlatform,
XcodeProjectInterpreter: () => FakeXcodeProjectInterpreterWithBuildSettings(), XcodeProjectInterpreter: () => FakeXcodeProjectInterpreterWithBuildSettings(),
}); });
testUsingContext('Extra error message for missing simulator platform in xcresult bundle.', () async { testUsingContext('Extra error message for missing simulator platform in xcresult bundle.', () async {
final BuildCommand command = BuildCommand( final BuildCommand command = BuildCommand(
artifacts: artifacts,
androidSdk: FakeAndroidSdk(), androidSdk: FakeAndroidSdk(),
buildSystem: TestBuildSystem.all(BuildResult(success: true)), buildSystem: TestBuildSystem.all(BuildResult(success: true)),
fileSystem: MemoryFileSystem.test(), fileSystem: fileSystem,
logger: BufferLogger.test(), logger: logger,
processUtils: processUtils,
osUtils: FakeOperatingSystemUtils(), osUtils: FakeOperatingSystemUtils(),
); );
processManager.addCommands(<FakeCommand>[
xattrCommand,
setUpFakeXcodeBuildHandler(exitCode: 1, onRun: () {
fileSystem.systemTempDirectory.childDirectory(_xcBundleDirectoryPath).createSync();
}),
setUpXCResultCommand(stdout: kSampleResultJsonWithActionIssues),
setUpRsyncCommand(),
]);
createMinimalMockProjectFiles(); createMinimalMockProjectFiles();
...@@ -783,38 +859,26 @@ void main() { ...@@ -783,38 +859,26 @@ void main() {
throwsToolExit(), throwsToolExit(),
); );
expect(testLogger.errorText, contains(missingPlatformInstructions('iOS 17.0'))); expect(logger.errorText, contains(missingPlatformInstructions('iOS 17.0')));
}, overrides: <Type, Generator>{ }, overrides: <Type, Generator>{
FileSystem: () => fileSystem, FileSystem: () => fileSystem,
ProcessManager: () => FakeProcessManager.list(<FakeCommand>[ Logger: () => logger,
xattrCommand, ProcessManager: () => processManager,
setUpFakeXcodeBuildHandler(exitCode: 1, onRun: () {
fileSystem.systemTempDirectory.childDirectory(_xcBundleDirectoryPath).createSync();
}),
setUpXCResultCommand(stdout: kSampleResultJsonWithActionIssues),
setUpRsyncCommand(),
]),
Platform: () => macosPlatform, Platform: () => macosPlatform,
XcodeProjectInterpreter: () => FakeXcodeProjectInterpreterWithBuildSettings(), XcodeProjectInterpreter: () => FakeXcodeProjectInterpreterWithBuildSettings(),
}); });
testUsingContext('Delete xcresult bundle before each xcodebuild command.', () async { testUsingContext('Delete xcresult bundle before each xcodebuild command.', () async {
final BuildCommand command = BuildCommand( final BuildCommand command = BuildCommand(
artifacts: artifacts,
androidSdk: FakeAndroidSdk(), androidSdk: FakeAndroidSdk(),
buildSystem: TestBuildSystem.all(BuildResult(success: true)), buildSystem: TestBuildSystem.all(BuildResult(success: true)),
fileSystem: MemoryFileSystem.test(), fileSystem: fileSystem,
logger: BufferLogger.test(), logger: logger,
processUtils: processUtils,
osUtils: FakeOperatingSystemUtils(), osUtils: FakeOperatingSystemUtils(),
); );
processManager.addCommands(<FakeCommand>[
createMinimalMockProjectFiles();
await createTestCommandRunner(command).run(const <String>['build', 'ios', '--no-pub']);
expect(testLogger.statusText, contains('Xcode build done.'));
}, overrides: <Type, Generator>{
FileSystem: () => fileSystem,
ProcessManager: () => FakeProcessManager.list(<FakeCommand>[
xattrCommand, xattrCommand,
// Intentionally fail the first xcodebuild command with concurrent run failure message. // Intentionally fail the first xcodebuild command with concurrent run failure message.
setUpFakeXcodeBuildHandler( setUpFakeXcodeBuildHandler(
...@@ -836,32 +900,32 @@ void main() { ...@@ -836,32 +900,32 @@ void main() {
), ),
setUpXCResultCommand(stdout: kSampleResultJsonNoIssues), setUpXCResultCommand(stdout: kSampleResultJsonNoIssues),
setUpRsyncCommand(), setUpRsyncCommand(),
], ]);
),
createMinimalMockProjectFiles();
await createTestCommandRunner(command).run(const <String>['build', 'ios', '--no-pub']);
expect(logger.statusText, contains('Xcode build done.'));
}, overrides: <Type, Generator>{
FileSystem: () => fileSystem,
Logger: () => logger,
ProcessManager: () => processManager,
Platform: () => macosPlatform, Platform: () => macosPlatform,
XcodeProjectInterpreter: () => FakeXcodeProjectInterpreterWithBuildSettings(), XcodeProjectInterpreter: () => FakeXcodeProjectInterpreterWithBuildSettings(),
}); });
testUsingContext('Failed to parse xcresult but display missing provisioning profile issue from stdout.', () async { testUsingContext('Failed to parse xcresult but display missing provisioning profile issue from stdout.', () async {
final BuildCommand command = BuildCommand( final BuildCommand command = BuildCommand(
artifacts: artifacts,
androidSdk: FakeAndroidSdk(), androidSdk: FakeAndroidSdk(),
buildSystem: TestBuildSystem.all(BuildResult(success: true)), buildSystem: TestBuildSystem.all(BuildResult(success: true)),
fileSystem: MemoryFileSystem.test(), fileSystem: fileSystem,
logger: BufferLogger.test(), logger: logger,
processUtils: processUtils,
osUtils: FakeOperatingSystemUtils(), osUtils: FakeOperatingSystemUtils(),
); );
processManager.addCommands(<FakeCommand>[
createMinimalMockProjectFiles();
await expectLater(
createTestCommandRunner(command).run(const <String>['build', 'ios', '--no-pub']),
throwsToolExit(),
);
expect(testLogger.errorText, contains(noProvisioningProfileInstruction));
}, overrides: <Type, Generator>{
FileSystem: () => fileSystem,
ProcessManager: () => FakeProcessManager.list(<FakeCommand>[
xattrCommand, xattrCommand,
setUpFakeXcodeBuildHandler( setUpFakeXcodeBuildHandler(
exitCode: 1, exitCode: 1,
...@@ -874,19 +938,45 @@ Runner requires a provisioning profile. Select a provisioning profile in the Sig ...@@ -874,19 +938,45 @@ Runner requires a provisioning profile. Select a provisioning profile in the Sig
), ),
setUpXCResultCommand(stdout: kSampleResultJsonInvalidIssuesMap), setUpXCResultCommand(stdout: kSampleResultJsonInvalidIssuesMap),
setUpRsyncCommand(), setUpRsyncCommand(),
]), ]);
createMinimalMockProjectFiles();
await expectLater(
createTestCommandRunner(command).run(const <String>['build', 'ios', '--no-pub']),
throwsToolExit(),
);
expect(logger.errorText, contains(noProvisioningProfileInstruction));
}, overrides: <Type, Generator>{
FileSystem: () => fileSystem,
Logger: () => logger,
ProcessManager: () => processManager,
Platform: () => macosPlatform, Platform: () => macosPlatform,
XcodeProjectInterpreter: () => FakeXcodeProjectInterpreterWithBuildSettings(), XcodeProjectInterpreter: () => FakeXcodeProjectInterpreterWithBuildSettings(),
}); });
testUsingContext('Failed to parse xcresult but detected no development team issue.', () async { testUsingContext('Failed to parse xcresult but detected no development team issue.', () async {
final BuildCommand command = BuildCommand( final BuildCommand command = BuildCommand(
artifacts: artifacts,
androidSdk: FakeAndroidSdk(), androidSdk: FakeAndroidSdk(),
buildSystem: TestBuildSystem.all(BuildResult(success: true)), buildSystem: TestBuildSystem.all(BuildResult(success: true)),
fileSystem: MemoryFileSystem.test(), fileSystem: fileSystem,
logger: BufferLogger.test(), logger: logger,
processUtils: processUtils,
osUtils: FakeOperatingSystemUtils(), osUtils: FakeOperatingSystemUtils(),
); );
processManager.addCommands(<FakeCommand>[
xattrCommand,
setUpFakeXcodeBuildHandler(
exitCode: 1,
onRun: () {
fileSystem.systemTempDirectory.childDirectory(_xcBundleDirectoryPath).createSync();
}
),
setUpXCResultCommand(stdout: kSampleResultJsonInvalidIssuesMap),
setUpRsyncCommand(),
]);
createMinimalMockProjectFiles(); createMinimalMockProjectFiles();
...@@ -895,30 +985,23 @@ Runner requires a provisioning profile. Select a provisioning profile in the Sig ...@@ -895,30 +985,23 @@ Runner requires a provisioning profile. Select a provisioning profile in the Sig
throwsToolExit(), throwsToolExit(),
); );
expect(testLogger.errorText, contains(noDevelopmentTeamInstruction)); expect(logger.errorText, contains(noDevelopmentTeamInstruction));
}, overrides: <Type, Generator>{ }, overrides: <Type, Generator>{
FileSystem: () => fileSystem, FileSystem: () => fileSystem,
ProcessManager: () => FakeProcessManager.list(<FakeCommand>[ Logger: () => logger,
xattrCommand, ProcessManager: () => processManager,
setUpFakeXcodeBuildHandler(
exitCode: 1,
onRun: () {
fileSystem.systemTempDirectory.childDirectory(_xcBundleDirectoryPath).createSync();
}
),
setUpXCResultCommand(stdout: kSampleResultJsonInvalidIssuesMap),
setUpRsyncCommand(),
]),
Platform: () => macosPlatform, Platform: () => macosPlatform,
XcodeProjectInterpreter: () => FakeXcodeProjectInterpreterWithBuildSettings(developmentTeam: null), XcodeProjectInterpreter: () => FakeXcodeProjectInterpreterWithBuildSettings(developmentTeam: null),
}); });
testUsingContext('xcresult did not detect issue but detected by stdout.', () async { testUsingContext('xcresult did not detect issue but detected by stdout.', () async {
final BuildCommand command = BuildCommand( final BuildCommand command = BuildCommand(
artifacts: artifacts,
androidSdk: FakeAndroidSdk(), androidSdk: FakeAndroidSdk(),
buildSystem: TestBuildSystem.all(BuildResult(success: true)), buildSystem: TestBuildSystem.all(BuildResult(success: true)),
fileSystem: MemoryFileSystem.test(), fileSystem: fileSystem,
logger: BufferLogger.test(), logger: logger,
processUtils: processUtils,
osUtils: FakeOperatingSystemUtils(), osUtils: FakeOperatingSystemUtils(),
); );
...@@ -953,12 +1036,25 @@ Runner requires a provisioning profile. Select a provisioning profile in the Sig ...@@ -953,12 +1036,25 @@ Runner requires a provisioning profile. Select a provisioning profile in the Sig
testUsingContext('xcresult did not detect issue, no development team is detected from build setting.', () async { testUsingContext('xcresult did not detect issue, no development team is detected from build setting.', () async {
final BuildCommand command = BuildCommand( final BuildCommand command = BuildCommand(
artifacts: artifacts,
androidSdk: FakeAndroidSdk(), androidSdk: FakeAndroidSdk(),
buildSystem: TestBuildSystem.all(BuildResult(success: true)), buildSystem: TestBuildSystem.all(BuildResult(success: true)),
fileSystem: MemoryFileSystem.test(), fileSystem: fileSystem,
logger: BufferLogger.test(), logger: logger,
processUtils: processUtils,
osUtils: FakeOperatingSystemUtils(), osUtils: FakeOperatingSystemUtils(),
); );
processManager.addCommands(<FakeCommand>[
xattrCommand,
setUpFakeXcodeBuildHandler(
exitCode: 1,
onRun: () {
fileSystem.systemTempDirectory.childDirectory(_xcBundleDirectoryPath).createSync();
}
),
setUpXCResultCommand(stdout: kSampleResultJsonInvalidIssuesMap),
setUpRsyncCommand(),
]);
createMinimalMockProjectFiles(); createMinimalMockProjectFiles();
...@@ -970,29 +1066,32 @@ Runner requires a provisioning profile. Select a provisioning profile in the Sig ...@@ -970,29 +1066,32 @@ Runner requires a provisioning profile. Select a provisioning profile in the Sig
expect(testLogger.errorText, contains(noDevelopmentTeamInstruction)); expect(testLogger.errorText, contains(noDevelopmentTeamInstruction));
}, overrides: <Type, Generator>{ }, overrides: <Type, Generator>{
FileSystem: () => fileSystem, FileSystem: () => fileSystem,
ProcessManager: () => FakeProcessManager.list(<FakeCommand>[ ProcessManager: () => processManager,
xattrCommand,
setUpFakeXcodeBuildHandler(
exitCode: 1,
onRun: () {
fileSystem.systemTempDirectory.childDirectory(_xcBundleDirectoryPath).createSync();
}
),
setUpXCResultCommand(stdout: kSampleResultJsonInvalidIssuesMap),
setUpRsyncCommand(),
]),
Platform: () => macosPlatform, Platform: () => macosPlatform,
XcodeProjectInterpreter: () => FakeXcodeProjectInterpreterWithBuildSettings(developmentTeam: null), XcodeProjectInterpreter: () => FakeXcodeProjectInterpreterWithBuildSettings(developmentTeam: null),
}); });
testUsingContext('No development team issue error message is not displayed if no provisioning profile issue is detected from xcresult first.', () async { testUsingContext('No development team issue error message is not displayed if no provisioning profile issue is detected from xcresult first.', () async {
final BuildCommand command = BuildCommand( final BuildCommand command = BuildCommand(
artifacts: artifacts,
androidSdk: FakeAndroidSdk(), androidSdk: FakeAndroidSdk(),
buildSystem: TestBuildSystem.all(BuildResult(success: true)), buildSystem: TestBuildSystem.all(BuildResult(success: true)),
fileSystem: MemoryFileSystem.test(), fileSystem: fileSystem,
logger: BufferLogger.test(), logger: logger,
processUtils: processUtils,
osUtils: FakeOperatingSystemUtils(), osUtils: FakeOperatingSystemUtils(),
); );
processManager.addCommands(<FakeCommand>[
xattrCommand,
setUpFakeXcodeBuildHandler(
exitCode: 1,
onRun: () {
fileSystem.systemTempDirectory.childDirectory(_xcBundleDirectoryPath).createSync();
}
),
setUpXCResultCommand(stdout: kSampleResultJsonWithNoProvisioningProfileIssue),
setUpRsyncCommand(),
]);
createMinimalMockProjectFiles(); createMinimalMockProjectFiles();
...@@ -1001,33 +1100,37 @@ Runner requires a provisioning profile. Select a provisioning profile in the Sig ...@@ -1001,33 +1100,37 @@ Runner requires a provisioning profile. Select a provisioning profile in the Sig
throwsToolExit(), throwsToolExit(),
); );
expect(testLogger.errorText, contains(noProvisioningProfileInstruction)); expect(logger.errorText, contains(noProvisioningProfileInstruction));
expect(testLogger.errorText, isNot(contains(noDevelopmentTeamInstruction))); expect(logger.errorText, isNot(contains(noDevelopmentTeamInstruction)));
}, overrides: <Type, Generator>{ }, overrides: <Type, Generator>{
FileSystem: () => fileSystem, FileSystem: () => fileSystem,
ProcessManager: () => FakeProcessManager.list(<FakeCommand>[ Logger: () => logger,
xattrCommand, ProcessManager: () => processManager,
setUpFakeXcodeBuildHandler(
exitCode: 1,
onRun: () {
fileSystem.systemTempDirectory.childDirectory(_xcBundleDirectoryPath).createSync();
}
),
setUpXCResultCommand(stdout: kSampleResultJsonWithNoProvisioningProfileIssue),
setUpRsyncCommand(),
]),
Platform: () => macosPlatform, Platform: () => macosPlatform,
XcodeProjectInterpreter: () => FakeXcodeProjectInterpreterWithBuildSettings(developmentTeam: null), XcodeProjectInterpreter: () => FakeXcodeProjectInterpreterWithBuildSettings(developmentTeam: null),
}); });
testUsingContext('General provisioning profile issue error message is not displayed if no development team issue is detected first.', () async { testUsingContext('General provisioning profile issue error message is not displayed if no development team issue is detected first.', () async {
final BuildCommand command = BuildCommand( final BuildCommand command = BuildCommand(
artifacts: artifacts,
androidSdk: FakeAndroidSdk(), androidSdk: FakeAndroidSdk(),
buildSystem: TestBuildSystem.all(BuildResult(success: true)), buildSystem: TestBuildSystem.all(BuildResult(success: true)),
fileSystem: MemoryFileSystem.test(), fileSystem: fileSystem,
logger: BufferLogger.test(), logger: logger,
processUtils: processUtils,
osUtils: FakeOperatingSystemUtils(), osUtils: FakeOperatingSystemUtils(),
); );
processManager.addCommands(<FakeCommand>[
xattrCommand,
setUpFakeXcodeBuildHandler(
exitCode: 1,
onRun: () {
fileSystem.systemTempDirectory.childDirectory(_xcBundleDirectoryPath).createSync();
}
),
setUpXCResultCommand(stdout: kSampleResultJsonWithProvisionIssue),
setUpRsyncCommand(),
]);
createMinimalMockProjectFiles(); createMinimalMockProjectFiles();
...@@ -1036,21 +1139,12 @@ Runner requires a provisioning profile. Select a provisioning profile in the Sig ...@@ -1036,21 +1139,12 @@ Runner requires a provisioning profile. Select a provisioning profile in the Sig
throwsToolExit(), throwsToolExit(),
); );
expect(testLogger.errorText, contains(noDevelopmentTeamInstruction)); expect(logger.errorText, contains(noDevelopmentTeamInstruction));
expect(testLogger.errorText, isNot(contains('It appears that there was a problem signing your application prior to installation on the device.'))); expect(logger.errorText, isNot(contains('It appears that there was a problem signing your application prior to installation on the device.')));
}, overrides: <Type, Generator>{ }, overrides: <Type, Generator>{
FileSystem: () => fileSystem, FileSystem: () => fileSystem,
ProcessManager: () => FakeProcessManager.list(<FakeCommand>[ Logger: () => logger,
xattrCommand, ProcessManager: () => processManager,
setUpFakeXcodeBuildHandler(
exitCode: 1,
onRun: () {
fileSystem.systemTempDirectory.childDirectory(_xcBundleDirectoryPath).createSync();
}
),
setUpXCResultCommand(stdout: kSampleResultJsonWithProvisionIssue),
setUpRsyncCommand(),
]),
Platform: () => macosPlatform, Platform: () => macosPlatform,
XcodeProjectInterpreter: () => FakeXcodeProjectInterpreterWithBuildSettings(developmentTeam: null), XcodeProjectInterpreter: () => FakeXcodeProjectInterpreterWithBuildSettings(developmentTeam: null),
}); });
...@@ -1059,24 +1153,15 @@ Runner requires a provisioning profile. Select a provisioning profile in the Sig ...@@ -1059,24 +1153,15 @@ Runner requires a provisioning profile. Select a provisioning profile in the Sig
group('xcresults simulator', () { group('xcresults simulator', () {
testUsingContext('Trace error if xcresult is empty.', () async { testUsingContext('Trace error if xcresult is empty.', () async {
final BuildCommand command = BuildCommand( final BuildCommand command = BuildCommand(
artifacts: artifacts,
androidSdk: FakeAndroidSdk(), androidSdk: FakeAndroidSdk(),
buildSystem: TestBuildSystem.all(BuildResult(success: true)), buildSystem: TestBuildSystem.all(BuildResult(success: true)),
fileSystem: MemoryFileSystem.test(), fileSystem: fileSystem,
logger: BufferLogger.test(), logger: logger,
processUtils: processUtils,
osUtils: FakeOperatingSystemUtils(), osUtils: FakeOperatingSystemUtils(),
); );
processManager.addCommands(<FakeCommand>[
createMinimalMockProjectFiles();
await expectLater(
createTestCommandRunner(command).run(const <String>['build', 'ios', '--simulator', '--no-pub']),
throwsToolExit(),
);
expect(testLogger.traceText, contains('xcresult parser: Unrecognized top level json format.'));
}, overrides: <Type, Generator>{
FileSystem: () => fileSystem,
ProcessManager: () => FakeProcessManager.list(<FakeCommand>[
xattrCommand, xattrCommand,
setUpFakeXcodeBuildHandler( setUpFakeXcodeBuildHandler(
simulator: true, simulator: true,
...@@ -1087,32 +1172,35 @@ Runner requires a provisioning profile. Select a provisioning profile in the Sig ...@@ -1087,32 +1172,35 @@ Runner requires a provisioning profile. Select a provisioning profile in the Sig
), ),
setUpXCResultCommand(), setUpXCResultCommand(),
setUpRsyncCommand(), setUpRsyncCommand(),
]), ]);
createMinimalMockProjectFiles();
await expectLater(
createTestCommandRunner(command).run(const <String>['build', 'ios', '--simulator', '--no-pub']),
throwsToolExit(),
);
expect(logger.traceText, contains('xcresult parser: Unrecognized top level json format.'));
}, overrides: <Type, Generator>{
FileSystem: () => fileSystem,
Logger: () => logger,
ProcessManager: () => processManager,
Platform: () => macosPlatform, Platform: () => macosPlatform,
XcodeProjectInterpreter: () => FakeXcodeProjectInterpreterWithBuildSettings(), XcodeProjectInterpreter: () => FakeXcodeProjectInterpreterWithBuildSettings(),
}); });
testUsingContext('Display xcresult issues on console if parsed.', () async { testUsingContext('Display xcresult issues on console if parsed.', () async {
final BuildCommand command = BuildCommand( final BuildCommand command = BuildCommand(
artifacts: artifacts,
androidSdk: FakeAndroidSdk(), androidSdk: FakeAndroidSdk(),
buildSystem: TestBuildSystem.all(BuildResult(success: true)), buildSystem: TestBuildSystem.all(BuildResult(success: true)),
fileSystem: MemoryFileSystem.test(), fileSystem: fileSystem,
logger: BufferLogger.test(), logger: logger,
processUtils: processUtils,
osUtils: FakeOperatingSystemUtils(), osUtils: FakeOperatingSystemUtils(),
); );
processManager.addCommands(<FakeCommand>[
createMinimalMockProjectFiles();
await expectLater(
createTestCommandRunner(command).run(const <String>['build', 'ios', '--simulator', '--no-pub']),
throwsToolExit(),
);
expect(testLogger.errorText, contains("Use of undeclared identifier 'asdas'"));
expect(testLogger.errorText, contains('/Users/m/Projects/test_create/ios/Runner/AppDelegate.m:7:56'));
}, overrides: <Type, Generator>{
FileSystem: () => fileSystem,
ProcessManager: () => FakeProcessManager.list(<FakeCommand>[
xattrCommand, xattrCommand,
setUpFakeXcodeBuildHandler( setUpFakeXcodeBuildHandler(
simulator: true, simulator: true,
...@@ -1123,34 +1211,37 @@ Runner requires a provisioning profile. Select a provisioning profile in the Sig ...@@ -1123,34 +1211,37 @@ Runner requires a provisioning profile. Select a provisioning profile in the Sig
), ),
setUpXCResultCommand(stdout: kSampleResultJsonWithIssues), setUpXCResultCommand(stdout: kSampleResultJsonWithIssues),
setUpRsyncCommand(), setUpRsyncCommand(),
]), ]);
createMinimalMockProjectFiles();
await expectLater(
createTestCommandRunner(command).run(const <String>['build', 'ios', '--simulator', '--no-pub']),
throwsToolExit(),
);
expect(logger.errorText, contains("Use of undeclared identifier 'asdas'"));
expect(logger.errorText, contains('/Users/m/Projects/test_create/ios/Runner/AppDelegate.m:7:56'));
}, overrides: <Type, Generator>{
FileSystem: () => fileSystem,
Logger: () => logger,
ProcessManager: () => processManager,
Platform: () => macosPlatform, Platform: () => macosPlatform,
XcodeProjectInterpreter: () => FakeXcodeProjectInterpreterWithBuildSettings(), XcodeProjectInterpreter: () => FakeXcodeProjectInterpreterWithBuildSettings(),
}); });
testUsingContext('Do not display xcresult issues that needs to be discarded.', () async { testUsingContext('Do not display xcresult issues that needs to be discarded.', () async {
final BuildCommand command = BuildCommand( final BuildCommand command = BuildCommand(
artifacts: artifacts,
androidSdk: FakeAndroidSdk(), androidSdk: FakeAndroidSdk(),
buildSystem: TestBuildSystem.all(BuildResult(success: true)), buildSystem: TestBuildSystem.all(BuildResult(success: true)),
fileSystem: MemoryFileSystem.test(), fileSystem: fileSystem,
logger: BufferLogger.test(), logger: logger,
processUtils: processUtils,
osUtils: FakeOperatingSystemUtils(), osUtils: FakeOperatingSystemUtils(),
); );
createMinimalMockProjectFiles(); processManager.addCommands(<FakeCommand>[
await expectLater(
createTestCommandRunner(command).run(const <String>['build', 'ios', '--simulator', '--no-pub']),
throwsToolExit(),
);
expect(testLogger.errorText, contains("Use of undeclared identifier 'asdas'"));
expect(testLogger.errorText, contains('/Users/m/Projects/test_create/ios/Runner/AppDelegate.m:7:56'));
expect(testLogger.errorText, isNot(contains('Command PhaseScriptExecution failed with a nonzero exit code')));
expect(testLogger.warningText, isNot(contains("The iOS deployment target 'IPHONEOS_DEPLOYMENT_TARGET' is set to 8.0, but the range of supported deployment target versions is 9.0 to 14.0.99.")));
}, overrides: <Type, Generator>{
FileSystem: () => fileSystem,
ProcessManager: () => FakeProcessManager.list(<FakeCommand>[
xattrCommand, xattrCommand,
setUpFakeXcodeBuildHandler( setUpFakeXcodeBuildHandler(
simulator: true, simulator: true,
...@@ -1161,19 +1252,46 @@ Runner requires a provisioning profile. Select a provisioning profile in the Sig ...@@ -1161,19 +1252,46 @@ Runner requires a provisioning profile. Select a provisioning profile in the Sig
), ),
setUpXCResultCommand(stdout: kSampleResultJsonWithIssuesToBeDiscarded), setUpXCResultCommand(stdout: kSampleResultJsonWithIssuesToBeDiscarded),
setUpRsyncCommand(), setUpRsyncCommand(),
]), ]);
createMinimalMockProjectFiles();
await expectLater(
createTestCommandRunner(command).run(const <String>['build', 'ios', '--simulator', '--no-pub']),
throwsToolExit(),
);
expect(logger.errorText, contains("Use of undeclared identifier 'asdas'"));
expect(logger.errorText, contains('/Users/m/Projects/test_create/ios/Runner/AppDelegate.m:7:56'));
expect(logger.errorText, isNot(contains('Command PhaseScriptExecution failed with a nonzero exit code')));
expect(logger.warningText, isNot(contains("The iOS deployment target 'IPHONEOS_DEPLOYMENT_TARGET' is set to 8.0, but the range of supported deployment target versions is 9.0 to 14.0.99.")));
}, overrides: <Type, Generator>{
FileSystem: () => fileSystem,
Logger: () => logger,
ProcessManager: () => processManager,
Platform: () => macosPlatform, Platform: () => macosPlatform,
XcodeProjectInterpreter: () => FakeXcodeProjectInterpreterWithBuildSettings(), XcodeProjectInterpreter: () => FakeXcodeProjectInterpreterWithBuildSettings(),
}); });
testUsingContext('Trace if xcresult bundle does not exist.', () async { testUsingContext('Trace if xcresult bundle does not exist.', () async {
final BuildCommand command = BuildCommand( final BuildCommand command = BuildCommand(
artifacts: artifacts,
androidSdk: FakeAndroidSdk(), androidSdk: FakeAndroidSdk(),
buildSystem: TestBuildSystem.all(BuildResult(success: true)), buildSystem: TestBuildSystem.all(BuildResult(success: true)),
fileSystem: MemoryFileSystem.test(), fileSystem: fileSystem,
logger: BufferLogger.test(), logger: logger,
processUtils: processUtils,
osUtils: FakeOperatingSystemUtils(), osUtils: FakeOperatingSystemUtils(),
); );
processManager.addCommands(<FakeCommand>[
xattrCommand,
setUpFakeXcodeBuildHandler(
simulator: true,
exitCode: 1,
),
setUpXCResultCommand(stdout: kSampleResultJsonWithIssues),
setUpRsyncCommand(),
]);
createMinimalMockProjectFiles(); createMinimalMockProjectFiles();
...@@ -1182,18 +1300,11 @@ Runner requires a provisioning profile. Select a provisioning profile in the Sig ...@@ -1182,18 +1300,11 @@ Runner requires a provisioning profile. Select a provisioning profile in the Sig
throwsToolExit(), throwsToolExit(),
); );
expect(testLogger.traceText, contains('The xcresult bundle are not generated. Displaying xcresult is disabled.')); expect(logger.traceText, contains('The xcresult bundle are not generated. Displaying xcresult is disabled.'));
}, overrides: <Type, Generator>{ }, overrides: <Type, Generator>{
FileSystem: () => fileSystem, FileSystem: () => fileSystem,
ProcessManager: () => FakeProcessManager.list(<FakeCommand>[ Logger: () => logger,
xattrCommand, ProcessManager: () => processManager,
setUpFakeXcodeBuildHandler(
simulator: true,
exitCode: 1,
),
setUpXCResultCommand(stdout: kSampleResultJsonWithIssues),
setUpRsyncCommand(),
]),
Platform: () => macosPlatform, Platform: () => macosPlatform,
XcodeProjectInterpreter: () => FakeXcodeProjectInterpreterWithBuildSettings(), XcodeProjectInterpreter: () => FakeXcodeProjectInterpreterWithBuildSettings(),
}); });
......
...@@ -6,9 +6,11 @@ import 'dart:typed_data'; ...@@ -6,9 +6,11 @@ import 'dart:typed_data';
import 'package:args/command_runner.dart'; import 'package:args/command_runner.dart';
import 'package:file/memory.dart'; 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/file_system.dart';
import 'package:flutter_tools/src/base/logger.dart'; import 'package:flutter_tools/src/base/logger.dart';
import 'package:flutter_tools/src/base/platform.dart'; import 'package:flutter_tools/src/base/platform.dart';
import 'package:flutter_tools/src/base/process.dart';
import 'package:flutter_tools/src/build_system/build_system.dart'; import 'package:flutter_tools/src/build_system/build_system.dart';
import 'package:flutter_tools/src/cache.dart'; import 'package:flutter_tools/src/cache.dart';
import 'package:flutter_tools/src/commands/build.dart'; import 'package:flutter_tools/src/commands/build.dart';
...@@ -33,10 +35,10 @@ class FakeXcodeProjectInterpreterWithBuildSettings extends FakeXcodeProjectInter ...@@ -33,10 +35,10 @@ class FakeXcodeProjectInterpreterWithBuildSettings extends FakeXcodeProjectInter
@override @override
Future<Map<String, String>> getBuildSettings( Future<Map<String, String>> getBuildSettings(
String projectPath, { String projectPath, {
XcodeProjectBuildContext? buildContext, XcodeProjectBuildContext? buildContext,
Duration timeout = const Duration(minutes: 1), Duration timeout = const Duration(minutes: 1),
}) async { }) async {
return <String, String>{ return <String, String>{
...overrides, ...overrides,
'PRODUCT_BUNDLE_IDENTIFIER': 'io.flutter.someProject', 'PRODUCT_BUNDLE_IDENTIFIER': 'io.flutter.someProject',
...@@ -72,7 +74,10 @@ void main() { ...@@ -72,7 +74,10 @@ void main() {
late FileSystem fileSystem; late FileSystem fileSystem;
late TestUsage usage; late TestUsage usage;
late FakeProcessManager fakeProcessManager; late FakeProcessManager fakeProcessManager;
late ProcessUtils processUtils;
late FakePlistUtils plistUtils; late FakePlistUtils plistUtils;
late BufferLogger logger;
late Artifacts artifacts;
setUpAll(() { setUpAll(() {
Cache.disableLocking(); Cache.disableLocking();
...@@ -80,8 +85,14 @@ void main() { ...@@ -80,8 +85,14 @@ void main() {
setUp(() { setUp(() {
fileSystem = MemoryFileSystem.test(); fileSystem = MemoryFileSystem.test();
artifacts = Artifacts.test(fileSystem: fileSystem);
usage = TestUsage(); usage = TestUsage();
fakeProcessManager = FakeProcessManager.empty(); fakeProcessManager = FakeProcessManager.empty();
logger = BufferLogger.test();
processUtils = ProcessUtils(
logger: logger,
processManager: fakeProcessManager,
);
plistUtils = FakePlistUtils(); plistUtils = FakePlistUtils();
}); });
...@@ -196,10 +207,12 @@ void main() { ...@@ -196,10 +207,12 @@ void main() {
testUsingContext('ipa build fails when there is no ios project', () async { testUsingContext('ipa build fails when there is no ios project', () async {
final BuildCommand command = BuildCommand( final BuildCommand command = BuildCommand(
artifacts: artifacts,
androidSdk: FakeAndroidSdk(), androidSdk: FakeAndroidSdk(),
buildSystem: TestBuildSystem.all(BuildResult(success: true)), buildSystem: TestBuildSystem.all(BuildResult(success: true)),
fileSystem: MemoryFileSystem.test(), logger: logger,
logger: BufferLogger.test(), fileSystem: fileSystem,
processUtils: processUtils,
osUtils: FakeOperatingSystemUtils(), osUtils: FakeOperatingSystemUtils(),
); );
createCoreMockProjectFiles(); createCoreMockProjectFiles();
...@@ -210,16 +223,18 @@ void main() { ...@@ -210,16 +223,18 @@ void main() {
}, overrides: <Type, Generator>{ }, overrides: <Type, Generator>{
Platform: () => macosPlatform, Platform: () => macosPlatform,
FileSystem: () => fileSystem, FileSystem: () => fileSystem,
ProcessManager: () => FakeProcessManager.any(), ProcessManager: () => fakeProcessManager,
XcodeProjectInterpreter: () => FakeXcodeProjectInterpreterWithBuildSettings(), XcodeProjectInterpreter: () => FakeXcodeProjectInterpreterWithBuildSettings(),
}); });
testUsingContext('ipa build fails in debug with code analysis', () async { testUsingContext('ipa build fails in debug with code analysis', () async {
final BuildCommand command = BuildCommand( final BuildCommand command = BuildCommand(
artifacts: artifacts,
androidSdk: FakeAndroidSdk(), androidSdk: FakeAndroidSdk(),
buildSystem: TestBuildSystem.all(BuildResult(success: true)), buildSystem: TestBuildSystem.all(BuildResult(success: true)),
fileSystem: MemoryFileSystem.test(), logger: logger,
logger: BufferLogger.test(), fileSystem: fileSystem,
processUtils: processUtils,
osUtils: FakeOperatingSystemUtils(), osUtils: FakeOperatingSystemUtils(),
); );
createCoreMockProjectFiles(); createCoreMockProjectFiles();
...@@ -230,16 +245,18 @@ void main() { ...@@ -230,16 +245,18 @@ void main() {
}, overrides: <Type, Generator>{ }, overrides: <Type, Generator>{
Platform: () => macosPlatform, Platform: () => macosPlatform,
FileSystem: () => fileSystem, FileSystem: () => fileSystem,
ProcessManager: () => FakeProcessManager.any(), ProcessManager: () => fakeProcessManager,
XcodeProjectInterpreter: () => FakeXcodeProjectInterpreterWithBuildSettings(), XcodeProjectInterpreter: () => FakeXcodeProjectInterpreterWithBuildSettings(),
}); });
testUsingContext('ipa build fails on non-macOS platform', () async { testUsingContext('ipa build fails on non-macOS platform', () async {
final BuildCommand command = BuildCommand( final BuildCommand command = BuildCommand(
artifacts: artifacts,
androidSdk: FakeAndroidSdk(), androidSdk: FakeAndroidSdk(),
buildSystem: TestBuildSystem.all(BuildResult(success: true)), buildSystem: TestBuildSystem.all(BuildResult(success: true)),
fileSystem: MemoryFileSystem.test(), logger: logger,
logger: BufferLogger.test(), fileSystem: fileSystem,
processUtils: processUtils,
osUtils: FakeOperatingSystemUtils(), osUtils: FakeOperatingSystemUtils(),
); );
fileSystem.file('pubspec.yaml').createSync(); fileSystem.file('pubspec.yaml').createSync();
...@@ -253,18 +270,21 @@ void main() { ...@@ -253,18 +270,21 @@ void main() {
), supported ? throwsToolExit() : throwsA(isA<UsageException>())); ), supported ? throwsToolExit() : throwsA(isA<UsageException>()));
}, overrides: <Type, Generator>{ }, overrides: <Type, Generator>{
Platform: () => notMacosPlatform, Platform: () => notMacosPlatform,
Logger: () => logger,
FileSystem: () => fileSystem, FileSystem: () => fileSystem,
ProcessManager: () => FakeProcessManager.any(), ProcessManager: () => fakeProcessManager,
XcodeProjectInterpreter: () => FakeXcodeProjectInterpreterWithBuildSettings(), XcodeProjectInterpreter: () => FakeXcodeProjectInterpreterWithBuildSettings(),
}); });
testUsingContext('ipa build fails when export plist does not exist', testUsingContext('ipa build fails when export plist does not exist',
() async { () async {
final BuildCommand command = BuildCommand( final BuildCommand command = BuildCommand(
artifacts: artifacts,
androidSdk: FakeAndroidSdk(), androidSdk: FakeAndroidSdk(),
buildSystem: TestBuildSystem.all(BuildResult(success: true)), buildSystem: TestBuildSystem.all(BuildResult(success: true)),
fileSystem: MemoryFileSystem.test(), logger: logger,
logger: BufferLogger.test(), fileSystem: fileSystem,
processUtils: processUtils,
osUtils: FakeOperatingSystemUtils(), osUtils: FakeOperatingSystemUtils(),
); );
createMinimalMockProjectFiles(); createMinimalMockProjectFiles();
...@@ -281,7 +301,8 @@ void main() { ...@@ -281,7 +301,8 @@ void main() {
); );
}, overrides: <Type, Generator>{ }, overrides: <Type, Generator>{
FileSystem: () => fileSystem, FileSystem: () => fileSystem,
ProcessManager: () => FakeProcessManager.any(), Logger: () => logger,
ProcessManager: () => fakeProcessManager,
Platform: () => macosPlatform, Platform: () => macosPlatform,
XcodeProjectInterpreter: () => XcodeProjectInterpreter: () =>
FakeXcodeProjectInterpreterWithBuildSettings(), FakeXcodeProjectInterpreterWithBuildSettings(),
...@@ -290,10 +311,12 @@ void main() { ...@@ -290,10 +311,12 @@ void main() {
testUsingContext('ipa build fails when export plist is not a file', () async { testUsingContext('ipa build fails when export plist is not a file', () async {
final Directory bogus = fileSystem.directory('bogus')..createSync(); final Directory bogus = fileSystem.directory('bogus')..createSync();
final BuildCommand command = BuildCommand( final BuildCommand command = BuildCommand(
artifacts: artifacts,
androidSdk: FakeAndroidSdk(), androidSdk: FakeAndroidSdk(),
buildSystem: TestBuildSystem.all(BuildResult(success: true)), buildSystem: TestBuildSystem.all(BuildResult(success: true)),
fileSystem: MemoryFileSystem.test(), logger: logger,
logger: BufferLogger.test(), fileSystem: fileSystem,
processUtils: processUtils,
osUtils: FakeOperatingSystemUtils(), osUtils: FakeOperatingSystemUtils(),
); );
createMinimalMockProjectFiles(); createMinimalMockProjectFiles();
...@@ -310,17 +333,19 @@ void main() { ...@@ -310,17 +333,19 @@ void main() {
); );
}, overrides: <Type, Generator>{ }, overrides: <Type, Generator>{
FileSystem: () => fileSystem, FileSystem: () => fileSystem,
ProcessManager: () => FakeProcessManager.any(), ProcessManager: () => fakeProcessManager,
Platform: () => macosPlatform, Platform: () => macosPlatform,
XcodeProjectInterpreter: () => FakeXcodeProjectInterpreterWithBuildSettings(), XcodeProjectInterpreter: () => FakeXcodeProjectInterpreterWithBuildSettings(),
}); });
testUsingContext('ipa build fails when --export-options-plist and --export-method are used together', () async { testUsingContext('ipa build fails when --export-options-plist and --export-method are used together', () async {
final BuildCommand command = BuildCommand( final BuildCommand command = BuildCommand(
artifacts: artifacts,
androidSdk: FakeAndroidSdk(), androidSdk: FakeAndroidSdk(),
buildSystem: TestBuildSystem.all(BuildResult(success: true)), buildSystem: TestBuildSystem.all(BuildResult(success: true)),
fileSystem: MemoryFileSystem.test(), logger: logger,
logger: BufferLogger.test(), fileSystem: fileSystem,
processUtils: processUtils,
osUtils: FakeOperatingSystemUtils(), osUtils: FakeOperatingSystemUtils(),
); );
createMinimalMockProjectFiles(); createMinimalMockProjectFiles();
...@@ -339,17 +364,19 @@ void main() { ...@@ -339,17 +364,19 @@ void main() {
); );
}, overrides: <Type, Generator>{ }, overrides: <Type, Generator>{
FileSystem: () => fileSystem, FileSystem: () => fileSystem,
ProcessManager: () => FakeProcessManager.any(), ProcessManager: () => fakeProcessManager,
Platform: () => macosPlatform, Platform: () => macosPlatform,
XcodeProjectInterpreter: () => FakeXcodeProjectInterpreterWithBuildSettings(), XcodeProjectInterpreter: () => FakeXcodeProjectInterpreterWithBuildSettings(),
}); });
testUsingContext('ipa build reports when IPA fails', () async { testUsingContext('ipa build reports when IPA fails', () async {
final BuildCommand command = BuildCommand( final BuildCommand command = BuildCommand(
artifacts: artifacts,
androidSdk: FakeAndroidSdk(), androidSdk: FakeAndroidSdk(),
buildSystem: TestBuildSystem.all(BuildResult(success: true)), buildSystem: TestBuildSystem.all(BuildResult(success: true)),
fileSystem: MemoryFileSystem.test(), logger: logger,
logger: BufferLogger.test(), fileSystem: fileSystem,
processUtils: processUtils,
osUtils: FakeOperatingSystemUtils(), osUtils: FakeOperatingSystemUtils(),
); );
fakeProcessManager.addCommands(<FakeCommand>[ fakeProcessManager.addCommands(<FakeCommand>[
...@@ -379,13 +406,14 @@ void main() { ...@@ -379,13 +406,14 @@ void main() {
const <String>['build', 'ipa', '--no-pub'] const <String>['build', 'ipa', '--no-pub']
); );
expect(testLogger.statusText, contains('build/ios/archive/Runner.xcarchive')); expect(logger.statusText, contains('build/ios/archive/Runner.xcarchive'));
expect(testLogger.statusText, contains('Building App Store IPA')); expect(logger.statusText, contains('Building App Store IPA'));
expect(testLogger.errorText, contains('Encountered error while creating the IPA:')); expect(logger.errorText, contains('Encountered error while creating the IPA:'));
expect(testLogger.errorText, contains('error: exportArchive: "Runner.app" requires a provisioning profile.')); expect(logger.errorText, contains('error: exportArchive: "Runner.app" requires a provisioning profile.'));
expect(fakeProcessManager, hasNoRemainingExpectations); expect(fakeProcessManager, hasNoRemainingExpectations);
}, overrides: <Type, Generator>{ }, overrides: <Type, Generator>{
FileSystem: () => fileSystem, FileSystem: () => fileSystem,
Logger: () => logger,
ProcessManager: () => fakeProcessManager, ProcessManager: () => fakeProcessManager,
Platform: () => macosPlatform, Platform: () => macosPlatform,
XcodeProjectInterpreter: () => FakeXcodeProjectInterpreterWithBuildSettings(), XcodeProjectInterpreter: () => FakeXcodeProjectInterpreterWithBuildSettings(),
...@@ -394,10 +422,12 @@ void main() { ...@@ -394,10 +422,12 @@ void main() {
testUsingContext('ipa build invokes xcodebuild and archives for app store', () async { testUsingContext('ipa build invokes xcodebuild and archives for app store', () async {
final File cachedExportOptionsPlist = fileSystem.file('/CachedExportOptions.plist'); final File cachedExportOptionsPlist = fileSystem.file('/CachedExportOptions.plist');
final BuildCommand command = BuildCommand( final BuildCommand command = BuildCommand(
artifacts: artifacts,
androidSdk: FakeAndroidSdk(), androidSdk: FakeAndroidSdk(),
buildSystem: TestBuildSystem.all(BuildResult(success: true)), buildSystem: TestBuildSystem.all(BuildResult(success: true)),
fileSystem: MemoryFileSystem.test(), logger: logger,
logger: BufferLogger.test(), fileSystem: fileSystem,
processUtils: processUtils,
osUtils: FakeOperatingSystemUtils(), osUtils: FakeOperatingSystemUtils(),
); );
fakeProcessManager.addCommands(<FakeCommand>[ fakeProcessManager.addCommands(<FakeCommand>[
...@@ -427,14 +457,15 @@ void main() { ...@@ -427,14 +457,15 @@ void main() {
final String actualIpaPlistContents = fileSystem.file(cachedExportOptionsPlist).readAsStringSync(); final String actualIpaPlistContents = fileSystem.file(cachedExportOptionsPlist).readAsStringSync();
expect(actualIpaPlistContents, expectedIpaPlistContents); expect(actualIpaPlistContents, expectedIpaPlistContents);
expect(testLogger.statusText, contains('build/ios/archive/Runner.xcarchive')); expect(logger.statusText, contains('build/ios/archive/Runner.xcarchive'));
expect(testLogger.statusText, contains('Building App Store IPA')); expect(logger.statusText, contains('Building App Store IPA'));
expect(testLogger.statusText, contains('Built IPA to /build/ios/ipa')); expect(logger.statusText, contains('Built IPA to /build/ios/ipa'));
expect(testLogger.statusText, contains('To upload to the App Store')); expect(logger.statusText, contains('To upload to the App Store'));
expect(testLogger.statusText, contains('Apple Transporter macOS app')); expect(logger.statusText, contains('Apple Transporter macOS app'));
expect(fakeProcessManager, hasNoRemainingExpectations); expect(fakeProcessManager, hasNoRemainingExpectations);
}, overrides: <Type, Generator>{ }, overrides: <Type, Generator>{
FileSystem: () => fileSystem, FileSystem: () => fileSystem,
Logger: () => logger,
ProcessManager: () => fakeProcessManager, ProcessManager: () => fakeProcessManager,
Platform: () => macosPlatform, Platform: () => macosPlatform,
XcodeProjectInterpreter: () => FakeXcodeProjectInterpreterWithBuildSettings(), XcodeProjectInterpreter: () => FakeXcodeProjectInterpreterWithBuildSettings(),
...@@ -443,10 +474,12 @@ void main() { ...@@ -443,10 +474,12 @@ void main() {
testUsingContext('ipa build invokes xcodebuild and archives for ad-hoc distribution', () async { testUsingContext('ipa build invokes xcodebuild and archives for ad-hoc distribution', () async {
final File cachedExportOptionsPlist = fileSystem.file('/CachedExportOptions.plist'); final File cachedExportOptionsPlist = fileSystem.file('/CachedExportOptions.plist');
final BuildCommand command = BuildCommand( final BuildCommand command = BuildCommand(
artifacts: artifacts,
androidSdk: FakeAndroidSdk(), androidSdk: FakeAndroidSdk(),
buildSystem: TestBuildSystem.all(BuildResult(success: true)), buildSystem: TestBuildSystem.all(BuildResult(success: true)),
fileSystem: MemoryFileSystem.test(), logger: logger,
logger: BufferLogger.test(), fileSystem: fileSystem,
processUtils: processUtils,
osUtils: FakeOperatingSystemUtils(), osUtils: FakeOperatingSystemUtils(),
); );
fakeProcessManager.addCommands(<FakeCommand>[ fakeProcessManager.addCommands(<FakeCommand>[
...@@ -476,14 +509,15 @@ void main() { ...@@ -476,14 +509,15 @@ void main() {
final String actualIpaPlistContents = fileSystem.file(cachedExportOptionsPlist).readAsStringSync(); final String actualIpaPlistContents = fileSystem.file(cachedExportOptionsPlist).readAsStringSync();
expect(actualIpaPlistContents, expectedIpaPlistContents); expect(actualIpaPlistContents, expectedIpaPlistContents);
expect(testLogger.statusText, contains('build/ios/archive/Runner.xcarchive')); expect(logger.statusText, contains('build/ios/archive/Runner.xcarchive'));
expect(testLogger.statusText, contains('Building ad-hoc IPA')); expect(logger.statusText, contains('Building ad-hoc IPA'));
expect(testLogger.statusText, contains('Built IPA to /build/ios/ipa')); expect(logger.statusText, contains('Built IPA to /build/ios/ipa'));
// Don't instruct how to upload to the App Store. // Don'ltruct how to upload to the App Store.
expect(testLogger.statusText, isNot(contains('To upload'))); expect(logger.statusText, isNot(contains('To upload')));
expect(fakeProcessManager, hasNoRemainingExpectations); expect(fakeProcessManager, hasNoRemainingExpectations);
}, overrides: <Type, Generator>{ }, overrides: <Type, Generator>{
FileSystem: () => fileSystem, FileSystem: () => fileSystem,
Logger: () => logger,
ProcessManager: () => fakeProcessManager, ProcessManager: () => fakeProcessManager,
Platform: () => macosPlatform, Platform: () => macosPlatform,
XcodeProjectInterpreter: () => FakeXcodeProjectInterpreterWithBuildSettings(), XcodeProjectInterpreter: () => FakeXcodeProjectInterpreterWithBuildSettings(),
...@@ -492,10 +526,12 @@ void main() { ...@@ -492,10 +526,12 @@ void main() {
testUsingContext('ipa build invokes xcodebuild and archives for enterprise distribution', () async { testUsingContext('ipa build invokes xcodebuild and archives for enterprise distribution', () async {
final File cachedExportOptionsPlist = fileSystem.file('/CachedExportOptions.plist'); final File cachedExportOptionsPlist = fileSystem.file('/CachedExportOptions.plist');
final BuildCommand command = BuildCommand( final BuildCommand command = BuildCommand(
artifacts: artifacts,
androidSdk: FakeAndroidSdk(), androidSdk: FakeAndroidSdk(),
buildSystem: TestBuildSystem.all(BuildResult(success: true)), buildSystem: TestBuildSystem.all(BuildResult(success: true)),
fileSystem: MemoryFileSystem.test(), logger: logger,
logger: BufferLogger.test(), fileSystem: fileSystem,
processUtils: processUtils,
osUtils: FakeOperatingSystemUtils(), osUtils: FakeOperatingSystemUtils(),
); );
fakeProcessManager.addCommands(<FakeCommand>[ fakeProcessManager.addCommands(<FakeCommand>[
...@@ -525,14 +561,15 @@ void main() { ...@@ -525,14 +561,15 @@ void main() {
final String actualIpaPlistContents = fileSystem.file(cachedExportOptionsPlist).readAsStringSync(); final String actualIpaPlistContents = fileSystem.file(cachedExportOptionsPlist).readAsStringSync();
expect(actualIpaPlistContents, expectedIpaPlistContents); expect(actualIpaPlistContents, expectedIpaPlistContents);
expect(testLogger.statusText, contains('build/ios/archive/Runner.xcarchive')); expect(logger.statusText, contains('build/ios/archive/Runner.xcarchive'));
expect(testLogger.statusText, contains('Building enterprise IPA')); expect(logger.statusText, contains('Building enterprise IPA'));
expect(testLogger.statusText, contains('Built IPA to /build/ios/ipa')); expect(logger.statusText, contains('Built IPA to /build/ios/ipa'));
// Don't instruct how to upload to the App Store. // Don'ltruct how to upload to the App Store.
expect(testLogger.statusText, isNot(contains('To upload'))); expect(logger.statusText, isNot(contains('To upload')));
expect(fakeProcessManager, hasNoRemainingExpectations); expect(fakeProcessManager, hasNoRemainingExpectations);
}, overrides: <Type, Generator>{ }, overrides: <Type, Generator>{
FileSystem: () => fileSystem, FileSystem: () => fileSystem,
Logger: () => logger,
ProcessManager: () => fakeProcessManager, ProcessManager: () => fakeProcessManager,
Platform: () => macosPlatform, Platform: () => macosPlatform,
XcodeProjectInterpreter: () => FakeXcodeProjectInterpreterWithBuildSettings(), XcodeProjectInterpreter: () => FakeXcodeProjectInterpreterWithBuildSettings(),
...@@ -540,10 +577,12 @@ void main() { ...@@ -540,10 +577,12 @@ void main() {
testUsingContext('ipa build invokes xcode build with verbosity', () async { testUsingContext('ipa build invokes xcode build with verbosity', () async {
final BuildCommand command = BuildCommand( final BuildCommand command = BuildCommand(
artifacts: artifacts,
androidSdk: FakeAndroidSdk(), androidSdk: FakeAndroidSdk(),
buildSystem: TestBuildSystem.all(BuildResult(success: true)), buildSystem: TestBuildSystem.all(BuildResult(success: true)),
fileSystem: MemoryFileSystem.test(), logger: logger,
logger: BufferLogger.test(), fileSystem: fileSystem,
processUtils: processUtils,
osUtils: FakeOperatingSystemUtils(), osUtils: FakeOperatingSystemUtils(),
); );
fakeProcessManager.addCommands(<FakeCommand>[ fakeProcessManager.addCommands(<FakeCommand>[
...@@ -559,6 +598,7 @@ void main() { ...@@ -559,6 +598,7 @@ void main() {
expect(fakeProcessManager, hasNoRemainingExpectations); expect(fakeProcessManager, hasNoRemainingExpectations);
}, overrides: <Type, Generator>{ }, overrides: <Type, Generator>{
FileSystem: () => fileSystem, FileSystem: () => fileSystem,
Logger: () => logger,
ProcessManager: () => fakeProcessManager, ProcessManager: () => fakeProcessManager,
Platform: () => macosPlatform, Platform: () => macosPlatform,
XcodeProjectInterpreter: () => FakeXcodeProjectInterpreterWithBuildSettings(), XcodeProjectInterpreter: () => FakeXcodeProjectInterpreterWithBuildSettings(),
...@@ -566,10 +606,12 @@ void main() { ...@@ -566,10 +606,12 @@ void main() {
testUsingContext('ipa build --no-codesign skips codesigning and IPA creation', () async { testUsingContext('ipa build --no-codesign skips codesigning and IPA creation', () async {
final BuildCommand command = BuildCommand( final BuildCommand command = BuildCommand(
artifacts: artifacts,
androidSdk: FakeAndroidSdk(), androidSdk: FakeAndroidSdk(),
buildSystem: TestBuildSystem.all(BuildResult(success: true)), buildSystem: TestBuildSystem.all(BuildResult(success: true)),
fileSystem: MemoryFileSystem.test(), logger: logger,
logger: BufferLogger.test(), fileSystem: fileSystem,
processUtils: processUtils,
osUtils: FakeOperatingSystemUtils(), osUtils: FakeOperatingSystemUtils(),
); );
fakeProcessManager.addCommands(<FakeCommand>[ fakeProcessManager.addCommands(<FakeCommand>[
...@@ -605,9 +647,10 @@ void main() { ...@@ -605,9 +647,10 @@ void main() {
const <String>['build', 'ipa', '--no-pub', '--no-codesign'] const <String>['build', 'ipa', '--no-pub', '--no-codesign']
); );
expect(fakeProcessManager, hasNoRemainingExpectations); expect(fakeProcessManager, hasNoRemainingExpectations);
expect(testLogger.statusText, contains('Codesigning disabled with --no-codesign, skipping IPA')); expect(logger.statusText, contains('Codesigning disabled with --no-codesign, skipping IPA'));
}, overrides: <Type, Generator>{ }, overrides: <Type, Generator>{
FileSystem: () => fileSystem, FileSystem: () => fileSystem,
Logger: () => logger,
ProcessManager: () => fakeProcessManager, ProcessManager: () => fakeProcessManager,
Platform: () => macosPlatform, Platform: () => macosPlatform,
XcodeProjectInterpreter: () => FakeXcodeProjectInterpreterWithBuildSettings(), XcodeProjectInterpreter: () => FakeXcodeProjectInterpreterWithBuildSettings(),
...@@ -615,14 +658,17 @@ void main() { ...@@ -615,14 +658,17 @@ void main() {
testUsingContext('code size analysis fails when app not found', () async { testUsingContext('code size analysis fails when app not found', () async {
final BuildCommand command = BuildCommand( final BuildCommand command = BuildCommand(
artifacts: artifacts,
androidSdk: FakeAndroidSdk(), androidSdk: FakeAndroidSdk(),
buildSystem: TestBuildSystem.all(BuildResult(success: true)), buildSystem: TestBuildSystem.all(BuildResult(success: true)),
fileSystem: MemoryFileSystem.test(), logger: logger,
logger: BufferLogger.test(), fileSystem: fileSystem,
processUtils: processUtils,
osUtils: FakeOperatingSystemUtils(), osUtils: FakeOperatingSystemUtils(),
); );
createMinimalMockProjectFiles(); createMinimalMockProjectFiles();
fakeProcessManager.addCommand(setUpFakeXcodeBuildHandler());
await expectToolExitLater( await expectToolExitLater(
createTestCommandRunner(command).run( createTestCommandRunner(command).run(
const <String>['build', 'ipa', '--no-pub', '--analyze-size'] const <String>['build', 'ipa', '--no-pub', '--analyze-size']
...@@ -631,17 +677,19 @@ void main() { ...@@ -631,17 +677,19 @@ void main() {
); );
}, overrides: <Type, Generator>{ }, overrides: <Type, Generator>{
FileSystem: () => fileSystem, FileSystem: () => fileSystem,
ProcessManager: () => FakeProcessManager.any(), ProcessManager: () => fakeProcessManager,
Platform: () => macosPlatform, Platform: () => macosPlatform,
XcodeProjectInterpreter: () => FakeXcodeProjectInterpreterWithBuildSettings(), XcodeProjectInterpreter: () => FakeXcodeProjectInterpreterWithBuildSettings(),
}); });
testUsingContext('Performs code size analysis and sends analytics', () async { testUsingContext('Performs code size analysis and sends analytics', () async {
final BuildCommand command = BuildCommand( final BuildCommand command = BuildCommand(
artifacts: artifacts,
androidSdk: FakeAndroidSdk(), androidSdk: FakeAndroidSdk(),
buildSystem: TestBuildSystem.all(BuildResult(success: true)), buildSystem: TestBuildSystem.all(BuildResult(success: true)),
fileSystem: MemoryFileSystem.test(), logger: logger,
logger: BufferLogger.test(), fileSystem: fileSystem,
processUtils: processUtils,
osUtils: FakeOperatingSystemUtils(), osUtils: FakeOperatingSystemUtils(),
); );
createMinimalMockProjectFiles(); createMinimalMockProjectFiles();
...@@ -674,14 +722,15 @@ void main() { ...@@ -674,14 +722,15 @@ void main() {
const <String>['build', 'ipa', '--no-pub', '--analyze-size'] const <String>['build', 'ipa', '--no-pub', '--analyze-size']
); );
expect(testLogger.statusText, contains('A summary of your iOS bundle analysis can be found at')); expect(logger.statusText, contains('A summary of your iOS bundle analysis can be found at'));
expect(testLogger.statusText, contains('dart devtools --appSizeBase=')); expect(logger.statusText, contains('dart devtools --appSizeBase='));
expect(usage.events, contains( expect(usage.events, contains(
const TestUsageEvent('code-size-analysis', 'ios'), const TestUsageEvent('code-size-analysis', 'ios'),
)); ));
expect(fakeProcessManager, hasNoRemainingExpectations); expect(fakeProcessManager, hasNoRemainingExpectations);
}, overrides: <Type, Generator>{ }, overrides: <Type, Generator>{
FileSystem: () => fileSystem, FileSystem: () => fileSystem,
Logger: () => logger,
ProcessManager: () => fakeProcessManager, ProcessManager: () => fakeProcessManager,
Platform: () => macosPlatform, Platform: () => macosPlatform,
FileSystemUtils: () => FileSystemUtils(fileSystem: fileSystem, platform: macosPlatform), FileSystemUtils: () => FileSystemUtils(fileSystem: fileSystem, platform: macosPlatform),
...@@ -695,10 +744,12 @@ void main() { ...@@ -695,10 +744,12 @@ void main() {
final File exportOptions = fileSystem.file('ExportOptions.plist') final File exportOptions = fileSystem.file('ExportOptions.plist')
..createSync(); ..createSync();
final BuildCommand command = BuildCommand( final BuildCommand command = BuildCommand(
artifacts: artifacts,
androidSdk: FakeAndroidSdk(), androidSdk: FakeAndroidSdk(),
buildSystem: TestBuildSystem.all(BuildResult(success: true)), buildSystem: TestBuildSystem.all(BuildResult(success: true)),
fileSystem: MemoryFileSystem.test(), logger: logger,
logger: BufferLogger.test(), fileSystem: fileSystem,
processUtils: processUtils,
osUtils: FakeOperatingSystemUtils(), osUtils: FakeOperatingSystemUtils(),
); );
fakeProcessManager.addCommands(<FakeCommand>[ fakeProcessManager.addCommands(<FakeCommand>[
...@@ -718,10 +769,11 @@ void main() { ...@@ -718,10 +769,11 @@ void main() {
], ],
); );
expect(testLogger.statusText, contains('Built IPA to $outputPath.')); expect(logger.statusText, contains('Built IPA to $outputPath.'));
expect(fakeProcessManager, hasNoRemainingExpectations); expect(fakeProcessManager, hasNoRemainingExpectations);
}, overrides: <Type, Generator>{ }, overrides: <Type, Generator>{
FileSystem: () => fileSystem, FileSystem: () => fileSystem,
Logger: () => logger,
ProcessManager: () => fakeProcessManager, ProcessManager: () => fakeProcessManager,
Platform: () => macosPlatform, Platform: () => macosPlatform,
XcodeProjectInterpreter: () => FakeXcodeProjectInterpreterWithBuildSettings(), XcodeProjectInterpreter: () => FakeXcodeProjectInterpreterWithBuildSettings(),
...@@ -729,10 +781,12 @@ void main() { ...@@ -729,10 +781,12 @@ void main() {
testUsingContext('Trace error if xcresult is empty.', () async { testUsingContext('Trace error if xcresult is empty.', () async {
final BuildCommand command = BuildCommand( final BuildCommand command = BuildCommand(
artifacts: artifacts,
androidSdk: FakeAndroidSdk(), androidSdk: FakeAndroidSdk(),
buildSystem: TestBuildSystem.all(BuildResult(success: true)), buildSystem: TestBuildSystem.all(BuildResult(success: true)),
fileSystem: MemoryFileSystem.test(), logger: logger,
logger: BufferLogger.test(), fileSystem: fileSystem,
processUtils: processUtils,
osUtils: FakeOperatingSystemUtils(), osUtils: FakeOperatingSystemUtils(),
); );
fakeProcessManager.addCommands(<FakeCommand>[ fakeProcessManager.addCommands(<FakeCommand>[
...@@ -749,10 +803,11 @@ void main() { ...@@ -749,10 +803,11 @@ void main() {
throwsToolExit(), throwsToolExit(),
); );
expect(testLogger.traceText, contains('xcresult parser: Unrecognized top level json format.')); expect(logger.traceText, contains('xcresult parser: Unrecognized top level json format.'));
expect(fakeProcessManager, hasNoRemainingExpectations); expect(fakeProcessManager, hasNoRemainingExpectations);
}, overrides: <Type, Generator>{ }, overrides: <Type, Generator>{
FileSystem: () => fileSystem, FileSystem: () => fileSystem,
Logger: () => logger,
ProcessManager: () => fakeProcessManager, ProcessManager: () => fakeProcessManager,
Platform: () => macosPlatform, Platform: () => macosPlatform,
XcodeProjectInterpreter: () => FakeXcodeProjectInterpreterWithBuildSettings(), XcodeProjectInterpreter: () => FakeXcodeProjectInterpreterWithBuildSettings(),
...@@ -760,10 +815,12 @@ void main() { ...@@ -760,10 +815,12 @@ void main() {
testUsingContext('Display xcresult issues on console if parsed.', () async { testUsingContext('Display xcresult issues on console if parsed.', () async {
final BuildCommand command = BuildCommand( final BuildCommand command = BuildCommand(
artifacts: artifacts,
androidSdk: FakeAndroidSdk(), androidSdk: FakeAndroidSdk(),
buildSystem: TestBuildSystem.all(BuildResult(success: true)), buildSystem: TestBuildSystem.all(BuildResult(success: true)),
fileSystem: MemoryFileSystem.test(), logger: logger,
logger: BufferLogger.test(), fileSystem: fileSystem,
processUtils: processUtils,
osUtils: FakeOperatingSystemUtils(), osUtils: FakeOperatingSystemUtils(),
); );
fakeProcessManager.addCommands(<FakeCommand>[ fakeProcessManager.addCommands(<FakeCommand>[
...@@ -780,11 +837,12 @@ void main() { ...@@ -780,11 +837,12 @@ void main() {
throwsToolExit(), throwsToolExit(),
); );
expect(testLogger.errorText, contains("Use of undeclared identifier 'asdas'")); expect(logger.errorText, contains("Use of undeclared identifier 'asdas'"));
expect(testLogger.errorText, contains('/Users/m/Projects/test_create/ios/Runner/AppDelegate.m:7:56')); expect(logger.errorText, contains('/Users/m/Projects/test_create/ios/Runner/AppDelegate.m:7:56'));
expect(fakeProcessManager, hasNoRemainingExpectations); expect(fakeProcessManager, hasNoRemainingExpectations);
}, overrides: <Type, Generator>{ }, overrides: <Type, Generator>{
FileSystem: () => fileSystem, FileSystem: () => fileSystem,
Logger: () => logger,
ProcessManager: () => fakeProcessManager, ProcessManager: () => fakeProcessManager,
Platform: () => macosPlatform, Platform: () => macosPlatform,
XcodeProjectInterpreter: () => FakeXcodeProjectInterpreterWithBuildSettings(), XcodeProjectInterpreter: () => FakeXcodeProjectInterpreterWithBuildSettings(),
...@@ -792,10 +850,12 @@ void main() { ...@@ -792,10 +850,12 @@ void main() {
testUsingContext('Do not display xcresult issues that needs to be discarded.', () async { testUsingContext('Do not display xcresult issues that needs to be discarded.', () async {
final BuildCommand command = BuildCommand( final BuildCommand command = BuildCommand(
artifacts: artifacts,
androidSdk: FakeAndroidSdk(), androidSdk: FakeAndroidSdk(),
buildSystem: TestBuildSystem.all(BuildResult(success: true)), buildSystem: TestBuildSystem.all(BuildResult(success: true)),
fileSystem: MemoryFileSystem.test(), logger: logger,
logger: BufferLogger.test(), fileSystem: fileSystem,
processUtils: processUtils,
osUtils: FakeOperatingSystemUtils(), osUtils: FakeOperatingSystemUtils(),
); );
fakeProcessManager.addCommands(<FakeCommand>[ fakeProcessManager.addCommands(<FakeCommand>[
...@@ -812,13 +872,14 @@ void main() { ...@@ -812,13 +872,14 @@ void main() {
throwsToolExit(), throwsToolExit(),
); );
expect(testLogger.errorText, contains("Use of undeclared identifier 'asdas'")); expect(logger.errorText, contains("Use of undeclared identifier 'asdas'"));
expect(testLogger.errorText, contains('/Users/m/Projects/test_create/ios/Runner/AppDelegate.m:7:56')); expect(logger.errorText, contains('/Users/m/Projects/test_create/ios/Runner/AppDelegate.m:7:56'));
expect(testLogger.errorText, isNot(contains('Command PhaseScriptExecution failed with a nonzero exit code'))); expect(logger.errorText, isNot(contains('Command PhaseScriptExecution failed with a nonzero exit code')));
expect(testLogger.warningText, isNot(contains("The iOS deployment target 'IPHONEOS_DEPLOYMENT_TARGET' is set to 8.0, but the range of supported deployment target versions is 9.0 to 14.0.99."))); expect(logger.warningText, isNot(contains("The iOS deployment target 'IPHONEOS_DEPLOYMENT_TARGET' is set to 8.0, but the range of supported deployment target versions is 9.0 to 14.0.99.")));
expect(fakeProcessManager, hasNoRemainingExpectations); expect(fakeProcessManager, hasNoRemainingExpectations);
}, overrides: <Type, Generator>{ }, overrides: <Type, Generator>{
FileSystem: () => fileSystem, FileSystem: () => fileSystem,
Logger: () => logger,
ProcessManager: () => fakeProcessManager, ProcessManager: () => fakeProcessManager,
Platform: () => macosPlatform, Platform: () => macosPlatform,
XcodeProjectInterpreter: () => FakeXcodeProjectInterpreterWithBuildSettings(), XcodeProjectInterpreter: () => FakeXcodeProjectInterpreterWithBuildSettings(),
...@@ -826,10 +887,12 @@ void main() { ...@@ -826,10 +887,12 @@ void main() {
testUsingContext('Trace if xcresult bundle does not exist.', () async { testUsingContext('Trace if xcresult bundle does not exist.', () async {
final BuildCommand command = BuildCommand( final BuildCommand command = BuildCommand(
artifacts: artifacts,
androidSdk: FakeAndroidSdk(), androidSdk: FakeAndroidSdk(),
buildSystem: TestBuildSystem.all(BuildResult(success: true)), buildSystem: TestBuildSystem.all(BuildResult(success: true)),
fileSystem: MemoryFileSystem.test(), logger: logger,
logger: BufferLogger.test(), fileSystem: fileSystem,
processUtils: processUtils,
osUtils: FakeOperatingSystemUtils(), osUtils: FakeOperatingSystemUtils(),
); );
fakeProcessManager.addCommands(<FakeCommand>[ fakeProcessManager.addCommands(<FakeCommand>[
...@@ -843,10 +906,11 @@ void main() { ...@@ -843,10 +906,11 @@ void main() {
throwsToolExit(), throwsToolExit(),
); );
expect(testLogger.traceText, contains('The xcresult bundle are not generated. Displaying xcresult is disabled.')); expect(logger.traceText, contains('The xcresult bundle are not generated. Displaying xcresult is disabled.'));
expect(fakeProcessManager, hasNoRemainingExpectations); expect(fakeProcessManager, hasNoRemainingExpectations);
}, overrides: <Type, Generator>{ }, overrides: <Type, Generator>{
FileSystem: () => fileSystem, FileSystem: () => fileSystem,
Logger: () => logger,
ProcessManager: () => fakeProcessManager, ProcessManager: () => fakeProcessManager,
Platform: () => macosPlatform, Platform: () => macosPlatform,
XcodeProjectInterpreter: () => FakeXcodeProjectInterpreterWithBuildSettings(), XcodeProjectInterpreter: () => FakeXcodeProjectInterpreterWithBuildSettings(),
...@@ -855,10 +919,12 @@ void main() { ...@@ -855,10 +919,12 @@ void main() {
testUsingContext('Extra error message for provision profile issue in xcresulb bundle.', () async { testUsingContext('Extra error message for provision profile issue in xcresulb bundle.', () async {
final BuildCommand command = BuildCommand( final BuildCommand command = BuildCommand(
artifacts: artifacts,
androidSdk: FakeAndroidSdk(), androidSdk: FakeAndroidSdk(),
buildSystem: TestBuildSystem.all(BuildResult(success: true)), buildSystem: TestBuildSystem.all(BuildResult(success: true)),
fileSystem: MemoryFileSystem.test(), logger: logger,
logger: BufferLogger.test(), fileSystem: fileSystem,
processUtils: processUtils,
osUtils: FakeOperatingSystemUtils(), osUtils: FakeOperatingSystemUtils(),
); );
fakeProcessManager.addCommands(<FakeCommand>[ fakeProcessManager.addCommands(<FakeCommand>[
...@@ -875,14 +941,15 @@ void main() { ...@@ -875,14 +941,15 @@ void main() {
throwsToolExit(), throwsToolExit(),
); );
expect(testLogger.errorText, contains('Some Provisioning profile issue.')); expect(logger.errorText, contains('Some Provisioning profile issue.'));
expect(testLogger.errorText, contains('It appears that there was a problem signing your application prior to installation on the device.')); expect(logger.errorText, contains('It appears that there was a problem signing your application prior to installation on the device.'));
expect(testLogger.errorText, contains('Verify that the Bundle Identifier in your project is your signing id in Xcode')); expect(logger.errorText, contains('Verify that the Bundle Identifier in your project is your signing id in Xcode'));
expect(testLogger.errorText, contains('open ios/Runner.xcworkspace')); expect(logger.errorText, contains('open ios/Runner.xcworkspace'));
expect(testLogger.errorText, contains("Also try selecting 'Product > Build' to fix the problem.")); expect(logger.errorText, contains("Also try selecting 'Product > Build' to fix the problem."));
expect(fakeProcessManager, hasNoRemainingExpectations); expect(fakeProcessManager, hasNoRemainingExpectations);
}, overrides: <Type, Generator>{ }, overrides: <Type, Generator>{
FileSystem: () => fileSystem, FileSystem: () => fileSystem,
Logger: () => logger,
ProcessManager: () => fakeProcessManager, ProcessManager: () => fakeProcessManager,
Platform: () => macosPlatform, Platform: () => macosPlatform,
XcodeProjectInterpreter: () => FakeXcodeProjectInterpreterWithBuildSettings(), XcodeProjectInterpreter: () => FakeXcodeProjectInterpreterWithBuildSettings(),
...@@ -907,17 +974,19 @@ void main() { ...@@ -907,17 +974,19 @@ void main() {
}; };
final BuildCommand command = BuildCommand( final BuildCommand command = BuildCommand(
artifacts: artifacts,
androidSdk: FakeAndroidSdk(), androidSdk: FakeAndroidSdk(),
buildSystem: TestBuildSystem.all(BuildResult(success: true)), buildSystem: TestBuildSystem.all(BuildResult(success: true)),
fileSystem: MemoryFileSystem.test(), logger: logger,
logger: BufferLogger.test(), fileSystem: fileSystem,
processUtils: processUtils,
osUtils: FakeOperatingSystemUtils(), osUtils: FakeOperatingSystemUtils(),
); );
await createTestCommandRunner(command).run( await createTestCommandRunner(command).run(
<String>['build', 'ipa', '--no-pub']); <String>['build', 'ipa', '--no-pub']);
expect( expect(
testLogger.statusText, logger.statusText,
contains( contains(
'[!] App Settings Validation\n' '[!] App Settings Validation\n'
' ! Version Number: Missing\n' ' ! Version Number: Missing\n'
...@@ -928,11 +997,12 @@ void main() { ...@@ -928,11 +997,12 @@ void main() {
' ! You must set up the missing app settings.\n' ' ! You must set up the missing app settings.\n'
)); ));
expect( expect(
testLogger.statusText, logger.statusText,
contains('To update the settings, please refer to https://docs.flutter.dev/deployment/ios') contains('To update the settings, please refer to https://docs.flutter.dev/deployment/ios')
); );
}, overrides: <Type, Generator>{ }, overrides: <Type, Generator>{
FileSystem: () => fileSystem, FileSystem: () => fileSystem,
Logger: () => logger,
ProcessManager: () => fakeProcessManager, ProcessManager: () => fakeProcessManager,
Platform: () => macosPlatform, Platform: () => macosPlatform,
XcodeProjectInterpreter: () => FakeXcodeProjectInterpreterWithBuildSettings(), XcodeProjectInterpreter: () => FakeXcodeProjectInterpreterWithBuildSettings(),
...@@ -963,17 +1033,19 @@ void main() { ...@@ -963,17 +1033,19 @@ void main() {
}; };
final BuildCommand command = BuildCommand( final BuildCommand command = BuildCommand(
artifacts: artifacts,
androidSdk: FakeAndroidSdk(), androidSdk: FakeAndroidSdk(),
buildSystem: TestBuildSystem.all(BuildResult(success: true)), buildSystem: TestBuildSystem.all(BuildResult(success: true)),
fileSystem: MemoryFileSystem.test(), logger: logger,
logger: BufferLogger.test(), fileSystem: fileSystem,
processUtils: processUtils,
osUtils: FakeOperatingSystemUtils(), osUtils: FakeOperatingSystemUtils(),
); );
await createTestCommandRunner(command).run( await createTestCommandRunner(command).run(
<String>['build', 'ipa', '--no-pub']); <String>['build', 'ipa', '--no-pub']);
expect( expect(
testLogger.statusText, logger.statusText,
contains( contains(
'[✓] App Settings Validation\n' '[✓] App Settings Validation\n'
' • Version Number: 12.34.56\n' ' • Version Number: 12.34.56\n'
...@@ -984,11 +1056,12 @@ void main() { ...@@ -984,11 +1056,12 @@ void main() {
) )
); );
expect( expect(
testLogger.statusText, logger.statusText,
contains('To update the settings, please refer to https://docs.flutter.dev/deployment/ios') contains('To update the settings, please refer to https://docs.flutter.dev/deployment/ios')
); );
}, overrides: <Type, Generator>{ }, overrides: <Type, Generator>{
FileSystem: () => fileSystem, FileSystem: () => fileSystem,
Logger: () => logger,
ProcessManager: () => fakeProcessManager, ProcessManager: () => fakeProcessManager,
Platform: () => macosPlatform, Platform: () => macosPlatform,
XcodeProjectInterpreter: () => FakeXcodeProjectInterpreterWithBuildSettings(), XcodeProjectInterpreter: () => FakeXcodeProjectInterpreterWithBuildSettings(),
...@@ -1018,32 +1091,35 @@ void main() { ...@@ -1018,32 +1091,35 @@ void main() {
}; };
final BuildCommand command = BuildCommand( final BuildCommand command = BuildCommand(
artifacts: artifacts,
androidSdk: FakeAndroidSdk(), androidSdk: FakeAndroidSdk(),
buildSystem: TestBuildSystem.all(BuildResult(success: true)), buildSystem: TestBuildSystem.all(BuildResult(success: true)),
fileSystem: MemoryFileSystem.test(), logger: logger,
logger: BufferLogger.test(), fileSystem: fileSystem,
processUtils: processUtils,
osUtils: FakeOperatingSystemUtils(), osUtils: FakeOperatingSystemUtils(),
); );
await createTestCommandRunner(command).run( await createTestCommandRunner(command).run(
<String>['build', 'ipa', '--no-pub']); <String>['build', 'ipa', '--no-pub']);
expect( expect(
testLogger.statusText, logger.statusText,
contains( contains(
'[✓] App Settings Validation\n' '[✓] App Settings Validation\n'
' • Version Number: 12.34.56\n' ' • Version Number: 12.34.56\n'
' • Build Number: 666\n' ' • Build Number: 666\n'
' • Display Name: Awesome Gallery\n' ' • Display Name: Awesome Gallery\n'
' • Deployment Target: 11.0\n' ' • Deployment Target: 11.0\n'
' • Bundle Identifier: io.flutter.someProject\n' ' • Bundle Identifier: io.flutter.someProject\n'
) ),
); );
expect( expect(
testLogger.statusText, logger.statusText,
contains('To update the settings, please refer to https://docs.flutter.dev/deployment/ios') contains('To update the settings, please refer to https://docs.flutter.dev/deployment/ios'),
); );
}, overrides: <Type, Generator>{ }, overrides: <Type, Generator>{
FileSystem: () => fileSystem, FileSystem: () => fileSystem,
Logger: () => logger,
ProcessManager: () => fakeProcessManager, ProcessManager: () => fakeProcessManager,
Platform: () => macosPlatform, Platform: () => macosPlatform,
XcodeProjectInterpreter: () => FakeXcodeProjectInterpreterWithBuildSettings(), XcodeProjectInterpreter: () => FakeXcodeProjectInterpreterWithBuildSettings(),
...@@ -1069,21 +1145,25 @@ void main() { ...@@ -1069,21 +1145,25 @@ void main() {
}; };
final BuildCommand command = BuildCommand( final BuildCommand command = BuildCommand(
artifacts: artifacts,
androidSdk: FakeAndroidSdk(), androidSdk: FakeAndroidSdk(),
buildSystem: TestBuildSystem.all(BuildResult(success: true)), buildSystem: TestBuildSystem.all(BuildResult(success: true)),
fileSystem: MemoryFileSystem.test(), logger: logger,
logger: BufferLogger.test(), fileSystem: fileSystem,
processUtils: processUtils,
osUtils: FakeOperatingSystemUtils(), osUtils: FakeOperatingSystemUtils(),
); );
await createTestCommandRunner(command).run( await createTestCommandRunner(command).run(
<String>['build', 'ipa', '--no-pub']); <String>['build', 'ipa', '--no-pub'],
);
expect( expect(
testLogger.statusText, logger.statusText,
contains(' ! Your application still contains the default "com.example" bundle identifier.') contains(' ! Your application still contains the default "com.example" bundle identifier.'),
); );
}, overrides: <Type, Generator>{ }, overrides: <Type, Generator>{
FileSystem: () => fileSystem, FileSystem: () => fileSystem,
Logger: () => logger,
ProcessManager: () => fakeProcessManager, ProcessManager: () => fakeProcessManager,
Platform: () => macosPlatform, Platform: () => macosPlatform,
XcodeProjectInterpreter: () => FakeXcodeProjectInterpreterWithBuildSettings(), XcodeProjectInterpreter: () => FakeXcodeProjectInterpreterWithBuildSettings(),
...@@ -1108,21 +1188,24 @@ void main() { ...@@ -1108,21 +1188,24 @@ void main() {
}; };
final BuildCommand command = BuildCommand( final BuildCommand command = BuildCommand(
artifacts: artifacts,
androidSdk: FakeAndroidSdk(), androidSdk: FakeAndroidSdk(),
buildSystem: TestBuildSystem.all(BuildResult(success: true)), buildSystem: TestBuildSystem.all(BuildResult(success: true)),
fileSystem: MemoryFileSystem.test(), logger: logger,
logger: BufferLogger.test(), fileSystem: fileSystem,
processUtils: processUtils,
osUtils: FakeOperatingSystemUtils(), osUtils: FakeOperatingSystemUtils(),
); );
await createTestCommandRunner(command).run( await createTestCommandRunner(command).run(
<String>['build', 'ipa', '--no-pub']); <String>['build', 'ipa', '--no-pub']);
expect( expect(
testLogger.statusText, logger.statusText,
isNot(contains(' ! Your application still contains the default "com.example" bundle identifier.')) isNot(contains(' ! Your application still contains the default "com.example" bundle identifier.'))
); );
}, overrides: <Type, Generator>{ }, overrides: <Type, Generator>{
FileSystem: () => fileSystem, FileSystem: () => fileSystem,
Logger: () => logger,
ProcessManager: () => fakeProcessManager, ProcessManager: () => fakeProcessManager,
Platform: () => macosPlatform, Platform: () => macosPlatform,
XcodeProjectInterpreter: () => FakeXcodeProjectInterpreterWithBuildSettings(), XcodeProjectInterpreter: () => FakeXcodeProjectInterpreterWithBuildSettings(),
...@@ -1189,21 +1272,24 @@ void main() { ...@@ -1189,21 +1272,24 @@ void main() {
createMinimalMockProjectFiles(); createMinimalMockProjectFiles();
final BuildCommand command = BuildCommand( final BuildCommand command = BuildCommand(
artifacts: artifacts,
androidSdk: FakeAndroidSdk(), androidSdk: FakeAndroidSdk(),
buildSystem: TestBuildSystem.all(BuildResult(success: true)), buildSystem: TestBuildSystem.all(BuildResult(success: true)),
fileSystem: MemoryFileSystem.test(), logger: logger,
logger: BufferLogger.test(), fileSystem: fileSystem,
processUtils: processUtils,
osUtils: FakeOperatingSystemUtils(), osUtils: FakeOperatingSystemUtils(),
); );
await createTestCommandRunner(command).run( await createTestCommandRunner(command).run(
<String>['build', 'ipa', '--no-pub']); <String>['build', 'ipa', '--no-pub']);
expect( expect(
testLogger.statusText, logger.statusText,
contains(' ! App icon is set to the default placeholder icon. Replace with unique icons.'), contains(' ! App icon is set to the default placeholder icon. Replace with unique icons.'),
); );
}, overrides: <Type, Generator>{ }, overrides: <Type, Generator>{
FileSystem: () => fileSystem, FileSystem: () => fileSystem,
Logger: () => logger,
ProcessManager: () => fakeProcessManager, ProcessManager: () => fakeProcessManager,
Platform: () => macosPlatform, Platform: () => macosPlatform,
XcodeProjectInterpreter: () => FakeXcodeProjectInterpreterWithBuildSettings(), XcodeProjectInterpreter: () => FakeXcodeProjectInterpreterWithBuildSettings(),
...@@ -1268,21 +1354,24 @@ void main() { ...@@ -1268,21 +1354,24 @@ void main() {
createMinimalMockProjectFiles(); createMinimalMockProjectFiles();
final BuildCommand command = BuildCommand( final BuildCommand command = BuildCommand(
artifacts: artifacts,
androidSdk: FakeAndroidSdk(), androidSdk: FakeAndroidSdk(),
buildSystem: TestBuildSystem.all(BuildResult(success: true)), buildSystem: TestBuildSystem.all(BuildResult(success: true)),
fileSystem: MemoryFileSystem.test(), logger: logger,
logger: BufferLogger.test(), fileSystem: fileSystem,
processUtils: processUtils,
osUtils: FakeOperatingSystemUtils(), osUtils: FakeOperatingSystemUtils(),
); );
await createTestCommandRunner(command).run( await createTestCommandRunner(command).run(
<String>['build', 'ipa', '--no-pub']); <String>['build', 'ipa', '--no-pub']);
expect( expect(
testLogger.statusText, logger.statusText,
isNot(contains(' ! App icon is set to the default placeholder icon. Replace with unique icons.')) isNot(contains('! App icon is set to the default placeholder icon. Replace with unique icons.')),
); );
}, overrides: <Type, Generator>{ }, overrides: <Type, Generator>{
FileSystem: () => fileSystem, FileSystem: () => fileSystem,
Logger: () => logger,
ProcessManager: () => fakeProcessManager, ProcessManager: () => fakeProcessManager,
Platform: () => macosPlatform, Platform: () => macosPlatform,
XcodeProjectInterpreter: () => FakeXcodeProjectInterpreterWithBuildSettings(), XcodeProjectInterpreter: () => FakeXcodeProjectInterpreterWithBuildSettings(),
...@@ -1327,21 +1416,24 @@ void main() { ...@@ -1327,21 +1416,24 @@ void main() {
createMinimalMockProjectFiles(); createMinimalMockProjectFiles();
final BuildCommand command = BuildCommand( final BuildCommand command = BuildCommand(
artifacts: artifacts,
androidSdk: FakeAndroidSdk(), androidSdk: FakeAndroidSdk(),
buildSystem: TestBuildSystem.all(BuildResult(success: true)), buildSystem: TestBuildSystem.all(BuildResult(success: true)),
fileSystem: MemoryFileSystem.test(), logger: logger,
logger: BufferLogger.test(), fileSystem: fileSystem,
processUtils: processUtils,
osUtils: FakeOperatingSystemUtils(), osUtils: FakeOperatingSystemUtils(),
); );
await createTestCommandRunner(command).run( await createTestCommandRunner(command).run(
<String>['build', 'ipa', '--no-pub']); <String>['build', 'ipa', '--no-pub']);
expect( expect(
testLogger.statusText, logger.statusText,
contains(' ! App icon is using the incorrect size (e.g. Icon-App-20x20@2x.png).') contains(' ! App icon is using the incorrect size (e.g. Icon-App-20x20@2x.png).')
); );
}, overrides: <Type, Generator>{ }, overrides: <Type, Generator>{
FileSystem: () => fileSystem, FileSystem: () => fileSystem,
Logger: () => logger,
ProcessManager: () => fakeProcessManager, ProcessManager: () => fakeProcessManager,
Platform: () => macosPlatform, Platform: () => macosPlatform,
XcodeProjectInterpreter: () => FakeXcodeProjectInterpreterWithBuildSettings(), XcodeProjectInterpreter: () => FakeXcodeProjectInterpreterWithBuildSettings(),
...@@ -1386,21 +1478,25 @@ void main() { ...@@ -1386,21 +1478,25 @@ void main() {
createMinimalMockProjectFiles(); createMinimalMockProjectFiles();
final BuildCommand command = BuildCommand( final BuildCommand command = BuildCommand(
artifacts: artifacts,
androidSdk: FakeAndroidSdk(), androidSdk: FakeAndroidSdk(),
buildSystem: TestBuildSystem.all(BuildResult(success: true)), buildSystem: TestBuildSystem.all(BuildResult(success: true)),
fileSystem: MemoryFileSystem.test(), logger: logger,
logger: BufferLogger.test(), fileSystem: fileSystem,
processUtils: processUtils,
osUtils: FakeOperatingSystemUtils(), osUtils: FakeOperatingSystemUtils(),
); );
await createTestCommandRunner(command).run( await createTestCommandRunner(command).run(
<String>['build', 'ipa', '--no-pub']); <String>['build', 'ipa', '--no-pub'],
);
expect( expect(
testLogger.statusText, logger.statusText,
contains(' ! App icon is using the incorrect size (e.g. Icon-App-20x20@2x.png).') contains(' ! App icon is using the incorrect size (e.g. Icon-App-20x20@2x.png).'),
); );
}, overrides: <Type, Generator>{ }, overrides: <Type, Generator>{
FileSystem: () => fileSystem, FileSystem: () => fileSystem,
Logger: () => logger,
ProcessManager: () => fakeProcessManager, ProcessManager: () => fakeProcessManager,
Platform: () => macosPlatform, Platform: () => macosPlatform,
XcodeProjectInterpreter: () => FakeXcodeProjectInterpreterWithBuildSettings(), XcodeProjectInterpreter: () => FakeXcodeProjectInterpreterWithBuildSettings(),
...@@ -1445,21 +1541,24 @@ void main() { ...@@ -1445,21 +1541,24 @@ void main() {
createMinimalMockProjectFiles(); createMinimalMockProjectFiles();
final BuildCommand command = BuildCommand( final BuildCommand command = BuildCommand(
artifacts: artifacts,
androidSdk: FakeAndroidSdk(), androidSdk: FakeAndroidSdk(),
buildSystem: TestBuildSystem.all(BuildResult(success: true)), buildSystem: TestBuildSystem.all(BuildResult(success: true)),
fileSystem: MemoryFileSystem.test(), logger: logger,
logger: BufferLogger.test(), fileSystem: fileSystem,
processUtils: processUtils,
osUtils: FakeOperatingSystemUtils(), osUtils: FakeOperatingSystemUtils(),
); );
await createTestCommandRunner(command).run( await createTestCommandRunner(command).run(
<String>['build', 'ipa', '--no-pub']); <String>['build', 'ipa', '--no-pub']);
expect( expect(
testLogger.statusText, logger.statusText,
isNot(contains(' ! App icon is using the incorrect size (e.g. Icon-App-20x20@2x.png).')) isNot(contains(' ! App icon is using the incorrect size (e.g. Icon-App-20x20@2x.png).')),
); );
}, overrides: <Type, Generator>{ }, overrides: <Type, Generator>{
FileSystem: () => fileSystem, FileSystem: () => fileSystem,
Logger: () => logger,
ProcessManager: () => fakeProcessManager, ProcessManager: () => fakeProcessManager,
Platform: () => macosPlatform, Platform: () => macosPlatform,
XcodeProjectInterpreter: () => FakeXcodeProjectInterpreterWithBuildSettings(), XcodeProjectInterpreter: () => FakeXcodeProjectInterpreterWithBuildSettings(),
...@@ -1505,22 +1604,26 @@ void main() { ...@@ -1505,22 +1604,26 @@ void main() {
createMinimalMockProjectFiles(); createMinimalMockProjectFiles();
final BuildCommand command = BuildCommand( final BuildCommand command = BuildCommand(
artifacts: artifacts,
androidSdk: FakeAndroidSdk(), androidSdk: FakeAndroidSdk(),
buildSystem: TestBuildSystem.all(BuildResult(success: true)), buildSystem: TestBuildSystem.all(BuildResult(success: true)),
fileSystem: MemoryFileSystem.test(), logger: logger,
logger: BufferLogger.test(), fileSystem: fileSystem,
processUtils: processUtils,
osUtils: FakeOperatingSystemUtils(), osUtils: FakeOperatingSystemUtils(),
); );
await createTestCommandRunner(command).run( await createTestCommandRunner(command).run(
<String>['build', 'ipa', '--no-pub']); <String>['build', 'ipa', '--no-pub'],
);
// The validation should be skipped, even when the icon size is incorrect. // The validation should be skipped, even when the icon size is incorrect.
expect( expect(
testLogger.statusText, logger.statusText,
isNot(contains(' ! App icon is using the incorrect size (e.g. Icon-App-20x20@2x.png).')), isNot(contains(' ! App icon is using the incorrect size (e.g. Icon-App-20x20@2x.png).')),
); );
}, overrides: <Type, Generator>{ }, overrides: <Type, Generator>{
FileSystem: () => fileSystem, FileSystem: () => fileSystem,
Logger: () => logger,
ProcessManager: () => fakeProcessManager, ProcessManager: () => fakeProcessManager,
Platform: () => macosPlatform, Platform: () => macosPlatform,
XcodeProjectInterpreter: () => FakeXcodeProjectInterpreterWithBuildSettings(), XcodeProjectInterpreter: () => FakeXcodeProjectInterpreterWithBuildSettings(),
...@@ -1609,24 +1712,28 @@ void main() { ...@@ -1609,24 +1712,28 @@ void main() {
createMinimalMockProjectFiles(); createMinimalMockProjectFiles();
final BuildCommand command = BuildCommand( final BuildCommand command = BuildCommand(
artifacts: artifacts,
androidSdk: FakeAndroidSdk(), androidSdk: FakeAndroidSdk(),
buildSystem: TestBuildSystem.all(BuildResult(success: true)), buildSystem: TestBuildSystem.all(BuildResult(success: true)),
fileSystem: MemoryFileSystem.test(), logger: logger,
logger: BufferLogger.test(), fileSystem: fileSystem,
processUtils: processUtils,
osUtils: FakeOperatingSystemUtils(), osUtils: FakeOperatingSystemUtils(),
); );
await createTestCommandRunner(command).run( await createTestCommandRunner(command).run(
<String>['build', 'ipa', '--no-pub']); <String>['build', 'ipa', '--no-pub'],
);
// The validation should be skipped, even when the image size is incorrect. // The validation should be skipped, even when the image size is incorrect.
for (final String imageFileName in imageFileNames) { for (final String imageFileName in imageFileNames) {
expect( expect(
testLogger.statusText, logger.statusText,
isNot(contains(' ! App icon is using the incorrect size (e.g. $imageFileName).')) isNot(contains(' ! App icon is using the incorrect size (e.g. $imageFileName).')),
); );
} }
}, overrides: <Type, Generator>{ }, overrides: <Type, Generator>{
FileSystem: () => fileSystem, FileSystem: () => fileSystem,
Logger: () => logger,
ProcessManager: () => fakeProcessManager, ProcessManager: () => fakeProcessManager,
Platform: () => macosPlatform, Platform: () => macosPlatform,
XcodeProjectInterpreter: () => FakeXcodeProjectInterpreterWithBuildSettings(), XcodeProjectInterpreter: () => FakeXcodeProjectInterpreterWithBuildSettings(),
...@@ -1689,21 +1796,24 @@ void main() { ...@@ -1689,21 +1796,24 @@ void main() {
createMinimalMockProjectFiles(); createMinimalMockProjectFiles();
final BuildCommand command = BuildCommand( final BuildCommand command = BuildCommand(
artifacts: artifacts,
androidSdk: FakeAndroidSdk(), androidSdk: FakeAndroidSdk(),
buildSystem: TestBuildSystem.all(BuildResult(success: true)), buildSystem: TestBuildSystem.all(BuildResult(success: true)),
fileSystem: MemoryFileSystem.test(), logger: logger,
logger: BufferLogger.test(), fileSystem: fileSystem,
processUtils: processUtils,
osUtils: FakeOperatingSystemUtils(), osUtils: FakeOperatingSystemUtils(),
); );
await createTestCommandRunner(command).run( await createTestCommandRunner(command).run(
<String>['build', 'ipa', '--no-pub']); <String>['build', 'ipa', '--no-pub']);
expect( expect(
testLogger.statusText, logger.statusText,
contains(' ! Launch image is set to the default placeholder icon. Replace with unique launch image.'), contains(' ! Launch image is set to the default placeholder icon. Replace with unique launch image.'),
); );
}, overrides: <Type, Generator>{ }, overrides: <Type, Generator>{
FileSystem: () => fileSystem, FileSystem: () => fileSystem,
Logger: () => logger,
ProcessManager: () => fakeProcessManager, ProcessManager: () => fakeProcessManager,
Platform: () => macosPlatform, Platform: () => macosPlatform,
XcodeProjectInterpreter: () => FakeXcodeProjectInterpreterWithBuildSettings(), XcodeProjectInterpreter: () => FakeXcodeProjectInterpreterWithBuildSettings(),
...@@ -1767,21 +1877,24 @@ void main() { ...@@ -1767,21 +1877,24 @@ void main() {
createMinimalMockProjectFiles(); createMinimalMockProjectFiles();
final BuildCommand command = BuildCommand( final BuildCommand command = BuildCommand(
artifacts: artifacts,
androidSdk: FakeAndroidSdk(), androidSdk: FakeAndroidSdk(),
buildSystem: TestBuildSystem.all(BuildResult(success: true)), buildSystem: TestBuildSystem.all(BuildResult(success: true)),
fileSystem: MemoryFileSystem.test(), logger: logger,
logger: BufferLogger.test(), fileSystem: fileSystem,
processUtils: processUtils,
osUtils: FakeOperatingSystemUtils(), osUtils: FakeOperatingSystemUtils(),
); );
await createTestCommandRunner(command).run( await createTestCommandRunner(command).run(
<String>['build', 'ipa', '--no-pub']); <String>['build', 'ipa', '--no-pub']);
expect( expect(
testLogger.statusText, logger.statusText,
isNot(contains(' ! Launch image is set to the default placeholder icon. Replace with unique launch image.')), isNot(contains(' ! Launch image is set to the default placeholder icon. Replace with unique launch image.')),
); );
}, overrides: <Type, Generator>{ }, overrides: <Type, Generator>{
FileSystem: () => fileSystem, FileSystem: () => fileSystem,
Logger: () => logger,
ProcessManager: () => fakeProcessManager, ProcessManager: () => fakeProcessManager,
Platform: () => macosPlatform, Platform: () => macosPlatform,
XcodeProjectInterpreter: () => FakeXcodeProjectInterpreterWithBuildSettings(), XcodeProjectInterpreter: () => FakeXcodeProjectInterpreterWithBuildSettings(),
......
...@@ -5,10 +5,12 @@ ...@@ -5,10 +5,12 @@
import 'package:args/command_runner.dart'; import 'package:args/command_runner.dart';
import 'package:file/memory.dart'; import 'package:file/memory.dart';
import 'package:file_testing/file_testing.dart'; import 'package:file_testing/file_testing.dart';
import 'package:flutter_tools/src/artifacts.dart';
import 'package:flutter_tools/src/base/file_system.dart'; import 'package:flutter_tools/src/base/file_system.dart';
import 'package:flutter_tools/src/base/logger.dart'; import 'package:flutter_tools/src/base/logger.dart';
import 'package:flutter_tools/src/base/os.dart'; import 'package:flutter_tools/src/base/os.dart';
import 'package:flutter_tools/src/base/platform.dart'; import 'package:flutter_tools/src/base/platform.dart';
import 'package:flutter_tools/src/base/process.dart';
import 'package:flutter_tools/src/base/utils.dart'; import 'package:flutter_tools/src/base/utils.dart';
import 'package:flutter_tools/src/build_system/build_system.dart'; import 'package:flutter_tools/src/build_system/build_system.dart';
import 'package:flutter_tools/src/cache.dart'; import 'package:flutter_tools/src/cache.dart';
...@@ -47,13 +49,23 @@ void main() { ...@@ -47,13 +49,23 @@ void main() {
}); });
late FileSystem fileSystem; late FileSystem fileSystem;
late ProcessManager processManager; late FakeProcessManager processManager;
late ProcessUtils processUtils;
late Logger logger;
late TestUsage usage; late TestUsage usage;
late Artifacts artifacts;
setUp(() { setUp(() {
fileSystem = MemoryFileSystem.test(); fileSystem = MemoryFileSystem.test();
artifacts = Artifacts.test(fileSystem: fileSystem);
Cache.flutterRoot = _kTestFlutterRoot; Cache.flutterRoot = _kTestFlutterRoot;
usage = TestUsage(); usage = TestUsage();
logger = BufferLogger.test();
processManager = FakeProcessManager.empty();
processUtils = ProcessUtils(
logger: logger,
processManager: processManager,
);
}); });
// Creates the mock files necessary to look like a Flutter project. // Creates the mock files necessary to look like a Flutter project.
...@@ -110,10 +122,12 @@ void main() { ...@@ -110,10 +122,12 @@ void main() {
testUsingContext('Linux build fails when there is no linux project', () async { testUsingContext('Linux build fails when there is no linux project', () async {
final BuildCommand command = BuildCommand( final BuildCommand command = BuildCommand(
artifacts: artifacts,
androidSdk: FakeAndroidSdk(), androidSdk: FakeAndroidSdk(),
buildSystem: TestBuildSystem.all(BuildResult(success: true)), buildSystem: TestBuildSystem.all(BuildResult(success: true)),
fileSystem: MemoryFileSystem.test(), fileSystem: fileSystem,
logger: BufferLogger.test(), logger: logger,
processUtils: processUtils,
osUtils: FakeOperatingSystemUtils(), osUtils: FakeOperatingSystemUtils(),
); );
setUpMockCoreProjectFiles(); setUpMockCoreProjectFiles();
...@@ -126,16 +140,18 @@ void main() { ...@@ -126,16 +140,18 @@ void main() {
}, overrides: <Type, Generator>{ }, overrides: <Type, Generator>{
Platform: () => linuxPlatform, Platform: () => linuxPlatform,
FileSystem: () => fileSystem, FileSystem: () => fileSystem,
ProcessManager: () => FakeProcessManager.any(), ProcessManager: () => processManager,
FeatureFlags: () => TestFeatureFlags(isLinuxEnabled: true), FeatureFlags: () => TestFeatureFlags(isLinuxEnabled: true),
}); });
testUsingContext('Linux build fails on non-linux platform', () async { testUsingContext('Linux build fails on non-linux platform', () async {
final BuildCommand command = BuildCommand( final BuildCommand command = BuildCommand(
artifacts: artifacts,
androidSdk: FakeAndroidSdk(), androidSdk: FakeAndroidSdk(),
buildSystem: TestBuildSystem.all(BuildResult(success: true)), buildSystem: TestBuildSystem.all(BuildResult(success: true)),
fileSystem: MemoryFileSystem.test(), fileSystem: fileSystem,
logger: BufferLogger.test(), logger: logger,
processUtils: processUtils,
osUtils: FakeOperatingSystemUtils(), osUtils: FakeOperatingSystemUtils(),
); );
setUpMockProjectFilesForBuild(); setUpMockProjectFilesForBuild();
...@@ -146,16 +162,18 @@ void main() { ...@@ -146,16 +162,18 @@ void main() {
}, overrides: <Type, Generator>{ }, overrides: <Type, Generator>{
Platform: () => notLinuxPlatform, Platform: () => notLinuxPlatform,
FileSystem: () => fileSystem, FileSystem: () => fileSystem,
ProcessManager: () => FakeProcessManager.any(), ProcessManager: () => processManager,
FeatureFlags: () => TestFeatureFlags(isLinuxEnabled: true), FeatureFlags: () => TestFeatureFlags(isLinuxEnabled: true),
}); });
testUsingContext('Linux build fails when feature is disabled', () async { testUsingContext('Linux build fails when feature is disabled', () async {
final BuildCommand command = BuildCommand( final BuildCommand command = BuildCommand(
artifacts: artifacts,
androidSdk: FakeAndroidSdk(), androidSdk: FakeAndroidSdk(),
buildSystem: TestBuildSystem.all(BuildResult(success: true)), buildSystem: TestBuildSystem.all(BuildResult(success: true)),
fileSystem: MemoryFileSystem.test(), fileSystem: fileSystem,
logger: BufferLogger.test(), logger: logger,
processUtils: processUtils,
osUtils: FakeOperatingSystemUtils(), osUtils: FakeOperatingSystemUtils(),
); );
setUpMockProjectFilesForBuild(); setUpMockProjectFilesForBuild();
...@@ -166,19 +184,21 @@ void main() { ...@@ -166,19 +184,21 @@ void main() {
}, overrides: <Type, Generator>{ }, overrides: <Type, Generator>{
Platform: () => linuxPlatform, Platform: () => linuxPlatform,
FileSystem: () => fileSystem, FileSystem: () => fileSystem,
ProcessManager: () => FakeProcessManager.any(), ProcessManager: () => processManager,
FeatureFlags: () => TestFeatureFlags(), FeatureFlags: () => TestFeatureFlags(),
}); });
testUsingContext('Linux build invokes CMake and ninja, and writes temporary files', () async { testUsingContext('Linux build invokes CMake and ninja, and writes temporary files', () async {
final BuildCommand command = BuildCommand( final BuildCommand command = BuildCommand(
artifacts: artifacts,
androidSdk: FakeAndroidSdk(), androidSdk: FakeAndroidSdk(),
buildSystem: TestBuildSystem.all(BuildResult(success: true)), buildSystem: TestBuildSystem.all(BuildResult(success: true)),
fileSystem: MemoryFileSystem.test(), fileSystem: fileSystem,
logger: BufferLogger.test(), logger: logger,
processUtils: processUtils,
osUtils: FakeOperatingSystemUtils(), osUtils: FakeOperatingSystemUtils(),
); );
processManager = FakeProcessManager.list(<FakeCommand>[ processManager.addCommands(<FakeCommand>[
cmakeCommand('release'), cmakeCommand('release'),
ninjaCommand('release'), ninjaCommand('release'),
]); ]);
...@@ -199,10 +219,12 @@ void main() { ...@@ -199,10 +219,12 @@ void main() {
testUsingContext('Handles missing cmake', () async { testUsingContext('Handles missing cmake', () async {
final BuildCommand command = BuildCommand( final BuildCommand command = BuildCommand(
artifacts: artifacts,
androidSdk: FakeAndroidSdk(), androidSdk: FakeAndroidSdk(),
buildSystem: TestBuildSystem.all(BuildResult(success: true)), buildSystem: TestBuildSystem.all(BuildResult(success: true)),
fileSystem: MemoryFileSystem.test(), fileSystem: fileSystem,
logger: BufferLogger.test(), logger: logger,
processUtils: processUtils,
osUtils: FakeOperatingSystemUtils(), osUtils: FakeOperatingSystemUtils(),
); );
setUpMockProjectFilesForBuild(); setUpMockProjectFilesForBuild();
...@@ -222,14 +244,16 @@ void main() { ...@@ -222,14 +244,16 @@ void main() {
testUsingContext('Handles argument error from missing ninja', () async { testUsingContext('Handles argument error from missing ninja', () async {
final BuildCommand command = BuildCommand( final BuildCommand command = BuildCommand(
artifacts: artifacts,
androidSdk: FakeAndroidSdk(), androidSdk: FakeAndroidSdk(),
buildSystem: TestBuildSystem.all(BuildResult(success: true)), buildSystem: TestBuildSystem.all(BuildResult(success: true)),
fileSystem: MemoryFileSystem.test(), fileSystem: fileSystem,
logger: BufferLogger.test(), logger: logger,
processUtils: processUtils,
osUtils: FakeOperatingSystemUtils(), osUtils: FakeOperatingSystemUtils(),
); );
setUpMockProjectFilesForBuild(); setUpMockProjectFilesForBuild();
processManager = FakeProcessManager.list(<FakeCommand>[ processManager.addCommands(<FakeCommand>[
cmakeCommand('release'), cmakeCommand('release'),
ninjaCommand('release', onRun: () { ninjaCommand('release', onRun: () {
throw ArgumentError(); throw ArgumentError();
...@@ -249,14 +273,16 @@ void main() { ...@@ -249,14 +273,16 @@ void main() {
testUsingContext('Linux build does not spew stdout to status logger', () async { testUsingContext('Linux build does not spew stdout to status logger', () async {
final BuildCommand command = BuildCommand( final BuildCommand command = BuildCommand(
artifacts: artifacts,
androidSdk: FakeAndroidSdk(), androidSdk: FakeAndroidSdk(),
buildSystem: TestBuildSystem.all(BuildResult(success: true)), buildSystem: TestBuildSystem.all(BuildResult(success: true)),
fileSystem: MemoryFileSystem.test(), fileSystem: fileSystem,
logger: BufferLogger.test(), logger: logger,
processUtils: processUtils,
osUtils: FakeOperatingSystemUtils(), osUtils: FakeOperatingSystemUtils(),
); );
setUpMockProjectFilesForBuild(); setUpMockProjectFilesForBuild();
processManager = FakeProcessManager.list(<FakeCommand>[ processManager.addCommands(<FakeCommand>[
cmakeCommand('debug'), cmakeCommand('debug'),
ninjaCommand('debug', ninjaCommand('debug',
stdout: 'STDOUT STUFF', stdout: 'STDOUT STUFF',
...@@ -280,10 +306,12 @@ void main() { ...@@ -280,10 +306,12 @@ void main() {
testUsingContext('Linux build extracts errors from stdout', () async { testUsingContext('Linux build extracts errors from stdout', () async {
final BuildCommand command = BuildCommand( final BuildCommand command = BuildCommand(
artifacts: artifacts,
androidSdk: FakeAndroidSdk(), androidSdk: FakeAndroidSdk(),
buildSystem: TestBuildSystem.all(BuildResult(success: true)), buildSystem: TestBuildSystem.all(BuildResult(success: true)),
fileSystem: MemoryFileSystem.test(), fileSystem: fileSystem,
logger: BufferLogger.test(), logger: logger,
processUtils: processUtils,
osUtils: FakeOperatingSystemUtils(), osUtils: FakeOperatingSystemUtils(),
); );
setUpMockProjectFilesForBuild(); setUpMockProjectFilesForBuild();
...@@ -309,7 +337,7 @@ ninja: build stopped: subcommand failed. ...@@ -309,7 +337,7 @@ ninja: build stopped: subcommand failed.
ERROR: No file or variants found for asset: images/a_dot_burr.jpeg ERROR: No file or variants found for asset: images/a_dot_burr.jpeg
'''; ''';
processManager = FakeProcessManager.list(<FakeCommand>[ processManager.addCommands(<FakeCommand>[
cmakeCommand('release'), cmakeCommand('release'),
ninjaCommand('release', ninjaCommand('release',
stdout: stdout, stdout: stdout,
...@@ -340,14 +368,16 @@ ERROR: No file or variants found for asset: images/a_dot_burr.jpeg ...@@ -340,14 +368,16 @@ ERROR: No file or variants found for asset: images/a_dot_burr.jpeg
testUsingContext('Linux verbose build sets VERBOSE_SCRIPT_LOGGING', () async { testUsingContext('Linux verbose build sets VERBOSE_SCRIPT_LOGGING', () async {
final BuildCommand command = BuildCommand( final BuildCommand command = BuildCommand(
artifacts: artifacts,
androidSdk: FakeAndroidSdk(), androidSdk: FakeAndroidSdk(),
buildSystem: TestBuildSystem.all(BuildResult(success: true)), buildSystem: TestBuildSystem.all(BuildResult(success: true)),
fileSystem: MemoryFileSystem.test(), fileSystem: fileSystem,
logger: BufferLogger.test(), logger: logger,
processUtils: processUtils,
osUtils: FakeOperatingSystemUtils(), osUtils: FakeOperatingSystemUtils(),
); );
setUpMockProjectFilesForBuild(); setUpMockProjectFilesForBuild();
processManager = FakeProcessManager.list(<FakeCommand>[ processManager.addCommands(<FakeCommand>[
cmakeCommand('debug'), cmakeCommand('debug'),
ninjaCommand('debug', ninjaCommand('debug',
environment: const <String, String>{ environment: const <String, String>{
...@@ -366,6 +396,7 @@ ERROR: No file or variants found for asset: images/a_dot_burr.jpeg ...@@ -366,6 +396,7 @@ ERROR: No file or variants found for asset: images/a_dot_burr.jpeg
expect(testLogger.errorText, isNot(contains('STDOUT STUFF'))); expect(testLogger.errorText, isNot(contains('STDOUT STUFF')));
}, overrides: <Type, Generator>{ }, overrides: <Type, Generator>{
FileSystem: () => fileSystem, FileSystem: () => fileSystem,
Logger: () => logger,
ProcessManager: () => processManager, ProcessManager: () => processManager,
Platform: () => linuxPlatform, Platform: () => linuxPlatform,
FeatureFlags: () => TestFeatureFlags(isLinuxEnabled: true), FeatureFlags: () => TestFeatureFlags(isLinuxEnabled: true),
...@@ -374,14 +405,16 @@ ERROR: No file or variants found for asset: images/a_dot_burr.jpeg ...@@ -374,14 +405,16 @@ ERROR: No file or variants found for asset: images/a_dot_burr.jpeg
testUsingContext('Linux on x64 build --debug passes debug mode to cmake and ninja', () async { testUsingContext('Linux on x64 build --debug passes debug mode to cmake and ninja', () async {
final BuildCommand command = BuildCommand( final BuildCommand command = BuildCommand(
artifacts: artifacts,
androidSdk: FakeAndroidSdk(), androidSdk: FakeAndroidSdk(),
buildSystem: TestBuildSystem.all(BuildResult(success: true)), buildSystem: TestBuildSystem.all(BuildResult(success: true)),
fileSystem: MemoryFileSystem.test(), fileSystem: fileSystem,
logger: BufferLogger.test(), logger: logger,
processUtils: processUtils,
osUtils: FakeOperatingSystemUtils(), osUtils: FakeOperatingSystemUtils(),
); );
setUpMockProjectFilesForBuild(); setUpMockProjectFilesForBuild();
processManager = FakeProcessManager.list(<FakeCommand>[ processManager.addCommands(<FakeCommand>[
cmakeCommand('debug'), cmakeCommand('debug'),
ninjaCommand('debug'), ninjaCommand('debug'),
]); ]);
...@@ -391,6 +424,7 @@ ERROR: No file or variants found for asset: images/a_dot_burr.jpeg ...@@ -391,6 +424,7 @@ ERROR: No file or variants found for asset: images/a_dot_burr.jpeg
); );
}, overrides: <Type, Generator>{ }, overrides: <Type, Generator>{
FileSystem: () => fileSystem, FileSystem: () => fileSystem,
Logger: () => logger,
ProcessManager: () => processManager, ProcessManager: () => processManager,
Platform: () => linuxPlatform, Platform: () => linuxPlatform,
FeatureFlags: () => TestFeatureFlags(isLinuxEnabled: true), FeatureFlags: () => TestFeatureFlags(isLinuxEnabled: true),
...@@ -399,14 +433,16 @@ ERROR: No file or variants found for asset: images/a_dot_burr.jpeg ...@@ -399,14 +433,16 @@ ERROR: No file or variants found for asset: images/a_dot_burr.jpeg
testUsingContext('Linux on ARM64 build --debug passes debug mode to cmake and ninja', () async { testUsingContext('Linux on ARM64 build --debug passes debug mode to cmake and ninja', () async {
final BuildCommand command = BuildCommand( final BuildCommand command = BuildCommand(
artifacts: artifacts,
androidSdk: FakeAndroidSdk(), androidSdk: FakeAndroidSdk(),
buildSystem: TestBuildSystem.all(BuildResult(success: true)), buildSystem: TestBuildSystem.all(BuildResult(success: true)),
fileSystem: MemoryFileSystem.test(), fileSystem: fileSystem,
logger: BufferLogger.test(), logger: logger,
processUtils: processUtils,
osUtils: CustomFakeOperatingSystemUtils(hostPlatform: HostPlatform.linux_arm64), osUtils: CustomFakeOperatingSystemUtils(hostPlatform: HostPlatform.linux_arm64),
); );
setUpMockProjectFilesForBuild(); setUpMockProjectFilesForBuild();
processManager = FakeProcessManager.list(<FakeCommand>[ processManager.addCommands(<FakeCommand>[
cmakeCommand('debug', target: 'arm64'), cmakeCommand('debug', target: 'arm64'),
ninjaCommand('debug', target: 'arm64'), ninjaCommand('debug', target: 'arm64'),
]); ]);
...@@ -423,14 +459,16 @@ ERROR: No file or variants found for asset: images/a_dot_burr.jpeg ...@@ -423,14 +459,16 @@ ERROR: No file or variants found for asset: images/a_dot_burr.jpeg
testUsingContext('Linux on x64 build --profile passes profile mode to make', () async { testUsingContext('Linux on x64 build --profile passes profile mode to make', () async {
final BuildCommand command = BuildCommand( final BuildCommand command = BuildCommand(
artifacts: artifacts,
androidSdk: FakeAndroidSdk(), androidSdk: FakeAndroidSdk(),
buildSystem: TestBuildSystem.all(BuildResult(success: true)), buildSystem: TestBuildSystem.all(BuildResult(success: true)),
fileSystem: MemoryFileSystem.test(), fileSystem: fileSystem,
logger: BufferLogger.test(), logger: logger,
processUtils: processUtils,
osUtils: FakeOperatingSystemUtils(), osUtils: FakeOperatingSystemUtils(),
); );
setUpMockProjectFilesForBuild(); setUpMockProjectFilesForBuild();
processManager = FakeProcessManager.list(<FakeCommand>[ processManager.addCommands(<FakeCommand>[
cmakeCommand('profile'), cmakeCommand('profile'),
ninjaCommand('profile'), ninjaCommand('profile'),
]); ]);
...@@ -448,14 +486,16 @@ ERROR: No file or variants found for asset: images/a_dot_burr.jpeg ...@@ -448,14 +486,16 @@ ERROR: No file or variants found for asset: images/a_dot_burr.jpeg
testUsingContext('Linux on ARM64 build --profile passes profile mode to make', () async { testUsingContext('Linux on ARM64 build --profile passes profile mode to make', () async {
final BuildCommand command = BuildCommand( final BuildCommand command = BuildCommand(
artifacts: artifacts,
androidSdk: FakeAndroidSdk(), androidSdk: FakeAndroidSdk(),
buildSystem: TestBuildSystem.all(BuildResult(success: true)), buildSystem: TestBuildSystem.all(BuildResult(success: true)),
fileSystem: MemoryFileSystem.test(), fileSystem: fileSystem,
logger: BufferLogger.test(), logger: logger,
processUtils: processUtils,
osUtils: CustomFakeOperatingSystemUtils(hostPlatform: HostPlatform.linux_arm64), osUtils: CustomFakeOperatingSystemUtils(hostPlatform: HostPlatform.linux_arm64),
); );
setUpMockProjectFilesForBuild(); setUpMockProjectFilesForBuild();
processManager = FakeProcessManager.list(<FakeCommand>[ processManager.addCommands(<FakeCommand>[
cmakeCommand('profile', target: 'arm64'), cmakeCommand('profile', target: 'arm64'),
ninjaCommand('profile', target: 'arm64'), ninjaCommand('profile', target: 'arm64'),
]); ]);
...@@ -472,10 +512,12 @@ ERROR: No file or variants found for asset: images/a_dot_burr.jpeg ...@@ -472,10 +512,12 @@ ERROR: No file or variants found for asset: images/a_dot_burr.jpeg
testUsingContext('Not support Linux cross-build for x64 on arm64', () async { testUsingContext('Not support Linux cross-build for x64 on arm64', () async {
final BuildCommand command = BuildCommand( final BuildCommand command = BuildCommand(
artifacts: artifacts,
androidSdk: FakeAndroidSdk(), androidSdk: FakeAndroidSdk(),
buildSystem: TestBuildSystem.all(BuildResult(success: true)), buildSystem: TestBuildSystem.all(BuildResult(success: true)),
fileSystem: MemoryFileSystem.test(), fileSystem: fileSystem,
logger: BufferLogger.test(), logger: logger,
processUtils: processUtils,
osUtils: CustomFakeOperatingSystemUtils(hostPlatform: HostPlatform.linux_arm64), osUtils: CustomFakeOperatingSystemUtils(hostPlatform: HostPlatform.linux_arm64),
); );
...@@ -489,14 +531,16 @@ ERROR: No file or variants found for asset: images/a_dot_burr.jpeg ...@@ -489,14 +531,16 @@ ERROR: No file or variants found for asset: images/a_dot_burr.jpeg
testUsingContext('Linux build configures CMake exports', () async { testUsingContext('Linux build configures CMake exports', () async {
final BuildCommand command = BuildCommand( final BuildCommand command = BuildCommand(
artifacts: artifacts,
androidSdk: FakeAndroidSdk(), androidSdk: FakeAndroidSdk(),
buildSystem: TestBuildSystem.all(BuildResult(success: true)), buildSystem: TestBuildSystem.all(BuildResult(success: true)),
fileSystem: MemoryFileSystem.test(), fileSystem: fileSystem,
logger: BufferLogger.test(), logger: logger,
processUtils: processUtils,
osUtils: FakeOperatingSystemUtils(), osUtils: FakeOperatingSystemUtils(),
); );
setUpMockProjectFilesForBuild(); setUpMockProjectFilesForBuild();
processManager = FakeProcessManager.list(<FakeCommand>[ processManager.addCommands(<FakeCommand>[
cmakeCommand('release'), cmakeCommand('release'),
ninjaCommand('release'), ninjaCommand('release'),
]); ]);
...@@ -576,21 +620,25 @@ set(BINARY_NAME "fizz_bar") ...@@ -576,21 +620,25 @@ set(BINARY_NAME "fizz_bar")
expect(getCmakeExecutableName(flutterProject.linux), 'fizz_bar'); expect(getCmakeExecutableName(flutterProject.linux), 'fizz_bar');
}, overrides: <Type, Generator>{ }, overrides: <Type, Generator>{
FileSystem: () => fileSystem, FileSystem: () => fileSystem,
ProcessManager: () => FakeProcessManager.any(), ProcessManager: () => processManager,
FeatureFlags: () => TestFeatureFlags(isLinuxEnabled: true), FeatureFlags: () => TestFeatureFlags(isLinuxEnabled: true),
}); });
testUsingContext('Refuses to build for Linux when feature is disabled', () { testUsingContext('Refuses to build for Linux when feature is disabled', () {
final CommandRunner<void> runner = createTestCommandRunner(BuildCommand( final CommandRunner<void> runner = createTestCommandRunner(BuildCommand(
artifacts: artifacts,
androidSdk: FakeAndroidSdk(), androidSdk: FakeAndroidSdk(),
buildSystem: TestBuildSystem.all(BuildResult(success: true)), buildSystem: TestBuildSystem.all(BuildResult(success: true)),
fileSystem: MemoryFileSystem.test(), fileSystem: fileSystem,
logger: BufferLogger.test(), logger: logger,
processUtils: processUtils,
osUtils: FakeOperatingSystemUtils(), osUtils: FakeOperatingSystemUtils(),
)); ));
expect(() => runner.run(<String>['build', 'linux', '--no-pub']), expect(
throwsToolExit()); () => runner.run(<String>['build', 'linux', '--no-pub']),
throwsToolExit(),
);
}, overrides: <Type, Generator>{ }, overrides: <Type, Generator>{
FeatureFlags: () => TestFeatureFlags(), FeatureFlags: () => TestFeatureFlags(),
}); });
...@@ -611,14 +659,16 @@ set(BINARY_NAME "fizz_bar") ...@@ -611,14 +659,16 @@ set(BINARY_NAME "fizz_bar")
testUsingContext('Performs code size analysis and sends analytics', () async { testUsingContext('Performs code size analysis and sends analytics', () async {
final BuildCommand command = BuildCommand( final BuildCommand command = BuildCommand(
artifacts: artifacts,
androidSdk: FakeAndroidSdk(), androidSdk: FakeAndroidSdk(),
buildSystem: TestBuildSystem.all(BuildResult(success: true)), buildSystem: TestBuildSystem.all(BuildResult(success: true)),
fileSystem: MemoryFileSystem.test(), fileSystem: fileSystem,
logger: BufferLogger.test(), logger: logger,
processUtils: processUtils,
osUtils: FakeOperatingSystemUtils(), osUtils: FakeOperatingSystemUtils(),
); );
setUpMockProjectFilesForBuild(); setUpMockProjectFilesForBuild();
processManager = FakeProcessManager.list(<FakeCommand>[ processManager.addCommands(<FakeCommand>[
cmakeCommand('release'), cmakeCommand('release'),
ninjaCommand('release', onRun: () { ninjaCommand('release', onRun: () {
fileSystem.file('build/flutter_size_01/snapshot.linux-x64.json') fileSystem.file('build/flutter_size_01/snapshot.linux-x64.json')
...@@ -662,14 +712,16 @@ set(BINARY_NAME "fizz_bar") ...@@ -662,14 +712,16 @@ set(BINARY_NAME "fizz_bar")
testUsingContext('Linux on ARM64 build --release passes, and check if the LinuxBuildDirectory for arm64 can be referenced correctly by using analytics', () async { testUsingContext('Linux on ARM64 build --release passes, and check if the LinuxBuildDirectory for arm64 can be referenced correctly by using analytics', () async {
final BuildCommand command = BuildCommand( final BuildCommand command = BuildCommand(
artifacts: artifacts,
androidSdk: FakeAndroidSdk(), androidSdk: FakeAndroidSdk(),
buildSystem: TestBuildSystem.all(BuildResult(success: true)), buildSystem: TestBuildSystem.all(BuildResult(success: true)),
fileSystem: MemoryFileSystem.test(), fileSystem: fileSystem,
logger: BufferLogger.test(), logger: logger,
processUtils: processUtils,
osUtils: CustomFakeOperatingSystemUtils(hostPlatform: HostPlatform.linux_arm64), osUtils: CustomFakeOperatingSystemUtils(hostPlatform: HostPlatform.linux_arm64),
); );
setUpMockProjectFilesForBuild(); setUpMockProjectFilesForBuild();
processManager = FakeProcessManager.list(<FakeCommand>[ processManager.addCommands(<FakeCommand>[
cmakeCommand('release', target: 'arm64'), cmakeCommand('release', target: 'arm64'),
ninjaCommand('release', target: 'arm64', onRun: () { ninjaCommand('release', target: 'arm64', onRun: () {
fileSystem.file('build/flutter_size_01/snapshot.linux-arm64.json') fileSystem.file('build/flutter_size_01/snapshot.linux-arm64.json')
......
...@@ -10,6 +10,7 @@ import 'package:flutter_tools/src/artifacts.dart'; ...@@ -10,6 +10,7 @@ import 'package:flutter_tools/src/artifacts.dart';
import 'package:flutter_tools/src/base/file_system.dart'; import 'package:flutter_tools/src/base/file_system.dart';
import 'package:flutter_tools/src/base/logger.dart'; import 'package:flutter_tools/src/base/logger.dart';
import 'package:flutter_tools/src/base/platform.dart'; import 'package:flutter_tools/src/base/platform.dart';
import 'package:flutter_tools/src/base/process.dart';
import 'package:flutter_tools/src/build_info.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/build_system.dart';
import 'package:flutter_tools/src/cache.dart'; import 'package:flutter_tools/src/cache.dart';
...@@ -65,7 +66,10 @@ void main() { ...@@ -65,7 +66,10 @@ void main() {
late FileSystem fileSystem; late FileSystem fileSystem;
late TestUsage usage; late TestUsage usage;
late FakeProcessManager fakeProcessManager; late FakeProcessManager fakeProcessManager;
late ProcessUtils processUtils;
late BufferLogger logger;
late XcodeProjectInterpreter xcodeProjectInterpreter; late XcodeProjectInterpreter xcodeProjectInterpreter;
late Artifacts artifacts;
setUpAll(() { setUpAll(() {
Cache.disableLocking(); Cache.disableLocking();
...@@ -73,8 +77,14 @@ void main() { ...@@ -73,8 +77,14 @@ void main() {
setUp(() { setUp(() {
fileSystem = MemoryFileSystem.test(); fileSystem = MemoryFileSystem.test();
artifacts = Artifacts.test(fileSystem: fileSystem);
logger = BufferLogger.test();
usage = TestUsage(); usage = TestUsage();
fakeProcessManager = FakeProcessManager.empty(); fakeProcessManager = FakeProcessManager.empty();
processUtils = ProcessUtils(
logger: logger,
processManager: fakeProcessManager,
);
xcodeProjectInterpreter = FakeXcodeProjectInterpreter(); xcodeProjectInterpreter = FakeXcodeProjectInterpreter();
}); });
...@@ -139,10 +149,12 @@ STDERR STUFF ...@@ -139,10 +149,12 @@ STDERR STUFF
testUsingContext('macOS build fails when there is no macos project', () async { testUsingContext('macOS build fails when there is no macos project', () async {
final BuildCommand command = BuildCommand( final BuildCommand command = BuildCommand(
artifacts: artifacts,
androidSdk: FakeAndroidSdk(), androidSdk: FakeAndroidSdk(),
buildSystem: TestBuildSystem.all(BuildResult(success: true)), buildSystem: TestBuildSystem.all(BuildResult(success: true)),
fileSystem: MemoryFileSystem.test(), fileSystem: fileSystem,
logger: BufferLogger.test(), logger: logger,
processUtils: processUtils,
osUtils: FakeOperatingSystemUtils(), osUtils: FakeOperatingSystemUtils(),
); );
createCoreMockProjectFiles(); createCoreMockProjectFiles();
...@@ -161,10 +173,12 @@ STDERR STUFF ...@@ -161,10 +173,12 @@ STDERR STUFF
testUsingContext('macOS build successfully with renamed .xcodeproj/.xcworkspace files', () async { testUsingContext('macOS build successfully with renamed .xcodeproj/.xcworkspace files', () async {
final BuildCommand command = BuildCommand( final BuildCommand command = BuildCommand(
artifacts: artifacts,
androidSdk: FakeAndroidSdk(), androidSdk: FakeAndroidSdk(),
buildSystem: TestBuildSystem.all(BuildResult(success: true)), buildSystem: TestBuildSystem.all(BuildResult(success: true)),
fileSystem: MemoryFileSystem.test(), fileSystem: fileSystem,
logger: BufferLogger.test(), logger: logger,
processUtils: processUtils,
osUtils: FakeOperatingSystemUtils(), osUtils: FakeOperatingSystemUtils(),
); );
...@@ -184,10 +198,12 @@ STDERR STUFF ...@@ -184,10 +198,12 @@ STDERR STUFF
testUsingContext('macOS build fails on non-macOS platform', () async { testUsingContext('macOS build fails on non-macOS platform', () async {
final BuildCommand command = BuildCommand( final BuildCommand command = BuildCommand(
artifacts: artifacts,
androidSdk: FakeAndroidSdk(), androidSdk: FakeAndroidSdk(),
buildSystem: TestBuildSystem.all(BuildResult(success: true)), buildSystem: TestBuildSystem.all(BuildResult(success: true)),
fileSystem: MemoryFileSystem.test(), fileSystem: fileSystem,
logger: BufferLogger.test(), logger: logger,
processUtils: processUtils,
osUtils: FakeOperatingSystemUtils(), osUtils: FakeOperatingSystemUtils(),
); );
fileSystem.file('pubspec.yaml').createSync(); fileSystem.file('pubspec.yaml').createSync();
...@@ -206,10 +222,12 @@ STDERR STUFF ...@@ -206,10 +222,12 @@ STDERR STUFF
testUsingContext('macOS build fails when feature is disabled', () async { testUsingContext('macOS build fails when feature is disabled', () async {
final BuildCommand command = BuildCommand( final BuildCommand command = BuildCommand(
artifacts: artifacts,
androidSdk: FakeAndroidSdk(), androidSdk: FakeAndroidSdk(),
buildSystem: TestBuildSystem.all(BuildResult(success: true)), buildSystem: TestBuildSystem.all(BuildResult(success: true)),
fileSystem: MemoryFileSystem.test(), fileSystem: fileSystem,
logger: BufferLogger.test(), logger: logger,
processUtils: processUtils,
osUtils: FakeOperatingSystemUtils(), osUtils: FakeOperatingSystemUtils(),
); );
fileSystem.file('pubspec.yaml').createSync(); fileSystem.file('pubspec.yaml').createSync();
...@@ -228,10 +246,12 @@ STDERR STUFF ...@@ -228,10 +246,12 @@ STDERR STUFF
testUsingContext('macOS build forwards error stdout to status logger error', () async { testUsingContext('macOS build forwards error stdout to status logger error', () async {
final BuildCommand command = BuildCommand( final BuildCommand command = BuildCommand(
artifacts: artifacts,
androidSdk: FakeAndroidSdk(), androidSdk: FakeAndroidSdk(),
buildSystem: TestBuildSystem.all(BuildResult(success: true)), buildSystem: TestBuildSystem.all(BuildResult(success: true)),
fileSystem: MemoryFileSystem.test(), fileSystem: fileSystem,
logger: BufferLogger.test(), logger: logger,
processUtils: processUtils,
osUtils: FakeOperatingSystemUtils(), osUtils: FakeOperatingSystemUtils(),
); );
createMinimalMockProjectFiles(); createMinimalMockProjectFiles();
...@@ -258,10 +278,12 @@ STDERR STUFF ...@@ -258,10 +278,12 @@ STDERR STUFF
testUsingContext('macOS build invokes xcode build (debug)', () async { testUsingContext('macOS build invokes xcode build (debug)', () async {
final BuildCommand command = BuildCommand( final BuildCommand command = BuildCommand(
artifacts: artifacts,
androidSdk: FakeAndroidSdk(), androidSdk: FakeAndroidSdk(),
buildSystem: TestBuildSystem.all(BuildResult(success: true)), buildSystem: TestBuildSystem.all(BuildResult(success: true)),
fileSystem: MemoryFileSystem.test(), fileSystem: fileSystem,
logger: BufferLogger.test(), logger: logger,
processUtils: processUtils,
osUtils: FakeOperatingSystemUtils(), osUtils: FakeOperatingSystemUtils(),
); );
createMinimalMockProjectFiles(); createMinimalMockProjectFiles();
...@@ -280,10 +302,12 @@ STDERR STUFF ...@@ -280,10 +302,12 @@ STDERR STUFF
testUsingContext('macOS build invokes xcode build (debug) with verbosity', () async { testUsingContext('macOS build invokes xcode build (debug) with verbosity', () async {
final BuildCommand command = BuildCommand( final BuildCommand command = BuildCommand(
artifacts: artifacts,
androidSdk: FakeAndroidSdk(), androidSdk: FakeAndroidSdk(),
buildSystem: TestBuildSystem.all(BuildResult(success: true)), buildSystem: TestBuildSystem.all(BuildResult(success: true)),
fileSystem: MemoryFileSystem.test(), fileSystem: fileSystem,
logger: BufferLogger.test(), logger: logger,
processUtils: processUtils,
osUtils: FakeOperatingSystemUtils(), osUtils: FakeOperatingSystemUtils(),
); );
createMinimalMockProjectFiles(); createMinimalMockProjectFiles();
...@@ -303,10 +327,12 @@ STDERR STUFF ...@@ -303,10 +327,12 @@ STDERR STUFF
testUsingContext('macOS build invokes xcode build (profile)', () async { testUsingContext('macOS build invokes xcode build (profile)', () async {
final BuildCommand command = BuildCommand( final BuildCommand command = BuildCommand(
artifacts: artifacts,
androidSdk: FakeAndroidSdk(), androidSdk: FakeAndroidSdk(),
buildSystem: TestBuildSystem.all(BuildResult(success: true)), buildSystem: TestBuildSystem.all(BuildResult(success: true)),
fileSystem: MemoryFileSystem.test(), fileSystem: fileSystem,
logger: BufferLogger.test(), logger: logger,
processUtils: processUtils,
osUtils: FakeOperatingSystemUtils(), osUtils: FakeOperatingSystemUtils(),
); );
createMinimalMockProjectFiles(); createMinimalMockProjectFiles();
...@@ -326,10 +352,12 @@ STDERR STUFF ...@@ -326,10 +352,12 @@ STDERR STUFF
testUsingContext('macOS build invokes xcode build (release)', () async { testUsingContext('macOS build invokes xcode build (release)', () async {
final BuildCommand command = BuildCommand( final BuildCommand command = BuildCommand(
artifacts: artifacts,
androidSdk: FakeAndroidSdk(), androidSdk: FakeAndroidSdk(),
buildSystem: TestBuildSystem.all(BuildResult(success: true)), buildSystem: TestBuildSystem.all(BuildResult(success: true)),
fileSystem: MemoryFileSystem.test(), fileSystem: fileSystem,
logger: BufferLogger.test(), logger: logger,
processUtils: processUtils,
osUtils: FakeOperatingSystemUtils(), osUtils: FakeOperatingSystemUtils(),
); );
createMinimalMockProjectFiles(); createMinimalMockProjectFiles();
...@@ -348,10 +376,12 @@ STDERR STUFF ...@@ -348,10 +376,12 @@ STDERR STUFF
testUsingContext('macOS build supports standard desktop build options', () async { testUsingContext('macOS build supports standard desktop build options', () async {
final BuildCommand command = BuildCommand( final BuildCommand command = BuildCommand(
artifacts: artifacts,
androidSdk: FakeAndroidSdk(), androidSdk: FakeAndroidSdk(),
buildSystem: TestBuildSystem.all(BuildResult(success: true)), buildSystem: TestBuildSystem.all(BuildResult(success: true)),
fileSystem: MemoryFileSystem.test(), fileSystem: fileSystem,
logger: BufferLogger.test(), logger: logger,
processUtils: processUtils,
osUtils: FakeOperatingSystemUtils(), osUtils: FakeOperatingSystemUtils(),
); );
createMinimalMockProjectFiles(); createMinimalMockProjectFiles();
...@@ -439,10 +469,12 @@ STDERR STUFF ...@@ -439,10 +469,12 @@ STDERR STUFF
]); ]);
final BuildCommand command = BuildCommand( final BuildCommand command = BuildCommand(
artifacts: artifacts,
androidSdk: FakeAndroidSdk(), androidSdk: FakeAndroidSdk(),
buildSystem: TestBuildSystem.all(BuildResult(success: true)), buildSystem: TestBuildSystem.all(BuildResult(success: true)),
fileSystem: fileSystem, fileSystem: fileSystem,
logger: BufferLogger.test(), logger: logger,
processUtils: processUtils,
osUtils: FakeOperatingSystemUtils(), osUtils: FakeOperatingSystemUtils(),
); );
...@@ -461,10 +493,12 @@ STDERR STUFF ...@@ -461,10 +493,12 @@ STDERR STUFF
testUsingContext('macOS build supports build-name and build-number', () async { testUsingContext('macOS build supports build-name and build-number', () async {
final BuildCommand command = BuildCommand( final BuildCommand command = BuildCommand(
artifacts: artifacts,
androidSdk: FakeAndroidSdk(), androidSdk: FakeAndroidSdk(),
buildSystem: TestBuildSystem.all(BuildResult(success: true)), buildSystem: TestBuildSystem.all(BuildResult(success: true)),
fileSystem: MemoryFileSystem.test(), fileSystem: fileSystem,
logger: BufferLogger.test(), logger: logger,
processUtils: processUtils,
osUtils: FakeOperatingSystemUtils(), osUtils: FakeOperatingSystemUtils(),
); );
createMinimalMockProjectFiles(); createMinimalMockProjectFiles();
...@@ -496,10 +530,12 @@ STDERR STUFF ...@@ -496,10 +530,12 @@ STDERR STUFF
testUsingContext('Refuses to build for macOS when feature is disabled', () { testUsingContext('Refuses to build for macOS when feature is disabled', () {
final CommandRunner<void> runner = createTestCommandRunner(BuildCommand( final CommandRunner<void> runner = createTestCommandRunner(BuildCommand(
artifacts: artifacts,
androidSdk: FakeAndroidSdk(), androidSdk: FakeAndroidSdk(),
buildSystem: TestBuildSystem.all(BuildResult(success: true)), buildSystem: TestBuildSystem.all(BuildResult(success: true)),
fileSystem: MemoryFileSystem.test(), fileSystem: fileSystem,
logger: BufferLogger.test(), logger: logger,
processUtils: processUtils,
osUtils: FakeOperatingSystemUtils(), osUtils: FakeOperatingSystemUtils(),
)); ));
...@@ -526,10 +562,12 @@ STDERR STUFF ...@@ -526,10 +562,12 @@ STDERR STUFF
testUsingContext('Performs code size analysis and sends analytics', () async { testUsingContext('Performs code size analysis and sends analytics', () async {
final BuildCommand command = BuildCommand( final BuildCommand command = BuildCommand(
artifacts: artifacts,
androidSdk: FakeAndroidSdk(), androidSdk: FakeAndroidSdk(),
buildSystem: TestBuildSystem.all(BuildResult(success: true)), buildSystem: TestBuildSystem.all(BuildResult(success: true)),
fileSystem: MemoryFileSystem.test(), fileSystem: fileSystem,
logger: BufferLogger.test(), logger: logger,
processUtils: processUtils,
osUtils: FakeOperatingSystemUtils(), osUtils: FakeOperatingSystemUtils(),
); );
createMinimalMockProjectFiles(); createMinimalMockProjectFiles();
......
...@@ -4,8 +4,10 @@ ...@@ -4,8 +4,10 @@
import 'package:args/command_runner.dart'; import 'package:args/command_runner.dart';
import 'package:file/memory.dart'; 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/file_system.dart';
import 'package:flutter_tools/src/base/logger.dart'; import 'package:flutter_tools/src/base/logger.dart';
import 'package:flutter_tools/src/base/process.dart';
import 'package:flutter_tools/src/build_system/build_system.dart'; import 'package:flutter_tools/src/build_system/build_system.dart';
import 'package:flutter_tools/src/cache.dart'; import 'package:flutter_tools/src/cache.dart';
import 'package:flutter_tools/src/commands/build.dart'; import 'package:flutter_tools/src/commands/build.dart';
...@@ -28,23 +30,37 @@ void main() { ...@@ -28,23 +30,37 @@ void main() {
]), throwsToolExit(message: '"--${FlutterOptions.kDartObfuscationOption}" can only be used in ' ]), throwsToolExit(message: '"--${FlutterOptions.kDartObfuscationOption}" can only be used in '
'combination with "--${FlutterOptions.kSplitDebugInfoOption}"')); 'combination with "--${FlutterOptions.kSplitDebugInfoOption}"'));
}); });
group('Fatal Logs', () { group('Fatal Logs', () {
late FakeBuildCommand command; late FakeBuildCommand command;
late MemoryFileSystem fs; late MemoryFileSystem fs;
late BufferLogger logger;
late ProcessManager processManager;
late ProcessUtils processUtils;
late Artifacts artifacts;
setUp(() { setUp(() {
fs = MemoryFileSystem.test(); fs = MemoryFileSystem.test();
artifacts = Artifacts.test(fileSystem: fs);
fs.file('/package/pubspec.yaml').createSync(recursive: true); fs.file('/package/pubspec.yaml').createSync(recursive: true);
fs.currentDirectory = '/package'; fs.currentDirectory = '/package';
Cache.disableLocking(); Cache.disableLocking();
logger = BufferLogger.test();
processManager = FakeProcessManager.empty();
processUtils = ProcessUtils(
logger: logger,
processManager: processManager,
);
}); });
testUsingContext("doesn't fail if --fatal-warnings specified and no warnings occur", () async { testUsingContext("doesn't fail if --fatal-warnings specified and no warnings occur", () async {
command = FakeBuildCommand( command = FakeBuildCommand(
artifacts: artifacts,
androidSdk: FakeAndroidSdk(), androidSdk: FakeAndroidSdk(),
buildSystem: TestBuildSystem.all(BuildResult(success: true)), buildSystem: TestBuildSystem.all(BuildResult(success: true)),
fileSystem: MemoryFileSystem.test(), fileSystem: fs,
logger: BufferLogger.test(), logger: logger,
processUtils: processUtils,
osUtils: FakeOperatingSystemUtils(), osUtils: FakeOperatingSystemUtils(),
); );
try { try {
...@@ -58,15 +74,17 @@ void main() { ...@@ -58,15 +74,17 @@ void main() {
} }
}, overrides: <Type, Generator>{ }, overrides: <Type, Generator>{
FileSystem: () => fs, FileSystem: () => fs,
ProcessManager: () => FakeProcessManager.any(), ProcessManager: () => processManager,
}); });
testUsingContext("doesn't fail if --fatal-warnings not specified", () async { testUsingContext("doesn't fail if --fatal-warnings not specified", () async {
command = FakeBuildCommand( command = FakeBuildCommand(
artifacts: artifacts,
androidSdk: FakeAndroidSdk(), androidSdk: FakeAndroidSdk(),
buildSystem: TestBuildSystem.all(BuildResult(success: true)), buildSystem: TestBuildSystem.all(BuildResult(success: true)),
fileSystem: MemoryFileSystem.test(), fileSystem: fs,
logger: BufferLogger.test(), logger: logger,
processUtils: processUtils,
osUtils: FakeOperatingSystemUtils(), osUtils: FakeOperatingSystemUtils(),
); );
testLogger.printWarning('Warning: Mild annoyance Will Robinson!'); testLogger.printWarning('Warning: Mild annoyance Will Robinson!');
...@@ -80,15 +98,17 @@ void main() { ...@@ -80,15 +98,17 @@ void main() {
} }
}, overrides: <Type, Generator>{ }, overrides: <Type, Generator>{
FileSystem: () => fs, FileSystem: () => fs,
ProcessManager: () => FakeProcessManager.any(), ProcessManager: () => processManager,
}); });
testUsingContext('fails if --fatal-warnings specified and warnings emitted', () async { testUsingContext('fails if --fatal-warnings specified and warnings emitted', () async {
command = FakeBuildCommand( command = FakeBuildCommand(
artifacts: artifacts,
androidSdk: FakeAndroidSdk(), androidSdk: FakeAndroidSdk(),
buildSystem: TestBuildSystem.all(BuildResult(success: true)), buildSystem: TestBuildSystem.all(BuildResult(success: true)),
fileSystem: MemoryFileSystem.test(), fileSystem: fs,
logger: BufferLogger.test(), logger: logger,
processUtils: processUtils,
osUtils: FakeOperatingSystemUtils(), osUtils: FakeOperatingSystemUtils(),
); );
testLogger.printWarning('Warning: Mild annoyance Will Robinson!'); testLogger.printWarning('Warning: Mild annoyance Will Robinson!');
...@@ -99,15 +119,17 @@ void main() { ...@@ -99,15 +119,17 @@ void main() {
]), throwsToolExit(message: 'Logger received warning output during the run, and "--${FlutterOptions.kFatalWarnings}" is enabled.')); ]), throwsToolExit(message: 'Logger received warning output during the run, and "--${FlutterOptions.kFatalWarnings}" is enabled.'));
}, overrides: <Type, Generator>{ }, overrides: <Type, Generator>{
FileSystem: () => fs, FileSystem: () => fs,
ProcessManager: () => FakeProcessManager.any(), ProcessManager: () => processManager,
}); });
testUsingContext('fails if --fatal-warnings specified and errors emitted', () async { testUsingContext('fails if --fatal-warnings specified and errors emitted', () async {
command = FakeBuildCommand( command = FakeBuildCommand(
artifacts: artifacts,
androidSdk: FakeAndroidSdk(), androidSdk: FakeAndroidSdk(),
buildSystem: TestBuildSystem.all(BuildResult(success: true)), buildSystem: TestBuildSystem.all(BuildResult(success: true)),
fileSystem: MemoryFileSystem.test(), fileSystem: fs,
logger: BufferLogger.test(), logger: logger,
processUtils: processUtils,
osUtils: FakeOperatingSystemUtils(), osUtils: FakeOperatingSystemUtils(),
); );
testLogger.printError('Error: Danger Will Robinson!'); testLogger.printError('Error: Danger Will Robinson!');
...@@ -118,7 +140,7 @@ void main() { ...@@ -118,7 +140,7 @@ void main() {
]), throwsToolExit(message: 'Logger received error output during the run, and "--${FlutterOptions.kFatalWarnings}" is enabled.')); ]), throwsToolExit(message: 'Logger received error output during the run, and "--${FlutterOptions.kFatalWarnings}" is enabled.'));
}, overrides: <Type, Generator>{ }, overrides: <Type, Generator>{
FileSystem: () => fs, FileSystem: () => fs,
ProcessManager: () => FakeProcessManager.any(), ProcessManager: () => processManager,
}); });
}); });
} }
...@@ -149,8 +171,10 @@ class FakeBuildCommand extends BuildCommand { ...@@ -149,8 +171,10 @@ class FakeBuildCommand extends BuildCommand {
required super.osUtils, required super.osUtils,
required Logger logger, required Logger logger,
required super.androidSdk, required super.androidSdk,
required super.processUtils,
required super.artifacts,
bool verboseHelp = false, bool verboseHelp = false,
}) : super(logger: logger, verboseHelp: verboseHelp,) { }) : super(logger: logger) {
addSubcommand(FakeBuildSubcommand(logger: logger, verboseHelp: verboseHelp)); addSubcommand(FakeBuildSubcommand(logger: logger, verboseHelp: verboseHelp));
} }
......
...@@ -4,9 +4,11 @@ ...@@ -4,9 +4,11 @@
import 'package:args/command_runner.dart'; import 'package:args/command_runner.dart';
import 'package:file/memory.dart'; 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/file_system.dart';
import 'package:flutter_tools/src/base/logger.dart'; import 'package:flutter_tools/src/base/logger.dart';
import 'package:flutter_tools/src/base/platform.dart'; import 'package:flutter_tools/src/base/platform.dart';
import 'package:flutter_tools/src/base/process.dart';
import 'package:flutter_tools/src/build_info.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/build_system.dart';
import 'package:flutter_tools/src/cache.dart'; import 'package:flutter_tools/src/cache.dart';
...@@ -28,6 +30,10 @@ void main() { ...@@ -28,6 +30,10 @@ void main() {
'FLUTTER_ROOT': '/', 'FLUTTER_ROOT': '/',
}, },
); );
late ProcessUtils processUtils;
late BufferLogger logger;
late ProcessManager processManager;
late Artifacts artifacts;
setUpAll(() { setUpAll(() {
Cache.flutterRoot = ''; Cache.flutterRoot = '';
...@@ -42,15 +48,24 @@ void main() { ...@@ -42,15 +48,24 @@ void main() {
fileSystem.file('.packages').createSync(); fileSystem.file('.packages').createSync();
fileSystem.file(fileSystem.path.join('web', 'index.html')).createSync(recursive: true); fileSystem.file(fileSystem.path.join('web', 'index.html')).createSync(recursive: true);
fileSystem.file(fileSystem.path.join('lib', 'main.dart')).createSync(recursive: true); fileSystem.file(fileSystem.path.join('lib', 'main.dart')).createSync(recursive: true);
artifacts = Artifacts.test(fileSystem: fileSystem);
logger = BufferLogger.test();
processManager = FakeProcessManager.empty();
processUtils = ProcessUtils(
logger: logger,
processManager: processManager,
);
}); });
testUsingContext('Refuses to build for web when missing index.html', () async { testUsingContext('Refuses to build for web when missing index.html', () async {
fileSystem.file(fileSystem.path.join('web', 'index.html')).deleteSync(); fileSystem.file(fileSystem.path.join('web', 'index.html')).deleteSync();
final CommandRunner<void> runner = createTestCommandRunner(BuildCommand( final CommandRunner<void> runner = createTestCommandRunner(BuildCommand(
artifacts: artifacts,
androidSdk: FakeAndroidSdk(), androidSdk: FakeAndroidSdk(),
buildSystem: TestBuildSystem.all(BuildResult(success: true)), buildSystem: TestBuildSystem.all(BuildResult(success: true)),
fileSystem: MemoryFileSystem.test(), fileSystem: fileSystem,
logger: BufferLogger.test(), logger: logger,
processUtils: processUtils,
osUtils: FakeOperatingSystemUtils(), osUtils: FakeOperatingSystemUtils(),
)); ));
...@@ -62,15 +77,17 @@ void main() { ...@@ -62,15 +77,17 @@ void main() {
Platform: () => fakePlatform, Platform: () => fakePlatform,
FileSystem: () => fileSystem, FileSystem: () => fileSystem,
FeatureFlags: () => TestFeatureFlags(isWebEnabled: true), FeatureFlags: () => TestFeatureFlags(isWebEnabled: true),
ProcessManager: () => FakeProcessManager.any(), ProcessManager: () => processManager,
}); });
testUsingContext('Refuses to build a debug build for web', () async { testUsingContext('Refuses to build a debug build for web', () async {
final CommandRunner<void> runner = createTestCommandRunner(BuildCommand( final CommandRunner<void> runner = createTestCommandRunner(BuildCommand(
artifacts: artifacts,
androidSdk: FakeAndroidSdk(), androidSdk: FakeAndroidSdk(),
buildSystem: TestBuildSystem.all(BuildResult(success: true)), buildSystem: TestBuildSystem.all(BuildResult(success: true)),
fileSystem: fileSystem, fileSystem: fileSystem,
logger: BufferLogger.test(), logger: logger,
processUtils: processUtils,
osUtils: FakeOperatingSystemUtils(), osUtils: FakeOperatingSystemUtils(),
)); ));
...@@ -79,15 +96,17 @@ void main() { ...@@ -79,15 +96,17 @@ void main() {
}, overrides: <Type, Generator>{ }, overrides: <Type, Generator>{
Platform: () => fakePlatform, Platform: () => fakePlatform,
FeatureFlags: () => TestFeatureFlags(isWebEnabled: true), FeatureFlags: () => TestFeatureFlags(isWebEnabled: true),
ProcessManager: () => FakeProcessManager.any(), ProcessManager: () => processManager,
}); });
testUsingContext('Refuses to build for web when feature is disabled', () async { testUsingContext('Refuses to build for web when feature is disabled', () async {
final CommandRunner<void> runner = createTestCommandRunner(BuildCommand( final CommandRunner<void> runner = createTestCommandRunner(BuildCommand(
artifacts: artifacts,
androidSdk: FakeAndroidSdk(), androidSdk: FakeAndroidSdk(),
buildSystem: TestBuildSystem.all(BuildResult(success: true)), buildSystem: TestBuildSystem.all(BuildResult(success: true)),
fileSystem: MemoryFileSystem.test(), fileSystem: MemoryFileSystem.test(),
logger: BufferLogger.test(), logger: logger,
processUtils: processUtils,
osUtils: FakeOperatingSystemUtils(), osUtils: FakeOperatingSystemUtils(),
)); ));
...@@ -99,15 +118,17 @@ void main() { ...@@ -99,15 +118,17 @@ void main() {
Platform: () => fakePlatform, Platform: () => fakePlatform,
FileSystem: () => fileSystem, FileSystem: () => fileSystem,
FeatureFlags: () => TestFeatureFlags(), FeatureFlags: () => TestFeatureFlags(),
ProcessManager: () => FakeProcessManager.any(), ProcessManager: () => processManager,
}); });
testUsingContext('Setup for a web build with default output directory', () async { testUsingContext('Setup for a web build with default output directory', () async {
final BuildCommand buildCommand = BuildCommand( final BuildCommand buildCommand = BuildCommand(
artifacts: artifacts,
androidSdk: FakeAndroidSdk(), androidSdk: FakeAndroidSdk(),
buildSystem: TestBuildSystem.all(BuildResult(success: true)), buildSystem: TestBuildSystem.all(BuildResult(success: true)),
fileSystem: fileSystem, fileSystem: fileSystem,
logger: BufferLogger.test(), logger: logger,
processUtils: processUtils,
osUtils: FakeOperatingSystemUtils(), osUtils: FakeOperatingSystemUtils(),
); );
final CommandRunner<void> runner = createTestCommandRunner(buildCommand); final CommandRunner<void> runner = createTestCommandRunner(buildCommand);
...@@ -121,7 +142,7 @@ void main() { ...@@ -121,7 +142,7 @@ void main() {
Platform: () => fakePlatform, Platform: () => fakePlatform,
FileSystem: () => fileSystem, FileSystem: () => fileSystem,
FeatureFlags: () => TestFeatureFlags(isWebEnabled: true), FeatureFlags: () => TestFeatureFlags(isWebEnabled: true),
ProcessManager: () => FakeProcessManager.any(), ProcessManager: () => processManager,
BuildSystem: () => TestBuildSystem.all(BuildResult(success: true), (Target target, Environment environment) { BuildSystem: () => TestBuildSystem.all(BuildResult(success: true), (Target target, Environment environment) {
expect(environment.defines, <String, String>{ expect(environment.defines, <String, String>{
'TargetFile': 'lib/main.dart', 'TargetFile': 'lib/main.dart',
...@@ -144,11 +165,13 @@ void main() { ...@@ -144,11 +165,13 @@ void main() {
testUsingContext('Does not allow -O0 optimization level', () async { testUsingContext('Does not allow -O0 optimization level', () async {
final BuildCommand buildCommand = BuildCommand( final BuildCommand buildCommand = BuildCommand(
artifacts: artifacts,
androidSdk: FakeAndroidSdk(), androidSdk: FakeAndroidSdk(),
buildSystem: TestBuildSystem.all(BuildResult(success: true)), buildSystem: TestBuildSystem.all(BuildResult(success: true)),
fileSystem: fileSystem, fileSystem: fileSystem,
logger: BufferLogger.test(), logger: BufferLogger.test(),
osUtils: FakeOperatingSystemUtils(), osUtils: FakeOperatingSystemUtils(),
processUtils: processUtils,
); );
final CommandRunner<void> runner = createTestCommandRunner(buildCommand); final CommandRunner<void> runner = createTestCommandRunner(buildCommand);
setupFileSystemForEndToEndTest(fileSystem); setupFileSystemForEndToEndTest(fileSystem);
...@@ -191,10 +214,12 @@ void main() { ...@@ -191,10 +214,12 @@ void main() {
testUsingContext('Setup for a web build with a user specified output directory', testUsingContext('Setup for a web build with a user specified output directory',
() async { () async {
final BuildCommand buildCommand = BuildCommand( final BuildCommand buildCommand = BuildCommand(
artifacts: artifacts,
androidSdk: FakeAndroidSdk(), androidSdk: FakeAndroidSdk(),
buildSystem: TestBuildSystem.all(BuildResult(success: true)), buildSystem: TestBuildSystem.all(BuildResult(success: true)),
fileSystem: fileSystem, fileSystem: fileSystem,
logger: BufferLogger.test(), logger: logger,
processUtils: processUtils,
osUtils: FakeOperatingSystemUtils(), osUtils: FakeOperatingSystemUtils(),
); );
final CommandRunner<void> runner = createTestCommandRunner(buildCommand); final CommandRunner<void> runner = createTestCommandRunner(buildCommand);
...@@ -219,7 +244,7 @@ void main() { ...@@ -219,7 +244,7 @@ void main() {
Platform: () => fakePlatform, Platform: () => fakePlatform,
FileSystem: () => fileSystem, FileSystem: () => fileSystem,
FeatureFlags: () => TestFeatureFlags(isWebEnabled: true), FeatureFlags: () => TestFeatureFlags(isWebEnabled: true),
ProcessManager: () => FakeProcessManager.any(), ProcessManager: () => processManager,
BuildSystem: () => TestBuildSystem.all(BuildResult(success: true), (Target target, Environment environment) { BuildSystem: () => TestBuildSystem.all(BuildResult(success: true), (Target target, Environment environment) {
expect(environment.defines, <String, String>{ expect(environment.defines, <String, String>{
'TargetFile': 'lib/main.dart', 'TargetFile': 'lib/main.dart',
...@@ -246,7 +271,7 @@ void main() { ...@@ -246,7 +271,7 @@ void main() {
Platform: () => fakePlatform, Platform: () => fakePlatform,
FileSystem: () => fileSystem, FileSystem: () => fileSystem,
FeatureFlags: () => TestFeatureFlags(), FeatureFlags: () => TestFeatureFlags(),
ProcessManager: () => FakeProcessManager.any(), ProcessManager: () => processManager,
}); });
testUsingContext('not hidden if feature flag is enabled', () async { testUsingContext('not hidden if feature flag is enabled', () async {
...@@ -255,7 +280,7 @@ void main() { ...@@ -255,7 +280,7 @@ void main() {
Platform: () => fakePlatform, Platform: () => fakePlatform,
FileSystem: () => fileSystem, FileSystem: () => fileSystem,
FeatureFlags: () => TestFeatureFlags(isWebEnabled: true), FeatureFlags: () => TestFeatureFlags(isWebEnabled: true),
ProcessManager: () => FakeProcessManager.any(), ProcessManager: () => processManager,
}); });
testUsingContext('Defaults to web renderer auto mode when no option is specified', () async { testUsingContext('Defaults to web renderer auto mode when no option is specified', () async {
...@@ -270,7 +295,7 @@ void main() { ...@@ -270,7 +295,7 @@ void main() {
Platform: () => fakePlatform, Platform: () => fakePlatform,
FileSystem: () => fileSystem, FileSystem: () => fileSystem,
FeatureFlags: () => TestFeatureFlags(isWebEnabled: true), FeatureFlags: () => TestFeatureFlags(isWebEnabled: true),
ProcessManager: () => FakeProcessManager.any(), ProcessManager: () => processManager,
BuildSystem: () => TestBuildSystem.all(BuildResult(success: true)), BuildSystem: () => TestBuildSystem.all(BuildResult(success: true)),
}); });
...@@ -295,7 +320,7 @@ void main() { ...@@ -295,7 +320,7 @@ void main() {
Platform: () => fakePlatform, Platform: () => fakePlatform,
FileSystem: () => fileSystem, FileSystem: () => fileSystem,
FeatureFlags: () => TestFeatureFlags(isWebEnabled: true), FeatureFlags: () => TestFeatureFlags(isWebEnabled: true),
ProcessManager: () => FakeProcessManager.any(), ProcessManager: () => processManager,
BuildSystem: () => TestBuildSystem.all(BuildResult(success: true)), BuildSystem: () => TestBuildSystem.all(BuildResult(success: true)),
}); });
...@@ -311,7 +336,7 @@ void main() { ...@@ -311,7 +336,7 @@ void main() {
Platform: () => fakePlatform, Platform: () => fakePlatform,
FileSystem: () => fileSystem, FileSystem: () => fileSystem,
FeatureFlags: () => TestFeatureFlags(isWebEnabled: true), FeatureFlags: () => TestFeatureFlags(isWebEnabled: true),
ProcessManager: () => FakeProcessManager.any(), ProcessManager: () => processManager,
BuildSystem: () => TestBuildSystem.all(BuildResult(success: true)), BuildSystem: () => TestBuildSystem.all(BuildResult(success: true)),
}); });
...@@ -327,7 +352,7 @@ void main() { ...@@ -327,7 +352,7 @@ void main() {
Platform: () => fakePlatform, Platform: () => fakePlatform,
FileSystem: () => fileSystem, FileSystem: () => fileSystem,
FeatureFlags: () => TestFeatureFlags(isWebEnabled: true), FeatureFlags: () => TestFeatureFlags(isWebEnabled: true),
ProcessManager: () => FakeProcessManager.any(), ProcessManager: () => processManager,
BuildSystem: () => TestBuildSystem.all(BuildResult(success: true)), BuildSystem: () => TestBuildSystem.all(BuildResult(success: true)),
}); });
} }
......
...@@ -82,7 +82,7 @@ void main() { ...@@ -82,7 +82,7 @@ void main() {
'-S', '-S',
fileSystem.path.absolute(fileSystem.path.dirname(buildFilePath)), fileSystem.path.absolute(fileSystem.path.dirname(buildFilePath)),
'-B', '-B',
r'build\windows\x64', r'C:\build\windows\x64',
'-G', '-G',
generator, generator,
'-A', '-A',
...@@ -103,7 +103,7 @@ void main() { ...@@ -103,7 +103,7 @@ void main() {
command: <String>[ command: <String>[
_cmakePath, _cmakePath,
'--build', '--build',
r'build\windows\x64', r'C:\build\windows\x64',
'--config', '--config',
buildMode, buildMode,
...<String>['--target', 'INSTALL'], ...<String>['--target', 'INSTALL'],
......
// 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:args/command_runner.dart';
import 'package:file_testing/file_testing.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/cache.dart';
import 'package:flutter_tools/src/commands/build_preview.dart';
import 'package:flutter_tools/src/globals.dart' as globals;
import '../../src/common.dart';
import '../../src/context.dart';
import '../../src/test_flutter_command_runner.dart';
void main() {
Cache.disableLocking();
late Directory tempDir;
late BufferLogger logger;
final FileSystem fs = LocalFileSystemBlockingSetCurrentDirectory();
setUp(() {
tempDir = fs.systemTempDirectory.createTempSync('flutter_tools_packages_test.');
logger = BufferLogger.test();
});
tearDown(() {
tryToDelete(tempDir);
});
testUsingContext('flutter build _preview creates preview device', () async {
final String projectPath = await createProject(
tempDir,
arguments: <String>['--no-pub', '--template=app'],
);
final BuildPreviewCommand command = BuildPreviewCommand(
logger: logger,
verboseHelp: true,
fs: fs,
processUtils: globals.processUtils,
flutterRoot: Cache.flutterRoot!,
artifacts: globals.artifacts!,
);
final CommandRunner<void> runner = createTestCommandRunner(command);
await runner.run(<String>[
'_preview',
'--no-pub',
fs.path.join(projectPath, 'lib', 'main.dart'),
]);
expect(
fs
.directory(Cache.flutterRoot)
.childDirectory('bin')
.childDirectory('cache')
.childDirectory('artifacts')
.childDirectory('flutter_preview')
.childFile('flutter_preview.exe'),
exists,
);
}, skip: !const LocalPlatform().isWindows); // [intended] Flutter Preview only supported on Windows currently
}
...@@ -6,11 +6,13 @@ import 'package:args/command_runner.dart'; ...@@ -6,11 +6,13 @@ import 'package:args/command_runner.dart';
import 'package:file/memory.dart'; import 'package:file/memory.dart';
import 'package:flutter_tools/src/android/android_studio.dart'; import 'package:flutter_tools/src/android/android_studio.dart';
import 'package:flutter_tools/src/android/android_workflow.dart'; import 'package:flutter_tools/src/android/android_workflow.dart';
import 'package:flutter_tools/src/artifacts.dart';
import 'package:flutter_tools/src/base/config.dart'; import 'package:flutter_tools/src/base/config.dart';
import 'package:flutter_tools/src/base/file_system.dart'; import 'package:flutter_tools/src/base/file_system.dart';
import 'package:flutter_tools/src/base/io.dart'; import 'package:flutter_tools/src/base/io.dart';
import 'package:flutter_tools/src/base/logger.dart'; import 'package:flutter_tools/src/base/logger.dart';
import 'package:flutter_tools/src/base/platform.dart'; import 'package:flutter_tools/src/base/platform.dart';
import 'package:flutter_tools/src/base/process.dart';
import 'package:flutter_tools/src/base/time.dart'; import 'package:flutter_tools/src/base/time.dart';
import 'package:flutter_tools/src/build_system/build_system.dart'; import 'package:flutter_tools/src/build_system/build_system.dart';
import 'package:flutter_tools/src/cache.dart'; import 'package:flutter_tools/src/cache.dart';
...@@ -42,6 +44,7 @@ void main() { ...@@ -42,6 +44,7 @@ void main() {
late Directory tempDir; late Directory tempDir;
late Config testConfig; late Config testConfig;
late FileSystem fs; late FileSystem fs;
const String flutterRoot = '/path/to/flutter'; const String flutterRoot = '/path/to/flutter';
setUp(() { setUp(() {
...@@ -161,6 +164,9 @@ void main() { ...@@ -161,6 +164,9 @@ void main() {
late FakeClock fakeClock; late FakeClock fakeClock;
late FakeDoctor doctor; late FakeDoctor doctor;
late FakeAndroidStudio androidStudio; late FakeAndroidStudio androidStudio;
late ProcessManager processManager;
late BufferLogger logger;
late ProcessUtils processUtils;
setUp(() { setUp(() {
memoryFileSystem = MemoryFileSystem.test(); memoryFileSystem = MemoryFileSystem.test();
...@@ -169,6 +175,9 @@ void main() { ...@@ -169,6 +175,9 @@ void main() {
fakeClock = FakeClock(); fakeClock = FakeClock();
doctor = FakeDoctor(); doctor = FakeDoctor();
androidStudio = FakeAndroidStudio(); androidStudio = FakeAndroidStudio();
processManager = FakeProcessManager.empty();
logger = BufferLogger.test();
processUtils = ProcessUtils(logger: logger, processManager: processManager);
}); });
testUsingContext('flutter commands send timing events', () async { testUsingContext('flutter commands send timing events', () async {
...@@ -220,17 +229,17 @@ void main() { ...@@ -220,17 +229,17 @@ void main() {
testUsingContext('compound command usage path', () async { testUsingContext('compound command usage path', () async {
final BuildCommand buildCommand = BuildCommand( final BuildCommand buildCommand = BuildCommand(
artifacts: Artifacts.test(fileSystem: memoryFileSystem),
androidSdk: FakeAndroidSdk(), androidSdk: FakeAndroidSdk(),
buildSystem: TestBuildSystem.all(BuildResult(success: true)), buildSystem: TestBuildSystem.all(BuildResult(success: true)),
fileSystem: MemoryFileSystem.test(), fileSystem: memoryFileSystem,
logger: BufferLogger.test(), logger: logger,
processUtils: processUtils,
osUtils: FakeOperatingSystemUtils(), osUtils: FakeOperatingSystemUtils(),
); );
final FlutterCommand buildApkCommand = buildCommand.subcommands['apk']! as FlutterCommand; final FlutterCommand buildApkCommand = buildCommand.subcommands['apk']! as FlutterCommand;
expect(await buildApkCommand.usagePath, 'build/apk'); expect(await buildApkCommand.usagePath, 'build/apk');
}, overrides: <Type, Generator>{
Usage: () => testUsage,
}); });
testUsingContext('command sends localtime', () async { testUsingContext('command sends localtime', () async {
...@@ -253,7 +262,7 @@ void main() { ...@@ -253,7 +262,7 @@ void main() {
expect(log.contains(formatDateTime(dateTime)), isTrue); expect(log.contains(formatDateTime(dateTime)), isTrue);
}, overrides: <Type, Generator>{ }, overrides: <Type, Generator>{
FileSystem: () => memoryFileSystem, FileSystem: () => memoryFileSystem,
ProcessManager: () => FakeProcessManager.any(), ProcessManager: () => processManager,
SystemClock: () => fakeClock, SystemClock: () => fakeClock,
Platform: () => FakePlatform( Platform: () => FakePlatform(
environment: <String, String>{ environment: <String, String>{
...@@ -283,7 +292,7 @@ void main() { ...@@ -283,7 +292,7 @@ void main() {
expect(log.contains(formatDateTime(dateTime)), isTrue); expect(log.contains(formatDateTime(dateTime)), isTrue);
}, overrides: <Type, Generator>{ }, overrides: <Type, Generator>{
FileSystem: () => memoryFileSystem, FileSystem: () => memoryFileSystem,
ProcessManager: () => FakeProcessManager.any(), ProcessManager: () => processManager,
SystemClock: () => fakeClock, SystemClock: () => fakeClock,
Platform: () => FakePlatform( Platform: () => FakePlatform(
environment: <String, String>{ environment: <String, String>{
......
...@@ -6,10 +6,10 @@ import 'package:flutter_tools/src/base/file_system.dart'; ...@@ -6,10 +6,10 @@ import 'package:flutter_tools/src/base/file_system.dart';
import 'package:flutter_tools/src/base/logger.dart'; import 'package:flutter_tools/src/base/logger.dart';
import 'package:flutter_tools/src/base/os.dart'; import 'package:flutter_tools/src/base/os.dart';
import 'package:flutter_tools/src/base/platform.dart'; import 'package:flutter_tools/src/base/platform.dart';
import 'package:flutter_tools/src/base/signals.dart';
import 'package:process/process.dart'; import 'package:process/process.dart';
import '../../src/common.dart'; import '../../src/common.dart';
import '../../src/context.dart';
void main() { void main() {
group('OperatingSystemUtils', () { group('OperatingSystemUtils', () {
...@@ -17,7 +17,7 @@ void main() { ...@@ -17,7 +17,7 @@ void main() {
late FileSystem fileSystem; late FileSystem fileSystem;
setUp(() { setUp(() {
fileSystem = LocalFileSystem.test(signals: Signals.test()); fileSystem = LocalFileSystem.test(signals: FakeSignals());
tempDir = fileSystem.systemTempDirectory.createTempSync('flutter_tools_os_utils_test.'); tempDir = fileSystem.systemTempDirectory.createTempSync('flutter_tools_os_utils_test.');
}); });
......
...@@ -5,10 +5,12 @@ ...@@ -5,10 +5,12 @@
import 'package:args/args.dart'; import 'package:args/args.dart';
import 'package:args/command_runner.dart'; import 'package:args/command_runner.dart';
import 'package:file/memory.dart'; 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/file_system.dart';
import 'package:flutter_tools/src/base/io.dart'; import 'package:flutter_tools/src/base/io.dart';
import 'package:flutter_tools/src/base/logger.dart'; import 'package:flutter_tools/src/base/logger.dart';
import 'package:flutter_tools/src/base/platform.dart'; import 'package:flutter_tools/src/base/platform.dart';
import 'package:flutter_tools/src/base/process.dart';
import 'package:flutter_tools/src/base/signals.dart'; import 'package:flutter_tools/src/base/signals.dart';
import 'package:flutter_tools/src/base/terminal.dart'; import 'package:flutter_tools/src/base/terminal.dart';
import 'package:flutter_tools/src/build_info.dart'; import 'package:flutter_tools/src/build_info.dart';
...@@ -111,11 +113,19 @@ void main() { ...@@ -111,11 +113,19 @@ void main() {
}); });
testUsingContext('Include only supported sub commands', () { testUsingContext('Include only supported sub commands', () {
final BufferLogger logger = BufferLogger.test();
final ProcessUtils processUtils = ProcessUtils(
logger: logger,
processManager: FakeProcessManager.empty(),
);
final MemoryFileSystem fs = MemoryFileSystem.test();
final BuildCommand command = BuildCommand( final BuildCommand command = BuildCommand(
artifacts: Artifacts.test(fileSystem: fs),
androidSdk: FakeAndroidSdk(), androidSdk: FakeAndroidSdk(),
buildSystem: TestBuildSystem.all(BuildResult(success: true)), buildSystem: TestBuildSystem.all(BuildResult(success: true)),
fileSystem: MemoryFileSystem.test(), fileSystem: fs,
logger: BufferLogger.test(), logger: logger,
processUtils: processUtils,
osUtils: FakeOperatingSystemUtils(), osUtils: FakeOperatingSystemUtils(),
); );
for (final Command<void> x in command.subcommands.values) { for (final Command<void> x in command.subcommands.values) {
......
...@@ -6,6 +6,7 @@ import 'dart:async'; ...@@ -6,6 +6,7 @@ import 'dart:async';
import 'package:file/memory.dart'; import 'package:file/memory.dart';
import 'package:flutter_tools/src/application_package.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/file_system.dart';
import 'package:flutter_tools/src/base/logger.dart'; import 'package:flutter_tools/src/base/logger.dart';
import 'package:flutter_tools/src/base/platform.dart'; import 'package:flutter_tools/src/base/platform.dart';
...@@ -22,20 +23,38 @@ import 'package:test/fake.dart'; ...@@ -22,20 +23,38 @@ import 'package:test/fake.dart';
import '../src/common.dart'; import '../src/common.dart';
import '../src/context.dart'; import '../src/context.dart';
import '../src/fakes.dart';
void main() { 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 { testWithoutContext('PreviewDevice defaults', () async {
final PreviewDevice device = PreviewDevice( final PreviewDevice device = PreviewDevice(
fileSystem: MemoryFileSystem.test(), artifacts: Artifacts.test(),
fileSystem: fs,
processManager: FakeProcessManager.any(), processManager: FakeProcessManager.any(),
previewBinary: previewBinary,
logger: BufferLogger.test(), logger: BufferLogger.test(),
platform: FakePlatform(),
); );
expect(await device.isLocalEmulator, false); expect(await device.isLocalEmulator, false);
expect(device.name, 'preview'); expect(device.name, 'preview');
expect(await device.sdkNameAndVersion, 'preview'); expect(await device.sdkNameAndVersion, 'preview');
expect(await device.targetPlatform, TargetPlatform.tester); expect(await device.targetPlatform, TargetPlatform.windows_x64);
expect(device.category, Category.desktop); expect(device.category, Category.desktop);
expect(device.ephemeral, false); expect(device.ephemeral, false);
expect(device.id, 'preview'); expect(device.id, 'preview');
...@@ -48,29 +67,29 @@ void main() { ...@@ -48,29 +67,29 @@ void main() {
}); });
testUsingContext('Can build a simulator app', () async { testUsingContext('Can build a simulator app', () async {
Cache.flutterRoot = '';
final Completer<void> completer = Completer<void>(); final Completer<void> completer = Completer<void>();
final FileSystem fileSystem = MemoryFileSystem.test();
final BufferLogger logger = BufferLogger.test(); final BufferLogger logger = BufferLogger.test();
final PreviewDevice device = PreviewDevice( final PreviewDevice device = PreviewDevice(
fileSystem: fileSystem, artifacts: Artifacts.test(),
fileSystem: fs,
previewBinary: previewBinary,
processManager: FakeProcessManager.list(<FakeCommand>[ processManager: FakeProcessManager.list(<FakeCommand>[
FakeCommand( FakeCommand(
command: const <String>[ command: const <String>[
'/.tmp_rand0/flutter_preview.rand0/splash', 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', stdout: 'The Dart VM service is listening on http://127.0.0.1:64494/fZ_B2N6JRwY=/\n',
completer: completer, completer: completer,
), ),
]), ]),
logger: logger, logger: logger,
platform: FakePlatform(), builderFactory: () => FakeBundleBuilder(fs),
builderFactory: () => FakeBundleBuilder(fileSystem),
); );
fileSystem final Directory previewDeviceCacheDir = fs
.directory('artifacts_temp') .directory('Artifact.windowsDesktopPath.TargetPlatform.windows_x64.debug')
.childDirectory('Debug') ..createSync(recursive: true);
.createSync(recursive: true); previewDeviceCacheDir.childFile('flutter_windows.dll').writeAsStringSync('1010101');
previewDeviceCacheDir.childFile('icudtl.dat').writeAsStringSync('1010101');
final LaunchResult result = await device.startApp( final LaunchResult result = await device.startApp(
FakeApplicationPackage(), FakeApplicationPackage(),
...@@ -80,6 +99,84 @@ void main() { ...@@ -80,6 +99,84 @@ void main() {
expect(result.started, true); expect(result.started, true);
expect(result.vmServiceUri, Uri.parse('http://127.0.0.1:64494/fZ_B2N6JRwY=/')); 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<Device> 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<Device> 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(<int>[1, 0, 0, 1]);
final PreviewDeviceDiscovery discovery = PreviewDeviceDiscovery(
artifacts: artifacts,
fileSystem: fs,
logger: BufferLogger.test(),
processManager: processManager,
platform: windowsPlatform,
featureFlags: featureFlags,
);
final List<Device> devices = await discovery.devices();
expect(devices, hasLength(1));
final Device previewDevice = devices.first;
expect(previewDevice, isA<PreviewDevice>());
});
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<Device> devices = await discovery.devices();
expect(devices, isEmpty);
});
});
} }
class FakeFlutterProject extends Fake implements FlutterProject { } class FakeFlutterProject extends Fake implements FlutterProject { }
......
...@@ -3,8 +3,10 @@ ...@@ -3,8 +3,10 @@
// found in the LICENSE file. // found in the LICENSE file.
import 'package:file/memory.dart'; 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/file_system.dart';
import 'package:flutter_tools/src/base/logger.dart'; import 'package:flutter_tools/src/base/logger.dart';
import 'package:flutter_tools/src/base/process.dart';
import 'package:flutter_tools/src/build_system/build_system.dart'; import 'package:flutter_tools/src/build_system/build_system.dart';
import 'package:flutter_tools/src/cache.dart'; import 'package:flutter_tools/src/cache.dart';
import 'package:flutter_tools/src/commands/build.dart'; import 'package:flutter_tools/src/commands/build.dart';
...@@ -26,14 +28,24 @@ void main() { ...@@ -26,14 +28,24 @@ void main() {
late File registrant; late File registrant;
// Environment overrides // Environment overrides
late Artifacts artifacts;
late FileSystem fileSystem; late FileSystem fileSystem;
late ProcessManager processManager; late ProcessManager processManager;
late BuildSystem buildSystem; late BuildSystem buildSystem;
late ProcessUtils processUtils;
late BufferLogger logger;
setUp(() { setUp(() {
// Prepare environment overrides // Prepare environment overrides
fileSystem = MemoryFileSystem.test(); fileSystem = MemoryFileSystem.test();
artifacts = Artifacts.test(fileSystem: fileSystem);
processManager = FakeProcessManager.any(); processManager = FakeProcessManager.any();
logger = BufferLogger.test();
processUtils = ProcessUtils(
processManager: processManager,
logger: logger,
);
buildSystem = TestBuildSystem.all(BuildResult(success: true)); buildSystem = TestBuildSystem.all(BuildResult(success: true));
// Write some initial state into our testing filesystem // Write some initial state into our testing filesystem
setupFileSystemForEndToEndTest(fileSystem); setupFileSystemForEndToEndTest(fileSystem);
...@@ -47,11 +59,13 @@ void main() { ...@@ -47,11 +59,13 @@ void main() {
expect(registrant.existsSync(), isFalse); expect(registrant.existsSync(), isFalse);
await createTestCommandRunner(BuildCommand( await createTestCommandRunner(BuildCommand(
artifacts: artifacts,
androidSdk: FakeAndroidSdk(), androidSdk: FakeAndroidSdk(),
buildSystem: buildSystem, buildSystem: buildSystem,
fileSystem: fileSystem, fileSystem: fileSystem,
logger: BufferLogger.test(), logger: BufferLogger.test(),
osUtils: FakeOperatingSystemUtils(), osUtils: FakeOperatingSystemUtils(),
processUtils: processUtils,
)) ))
.run(<String>['build', 'web', '--no-pub']); .run(<String>['build', 'web', '--no-pub']);
...@@ -70,11 +84,13 @@ void main() { ...@@ -70,11 +84,13 @@ void main() {
expect(contentsBeforeBuild, isNot(contains('lib/generated_plugin_registrant.dart'))); expect(contentsBeforeBuild, isNot(contains('lib/generated_plugin_registrant.dart')));
await createTestCommandRunner(BuildCommand( await createTestCommandRunner(BuildCommand(
artifacts: artifacts,
androidSdk: FakeAndroidSdk(), androidSdk: FakeAndroidSdk(),
buildSystem: buildSystem, buildSystem: buildSystem,
fileSystem: fileSystem, fileSystem: fileSystem,
logger: BufferLogger.test(), logger: logger,
osUtils: FakeOperatingSystemUtils(), osUtils: FakeOperatingSystemUtils(),
processUtils: processUtils,
)) ))
.run(<String>['build', 'web', '--no-pub']); .run(<String>['build', 'web', '--no-pub']);
...@@ -92,10 +108,12 @@ void main() { ...@@ -92,10 +108,12 @@ void main() {
expect(gitignore.readAsStringSync(), contains('lib/generated_plugin_registrant.dart')); expect(gitignore.readAsStringSync(), contains('lib/generated_plugin_registrant.dart'));
await createTestCommandRunner(BuildCommand( await createTestCommandRunner(BuildCommand(
artifacts: artifacts,
androidSdk: FakeAndroidSdk(), androidSdk: FakeAndroidSdk(),
buildSystem: buildSystem, buildSystem: buildSystem,
fileSystem: fileSystem, fileSystem: fileSystem,
logger: BufferLogger.test(), logger: logger,
processUtils: processUtils,
osUtils: FakeOperatingSystemUtils(), osUtils: FakeOperatingSystemUtils(),
)) ))
.run(<String>['build', 'web', '--no-pub']); .run(<String>['build', 'web', '--no-pub']);
...@@ -113,10 +131,12 @@ void main() { ...@@ -113,10 +131,12 @@ void main() {
expect(registrant.existsSync(), isTrue); expect(registrant.existsSync(), isTrue);
await createTestCommandRunner(BuildCommand( await createTestCommandRunner(BuildCommand(
artifacts: artifacts,
androidSdk: FakeAndroidSdk(), androidSdk: FakeAndroidSdk(),
buildSystem: buildSystem, buildSystem: buildSystem,
fileSystem: fileSystem, fileSystem: fileSystem,
logger: BufferLogger.test(), logger: logger,
processUtils: processUtils,
osUtils: FakeOperatingSystemUtils(), osUtils: FakeOperatingSystemUtils(),
)) ))
.run(<String>['build', 'web', '--no-pub']); .run(<String>['build', 'web', '--no-pub']);
...@@ -136,10 +156,12 @@ void main() { ...@@ -136,10 +156,12 @@ void main() {
expect(gitignore.readAsStringSync(), contains('lib/generated_plugin_registrant.dart')); expect(gitignore.readAsStringSync(), contains('lib/generated_plugin_registrant.dart'));
await createTestCommandRunner(BuildCommand( await createTestCommandRunner(BuildCommand(
artifacts: artifacts,
androidSdk: FakeAndroidSdk(), androidSdk: FakeAndroidSdk(),
buildSystem: buildSystem, buildSystem: buildSystem,
fileSystem: fileSystem, fileSystem: fileSystem,
logger: BufferLogger.test(), logger: logger,
processUtils: processUtils,
osUtils: FakeOperatingSystemUtils(), osUtils: FakeOperatingSystemUtils(),
)) ))
.run(<String>['build', 'web', '--no-pub']); .run(<String>['build', 'web', '--no-pub']);
......
...@@ -382,7 +382,8 @@ class NoopCrashReporter implements CrashReporter { ...@@ -382,7 +382,8 @@ class NoopCrashReporter implements CrashReporter {
} }
class LocalFileSystemBlockingSetCurrentDirectory extends LocalFileSystem { class LocalFileSystemBlockingSetCurrentDirectory extends LocalFileSystem {
// Use [FakeSignals] so developers running the test suite can kill the test runner. // Use [FakeSignals] so developers running the test suite can kill the test
// runner.
LocalFileSystemBlockingSetCurrentDirectory() : super.test(signals: FakeSignals()); LocalFileSystemBlockingSetCurrentDirectory() : super.test(signals: FakeSignals());
@override @override
......
...@@ -462,6 +462,7 @@ class TestFeatureFlags implements FeatureFlags { ...@@ -462,6 +462,7 @@ class TestFeatureFlags implements FeatureFlags {
this.isFlutterWebWasmEnabled = false, this.isFlutterWebWasmEnabled = false,
this.isCliAnimationEnabled = true, this.isCliAnimationEnabled = true,
this.isNativeAssetsEnabled = false, this.isNativeAssetsEnabled = false,
this.isPreviewDeviceEnabled = false,
}); });
@override @override
...@@ -497,31 +498,24 @@ class TestFeatureFlags implements FeatureFlags { ...@@ -497,31 +498,24 @@ class TestFeatureFlags implements FeatureFlags {
@override @override
final bool isNativeAssetsEnabled; final bool isNativeAssetsEnabled;
@override
final bool isPreviewDeviceEnabled;
@override @override
bool isEnabled(Feature feature) { bool isEnabled(Feature feature) {
switch (feature) { return switch (feature) {
case flutterWebFeature: flutterWebFeature => isWebEnabled,
return isWebEnabled; flutterLinuxDesktopFeature => isLinuxEnabled,
case flutterLinuxDesktopFeature: flutterMacOSDesktopFeature => isMacOSEnabled,
return isLinuxEnabled; flutterWindowsDesktopFeature => isWindowsEnabled,
case flutterMacOSDesktopFeature: flutterAndroidFeature => isAndroidEnabled,
return isMacOSEnabled; flutterIOSFeature => isIOSEnabled,
case flutterWindowsDesktopFeature: flutterFuchsiaFeature => isFuchsiaEnabled,
return isWindowsEnabled; flutterCustomDevicesFeature => areCustomDevicesEnabled,
case flutterAndroidFeature: cliAnimation => isCliAnimationEnabled,
return isAndroidEnabled; nativeAssets => isNativeAssetsEnabled,
case flutterIOSFeature: _ => false,
return isIOSEnabled; };
case flutterFuchsiaFeature:
return isFuchsiaEnabled;
case flutterCustomDevicesFeature:
return areCustomDevicesEnabled;
case cliAnimation:
return isCliAnimationEnabled;
case nativeAssets:
return isNativeAssetsEnabled;
}
return false;
} }
} }
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment