packages_test.dart 26.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
import 'dart:convert';
6 7

import 'package:args/command_runner.dart';
8
import 'package:flutter_tools/src/base/bot_detector.dart';
9
import 'package:flutter_tools/src/base/error_handling_io.dart';
10
import 'package:flutter_tools/src/base/file_system.dart' hide IOSink;
11
import 'package:flutter_tools/src/base/io.dart';
12
import 'package:flutter_tools/src/cache.dart';
13
import 'package:flutter_tools/src/commands/packages.dart';
14
import 'package:flutter_tools/src/dart/pub.dart';
15
import 'package:flutter_tools/src/reporting/reporting.dart';
16
import 'package:process/process.dart';
17
import 'package:flutter_tools/src/globals.dart' as globals;
18

19 20
import '../../src/common.dart';
import '../../src/context.dart';
Dan Field's avatar
Dan Field committed
21
import '../../src/mocks.dart' show MockProcessManager, MockStdio, PromptingProcess, AlwaysTrueBotDetector, AlwaysFalseBotDetector;
22
import '../../src/testbed.dart';
23 24

void main() {
25 26
  Cache.disableLocking();
  group('packages get/upgrade', () {
27
    Directory tempDir;
28 29

    setUp(() {
30
      tempDir = globals.fs.systemTempDirectory.createTempSync('flutter_tools_packages_test.');
31 32 33
    });

    tearDown(() {
34
      tryToDelete(tempDir);
35 36
    });

37
    Future<String> createProjectWithPlugin(String plugin, { List<String> arguments }) async {
38
      final String projectPath = await createProject(tempDir, arguments: arguments);
39
      final File pubspec = globals.fs.file(globals.fs.path.join(projectPath, 'pubspec.yaml'));
40
      String content = await pubspec.readAsString();
41 42 43 44 45 46 47 48
      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');
49 50 51
      await pubspec.writeAsString(content, flush: true);
      return projectPath;
    }
52

53
    Future<PackagesCommand> runCommandIn(String projectPath, String verb, { List<String> args }) async {
54
      final PackagesCommand command = PackagesCommand();
55
      final CommandRunner<void> runner = createTestCommandRunner(command);
56 57 58 59 60 61
      await runner.run(<String>[
        'packages',
        verb,
        ...?args,
        projectPath,
      ]);
62
      return command;
63 64
    }

65
    void expectExists(String projectPath, String relPath) {
66
      expect(
67
        globals.fs.isFileSync(globals.fs.path.join(projectPath, relPath)),
68 69 70 71 72 73 74 75
        true,
        reason: '$projectPath/$relPath should exist, but does not',
      );
    }

    void expectContains(String projectPath, String relPath, String substring) {
      expectExists(projectPath, relPath);
      expect(
76
        globals.fs.file(globals.fs.path.join(projectPath, relPath)).readAsStringSync(),
77
        contains(substring),
78
        reason: '$projectPath/$relPath has unexpected content',
79 80 81 82 83
      );
    }

    void expectNotExists(String projectPath, String relPath) {
      expect(
84
        globals.fs.isFileSync(globals.fs.path.join(projectPath, relPath)),
85 86 87 88 89 90 91 92
        false,
        reason: '$projectPath/$relPath should not exist, but does',
      );
    }

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

99
    const List<String> pubOutput = <String>[
100 101 102 103
      '.packages',
      'pubspec.lock',
    ];

104
    const List<String> pluginRegistrants = <String>[
105 106 107 108 109
      'ios/Runner/GeneratedPluginRegistrant.h',
      'ios/Runner/GeneratedPluginRegistrant.m',
      'android/app/src/main/java/io/flutter/plugins/GeneratedPluginRegistrant.java',
    ];

110
    const List<String> modulePluginRegistrants = <String>[
111 112 113 114 115
      '.ios/Flutter/FlutterPluginRegistrant/Classes/GeneratedPluginRegistrant.h',
      '.ios/Flutter/FlutterPluginRegistrant/Classes/GeneratedPluginRegistrant.m',
      '.android/Flutter/src/main/java/io/flutter/plugins/GeneratedPluginRegistrant.java',
    ];

116
    const List<String> pluginWitnesses = <String>[
117 118 119 120
      '.flutter-plugins',
      'ios/Podfile',
    ];

121
    const List<String> modulePluginWitnesses = <String>[
122 123 124 125
      '.flutter-plugins',
      '.ios/Podfile',
    ];

126
    const Map<String, String> pluginContentWitnesses = <String, String>{
127 128 129 130
      '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"',
    };

131
    const Map<String, String> modulePluginContentWitnesses = <String, String>{
132 133 134 135
      '.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"',
    };

136
    void expectDependenciesResolved(String projectPath) {
137
      for (final String output in pubOutput) {
138 139 140 141 142
        expectExists(projectPath, output);
      }
    }

    void expectZeroPluginsInjected(String projectPath) {
143
      for (final String registrant in modulePluginRegistrants) {
144 145 146 147 148
        expectExists(projectPath, registrant);
      }
      for (final String witness in pluginWitnesses) {
        expectNotExists(projectPath, witness);
      }
149
      modulePluginContentWitnesses.forEach((String witness, String content) {
150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165
        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);
      });
    }

166 167
    void expectModulePluginInjected(String projectPath) {
      for (final String registrant in modulePluginRegistrants) {
168 169
        expectExists(projectPath, registrant);
      }
170
      for (final String witness in modulePluginWitnesses) {
171 172
        expectExists(projectPath, witness);
      }
173
      modulePluginContentWitnesses.forEach((String witness, String content) {
174 175 176 177
        expectContains(projectPath, witness, content);
      });
    }

178 179 180
    void removeGeneratedFiles(String projectPath) {
      final Iterable<String> allFiles = <List<String>>[
        pubOutput,
181
        modulePluginRegistrants,
182
        pluginWitnesses,
183
      ].expand<String>((List<String> list) => list);
184
      for (final String path in allFiles) {
185
        final File file = globals.fs.file(globals.fs.path.join(projectPath, path));
186
        ErrorHandlingFileSystem.deleteIfExists(file);
187
      }
188 189
    }

190
    testUsingContext('get fetches packages', () async {
191 192
      final String projectPath = await createProject(tempDir,
        arguments: <String>['--no-pub', '--template=module']);
193 194 195 196 197 198
      removeGeneratedFiles(projectPath);

      await runCommandIn(projectPath, 'get');

      expectDependenciesResolved(projectPath);
      expectZeroPluginsInjected(projectPath);
199
    }, overrides: <Type, Generator>{
200 201 202 203 204 205 206 207
      Pub: () => Pub(
        fileSystem: globals.fs,
        logger: globals.logger,
        processManager: globals.processManager,
        usage: globals.flutterUsage,
        botDetector: globals.botDetector,
        platform: globals.platform,
      ),
208
    });
209

210
    testUsingContext('get --offline fetches packages', () async {
211 212
      final String projectPath = await createProject(tempDir,
        arguments: <String>['--no-pub', '--template=module']);
213 214 215 216 217 218
      removeGeneratedFiles(projectPath);

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

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

230 231 232 233 234 235 236 237
    testUsingContext('set the number of plugins as usage value', () async {
      final String projectPath = await createProject(tempDir,
        arguments: <String>['--no-pub', '--template=module']);
      removeGeneratedFiles(projectPath);

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

238 239
      expect(await getCommand.usageValues,
             containsPair(CustomDimensions.commandPackagesNumberPlugins, '0'));
240
    }, overrides: <Type, Generator>{
241 242 243 244 245 246 247 248
      Pub: () => Pub(
        fileSystem: globals.fs,
        logger: globals.logger,
        processManager: globals.processManager,
        usage: globals.flutterUsage,
        botDetector: globals.botDetector,
        platform: globals.platform,
      ),
249
    });
250 251 252 253 254 255 256 257 258

    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');
      final PackagesGetCommand getCommand = command.subcommands['get'] as PackagesGetCommand;

259 260
      expect(await getCommand.usageValues,
             containsPair(CustomDimensions.commandPackagesProjectModule, 'false'));
261
    }, overrides: <Type, Generator>{
262 263 264 265 266 267 268 269
      Pub: () => Pub(
        fileSystem: globals.fs,
        logger: globals.logger,
        processManager: globals.processManager,
        usage: globals.flutterUsage,
        botDetector: globals.botDetector,
        platform: globals.platform,
      ),
270
    });
271 272 273 274 275 276 277 278 279

    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');
      final PackagesGetCommand getCommand = command.subcommands['get'] as PackagesGetCommand;

280 281
      expect(await getCommand.usageValues,
             containsPair(CustomDimensions.commandPackagesProjectModule, 'true'));
282
    }, overrides: <Type, Generator>{
283 284 285 286 287 288 289 290
      Pub: () => Pub(
        fileSystem: globals.fs,
        logger: globals.logger,
        processManager: globals.processManager,
        usage: globals.flutterUsage,
        botDetector: globals.botDetector,
        platform: globals.platform,
      ),
291
    });
