| // 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/android/android_builder.dart'; |
| import 'package:flutter_tools/src/base/exit.dart'; |
| import 'package:flutter_tools/src/base/file_system.dart'; |
| import 'package:flutter_tools/src/base/platform.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/features.dart'; |
| import 'package:flutter_tools/src/runner/flutter_command.dart'; |
| |
| import '../../src/android_common.dart'; |
| |
| import '../../src/common.dart'; |
| import '../../src/context.dart'; |
| import '../../src/fake_build_command.dart'; |
| import '../../src/fakes.dart'; |
| import '../../src/test_build_system.dart'; |
| import '../../src/test_flutter_command_runner.dart'; |
| |
| void main() { |
| setUp(() { |
| Cache.disableLocking(); |
| }); |
| |
| tearDown(() { |
| restoreExitFunction(); |
| }); |
| |
| testUsingContext('flutter build without arguments prints help and exits with code 1', () async { |
| int? exitCode; |
| setExitFunctionForTests((int code) { |
| exitCode = code; |
| }); |
| |
| final BuildCommand command = createFakeBuildCommand( |
| androidSdk: FakeAndroidSdk(), |
| buildSystem: TestBuildSystem.all(BuildResult(success: true)), |
| fileSystem: MemoryFileSystem.test(), |
| logger: testLogger, |
| osUtils: FakeOperatingSystemUtils(), |
| config: FakeConfig(), |
| platform: FakePlatform(), |
| fileSystemUtils: FakeFileSystemUtils(), |
| terminal: FakeTerminal(), |
| plistParser: FakePlistParser(), |
| processUtils: FakeProcessUtils(), |
| processManager: FakeProcessManager.any(), |
| templateRenderer: FakeTemplateRenderer(), |
| xcode: FakeXcode(), |
| artifacts: FakeArtifacts(), |
| cache: FakeCache(), |
| flutterVersion: FakeFlutterVersion(), |
| featureFlags: TestFeatureFlags(), |
| ); |
| final CommandRunner<void> commandRunner = createTestCommandRunner(command); |
| |
| await commandRunner.run(<String>['build']); |
| |
| expect(exitCode, 1); |
| expect(testLogger.statusText, contains(command.description)); |
| }); |
| |
| testUsingContext('obfuscate requires split-debug-info', () { |
| final 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 ProcessManager processManager; |
| |
| setUp(() { |
| fs = MemoryFileSystem.test(); |
| fs.file('/package/pubspec.yaml').createSync(recursive: true); |
| fs.currentDirectory = '/package'; |
| Cache.disableLocking(); |
| processManager = FakeProcessManager.empty(); |
| }); |
| |
| testUsingContext("doesn't fail if --fatal-warnings specified and no warnings occur", () async { |
| command = FakeBuildCommand( |
| androidContext: FakeAndroidContext(), |
| appleContext: FakeAppleContext(), |
| buildSystem: TestBuildSystem.all(BuildResult(success: true)), |
| templateRenderer: FakeTemplateRenderer(), |
| toolContext: FakeToolContext(fs: fs, logger: testLogger), |
| ); |
| 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( |
| androidContext: FakeAndroidContext(), |
| appleContext: FakeAppleContext(), |
| buildSystem: TestBuildSystem.all(BuildResult(success: true)), |
| templateRenderer: FakeTemplateRenderer(), |
| toolContext: FakeToolContext(fs: fs, logger: testLogger), |
| ); |
| 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( |
| androidContext: FakeAndroidContext(), |
| appleContext: FakeAppleContext(), |
| buildSystem: TestBuildSystem.all(BuildResult(success: true)), |
| templateRenderer: FakeTemplateRenderer(), |
| toolContext: FakeToolContext(fs: fs, logger: testLogger), |
| ); |
| 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( |
| androidContext: FakeAndroidContext(), |
| appleContext: FakeAppleContext(), |
| buildSystem: TestBuildSystem.all(BuildResult(success: true)), |
| templateRenderer: FakeTemplateRenderer(), |
| toolContext: FakeToolContext(fs: fs, logger: testLogger), |
| ); |
| 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.androidContext, |
| required super.appleContext, |
| required super.buildSystem, |
| required super.templateRenderer, |
| required super.toolContext, |
| AndroidBuilder? androidBuilder, |
| FeatureFlags? featureFlags, |
| bool verboseHelp = false, |
| }) : super( |
| androidBuilder: androidBuilder ?? FakeAndroidBuilder(), |
| featureFlags: featureFlags ?? TestFeatureFlags(), |
| verboseHelp: verboseHelp, |
| ) { |
| addSubcommand(FakeBuildSubcommand(logger: toolContext.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(); |
| } |
| } |