mirror of
https://github.com/flutter/flutter.git
synced 2025-06-03 00:51:18 +00:00

Mainly, this adds documentation to members that were previously lacking documentation. It also adds a big block of documentation about improving performance of widgets. This also removes some references to package:collection and adds global setEquals and listEquals methods in foundation that we can use. (setEquals in particular should be much faster than the package:collection equivalent, though both should be faster as they avoid allocating new objects.) All remaining references now qualify the import so we know what our remaining dependencies are. Also lots of code reordering in Flutter driver to make the code consistent and apply the style guide more thoroughly.
326 lines
12 KiB
Dart
326 lines
12 KiB
Dart
// Copyright 2017 The Chromium 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:convert';
|
|
|
|
import 'package:collection/collection.dart' show ListEquality;
|
|
import 'package:mockito/mockito.dart';
|
|
import 'package:process/process.dart';
|
|
import 'package:quiver/time.dart';
|
|
import 'package:test/test.dart';
|
|
|
|
import 'package:flutter_tools/src/base/context.dart';
|
|
import 'package:flutter_tools/src/base/io.dart';
|
|
import 'package:flutter_tools/src/base/logger.dart';
|
|
import 'package:flutter_tools/src/cache.dart';
|
|
import 'package:flutter_tools/src/version.dart';
|
|
|
|
import 'src/context.dart';
|
|
|
|
const JsonEncoder _kPrettyJsonEncoder = const JsonEncoder.withIndent(' ');
|
|
final Clock _testClock = new Clock.fixed(new DateTime(2015, 1, 1));
|
|
final DateTime _upToDateVersion = _testClock.agoBy(FlutterVersion.kVersionAgeConsideredUpToDate ~/ 2);
|
|
final DateTime _outOfDateVersion = _testClock.agoBy(FlutterVersion.kVersionAgeConsideredUpToDate * 2);
|
|
final DateTime _stampUpToDate = _testClock.agoBy(FlutterVersion.kCheckAgeConsideredUpToDate ~/ 2);
|
|
final DateTime _stampOutOfDate = _testClock.agoBy(FlutterVersion.kCheckAgeConsideredUpToDate * 2);
|
|
|
|
void main() {
|
|
group('$FlutterVersion', () {
|
|
setUpAll(() {
|
|
Cache.disableLocking();
|
|
FlutterVersion.kPauseToLetUserReadTheMessage = Duration.ZERO;
|
|
});
|
|
|
|
testFlutterVersion('prints nothing when Flutter installation looks fresh', () async {
|
|
fakeData(localCommitDate: _upToDateVersion);
|
|
await FlutterVersion.instance.checkFlutterVersionFreshness();
|
|
_expectVersionMessage('');
|
|
});
|
|
|
|
testFlutterVersion('prints nothing when Flutter installation looks out-of-date by is actually up-to-date', () async {
|
|
final FlutterVersion version = FlutterVersion.instance;
|
|
|
|
fakeData(
|
|
localCommitDate: _outOfDateVersion,
|
|
stamp: new VersionCheckStamp(
|
|
lastTimeVersionWasChecked: _stampOutOfDate,
|
|
lastKnownRemoteVersion: _outOfDateVersion,
|
|
),
|
|
remoteCommitDate: _outOfDateVersion,
|
|
expectSetStamp: true,
|
|
expectServerPing: true,
|
|
);
|
|
|
|
await version.checkFlutterVersionFreshness();
|
|
_expectVersionMessage('');
|
|
});
|
|
|
|
testFlutterVersion('does not ping server when version stamp is up-to-date', () async {
|
|
final FlutterVersion version = FlutterVersion.instance;
|
|
|
|
fakeData(
|
|
localCommitDate: _outOfDateVersion,
|
|
stamp: new VersionCheckStamp(
|
|
lastTimeVersionWasChecked: _stampUpToDate,
|
|
lastKnownRemoteVersion: _upToDateVersion,
|
|
),
|
|
expectSetStamp: true,
|
|
);
|
|
|
|
await version.checkFlutterVersionFreshness();
|
|
_expectVersionMessage(FlutterVersion.versionOutOfDateMessage(_testClock.now().difference(_outOfDateVersion)));
|
|
});
|
|
|
|
testFlutterVersion('does not print warning if printed recently', () async {
|
|
final FlutterVersion version = FlutterVersion.instance;
|
|
|
|
fakeData(
|
|
localCommitDate: _outOfDateVersion,
|
|
stamp: new VersionCheckStamp(
|
|
lastTimeVersionWasChecked: _stampUpToDate,
|
|
lastKnownRemoteVersion: _upToDateVersion,
|
|
),
|
|
expectSetStamp: true,
|
|
);
|
|
|
|
await version.checkFlutterVersionFreshness();
|
|
_expectVersionMessage(FlutterVersion.versionOutOfDateMessage(_testClock.now().difference(_outOfDateVersion)));
|
|
expect((await VersionCheckStamp.load()).lastTimeWarningWasPrinted, _testClock.now());
|
|
|
|
await version.checkFlutterVersionFreshness();
|
|
_expectVersionMessage('');
|
|
});
|
|
|
|
testFlutterVersion('pings server when version stamp is missing then does not', () async {
|
|
final FlutterVersion version = FlutterVersion.instance;
|
|
|
|
fakeData(
|
|
localCommitDate: _outOfDateVersion,
|
|
remoteCommitDate: _upToDateVersion,
|
|
expectSetStamp: true,
|
|
expectServerPing: true,
|
|
);
|
|
|
|
await version.checkFlutterVersionFreshness();
|
|
_expectVersionMessage(FlutterVersion.versionOutOfDateMessage(_testClock.now().difference(_outOfDateVersion)));
|
|
|
|
// Immediate subsequent check is not expected to ping the server.
|
|
fakeData(
|
|
localCommitDate: _outOfDateVersion,
|
|
stamp: await VersionCheckStamp.load(),
|
|
);
|
|
await version.checkFlutterVersionFreshness();
|
|
_expectVersionMessage('');
|
|
});
|
|
|
|
testFlutterVersion('pings server when version stamp is out-of-date', () async {
|
|
final FlutterVersion version = FlutterVersion.instance;
|
|
|
|
fakeData(
|
|
localCommitDate: _outOfDateVersion,
|
|
stamp: new VersionCheckStamp(
|
|
lastTimeVersionWasChecked: _stampOutOfDate,
|
|
lastKnownRemoteVersion: _testClock.ago(days: 2),
|
|
),
|
|
remoteCommitDate: _upToDateVersion,
|
|
expectSetStamp: true,
|
|
expectServerPing: true,
|
|
);
|
|
|
|
await version.checkFlutterVersionFreshness();
|
|
_expectVersionMessage(FlutterVersion.versionOutOfDateMessage(_testClock.now().difference(_outOfDateVersion)));
|
|
});
|
|
|
|
testFlutterVersion('ignores network issues', () async {
|
|
final FlutterVersion version = FlutterVersion.instance;
|
|
|
|
fakeData(
|
|
localCommitDate: _outOfDateVersion,
|
|
errorOnFetch: true,
|
|
expectServerPing: true,
|
|
);
|
|
|
|
await version.checkFlutterVersionFreshness();
|
|
_expectVersionMessage('');
|
|
});
|
|
});
|
|
|
|
group('$VersionCheckStamp', () {
|
|
void _expectDefault(VersionCheckStamp stamp) {
|
|
expect(stamp.lastKnownRemoteVersion, isNull);
|
|
expect(stamp.lastTimeVersionWasChecked, isNull);
|
|
expect(stamp.lastTimeWarningWasPrinted, isNull);
|
|
}
|
|
|
|
testFlutterVersion('loads blank when stamp file missing', () async {
|
|
fakeData();
|
|
_expectDefault(await VersionCheckStamp.load());
|
|
});
|
|
|
|
testFlutterVersion('loads blank when stamp file is malformed JSON', () async {
|
|
fakeData(stampJson: '<');
|
|
_expectDefault(await VersionCheckStamp.load());
|
|
});
|
|
|
|
testFlutterVersion('loads blank when stamp file is well-formed but invalid JSON', () async {
|
|
fakeData(stampJson: '[]');
|
|
_expectDefault(await VersionCheckStamp.load());
|
|
});
|
|
|
|
testFlutterVersion('loads valid JSON', () async {
|
|
fakeData(stampJson: '''
|
|
{
|
|
"lastKnownRemoteVersion": "${_testClock.ago(days: 1)}",
|
|
"lastTimeVersionWasChecked": "${_testClock.ago(days: 2)}",
|
|
"lastTimeWarningWasPrinted": "${_testClock.now()}"
|
|
}
|
|
''');
|
|
|
|
final VersionCheckStamp stamp = await VersionCheckStamp.load();
|
|
expect(stamp.lastKnownRemoteVersion, _testClock.ago(days: 1));
|
|
expect(stamp.lastTimeVersionWasChecked, _testClock.ago(days: 2));
|
|
expect(stamp.lastTimeWarningWasPrinted, _testClock.now());
|
|
});
|
|
|
|
testFlutterVersion('stores version stamp', () async {
|
|
fakeData(expectSetStamp: true);
|
|
|
|
_expectDefault(await VersionCheckStamp.load());
|
|
|
|
final VersionCheckStamp stamp = new VersionCheckStamp(
|
|
lastKnownRemoteVersion: _testClock.ago(days: 1),
|
|
lastTimeVersionWasChecked: _testClock.ago(days: 2),
|
|
lastTimeWarningWasPrinted: _testClock.now(),
|
|
);
|
|
await stamp.store();
|
|
|
|
final VersionCheckStamp storedStamp = await VersionCheckStamp.load();
|
|
expect(storedStamp.lastKnownRemoteVersion, _testClock.ago(days: 1));
|
|
expect(storedStamp.lastTimeVersionWasChecked, _testClock.ago(days: 2));
|
|
expect(storedStamp.lastTimeWarningWasPrinted, _testClock.now());
|
|
});
|
|
|
|
testFlutterVersion('overwrites individual fields', () async {
|
|
fakeData(expectSetStamp: true);
|
|
|
|
_expectDefault(await VersionCheckStamp.load());
|
|
|
|
final VersionCheckStamp stamp = new VersionCheckStamp(
|
|
lastKnownRemoteVersion: _testClock.ago(days: 10),
|
|
lastTimeVersionWasChecked: _testClock.ago(days: 9),
|
|
lastTimeWarningWasPrinted: _testClock.ago(days: 8),
|
|
);
|
|
await stamp.store(
|
|
newKnownRemoteVersion: _testClock.ago(days: 1),
|
|
newTimeVersionWasChecked: _testClock.ago(days: 2),
|
|
newTimeWarningWasPrinted: _testClock.now(),
|
|
);
|
|
|
|
final VersionCheckStamp storedStamp = await VersionCheckStamp.load();
|
|
expect(storedStamp.lastKnownRemoteVersion, _testClock.ago(days: 1));
|
|
expect(storedStamp.lastTimeVersionWasChecked, _testClock.ago(days: 2));
|
|
expect(storedStamp.lastTimeWarningWasPrinted, _testClock.now());
|
|
});
|
|
});
|
|
}
|
|
|
|
void _expectVersionMessage(String message) {
|
|
final BufferLogger logger = context[Logger];
|
|
expect(logger.statusText.trim(), message.trim());
|
|
logger.clear();
|
|
}
|
|
|
|
void testFlutterVersion(String description, dynamic testMethod()) {
|
|
testUsingContext(
|
|
description,
|
|
testMethod,
|
|
overrides: <Type, Generator>{
|
|
FlutterVersion: () => new FlutterVersion(_testClock),
|
|
},
|
|
);
|
|
}
|
|
|
|
void fakeData({
|
|
DateTime localCommitDate,
|
|
DateTime remoteCommitDate,
|
|
VersionCheckStamp stamp,
|
|
String stampJson,
|
|
bool errorOnFetch: false,
|
|
bool expectSetStamp: false,
|
|
bool expectServerPing: false,
|
|
}) {
|
|
final MockProcessManager pm = new MockProcessManager();
|
|
context.setVariable(ProcessManager, pm);
|
|
|
|
final MockCache cache = new MockCache();
|
|
context.setVariable(Cache, cache);
|
|
|
|
ProcessResult success(String standardOutput) {
|
|
return new ProcessResult(1, 0, standardOutput, '');
|
|
}
|
|
|
|
ProcessResult failure(int exitCode) {
|
|
return new ProcessResult(1, exitCode, '', 'error');
|
|
}
|
|
|
|
when(cache.getStampFor(any)).thenAnswer((Invocation invocation) {
|
|
expect(invocation.positionalArguments.single, VersionCheckStamp.kFlutterVersionCheckStampFile);
|
|
|
|
if (stampJson != null)
|
|
return stampJson;
|
|
|
|
if (stamp != null)
|
|
return JSON.encode(stamp.toJson());
|
|
|
|
return null;
|
|
});
|
|
|
|
when(cache.setStampFor(any, any)).thenAnswer((Invocation invocation) {
|
|
expect(invocation.positionalArguments.first, VersionCheckStamp.kFlutterVersionCheckStampFile);
|
|
|
|
if (expectSetStamp) {
|
|
stamp = VersionCheckStamp.fromJson(JSON.decode(invocation.positionalArguments[1]));
|
|
return null;
|
|
}
|
|
|
|
throw new StateError('Unexpected call to Cache.setStampFor(${invocation.positionalArguments}, ${invocation.namedArguments})');
|
|
});
|
|
|
|
final Answering syncAnswer = (Invocation invocation) {
|
|
bool argsAre(String a1, [String a2, String a3, String a4, String a5, String a6, String a7, String a8]) {
|
|
const ListEquality<String> equality = const ListEquality<String>();
|
|
final List<String> args = invocation.positionalArguments.single;
|
|
final List<String> expectedArgs =
|
|
<String>[a1, a2, a3, a4, a5, a6, a7, a8]
|
|
.where((String arg) => arg != null)
|
|
.toList();
|
|
return equality.equals(args, expectedArgs);
|
|
}
|
|
|
|
if (argsAre('git', 'log', '-n', '1', '--pretty=format:%ad', '--date=iso')) {
|
|
return success(localCommitDate.toString());
|
|
} else if (argsAre('git', 'remote')) {
|
|
return success('');
|
|
} else if (argsAre('git', 'remote', 'add', '__flutter_version_check__', 'https://github.com/flutter/flutter.git')) {
|
|
return success('');
|
|
} else if (argsAre('git', 'fetch', '__flutter_version_check__', 'master')) {
|
|
if (!expectServerPing)
|
|
fail('Did not expect server ping');
|
|
return errorOnFetch ? failure(128) : success('');
|
|
} else if (remoteCommitDate != null && argsAre('git', 'log', '__flutter_version_check__/master', '-n', '1', '--pretty=format:%ad', '--date=iso')) {
|
|
return success(remoteCommitDate.toString());
|
|
}
|
|
|
|
throw new StateError('Unexpected call to ProcessManager.run(${invocation.positionalArguments}, ${invocation.namedArguments})');
|
|
};
|
|
|
|
when(pm.runSync(any, workingDirectory: any)).thenAnswer(syncAnswer);
|
|
when(pm.run(any, workingDirectory: any)).thenAnswer((Invocation invocation) async {
|
|
return syncAnswer(invocation);
|
|
});
|
|
}
|
|
|
|
class MockProcessManager extends Mock implements ProcessManager {}
|
|
class MockCache extends Mock implements Cache {}
|