[flutter_plugin_tools] Run pub get for custom-test (#5322)

When running a Dart test script for `custom-test`, `pub get` needs to be
run first in order for it to work in a clean environment such as CI.

This will unblock enabling Pigeon's Dart tests in flutter/packages.
diff --git a/script/tool/CHANGELOG.md b/script/tool/CHANGELOG.md
index 6e632c6..367f258 100644
--- a/script/tool/CHANGELOG.md
+++ b/script/tool/CHANGELOG.md
@@ -1,10 +1,11 @@
-## NEXT
+## 0.8.2+1
 
 - Adds a new `readme-check` command.
 - Updates `publish-plugin` command documentation.
 - Fixes `all-plugins-app` to preserve the original application's Dart SDK
   version to avoid changing language feature opt-ins that the template may
   rely on.
+- Fixes `custom-test` to run `pub get` before running Dart test scripts.
 
 ## 0.8.2
 
diff --git a/script/tool/lib/src/custom_test_command.dart b/script/tool/lib/src/custom_test_command.dart
index 1c1dfc0..cd9ac32 100644
--- a/script/tool/lib/src/custom_test_command.dart
+++ b/script/tool/lib/src/custom_test_command.dart
@@ -43,10 +43,19 @@
 
     // Run the custom Dart script if presest.
     if (script.existsSync()) {
-      final int exitCode = await processRunner.runAndStream(
+      // Ensure that dependencies are available.
+      final int pubGetExitCode = await processRunner.runAndStream(
+          'dart', <String>['pub', 'get'],
+          workingDir: package.directory);
+      if (pubGetExitCode != 0) {
+        return PackageResult.fail(
+            <String>['Unable to get script dependencies']);
+      }
+
+      final int testExitCode = await processRunner.runAndStream(
           'dart', <String>['run', 'tool/$_scriptName'],
           workingDir: package.directory);
-      if (exitCode != 0) {
+      if (testExitCode != 0) {
         return PackageResult.fail();
       }
       ranTests = true;
diff --git a/script/tool/pubspec.yaml b/script/tool/pubspec.yaml
index f005c56..14b22a1 100644
--- a/script/tool/pubspec.yaml
+++ b/script/tool/pubspec.yaml
@@ -1,7 +1,7 @@
 name: flutter_plugin_tools
 description: Productivity utils for flutter/plugins and flutter/packages
 repository: https://github.com/flutter/plugins/tree/main/script/tool
-version: 0.8.2
+version: 0.8.2+1
 
 dependencies:
   args: ^2.1.0
diff --git a/script/tool/test/custom_test_command_test.dart b/script/tool/test/custom_test_command_test.dart
index 6a34c26..bc30d9a 100644
--- a/script/tool/test/custom_test_command_test.dart
+++ b/script/tool/test/custom_test_command_test.dart
@@ -85,6 +85,21 @@
           ]));
     });
 
+    test('runs pub get before running Dart test script', () async {
+      final Directory package = createFakePlugin('a_package', packagesDir,
+          extraFiles: <String>['tool/run_tests.dart']);
+
+      await runCapturingPrint(runner, <String>['custom-test']);
+
+      expect(
+          processRunner.recordedCalls,
+          containsAll(<ProcessCall>[
+            ProcessCall('dart', const <String>['pub', 'get'], package.path),
+            ProcessCall('dart', const <String>['run', 'tool/run_tests.dart'],
+                package.path),
+          ]));
+    });
+
     test('runs when only legacy is present', () async {
       final Directory package = createFakePlugin('a_package', packagesDir,
           extraFiles: <String>['run_tests.sh']);
@@ -128,7 +143,8 @@
       ]);
 
       processRunner.mockProcessesForExecutable['dart'] = <io.Process>[
-        MockProcess(exitCode: 1),
+        MockProcess(exitCode: 0), // pub get
+        MockProcess(exitCode: 1), // test script
       ];
 
       Error? commandError;
@@ -146,6 +162,32 @@
           ]));
     });
 
+    test('fails if pub get fails', () async {
+      createFakePlugin('a_package', packagesDir, extraFiles: <String>[
+        'tool/run_tests.dart',
+        'run_tests.sh',
+      ]);
+
+      processRunner.mockProcessesForExecutable['dart'] = <io.Process>[
+        MockProcess(exitCode: 1),
+      ];
+
+      Error? commandError;
+      final List<String> output = await runCapturingPrint(
+          runner, <String>['custom-test'], errorHandler: (Error e) {
+        commandError = e;
+      });
+
+      expect(commandError, isA<ToolExit>());
+      expect(
+          output,
+          containsAllInOrder(<Matcher>[
+            contains('The following packages had errors:'),
+            contains('a_package:\n'
+                '    Unable to get script dependencies')
+          ]));
+    });
+
     test('fails if legacy fails', () async {
       final Directory package =
           createFakePlugin('a_package', packagesDir, extraFiles: <String>[
@@ -260,7 +302,8 @@
       ]);
 
       processRunner.mockProcessesForExecutable['dart'] = <io.Process>[
-        MockProcess(exitCode: 1),
+        MockProcess(exitCode: 0), // pub get
+        MockProcess(exitCode: 1), // test script
       ];
 
       Error? commandError;