blob: 12301c7948fb2f03fe9715d6c65f200c0030ce30 [file] [log] [blame]
// 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/memory.dart';
import 'package:flutter_tools/src/base/bot_detector.dart';
import 'package:flutter_tools/src/base/file_system.dart';
import 'package:flutter_tools/src/base/io.dart';
import 'package:flutter_tools/src/base/platform.dart';
import 'package:flutter_tools/src/base/terminal.dart';
import 'package:flutter_tools/src/cache.dart';
import 'package:flutter_tools/src/globals.dart' as globals;
import 'package:flutter_tools/src/runner/flutter_command.dart';
import 'package:flutter_tools/src/runner/flutter_command_runner.dart';
import 'package:flutter_tools/src/version.dart';
import '../../src/context.dart';
import '../../src/fakes.dart';
import '../../src/test_flutter_command_runner.dart';
import 'utils.dart';
const String _kFlutterRoot = '/flutter/flutter';
const String _kProjectRoot = '/project';
void main() {
group('FlutterCommandRunner', () {
late MemoryFileSystem fileSystem;
late Platform platform;
setUpAll(() {
Cache.disableLocking();
});
setUp(() {
fileSystem = MemoryFileSystem.test();
fileSystem.directory(_kFlutterRoot).createSync(recursive: true);
fileSystem.directory(_kProjectRoot).createSync(recursive: true);
fileSystem.currentDirectory = _kProjectRoot;
platform = FakePlatform(
environment: <String, String>{
'FLUTTER_ROOT': _kFlutterRoot,
},
version: '1 2 3 4 5',
);
});
group('run', () {
testUsingContext('checks that Flutter installation is up-to-date', () async {
final FlutterCommandRunner runner = createTestCommandRunner(DummyFlutterCommand()) as FlutterCommandRunner;
final FakeFlutterVersion version = globals.flutterVersion as FakeFlutterVersion;
await runner.run(<String>['dummy']);
expect(version.didCheckFlutterVersionFreshness, true);
}, overrides: <Type, Generator>{
FileSystem: () => fileSystem,
ProcessManager: () => FakeProcessManager.any(),
Platform: () => platform,
FlutterVersion: () => FakeFlutterVersion(),
BotDetector: () => const FakeBotDetector(false),
OutputPreferences: () => OutputPreferences.test(),
});
testUsingContext('does not check that Flutter installation is up-to-date with --machine flag', () async {
final FlutterCommandRunner runner = createTestCommandRunner(DummyFlutterCommand()) as FlutterCommandRunner;
final FakeFlutterVersion version = globals.flutterVersion as FakeFlutterVersion;
await runner.run(<String>['dummy', '--machine', '--version']);
expect(version.didCheckFlutterVersionFreshness, false);
}, overrides: <Type, Generator>{
FileSystem: () => fileSystem,
ProcessManager: () => FakeProcessManager.any(),
Platform: () => platform,
FlutterVersion: () => FakeFlutterVersion(),
OutputPreferences: () => OutputPreferences.test(),
});
testUsingContext('does not check that Flutter installation is up-to-date with CI=true in environment', () async {
final FlutterCommandRunner runner = createTestCommandRunner(DummyFlutterCommand()) as FlutterCommandRunner;
final FakeFlutterVersion version = globals.flutterVersion as FakeFlutterVersion;
await runner.run(<String>['dummy', '--version']);
expect(version.didCheckFlutterVersionFreshness, false);
}, overrides: <Type, Generator>{
FileSystem: () => fileSystem,
ProcessManager: () => FakeProcessManager.any(),
Platform: () => platform,
BotDetector: () => const FakeBotDetector(true),
}, initializeFlutterRoot: false);
testUsingContext('checks that Flutter installation is up-to-date with CI=true and --machine when explicit --version-check', () async {
final FlutterCommandRunner runner = createTestCommandRunner(DummyFlutterCommand()) as FlutterCommandRunner;
final FakeFlutterVersion version = globals.flutterVersion as FakeFlutterVersion;
await runner.run(<String>['dummy', '--version', '--machine', '--version-check']);
expect(version.didCheckFlutterVersionFreshness, true);
}, overrides: <Type, Generator>{
FileSystem: () => fileSystem,
ProcessManager: () => FakeProcessManager.any(),
Platform: () => platform,
BotDetector: () => const FakeBotDetector(true),
}, initializeFlutterRoot: false);
testUsingContext('checks that Flutter installation is up-to-date if shell completion to terminal', () async {
final FlutterCommand command = DummyFlutterCommand(name: 'bash-completion');
final FlutterCommandRunner runner = createTestCommandRunner(command) as FlutterCommandRunner;
final FakeFlutterVersion version = globals.flutterVersion as FakeFlutterVersion;
await runner.run(<String>['bash-completion']);
expect(version.didCheckFlutterVersionFreshness, true);
}, overrides: <Type, Generator>{
FileSystem: () => fileSystem,
ProcessManager: () => FakeProcessManager.any(),
Platform: () => platform,
FlutterVersion: () => FakeFlutterVersion(),
BotDetector: () => const FakeBotDetector(false),
Stdio: () => FakeStdio(hasFakeTerminal: true),
});
testUsingContext('does not check that Flutter installation is up-to-date if redirecting shell completion', () async {
final FlutterCommand command = DummyFlutterCommand(name: 'bash-completion');
final FlutterCommandRunner runner = createTestCommandRunner(command) as FlutterCommandRunner;
final FakeFlutterVersion version = globals.flutterVersion as FakeFlutterVersion;
await runner.run(<String>['bash-completion']);
expect(version.didCheckFlutterVersionFreshness, false);
}, overrides: <Type, Generator>{
FileSystem: () => fileSystem,
ProcessManager: () => FakeProcessManager.any(),
Platform: () => platform,
FlutterVersion: () => FakeFlutterVersion(),
BotDetector: () => const FakeBotDetector(false),
Stdio: () => FakeStdio(hasFakeTerminal: false),
});
testUsingContext('Fetches tags when --version is used', () async {
final FlutterCommandRunner runner = createTestCommandRunner(DummyFlutterCommand()) as FlutterCommandRunner;
final FakeFlutterVersion version = globals.flutterVersion as FakeFlutterVersion;
await runner.run(<String>['--version']);
expect(version.didFetchTagsAndUpdate, true);
}, overrides: <Type, Generator>{
FileSystem: () => fileSystem,
ProcessManager: () => FakeProcessManager.any(),
Platform: () => platform,
FlutterVersion: () => FakeFlutterVersion(),
OutputPreferences: () => OutputPreferences.test(),
});
testUsingContext("Doesn't crash on invalid .packages file", () async {
final FlutterCommandRunner runner = createTestCommandRunner(DummyFlutterCommand()) as FlutterCommandRunner;
fileSystem.file('pubspec.yaml').createSync();
fileSystem.file('.packages')
..createSync()
..writeAsStringSync('Not a valid package');
await runner.run(<String>['dummy']);
}, overrides: <Type, Generator>{
FileSystem: () => fileSystem,
ProcessManager: () => FakeProcessManager.any(),
Platform: () => platform,
OutputPreferences: () => OutputPreferences.test(),
});
group('getRepoPackages', () {
late String? oldFlutterRoot;
setUp(() {
oldFlutterRoot = Cache.flutterRoot;
Cache.flutterRoot = _kFlutterRoot;
fileSystem.directory(fileSystem.path.join(_kFlutterRoot, 'examples'))
.createSync(recursive: true);
fileSystem.directory(fileSystem.path.join(_kFlutterRoot, 'packages'))
.createSync(recursive: true);
fileSystem.directory(fileSystem.path.join(_kFlutterRoot, 'dev', 'tools', 'aatool'))
.createSync(recursive: true);
fileSystem.file(fileSystem.path.join(_kFlutterRoot, 'dev', 'tools', 'pubspec.yaml'))
.createSync();
fileSystem.file(fileSystem.path.join(_kFlutterRoot, 'dev', 'tools', 'aatool', 'pubspec.yaml'))
.createSync();
});
tearDown(() {
Cache.flutterRoot = oldFlutterRoot;
});
testUsingContext('', () {
final FlutterCommandRunner runner = createTestCommandRunner(DummyFlutterCommand()) as FlutterCommandRunner;
final List<String> packagePaths = runner.getRepoPackages()
.map((Directory d) => d.path).toList();
expect(packagePaths, <String>[
fileSystem.directory(fileSystem.path.join(_kFlutterRoot, 'dev', 'tools', 'aatool')).path,
fileSystem.directory(fileSystem.path.join(_kFlutterRoot, 'dev', 'tools')).path,
]);
}, overrides: <Type, Generator>{
FileSystem: () => fileSystem,
ProcessManager: () => FakeProcessManager.any(),
Platform: () => platform,
FlutterVersion: () => FakeFlutterVersion(),
OutputPreferences: () => OutputPreferences.test(),
});
});
group('wrapping', () {
testUsingContext('checks that output wrapping is turned on when writing to a terminal', () async {
final FlutterCommandRunner runner = createTestCommandRunner(DummyFlutterCommand()) as FlutterCommandRunner;
final FakeFlutterCommand fakeCommand = FakeFlutterCommand();
runner.addCommand(fakeCommand);
await runner.run(<String>['fake']);
expect(fakeCommand.preferences.wrapText, isTrue);
}, overrides: <Type, Generator>{
FileSystem: () => fileSystem,
ProcessManager: () => FakeProcessManager.any(),
Stdio: () => FakeStdio(hasFakeTerminal: true),
OutputPreferences: () => OutputPreferences.test(),
}, initializeFlutterRoot: false);
testUsingContext('checks that output wrapping is turned off when not writing to a terminal', () async {
final FlutterCommandRunner runner = createTestCommandRunner(DummyFlutterCommand()) as FlutterCommandRunner;
final FakeFlutterCommand fakeCommand = FakeFlutterCommand();
runner.addCommand(fakeCommand);
await runner.run(<String>['fake']);
expect(fakeCommand.preferences.wrapText, isFalse);
}, overrides: <Type, Generator>{
FileSystem: () => fileSystem,
ProcessManager: () => FakeProcessManager.any(),
Stdio: () => FakeStdio(hasFakeTerminal: false),
OutputPreferences: () => OutputPreferences.test(),
}, initializeFlutterRoot: false);
testUsingContext('checks that output wrapping is turned off when set on the command line and writing to a terminal', () async {
final FlutterCommandRunner runner = createTestCommandRunner(DummyFlutterCommand()) as FlutterCommandRunner;
final FakeFlutterCommand fakeCommand = FakeFlutterCommand();
runner.addCommand(fakeCommand);
await runner.run(<String>['--no-wrap', 'fake']);
expect(fakeCommand.preferences.wrapText, isFalse);
}, overrides: <Type, Generator>{
FileSystem: () => fileSystem,
ProcessManager: () => FakeProcessManager.any(),
Stdio: () => FakeStdio(hasFakeTerminal: true),
OutputPreferences: () => OutputPreferences.test(),
}, initializeFlutterRoot: false);
testUsingContext('checks that output wrapping is turned on when set on the command line, but not writing to a terminal', () async {
final FlutterCommandRunner runner = createTestCommandRunner(DummyFlutterCommand()) as FlutterCommandRunner;
final FakeFlutterCommand fakeCommand = FakeFlutterCommand();
runner.addCommand(fakeCommand);
await runner.run(<String>['--wrap', 'fake']);
expect(fakeCommand.preferences.wrapText, isTrue);
}, overrides: <Type, Generator>{
FileSystem: () => fileSystem,
ProcessManager: () => FakeProcessManager.any(),
Stdio: () => FakeStdio(hasFakeTerminal: false),
OutputPreferences: () => OutputPreferences.test(),
}, initializeFlutterRoot: false);
});
});
});
}
class FakeFlutterCommand extends FlutterCommand {
late OutputPreferences preferences;
@override
Future<FlutterCommandResult> runCommand() {
preferences = globals.outputPreferences;
return Future<FlutterCommandResult>.value(const FlutterCommandResult(ExitStatus.success));
}
@override
String get description => '';
@override
String get name => 'fake';
}
class FakeStdio extends Stdio {
FakeStdio({required this.hasFakeTerminal});
final bool hasFakeTerminal;
@override
bool get hasTerminal => hasFakeTerminal;
@override
int? get terminalColumns => hasFakeTerminal ? 80 : null;
@override
int? get terminalLines => hasFakeTerminal ? 24 : null;
@override
bool get supportsAnsiEscapes => hasFakeTerminal;
}