flutter/packages/flutter_tools/test/commands.shard/hermetic/build_test.dart
Christopher Fujino 8a31a3a284
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.
2023-10-18 00:27:54 +00:00

207 lines
6.5 KiB
Dart

// 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/memory.dart';
import 'package:flutter_tools/src/artifacts.dart';
import 'package:flutter_tools/src/base/file_system.dart';
import 'package:flutter_tools/src/base/logger.dart';
import 'package:flutter_tools/src/base/process.dart';
import 'package:flutter_tools/src/build_system/build_system.dart';
import 'package:flutter_tools/src/cache.dart';
import 'package:flutter_tools/src/commands/build.dart';
import 'package:flutter_tools/src/runner/flutter_command.dart';
import '../../src/common.dart';
import '../../src/context.dart';
import '../../src/fakes.dart';
import '../../src/test_build_system.dart';
import '../../src/test_flutter_command_runner.dart';
void main() {
testUsingContext('obfuscate requires split-debug-info', () {
final FakeBuildInfoCommand command = FakeBuildInfoCommand();
final CommandRunner<void> commandRunner = createTestCommandRunner(command);
expect(() => commandRunner.run(<String>[
'fake',
'--obfuscate',
]), throwsToolExit(message: '"--${FlutterOptions.kDartObfuscationOption}" can only be used in '
'combination with "--${FlutterOptions.kSplitDebugInfoOption}"'));
});
group('Fatal Logs', () {
late FakeBuildCommand command;
late MemoryFileSystem fs;
late BufferLogger logger;
late ProcessManager processManager;
late ProcessUtils processUtils;
late Artifacts artifacts;
setUp(() {
fs = MemoryFileSystem.test();
artifacts = Artifacts.test(fileSystem: fs);
fs.file('/package/pubspec.yaml').createSync(recursive: true);
fs.currentDirectory = '/package';
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 {
command = FakeBuildCommand(
artifacts: artifacts,
androidSdk: FakeAndroidSdk(),
buildSystem: TestBuildSystem.all(BuildResult(success: true)),
fileSystem: fs,
logger: logger,
processUtils: processUtils,
osUtils: FakeOperatingSystemUtils(),
);
try {
await createTestCommandRunner(command).run(<String>[
'build',
'test',
'--${FlutterOptions.kFatalWarnings}',
]);
} on Exception {
fail('Unexpected exception thrown');
}
}, overrides: <Type, Generator>{
FileSystem: () => fs,
ProcessManager: () => processManager,
});
testUsingContext("doesn't fail if --fatal-warnings not specified", () async {
command = FakeBuildCommand(
artifacts: artifacts,
androidSdk: FakeAndroidSdk(),
buildSystem: TestBuildSystem.all(BuildResult(success: true)),
fileSystem: fs,
logger: logger,
processUtils: processUtils,
osUtils: FakeOperatingSystemUtils(),
);
testLogger.printWarning('Warning: Mild annoyance Will Robinson!');
try {
await createTestCommandRunner(command).run(<String>[
'build',
'test',
]);
} on Exception {
fail('Unexpected exception thrown');
}
}, overrides: <Type, Generator>{
FileSystem: () => fs,
ProcessManager: () => processManager,
});
testUsingContext('fails if --fatal-warnings specified and warnings emitted', () async {
command = FakeBuildCommand(
artifacts: artifacts,
androidSdk: FakeAndroidSdk(),
buildSystem: TestBuildSystem.all(BuildResult(success: true)),
fileSystem: fs,
logger: logger,
processUtils: processUtils,
osUtils: FakeOperatingSystemUtils(),
);
testLogger.printWarning('Warning: Mild annoyance Will Robinson!');
await expectLater(createTestCommandRunner(command).run(<String>[
'build',
'test',
'--${FlutterOptions.kFatalWarnings}',
]), throwsToolExit(message: 'Logger received warning output during the run, and "--${FlutterOptions.kFatalWarnings}" is enabled.'));
}, overrides: <Type, Generator>{
FileSystem: () => fs,
ProcessManager: () => processManager,
});
testUsingContext('fails if --fatal-warnings specified and errors emitted', () async {
command = FakeBuildCommand(
artifacts: artifacts,
androidSdk: FakeAndroidSdk(),
buildSystem: TestBuildSystem.all(BuildResult(success: true)),
fileSystem: fs,
logger: logger,
processUtils: processUtils,
osUtils: FakeOperatingSystemUtils(),
);
testLogger.printError('Error: Danger Will Robinson!');
await expectLater(createTestCommandRunner(command).run(<String>[
'build',
'test',
'--${FlutterOptions.kFatalWarnings}',
]), throwsToolExit(message: 'Logger received error output during the run, and "--${FlutterOptions.kFatalWarnings}" is enabled.'));
}, overrides: <Type, Generator>{
FileSystem: () => fs,
ProcessManager: () => processManager,
});
});
}
class FakeBuildInfoCommand extends FlutterCommand {
FakeBuildInfoCommand() : super() {
addSplitDebugInfoOption();
addDartObfuscationOption();
}
@override
String get description => '';
@override
String get name => 'fake';
@override
Future<FlutterCommandResult> runCommand() async {
await getBuildInfo();
return FlutterCommandResult.success();
}
}
class FakeBuildCommand extends BuildCommand {
FakeBuildCommand({
required super.fileSystem,
required super.buildSystem,
required super.osUtils,
required Logger logger,
required super.androidSdk,
required super.processUtils,
required super.artifacts,
bool verboseHelp = false,
}) : super(logger: logger) {
addSubcommand(FakeBuildSubcommand(logger: logger, verboseHelp: verboseHelp));
}
@override
String get description => '';
@override
String get name => 'build';
@override
Future<FlutterCommandResult> runCommand() async {
return FlutterCommandResult.success();
}
}
class FakeBuildSubcommand extends BuildSubCommand {
FakeBuildSubcommand({required super.logger, required super.verboseHelp});
@override
String get description => '';
@override
String get name => 'test';
@override
Future<FlutterCommandResult> runCommand() async {
return FlutterCommandResult.success();
}
}