292

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

298 299 300 301 302 303 304 305 306
      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);

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

      expect(await getCommand.usageValues,
             containsPair(CustomDimensions.commandPackagesAndroidEmbeddingVersion, 'v1'));
    }, overrides: <Type, Generator>{
313 314 315 316 317 318 319 320
      Pub: () => Pub(
        fileSystem: globals.fs,
        logger: globals.logger,
        processManager: globals.processManager,
        usage: globals.flutterUsage,
        botDetector: globals.botDetector,
        platform: globals.platform,
      ),
321 322 323 324 325 326 327 328 329 330 331 332 333
    });

    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');
      final PackagesGetCommand getCommand = command.subcommands['get'] as PackagesGetCommand;

      expect(await getCommand.usageValues,
             containsPair(CustomDimensions.commandPackagesAndroidEmbeddingVersion, 'v2'));
    }, overrides: <Type, Generator>{
334 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 343
    });

344
    testUsingContext('upgrade fetches packages', () async {
345 346
      final String projectPath = await createProject(tempDir,
        arguments: <String>['--no-pub', '--template=module']);
347 348 349 350 351 352
      removeGeneratedFiles(projectPath);

      await runCommandIn(projectPath, 'upgrade');

      expectDependenciesResolved(projectPath);
      expectZeroPluginsInjected(projectPath);
353
    }, overrides: <Type, Generator>{
354 355 356 357 358 359 360 361
      Pub: () => Pub(
        fileSystem: globals.fs,
        logger: globals.logger,
        processManager: globals.processManager,
        usage: globals.flutterUsage,
        botDetector: globals.botDetector,
        platform: globals.platform,
      ),
362
    });
