version_test.dart 10.2 KB
Newer Older
Ian Hickson's avatar
Ian Hickson committed
1
// Copyright 2014 The Flutter Authors. All rights reserved.
2 3 4 5 6 7 8
// 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';

9
import 'package:flutter_tools/src/base/common.dart';
10
import 'package:flutter_tools/src/base/io.dart';
11
import 'package:flutter_tools/src/base/terminal.dart';
12 13
import 'package:flutter_tools/src/cache.dart';
import 'package:flutter_tools/src/commands/version.dart';
14
import 'package:flutter_tools/src/version.dart';
15 16
import 'package:mockito/mockito.dart';
import 'package:process/process.dart';
17
import 'package:flutter_tools/src/globals.dart' as globals;
18

19 20 21
import '../../src/common.dart';
import '../../src/context.dart';
import '../../src/mocks.dart' show MockProcess;
22 23 24

void main() {
  group('version', () {
25
    MockStdio mockStdio;
26
    MockVersion mockVersion;
27

28 29 30 31
    setUpAll(() {
      Cache.disableLocking();
    });

32 33
    setUp(() {
      mockStdio = MockStdio();
34
      mockVersion = MockVersion();
35 36 37 38
      when(mockStdio.stdinHasTerminal).thenReturn(false);
      when(mockStdio.hasTerminal).thenReturn(false);
    });

39 40
    testUsingContext('version ls', () async {
      final VersionCommand command = VersionCommand();
41 42 43 44
      await createTestCommandRunner(command).run(<String>[
        'version',
        '--no-pub',
      ]);
45
      expect(testLogger.statusText, equals('v10.0.0\r\nv20.0.0\r\n30.0.0-dev.0.0\r\n31.0.0-0.0.pre\n'));
46 47
    }, overrides: <Type, Generator>{
      ProcessManager: () => MockProcessManager(),
48
      Stdio: () => mockStdio,
49
      FlutterVersion: () => mockVersion,
50 51
    });

52 53
    testUsingContext('version switch prompt is accepted', () async {
      when(mockStdio.stdinHasTerminal).thenReturn(true);
54
      const String version = 'v10.0.0';
55
      final VersionCommand command = VersionCommand();
56 57 58 59 60
      when(globals.terminal.promptForCharInput(<String>['y', 'n'],
        logger: anyNamed('logger'),
        prompt: 'Are you sure you want to proceed?')
      ).thenAnswer((Invocation invocation) async => 'y');

61 62 63 64 65
      await createTestCommandRunner(command).run(<String>[
        'version',
        '--no-pub',
        version,
      ]);
66 67 68
      expect(testLogger.statusText, contains('Switching Flutter to version $version'));
    }, overrides: <Type, Generator>{
      ProcessManager: () => MockProcessManager(),
69 70
      Stdio: () => mockStdio,
      AnsiTerminal: () => MockTerminal(),
71
      FlutterVersion: () => mockVersion,
72 73
    });

74
    testUsingContext('old dev version switch prompt is accepted', () async {
75
      when(mockStdio.stdinHasTerminal).thenReturn(true);
76
      const String version = '30.0.0-dev.0.0';
77 78 79 80
      final VersionCommand command = VersionCommand();
      when(globals.terminal.promptForCharInput(<String>['y', 'n'],
        logger: anyNamed('logger'),
        prompt: 'Are you sure you want to proceed?')
81
      ).thenAnswer((Invocation invocation) async => 'y');
82 83 84 85 86 87

      await createTestCommandRunner(command).run(<String>[
        'version',
        '--no-pub',
        version,
      ]);
88
      expect(testLogger.statusText, contains('Switching Flutter to version $version'));
89 90 91 92
    }, overrides: <Type, Generator>{
      ProcessManager: () => MockProcessManager(),
      Stdio: () => mockStdio,
      AnsiTerminal: () => MockTerminal(),
93
      FlutterVersion: () => mockVersion,
94 95
    });

96 97 98
    testUsingContext('dev version switch prompt is accepted', () async {
      when(mockStdio.stdinHasTerminal).thenReturn(true);
      const String version = '31.0.0-0.0.pre';
99
      final VersionCommand command = VersionCommand();
100 101 102 103 104
      when(globals.terminal.promptForCharInput(<String>['y', 'n'],
        logger: anyNamed('logger'),
        prompt: 'Are you sure you want to proceed?')
      ).thenAnswer((Invocation invocation) async => 'y');

105 106 107 108 109
      await createTestCommandRunner(command).run(<String>[
        'version',
        '--no-pub',
        version,
      ]);
110
      expect(testLogger.statusText, contains('Switching Flutter to version $version'));
111
    }, overrides: <Type, Generator>{
112
      ProcessManager: () => MockProcessManager(),
113
      Stdio: () => mockStdio,
114
      AnsiTerminal: () => MockTerminal(),
115
      FlutterVersion: () => mockVersion,
116 117
    });

118 119 120 121 122 123 124 125 126 127 128 129 130 131 132
    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')));
133
    }, overrides: <Type, Generator>{
134
      ProcessManager: () => MockProcessManager(),
135
      Stdio: () => mockStdio,
136
      AnsiTerminal: () => MockTerminal(),
137
      FlutterVersion: () => mockVersion,
138 139 140 141 142
    });

    testUsingContext('switch to not supported version without force', () async {
      const String version = '1.1.5';
      final VersionCommand command = VersionCommand();
143 144 145 146 147
      await createTestCommandRunner(command).run(<String>[
        'version',
        '--no-pub',
        version,
      ]);
148 149 150
      expect(testLogger.errorText, contains('Version command is not supported in'));
    }, overrides: <Type, Generator>{
      ProcessManager: () => MockProcessManager(),
151
      Stdio: () => mockStdio,
152
      FlutterVersion: () => mockVersion,
153 154 155 156 157
    });

    testUsingContext('switch to not supported version with force', () async {
      const String version = '1.1.5';
      final VersionCommand command = VersionCommand();
158 159 160 161 162 163
      await createTestCommandRunner(command).run(<String>[
        'version',
        '--no-pub',
        '--force',
        version,
      ]);
164 165 166
      expect(testLogger.statusText, contains('Switching Flutter to version $version with force'));
    }, overrides: <Type, Generator>{
      ProcessManager: () => MockProcessManager(),
167
      Stdio: () => mockStdio,
168
      FlutterVersion: () => mockVersion,
169
    });
170

171 172 173
    testUsingContext('tool exit on confusing version', () async {
      const String version = 'master';
      final VersionCommand command = VersionCommand();
174 175 176 177 178 179
      expect(() async =>
        await createTestCommandRunner(command).run(<String>[
          'version',
          '--no-pub',
          version,
        ]),
Dan Field's avatar
Dan Field committed
180
        throwsToolExit(),
181
      );
182 183
    }, overrides: <Type, Generator>{
      ProcessManager: () => MockProcessManager(),
184
      Stdio: () => mockStdio,
185
      FlutterVersion: () => mockVersion,
186 187
    });

188
    testUsingContext("exit tool if can't get the tags", () async {
189 190 191 192
      final VersionCommand command = VersionCommand();
      try {
        await command.getTags();
        fail('ToolExit expected');
193
      } on Exception catch (e) {
Dan Field's avatar
Dan Field committed
194
        expect(e, isA<ToolExit>());
195 196 197
      }
    }, overrides: <Type, Generator>{
      ProcessManager: () => MockProcessManager(failGitTag: true),
198
      Stdio: () => mockStdio,
199
      FlutterVersion: () => mockVersion,
200
    });
201 202 203 204 205 206

    testUsingContext('Does not run pub when outside a project', () async {
      final VersionCommand command = VersionCommand();
      await createTestCommandRunner(command).run(<String>[
        'version',
      ]);
207
      expect(testLogger.statusText, equals('v10.0.0\r\nv20.0.0\r\n30.0.0-dev.0.0\r\n31.0.0-0.0.pre\n'));
208 209 210
    }, overrides: <Type, Generator>{
      ProcessManager: () => MockProcessManager(),
      Stdio: () => mockStdio,
211 212 213 214 215 216 217 218 219 220 221 222 223
      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,
224
    });
225 226 227
  });
}

