[flutter_tool] Update analytics policy, send event on disable (#43217)
This commit is contained in:
parent
f6eb129597
commit
372fe290e4
@ -215,9 +215,8 @@ Future<String> _doctorText() async {
|
||||
}
|
||||
|
||||
Future<int> _exit(int code) async {
|
||||
if (flutterUsage.isFirstRun) {
|
||||
flutterUsage.printWelcome();
|
||||
}
|
||||
// Prints the welcome message if needed.
|
||||
flutterUsage.printWelcome();
|
||||
|
||||
// Send any last analytics calls that are in progress without overly delaying
|
||||
// the tool's exit (we wait a maximum of 250ms).
|
||||
|
@ -5,11 +5,10 @@
|
||||
import '../convert.dart';
|
||||
import 'context.dart';
|
||||
import 'file_system.dart';
|
||||
import 'platform.dart';
|
||||
|
||||
class Config {
|
||||
Config([File configFile]) {
|
||||
_configFile = configFile ?? fs.file(fs.path.join(_userHomeDir(), '.flutter_settings'));
|
||||
_configFile = configFile ?? fs.file(fs.path.join(userHomePath(), '.flutter_settings'));
|
||||
if (_configFile.existsSync()) {
|
||||
_values = json.decode(_configFile.readAsStringSync());
|
||||
}
|
||||
@ -44,8 +43,3 @@ class Config {
|
||||
_configFile.writeAsStringSync(json);
|
||||
}
|
||||
}
|
||||
|
||||
String _userHomeDir() {
|
||||
final String envKey = platform.operatingSystem == 'windows' ? 'APPDATA' : 'HOME';
|
||||
return platform.environment[envKey] ?? '.';
|
||||
}
|
||||
|
@ -185,3 +185,11 @@ class FileNotFoundException implements IOException {
|
||||
@override
|
||||
String toString() => 'File not found: $path';
|
||||
}
|
||||
|
||||
/// Reads the process environment to find the current user's home directory.
|
||||
///
|
||||
/// If the searched environment variables are not set, '.' is returned instead.
|
||||
String userHomePath() {
|
||||
final String envKey = platform.operatingSystem == 'windows' ? 'APPDATA' : 'HOME';
|
||||
return platform.environment[envKey] ?? '.';
|
||||
}
|
||||
|
@ -117,6 +117,7 @@ class ConfigCommand extends FlutterCommand {
|
||||
if (argResults.wasParsed('analytics')) {
|
||||
final bool value = argResults['analytics'];
|
||||
flutterUsage.enabled = value;
|
||||
AnalyticsConfigEvent(enabled: value).send();
|
||||
printStatus('Analytics reporting ${value ? 'enabled' : 'disabled'}.');
|
||||
}
|
||||
|
||||
|
@ -15,12 +15,14 @@ import '../base/process.dart';
|
||||
import '../cache.dart';
|
||||
import '../dart/pub.dart';
|
||||
import '../globals.dart';
|
||||
import '../persistent_tool_state.dart';
|
||||
import '../runner/flutter_command.dart';
|
||||
import '../version.dart';
|
||||
import 'channel.dart';
|
||||
|
||||
class UpgradeCommand extends FlutterCommand {
|
||||
UpgradeCommand() {
|
||||
UpgradeCommand([UpgradeCommandRunner commandRunner])
|
||||
: _commandRunner = commandRunner ?? UpgradeCommandRunner() {
|
||||
argParser
|
||||
..addFlag(
|
||||
'force',
|
||||
@ -32,10 +34,14 @@ class UpgradeCommand extends FlutterCommand {
|
||||
'continue',
|
||||
hide: true,
|
||||
negatable: false,
|
||||
help: 'For the second half of the upgrade flow requiring the new version of Flutter. Should not be invoked manually, but re-entrantly by the standard upgrade command.',
|
||||
help: 'For the second half of the upgrade flow requiring the new '
|
||||
'version of Flutter. Should not be invoked manually, but '
|
||||
're-entrantly by the standard upgrade command.',
|
||||
);
|
||||
}
|
||||
|
||||
final UpgradeCommandRunner _commandRunner;
|
||||
|
||||
@override
|
||||
final String name = 'upgrade';
|
||||
|
||||
@ -52,8 +58,7 @@ class UpgradeCommand extends FlutterCommand {
|
||||
|
||||
@override
|
||||
Future<FlutterCommandResult> runCommand() async {
|
||||
final UpgradeCommandRunner upgradeCommandRunner = UpgradeCommandRunner();
|
||||
await upgradeCommandRunner.runCommand(
|
||||
await _commandRunner.runCommand(
|
||||
argResults['force'],
|
||||
argResults['continue'],
|
||||
GitTagVersion.determine(),
|
||||
@ -141,9 +146,13 @@ class UpgradeCommandRunner {
|
||||
// This method should only be called if the upgrade command is invoked
|
||||
// re-entrantly with the `--continue` flag
|
||||
Future<void> runCommandSecondHalf(FlutterVersion flutterVersion) async {
|
||||
// Make sure the welcome message re-display is delayed until the end.
|
||||
persistentToolState.redisplayWelcomeMessage = false;
|
||||
await precacheArtifacts();
|
||||
await updatePackages(flutterVersion);
|
||||
await runDoctor();
|
||||
// Force the welcome message to re-display following the upgrade.
|
||||
persistentToolState.redisplayWelcomeMessage = true;
|
||||
}
|
||||
|
||||
Future<bool> hasUncomittedChanges() async {
|
||||
|
@ -48,6 +48,7 @@ import 'macos/macos_workflow.dart';
|
||||
import 'macos/xcode.dart';
|
||||
import 'macos/xcode_validator.dart';
|
||||
import 'mdns_discovery.dart';
|
||||
import 'persistent_tool_state.dart';
|
||||
import 'reporting/reporting.dart';
|
||||
import 'run_hot.dart';
|
||||
import 'version.dart';
|
||||
@ -106,9 +107,10 @@ Future<T> runInContext<T>(
|
||||
MacOSWorkflow: () => const MacOSWorkflow(),
|
||||
MDnsObservatoryDiscovery: () => MDnsObservatoryDiscovery(),
|
||||
OperatingSystemUtils: () => OperatingSystemUtils(),
|
||||
Pub: () => const Pub(),
|
||||
PersistentToolState: () => PersistentToolState(),
|
||||
ProcessInfo: () => ProcessInfo(),
|
||||
ProcessUtils: () => ProcessUtils(),
|
||||
Pub: () => const Pub(),
|
||||
Signals: () => Signals(),
|
||||
SimControl: () => SimControl(),
|
||||
Stdio: () => const Stdio(),
|
||||
@ -121,8 +123,8 @@ Future<T> runInContext<T>(
|
||||
WebWorkflow: () => const WebWorkflow(),
|
||||
WindowsWorkflow: () => const WindowsWorkflow(),
|
||||
Xcode: () => Xcode(),
|
||||
XcodeValidator: () => const XcodeValidator(),
|
||||
XcodeProjectInterpreter: () => XcodeProjectInterpreter(),
|
||||
XcodeValidator: () => const XcodeValidator(),
|
||||
},
|
||||
);
|
||||
}
|
||||
|
41
packages/flutter_tools/lib/src/persistent_tool_state.dart
Normal file
41
packages/flutter_tools/lib/src/persistent_tool_state.dart
Normal file
@ -0,0 +1,41 @@
|
||||
// Copyright 2019 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 'base/config.dart';
|
||||
import 'base/context.dart';
|
||||
import 'base/file_system.dart';
|
||||
|
||||
PersistentToolState get persistentToolState => PersistentToolState.instance;
|
||||
|
||||
/// A class that represents global (non-project-specific) internal state that
|
||||
/// must persist across tool invocations.
|
||||
abstract class PersistentToolState {
|
||||
factory PersistentToolState([File configFile]) =>
|
||||
_DefaultPersistentToolState(configFile);
|
||||
|
||||
static PersistentToolState get instance => context.get<PersistentToolState>();
|
||||
|
||||
/// Whether the welcome message should be redisplayed.
|
||||
///
|
||||
/// May give null if the value has not been set.
|
||||
bool redisplayWelcomeMessage;
|
||||
}
|
||||
|
||||
class _DefaultPersistentToolState implements PersistentToolState {
|
||||
_DefaultPersistentToolState([File configFile]) :
|
||||
_config = Config(configFile ?? fs.file(fs.path.join(userHomePath(), _kFileName)));
|
||||
|
||||
static const String _kFileName = '.flutter_tool_state';
|
||||
static const String _kRedisplayWelcomeMessage = 'redisplay-welcome-message';
|
||||
|
||||
final Config _config;
|
||||
|
||||
@override
|
||||
bool get redisplayWelcomeMessage => _config.getValue(_kRedisplayWelcomeMessage);
|
||||
|
||||
@override
|
||||
set redisplayWelcomeMessage(bool value) {
|
||||
_config.setValue(_kRedisplayWelcomeMessage, value);
|
||||
}
|
||||
}
|
@ -199,3 +199,15 @@ class CommandResultEvent extends UsageEvent {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// An event that reports on changes in the configuration of analytics.
|
||||
class AnalyticsConfigEvent extends UsageEvent {
|
||||
AnalyticsConfigEvent({
|
||||
/// Whether analytics reporting is being enabled (true) or disabled (false).
|
||||
@required bool enabled,
|
||||
}) : super(
|
||||
'analytics',
|
||||
'enabled',
|
||||
label: enabled ? 'true' : 'false',
|
||||
);
|
||||
}
|
||||
|
@ -21,6 +21,7 @@ import '../base/utils.dart';
|
||||
import '../doctor.dart';
|
||||
import '../features.dart';
|
||||
import '../globals.dart';
|
||||
import '../persistent_tool_state.dart';
|
||||
import '../runner/flutter_command.dart';
|
||||
import '../version.dart';
|
||||
|
||||
|
@ -323,35 +323,55 @@ class _DefaultUsage implements Usage {
|
||||
await _analytics.waitForLastPing(timeout: const Duration(milliseconds: 250));
|
||||
}
|
||||
|
||||
@override
|
||||
void printWelcome() {
|
||||
// This gets called if it's the first run by the selected command, if any,
|
||||
// and on exit, in case there was no command.
|
||||
if (_printedWelcome) {
|
||||
return;
|
||||
}
|
||||
_printedWelcome = true;
|
||||
|
||||
void _printWelcome() {
|
||||
printStatus('');
|
||||
printStatus('''
|
||||
╔════════════════════════════════════════════════════════════════════════════╗
|
||||
║ Welcome to Flutter! - https://flutter.dev ║
|
||||
║ ║
|
||||
║ The Flutter tool anonymously reports feature usage statistics and crash ║
|
||||
║ reports to Google in order to help Google contribute improvements to ║
|
||||
║ Flutter over time. ║
|
||||
║ The Flutter tool uses Google Analytics to anonymously report feature usage ║
|
||||
║ statistics and basic crash reports. This data is used to help improve ║
|
||||
║ Flutter tools over time. ║
|
||||
║ ║
|
||||
║ Flutter tool analytics are not sent on the very first run. To disable ║
|
||||
║ reporting, type 'flutter config --no-analytics'. To display the current ║
|
||||
║ setting, type 'flutter config'. If you opt out of analytics, an opt-out ║
|
||||
║ event will be sent, and then no further information will be sent by the ║
|
||||
║ Flutter tool. ║
|
||||
║ ║
|
||||
║ By downloading the Flutter SDK, you agree to the Google Terms of Service. ║
|
||||
║ Note: The Google Privacy Policy describes how data is handled in this ║
|
||||
║ service. ║
|
||||
║ ║
|
||||
║ Moreover, Flutter includes the Dart SDK, which may send usage metrics and ║
|
||||
║ crash reports to Google. ║
|
||||
║ ║
|
||||
║ Read about data we send with crash reports: ║
|
||||
║ https://github.com/flutter/flutter/wiki/Flutter-CLI-crash-reporting ║
|
||||
║ ║
|
||||
║ See Google's privacy policy: ║
|
||||
║ https://www.google.com/intl/en/policies/privacy/ ║
|
||||
║ ║
|
||||
║ Use "flutter config --no-analytics" to disable analytics and crash ║
|
||||
║ reporting. ║
|
||||
╚════════════════════════════════════════════════════════════════════════════╝
|
||||
''', emphasis: true);
|
||||
}
|
||||
|
||||
@override
|
||||
void printWelcome() {
|
||||
// Only print once per run.
|
||||
if (_printedWelcome) {
|
||||
return;
|
||||
}
|
||||
if (// Display the welcome message if this is the first run of the tool.
|
||||
isFirstRun ||
|
||||
// Display the welcome message if we are not on master, and if the
|
||||
// persistent tool state instructs that we should.
|
||||
(!FlutterVersion.instance.isMaster &&
|
||||
(persistentToolState.redisplayWelcomeMessage ?? true))) {
|
||||
_printWelcome();
|
||||
_printedWelcome = true;
|
||||
persistentToolState.redisplayWelcomeMessage = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// An Analytics mock that logs to file. Unimplemented methods goes to stdout.
|
||||
|
@ -447,9 +447,8 @@ abstract class FlutterCommand extends Command<void> {
|
||||
name: 'command',
|
||||
overrides: <Type, Generator>{FlutterCommand: () => this},
|
||||
body: () async {
|
||||
if (flutterUsage.isFirstRun) {
|
||||
flutterUsage.printWelcome();
|
||||
}
|
||||
// Prints the welcome message if needed.
|
||||
flutterUsage.printWelcome();
|
||||
final String commandPath = await usagePath;
|
||||
_registerSignalHandlers(commandPath, startTime);
|
||||
FlutterCommandResult commandResult;
|
||||
|
@ -14,6 +14,7 @@ import 'package:flutter_tools/src/base/logger.dart';
|
||||
import 'package:flutter_tools/src/build_info.dart';
|
||||
import 'package:flutter_tools/src/cache.dart';
|
||||
import 'package:flutter_tools/src/commands/config.dart';
|
||||
import 'package:flutter_tools/src/reporting/reporting.dart';
|
||||
import 'package:flutter_tools/src/version.dart';
|
||||
import 'package:mockito/mockito.dart';
|
||||
|
||||
@ -24,6 +25,7 @@ void main() {
|
||||
MockAndroidStudio mockAndroidStudio;
|
||||
MockAndroidSdk mockAndroidSdk;
|
||||
MockFlutterVersion mockFlutterVersion;
|
||||
MockUsage mockUsage;
|
||||
|
||||
setUpAll(() {
|
||||
Cache.disableLocking();
|
||||
@ -33,8 +35,31 @@ void main() {
|
||||
mockAndroidStudio = MockAndroidStudio();
|
||||
mockAndroidSdk = MockAndroidSdk();
|
||||
mockFlutterVersion = MockFlutterVersion();
|
||||
mockUsage = MockUsage();
|
||||
|
||||
when(mockUsage.isFirstRun).thenReturn(false);
|
||||
});
|
||||
|
||||
void verifyNoAnalytics() {
|
||||
verifyNever(mockUsage.sendCommand(
|
||||
any,
|
||||
parameters: anyNamed('parameters'),
|
||||
));
|
||||
verifyNever(mockUsage.sendEvent(
|
||||
any,
|
||||
any,
|
||||
label: anyNamed('label'),
|
||||
value: anyNamed('value'),
|
||||
parameters: anyNamed('parameters'),
|
||||
));
|
||||
verifyNever(mockUsage.sendTiming(
|
||||
any,
|
||||
any,
|
||||
any,
|
||||
label: anyNamed('label'),
|
||||
));
|
||||
}
|
||||
|
||||
group('config', () {
|
||||
testUsingContext('machine flag', () async {
|
||||
final BufferLogger logger = context.get<Logger>();
|
||||
@ -50,9 +75,11 @@ void main() {
|
||||
|
||||
expect(jsonObject.containsKey('android-sdk'), true);
|
||||
expect(jsonObject['android-sdk'], isNotNull);
|
||||
verifyNoAnalytics();
|
||||
}, overrides: <Type, Generator>{
|
||||
AndroidStudio: () => mockAndroidStudio,
|
||||
AndroidSdk: () => mockAndroidSdk,
|
||||
Usage: () => mockUsage,
|
||||
});
|
||||
|
||||
testUsingContext('Can set build-dir', () async {
|
||||
@ -65,6 +92,9 @@ void main() {
|
||||
]);
|
||||
|
||||
expect(getBuildDirectory(), 'foo');
|
||||
verifyNoAnalytics();
|
||||
}, overrides: <Type, Generator>{
|
||||
Usage: () => mockUsage,
|
||||
});
|
||||
|
||||
testUsingContext('throws error on absolute path to build-dir', () async {
|
||||
@ -75,6 +105,9 @@ void main() {
|
||||
'config',
|
||||
'--build-dir=/foo',
|
||||
]), throwsA(isInstanceOf<ToolExit>()));
|
||||
verifyNoAnalytics();
|
||||
}, overrides: <Type, Generator>{
|
||||
Usage: () => mockUsage,
|
||||
});
|
||||
|
||||
testUsingContext('allows setting and removing feature flags', () async {
|
||||
@ -115,9 +148,11 @@ void main() {
|
||||
expect(Config.instance.getValue('enable-linux-desktop'), false);
|
||||
expect(Config.instance.getValue('enable-windows-desktop'), false);
|
||||
expect(Config.instance.getValue('enable-macos-desktop'), false);
|
||||
verifyNoAnalytics();
|
||||
}, overrides: <Type, Generator>{
|
||||
AndroidStudio: () => mockAndroidStudio,
|
||||
AndroidSdk: () => mockAndroidSdk,
|
||||
Usage: () => mockUsage,
|
||||
});
|
||||
|
||||
testUsingContext('displays which config settings are available on stable', () async {
|
||||
@ -142,10 +177,86 @@ void main() {
|
||||
expect(logger.statusText, contains('enable-linux-desktop: true (Unavailable)'));
|
||||
expect(logger.statusText, contains('enable-windows-desktop: true (Unavailable)'));
|
||||
expect(logger.statusText, contains('enable-macos-desktop: true (Unavailable)'));
|
||||
verifyNoAnalytics();
|
||||
}, overrides: <Type, Generator>{
|
||||
AndroidStudio: () => mockAndroidStudio,
|
||||
AndroidSdk: () => mockAndroidSdk,
|
||||
FlutterVersion: () => mockFlutterVersion,
|
||||
Usage: () => mockUsage,
|
||||
});
|
||||
|
||||
testUsingContext('no-analytics flag flips usage flag and sends event', () async {
|
||||
final ConfigCommand configCommand = ConfigCommand();
|
||||
final CommandRunner<void> commandRunner = createTestCommandRunner(configCommand);
|
||||
|
||||
await commandRunner.run(<String>[
|
||||
'config',
|
||||
'--no-analytics',
|
||||
]);
|
||||
|
||||
expect(mockUsage.enabled, false);
|
||||
|
||||
// Verify that we only send the analytics disable event, and no other
|
||||
// info.
|
||||
verifyNever(mockUsage.sendCommand(
|
||||
any,
|
||||
parameters: anyNamed('parameters'),
|
||||
));
|
||||
verifyNever(mockUsage.sendTiming(
|
||||
any,
|
||||
any,
|
||||
any,
|
||||
label: anyNamed('label'),
|
||||
));
|
||||
|
||||
expect(verify(mockUsage.sendEvent(
|
||||
captureAny,
|
||||
captureAny,
|
||||
label: captureAnyNamed('label'),
|
||||
value: anyNamed('value'),
|
||||
parameters: anyNamed('parameters'),
|
||||
)).captured,
|
||||
<dynamic>['analytics', 'enabled', 'false'],
|
||||
);
|
||||
}, overrides: <Type, Generator>{
|
||||
Usage: () => mockUsage,
|
||||
});
|
||||
|
||||
testUsingContext('analytics flag flips usage flag and sends event', () async {
|
||||
final ConfigCommand configCommand = ConfigCommand();
|
||||
final CommandRunner<void> commandRunner = createTestCommandRunner(configCommand);
|
||||
|
||||
await commandRunner.run(<String>[
|
||||
'config',
|
||||
'--analytics',
|
||||
]);
|
||||
|
||||
expect(mockUsage.enabled, true);
|
||||
|
||||
// Verify that we only send the analytics disable event, and no other
|
||||
// info.
|
||||
verifyNever(mockUsage.sendCommand(
|
||||
any,
|
||||
parameters: anyNamed('parameters'),
|
||||
));
|
||||
verifyNever(mockUsage.sendTiming(
|
||||
any,
|
||||
any,
|
||||
any,
|
||||
label: anyNamed('label'),
|
||||
));
|
||||
|
||||
expect(verify(mockUsage.sendEvent(
|
||||
captureAny,
|
||||
captureAny,
|
||||
label: captureAnyNamed('label'),
|
||||
value: anyNamed('value'),
|
||||
parameters: anyNamed('parameters'),
|
||||
)).captured,
|
||||
<dynamic>['analytics', 'enabled', 'true'],
|
||||
);
|
||||
}, overrides: <Type, Generator>{
|
||||
Usage: () => mockUsage,
|
||||
});
|
||||
});
|
||||
}
|
||||
@ -161,3 +272,8 @@ class MockAndroidSdk extends Mock implements AndroidSdk {
|
||||
}
|
||||
|
||||
class MockFlutterVersion extends Mock implements FlutterVersion {}
|
||||
|
||||
class MockUsage extends Mock implements Usage {
|
||||
@override
|
||||
bool enabled = true;
|
||||
}
|
||||
|
@ -2,6 +2,7 @@
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
import 'package:flutter_tools/runner.dart' as runner;
|
||||
import 'package:flutter_tools/src/base/common.dart';
|
||||
import 'package:flutter_tools/src/base/file_system.dart';
|
||||
import 'package:flutter_tools/src/base/io.dart';
|
||||
@ -9,6 +10,7 @@ import 'package:flutter_tools/src/base/platform.dart';
|
||||
import 'package:flutter_tools/src/base/os.dart';
|
||||
import 'package:flutter_tools/src/cache.dart';
|
||||
import 'package:flutter_tools/src/commands/upgrade.dart';
|
||||
import 'package:flutter_tools/src/persistent_tool_state.dart';
|
||||
import 'package:flutter_tools/src/runner/flutter_command.dart';
|
||||
import 'package:flutter_tools/src/version.dart';
|
||||
import 'package:mockito/mockito.dart';
|
||||
@ -17,6 +19,7 @@ import 'package:process/process.dart';
|
||||
|
||||
import '../../src/common.dart';
|
||||
import '../../src/context.dart';
|
||||
import '../../src/fake_process_manager.dart';
|
||||
import '../../src/mocks.dart';
|
||||
|
||||
void main() {
|
||||
@ -184,6 +187,49 @@ void main() {
|
||||
ProcessManager: () => processManager,
|
||||
Platform: () => fakePlatform,
|
||||
});
|
||||
|
||||
group('full command', () {
|
||||
final FakeProcessManager fakeProcessManager = FakeProcessManager.list(<FakeCommand>[
|
||||
const FakeCommand(command: <String>[
|
||||
'git', 'describe', '--match', 'v*.*.*', '--first-parent', '--long', '--tags',
|
||||
]),
|
||||
]);
|
||||
|
||||
Directory tempDir;
|
||||
File flutterToolState;
|
||||
|
||||
FlutterVersion mockFlutterVersion;
|
||||
|
||||
setUp(() {
|
||||
Cache.disableLocking();
|
||||
tempDir = fs.systemTempDirectory.createTempSync('flutter_upgrade_test.');
|
||||
flutterToolState = tempDir.childFile('.flutter_tool_state');
|
||||
mockFlutterVersion = MockFlutterVersion(isStable: true);
|
||||
});
|
||||
|
||||
tearDown(() {
|
||||
Cache.enableLocking();
|
||||
tryToDelete(tempDir);
|
||||
});
|
||||
|
||||
testUsingContext('upgrade continue prints welcome message', () async {
|
||||
final UpgradeCommand upgradeCommand = UpgradeCommand(fakeCommandRunner);
|
||||
await runner.run(
|
||||
<String>[
|
||||
'upgrade',
|
||||
'--continue',
|
||||
],
|
||||
<FlutterCommand>[
|
||||
upgradeCommand,
|
||||
],
|
||||
);
|
||||
expect(testLogger.statusText, contains('Welcome to Flutter!'));
|
||||
}, overrides: <Type, Generator>{
|
||||
FlutterVersion: () => mockFlutterVersion,
|
||||
ProcessManager: () => fakeProcessManager,
|
||||
PersistentToolState: () => PersistentToolState(flutterToolState),
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
group('matchesGitLine', () {
|
||||
@ -267,7 +313,6 @@ class FakeUpgradeCommandRunner extends UpgradeCommandRunner {
|
||||
Future<void> runDoctor() async {}
|
||||
}
|
||||
|
||||
class MockFlutterVersion extends Mock implements FlutterVersion {}
|
||||
class MockProcess extends Mock implements Process {}
|
||||
class MockProcessManager extends Mock implements ProcessManager {}
|
||||
class FakeProcessResult implements ProcessResult {
|
||||
|
@ -0,0 +1,31 @@
|
||||
// Copyright 2019 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 'package:flutter_tools/src/base/file_system.dart';
|
||||
import 'package:flutter_tools/src/persistent_tool_state.dart';
|
||||
|
||||
import '../src/common.dart';
|
||||
import '../src/testbed.dart';
|
||||
|
||||
void main() {
|
||||
Testbed testbed;
|
||||
|
||||
setUp(() {
|
||||
testbed = Testbed();
|
||||
});
|
||||
|
||||
test('state can be set and persists', () => testbed.run(() {
|
||||
final File stateFile = fs.file('.flutter_tool_state');
|
||||
final PersistentToolState state1 = PersistentToolState(stateFile);
|
||||
expect(state1.redisplayWelcomeMessage, null);
|
||||
state1.redisplayWelcomeMessage = true;
|
||||
expect(stateFile.existsSync(), true);
|
||||
expect(state1.redisplayWelcomeMessage, true);
|
||||
state1.redisplayWelcomeMessage = false;
|
||||
expect(state1.redisplayWelcomeMessage, false);
|
||||
|
||||
final PersistentToolState state2 = PersistentToolState(stateFile);
|
||||
expect(state2.redisplayWelcomeMessage, false);
|
||||
}));
|
||||
}
|
@ -23,6 +23,7 @@ import 'package:flutter_tools/src/doctor.dart';
|
||||
import 'package:flutter_tools/src/ios/plist_parser.dart';
|
||||
import 'package:flutter_tools/src/ios/simulators.dart';
|
||||
import 'package:flutter_tools/src/ios/xcodeproj.dart';
|
||||
import 'package:flutter_tools/src/persistent_tool_state.dart';
|
||||
import 'package:flutter_tools/src/project.dart';
|
||||
import 'package:flutter_tools/src/reporting/reporting.dart';
|
||||
import 'package:flutter_tools/src/version.dart';
|
||||
@ -71,12 +72,18 @@ void testUsingContext(
|
||||
}
|
||||
});
|
||||
Config buildConfig(FileSystem fs) {
|
||||
configDir = fs.systemTempDirectory.createTempSync('flutter_config_dir_test.');
|
||||
configDir ??= fs.systemTempDirectory.createTempSync('flutter_config_dir_test.');
|
||||
final File settingsFile = fs.file(
|
||||
fs.path.join(configDir.path, '.flutter_settings')
|
||||
);
|
||||
return Config(settingsFile);
|
||||
}
|
||||
PersistentToolState buildPersistentToolState(FileSystem fs) {
|
||||
configDir ??= fs.systemTempDirectory.createTempSync('flutter_config_dir_test.');
|
||||
final File toolStateFile = fs.file(
|
||||
fs.path.join(configDir.path, '.flutter_tool_state'));
|
||||
return PersistentToolState(toolStateFile);
|
||||
}
|
||||
|
||||
test(description, () async {
|
||||
await runInContext<dynamic>(() {
|
||||
@ -96,6 +103,7 @@ void testUsingContext(
|
||||
OutputPreferences: () => OutputPreferences.test(),
|
||||
Logger: () => BufferLogger(),
|
||||
OperatingSystemUtils: () => FakeOperatingSystemUtils(),
|
||||
PersistentToolState: () => buildPersistentToolState(fs),
|
||||
SimControl: () => MockSimControl(),
|
||||
Usage: () => FakeUsage(),
|
||||
XcodeProjectInterpreter: () => FakeXcodeProjectInterpreter(),
|
||||
|
@ -64,7 +64,7 @@ final Map<Type, Generator> _testbedDefaults = <Type, Generator>{
|
||||
/// });
|
||||
/// })
|
||||
///
|
||||
/// test('Can delete a file', () => testBed.run(() {
|
||||
/// test('Can delete a file', () => testbed.run(() {
|
||||
/// expect(fs.file('foo').existsSync(), true);
|
||||
/// fs.file('foo').deleteSync();
|
||||
/// expect(fs.file('foo').existsSync(), false);
|
||||
|
Loading…
x
Reference in New Issue
Block a user