packages_test.dart 22.6 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 7 8 9 10
// TODO(gspencergoog): Remove this tag once this test's state leaks/test
// dependencies have been fixed.
// https://github.com/flutter/flutter/issues/85160
// Fails with "flutter test --test-randomize-ordering-seed=1000"
@Tags(<String>['no-shuffle'])

11
import 'dart:async';
12
import 'dart:convert';
13 14

import 'package:args/command_runner.dart';
15
import 'package:file/memory.dart';
16
import 'package:flutter_tools/src/base/bot_detector.dart';
17
import 'package:flutter_tools/src/base/error_handling_io.dart';
18
import 'package:flutter_tools/src/base/file_system.dart' hide IOSink;
19
import 'package:flutter_tools/src/base/io.dart';
20
import 'package:flutter_tools/src/base/platform.dart';
21
import 'package:flutter_tools/src/cache.dart';
22
import 'package:flutter_tools/src/commands/packages.dart';
23
import 'package:flutter_tools/src/dart/pub.dart';
24
import 'package:flutter_tools/src/globals.dart' as globals;
25

26 27
import '../../src/common.dart';
import '../../src/context.dart';
28
import '../../src/fake_process_manager.dart';
29
import '../../src/fakes.dart';
30
import '../../src/test_flutter_command_runner.dart';
31 32