228
class MockVersion extends Mock implements FlutterVersion {}
229 230
class MockTerminal extends Mock implements AnsiTerminal {}
class MockStdio extends Mock implements Stdio {}
231
class MockProcessManager extends Mock implements ProcessManager {
232 233 234 235
  MockProcessManager({
    this.failGitTag = false,
    this.latestCommitFails = false,
  });
236

237 238
  String version = '';

239 240
  final bool failGitTag;
  final bool latestCommitFails;
241

242 243 244 245 246 247 248 249 250 251 252
  @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') {
253 254 255
      if (failGitTag) {
        return ProcessResult(0, 1, '', '');
      }
256
      return ProcessResult(0, 0, 'v10.0.0\r\nv20.0.0\r\n30.0.0-dev.0.0\r\n31.0.0-0.0.pre', '');
257 258
    }
    if (command[0] == 'git' && command[1] == 'checkout') {
259
      version = (command[2] as String).replaceFirst(RegExp('^v'), '');
260
    }
261

262 263 264 265 266 267 268 269 270 271 272 273 274 275
    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(' ');
276
    if (commandStr == FlutterVersion.gitLog(<String>['-n', '1', '--pretty=format:%H']).join(' ')) {
277 278 279
      return ProcessResult(0, 0, '000000000000000000000', '');
    }
    if (commandStr ==
280
        'git describe --match *.*.*-*.*.pre --first-parent --long --tags') {
281 282 283 284 285 286 287 288
      if (version.isNotEmpty) {
        return ProcessResult(0, 0, '$version-0-g00000000', '');
      }
    }
    return ProcessResult(0, 0, '', '');
  }

  @override
289 290 291 292 293 294 295 296
  Future<Process> start(
    List<dynamic> command, {
    String workingDirectory,
    Map<String, String> environment,
    bool includeParentEnvironment = true,
    bool runInShell = false,
    ProcessStartMode mode = ProcessStartMode.normal,
  }) {
297 298 299 300 301
    final Completer<Process> completer = Completer<Process>();
    completer.complete(MockProcess());
    return completer.future;
  }
}