version_test.dart 24.4 KB
Newer Older
Ian Hickson's avatar
Ian Hickson committed
1
// Copyright 2014 The Flutter Authors. All rights reserved.
2 3 4
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

5 6
// @dart = 2.8

7 8
import 'dart:convert';

9
import 'package:flutter_tools/src/base/logger.dart';
10
import 'package:flutter_tools/src/base/platform.dart';
11
import 'package:flutter_tools/src/base/process.dart';
12
import 'package:flutter_tools/src/base/time.dart';
13
import 'package:flutter_tools/src/cache.dart';
14
import 'package:flutter_tools/src/globals_null_migrated.dart' as globals;
15
import 'package:flutter_tools/src/version.dart';
16
import 'package:test/fake.dart';
17

18 19
import '../src/common.dart';
import '../src/context.dart';
20
import '../src/fake_process_manager.dart';
21

22
final SystemClock _testClock = SystemClock.fixed(DateTime(2015, 1, 1));
23 24
final DateTime _stampUpToDate = _testClock.ago(checkAgeConsideredUpToDate ~/ 2);
final DateTime _stampOutOfDate = _testClock.ago(checkAgeConsideredUpToDate * 2);
25 26

void main() {
27
  FakeCache cache;
28
  FakeProcessManager processManager;
29 30

  setUp(() {
31
    processManager = FakeProcessManager.empty();
32
    cache = FakeCache();
33
  });
34

35 36 37 38 39 40 41 42 43
  testUsingContext('Channel enum and string transform to each other', () {
    for (final Channel channel in Channel.values) {
      expect(getNameForChannel(channel), kOfficialChannels.toList()[channel.index]);
    }
    expect(kOfficialChannels.toList().map((String str) => getChannelForName(str)).toList(),
      Channel.values);
  });

  for (final String channel in kOfficialChannels) {
44
    DateTime getChannelUpToDateVersion() {
45
      return _testClock.ago(versionAgeConsideredUpToDate(channel) ~/ 2);
46
    }
47

48
    DateTime getChannelOutOfDateVersion() {
49
      return _testClock.ago(versionAgeConsideredUpToDate(channel) * 2);
50
    }
51

52 53 54
    group('$FlutterVersion for $channel', () {
      setUpAll(() {
        Cache.disableLocking();
55
        timeToPauseToLetUserReadTheMessage = Duration.zero;
56
      });
57

58
      testUsingContext('prints nothing when Flutter installation looks fresh', () async {
59 60 61 62 63 64
        processManager.addCommand(const FakeCommand(
          command: <String>['git', '-c', 'log.showSignature=false', 'log', '-n', '1', '--pretty=format:%H'],
          stdout: '1234abcd',
        ));

        processManager.addCommand(const FakeCommand(
65
          command: <String>['git', 'tag', '--points-at', '1234abcd'],
66 67 68
        ));

        processManager.addCommand(const FakeCommand(
69
          command: <String>['git', 'describe', '--match', '*.*.*', '--long', '--tags', '1234abcd'],
70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102
          stdout: '0.1.2-3-1234abcd',
        ));

        processManager.addCommand(FakeCommand(
          command: const <String>['git', 'rev-parse', '--abbrev-ref', '--symbolic', '@{u}'],
          stdout: channel,
        ));

        processManager.addCommand(FakeCommand(
          command: const <String>['git', '-c', 'log.showSignature=false', 'log', '-n', '1', '--pretty=format:%ad', '--date=iso'],
          stdout: getChannelUpToDateVersion().toString(),
        ));

        processManager.addCommand(const FakeCommand(
          command: <String>['git', 'remote'],
        ));

        processManager.addCommand(const FakeCommand(
          command: <String>['git', 'remote', 'add', '__flutter_version_check__', 'https://github.com/flutter/flutter.git'],
        ));

        processManager.addCommand(FakeCommand(
          command: <String>['git', 'fetch', '__flutter_version_check__', channel],
        ));

        processManager.addCommand(FakeCommand(
          command: <String>['git', '-c', 'log.showSignature=false', 'log', '__flutter_version_check__/$channel', '-n', '1', '--pretty=format:%ad', '--date=iso'],
          stdout: getChannelOutOfDateVersion().toString(),
        ));
        processManager.addCommand(const FakeCommand(
          command: <String>['git', 'remote'],
        ));

103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127
        processManager.addCommands(<FakeCommand>[
          const FakeCommand(
            command: <String>['git', '-c', 'log.showSignature=false', 'log', '-n', '1', '--pretty=format:%ar'],
            stdout: '1 second ago',
          ),
          FakeCommand(
            command: const <String>['git', '-c', 'log.showSignature=false', 'log', '-n', '1', '--pretty=format:%ad', '--date=iso'],
            stdout: getChannelUpToDateVersion().toString(),
          ),
          FakeCommand(
            command: const <String>['git', 'rev-parse', '--abbrev-ref', 'HEAD'],
            stdout: channel,
          ),
        ]);

        final FlutterVersion flutterVersion = globals.flutterVersion;
        await flutterVersion.checkFlutterVersionFreshness();
        expect(flutterVersion.channel, channel);
        expect(flutterVersion.frameworkRevision, '1234abcd');
        expect(flutterVersion.frameworkRevisionShort, '1234abcd');
        expect(flutterVersion.frameworkVersion, '0.0.0-unknown');
        expect(
          flutterVersion.toString(),
          'Flutter • channel $channel • unknown source\n'
          'Framework • revision 1234abcd (1 second ago) • ${getChannelUpToDateVersion()}\n'
128 129
          'Engine • revision abcdefg\n'
          'Tools • Dart 2.12.0',
130 131 132 133 134 135 136
        );
        expect(flutterVersion.frameworkAge, '1 second ago');
        expect(flutterVersion.getVersionString(), '$channel/1234abcd');
        expect(flutterVersion.getBranchName(), channel);
        expect(flutterVersion.getVersionString(redactUnknownBranches: true), '$channel/1234abcd');
        expect(flutterVersion.getBranchName(redactUnknownBranches: true), channel);

137
        _expectVersionMessage('', testLogger);
138
        expect(processManager.hasRemainingExpectations, isFalse);
139
      }, overrides: <Type, Generator>{
140
        FlutterVersion: () => FlutterVersion(clock: _testClock),
141
        ProcessManager: () => processManager,
142
        Cache: () => cache,
143 144
      });

145 146 147 148 149 150
      testWithoutContext('prints nothing when Flutter installation looks out-of-date but is actually up-to-date', () async {
        final FakeFlutterVersion flutterVersion = FakeFlutterVersion(channel);
        final BufferLogger logger = BufferLogger.test();
        final VersionCheckStamp stamp = VersionCheckStamp(
          lastTimeVersionWasChecked: _stampOutOfDate,
          lastKnownRemoteVersion: getChannelOutOfDateVersion(),
151
        );
152
        cache.versionStamp = json.encode(stamp);
153

154 155
        await checkVersionFreshness(
          flutterVersion,
156
          cache: cache,
157 158 159 160
          clock: _testClock,
          logger: logger,
          localFrameworkCommitDate: getChannelOutOfDateVersion(),
          latestFlutterCommitDate: getChannelOutOfDateVersion(),
161 162
        );

163
        _expectVersionMessage('', logger);
164 165
      });

166 167 168 169 170 171
      testWithoutContext('does not ping server when version stamp is up-to-date', () async {
        final FakeFlutterVersion flutterVersion = FakeFlutterVersion(channel);
        final BufferLogger logger = BufferLogger.test();
        final VersionCheckStamp stamp = VersionCheckStamp(
          lastTimeVersionWasChecked: _stampUpToDate,
          lastKnownRemoteVersion: getChannelUpToDateVersion(),
172
        );
173
        cache.versionStamp = json.encode(stamp);
174

175 176
        await checkVersionFreshness(
          flutterVersion,
177
          cache: cache,
178 179 180 181
          clock: _testClock,
          logger: logger,
          localFrameworkCommitDate: getChannelOutOfDateVersion(),
          latestFlutterCommitDate: getChannelUpToDateVersion(),
182
        );
183 184

        _expectVersionMessage(newVersionAvailableMessage(), logger);
185
        expect(cache.setVersionStamp, true);
186 187
      });

188 189 190 191 192 193 194
      testWithoutContext('does not print warning if printed recently', () async {
        final FakeFlutterVersion flutterVersion = FakeFlutterVersion(channel);
        final BufferLogger logger = BufferLogger.test();
        final VersionCheckStamp stamp = VersionCheckStamp(
          lastTimeVersionWasChecked: _stampUpToDate,
          lastKnownRemoteVersion: getChannelUpToDateVersion(),
          lastTimeWarningWasPrinted: _testClock.now(),
195
        );
196
        cache.versionStamp = json.encode(stamp);
197

198 199
        await checkVersionFreshness(
          flutterVersion,
200
          cache: cache,
201 202 203 204
          clock: _testClock,
          logger: logger,
          localFrameworkCommitDate: getChannelOutOfDateVersion(),
          latestFlutterCommitDate: getChannelUpToDateVersion(),
205 206
        );

207
        _expectVersionMessage('', logger);
208 209
      });

210 211 212
      testWithoutContext('pings server when version stamp is missing', () async {
        final FakeFlutterVersion flutterVersion = FakeFlutterVersion(channel);
        final BufferLogger logger = BufferLogger.test();
213
        cache.versionStamp = '{}';
214 215 216

        await checkVersionFreshness(
          flutterVersion,
217
          cache: cache,
218 219 220 221
          clock: _testClock,
          logger: logger,
          localFrameworkCommitDate: getChannelOutOfDateVersion(),
          latestFlutterCommitDate: getChannelUpToDateVersion(),
222 223
        );

224
        _expectVersionMessage(newVersionAvailableMessage(), logger);
225
        expect(cache.setVersionStamp, true);
226
      });
227

228 229 230 231
      testWithoutContext('pings server when version stamp is out-of-date', () async {
        final FakeFlutterVersion flutterVersion = FakeFlutterVersion(channel);
        final BufferLogger logger = BufferLogger.test();
        final VersionCheckStamp stamp = VersionCheckStamp(
232 233 234 235
          lastTimeVersionWasChecked: _stampOutOfDate,
          lastKnownRemoteVersion: _testClock.ago(const Duration(days: 2)),
        );
        cache.versionStamp = json.encode(stamp);
236 237 238

        await checkVersionFreshness(
          flutterVersion,
239
          cache: cache,
240 241 242 243 244
          clock: _testClock,
          logger: logger,
          localFrameworkCommitDate: getChannelOutOfDateVersion(),
          latestFlutterCommitDate: getChannelUpToDateVersion(),
        );
245

246
        _expectVersionMessage(newVersionAvailableMessage(), logger);
247 248
      });

249 250 251
      testWithoutContext('does not print warning when unable to connect to server if not out of date', () async {
        final FakeFlutterVersion flutterVersion = FakeFlutterVersion(channel);
        final BufferLogger logger = BufferLogger.test();
252
        cache.versionStamp = '{}';
253

254 255
        await checkVersionFreshness(
          flutterVersion,
256
          cache: cache,
257 258 259 260
          clock: _testClock,
          logger: logger,
          localFrameworkCommitDate: getChannelUpToDateVersion(),
          latestFlutterCommitDate: null, // Failed to get remote version
261 262
        );

263
        _expectVersionMessage('', logger);
264 265
      });

266 267 268
      testWithoutContext('prints warning when unable to connect to server if really out of date', () async {
        final FakeFlutterVersion flutterVersion = FakeFlutterVersion(channel);
        final BufferLogger logger = BufferLogger.test();
269
        final VersionCheckStamp stamp = VersionCheckStamp(
270 271 272 273
          lastTimeVersionWasChecked: _stampOutOfDate,
          lastKnownRemoteVersion: _testClock.ago(const Duration(days: 2)),
        );
        cache.versionStamp = json.encode(stamp);
274 275 276

        await checkVersionFreshness(
          flutterVersion,
277
          cache: cache,
278 279 280 281
          clock: _testClock,
          logger: logger,
          localFrameworkCommitDate: getChannelOutOfDateVersion(),
          latestFlutterCommitDate: null, // Failed to get remote version
282 283
        );

284
        _expectVersionMessage(versionOutOfDateMessage(_testClock.now().difference(getChannelOutOfDateVersion())), logger);
285 286
      });

287 288 289 290 291 292 293 294
      group('$VersionCheckStamp for $channel', () {
        void _expectDefault(VersionCheckStamp stamp) {
          expect(stamp.lastKnownRemoteVersion, isNull);
          expect(stamp.lastTimeVersionWasChecked, isNull);
          expect(stamp.lastTimeWarningWasPrinted, isNull);
        }

        testWithoutContext('loads blank when stamp file missing', () async {
295
          cache.versionStamp = null;
296

297
          _expectDefault(await VersionCheckStamp.load(cache, BufferLogger.test()));
298 299 300
        });

        testWithoutContext('loads blank when stamp file is malformed JSON', () async {
301
          cache.versionStamp = '<';
302

303
          _expectDefault(await VersionCheckStamp.load(cache, BufferLogger.test()));
304 305 306
        });

        testWithoutContext('loads blank when stamp file is well-formed but invalid JSON', () async {
307
          cache.versionStamp = '[]';
308

309
          _expectDefault(await VersionCheckStamp.load(cache, BufferLogger.test()));
310 311 312 313 314 315 316 317 318 319
        });

        testWithoutContext('loads valid JSON', () async {
          final String value = '''
        {
          "lastKnownRemoteVersion": "${_testClock.ago(const Duration(days: 1))}",
          "lastTimeVersionWasChecked": "${_testClock.ago(const Duration(days: 2))}",
          "lastTimeWarningWasPrinted": "${_testClock.now()}"
        }
        ''';
320
          cache.versionStamp = value;
321

322
          final VersionCheckStamp stamp = await VersionCheckStamp.load(cache, BufferLogger.test());
323 324 325 326 327

          expect(stamp.lastKnownRemoteVersion, _testClock.ago(const Duration(days: 1)));
          expect(stamp.lastTimeVersionWasChecked, _testClock.ago(const Duration(days: 2)));
          expect(stamp.lastTimeWarningWasPrinted, _testClock.now());
        });
328
      });
329
    });
330
  }
331

332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364
  testUsingContext('version handles unknown branch', () async {
    processManager.addCommands(<FakeCommand>[
      const FakeCommand(
        command: <String>['git', '-c', 'log.showSignature=false', 'log', '-n', '1', '--pretty=format:%H'],
        stdout: '1234abcd',
      ),
      const FakeCommand(
        command: <String>['git', 'tag', '--points-at', '1234abcd'],
      ),
      const FakeCommand(
        command: <String>['git', 'describe', '--match', '*.*.*', '--long', '--tags', '1234abcd'],
        stdout: '0.1.2-3-1234abcd',
      ),
      const FakeCommand(
        command: <String>['git', 'rev-parse', '--abbrev-ref', '--symbolic', '@{u}'],
        stdout: 'feature-branch',
      ),
      const FakeCommand(
        command: <String>['git', 'rev-parse', '--abbrev-ref', 'HEAD'],
        stdout: 'feature-branch',
      ),
    ]);

    final FlutterVersion flutterVersion = globals.flutterVersion;
    expect(flutterVersion.channel, 'feature-branch');
    expect(flutterVersion.getVersionString(), 'feature-branch/1234abcd');
    expect(flutterVersion.getBranchName(), 'feature-branch');
    expect(flutterVersion.getVersionString(redactUnknownBranches: true), '[user-branch]/1234abcd');
    expect(flutterVersion.getBranchName(redactUnknownBranches: true), '[user-branch]');
    expect(processManager.hasRemainingExpectations, isFalse);
  }, overrides: <Type, Generator>{
    FlutterVersion: () => FlutterVersion(clock: _testClock),
    ProcessManager: () => processManager,
365
    Cache: () => cache,
366 367
  });

368 369
  testUsingContext('GitTagVersion', () {
    const String hash = 'abcdef';
370 371
    GitTagVersion gitTagVersion;

372 373 374 375
    // Master channel
    gitTagVersion = GitTagVersion.parse('1.2.3-4.5.pre-13-g$hash');
    expect(gitTagVersion.frameworkVersionFor(hash), '1.2.3-5.0.pre.13');
    expect(gitTagVersion.gitTag, '1.2.3-4.5.pre');
376 377 378
    expect(gitTagVersion.devVersion, 4);
    expect(gitTagVersion.devPatch, 5);

379 380 381 382 383 384 385 386 387 388 389 390
    // Stable channel
    gitTagVersion = GitTagVersion.parse('1.2.3');
    expect(gitTagVersion.frameworkVersionFor(hash), '1.2.3');
    expect(gitTagVersion.x, 1);
    expect(gitTagVersion.y, 2);
    expect(gitTagVersion.z, 3);
    expect(gitTagVersion.devVersion, null);
    expect(gitTagVersion.devPatch, null);

    // Dev channel
    gitTagVersion = GitTagVersion.parse('1.2.3-4.5.pre');
    expect(gitTagVersion.frameworkVersionFor(hash), '1.2.3-4.5.pre');
391 392 393 394 395
    expect(gitTagVersion.gitTag, '1.2.3-4.5.pre');
    expect(gitTagVersion.devVersion, 4);
    expect(gitTagVersion.devPatch, 5);

    gitTagVersion = GitTagVersion.parse('1.2.3-13-g$hash');
396
    expect(gitTagVersion.frameworkVersionFor(hash), '1.2.4-0.0.pre.13');
397
    expect(gitTagVersion.gitTag, '1.2.3');
398 399 400
    expect(gitTagVersion.devVersion, null);
    expect(gitTagVersion.devPatch, null);

401 402 403 404
    // new tag release format, dev channel
    gitTagVersion = GitTagVersion.parse('1.2.3-4.5.pre-0-g$hash');
    expect(gitTagVersion.frameworkVersionFor(hash), '1.2.3-4.5.pre');
    expect(gitTagVersion.gitTag, '1.2.3-4.5.pre');
405 406 407
    expect(gitTagVersion.devVersion, 4);
    expect(gitTagVersion.devPatch, 5);

408
    // new tag release format, stable channel
409
    gitTagVersion = GitTagVersion.parse('1.2.3-13-g$hash');
410
    expect(gitTagVersion.frameworkVersionFor(hash), '1.2.4-0.0.pre.13');
411
    expect(gitTagVersion.gitTag, '1.2.3');
412 413 414
    expect(gitTagVersion.devVersion, null);
    expect(gitTagVersion.devPatch, null);

415
    expect(GitTagVersion.parse('98.76.54-32-g$hash').frameworkVersionFor(hash), '98.76.55-0.0.pre.32');
416
    expect(GitTagVersion.parse('10.20.30-0-g$hash').frameworkVersionFor(hash), '10.20.30');
417
    expect(testLogger.traceText, '');
418
    expect(GitTagVersion.parse('v1.2.3+hotfix.1-4-g$hash').frameworkVersionFor(hash), '0.0.0-unknown');
419
    expect(GitTagVersion.parse('x1.2.3-4-g$hash').frameworkVersionFor(hash), '0.0.0-unknown');
420
    expect(GitTagVersion.parse('1.0.0-unknown-0-g$hash').frameworkVersionFor(hash), '0.0.0-unknown');
421
    expect(GitTagVersion.parse('beta-1-g$hash').frameworkVersionFor(hash), '0.0.0-unknown');
422
    expect(GitTagVersion.parse('1.2.3-4-gx$hash').frameworkVersionFor(hash), '0.0.0-unknown');
423 424
    expect(testLogger.statusText, '');
    expect(testLogger.errorText, '');
425 426
    expect(
      testLogger.traceText,
427
      'Could not interpret results of "git describe": v1.2.3+hotfix.1-4-gabcdef\n'
428
      'Could not interpret results of "git describe": x1.2.3-4-gabcdef\n'
429
      'Could not interpret results of "git describe": 1.0.0-unknown-0-gabcdef\n'
430
      'Could not interpret results of "git describe": beta-1-gabcdef\n'
431
      'Could not interpret results of "git describe": 1.2.3-4-gxabcdef\n',
432 433
    );
  });
434

435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452
  testUsingContext('determine reports correct stable version if HEAD is at a tag', () {
    const String stableTag = '1.2.3';
    final FakeProcessManager fakeProcessManager = FakeProcessManager.list(
      <FakeCommand>[
        const FakeCommand(
          command: <String>['git', 'tag', '--points-at', 'HEAD'],
          stdout: stableTag,
        ),
      ],
    );
    final ProcessUtils processUtils = ProcessUtils(
      processManager: fakeProcessManager,
      logger: BufferLogger.test(),
    );
    final GitTagVersion gitTagVersion = GitTagVersion.determine(processUtils, workingDirectory: '.');
    expect(gitTagVersion.frameworkVersionFor('abcd1234'), stableTag);
  });

453
  testUsingContext('determine favors stable tag over dev tag if both identify HEAD', () {
454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482
    const String stableTag = '1.2.3';
    final FakeProcessManager fakeProcessManager = FakeProcessManager.list(
      <FakeCommand>[
        const FakeCommand(
          command: <String>['git', 'tag', '--points-at', 'HEAD'],
          // This tests the unlikely edge case where a dev release made it to stable without any cherry picks
          stdout: '1.2.3-6.0.pre\n$stableTag',
        ),
      ],
    );
    final ProcessUtils processUtils = ProcessUtils(
      processManager: fakeProcessManager,
      logger: BufferLogger.test(),
    );
    final GitTagVersion gitTagVersion = GitTagVersion.determine(processUtils, workingDirectory: '.');
    expect(gitTagVersion.frameworkVersionFor('abcd1234'), stableTag);
  });

  testUsingContext('determine reports correct git describe version if HEAD is not at a tag', () {
    const String devTag = '1.2.3-2.0.pre';
    const String headRevision = 'abcd1234';
    const String commitsAhead = '12';
    final FakeProcessManager fakeProcessManager = FakeProcessManager.list(
      <FakeCommand>[
        const FakeCommand(
          command: <String>['git', 'tag', '--points-at', 'HEAD'],
          stdout: '', // no tag
        ),
        const FakeCommand(
483
          command: <String>['git', 'describe', '--match', '*.*.*', '--long', '--tags', 'HEAD'],
484 485 486 487 488 489 490 491 492 493 494
          stdout: '$devTag-$commitsAhead-g$headRevision',
        ),
      ],
    );
    final ProcessUtils processUtils = ProcessUtils(
      processManager: fakeProcessManager,
      logger: BufferLogger.test(),
    );
    final GitTagVersion gitTagVersion = GitTagVersion.determine(processUtils, workingDirectory: '.');
    // reported version should increment the number after the dash
    expect(gitTagVersion.frameworkVersionFor(headRevision), '1.2.3-3.0.pre.12');
495 496
  });

497
  testUsingContext('determine does not call fetch --tags', () {
498 499 500 501 502 503 504 505 506 507 508 509 510
    final FakeProcessManager fakeProcessManager = FakeProcessManager.list(<FakeCommand>[
      const FakeCommand(
        command: <String>['git', 'tag', '--points-at', 'HEAD'],
      ),
      const FakeCommand(
        command: <String>['git', 'describe', '--match', '*.*.*', '--long', '--tags', 'HEAD'],
        stdout: 'v0.1.2-3-1234abcd',
      ),
    ]);
    final ProcessUtils processUtils = ProcessUtils(
      processManager: fakeProcessManager,
      logger: BufferLogger.test(),
    );
511 512

    GitTagVersion.determine(processUtils, workingDirectory: '.');
513
    expect(fakeProcessManager, hasNoRemainingExpectations);
514 515
  });

516
  testUsingContext('determine does not fetch tags on dev/stable/beta', () {
517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533
    final FakeProcessManager fakeProcessManager = FakeProcessManager.list(<FakeCommand>[
      const FakeCommand(
        command: <String>['git', 'rev-parse', '--abbrev-ref', 'HEAD'],
        stdout: 'dev',
      ),
      const FakeCommand(
        command: <String>['git', 'tag', '--points-at', 'HEAD'],
      ),
      const FakeCommand(
        command: <String>['git', 'describe', '--match', '*.*.*', '--long', '--tags', 'HEAD'],
        stdout: 'v0.1.2-3-1234abcd',
      ),
    ]);
    final ProcessUtils processUtils = ProcessUtils(
      processManager: fakeProcessManager,
      logger: BufferLogger.test(),
    );
534 535

    GitTagVersion.determine(processUtils, workingDirectory: '.', fetchTags: true);
536
    expect(fakeProcessManager, hasNoRemainingExpectations);
537 538 539
  });

  testUsingContext('determine calls fetch --tags on master', () {
540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559
    final FakeProcessManager fakeProcessManager = FakeProcessManager.list(<FakeCommand>[
      const FakeCommand(
        command: <String>['git', 'rev-parse', '--abbrev-ref', 'HEAD'],
        stdout: 'master',
      ),
      const FakeCommand(
        command: <String>['git', 'fetch', 'https://github.com/flutter/flutter.git', '--tags', '-f'],
      ),
      const FakeCommand(
        command: <String>['git', 'tag', '--points-at', 'HEAD'],
      ),
      const FakeCommand(
        command: <String>['git', 'describe', '--match', '*.*.*', '--long', '--tags', 'HEAD'],
        stdout: 'v0.1.2-3-1234abcd',
      ),
    ]);
    final ProcessUtils processUtils = ProcessUtils(
      processManager: fakeProcessManager,
      logger: BufferLogger.test(),
    );
560 561

    GitTagVersion.determine(processUtils, workingDirectory: '.', fetchTags: true);
562
    expect(fakeProcessManager, hasNoRemainingExpectations);
563
  });
564 565

  testUsingContext('determine uses overridden git url', () {
566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585
    final FakeProcessManager fakeProcessManager = FakeProcessManager.list(<FakeCommand>[
      const FakeCommand(
        command: <String>['git', 'rev-parse', '--abbrev-ref', 'HEAD'],
        stdout: 'master',
      ),
      const FakeCommand(
        command: <String>['git', 'fetch', 'https://githubmirror.com/flutter.git', '--tags', '-f'],
      ),
      const FakeCommand(
        command: <String>['git', 'tag', '--points-at', 'HEAD'],
      ),
      const FakeCommand(
        command: <String>['git', 'describe', '--match', '*.*.*', '--long', '--tags', 'HEAD'],
        stdout: 'v0.1.2-3-1234abcd',
      ),
    ]);
    final ProcessUtils processUtils = ProcessUtils(
      processManager: fakeProcessManager,
      logger: BufferLogger.test(),
    );
586 587

    GitTagVersion.determine(processUtils, workingDirectory: '.', fetchTags: true);
588
    expect(fakeProcessManager, hasNoRemainingExpectations);
589 590 591 592 593
  }, overrides: <Type, Generator>{
    Platform: () => FakePlatform(environment: <String, String>{
      'FLUTTER_GIT_URL': 'https://githubmirror.com/flutter.git',
    }),
  });
594 595
}

596 597 598
void _expectVersionMessage(String message, BufferLogger logger) {
  expect(logger.statusText.trim(), message.trim());
  logger.clear();
599 600
}

601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628
class FakeCache extends Fake implements Cache {
  String versionStamp;
  bool setVersionStamp = false;

  @override
  String get engineRevision => 'abcdefg';

  @override
  String get dartSdkVersion => '2.12.0';

  @override
  void checkLockAcquired() { }

  @override
  String getStampFor(String artifactName) {
    if (artifactName == VersionCheckStamp.flutterVersionCheckStampFile) {
      return versionStamp;
    }
    return null;
  }

  @override
  void setStampFor(String artifactName, String version) {
    if (artifactName == VersionCheckStamp.flutterVersionCheckStampFile) {
      setVersionStamp = true;
    }
  }
}
629

630 631
class FakeFlutterVersion extends Fake implements FlutterVersion {
  FakeFlutterVersion(this.channel);
632

633 634
  @override
  final String channel;
635
}