config_test.dart 9.66 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:args/command_runner.dart';
10 11
import 'package:flutter_tools/src/android/android_sdk.dart';
import 'package:flutter_tools/src/android/android_studio.dart';
12
import 'package:flutter_tools/src/base/file_system.dart';
13
import 'package:flutter_tools/src/build_info.dart';
14
import 'package:flutter_tools/src/cache.dart';
15
import 'package:flutter_tools/src/commands/config.dart';
16
import 'package:flutter_tools/src/globals_null_migrated.dart' as globals;
17
import 'package:flutter_tools/src/reporting/reporting.dart';
18
import 'package:flutter_tools/src/version.dart';
19
import 'package:test/fake.dart';
20

21 22
import '../../src/common.dart';
import '../../src/context.dart';
23
import '../../src/test_flutter_command_runner.dart';
24 25

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

  setUpAll(() {
    Cache.disableLocking();
  });
34 35

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

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

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

53 54
      expect(testLogger.statusText, isNotEmpty);
      final dynamic jsonObject = json.decode(testLogger.statusText);
55 56 57 58
      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);
59

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

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

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

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

    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',
91
        '--build-dir=/foo',
Dan Field's avatar
Dan Field committed
92
      ]), throwsToolExit());
93 94
      verifyNoAnalytics();
    }, overrides: <Type, Generator>{
95
      Usage: () => testUsage,
96 97
    });

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

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

112 113
      expect(globals.config.getValue('enable-android'), true);
      expect(globals.config.getValue('enable-ios'), true);
114 115 116 117
      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);
118 119 120 121 122

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

123 124
      expect(globals.config.getValue('enable-android'), null);
      expect(globals.config.getValue('enable-ios'), null);
125 126 127 128
      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);
129 130 131

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

140 141
      expect(globals.config.getValue('enable-android'), false);
      expect(globals.config.getValue('enable-ios'), false);
142 143 144 145
      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);
146
      verifyNoAnalytics();
147
    }, overrides: <Type, Generator>{
148 149
      AndroidStudio: () => fakeAndroidStudio,
      AndroidSdk: () => fakeAndroidSdk,
150
      Usage: () => testUsage,
151 152
    });

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

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

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

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

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

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

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

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

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

221
      expect(testUsage.enabled, false);
222

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

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

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

246
      expect(testUsage.enabled, true);
247

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

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

263
      testUsage.suppressAnalytics = true;
264 265 266 267 268 269 270 271 272 273

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

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

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

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

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

  @override
  void ensureVersionFile() {}

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