// 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/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 '../../src/common.dart'; import '../../src/context.dart'; import '../../src/mocks.dart' show MockProcess; void main() { group('version', () { setUpAll(() { Cache.disableLocking(); }); 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\n' '')); }, overrides: <Type, Generator>{ ProcessManager: () => MockProcessManager(), }); testUsingContext('version switch', () async { const String version = '10.0.0'; final VersionCommand command = VersionCommand(); await createTestCommandRunner(command).run(<String>[ 'version', '--no-pub', version, ]); expect(testLogger.statusText, contains('Switching Flutter to version $version')); }, overrides: <Type, Generator>{ ProcessManager: () => MockProcessManager(), }); 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), }); 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), }); 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(), }); 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(), }); 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, ]), throwsA(isInstanceOf<ToolExit>()), ); }, overrides: <Type, Generator>{ ProcessManager: () => MockProcessManager(), }); testUsingContext('exit tool if can\'t get the tags', () async { final VersionCommand command = VersionCommand(); try { await command.getTags(); fail('ToolExit expected'); } catch(e) { expect(e, isInstanceOf<ToolExit>()); } }, overrides: <Type, Generator>{ ProcessManager: () => MockProcessManager(failGitTag: true), }); }); } 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', ''); } if (command[0] == 'git' && command[1] == 'checkout') { version = command[2] as String; } 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 v*.*.* --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; } }