363 364

    testUsingContext('get fetches packages and injects plugin', () async {
365 366
      final String projectPath = await createProjectWithPlugin('path_provider',
        arguments: <String>['--no-pub', '--template=module']);
367 368 369
      removeGeneratedFiles(projectPath);

      await runCommandIn(projectPath, 'get');
370

371
      expectDependenciesResolved(projectPath);
372
      expectModulePluginInjected(projectPath);
373
    }, overrides: <Type, Generator>{
374 375 376 377 378 379 380 381
      Pub: () => Pub(
        fileSystem: globals.fs,
        logger: globals.logger,
        processManager: globals.processManager,
        usage: globals.flutterUsage,
        botDetector: globals.botDetector,
        platform: globals.platform,
      ),
382
    });
383

384 385
    testUsingContext('get fetches packages and injects plugin in plugin project', () async {
      final String projectPath = await createProject(
386
        tempDir,
387
        arguments: <String>['--template=plugin', '--no-pub', '--platforms=ios,android'],
388
      );
389
      final String exampleProjectPath = globals.fs.path.join(projectPath, 'example');
390 391 392 393 394 395 396 397 398 399 400
      removeGeneratedFiles(projectPath);
      removeGeneratedFiles(exampleProjectPath);

      await runCommandIn(projectPath, 'get');

      expectDependenciesResolved(projectPath);

      await runCommandIn(exampleProjectPath, 'get');

      expectDependenciesResolved(exampleProjectPath);
      expectPluginInjected(exampleProjectPath);
401
    }, overrides: <Type, Generator>{
402 403 404 405 406 407 408 409
      Pub: () => Pub(
        fileSystem: globals.fs,
        logger: globals.logger,
        processManager: globals.processManager,
        usage: globals.flutterUsage,
        botDetector: globals.botDetector,
        platform: globals.platform,
      ),
410
    });
411
  });