void main() {
33 34 35 36 37 38
  late FakeStdio mockStdio;

  setUp(() {
    mockStdio = FakeStdio()..stdout.terminalColumns = 80;
  });

39 40
  Cache.disableLocking();
  group('packages get/upgrade', () {
41
    late Directory tempDir;
42 43

    setUp(() {
44
      tempDir = globals.fs.systemTempDirectory.createTempSync('flutter_tools_packages_test.');
45 46 47
    });

    tearDown(() {
48
      tryToDelete(tempDir);
49 50
    });

51
    Future<String> createProjectWithPlugin(String plugin, { List<String>? arguments }) async {
52
      final String projectPath = await createProject(tempDir, arguments: arguments);
53
      final File pubspec = globals.fs.file(globals.fs.path.join(projectPath, 'pubspec.yaml'));
54
      String content = await pubspec.readAsString();
55 56 57 58 59 60 61 62
      final List<String> contentLines = LineSplitter.split(content).toList();
      final int depsIndex = contentLines.indexOf('dependencies:');
      expect(depsIndex, isNot(-1));
      contentLines.replaceRange(depsIndex, depsIndex + 1, <String>[
        'dependencies:',
        '  $plugin:',
      ]);
      content = contentLines.join('\n');
63 64 65
      await pubspec.writeAsString(content, flush: true);
      return projectPath;
    }
66

67
    Future<PackagesCommand> runCommandIn(String projectPath, String verb, { List<String>? args }) async {
68
      final PackagesCommand command = PackagesCommand();
69
      final CommandRunner<void> runner = createTestCommandRunner(command);
70 71 72 73 74 75
      await runner.run(<String>[
        'packages',
        verb,
        ...?args,
        projectPath,
      ]);
76
      return command;
77 78
    }

79
    void expectExists(String projectPath, String relPath) {
80
      expect(
81
        globals.fs.isFileSync(globals.fs.path.join(projectPath, relPath)),
82 83 84 85 86 87 88 89
        true,
        reason: '$projectPath/$relPath should exist, but does not',
      );
    }

    void expectContains(String projectPath, String relPath, String substring) {
      expectExists(projectPath, relPath);
      expect(
90
        globals.fs.file(globals.fs.path.join(projectPath, relPath)).readAsStringSync(),
91
        contains(substring),
92
        reason: '$projectPath/$relPath has unexpected content',
93 94 95 96 97
      );
    }

    void expectNotExists(String projectPath, String relPath) {
      expect(
98
        globals.fs.isFileSync(globals.fs.path.join(projectPath, relPath)),
99 100 101 102 103 104 105 106
        false,
        reason: '$projectPath/$relPath should not exist, but does',
      );
    }

    void expectNotContains(String projectPath, String relPath, String substring) {
      expectExists(projectPath, relPath);
      expect(
107
        globals.fs.file(globals.fs.path.join(projectPath, relPath)).readAsStringSync(),
108 109 110 111 112
        isNot(contains(substring)),
        reason: '$projectPath/$relPath has unexpected content',
      );
    }

113 114
    final List<String> pubOutput = <String>[
      globals.fs.path.join('.dart_tool', 'package_config.json'),
115 116 117
      'pubspec.lock',
    ];

118
    const List<String> pluginRegistrants = <String>[
119 120 121 122 123
      'ios/Runner/GeneratedPluginRegistrant.h',
      'ios/Runner/GeneratedPluginRegistrant.m',
      'android/app/src/main/java/io/flutter/plugins/GeneratedPluginRegistrant.java',
    ];

124
    const List<String> modulePluginRegistrants = <String>[
125 126 127 128 129
      '.ios/Flutter/FlutterPluginRegistrant/Classes/GeneratedPluginRegistrant.h',
      '.ios/Flutter/FlutterPluginRegistrant/Classes/GeneratedPluginRegistrant.m',
      '.android/Flutter/src/main/java/io/flutter/plugins/GeneratedPluginRegistrant.java',
    ];

130
    const List<String> pluginWitnesses = <String>[
131 132 133 134
      '.flutter-plugins',
      'ios/Podfile',
    ];

135
    const List<String> modulePluginWitnesses = <String>[
136 137 138 139
      '.flutter-plugins',
      '.ios/Podfile',
    ];

140
    const Map<String, String> pluginContentWitnesses = <String, String>{
141 142
      'ios/Flutter/Debug.xcconfig': '#include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig"',
      'ios/Flutter/Release.xcconfig': '#include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig"',
143 144
    };

145
    const Map<String, String> modulePluginContentWitnesses = <String, String>{
146 147
      '.ios/Config/Debug.xcconfig': '#include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig"',
      '.ios/Config/Release.xcconfig': '#include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig"',
148 149
    };

150
    void expectDependenciesResolved(String projectPath) {
151
      for (final String output in pubOutput) {
152 153 154 155 156
        expectExists(projectPath, output);
      }
    }

    void expectZeroPluginsInjected(String projectPath) {
157
      for (final String registrant in modulePluginRegistrants) {
158 159 160 161 162
        expectExists(projectPath, registrant);
      }
      for (final String witness in pluginWitnesses) {
        expectNotExists(projectPath, witness);
      }
163
      modulePluginContentWitnesses.forEach((String witness, String content) {
164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179
        expectNotContains(projectPath, witness, content);
      });
    }

    void expectPluginInjected(String projectPath) {
      for (final String registrant in pluginRegistrants) {
        expectExists(projectPath, registrant);
      }
      for (final String witness in pluginWitnesses) {
        expectExists(projectPath, witness);
      }
      pluginContentWitnesses.forEach((String witness, String content) {
        expectContains(projectPath, witness, content);
      });
    }

180 181
    void expectModulePluginInjected(String projectPath) {
      for (final String registrant in modulePluginRegistrants) {
182 183
        expectExists(projectPath, registrant);
      }
184
      for (final String witness in modulePluginWitnesses) {
185 186
        expectExists(projectPath, witness);
      }
187
      modulePluginContentWitnesses.forEach((String witness, String content) {
188 189 190 191
        expectContains(projectPath, witness, content);
      });
    }

192 193 194
    void removeGeneratedFiles(String projectPath) {
      final Iterable<String> allFiles = <List<String>>[
        pubOutput,
195
        modulePluginRegistrants,
196
        pluginWitnesses,
197
      ].expand<String>((List<String> list) => list);
198
      for (final String path in allFiles) {
199
        final File file = globals.fs.file(globals.fs.path.join(projectPath, path));
200
        ErrorHandlingFileSystem.deleteIfExists(file);
201
      }
202 203
    }

204
    testUsingContext('get fetches packages and has output from pub', () async {
205 206
      final String projectPath = await createProject(tempDir,
        arguments: <String>['--no-pub', '--template=module']);
207 208 209 210
      removeGeneratedFiles(projectPath);

      await runCommandIn(projectPath, 'get');

211 212 213 214 215 216 217 218
      expect(mockStdio.stdout.writes.map(utf8.decode),
        allOf(
          contains(matches(RegExp(r'Resolving dependencies in .+flutter_project\.\.\.'))),
          contains('+ flutter 0.0.0 from sdk flutter\n'),
          contains(matches(RegExp(r'Changed \d+ dependencies in .+flutter_project!'))),
        ),
      );

219 220
      expectDependenciesResolved(projectPath);
      expectZeroPluginsInjected(projectPath);
221
    }, overrides: <Type, Generator>{
222
      Stdio: () => mockStdio,
223 224 225 226 227 228 229
      Pub: () => Pub(
        fileSystem: globals.fs,
        logger: globals.logger,
        processManager: globals.processManager,
        usage: globals.flutterUsage,
        botDetector: globals.botDetector,
        platform: globals.platform,
230
        stdio: mockStdio,
231
      ),
232
    });
233

234
    testUsingContext('get --offline fetches packages', () async {
235 236
      final String projectPath = await createProject(tempDir,
        arguments: <String>['--no-pub', '--template=module']);
237 238 239 240 241 242
      removeGeneratedFiles(projectPath);

      await runCommandIn(projectPath, 'get', args: <String>['--offline']);

      expectDependenciesResolved(projectPath);
      expectZeroPluginsInjected(projectPath);
243
    }, overrides: <Type, Generator>{
244
      Stdio: () => mockStdio,
245 246 247 248 249 250 251
      Pub: () => Pub(
        fileSystem: globals.fs,
        logger: globals.logger,
        processManager: globals.processManager,
        usage: globals.flutterUsage,
        botDetector: globals.botDetector,
        platform: globals.platform,
252
        stdio: mockStdio,
253
      ),
254
    });
255

256
    testUsingContext('set no plugins as usage value', () async {
257 258 259 260 261
      final String projectPath = await createProject(tempDir,
        arguments: <String>['--no-pub', '--template=module']);
      removeGeneratedFiles(projectPath);

      final PackagesCommand command = await runCommandIn(projectPath, 'get');
262
      final PackagesGetCommand getCommand = command.subcommands['get']! as PackagesGetCommand;
263

264
      expect((await getCommand.usageValues).commandPackagesNumberPlugins, 0);
265
    }, overrides: <Type, Generator>{
266
      Stdio: () => mockStdio,
267 268 269 270 271 272 273
      Pub: () => Pub(
        fileSystem: globals.fs,
        logger: globals.logger,
        processManager: globals.processManager,
        usage: globals.flutterUsage,
        botDetector: globals.botDetector,
        platform: globals.platform,
274
        stdio: mockStdio,
275
      ),
276
    });
277

278 279 280 281 282 283 284 285
    testUsingContext('set the number of plugins as usage value', () async {
      final String projectPath = await createProject(
        tempDir,
        arguments: <String>['--template=plugin', '--no-pub', '--platforms=ios,android,macos,windows'],
      );
      final String exampleProjectPath = globals.fs.path.join(projectPath, 'example');

      final PackagesCommand command = await runCommandIn(exampleProjectPath, 'get');
286
      final PackagesGetCommand getCommand = command.subcommands['get']! as PackagesGetCommand;
287

288
      expect((await getCommand.usageValues).commandPackagesNumberPlugins, 1);
289
    }, overrides: <Type, Generator>{
290
      Stdio: () => mockStdio,
291 292 293 294 295 296 297
      Pub: () => Pub(
        fileSystem: globals.fs,
        logger: globals.logger,
        processManager: globals.processManager,
        usage: globals.flutterUsage,
        botDetector: globals.botDetector,
        platform: globals.platform,
298
        stdio: mockStdio,
299 300 301
      ),
    });

302 303 304 305 306 307
    testUsingContext('indicate that the project is not a module in usage value', () async {
      final String projectPath = await createProject(tempDir,
        arguments: <String>['--no-pub']);
      removeGeneratedFiles(projectPath);

      final PackagesCommand command = await runCommandIn(projectPath, 'get');
308
      final PackagesGetCommand getCommand = command.subcommands['get']! as PackagesGetCommand;
309

310
      expect((await getCommand.usageValues).commandPackagesProjectModule, false);
311
    }, overrides: <Type, Generator>{
312
      Stdio: () => mockStdio,
313 314 315 316 317 318 319
      Pub: () => Pub(
        fileSystem: globals.fs,
        logger: globals.logger,
        processManager: globals.processManager,
        usage: globals.flutterUsage,
        botDetector: globals.botDetector,
        platform: globals.platform,
320
        stdio: mockStdio,
321
      ),
322
    });
323 324 325 326 327 328 329

    testUsingContext('indicate that the project is a module in usage value', () async {
      final String projectPath = await createProject(tempDir,
        arguments: <String>['--no-pub', '--template=module']);
      removeGeneratedFiles(projectPath);

      final PackagesCommand command = await runCommandIn(projectPath, 'get');
330
      final PackagesGetCommand getCommand = command.subcommands['get']! as PackagesGetCommand;
331

332
      expect((await getCommand.usageValues).commandPackagesProjectModule, true);
333
    }, overrides: <Type, Generator>{
334
      Stdio: () => mockStdio,
335 336 337 338 339 340 341
      Pub: () => Pub(
        fileSystem: globals.fs,
        logger: globals.logger,
        processManager: globals.processManager,
        usage: globals.flutterUsage,
        botDetector: globals.botDetector,
        platform: globals.platform,
342
        stdio: mockStdio,
343
      ),
344
    });
345

346 347 348 349 350
    testUsingContext('indicate that Android project reports v1 in usage value', () async {
      final String projectPath = await createProject(tempDir,
        arguments: <String>['--no-pub']);
      removeGeneratedFiles(projectPath);

351 352 353 354 355 356 357 358 359
      final File androidManifest = globals.fs.file(globals.fs.path.join(
        projectPath,
        'android/app/src/main/AndroidManifest.xml',
      ));
      final String updatedAndroidManifestString =
          androidManifest.readAsStringSync().replaceAll('android:value="2"', 'android:value="1"');

      androidManifest.writeAsStringSync(updatedAndroidManifestString);

360
      final PackagesCommand command = await runCommandIn(projectPath, 'get');
361
      final PackagesGetCommand getCommand = command.subcommands['get']! as PackagesGetCommand;
362

363
      expect((await getCommand.usageValues).commandPackagesAndroidEmbeddingVersion, 'v1');
364
    }, overrides: <Type, Generator>{
365
      Stdio: () => mockStdio,
366 367 368 369 370 371 372
      Pub: () => Pub(
        fileSystem: globals.fs,
        logger: globals.logger,
        processManager: globals.processManager,
        usage: globals.flutterUsage,
        botDetector: globals.botDetector,
        platform: globals.platform,
373
        stdio: mockStdio,
374
      ),
375 376 377 378 379 380 381 382
    });

    testUsingContext('indicate that Android project reports v2 in usage value', () async {
      final String projectPath = await createProject(tempDir,
        arguments: <String>['--no-pub']);
      removeGeneratedFiles(projectPath);

      final PackagesCommand command = await runCommandIn(projectPath, 'get');
383
      final PackagesGetCommand getCommand = command.subcommands['get']! as PackagesGetCommand;
384

385
      expect((await getCommand.usageValues).commandPackagesAndroidEmbeddingVersion, 'v2');
386
    }, overrides: <Type, Generator>{
387
      Stdio: () => mockStdio,
388 389 390 391 392 393 394
      Pub: () => Pub(
        fileSystem: globals.fs,
        logger: globals.logger,
        processManager: globals.processManager,
        usage: globals.flutterUsage,
        botDetector: globals.botDetector,
        platform: globals.platform,
395
        stdio: mockStdio,
396
      ),
397 398
    });

399
    testUsingContext('upgrade fetches packages', () async {
400 401
      final String projectPath = await createProject(tempDir,
        arguments: <String>['--no-pub', '--template=module']);
402 403 404 405 406 407
      removeGeneratedFiles(projectPath);

      await runCommandIn(projectPath, 'upgrade');

      expectDependenciesResolved(projectPath);
      expectZeroPluginsInjected(projectPath);
408
    }, overrides: <Type, Generator>{
409
      Stdio: () => mockStdio,
410 411 412 413 414 415 416
      Pub: () => Pub(
        fileSystem: globals.fs,
        logger: globals.logger,
        processManager: globals.processManager,
        usage: globals.flutterUsage,
        botDetector: globals.botDetector,
        platform: globals.platform,
417
        stdio: mockStdio,
418
      ),
419
    });
420 421

    testUsingContext('get fetches packages and injects plugin', () async {
422 423
      final String projectPath = await createProjectWithPlugin('path_provider',
        arguments: <String>['--no-pub', '--template=module']);
424 425 426
      removeGeneratedFiles(projectPath);

      await runCommandIn(projectPath, 'get');
427

428
      expectDependenciesResolved(projectPath);
429
      expectModulePluginInjected(projectPath);
430
    }, overrides: <Type, Generator>{
431
      Stdio: () => mockStdio,
432 433 434 435 436 437 438
      Pub: () => Pub(
        fileSystem: globals.fs,
        logger: globals.logger,
        processManager: globals.processManager,
        usage: globals.flutterUsage,
        botDetector: globals.botDetector,
        platform: globals.platform,
439
        stdio: mockStdio,
440
      ),
441
    });
442

443 444
    testUsingContext('get fetches packages and injects plugin in plugin project', () async {
      final String projectPath = await createProject(
445
        tempDir,
446
        arguments: <String>['--template=plugin', '--no-pub', '--platforms=ios,android'],
447
      );
448
      final String exampleProjectPath = globals.fs.path.join(projectPath, 'example');
449 450 451 452 453 454 455 456 457 458 459
      removeGeneratedFiles(projectPath);
      removeGeneratedFiles(exampleProjectPath);

      await runCommandIn(projectPath, 'get');

      expectDependenciesResolved(projectPath);

      await runCommandIn(exampleProjectPath, 'get');

      expectDependenciesResolved(exampleProjectPath);
      expectPluginInjected(exampleProjectPath);
460
    }, overrides: <Type, Generator>{
461
      Stdio: () => mockStdio,
462 463 464 465 466 467 468
      Pub: () => Pub(
        fileSystem: globals.fs,
        logger: globals.logger,
        processManager: globals.processManager,
        usage: globals.flutterUsage,
        botDetector: globals.botDetector,
        platform: globals.platform,
469
        stdio: mockStdio,
470
      ),
471
    });
472
  });
473 474

  group('packages test/pub', () {
475 476
    late FakeProcessManager processManager;
    late FakeStdio mockStdio;
477 478

    setUp(() {
479
      processManager = FakeProcessManager.empty();
480
      mockStdio = FakeStdio()..stdout.terminalColumns = 80;
481 482
    });

483
    testUsingContext('test without bot', () async {
484
      Cache.flutterRoot = '';
485
      globals.fs.directory('/packages/flutter_tools').createSync(recursive: true);
486 487
      globals.fs.file('pubspec.yaml').createSync();
      processManager.addCommand(
488
        const FakeCommand(command: <String>['/bin/cache/dart-sdk/bin/dart', '__deprecated_pub', 'run', 'test']),
489
      );
490
      await createTestCommandRunner(PackagesCommand()).run(<String>['packages', 'test']);
491

492
      expect(processManager, hasNoRemainingExpectations);
493
    }, overrides: <Type, Generator>{
494
      FileSystem: () => MemoryFileSystem.test(),
495
      Platform: () => FakePlatform(environment: <String, String>{}),
496
      ProcessManager: () => processManager,
497
      Stdio: () => mockStdio,
498
      BotDetector: () => const FakeBotDetector(false),
499 500 501 502 503 504 505
      Pub: () => Pub(
        fileSystem: globals.fs,
        logger: globals.logger,
        processManager: globals.processManager,
        usage: globals.flutterUsage,
        botDetector: globals.botDetector,
        platform: globals.platform,
506
        stdio: mockStdio,
507
      ),
508 509 510
    });

    testUsingContext('test with bot', () async {
511 512 513
      Cache.flutterRoot = '';
      globals.fs.file('pubspec.yaml').createSync();
      processManager.addCommand(
514
        const FakeCommand(command: <String>['/bin/cache/dart-sdk/bin/dart', '__deprecated_pub', '--trace', 'run', 'test']),
515
      );
516
      await createTestCommandRunner(PackagesCommand()).run(<String>['packages', 'test']);
517

518
      expect(processManager, hasNoRemainingExpectations);
519
    }, overrides: <Type, Generator>{
520
      FileSystem: () => MemoryFileSystem.test(),
521
      Platform: () => FakePlatform(environment: <String, String>{}),
522
      ProcessManager: () => processManager,
523
      Stdio: () => mockStdio,
524
      BotDetector: () => const FakeBotDetector(true),
525 526 527 528 529 530 531
      Pub: () => Pub(
        fileSystem: globals.fs,
        logger: globals.logger,
        processManager: globals.processManager,
        usage: globals.flutterUsage,
        botDetector: globals.botDetector,
        platform: globals.platform,
532
        stdio: mockStdio,
533
      ),
534 535
    });

536 537 538 539 540
    testUsingContext('run pass arguments through to pub', () async {
      Cache.flutterRoot = '';
      globals.fs.file('pubspec.yaml').createSync();
      final IOSink stdin = IOSink(StreamController<List<int>>().sink);
      processManager.addCommand(
541 542 543 544
        FakeCommand(
          command: const <String>[
            '/bin/cache/dart-sdk/bin/dart', '__deprecated_pub', 'run', '--foo', 'bar',
          ],
545 546 547 548
          stdin: stdin,
        ),
      );
      await createTestCommandRunner(PackagesCommand()).run(<String>['packages', '--verbose', 'pub', 'run', '--foo', 'bar']);
549

550
      expect(processManager, hasNoRemainingExpectations);
551
    }, overrides: <Type, Generator>{
552
      FileSystem: () => MemoryFileSystem.test(),
553
      Platform: () => FakePlatform(environment: <String, String>{}),
554
      ProcessManager: () => processManager,
555
      Stdio: () => mockStdio,
556 557 558 559 560 561 562
      Pub: () => Pub(
        fileSystem: globals.fs,
        logger: globals.logger,
        processManager: globals.processManager,
        usage: globals.flutterUsage,
        botDetector: globals.botDetector,
        platform: globals.platform,
563
        stdio: mockStdio,
564
      ),
565
    });
566

567 568 569 570 571
    testUsingContext('token pass arguments through to pub', () async {
      Cache.flutterRoot = '';
      globals.fs.file('pubspec.yaml').createSync();
      final IOSink stdin = IOSink(StreamController<List<int>>().sink);
      processManager.addCommand(
572 573 574 575
        FakeCommand(
          command: const <String>[
            '/bin/cache/dart-sdk/bin/dart', '__deprecated_pub', 'token', 'list',
          ],
576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593
          stdin: stdin,
        ),
      );
      await createTestCommandRunner(PackagesCommand()).run(<String>['packages', '--verbose', 'pub', 'token', 'list']);

      expect(processManager, hasNoRemainingExpectations);
    }, overrides: <Type, Generator>{
      FileSystem: () => MemoryFileSystem.test(),
      Platform: () => FakePlatform(environment: <String, String>{}),
      ProcessManager: () => processManager,
      Stdio: () => mockStdio,
      Pub: () => Pub(
        fileSystem: globals.fs,
        logger: globals.logger,
        processManager: globals.processManager,
        usage: globals.flutterUsage,
        botDetector: globals.botDetector,
        platform: globals.platform,
594
        stdio: mockStdio,
595 596 597
      ),
    });

598 599 600
    testUsingContext('upgrade does not check for pubspec.yaml if -h/--help is passed', () async {
      Cache.flutterRoot = '';
      processManager.addCommand(
601 602 603 604
        FakeCommand(
          command: const <String>[
            '/bin/cache/dart-sdk/bin/dart', '__deprecated_pub', 'upgrade', '-h',
          ],
605 606 607 608 609 610 611 612
          stdin:  IOSink(StreamController<List<int>>().sink),
        ),
      );
      await createTestCommandRunner(PackagesCommand()).run(<String>['pub', 'upgrade', '-h']);

      expect(processManager, hasNoRemainingExpectations);
    }, overrides: <Type, Generator>{
      FileSystem: () => MemoryFileSystem.test(),
613
      Platform: () => FakePlatform(environment: <String, String>{}),
614 615 616 617 618 619 620 621 622
      ProcessManager: () => processManager,
      Stdio: () => mockStdio,
      Pub: () => Pub(
        fileSystem: globals.fs,
        logger: globals.logger,
        processManager: globals.processManager,
        usage: globals.flutterUsage,
        botDetector: globals.botDetector,
        platform: globals.platform,
623
        stdio: mockStdio,
624 625
      ),
    });
626 627
  });
}