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

import 'dart:convert';

7
import 'package:args/command_runner.dart';
8 9
import 'package:flutter_tools/src/android/android_sdk.dart';
import 'package:flutter_tools/src/android/android_studio.dart';
10
import 'package:flutter_tools/src/base/file_system.dart';
11
import 'package:flutter_tools/src/build_info.dart';
12
import 'package:flutter_tools/src/cache.dart';
13
import 'package:flutter_tools/src/commands/config.dart';
14
import 'package:flutter_tools/src/globals.dart' as globals;
15
import 'package:flutter_tools/src/reporting/reporting.dart';
16
import 'package:flutter_tools/src/version.dart';
17
import 'package:test/fake.dart';
18

19 20
import '../../src/common.dart';
import '../../src/context.dart';
21
import '../../src/test_flutter_command_runner.dart';
22 23

void main() {
24 25 26 27
  late FakeAndroidStudio fakeAndroidStudio;
  late FakeAndroidSdk fakeAndroidSdk;
  late FakeFlutterVersion fakeFlutterVersion;
  late TestUsage testUsage;
28 29 30 31

  setUpAll(() {
    Cache.disableLocking();
  });
32 33

  setUp(() {
34 35 36
    fakeAndroidStudio = FakeAndroidStudio();
    fakeAndroidSdk = FakeAndroidSdk();
    fakeFlutterVersion = FakeFlutterVersion();
37
    testUsage = TestUsage();
38 39
  });

40
  void verifyNoAnalytics() {
41 42 43
    expect(testUsage.commands, isEmpty);
    expect(testUsage.events, isEmpty);
    expect(testUsage.timings, isEmpty);
44 45
  }

46 47
  group('config', () {
    testUsingContext('machine flag', () async {
48
      final ConfigCommand command = ConfigCommand();
49 50
      await command.handleMachine();

51 52
      expect(testLogger.statusText, isNotEmpty);
      final dynamic jsonObject = json.decode(testLogger.statusText);
53 54 55 56
      expect(jsonObject, const TypeMatcher<Map<String, dynamic>>());
      if (jsonObject is Map<String, dynamic>) {
        expect(jsonObject.containsKey('android-studio-dir'), true);
        expect(jsonObject['android-studio-dir'], isNotNull);
57

58 59 60
        expect(jsonObject.containsKey('android-sdk'), true);
        expect(jsonObject['android-sdk'], isNotNull);
      }
61
      verifyNoAnalytics();
62
    }, overrides: <Type, Generator>{
63 64
      AndroidStudio: () => fakeAndroidStudio,
      AndroidSdk: () => fakeAndroidSdk,
65
      Usage: () => testUsage,
66
    });
67

68 69 70 71 72 73
    testUsingContext('Can set build-dir', () async {
      final ConfigCommand configCommand = ConfigCommand();
      final CommandRunner<void> commandRunner = createTestCommandRunner(configCommand);

      await commandRunner.run(<String>[
        'config',
74
        '--build-dir=foo',
75 76 77
      ]);

      expect(getBuildDirectory(), 'foo');
78 79
      verifyNoAnalytics();
    }, overrides: <Type, Generator>{
80
      Usage: () => testUsage,
81 82 83 84 85 86 87 88
    });

    testUsingContext('throws error on absolute path to build-dir', () async {
      final ConfigCommand configCommand = ConfigCommand();
      final CommandRunner<void> commandRunner = createTestCommandRunner(configCommand);

      expect(() => commandRunner.run(<String>[
        'config',
89
        '--build-dir=/foo',
Dan Field's avatar
Dan Field committed
90
      ]), throwsToolExit());
91 92
      verifyNoAnalytics();
    }, overrides: <Type, Generator>{
93
      Usage: () => testUsage,
94 95
    });

96 97 98 99 100 101
    testUsingContext('allows setting and removing feature flags', () async {
      final ConfigCommand configCommand = ConfigCommand();
      final CommandRunner<void> commandRunner = createTestCommandRunner(configCommand);

      await commandRunner.run(<String>[
        'config',
102 103
        '--enable-android',
        '--enable-ios',
104 105 106
        '--enable-web',
        '--enable-linux-desktop',
        '--enable-windows-desktop',
107
        '--enable-macos-desktop',
108 109
      ]);

110 111
      expect(globals.config.getValue('enable-android'), true);
      expect(globals.config.getValue('enable-ios'), true);
112 113 114 115
      expect(globals.config.getValue('enable-web'), true);
      expect(globals.config.getValue('enable-linux-desktop'), true);
      expect(globals.config.getValue('enable-windows-desktop'), true);
      expect(globals.config.getValue('enable-macos-desktop'), true);
116 117 118 119 120

      await commandRunner.run(<String>[
        'config', '--clear-features',
      ]);

121 122
      expect(globals.config.getValue('enable-android'), null);
      expect(globals.config.getValue('enable-ios'), null);
123 124 125 126
      expect(globals.config.getValue('enable-web'), null);
      expect(globals.config.getValue('enable-linux-desktop'), null);
      expect(globals.config.getValue('enable-windows-desktop'), null);
      expect(globals.config.getValue('enable-macos-desktop'), null);
127 128 129

      await commandRunner.run(<String>[
        'config',
130 131
        '--no-enable-android',
        '--no-enable-ios',
132 133 134
        '--no-enable-web',
        '--no-enable-linux-desktop',
        '--no-enable-windows-desktop',
135
        '--no-enable-macos-desktop',
136 137
      ]);

138 139
      expect(globals.config.getValue('enable-android'), false);
      expect(globals.config.getValue('enable-ios'), false);
140 141 142 143
      expect(globals.config.getValue('enable-web'), false);
      expect(globals.config.getValue('enable-linux-desktop'), false);
      expect(globals.config.getValue('enable-windows-desktop'), false);
      expect(globals.config.getValue('enable-macos-desktop'), false);
144
      verifyNoAnalytics();
145
    }, overrides: <Type, Generator>{
146 147
      AndroidStudio: () => fakeAndroidStudio,
      AndroidSdk: () => fakeAndroidSdk,
148
      Usage: () => testUsage,
149 150
    });

151 152 153 154 155 156
    testUsingContext('warns the user to reload IDE', () async {
      final ConfigCommand configCommand = ConfigCommand();
      final CommandRunner<void> commandRunner = createTestCommandRunner(configCommand);

      await commandRunner.run(<String>[
        'config',
157
        '--enable-web',
158 159
      ]);

160 161 162 163
      expect(
        testLogger.statusText,
        containsIgnoringWhitespace('You may need to restart any open editors'),
      );
164
    }, overrides: <Type, Generator>{
165
      Usage: () => testUsage,
166 167
    });

168
    testUsingContext('displays which config settings are available on stable', () async {
169
      fakeFlutterVersion.channel = 'stable';
170 171 172 173 174 175 176 177
      final ConfigCommand configCommand = ConfigCommand();
      final CommandRunner<void> commandRunner = createTestCommandRunner(configCommand);

      await commandRunner.run(<String>[
        'config',
        '--enable-web',
        '--enable-linux-desktop',
        '--enable-windows-desktop',
178
        '--enable-macos-desktop',
179 180 181 182 183 184
      ]);

      await commandRunner.run(<String>[
        'config',
      ]);

185 186
      expect(
        testLogger.statusText,
187
        containsIgnoringWhitespace('enable-web: true'),
188 189 190
      );
      expect(
        testLogger.statusText,
191
        containsIgnoringWhitespace('enable-linux-desktop: true'),
192 193 194
      );
      expect(
        testLogger.statusText,
195
        containsIgnoringWhitespace('enable-windows-desktop: true'),
196 197 198
      );
      expect(
        testLogger.statusText,
199
        containsIgnoringWhitespace('enable-macos-desktop: true'),
200
      );
201
      verifyNoAnalytics();
202
    }, overrides: <Type, Generator>{
203 204 205
      AndroidStudio: () => fakeAndroidStudio,
      AndroidSdk: () => fakeAndroidSdk,
      FlutterVersion: () => fakeFlutterVersion,
206
      Usage: () => testUsage,
207 208 209 210 211 212
    });

    testUsingContext('no-analytics flag flips usage flag and sends event', () async {
      final ConfigCommand configCommand = ConfigCommand();
      final CommandRunner<void> commandRunner = createTestCommandRunner(configCommand);

213
      expect(testUsage.enabled, true);
214 215 216 217 218
      await commandRunner.run(<String>[
        'config',
        '--no-analytics',
      ]);

219
      expect(testUsage.enabled, false);
220

221
      // Verify that we flushed the analytics queue.
222
      expect(testUsage.ensureAnalyticsSentCalls, 1);
223

224 225
      // Verify that we only send the analytics disable event, and no other
      // info.
226 227 228 229 230
      expect(testUsage.events, equals(<TestUsageEvent>[
        const TestUsageEvent('analytics', 'enabled', label: 'false'),
      ]));
      expect(testUsage.commands, isEmpty);
      expect(testUsage.timings, isEmpty);
231
    }, overrides: <Type, Generator>{
232
      Usage: () => testUsage,
233 234 235 236 237 238 239 240 241 242 243
    });

    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',
      ]);

244
      expect(testUsage.enabled, true);
245

246
      // Verify that we only send the analytics enable event, and no other
247
      // info.
248 249 250 251 252
      expect(testUsage.events, equals(<TestUsageEvent>[
        const TestUsageEvent('analytics', 'enabled', label: 'true'),
      ]));
      expect(testUsage.commands, isEmpty);
      expect(testUsage.timings, isEmpty);
253
    }, overrides: <Type, Generator>{
254
      Usage: () => testUsage,
255
    });
256 257 258 259 260

    testUsingContext('analytics reported disabled when suppressed', () async {
      final ConfigCommand configCommand = ConfigCommand();
      final CommandRunner<void> commandRunner = createTestCommandRunner(configCommand);

261
      testUsage.suppressAnalytics = true;
262 263 264 265 266 267 268 269 270 271

      await commandRunner.run(<String>[
        'config',
      ]);

      expect(
        testLogger.statusText,
        containsIgnoringWhitespace('Analytics reporting is currently disabled'),
      );
    }, overrides: <Type, Generator>{
272
      Usage: () => testUsage,
273
    });
274 275 276
  });
}

277
class FakeAndroidStudio extends Fake implements AndroidStudio, Comparable<AndroidStudio> {
278 279 280 281
  @override
  String get directory => 'path/to/android/stdio';
}

282
class FakeAndroidSdk extends Fake implements AndroidSdk {
283
  @override
284
  Directory get directory => globals.fs.directory('path/to/android/sdk');
285
}
286

287 288
class FakeFlutterVersion extends Fake implements FlutterVersion {
  @override
289
  late String channel;
290 291 292 293 294 295 296

  @override
  void ensureVersionFile() {}

  @override
  Future<void> checkFlutterVersionFreshness() async {}
}