412 413

  group('packages test/pub', () {
414 415 416 417
    MockProcessManager mockProcessManager;
    MockStdio mockStdio;

    setUp(() {
418
      mockProcessManager = MockProcessManager();
kwkr's avatar
kwkr committed
419
      mockStdio = MockStdio()..stdout.terminalColumns = 80;
420 421
    });

422
    testUsingContext('test without bot', () async {
423
      await createTestCommandRunner(PackagesCommand()).run(<String>['packages', 'test']);
424 425 426 427 428 429 430 431 432
      final List<String> commands = mockProcessManager.commands;
      expect(commands, hasLength(3));
      expect(commands[0], matches(r'dart-sdk[\\/]bin[\\/]pub'));
      expect(commands[1], 'run');
      expect(commands[2], 'test');
    }, overrides: <Type, Generator>{
      ProcessManager: () => mockProcessManager,
      Stdio: () => mockStdio,
      BotDetector: () => const AlwaysFalseBotDetector(),
433 434 435 436 437 438 439 440
      Pub: () => Pub(
        fileSystem: globals.fs,
        logger: globals.logger,
        processManager: globals.processManager,
        usage: globals.flutterUsage,
        botDetector: globals.botDetector,
        platform: globals.platform,
      ),
441 442 443
    });

    testUsingContext('test with bot', () async {
444
      await createTestCommandRunner(PackagesCommand()).run(<String>['packages', 'test']);
445
      final List<String> commands = mockProcessManager.commands;
446
      expect(commands, hasLength(4));
447
      expect(commands[0], matches(r'dart-sdk[\\/]bin[\\/]pub'));
448 449 450
      expect(commands[1], '--trace');
      expect(commands[2], 'run');
      expect(commands[3], 'test');
451
    }, overrides: <Type, Generator>{
452 453
      ProcessManager: () => mockProcessManager,
      Stdio: () => mockStdio,
454
      BotDetector: () => const AlwaysTrueBotDetector(),
455 456 457 458 459 460 461 462
      Pub: () => Pub(
        fileSystem: globals.fs,
        logger: globals.logger,
        processManager: globals.processManager,
        usage: globals.flutterUsage,
        botDetector: globals.botDetector,
        platform: globals.platform,
      ),
463
    });
464

465
    testUsingContext('run', () async {
466
      await createTestCommandRunner(PackagesCommand()).run(<String>['packages', '--verbose', 'pub', 'run', '--foo', 'bar']);
467 468 469 470 471 472 473 474 475
      final List<String> commands = mockProcessManager.commands;
      expect(commands, hasLength(4));
      expect(commands[0], matches(r'dart-sdk[\\/]bin[\\/]pub'));
      expect(commands[1], 'run');
      expect(commands[2], '--foo');
      expect(commands[3], 'bar');
    }, overrides: <Type, Generator>{
      ProcessManager: () => mockProcessManager,
      Stdio: () => mockStdio,
476 477 478 479 480 481 482 483
      Pub: () => Pub(
        fileSystem: globals.fs,
        logger: globals.logger,
        processManager: globals.processManager,
        usage: globals.flutterUsage,
        botDetector: globals.botDetector,
        platform: globals.platform,
      ),
484 485
    });

486
    testUsingContext('pub publish', () async {
487
      final PromptingProcess process = PromptingProcess();
488
      mockProcessManager.processFactory = (List<String> commands) => process;
489
      final Future<void> runPackages = createTestCommandRunner(PackagesCommand()).run(<String>['pub', 'publish']);
490 491
      final Future<void> runPrompt = process.showPrompt('Proceed (y/n)? ', <String>['hello', 'world']);
      final Future<void> simulateUserInput = Future<void>(() {
492 493
        mockStdio.simulateStdin('y');
      });
494
      await Future.wait<void>(<Future<void>>[runPackages, runPrompt, simulateUserInput]);
495 496 497 498 499 500 501 502 503 504
      final List<String> commands = mockProcessManager.commands;
      expect(commands, hasLength(2));
      expect(commands[0], matches(r'dart-sdk[\\/]bin[\\/]pub'));
      expect(commands[1], 'publish');
      final List<String> stdout = mockStdio.writtenToStdout;
      expect(stdout, hasLength(4));
      expect(stdout.sublist(0, 2), contains('Proceed (y/n)? '));
      expect(stdout.sublist(0, 2), contains('y\n'));
      expect(stdout[2], 'hello\n');
      expect(stdout[3], 'world\n');
505
    }, overrides: <Type, Generator>{
506 507
      ProcessManager: () => mockProcessManager,
      Stdio: () => mockStdio,
508 509 510 511 512 513 514 515
      Pub: () => Pub(
        fileSystem: globals.fs,
        logger: globals.logger,
        processManager: globals.processManager,
        usage: globals.flutterUsage,
        botDetector: globals.botDetector,
        platform: globals.platform,
      ),
516
    });
517

518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535
    testUsingContext('pub publish input fails', () async {
      final PromptingProcess process = PromptingProcess(stdinError: true);
      mockProcessManager.processFactory = (List<String> commands) => process;
      final Future<void> runPackages = createTestCommandRunner(PackagesCommand()).run(<String>['pub', 'publish']);
      final Future<void> runPrompt = process.showPrompt('Proceed (y/n)? ', <String>['hello', 'world']);
      final Future<void> simulateUserInput = Future<void>(() {
        mockStdio.simulateStdin('y');
      });
      await Future.wait<void>(<Future<void>>[runPackages, runPrompt, simulateUserInput]);
      final List<String> commands = mockProcessManager.commands;
      expect(commands, hasLength(2));
      expect(commands[0], matches(r'dart-sdk[\\/]bin[\\/]pub'));
      expect(commands[1], 'publish');
      // We get a trace message about the write to stdin failing.
      expect(testLogger.traceText, contains('Echoing stdin to the pub subprocess failed'));
    }, overrides: <Type, Generator>{
      ProcessManager: () => mockProcessManager,
      Stdio: () => mockStdio,
536 537 538 539 540 541 542 543
      Pub: () => Pub(
        fileSystem: globals.fs,
        logger: globals.logger,
        processManager: globals.processManager,
        usage: globals.flutterUsage,
        botDetector: globals.botDetector,
        platform: globals.platform,
      ),
544 545
    });

546
    testUsingContext('publish', () async {
547
      await createTestCommandRunner(PackagesCommand()).run(<String>['pub', 'publish']);
548
      final List<String> commands = mockProcessManager.commands;
549
      expect(commands, hasLength(2));
550
      expect(commands[0], matches(r'dart-sdk[\\/]bin[\\/]pub'));
551 552 553 554 555
      expect(commands[1], 'publish');
    }, overrides: <Type, Generator>{
      ProcessManager: () => mockProcessManager,
      Stdio: () => mockStdio,
      BotDetector: () => const AlwaysTrueBotDetector(),
556 557 558 559 560 561 562 563
      Pub: () => Pub(
        fileSystem: globals.fs,
        logger: globals.logger,
        processManager: globals.processManager,
        usage: globals.flutterUsage,
        botDetector: globals.botDetector,
        platform: globals.platform,
      ),
564 565 566 567 568 569 570 571
    });

    testUsingContext('packages publish', () async {
      await createTestCommandRunner(PackagesCommand()).run(<String>['packages', 'pub', 'publish']);
      final List<String> commands = mockProcessManager.commands;
      expect(commands, hasLength(2));
      expect(commands[0], matches(r'dart-sdk[\\/]bin[\\/]pub'));
      expect(commands[1], 'publish');
572 573 574 575
    }, overrides: <Type, Generator>{
      ProcessManager: () => mockProcessManager,
      Stdio: () => mockStdio,
      BotDetector: () => const AlwaysTrueBotDetector(),
576 577 578 579 580 581 582 583
      Pub: () => Pub(
        fileSystem: globals.fs,
        logger: globals.logger,
        processManager: globals.processManager,
        usage: globals.flutterUsage,
        botDetector: globals.botDetector,
        platform: globals.platform,
      ),
584 585 586 587 588
    });

    testUsingContext('deps', () async {
      await createTestCommandRunner(PackagesCommand()).run(<String>['packages', 'deps']);
      final List<String> commands = mockProcessManager.commands;
589
      expect(commands, hasLength(2));
590
      expect(commands[0], matches(r'dart-sdk[\\/]bin[\\/]pub'));
591
      expect(commands[1], 'deps');
592 593 594 595
    }, overrides: <Type, Generator>{
      ProcessManager: () => mockProcessManager,
      Stdio: () => mockStdio,
      BotDetector: () => const AlwaysTrueBotDetector(),
596 597 598 599 600 601 602 603
      Pub: () => Pub(
        fileSystem: globals.fs,
        logger: globals.logger,
        processManager: globals.processManager,
        usage: globals.flutterUsage,
        botDetector: globals.botDetector,
        platform: globals.platform,
      ),
604 605 606 607 608
    });

    testUsingContext('cache', () async {
      await createTestCommandRunner(PackagesCommand()).run(<String>['packages', 'cache']);
      final List<String> commands = mockProcessManager.commands;
609
      expect(commands, hasLength(2));
610
      expect(commands[0], matches(r'dart-sdk[\\/]bin[\\/]pub'));
611
      expect(commands[1], 'cache');
612 613 614 615
    }, overrides: <Type, Generator>{
      ProcessManager: () => mockProcessManager,
      Stdio: () => mockStdio,
      BotDetector: () => const AlwaysTrueBotDetector(),
616 617 618 619 620 621 622 623
      Pub: () => Pub(
        fileSystem: globals.fs,
        logger: globals.logger,
        processManager: globals.processManager,
        usage: globals.flutterUsage,
        botDetector: globals.botDetector,
        platform: globals.platform,
      ),
624 625 626 627 628
    });

    testUsingContext('version', () async {
      await createTestCommandRunner(PackagesCommand()).run(<String>['packages', 'version']);
      final List<String> commands = mockProcessManager.commands;
629
      expect(commands, hasLength(2));
630
      expect(commands[0], matches(r'dart-sdk[\\/]bin[\\/]pub'));
631
      expect(commands[1], 'version');
632 633 634 635
    }, overrides: <Type, Generator>{
      ProcessManager: () => mockProcessManager,
      Stdio: () => mockStdio,
      BotDetector: () => const AlwaysTrueBotDetector(),
636 637 638 639 640 641 642 643
      Pub: () => Pub(
        fileSystem: globals.fs,
        logger: globals.logger,
        processManager: globals.processManager,
        usage: globals.flutterUsage,
        botDetector: globals.botDetector,
        platform: globals.platform,
      ),
644 645 646 647 648
    });

    testUsingContext('uploader', () async {
      await createTestCommandRunner(PackagesCommand()).run(<String>['packages', 'uploader']);
      final List<String> commands = mockProcessManager.commands;
649
      expect(commands, hasLength(2));
650
      expect(commands[0], matches(r'dart-sdk[\\/]bin[\\/]pub'));
651
      expect(commands[1], 'uploader');
652 653 654 655
    }, overrides: <Type, Generator>{
      ProcessManager: () => mockProcessManager,
      Stdio: () => mockStdio,
      BotDetector: () => const AlwaysTrueBotDetector(),
656 657 658 659 660 661 662 663
      Pub: () => Pub(
        fileSystem: globals.fs,
        logger: globals.logger,
        processManager: globals.processManager,
        usage: globals.flutterUsage,
        botDetector: globals.botDetector,
        platform: globals.platform,
      ),
664 665 666 667 668
    });

    testUsingContext('global', () async {
      await createTestCommandRunner(PackagesCommand()).run(<String>['packages', 'global', 'list']);
      final List<String> commands = mockProcessManager.commands;
669
      expect(commands, hasLength(3));
670
      expect(commands[0], matches(r'dart-sdk[\\/]bin[\\/]pub'));
671 672
      expect(commands[1], 'global');
      expect(commands[2], 'list');
673 674 675 676
    }, overrides: <Type, Generator>{
      ProcessManager: () => mockProcessManager,
      Stdio: () => mockStdio,
      BotDetector: () => const AlwaysTrueBotDetector(),
677 678 679 680 681 682 683 684
      Pub: () => Pub(
        fileSystem: globals.fs,
        logger: globals.logger,
        processManager: globals.processManager,
        usage: globals.flutterUsage,
        botDetector: globals.botDetector,
        platform: globals.platform,
      ),
685
    });
686 687 688 689 690 691 692 693 694 695 696

    testUsingContext('outdated', () async {
      await createTestCommandRunner(PackagesCommand()).run(<String>['packages', 'outdated']);
      final List<String> commands = mockProcessManager.commands;
      expect(commands, hasLength(2));
      expect(commands[0], matches(r'dart-sdk[\\/]bin[\\/]pub'));
      expect(commands[1], 'outdated');
    }, overrides: <Type, Generator>{
      ProcessManager: () => mockProcessManager,
      Stdio: () => mockStdio,
      BotDetector: () => const AlwaysTrueBotDetector(),
697 698 699 700 701 702 703 704
      Pub: () => Pub(
        fileSystem: globals.fs,
        logger: globals.logger,
        processManager: globals.processManager,
        usage: globals.flutterUsage,
        botDetector: globals.botDetector,
        platform: globals.platform,
      ),
705
    });
706 707
  });
}