blob: 0365e108435eefc947d1b4ae07cd94c7ccad859b [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 'dart:async';
import 'dart:convert';
import 'dart:io';
import 'package:flutter_tools/src/base/common.dart';
import 'package:flutter_tools/src/base/io.dart';
import 'package:flutter_tools/src/base/terminal.dart';
import 'package:flutter_tools/src/cache.dart';
import 'package:flutter_tools/src/commands/version.dart';
import 'package:flutter_tools/src/version.dart';
import 'package:mockito/mockito.dart';
import 'package:process/process.dart';
import 'package:flutter_tools/src/globals.dart' as globals;
import '../../src/common.dart';
import '../../src/context.dart';
import '../../src/mocks.dart' show MockProcess;
void main() {
group('version', () {
MockStdio mockStdio;
MockVersion mockVersion;
setUpAll(() {
Cache.disableLocking();
});
setUp(() {
mockStdio = MockStdio();
mockVersion = MockVersion();
when(mockStdio.stdinHasTerminal).thenReturn(false);
when(mockStdio.hasTerminal).thenReturn(false);
});
testUsingContext('version ls', () async {
final VersionCommand command = VersionCommand();
await createTestCommandRunner(command).run(<String>[
'version',
'--no-pub',
]);
expect(testLogger.statusText, equals('v10.0.0\r\nv20.0.0\r\n30.0.0-dev.0.0\n'));
}, overrides: <Type, Generator>{
ProcessManager: () => MockProcessManager(),
Stdio: () => mockStdio,
FlutterVersion: () => mockVersion,
});
testUsingContext('version switch prompt is accepted', () async {
when(mockStdio.stdinHasTerminal).thenReturn(true);
const String version = '10.0.0';
final VersionCommand command = VersionCommand();
when(globals.terminal.promptForCharInput(<String>['y', 'n'],
logger: anyNamed('logger'),
prompt: 'Are you sure you want to proceed?')
).thenAnswer((Invocation invocation) async => 'y');
await createTestCommandRunner(command).run(<String>[
'version',
'--no-pub',
version,
]);
expect(testLogger.statusText, contains('Switching Flutter to version $version'));
}, overrides: <Type, Generator>{
ProcessManager: () => MockProcessManager(),
Stdio: () => mockStdio,
AnsiTerminal: () => MockTerminal(),
FlutterVersion: () => mockVersion,
});
testUsingContext('version switch prompt is declined', () async {
when(mockStdio.stdinHasTerminal).thenReturn(true);
const String version = '10.0.0';
final VersionCommand command = VersionCommand();
when(globals.terminal.promptForCharInput(<String>['y', 'n'],
logger: anyNamed('logger'),
prompt: 'Are you sure you want to proceed?')
).thenAnswer((Invocation invocation) async => 'n');
await createTestCommandRunner(command).run(<String>[
'version',
'--no-pub',
version,
]);
expect(testLogger.statusText, isNot(contains('Switching Flutter to version $version')));
}, overrides: <Type, Generator>{
ProcessManager: () => MockProcessManager(),
Stdio: () => mockStdio,
AnsiTerminal: () => MockTerminal(),
FlutterVersion: () => mockVersion,
});
testUsingContext('version switch, latest commit query fails', () async {
const String version = '10.0.0';
final VersionCommand command = VersionCommand();
await createTestCommandRunner(command).run(<String>[
'version',
'--no-pub',
version,
]);
expect(testLogger.errorText, contains('git failed'));
}, overrides: <Type, Generator>{
ProcessManager: () => MockProcessManager(latestCommitFails: true),
Stdio: () => mockStdio,
FlutterVersion: () => mockVersion,
});
testUsingContext('latest commit is parsable when query fails', () {
final FlutterVersion flutterVersion = FlutterVersion();
expect(
() => DateTime.parse(flutterVersion.frameworkCommitDate),
returnsNormally,
);
}, overrides: <Type, Generator>{
ProcessManager: () => MockProcessManager(latestCommitFails: true),
Stdio: () => mockStdio,
FlutterVersion: () => mockVersion,
});
testUsingContext('switch to not supported version without force', () async {
const String version = '1.1.5';
final VersionCommand command = VersionCommand();
await createTestCommandRunner(command).run(<String>[
'version',
'--no-pub',
version,
]);
expect(testLogger.errorText, contains('Version command is not supported in'));
}, overrides: <Type, Generator>{
ProcessManager: () => MockProcessManager(),
Stdio: () => mockStdio,
FlutterVersion: () => mockVersion,
});
testUsingContext('switch to not supported version with force', () async {
const String version = '1.1.5';
final VersionCommand command = VersionCommand();
await createTestCommandRunner(command).run(<String>[
'version',
'--no-pub',
'--force',
version,
]);
expect(testLogger.statusText, contains('Switching Flutter to version $version with force'));
}, overrides: <Type, Generator>{
ProcessManager: () => MockProcessManager(),
Stdio: () => mockStdio,
FlutterVersion: () => mockVersion,
});
testUsingContext('tool exit on confusing version', () async {
const String version = 'master';
final VersionCommand command = VersionCommand();
expect(() async =>
await createTestCommandRunner(command).run(<String>[
'version',
'--no-pub',
version,
]),
throwsToolExit(),
);
}, overrides: <Type, Generator>{
ProcessManager: () => MockProcessManager(),
Stdio: () => mockStdio,
FlutterVersion: () => mockVersion,
});
testUsingContext("exit tool if can't get the tags", () async {
final VersionCommand command = VersionCommand();
try {
await command.getTags();
fail('ToolExit expected');
} on Exception catch (e) {
expect(e, isA<ToolExit>());
}
}, overrides: <Type, Generator>{
ProcessManager: () => MockProcessManager(failGitTag: true),
Stdio: () => mockStdio,
FlutterVersion: () => mockVersion,
});
testUsingContext('Does not run pub when outside a project', () async {
final VersionCommand command = VersionCommand();
await createTestCommandRunner(command).run(<String>[
'version',
]);
expect(testLogger.statusText, equals('v10.0.0\r\nv20.0.0\r\n30.0.0-dev.0.0\n'));
}, overrides: <Type, Generator>{
ProcessManager: () => MockProcessManager(),
Stdio: () => mockStdio,
FlutterVersion: () => mockVersion,
});
testUsingContext('Fetches upstream tags', () async {
final VersionCommand command = VersionCommand();
await createTestCommandRunner(command).run(<String>[
'version',
]);
verify(mockVersion.fetchTagsAndUpdate()).called(1);
}, overrides: <Type, Generator>{
ProcessManager: () => MockProcessManager(),
Stdio: () => mockStdio,
FlutterVersion: () => mockVersion,
});
});
}
class MockVersion extends Mock implements FlutterVersion {}
class MockTerminal extends Mock implements AnsiTerminal {}
class MockStdio extends Mock implements Stdio {}
class MockProcessManager extends Mock implements ProcessManager {
MockProcessManager({
this.failGitTag = false,
this.latestCommitFails = false,
});
String version = '';
final bool failGitTag;
final bool latestCommitFails;
@override
Future<ProcessResult> run(
List<dynamic> command, {
String workingDirectory,
Map<String, String> environment,
bool includeParentEnvironment = true,
bool runInShell = false,
Encoding stdoutEncoding = systemEncoding,
Encoding stderrEncoding = systemEncoding,
}) async {
if (command[0] == 'git' && command[1] == 'tag') {
if (failGitTag) {
return ProcessResult(0, 1, '', '');
}
return ProcessResult(0, 0, 'v10.0.0\r\nv20.0.0\r\n30.0.0-dev.0.0', '');
}
if (command[0] == 'git' && command[1] == 'checkout') {
version = (command[2] as String).replaceFirst('v', '');
}
return ProcessResult(0, 0, '', '');
}
@override
ProcessResult runSync(
List<dynamic> command, {
String workingDirectory,
Map<String, String> environment,
bool includeParentEnvironment = true,
bool runInShell = false,
Encoding stdoutEncoding = systemEncoding,
Encoding stderrEncoding = systemEncoding,
}) {
final String commandStr = command.join(' ');
if (commandStr == FlutterVersion.gitLog(<String>['-n', '1', '--pretty=format:%H']).join(' ')) {
return ProcessResult(0, 0, '000000000000000000000', '');
}
if (commandStr ==
'git describe --match *.*.* --first-parent --long --tags') {
if (version.isNotEmpty) {
return ProcessResult(0, 0, '$version-0-g00000000', '');
}
}
final List<String> commitDateCommand = <String>[
'-n', '1',
'--pretty=format:%ad',
'--date=iso',
];
if (latestCommitFails && commandStr == FlutterVersion.gitLog(commitDateCommand).join(' ')) {
return ProcessResult(0, -9, '', 'git failed');
}
return ProcessResult(0, 0, '', '');
}
@override
Future<Process> start(
List<dynamic> command, {
String workingDirectory,
Map<String, String> environment,
bool includeParentEnvironment = true,
bool runInShell = false,
ProcessStartMode mode = ProcessStartMode.normal,
}) {
final Completer<Process> completer = Completer<Process>();
completer.complete(MockProcess());
return completer.future;
}
}