Introducing command-line interface tests (#3161)

* Introducing --help tests

* cleanup some tests

* Update golden files

* Refactored logic for golden tests
diff --git a/test/cache/add/bad_version_test.dart b/test/cache/add/bad_version_test.dart
index e0a57e0..8d5d2e1 100644
--- a/test/cache/add/bad_version_test.dart
+++ b/test/cache/add/bad_version_test.dart
@@ -11,16 +11,10 @@
 
 void main() {
   test('fails if the version constraint cannot be parsed', () {
-    return runPub(args: ['cache', 'add', 'foo', '-v', '1.0'], error: '''
-            Could not parse version "1.0". Unknown text at "1.0".
-            
-            Usage: pub cache add <package> [--version <constraint>] [--all]
-            -h, --help       Print this usage information.
-                --all        Install all matching versions.
-            -v, --version    Version constraint.
-
-            Run "pub help" to see global options.
-            See https://dart.dev/tools/pub/cmd/pub-cache for detailed documentation.
-            ''', exitCode: exit_codes.USAGE);
+    return runPub(
+      args: ['cache', 'add', 'foo', '-v', '1.0'],
+      error: contains('Could not parse version "1.0". Unknown text at "1.0".'),
+      exitCode: exit_codes.USAGE,
+    );
   });
 }
diff --git a/test/cache/add/missing_package_arg_test.dart b/test/cache/add/missing_package_arg_test.dart
index 2274992..426b0d8 100644
--- a/test/cache/add/missing_package_arg_test.dart
+++ b/test/cache/add/missing_package_arg_test.dart
@@ -11,16 +11,10 @@
 
 void main() {
   test('fails if no package was given', () {
-    return runPub(args: ['cache', 'add'], error: '''
-            No package to add given.
-            
-            Usage: pub cache add <package> [--version <constraint>] [--all]
-            -h, --help       Print this usage information.
-                --all        Install all matching versions.
-            -v, --version    Version constraint.
-
-            Run "pub help" to see global options.
-            See https://dart.dev/tools/pub/cmd/pub-cache for detailed documentation.
-            ''', exitCode: exit_codes.USAGE);
+    return runPub(
+      args: ['cache', 'add'],
+      error: contains('No package to add given.'),
+      exitCode: exit_codes.USAGE,
+    );
   });
 }
diff --git a/test/cache/add/unexpected_arguments_test.dart b/test/cache/add/unexpected_arguments_test.dart
index 66174db..7ec0f30 100644
--- a/test/cache/add/unexpected_arguments_test.dart
+++ b/test/cache/add/unexpected_arguments_test.dart
@@ -11,16 +11,10 @@
 
 void main() {
   test('fails if there are extra arguments', () {
-    return runPub(args: ['cache', 'add', 'foo', 'bar', 'baz'], error: '''
-            Unexpected arguments "bar" and "baz".
-            
-            Usage: pub cache add <package> [--version <constraint>] [--all]
-            -h, --help       Print this usage information.
-                --all        Install all matching versions.
-            -v, --version    Version constraint.
-
-            Run "pub help" to see global options.
-            See https://dart.dev/tools/pub/cmd/pub-cache for detailed documentation.
-            ''', exitCode: exit_codes.USAGE);
+    return runPub(
+      args: ['cache', 'add', 'foo', 'bar', 'baz'],
+      error: contains('Unexpected arguments "bar" and "baz".'),
+      exitCode: exit_codes.USAGE,
+    );
   });
 }
diff --git a/test/deps/executables_test.dart b/test/deps/executables_test.dart
index f568511..978cc24 100644
--- a/test/deps/executables_test.dart
+++ b/test/deps/executables_test.dart
@@ -4,11 +4,6 @@
 
 // @dart=2.10
 
-import 'package:pub/src/ascii_tree.dart' as tree;
-import 'package:pub/src/io.dart';
-import 'package:test/test.dart';
-
-import '../ascii_tree_test.dart';
 import '../descriptor.dart' as d;
 import '../golden_file.dart';
 import '../test_pub.dart';
@@ -16,31 +11,29 @@
 const _validMain = 'main() {}';
 const _invalidMain = 'main() {';
 
-Future<void> variations(String name) async {
-  final buffer = StringBuffer();
-  buffer.writeln(stripColors(
-      tree.fromFiles(listDir(d.sandbox, recursive: true), baseDir: d.sandbox)));
+extension on GoldenTestContext {
+  Future<void> runExecutablesTest() async {
+    await pubGet();
 
-  await pubGet();
-  await runPubIntoBuffer(['deps', '--executables'], buffer);
-  await runPubIntoBuffer(['deps', '--executables', '--dev'], buffer);
-  // The json ouput also lists the exectuables.
-  await runPubIntoBuffer(['deps', '--json'], buffer);
-  // The easiest way to update the golden files is to delete them and rerun the
-  // test.
-  expectMatchesGoldenFile(buffer.toString(), 'test/deps/goldens/$name.txt');
+    await tree();
+
+    await run(['deps', '--executables']);
+    await run(['deps', '--executables', '--dev']);
+    await run(['deps', '--json']);
+  }
 }
 
 void main() {
-  test('skips non-Dart executables', () async {
+  testWithGolden('skips non-Dart executables', (ctx) async {
     await d.dir(appPath, [
       d.appPubspec(),
       d.dir('bin', [d.file('foo.py'), d.file('bar.sh')])
     ]).create();
-    await variations('non_dart_executables');
+
+    await ctx.runExecutablesTest();
   });
 
-  test('lists Dart executables, even without entrypoints', () async {
+  testWithGolden('lists Dart executables, without entrypoints', (ctx) async {
     await d.dir(appPath, [
       d.appPubspec(),
       d.dir(
@@ -48,10 +41,11 @@
         [d.file('foo.dart', _validMain), d.file('bar.dart', _invalidMain)],
       )
     ]).create();
-    await variations('dart_executables');
+
+    await ctx.runExecutablesTest();
   });
 
-  test('skips executables in sub directories', () async {
+  testWithGolden('skips executables in sub directories', (ctx) async {
     await d.dir(appPath, [
       d.appPubspec(),
       d.dir('bin', [
@@ -59,10 +53,11 @@
         d.dir('sub', [d.file('bar.dart', _validMain)])
       ])
     ]).create();
-    await variations('nothing_in_sub_drectories');
+
+    await ctx.runExecutablesTest();
   });
 
-  test('lists executables from a dependency', () async {
+  testWithGolden('lists executables from a dependency', (ctx) async {
     await d.dir('foo', [
       d.libPubspec('foo', '1.0.0'),
       d.dir('bin', [d.file('bar.dart', _validMain)])
@@ -74,10 +69,11 @@
       })
     ]).create();
 
-    await variations('from_dependency');
+    await ctx.runExecutablesTest();
   });
 
-  test('lists executables only from immediate dependencies', () async {
+  testWithGolden('lists executables only from immediate dependencies',
+      (ctx) async {
     await d.dir(appPath, [
       d.appPubspec({
         'foo': {'path': '../foo'}
@@ -96,10 +92,10 @@
       d.dir('bin', [d.file('qux.dart', _validMain)])
     ]).create();
 
-    await variations('only_immediate');
+    await ctx.runExecutablesTest();
   });
 
-  test('applies formatting before printing executables', () async {
+  testWithGolden('applies formatting before printing executables', (ctx) async {
     await d.dir(appPath, [
       d.appPubspec({
         'foo': {'path': '../foo'},
@@ -119,10 +115,10 @@
       d.dir('bin', [d.file('qux.dart', _validMain)])
     ]).create();
 
-    await variations('formatting');
+    await ctx.runExecutablesTest();
   });
 
-  test('dev dependencies', () async {
+  testWithGolden('dev dependencies', (ctx) async {
     await d.dir('foo', [
       d.libPubspec('foo', '1.0.0'),
       d.dir('bin', [d.file('bar.dart', _validMain)])
@@ -136,10 +132,11 @@
         }
       })
     ]).create();
-    await variations('dev_dependencies');
+
+    await ctx.runExecutablesTest();
   });
 
-  test('overriden dependencies executables', () async {
+  testWithGolden('overriden dependencies executables', (ctx) async {
     await d.dir('foo-1.0', [
       d.libPubspec('foo', '1.0.0'),
       d.dir('bin', [d.file('bar.dart', _validMain)])
@@ -162,6 +159,7 @@
         }
       })
     ]).create();
-    await variations('overrides');
+
+    await ctx.runExecutablesTest();
   });
 }
diff --git a/test/directory_option_test.dart b/test/directory_option_test.dart
index c993200..541ddd4 100644
--- a/test/directory_option_test.dart
+++ b/test/directory_option_test.dart
@@ -8,14 +8,14 @@
 
 import 'package:path/path.dart' as p;
 import 'package:shelf/shelf.dart' as shelf;
-import 'package:test/test.dart';
 
 import 'descriptor.dart';
 import 'golden_file.dart';
 import 'test_pub.dart';
 
 Future<void> main() async {
-  test('commands taking a --directory/-C parameter work', () async {
+  testWithGolden('commands taking a --directory/-C parameter work',
+      (ctx) async {
     await servePackages((b) => b
       ..serve('foo', '1.0.0')
       ..serve('foo', '0.1.2')
@@ -24,10 +24,11 @@
     globalPackageServer
         .extraHandlers[RegExp('/api/packages/test_pkg/uploaders')] = (request) {
       return shelf.Response.ok(
-          jsonEncode({
-            'success': {'message': 'Good job!'}
-          }),
-          headers: {'content-type': 'application/json'});
+        jsonEncode({
+          'success': {'message': 'Good job!'}
+        }),
+        headers: {'content-type': 'application/json'},
+      );
     };
 
     await validPackage.create();
@@ -56,42 +57,34 @@
         })
       ]),
     ]).create();
-    final buffer = StringBuffer();
-    Future<void> run(List<String> args) async {
-      await runPubIntoBuffer(
-        args,
-        buffer,
+
+    final cases = [
+      // Try --directory after command.
+      ['add', '--directory=$appPath', 'foo'],
+      // Try the top-level version also.
+      ['-C', appPath, 'add', 'bar'],
+      // When both top-level and after command, the one after command takes
+      // precedence.
+      ['-C', p.join(appPath, 'example'), 'get', '--directory=$appPath', 'bar'],
+      ['remove', 'bar', '-C', appPath],
+      ['get', 'bar', '-C', appPath],
+      ['get', 'bar', '-C', '$appPath/example'],
+      ['get', 'bar', '-C', '$appPath/example2'],
+      ['get', 'bar', '-C', '$appPath/broken_dir'],
+      ['downgrade', '-C', appPath],
+      ['upgrade', 'bar', '-C', appPath],
+      ['run', '-C', appPath, 'bin/app.dart'],
+      ['publish', '-C', appPath, '--dry-run'],
+      ['uploader', '-C', appPath, 'add', 'sigurdm@google.com'],
+      ['deps', '-C', appPath],
+    ];
+
+    for (var i = 0; i < cases.length; i++) {
+      await ctx.run(
+        cases[i],
         workingDirectory: sandbox,
         environment: {'_PUB_TEST_SDK_VERSION': '1.12.0'},
       );
     }
-
-    await run(['add', '--directory=$appPath', 'foo']);
-    // Try the top-level version also.
-    await run(['-C', appPath, 'add', 'bar']);
-    // When both top-level and after command, the one after command takes
-    // precedence.
-    await run([
-      '-C',
-      p.join(appPath, 'example'),
-      'get',
-      '--directory=$appPath',
-      'bar',
-    ]);
-    await run(['remove', 'bar', '-C', appPath]);
-    await run(['get', 'bar', '-C', appPath]);
-    await run(['get', 'bar', '-C', '$appPath/example']);
-    await run(['get', 'bar', '-C', '$appPath/example2']);
-    await run(['get', 'bar', '-C', '$appPath/broken_dir']);
-    await run(['downgrade', '-C', appPath]);
-    await run(['upgrade', 'bar', '-C', appPath]);
-    await run(['run', '-C', appPath, 'bin/app.dart']);
-    await run(['publish', '-C', appPath, '--dry-run']);
-    await run(['uploader', '-C', appPath, 'add', 'sigurdm@google.com']);
-    await run(['deps', '-C', appPath]);
-    // TODO(sigurdm): we should also test `list-package-dirs` - it is a bit
-    // hard on windows due to quoted back-slashes on windows.
-    expectMatchesGoldenFile(
-        buffer.toString(), 'test/goldens/directory_option.txt');
   });
 }
diff --git a/test/embedding/embedding_test.dart b/test/embedding/embedding_test.dart
index dbe6c89..b5cf8bd 100644
--- a/test/embedding/embedding_test.dart
+++ b/test/embedding/embedding_test.dart
@@ -19,10 +19,13 @@
 String snapshot;
 
 /// Runs `dart tool/test-bin/pub_command_runner.dart [args]` and appends the output to [buffer].
-Future<void> runEmbedding(List<String> args, StringBuffer buffer,
-    {String workingDirextory,
-    Map<String, String> environment,
-    dynamic exitCode = 0}) async {
+Future<void> runEmbeddingToBuffer(
+  List<String> args,
+  StringBuffer buffer, {
+  String workingDirextory,
+  Map<String, String> environment,
+  dynamic exitCode = 0,
+}) async {
   final process = await TestProcess.start(
     Platform.resolvedExecutable,
     ['--enable-asserts', snapshot, ...args],
@@ -45,6 +48,28 @@
   buffer.write('\n');
 }
 
+extension on GoldenTestContext {
+  /// Runs `dart tool/test-bin/pub_command_runner.dart [args]` and compare to
+  /// next section in golden file.
+  Future<void> runEmbedding(
+    List<String> args, {
+    String workingDirextory,
+    Map<String, String> environment,
+    dynamic exitCode = 0,
+  }) async {
+    final buffer = StringBuffer();
+    await runEmbeddingToBuffer(
+      args,
+      buffer,
+      workingDirextory: workingDirextory,
+      environment: environment,
+      exitCode: exitCode,
+    );
+
+    expectNextSection(buffer.toString());
+  }
+}
+
 Future<void> main() async {
   setUpAll(() async {
     final tempDir = Directory.systemTemp.createTempSync();
@@ -57,20 +82,8 @@
   tearDownAll(() {
     File(snapshot).parent.deleteSync(recursive: true);
   });
-  test('help text', () async {
-    final buffer = StringBuffer();
-    await runEmbedding([''], buffer, exitCode: 64);
-    await runEmbedding(['--help'], buffer);
-    await runEmbedding(['pub'], buffer, exitCode: 64);
-    await runEmbedding(['pub', '--help'], buffer);
-    await runEmbedding(['pub', 'get', '--help'], buffer);
-    await runEmbedding(['pub', 'global'], buffer, exitCode: 64);
-    expectMatchesGoldenFile(
-        buffer.toString(), 'test/embedding/goldens/helptext.txt');
-  });
 
-  test('run works, though hidden', () async {
-    final buffer = StringBuffer();
+  testWithGolden('run works, though hidden', (ctx) async {
     await d.dir(appPath, [
       d.pubspec({
         'name': 'myapp',
@@ -88,21 +101,15 @@
 ''')
       ]),
     ]).create();
-    await runEmbedding(
+    await ctx.runEmbedding(
       ['pub', 'get'],
-      buffer,
       workingDirextory: d.path(appPath),
     );
-    await runEmbedding(
+    await ctx.runEmbedding(
       ['pub', 'run', 'bin/main.dart'],
-      buffer,
       exitCode: 123,
       workingDirextory: d.path(appPath),
     );
-    expectMatchesGoldenFile(
-      buffer.toString(),
-      'test/embedding/goldens/run.txt',
-    );
   });
 
   test('analytics', () async {
@@ -126,7 +133,7 @@
 
     final buffer = StringBuffer();
 
-    await runEmbedding(
+    await runEmbeddingToBuffer(
       ['pub', 'get'],
       buffer,
       workingDirextory: app.io.path,
diff --git a/test/embedding/goldens/helptext.txt b/test/embedding/goldens/helptext.txt
deleted file mode 100644
index b5c206f..0000000
--- a/test/embedding/goldens/helptext.txt
+++ /dev/null
@@ -1,113 +0,0 @@
-$ tool/test-bin/pub_command_runner.dart 
-[E] Could not find a command named "".
-[E] 
-[E] Usage: pub_command_runner <command> [arguments]
-[E] 
-[E] Global options:
-[E] -h, --help    Print this usage information.
-[E] 
-[E] Available commands:
-[E]   pub   Work with packages.
-[E] 
-[E] Run "pub_command_runner help <command>" for more information about a command.
-
-$ tool/test-bin/pub_command_runner.dart --help
-Tests the embeddable pub command.
-
-Usage: pub_command_runner <command> [arguments]
-
-Global options:
--h, --help    Print this usage information.
-
-Available commands:
-  pub   Work with packages.
-
-Run "pub_command_runner help <command>" for more information about a command.
-
-$ tool/test-bin/pub_command_runner.dart pub
-[E] Missing subcommand for "pub_command_runner pub".
-[E] 
-[E] Usage: pub_command_runner pub [arguments...]
-[E] -h, --help               Print this usage information.
-[E]     --[no-]trace         Print debugging information when an error occurs.
-[E] -v, --verbose            Shortcut for "--verbosity=all".
-[E] -C, --directory=<dir>    Run the subcommand in the directory<dir>.
-[E]                          (defaults to ".")
-[E] 
-[E] Available subcommands:
-[E]   add         Add a dependency to pubspec.yaml.
-[E]   cache       Work with the system cache.
-[E]   deps        Print package dependencies.
-[E]   downgrade   Downgrade the current package's dependencies to oldest versions.
-[E]   get         Get the current package's dependencies.
-[E]   global      Work with global packages.
-[E]   login       Log into pub.dev.
-[E]   logout      Log out of pub.dev.
-[E]   outdated    Analyze your dependencies to find which ones can be upgraded.
-[E]   publish     Publish the current package to pub.dartlang.org.
-[E]   remove      Removes a dependency from the current package.
-[E]   token       Manage authentication tokens for hosted pub repositories.
-[E]   upgrade     Upgrade the current package's dependencies to latest versions.
-[E]   uploader    Manage uploaders for a package on pub.dartlang.org.
-[E] 
-[E] Run "pub_command_runner help" to see global options.
-[E] See https://dart.dev/tools/pub/cmd/pub-global for detailed documentation.
-
-$ tool/test-bin/pub_command_runner.dart pub --help
-Work with packages.
-
-Usage: pub_command_runner pub [arguments...]
--h, --help               Print this usage information.
-    --[no-]trace         Print debugging information when an error occurs.
--v, --verbose            Shortcut for "--verbosity=all".
--C, --directory=<dir>    Run the subcommand in the directory<dir>.
-                         (defaults to ".")
-
-Available subcommands:
-  add         Add a dependency to pubspec.yaml.
-  cache       Work with the system cache.
-  deps        Print package dependencies.
-  downgrade   Downgrade the current package's dependencies to oldest versions.
-  get         Get the current package's dependencies.
-  global      Work with global packages.
-  login       Log into pub.dev.
-  logout      Log out of pub.dev.
-  outdated    Analyze your dependencies to find which ones can be upgraded.
-  publish     Publish the current package to pub.dartlang.org.
-  remove      Removes a dependency from the current package.
-  token       Manage authentication tokens for hosted pub repositories.
-  upgrade     Upgrade the current package's dependencies to latest versions.
-  uploader    Manage uploaders for a package on pub.dartlang.org.
-
-Run "pub_command_runner help" to see global options.
-See https://dart.dev/tools/pub/cmd/pub-global for detailed documentation.
-
-$ tool/test-bin/pub_command_runner.dart pub get --help
-Get the current package's dependencies.
-
-Usage: pub_command_runner pub get <subcommand> [arguments...]
--h, --help               Print this usage information.
-    --[no-]offline       Use cached packages instead of accessing the network.
--n, --dry-run            Report what dependencies would change but don't change
-                         any.
-    --[no-]precompile    Build executables in immediate dependencies.
--C, --directory=<dir>    Run this in the directory<dir>.
-
-Run "pub_command_runner help" to see global options.
-See https://dart.dev/tools/pub/cmd/pub-get for detailed documentation.
-
-$ tool/test-bin/pub_command_runner.dart pub global
-[E] Missing subcommand for "pub_command_runner pub global".
-[E] 
-[E] Usage: pub_command_runner pub global [arguments...]
-[E] -h, --help    Print this usage information.
-[E] 
-[E] Available subcommands:
-[E]   activate     Make a package's executables globally available.
-[E]   deactivate   Remove a previously activated package.
-[E]   list         List globally activated packages.
-[E]   run          Run an executable from a globally activated package.
-[E] 
-[E] Run "pub_command_runner help" to see global options.
-[E] See https://dart.dev/tools/pub/cmd/pub-global for detailed documentation.
-
diff --git a/test/global/activate/missing_package_arg_test.dart b/test/global/activate/missing_package_arg_test.dart
index 5923bd9..0b747af 100644
--- a/test/global/activate/missing_package_arg_test.dart
+++ b/test/global/activate/missing_package_arg_test.dart
@@ -12,8 +12,9 @@
 void main() {
   test('fails if no package was given', () {
     return runPub(
-        args: ['global', 'activate'],
-        error: contains('No package to activate given.'),
-        exitCode: exit_codes.USAGE);
+      args: ['global', 'activate'],
+      error: contains('No package to activate given.'),
+      exitCode: exit_codes.USAGE,
+    );
   });
 }
diff --git a/test/global/deactivate/missing_package_arg_test.dart b/test/global/deactivate/missing_package_arg_test.dart
index 7d41b82..6671991 100644
--- a/test/global/deactivate/missing_package_arg_test.dart
+++ b/test/global/deactivate/missing_package_arg_test.dart
@@ -11,13 +11,10 @@
 
 void main() {
   test('fails if no package was given', () {
-    return runPub(args: ['global', 'deactivate'], error: '''
-            No package to deactivate given.
-
-            Usage: pub global deactivate <package>
-            -h, --help    Print this usage information.
-
-            Run "pub help" to see global options.
-            ''', exitCode: exit_codes.USAGE);
+    return runPub(
+      args: ['global', 'deactivate'],
+      error: contains('No package to deactivate given.'),
+      exitCode: exit_codes.USAGE,
+    );
   });
 }
diff --git a/test/global/deactivate/unexpected_arguments_test.dart b/test/global/deactivate/unexpected_arguments_test.dart
index d5748f2..426b7f8 100644
--- a/test/global/deactivate/unexpected_arguments_test.dart
+++ b/test/global/deactivate/unexpected_arguments_test.dart
@@ -12,13 +12,9 @@
 void main() {
   test('fails if there are extra arguments', () {
     return runPub(
-        args: ['global', 'deactivate', 'foo', 'bar', 'baz'], error: '''
-            Unexpected arguments "bar" and "baz".
-
-            Usage: pub global deactivate <package>
-            -h, --help    Print this usage information.
-
-            Run "pub help" to see global options.
-            ''', exitCode: exit_codes.USAGE);
+      args: ['global', 'deactivate', 'foo', 'bar', 'baz'],
+      error: contains('Unexpected arguments "bar" and "baz".'),
+      exitCode: exit_codes.USAGE,
+    );
   });
 }
diff --git a/test/global/run/errors_if_outside_bin_test.dart b/test/global/run/errors_if_outside_bin_test.dart
index 497f26a..e6c15f7 100644
--- a/test/global/run/errors_if_outside_bin_test.dart
+++ b/test/global/run/errors_if_outside_bin_test.dart
@@ -19,20 +19,11 @@
     });
 
     await runPub(args: ['global', 'activate', 'foo']);
-    await runPub(args: ['global', 'run', 'foo:example/script'], error: '''
-Cannot run an executable in a subdirectory of a global package.
-
-Usage: pub global run <package>:<executable> [args...]
--h, --help                              Print this usage information.
-    --[no-]enable-asserts               Enable assert statements.
-    --enable-experiment=<experiment>    Runs the executable in a VM with the
-                                        given experiments enabled. (Will disable
-                                        snapshotting, resulting in slower
-                                        startup).
-    --[no-]sound-null-safety            Override the default null safety
-                                        execution mode.
-
-Run "pub help" to see global options.
-''', exitCode: exit_codes.USAGE);
+    await runPub(
+      args: ['global', 'run', 'foo:example/script'],
+      error: contains(
+          'Cannot run an executable in a subdirectory of a global package.'),
+      exitCode: exit_codes.USAGE,
+    );
   });
 }
diff --git a/test/global/run/missing_executable_arg_test.dart b/test/global/run/missing_executable_arg_test.dart
index 2bb8ec8..efab258 100644
--- a/test/global/run/missing_executable_arg_test.dart
+++ b/test/global/run/missing_executable_arg_test.dart
@@ -11,20 +11,10 @@
 
 void main() {
   test('fails if no executable was given', () {
-    return runPub(args: ['global', 'run'], error: '''
-Must specify an executable to run.
-
-Usage: pub global run <package>:<executable> [args...]
--h, --help                              Print this usage information.
-    --[no-]enable-asserts               Enable assert statements.
-    --enable-experiment=<experiment>    Runs the executable in a VM with the
-                                        given experiments enabled. (Will disable
-                                        snapshotting, resulting in slower
-                                        startup).
-    --[no-]sound-null-safety            Override the default null safety
-                                        execution mode.
-
-Run "pub help" to see global options.
-''', exitCode: exit_codes.USAGE);
+    return runPub(
+      args: ['global', 'run'],
+      error: contains('Must specify an executable to run.'),
+      exitCode: exit_codes.USAGE,
+    );
   });
 }
diff --git a/test/golden_file.dart b/test/golden_file.dart
index 055c5c5..90d2340 100644
--- a/test/golden_file.dart
+++ b/test/golden_file.dart
@@ -4,33 +4,210 @@
 
 // @dart=2.10
 
+import 'dart:async';
 import 'dart:io';
 
-import 'package:path/path.dart' as path;
+import 'package:path/path.dart' as p;
+import 'package:pub/src/ascii_tree.dart' as ascii_tree;
+import 'package:pub/src/io.dart';
+import 'package:stack_trace/stack_trace.dart' show Trace;
 import 'package:test/test.dart';
 
-/// Will test [actual] against the contests of the file at [goldenFilePath].
-///
-/// If the file doesn't exist, the file is instead created containing [actual].
-void expectMatchesGoldenFile(String actual, String goldenFilePath) {
-  var goldenFile = File(goldenFilePath);
-  if (goldenFile.existsSync()) {
-    expect(
-        actual, equals(goldenFile.readAsStringSync().replaceAll('\r\n', '\n')),
-        reason: 'goldenFilePath: "$goldenFilePath"');
-  } else {
-    // This enables writing the updated file when run in otherwise hermetic
-    // settings.
-    //
-    // This is to make updating the golden files easier in a bazel environment
-    // See https://docs.bazel.build/versions/2.0.0/user-manual.html#run .
-    final workspaceDirectory =
-        Platform.environment['BUILD_WORKSPACE_DIRECTORY'];
-    if (workspaceDirectory != null) {
-      goldenFile = File(path.join(workspaceDirectory, goldenFilePath));
-    }
-    goldenFile
-      ..createSync(recursive: true)
-      ..writeAsStringSync(actual);
+import 'ascii_tree_test.dart';
+import 'descriptor.dart' as d;
+import 'test_pub.dart';
+
+final _isCI = () {
+  final p = RegExp(r'^1|(?:true)$', caseSensitive: false);
+  final ci = Platform.environment['CI'];
+  return ci != null && ci.isNotEmpty && p.hasMatch(ci);
+}();
+
+/// Find the current `_test.dart` filename invoked from stack-trace.
+String _findCurrentTestFilename() => Trace.current()
+    .frames
+    .lastWhere(
+      (frame) =>
+          frame.uri.isScheme('file') &&
+          p.basename(frame.uri.toFilePath()).endsWith('_test.dart'),
+    )
+    .uri
+    .toFilePath();
+
+class GoldenTestContext {
+  static const _endOfSection = ''
+      '--------------------------------'
+      ' END OF OUTPUT '
+      '---------------------------------\n\n';
+
+  final String _currentTestFile;
+  final String _testName;
+
+  String _goldenFilePath;
+  File _goldenFile;
+  String _header;
+  final _results = <String>[];
+  bool _goldenFileExists;
+  bool _generatedNewData = false; // track if new data is generated
+  int _nextSectionIndex = 0;
+
+  GoldenTestContext._(this._currentTestFile, this._testName) {
+    final rel = p.relative(
+      _currentTestFile.replaceAll(RegExp(r'\.dart$'), ''),
+      from: p.join(p.current, 'test'),
+    );
+    _goldenFilePath = p.join(
+      'test',
+      'testdata',
+      'goldens',
+      rel,
+      // Sanitize the name, and add .txt
+      _testName.replaceAll(RegExp(r'[<>:"/\|?*%#]'), '~') + '.txt',
+    );
+    _goldenFile = File(_goldenFilePath);
+    _header = '# GENERATED BY: ${p.relative(_currentTestFile)}\n\n';
   }
+
+  void _readGoldenFile() {
+    _goldenFileExists = _goldenFile.existsSync();
+
+    // Read the golden file for this test
+    if (_goldenFileExists) {
+      var text = _goldenFile.readAsStringSync().replaceAll('\r\n', '\n');
+      // Strip header line
+      if (text.startsWith('#') && text.contains('\n\n')) {
+        text = text.substring(text.indexOf('\n\n') + 2);
+      }
+      _results.addAll(text.split(_endOfSection));
+    }
+  }
+
+  /// Expect section [sectionIndex] to match [actual].
+  void _expectSection(int sectionIndex, String actual) {
+    if (_goldenFileExists &&
+        _results.length > sectionIndex &&
+        _results[sectionIndex].isNotEmpty) {
+      expect(
+        actual,
+        equals(_results[sectionIndex]),
+        reason: 'Expect matching section $sectionIndex from "$_goldenFilePath"',
+      );
+    } else {
+      while (_results.length <= sectionIndex) {
+        _results.add('');
+      }
+      _results[sectionIndex] = actual;
+      _generatedNewData = true;
+    }
+  }
+
+  void _writeGoldenFile() {
+    // If we generated new data, then we need to write a new file, and fail the
+    // test case, or mark it as skipped.
+    if (_generatedNewData) {
+      // This enables writing the updated file when run in otherwise hermetic
+      // settings.
+      //
+      // This is to make updating the golden files easier in a bazel environment
+      // See https://docs.bazel.build/versions/2.0.0/user-manual.html#run .
+      var goldenFile = _goldenFile;
+      final workspaceDirectory =
+          Platform.environment['BUILD_WORKSPACE_DIRECTORY'];
+      if (workspaceDirectory != null) {
+        goldenFile = File(p.join(workspaceDirectory, _goldenFilePath));
+      }
+      goldenFile
+        ..createSync(recursive: true)
+        ..writeAsStringSync(_header + _results.join(_endOfSection));
+
+      // If running in CI we should fail if the golden file doesn't already
+      // exist, or is missing entries.
+      // This typically happens if we forgot to commit a file to git.
+      if (_isCI) {
+        fail('Missing golden file: "$_goldenFilePath", '
+            'try running tests again and commit the file');
+      } else {
+        // If not running in CI, then we consider the test as skipped, we've
+        // generated the file, but the user should run the tests again.
+        // Or push to CI in which case we'll run the tests again anyways.
+        markTestSkipped(
+          'Generated golden file: "$_goldenFilePath" instead of running test',
+        );
+      }
+    }
+  }
+
+  /// Expect the next section in the golden file to match [actual].
+  ///
+  /// This will create the section if it is missing.
+  ///
+  /// **Warning**: Take care when using this in an async context, sections are
+  /// numbered based on the other in which calls are made. Hence, ensure
+  /// consistent ordering of calls.
+  void expectNextSection(String actual) =>
+      _expectSection(_nextSectionIndex++, actual);
+
+  /// Run `pub` [args] with [environment] variables in [workingDirectory], and
+  /// log stdout/stderr and exitcode to golden file.
+  Future<void> run(
+    List<String> args, {
+    Map<String, String> environment,
+    String workingDirectory,
+  }) async {
+    // Create new section index number (before doing anything async)
+    final sectionIndex = _nextSectionIndex++;
+    final s = StringBuffer();
+    s.writeln('## Section $sectionIndex');
+    await runPubIntoBuffer(
+      args,
+      s,
+      environment: environment,
+      workingDirectory: workingDirectory,
+    );
+
+    _expectSection(sectionIndex, s.toString());
+  }
+
+  /// Log directory tree structure under [directory] to golden file.
+  Future<void> tree([String directory]) async {
+    // Create new section index number (before doing anything async)
+    final sectionIndex = _nextSectionIndex++;
+
+    final target = p.join(d.sandbox, directory ?? '.');
+
+    final s = StringBuffer();
+    s.writeln('## Section $sectionIndex');
+    if (directory != null) {
+      s.writeln('\$ cd $directory');
+    }
+    s.writeln('\$ tree');
+    s.writeln(stripColors(ascii_tree.fromFiles(
+      listDir(target, recursive: true),
+      baseDir: target,
+    )));
+
+    _expectSection(sectionIndex, s.toString());
+  }
+}
+
+/// Create a [test] with [GoldenTestContext] which allows running golden tests.
+///
+/// This will create a golden file containing output of calls to:
+///  * [GoldenTestContext.run]
+///  * [GoldenTestContext.tree]
+///
+/// The golden file with the recorded output will be created at:
+///   `test/testdata/goldens/path/to/myfile_test/<name>.txt`
+/// , when `path/to/myfile_test.dart` is the `_test.dart` file from which this
+/// function is called.
+void testWithGolden(
+  String name,
+  FutureOr<void> Function(GoldenTestContext ctx) fn,
+) {
+  final ctx = GoldenTestContext._(_findCurrentTestFilename(), name);
+  test(name, () async {
+    ctx._readGoldenFile();
+    await fn(ctx);
+    ctx._writeGoldenFile();
+  });
 }
diff --git a/test/goldens/directory_option.txt b/test/goldens/directory_option.txt
deleted file mode 100644
index 356480c..0000000
--- a/test/goldens/directory_option.txt
+++ /dev/null
@@ -1,84 +0,0 @@
-$ pub add --directory=myapp foo
-Resolving dependencies in myapp...
-+ foo 1.0.0
-Changed 1 dependency in myapp!
-
-$ pub -C myapp add bar
-Resolving dependencies in myapp...
-+ bar 1.2.3
-Changed 1 dependency in myapp!
-
-$ pub -C myapp/example get --directory=myapp bar
-Resolving dependencies in myapp...
-Got dependencies in myapp!
-
-$ pub remove bar -C myapp
-Resolving dependencies in myapp...
-These packages are no longer being depended on:
-- bar 1.2.3
-Changed 1 dependency in myapp!
-
-$ pub get bar -C myapp
-Resolving dependencies in myapp...
-Got dependencies in myapp!
-
-$ pub get bar -C myapp/example
-Resolving dependencies in myapp/example...
-+ foo 1.0.0
-+ test_pkg 1.0.0 from path myapp
-Changed 2 dependencies in myapp/example!
-
-$ pub get bar -C myapp/example2
-Resolving dependencies in myapp/example2...
-[ERR] Error on line 1, column 9 of myapp/pubspec.yaml: "name" field doesn't match expected name "myapp".
-[ERR]   ╷
-[ERR] 1 │ {"name":"test_pkg","version":"1.0.0","homepage":"http://pub.dartlang.org","description":"A package, I guess.","environment":{"sdk":">=1.8.0 <=2.0.0"}, dependencies: { foo: ^1.0.0}}
-[ERR]   │         ^^^^^^^^^^
-[ERR]   ╵
-[Exit code] 65
-
-$ pub get bar -C myapp/broken_dir
-[ERR] Could not find a file named "pubspec.yaml" in "$SANDBOX/myapp/broken_dir".
-[Exit code] 66
-
-$ pub downgrade -C myapp
-Resolving dependencies in myapp...
-  foo 1.0.0
-No dependencies changed in myapp.
-
-$ pub upgrade bar -C myapp
-Resolving dependencies in myapp...
-  foo 1.0.0
-No dependencies changed in myapp.
-
-$ pub run -C myapp bin/app.dart
-Building package executable...
-Built test_pkg:app.
-Hi
-
-$ pub publish -C myapp --dry-run
-Publishing test_pkg 1.0.0 to http://localhost:$PORT:
-|-- CHANGELOG.md
-|-- LICENSE
-|-- README.md
-|-- bin
-|   '-- app.dart
-|-- example
-|   '-- pubspec.yaml
-|-- example2
-|   '-- pubspec.yaml
-|-- lib
-|   '-- test_pkg.dart
-'-- pubspec.yaml
-The server may enforce additional checks.
-[ERR] 
-[ERR] Package has 0 warnings.
-
-$ pub uploader -C myapp add sigurdm@google.com
-Good job!
-
-$ pub deps -C myapp
-Dart SDK 1.12.0
-test_pkg 1.0.0
-'-- foo 1.0.0
-
diff --git a/test/goldens/help.txt b/test/goldens/help.txt
deleted file mode 100644
index 10997b4..0000000
--- a/test/goldens/help.txt
+++ /dev/null
@@ -1,386 +0,0 @@
-[command]
-> pub add --help
-[stdout]
-Add a dependency to pubspec.yaml.
-
-Usage: pub add <package>[:<constraint>] [options]
--h, --help               Print this usage information.
--d, --dev                Adds package to the development dependencies instead.
-    --git-url            Git URL of the package
-    --git-ref            Git branch or commit to be retrieved
-    --git-path           Path of git package in repository
-    --hosted-url         URL of package host server
-    --path               Local path
-    --sdk                SDK source for package
-    --[no-]offline       Use cached packages instead of accessing the network.
--n, --dry-run            Report what dependencies would change but don't change
-                         any.
-    --[no-]precompile    Build executables in immediate dependencies.
-
-Run "pub help" to see global options.
-See https://dart.dev/tools/pub/cmd/pub-add for detailed documentation.
-[stderr]
-
-[exitCode]
-0
-
-[command]
-> pub build --help
-[stdout]
-Deprecated command
-
-Usage: pub build <subcommand> [arguments...]
--h, --help    Print this usage information.
-
-Run "pub help" to see global options.
-[stderr]
-
-[exitCode]
-0
-
-[command]
-> pub cache --help
-[stdout]
-Work with the system cache.
-
-Usage: pub cache [arguments...]
--h, --help    Print this usage information.
-
-Available subcommands:
-  add      Install a package.
-  repair   Reinstall cached packages.
-
-Run "pub help" to see global options.
-See https://dart.dev/tools/pub/cmd/pub-cache for detailed documentation.
-[stderr]
-
-[exitCode]
-0
-
-[command]
-> pub cache add --help
-[stdout]
-Install a package.
-
-Usage: pub cache add <package> [--version <constraint>] [--all]
--h, --help       Print this usage information.
-    --all        Install all matching versions.
--v, --version    Version constraint.
-
-Run "pub help" to see global options.
-See https://dart.dev/tools/pub/cmd/pub-cache for detailed documentation.
-[stderr]
-
-[exitCode]
-0
-
-[command]
-> pub cache list --help
-[stdout]
-List packages in the system cache.
-
-Usage: pub cache list <subcommand> [arguments...]
--h, --help    Print this usage information.
-
-Run "pub help" to see global options.
-[stderr]
-
-[exitCode]
-0
-
-[command]
-> pub cache repair --help
-[stdout]
-Reinstall cached packages.
-
-Usage: pub cache repair <subcommand> [arguments...]
--h, --help    Print this usage information.
-
-Run "pub help" to see global options.
-See https://dart.dev/tools/pub/cmd/pub-cache for detailed documentation.
-[stderr]
-
-[exitCode]
-0
-
-[command]
-> pub deps --help
-[stdout]
-Print package dependencies.
-
-Usage: pub deps [arguments...]
--h, --help           Print this usage information.
--s, --style          How output should be displayed.
-                     [compact, tree (default), list]
-    --[no-]dev       Whether to include dev dependencies.
-                     (defaults to on)
-    --executables    List all available executables.
-
-Run "pub help" to see global options.
-See https://dart.dev/tools/pub/cmd/pub-deps for detailed documentation.
-[stderr]
-
-[exitCode]
-0
-
-[command]
-> pub downgrade --help
-[stdout]
-Downgrade the current package's dependencies to oldest versions.
-
-This doesn't modify the lockfile, so it can be reset with "pub get".
-
-Usage: pub downgrade [dependencies...]
--h, --help            Print this usage information.
-    --[no-]offline    Use cached packages instead of accessing the network.
--n, --dry-run         Report what dependencies would change but don't change
-                      any.
-
-Run "pub help" to see global options.
-See https://dart.dev/tools/pub/cmd/pub-downgrade for detailed documentation.
-[stderr]
-
-[exitCode]
-0
-
-[command]
-> pub global --help
-[stdout]
-Work with global packages.
-
-Usage: pub global [arguments...]
--h, --help    Print this usage information.
-
-Available subcommands:
-  activate     Make a package's executables globally available.
-  deactivate   Remove a previously activated package.
-  list         List globally activated packages.
-  run          Run an executable from a globally activated package.
-
-Run "pub help" to see global options.
-See https://dart.dev/tools/pub/cmd/pub-global for detailed documentation.
-[stderr]
-
-[exitCode]
-0
-
-[command]
-> pub get --help
-[stdout]
-Get the current package's dependencies.
-
-Usage: pub get <subcommand> [arguments...]
--h, --help               Print this usage information.
-    --[no-]offline       Use cached packages instead of accessing the network.
--n, --dry-run            Report what dependencies would change but don't change
-                         any.
-    --[no-]precompile    Build executables in immediate dependencies.
-
-Run "pub help" to see global options.
-See https://dart.dev/tools/pub/cmd/pub-get for detailed documentation.
-[stderr]
-
-[exitCode]
-0
-
-[command]
-> pub list-package-dirs --help
-[stdout]
-Print local paths to dependencies.
-
-Usage: pub list-package-dirs
--h, --help      Print this usage information.
-    --format    How output should be displayed.
-                [json]
-
-Run "pub help" to see global options.
-[stderr]
-
-[exitCode]
-0
-
-[command]
-> pub publish --help
-[stdout]
-Publish the current package to pub.dartlang.org.
-
-Usage: pub publish [options]
--h, --help       Print this usage information.
--n, --dry-run    Validate but do not publish the package.
--f, --force      Publish without confirmation if there are no errors.
-
-Run "pub help" to see global options.
-See https://dart.dev/tools/pub/cmd/pub-lish for detailed documentation.
-[stderr]
-
-[exitCode]
-0
-
-[command]
-> pub outdated --help
-[stdout]
-Analyze your dependencies to find which ones can be upgraded.
-
-Usage: pub outdated [options]
--h, --help                         Print this usage information.
-    --[no-]color                   Whether to color the output.
-                                   Defaults to color when connected to a
-                                   terminal, and no-color otherwise.
-    --[no-]dependency-overrides    Show resolutions with `dependency_overrides`.
-                                   (defaults to on)
-    --[no-]dev-dependencies        Take dev dependencies into account.
-                                   (defaults to on)
-    --json                         Output the results using a json format.
-    --mode=<PROPERTY>              Highlight versions with PROPERTY.
-                                   Only packages currently missing that PROPERTY
-                                   will be included unless --show-all.
-                                   [outdated (default), null-safety]
-    --[no-]prereleases             Include prereleases in latest version.
-                                   (defaults to on in --mode=null-safety).
-    --[no-]show-all                Include dependencies that are already
-                                   fullfilling --mode.
-    --[no-]transitive              Show transitive dependencies.
-                                   (defaults to off in --mode=null-safety).
-
-Run "pub help" to see global options.
-See https://dart.dev/tools/pub/cmd/pub-outdated for detailed documentation.
-[stderr]
-
-[exitCode]
-0
-
-[command]
-> pub remove --help
-[stdout]
-Removes a dependency from the current package.
-
-Usage: pub remove <package>
--h, --help               Print this usage information.
-    --[no-]offline       Use cached packages instead of accessing the network.
--n, --dry-run            Report what dependencies would change but don't change
-                         any.
-    --[no-]precompile    Build executables in immediate dependencies.
-
-Run "pub help" to see global options.
-See https://dart.dev/tools/pub/cmd/pub-remove for detailed documentation.
-[stderr]
-
-[exitCode]
-0
-
-[command]
-> pub run --help
-[stdout]
-Run an executable from a package.
-
-Usage: pub run <executable> [arguments...]
--h, --help                              Print this usage information.
-    --[no-]enable-asserts               Enable assert statements.
-    --enable-experiment=<experiment>    Runs the executable in a VM with the
-                                        given experiments enabled.
-                                        (Will disable snapshotting, resulting in
-                                        slower startup).
-    --[no-]sound-null-safety            Override the default null safety
-                                        execution mode.
-
-Run "pub help" to see global options.
-See https://dart.dev/tools/pub/cmd/pub-run for detailed documentation.
-[stderr]
-
-[exitCode]
-0
-
-[command]
-> pub serve --help
-[stdout]
-Deprecated command
-
-Usage: pub serve <subcommand> [arguments...]
--h, --help    Print this usage information.
-
-Run "pub help" to see global options.
-[stderr]
-
-[exitCode]
-0
-
-[command]
-> pub upgrade --help
-[stdout]
-Upgrade the current package's dependencies to latest versions.
-
-Usage: pub upgrade [dependencies...]
--h, --help               Print this usage information.
-    --[no-]offline       Use cached packages instead of accessing the network.
--n, --dry-run            Report what dependencies would change but don't change
-                         any.
-    --[no-]precompile    Build executables in immediate dependencies.
-    --null-safety        Upgrade constraints in pubspec.yaml to null-safety
-                         versions
-
-Run "pub help" to see global options.
-See https://dart.dev/tools/pub/cmd/pub-upgrade for detailed documentation.
-[stderr]
-
-[exitCode]
-0
-
-[command]
-> pub uploader --help
-[stdout]
-Manage uploaders for a package on pub.dartlang.org.
-
-Usage: pub uploader [options] {add/remove} <email>
--h, --help       Print this usage information.
-    --package    The package whose uploaders will be modified.
-                 (defaults to the current package)
-
-Run "pub help" to see global options.
-See https://dart.dev/tools/pub/cmd/pub-uploader for detailed documentation.
-[stderr]
-
-[exitCode]
-0
-
-[command]
-> pub login --help
-[stdout]
-Log into pub.dev.
-
-Usage: pub login
--h, --help    Print this usage information.
-
-Run "pub help" to see global options.
-[stderr]
-
-[exitCode]
-0
-
-[command]
-> pub logout --help
-[stdout]
-Log out of pub.dev.
-
-Usage: pub logout <subcommand> [arguments...]
--h, --help    Print this usage information.
-
-Run "pub help" to see global options.
-[stderr]
-
-[exitCode]
-0
-
-[command]
-> pub version --help
-[stdout]
-Print pub version.
-
-Usage: pub version
--h, --help    Print this usage information.
-
-Run "pub help" to see global options.
-[stderr]
-
-[exitCode]
-0
-
diff --git a/test/goldens/usage_exception.txt b/test/goldens/usage_exception.txt
deleted file mode 100644
index 5c7ead7..0000000
--- a/test/goldens/usage_exception.txt
+++ /dev/null
@@ -1,66 +0,0 @@
-[command]
-> pub 
-[stdout]
-Pub is a package manager for Dart.
-
-Usage: pub <command> [arguments]
-
-Global options:
--h, --help             Print this usage information.
-    --version          Print pub version.
-    --[no-]trace       Print debugging information when an error occurs.
-    --verbosity        Control output verbosity.
-
-          [all]        Show all output including internal tracing messages.
-          [error]      Show only errors.
-          [io]         Also show IO operations.
-          [normal]     Show errors, warnings, and user messages.
-          [solver]     Show steps during version resolution.
-          [warning]    Show only errors and warnings.
-
--v, --verbose          Shortcut for "--verbosity=all".
-
-Available commands:
-  add         Add a dependency to pubspec.yaml.
-  cache       Work with the system cache.
-  deps        Print package dependencies.
-  downgrade   Downgrade the current package's dependencies to oldest versions.
-  get         Get the current package's dependencies.
-  global      Work with global packages.
-  login       Log into pub.dev.
-  logout      Log out of pub.dev.
-  outdated    Analyze your dependencies to find which ones can be upgraded.
-  publish     Publish the current package to pub.dartlang.org.
-  remove      Removes a dependency from the current package.
-  run         Run an executable from a package.
-  upgrade     Upgrade the current package's dependencies to latest versions.
-  uploader    Manage uploaders for a package on pub.dartlang.org.
-  version     Print pub version.
-
-Run "pub help <command>" for more information about a command.
-See https://dart.dev/tools/pub/cmd for detailed documentation.
-[stderr]
-
-[exitCode]
-0
-
-[command]
-> pub global
-[stdout]
-
-[stderr]
-Missing subcommand for "pub global".
-
-Usage: pub global [arguments...]
--h, --help    Print this usage information.
-
-Available subcommands:
-  activate     Make a package's executables globally available.
-  deactivate   Remove a previously activated package.
-  list         List globally activated packages.
-  run          Run an executable from a globally activated package.
-
-Run "pub help" to see global options.
-See https://dart.dev/tools/pub/cmd/pub-global for detailed documentation.
-[exitCode]
-64
diff --git a/test/goldens/version.txt b/test/goldens/version.txt
deleted file mode 100644
index a093c93..0000000
--- a/test/goldens/version.txt
+++ /dev/null
@@ -1,17 +0,0 @@
-[command]
-> pub --version
-[stdout]
-Pub 0.1.2+3
-[stderr]
-
-[exitCode]
-0
-
-[command]
-> pub version
-[stdout]
-Pub 0.1.2+3
-[stderr]
-
-[exitCode]
-0
diff --git a/test/help_test.dart b/test/help_test.dart
new file mode 100644
index 0000000..7ef96ff
--- /dev/null
+++ b/test/help_test.dart
@@ -0,0 +1,47 @@
+// Copyright (c) 2021, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+// @dart=2.10
+import 'package:args/command_runner.dart';
+import 'package:pub/src/command_runner.dart' show PubCommandRunner;
+
+import 'golden_file.dart';
+
+/// Extract all commands and subcommands.
+///
+/// Result will be an iterable of lists, illustrated as follows:
+/// ```
+/// [
+///   [pub]
+///   [pub, get]
+///   ...
+/// ]
+/// ```
+Iterable<List<String>> _extractCommands(
+  List<String> parents,
+  Iterable<Command> cmds,
+) sync* {
+  if (parents.isNotEmpty) {
+    yield parents;
+  }
+  // Track that we don't add more than once, we don't want to test aliases
+  final names = <String>{};
+  yield* cmds
+      .where((sub) => !sub.hidden && names.add(sub.name))
+      .map((sub) => _extractCommands(
+            [...parents, sub.name],
+            sub.subcommands.values,
+          ))
+      .expand((cmds) => cmds);
+}
+
+/// Tests for `pub ... --help`.
+Future<void> main() async {
+  final cmds = _extractCommands([], PubCommandRunner().commands.values);
+  for (final c in cmds) {
+    testWithGolden('pub ${c.join(' ')} --help', (ctx) async {
+      await ctx.run([...c, '--help']);
+    });
+  }
+}
diff --git a/test/lish/force_cannot_be_combined_with_dry_run_test.dart b/test/lish/force_cannot_be_combined_with_dry_run_test.dart
index def3f7a..6e77aa3 100644
--- a/test/lish/force_cannot_be_combined_with_dry_run_test.dart
+++ b/test/lish/force_cannot_be_combined_with_dry_run_test.dart
@@ -14,17 +14,10 @@
   setUp(d.validPackage.create);
 
   test('--force cannot be combined with --dry-run', () async {
-    await runPub(args: ['lish', '--force', '--dry-run'], error: '''
-Cannot use both --force and --dry-run.
-
-Usage: pub publish [options]
--h, --help               Print this usage information.
--n, --dry-run            Validate but do not publish the package.
--f, --force              Publish without confirmation if there are no errors.
--C, --directory=<dir>    Run this in the directory<dir>.
-
-Run "pub help" to see global options.
-See https://dart.dev/tools/pub/cmd/pub-lish for detailed documentation.
-''', exitCode: exit_codes.USAGE);
+    await runPub(
+      args: ['lish', '--force', '--dry-run'],
+      error: contains('Cannot use both --force and --dry-run.'),
+      exitCode: exit_codes.USAGE,
+    );
   });
 }
diff --git a/test/outdated/outdated_test.dart b/test/outdated/outdated_test.dart
index 925e0de..2f47bbd 100644
--- a/test/outdated/outdated_test.dart
+++ b/test/outdated/outdated_test.dart
@@ -4,72 +4,65 @@
 
 // @dart=2.10
 
-import 'package:test/test.dart';
 import '../descriptor.dart' as d;
 import '../golden_file.dart';
 import '../test_pub.dart';
 
-/// Try running 'pub outdated' with a number of different sets of arguments.
-///
-/// Compare the stdout and stderr output to the file in goldens/$[name].
-Future<void> variations(String name, {Map<String, String> environment}) async {
-  final buffer = StringBuffer();
-  for (final args in [
-    ['outdated', '--json'],
-    ['outdated', '--no-color'],
-    ['outdated', '--no-color', '--no-transitive'],
-    ['outdated', '--no-color', '--up-to-date'],
-    ['outdated', '--no-color', '--prereleases'],
-    ['outdated', '--no-color', '--no-dev-dependencies'],
-    ['outdated', '--no-color', '--no-dependency-overrides'],
-    ['outdated', '--no-color', '--mode=null-safety'],
-    ['outdated', '--no-color', '--mode=null-safety', '--transitive'],
-    ['outdated', '--no-color', '--mode=null-safety', '--no-prereleases'],
-    ['outdated', '--json', '--mode=null-safety'],
-    ['outdated', '--json', '--no-dev-dependencies'],
-  ]) {
-    await runPubIntoBuffer(args, buffer, environment: environment);
+extension on GoldenTestContext {
+  /// Try running 'pub outdated' with a number of different sets of arguments.
+  /// And compare to results from test/testdata/goldens/...
+  Future<void> runOutdatedTests({
+    Map<String, String> environment,
+    String workingDirectory,
+  }) async {
+    const commands = [
+      ['outdated', '--json'],
+      ['outdated', '--no-color'],
+      ['outdated', '--no-color', '--no-transitive'],
+      ['outdated', '--no-color', '--up-to-date'],
+      ['outdated', '--no-color', '--prereleases'],
+      ['outdated', '--no-color', '--no-dev-dependencies'],
+      ['outdated', '--no-color', '--no-dependency-overrides'],
+      ['outdated', '--no-color', '--mode=null-safety'],
+      ['outdated', '--no-color', '--mode=null-safety', '--transitive'],
+      ['outdated', '--no-color', '--mode=null-safety', '--no-prereleases'],
+      ['outdated', '--json', '--mode=null-safety'],
+      ['outdated', '--json', '--no-dev-dependencies'],
+    ];
+    for (final args in commands) {
+      await run(
+        args,
+        environment: environment,
+        workingDirectory: workingDirectory,
+      );
+    }
   }
-  // The easiest way to update the golden files is to delete them and rerun the
-  // test.
-  expectMatchesGoldenFile(buffer.toString(), 'test/outdated/goldens/$name.txt');
 }
 
 Future<void> main() async {
-  test('help text', () async {
-    final buffer = StringBuffer();
-    await runPubIntoBuffer(
-      ['outdated', '--help'],
-      buffer,
-    );
-    expectMatchesGoldenFile(
-        buffer.toString(), 'test/outdated/goldens/helptext.txt');
-  });
-
-  test('no pubspec', () async {
+  testWithGolden('no pubspec', (ctx) async {
     await d.dir(appPath, []).create();
-    final buffer = StringBuffer();
-    await runPubIntoBuffer(['outdated'], buffer);
-    expectMatchesGoldenFile(
-        buffer.toString(), 'test/outdated/goldens/no_pubspec.txt');
+    await ctx.run(['outdated']);
   });
 
-  test('no lockfile', () async {
+  testWithGolden('no lockfile', (ctx) async {
     await d.appDir({'foo': '^1.0.0', 'bar': '^1.0.0'}).create();
     await servePackages((builder) => builder
       ..serve('foo', '1.2.3')
       ..serve('bar', '1.2.3')
       ..serve('bar', '2.0.0'));
-    await variations('no_lockfile');
+
+    await ctx.runOutdatedTests();
   });
 
-  test('no dependencies', () async {
+  testWithGolden('no dependencies', (ctx) async {
     await d.appDir().create();
     await pubGet();
-    await variations('no_dependencies');
+
+    await ctx.runOutdatedTests();
   });
 
-  test('newer versions available', () async {
+  testWithGolden('newer versions available', (ctx) async {
     await servePackages((builder) => builder
       ..serve('foo', '1.2.3', deps: {'transitive': '^1.0.0'})
       ..serve('bar', '1.0.0')
@@ -114,10 +107,11 @@
       ..serve('transitive2', '1.0.0')
       ..serve('transitive3', '1.0.0')
       ..serve('dev_trans', '2.0.0'));
-    await variations('newer_versions');
+
+    await ctx.runOutdatedTests();
   });
 
-  test('circular dependency on root', () async {
+  testWithGolden('circular dependency on root', (ctx) async {
     await servePackages(
       (builder) => builder..serve('foo', '1.2.3', deps: {'app': '^1.0.0'}),
     );
@@ -137,10 +131,11 @@
     globalPackageServer.add(
       (builder) => builder..serve('foo', '1.3.0', deps: {'app': '^1.0.1'}),
     );
-    await variations('circular_dependencies');
+
+    await ctx.runOutdatedTests();
   });
 
-  test('mutually incompatible newer versions', () async {
+  testWithGolden('mutually incompatible newer versions', (ctx) async {
     await d.dir(appPath, [
       d.pubspec({
         'name': 'app',
@@ -159,10 +154,10 @@
       ..serve('bar', '2.0.0', deps: {'foo': '^1.0.0'}));
     await pubGet();
 
-    await variations('mutually_incompatible');
+    await ctx.runOutdatedTests();
   });
 
-  test('null safety compliance', () async {
+  testWithGolden('null safety compliance', (ctx) async {
     await d.dir(appPath, [
       d.pubspec({
         'name': 'app',
@@ -237,11 +232,12 @@
     );
     await pubGet(environment: {'_PUB_TEST_SDK_VERSION': '2.13.0'});
 
-    await variations('null_safety',
-        environment: {'_PUB_TEST_SDK_VERSION': '2.13.0'});
+    await ctx.runOutdatedTests(environment: {
+      '_PUB_TEST_SDK_VERSION': '2.13.0',
+    });
   });
 
-  test('null-safety no resolution', () async {
+  testWithGolden('null-safety no resolution', (ctx) async {
     await servePackages((builder) => builder
       ..serve('foo', '1.0.0', pubspec: {
         'environment': {'sdk': '>=2.9.0 < 3.0.0'}
@@ -274,11 +270,12 @@
 
     await pubGet(environment: {'_PUB_TEST_SDK_VERSION': '2.13.0'});
 
-    await variations('null_safety_no_resolution',
-        environment: {'_PUB_TEST_SDK_VERSION': '2.13.0'});
+    await ctx.runOutdatedTests(environment: {
+      '_PUB_TEST_SDK_VERSION': '2.13.0',
+    });
   });
 
-  test('null-safety already migrated', () async {
+  testWithGolden('null-safety already migrated', (ctx) async {
     await servePackages((builder) => builder
       ..serve('foo', '1.0.0', pubspec: {
         'environment': {'sdk': '>=2.9.0 < 3.0.0'}
@@ -314,11 +311,12 @@
 
     await pubGet(environment: {'_PUB_TEST_SDK_VERSION': '2.13.0'});
 
-    await variations('null_safety_already_migrated',
-        environment: {'_PUB_TEST_SDK_VERSION': '2.13.0'});
+    await ctx.runOutdatedTests(environment: {
+      '_PUB_TEST_SDK_VERSION': '2.13.0',
+    });
   });
 
-  test('overridden dependencies', () async {
+  testWithGolden('overridden dependencies', (ctx) async {
     ensureGit();
     await servePackages(
       (builder) => builder
@@ -359,10 +357,10 @@
 
     await pubGet();
 
-    await variations('dependency_overrides');
+    await ctx.runOutdatedTests();
   });
 
-  test('overridden dependencies - no resolution', () async {
+  testWithGolden('overridden dependencies - no resolution', (ctx) async {
     ensureGit();
     await servePackages(
       (builder) => builder
@@ -389,12 +387,12 @@
 
     await pubGet();
 
-    await variations('dependency_overrides_no_solution');
+    await ctx.runOutdatedTests();
   });
 
-  test(
+  testWithGolden(
       'latest version reported while locked on a prerelease can be a prerelease',
-      () async {
+      (ctx) async {
     await servePackages((builder) => builder
       ..serve('foo', '0.9.0')
       ..serve('foo', '1.0.0-dev.1')
@@ -419,10 +417,10 @@
 
     await pubGet();
 
-    await variations('prereleases');
+    await ctx.runOutdatedTests();
   });
 
-  test('Handles SDK dependencies', () async {
+  testWithGolden('Handles SDK dependencies', (ctx) async {
     await servePackages((builder) => builder
       ..serve('foo', '1.0.0', pubspec: {
         'environment': {'sdk': '>=2.10.0 <3.0.0'}
@@ -471,7 +469,7 @@
       '_PUB_TEST_SDK_VERSION': '2.13.0'
     });
 
-    await variations('handles_sdk_dependencies', environment: {
+    await ctx.runOutdatedTests(environment: {
       'FLUTTER_ROOT': d.path('flutter-root'),
       '_PUB_TEST_SDK_VERSION': '2.13.0',
       // To test that the reproduction command is reflected correctly.
@@ -479,11 +477,8 @@
     });
   });
 
-  test("doesn't allow arguments. Handles bad flags", () async {
-    final sb = StringBuffer();
-    await runPubIntoBuffer(['outdated', 'random_argument'], sb);
-    await runPubIntoBuffer(['outdated', '--bad_flag'], sb);
-    expectMatchesGoldenFile(
-        sb.toString(), 'test/outdated/goldens/bad_arguments.txt');
+  testWithGolden('does not allow arguments - handles bad flags', (ctx) async {
+    await ctx.run(['outdated', 'random_argument']);
+    await ctx.run(['outdated', '--bad_flag']);
   });
 }
diff --git a/test/pub_uploader_test.dart b/test/pub_uploader_test.dart
index 98bd2fe..c45c8ed 100644
--- a/test/pub_uploader_test.dart
+++ b/test/pub_uploader_test.dart
@@ -15,19 +15,6 @@
 import 'descriptor.dart' as d;
 import 'test_pub.dart';
 
-const _usageString = '''
-Manage uploaders for a package on pub.dartlang.org.
-
-Usage: pub uploader [options] {add/remove} <email>
--h, --help               Print this usage information.
-    --package            The package whose uploaders will be modified.
-                         (defaults to the current package)
--C, --directory=<dir>    Run this in the directory<dir>.
-
-Run "pub help" to see global options.
-See https://dart.dev/tools/pub/cmd/pub-uploader for detailed documentation.
-''';
-
 Future<TestProcess> startPubUploader(PackageServer server, List<String> args) {
   var tokenEndpoint = Uri.parse(server.url).resolve('/token').toString();
   var allArgs = ['uploader', ...args];
@@ -40,22 +27,16 @@
 void main() {
   group('displays usage', () {
     test('when run with no arguments', () {
-      return runPub(
-          args: ['uploader'], output: _usageString, exitCode: exit_codes.USAGE);
+      return runPub(args: ['uploader'], exitCode: exit_codes.USAGE);
     });
 
     test('when run with only a command', () {
-      return runPub(
-          args: ['uploader', 'add'],
-          output: _usageString,
-          exitCode: exit_codes.USAGE);
+      return runPub(args: ['uploader', 'add'], exitCode: exit_codes.USAGE);
     });
 
     test('when run with an invalid command', () {
       return runPub(
-          args: ['uploader', 'foo', 'email'],
-          output: _usageString,
-          exitCode: exit_codes.USAGE);
+          args: ['uploader', 'foo', 'email'], exitCode: exit_codes.USAGE);
     });
   });
 
diff --git a/test/run/errors_if_no_executable_is_given_test.dart b/test/run/errors_if_no_executable_is_given_test.dart
index 2bec1a3..92f0073 100644
--- a/test/run/errors_if_no_executable_is_given_test.dart
+++ b/test/run/errors_if_no_executable_is_given_test.dart
@@ -14,22 +14,10 @@
   test('Errors if the executable does not exist.', () async {
     await d.dir(appPath, [d.appPubspec()]).create();
 
-    await runPub(args: ['run'], error: '''
-Must specify an executable to run.
-
-Usage: pub run <executable> [arguments...]
--h, --help                              Print this usage information.
-    --[no-]enable-asserts               Enable assert statements.
-    --enable-experiment=<experiment>    Runs the executable in a VM with the
-                                        given experiments enabled.
-                                        (Will disable snapshotting, resulting in
-                                        slower startup).
-    --[no-]sound-null-safety            Override the default null safety
-                                        execution mode.
--C, --directory=<dir>                   Run this in the directory<dir>.
-
-Run "pub help" to see global options.
-See https://dart.dev/tools/pub/cmd/pub-run for detailed documentation.
-''', exitCode: exit_codes.USAGE);
+    await runPub(
+      args: ['run'],
+      error: contains('Must specify an executable to run.'),
+      exitCode: exit_codes.USAGE,
+    );
   });
 }
diff --git a/test/run/errors_if_path_in_dependency_test.dart b/test/run/errors_if_path_in_dependency_test.dart
index 5625c4e..2affef7 100644
--- a/test/run/errors_if_path_in_dependency_test.dart
+++ b/test/run/errors_if_path_in_dependency_test.dart
@@ -22,22 +22,12 @@
       })
     ]).create();
 
-    await runPub(args: ['run', 'foo:sub/dir'], error: '''
-Cannot run an executable in a subdirectory of a dependency.
-
-Usage: pub run <executable> [arguments...]
--h, --help                              Print this usage information.
-    --[no-]enable-asserts               Enable assert statements.
-    --enable-experiment=<experiment>    Runs the executable in a VM with the
-                                        given experiments enabled.
-                                        (Will disable snapshotting, resulting in
-                                        slower startup).
-    --[no-]sound-null-safety            Override the default null safety
-                                        execution mode.
--C, --directory=<dir>                   Run this in the directory<dir>.
-
-Run "pub help" to see global options.
-See https://dart.dev/tools/pub/cmd/pub-run for detailed documentation.
-''', exitCode: exit_codes.USAGE);
+    await runPub(
+      args: ['run', 'foo:sub/dir'],
+      error: contains(
+        'Cannot run an executable in a subdirectory of a dependency.',
+      ),
+      exitCode: exit_codes.USAGE,
+    );
   });
 }
diff --git a/test/test_pub.dart b/test/test_pub.dart
index cccefbe..2d68233 100644
--- a/test/test_pub.dart
+++ b/test/test_pub.dart
@@ -934,15 +934,24 @@
   );
   final exitCode = await process.exitCode;
 
+  // TODO(jonasfj): Clean out temporary directory names from env vars...
+  // if (workingDirectory != null) {
+  //   buffer.writeln('\$ cd $workingDirectory');
+  // }
+  // if (environment != null && environment.isNotEmpty) {
+  //   buffer.writeln(environment.entries
+  //       .map((e) => '\$ export ${e.key}=${e.value}')
+  //       .join('\n'));
+  // }
   buffer.writeln(_filter([
     '\$ pub ${args.join(' ')}',
     ...await process.stdout.rest.toList(),
   ]).join('\n'));
   for (final line in _filter(await process.stderr.rest.toList())) {
-    buffer.writeln('[ERR] $line');
+    buffer.writeln('[STDERR] $line');
   }
   if (exitCode != 0) {
-    buffer.writeln('[Exit code] $exitCode');
+    buffer.writeln('[EXIT CODE] $exitCode');
   }
   buffer.write('\n');
 }
diff --git a/test/testdata/README.md b/test/testdata/README.md
new file mode 100644
index 0000000..ad4a817
--- /dev/null
+++ b/test/testdata/README.md
@@ -0,0 +1,25 @@
+# Test Data
+
+Data used in tests is called _test data_ and is located in this folder, or
+sub-folders thereof. This is not for test files, this folder should not contain
+test code, only data used in tests.
+
+## Golden Test
+
+The `test` wrapper `testWithGolden('<name>', (ctx) async {` will register a
+test case, and create a file:
+  `test/testdata/goldens/path/to/myfile_test/<name>.txt`
+, where `path/to/myfile_test.dart` is the name of the file containing the test
+case, and `<name>` is the name of the test case.
+
+Any calls to `ctx.run` will run `pub` and compare the output to a section in the
+golden file. If the file does not exist, it is created and the
+test is marked as skipped.
+Thus, it is safe to delete all files in `test/testdata/goldens` and recreate
+them -- just carefully review the changes before committing.
+
+**Maintaining goldens**:
+ 1. Delete `test/testdata/goldens/`.
+ 2. Re-run tests to re-create files in `test/testdata/goldens/`.
+ 3. Compare changes, using `git diff test/testdata/goldens/`.
+
diff --git a/test/testdata/goldens/deps/executables_test/applies formatting before printing executables.txt b/test/testdata/goldens/deps/executables_test/applies formatting before printing executables.txt
new file mode 100644
index 0000000..d8448df
--- /dev/null
+++ b/test/testdata/goldens/deps/executables_test/applies formatting before printing executables.txt
@@ -0,0 +1,81 @@
+# GENERATED BY: test/deps/executables_test.dart
+
+## Section 0
+$ tree
+|-- bar
+|   |-- bin
+|   |   '-- qux.dart
+|   '-- pubspec.yaml
+|-- foo
+|   |-- bin
+|   |   |-- baz.dart
+|   |   '-- foo.dart
+|   '-- pubspec.yaml
+'-- myapp
+    |-- bin
+    |   '-- myapp.dart
+    |-- pubspec.lock
+    '-- pubspec.yaml
+
+-------------------------------- END OF OUTPUT ---------------------------------
+
+## Section 1
+$ pub deps --executables
+myapp
+foo: foo, baz
+bar:qux
+
+-------------------------------- END OF OUTPUT ---------------------------------
+
+## Section 2
+$ pub deps --executables --dev
+myapp
+foo: foo, baz
+bar:qux
+
+-------------------------------- END OF OUTPUT ---------------------------------
+
+## Section 3
+$ pub deps --json
+{
+  "root": "myapp",
+  "packages": [
+    {
+      "name": "myapp",
+      "version": "0.0.0",
+      "kind": "root",
+      "source": "root",
+      "dependencies": [
+        "foo",
+        "bar"
+      ]
+    },
+    {
+      "name": "bar",
+      "version": "1.0.0",
+      "kind": "direct",
+      "source": "path",
+      "dependencies": []
+    },
+    {
+      "name": "foo",
+      "version": "1.0.0",
+      "kind": "direct",
+      "source": "path",
+      "dependencies": []
+    }
+  ],
+  "sdks": [
+    {
+      "name": "Dart",
+      "version": "0.1.2+3"
+    }
+  ],
+  "executables": [
+    ":myapp",
+    "foo:baz",
+    "foo",
+    "bar:qux"
+  ]
+}
+
diff --git a/test/testdata/goldens/deps/executables_test/dev dependencies.txt b/test/testdata/goldens/deps/executables_test/dev dependencies.txt
new file mode 100644
index 0000000..2d72b44
--- /dev/null
+++ b/test/testdata/goldens/deps/executables_test/dev dependencies.txt
@@ -0,0 +1,59 @@
+# GENERATED BY: test/deps/executables_test.dart
+
+## Section 0
+$ tree
+|-- foo
+|   |-- bin
+|   |   '-- bar.dart
+|   '-- pubspec.yaml
+'-- myapp
+    |-- pubspec.lock
+    '-- pubspec.yaml
+
+-------------------------------- END OF OUTPUT ---------------------------------
+
+## Section 1
+$ pub deps --executables
+foo:bar
+
+-------------------------------- END OF OUTPUT ---------------------------------
+
+## Section 2
+$ pub deps --executables --dev
+foo:bar
+
+-------------------------------- END OF OUTPUT ---------------------------------
+
+## Section 3
+$ pub deps --json
+{
+  "root": "myapp",
+  "packages": [
+    {
+      "name": "myapp",
+      "version": "0.0.0",
+      "kind": "root",
+      "source": "root",
+      "dependencies": [
+        "foo"
+      ]
+    },
+    {
+      "name": "foo",
+      "version": "1.0.0",
+      "kind": "dev",
+      "source": "path",
+      "dependencies": []
+    }
+  ],
+  "sdks": [
+    {
+      "name": "Dart",
+      "version": "0.1.2+3"
+    }
+  ],
+  "executables": [
+    "foo:bar"
+  ]
+}
+
diff --git a/test/testdata/goldens/deps/executables_test/lists Dart executables, without entrypoints.txt b/test/testdata/goldens/deps/executables_test/lists Dart executables, without entrypoints.txt
new file mode 100644
index 0000000..a12d363
--- /dev/null
+++ b/test/testdata/goldens/deps/executables_test/lists Dart executables, without entrypoints.txt
@@ -0,0 +1,50 @@
+# GENERATED BY: test/deps/executables_test.dart
+
+## Section 0
+$ tree
+'-- myapp
+    |-- bin
+    |   |-- bar.dart
+    |   '-- foo.dart
+    |-- pubspec.lock
+    '-- pubspec.yaml
+
+-------------------------------- END OF OUTPUT ---------------------------------
+
+## Section 1
+$ pub deps --executables
+myapp: bar, foo
+
+-------------------------------- END OF OUTPUT ---------------------------------
+
+## Section 2
+$ pub deps --executables --dev
+myapp: bar, foo
+
+-------------------------------- END OF OUTPUT ---------------------------------
+
+## Section 3
+$ pub deps --json
+{
+  "root": "myapp",
+  "packages": [
+    {
+      "name": "myapp",
+      "version": "0.0.0",
+      "kind": "root",
+      "source": "root",
+      "dependencies": []
+    }
+  ],
+  "sdks": [
+    {
+      "name": "Dart",
+      "version": "0.1.2+3"
+    }
+  ],
+  "executables": [
+    ":bar",
+    ":foo"
+  ]
+}
+
diff --git a/test/testdata/goldens/deps/executables_test/lists executables from a dependency.txt b/test/testdata/goldens/deps/executables_test/lists executables from a dependency.txt
new file mode 100644
index 0000000..75a1b33
--- /dev/null
+++ b/test/testdata/goldens/deps/executables_test/lists executables from a dependency.txt
@@ -0,0 +1,59 @@
+# GENERATED BY: test/deps/executables_test.dart
+
+## Section 0
+$ tree
+|-- foo
+|   |-- bin
+|   |   '-- bar.dart
+|   '-- pubspec.yaml
+'-- myapp
+    |-- pubspec.lock
+    '-- pubspec.yaml
+
+-------------------------------- END OF OUTPUT ---------------------------------
+
+## Section 1
+$ pub deps --executables
+foo:bar
+
+-------------------------------- END OF OUTPUT ---------------------------------
+
+## Section 2
+$ pub deps --executables --dev
+foo:bar
+
+-------------------------------- END OF OUTPUT ---------------------------------
+
+## Section 3
+$ pub deps --json
+{
+  "root": "myapp",
+  "packages": [
+    {
+      "name": "myapp",
+      "version": "0.0.0",
+      "kind": "root",
+      "source": "root",
+      "dependencies": [
+        "foo"
+      ]
+    },
+    {
+      "name": "foo",
+      "version": "1.0.0",
+      "kind": "direct",
+      "source": "path",
+      "dependencies": []
+    }
+  ],
+  "sdks": [
+    {
+      "name": "Dart",
+      "version": "0.1.2+3"
+    }
+  ],
+  "executables": [
+    "foo:bar"
+  ]
+}
+
diff --git a/test/testdata/goldens/deps/executables_test/lists executables only from immediate dependencies.txt b/test/testdata/goldens/deps/executables_test/lists executables only from immediate dependencies.txt
new file mode 100644
index 0000000..de70643
--- /dev/null
+++ b/test/testdata/goldens/deps/executables_test/lists executables only from immediate dependencies.txt
@@ -0,0 +1,72 @@
+# GENERATED BY: test/deps/executables_test.dart
+
+## Section 0
+$ tree
+|-- baz
+|   |-- bin
+|   |   '-- qux.dart
+|   '-- pubspec.yaml
+|-- foo
+|   |-- bin
+|   |   '-- bar.dart
+|   '-- pubspec.yaml
+'-- myapp
+    |-- pubspec.lock
+    '-- pubspec.yaml
+
+-------------------------------- END OF OUTPUT ---------------------------------
+
+## Section 1
+$ pub deps --executables
+foo:bar
+
+-------------------------------- END OF OUTPUT ---------------------------------
+
+## Section 2
+$ pub deps --executables --dev
+foo:bar
+
+-------------------------------- END OF OUTPUT ---------------------------------
+
+## Section 3
+$ pub deps --json
+{
+  "root": "myapp",
+  "packages": [
+    {
+      "name": "myapp",
+      "version": "0.0.0",
+      "kind": "root",
+      "source": "root",
+      "dependencies": [
+        "foo"
+      ]
+    },
+    {
+      "name": "foo",
+      "version": "1.0.0",
+      "kind": "direct",
+      "source": "path",
+      "dependencies": [
+        "baz"
+      ]
+    },
+    {
+      "name": "baz",
+      "version": "1.0.0",
+      "kind": "transitive",
+      "source": "path",
+      "dependencies": []
+    }
+  ],
+  "sdks": [
+    {
+      "name": "Dart",
+      "version": "0.1.2+3"
+    }
+  ],
+  "executables": [
+    "foo:bar"
+  ]
+}
+
diff --git a/test/testdata/goldens/deps/executables_test/overriden dependencies executables.txt b/test/testdata/goldens/deps/executables_test/overriden dependencies executables.txt
new file mode 100644
index 0000000..910210e
--- /dev/null
+++ b/test/testdata/goldens/deps/executables_test/overriden dependencies executables.txt
@@ -0,0 +1,65 @@
+# GENERATED BY: test/deps/executables_test.dart
+
+## Section 0
+$ tree
+|-- foo-1.0
+|   |-- bin
+|   |   '-- bar.dart
+|   '-- pubspec.yaml
+|-- foo-2.0
+|   |-- bin
+|   |   |-- bar.dart
+|   |   '-- baz.dart
+|   '-- pubspec.yaml
+'-- myapp
+    |-- pubspec.lock
+    '-- pubspec.yaml
+
+-------------------------------- END OF OUTPUT ---------------------------------
+
+## Section 1
+$ pub deps --executables
+foo: bar, baz
+
+-------------------------------- END OF OUTPUT ---------------------------------
+
+## Section 2
+$ pub deps --executables --dev
+foo: bar, baz
+
+-------------------------------- END OF OUTPUT ---------------------------------
+
+## Section 3
+$ pub deps --json
+{
+  "root": "myapp",
+  "packages": [
+    {
+      "name": "myapp",
+      "version": "0.0.0",
+      "kind": "root",
+      "source": "root",
+      "dependencies": [
+        "foo"
+      ]
+    },
+    {
+      "name": "foo",
+      "version": "2.0.0",
+      "kind": "direct",
+      "source": "path",
+      "dependencies": []
+    }
+  ],
+  "sdks": [
+    {
+      "name": "Dart",
+      "version": "0.1.2+3"
+    }
+  ],
+  "executables": [
+    "foo:bar",
+    "foo:baz"
+  ]
+}
+
diff --git a/test/testdata/goldens/deps/executables_test/skips executables in sub directories.txt b/test/testdata/goldens/deps/executables_test/skips executables in sub directories.txt
new file mode 100644
index 0000000..289f7c8
--- /dev/null
+++ b/test/testdata/goldens/deps/executables_test/skips executables in sub directories.txt
@@ -0,0 +1,50 @@
+# GENERATED BY: test/deps/executables_test.dart
+
+## Section 0
+$ tree
+'-- myapp
+    |-- bin
+    |   |-- foo.dart
+    |   '-- sub
+    |       '-- bar.dart
+    |-- pubspec.lock
+    '-- pubspec.yaml
+
+-------------------------------- END OF OUTPUT ---------------------------------
+
+## Section 1
+$ pub deps --executables
+myapp:foo
+
+-------------------------------- END OF OUTPUT ---------------------------------
+
+## Section 2
+$ pub deps --executables --dev
+myapp:foo
+
+-------------------------------- END OF OUTPUT ---------------------------------
+
+## Section 3
+$ pub deps --json
+{
+  "root": "myapp",
+  "packages": [
+    {
+      "name": "myapp",
+      "version": "0.0.0",
+      "kind": "root",
+      "source": "root",
+      "dependencies": []
+    }
+  ],
+  "sdks": [
+    {
+      "name": "Dart",
+      "version": "0.1.2+3"
+    }
+  ],
+  "executables": [
+    ":foo"
+  ]
+}
+
diff --git a/test/testdata/goldens/deps/executables_test/skips non-Dart executables.txt b/test/testdata/goldens/deps/executables_test/skips non-Dart executables.txt
new file mode 100644
index 0000000..d4a2db3
--- /dev/null
+++ b/test/testdata/goldens/deps/executables_test/skips non-Dart executables.txt
@@ -0,0 +1,45 @@
+# GENERATED BY: test/deps/executables_test.dart
+
+## Section 0
+$ tree
+'-- myapp
+    |-- bin
+    |   |-- bar.sh
+    |   '-- foo.py
+    |-- pubspec.lock
+    '-- pubspec.yaml
+
+-------------------------------- END OF OUTPUT ---------------------------------
+
+## Section 1
+$ pub deps --executables
+
+-------------------------------- END OF OUTPUT ---------------------------------
+
+## Section 2
+$ pub deps --executables --dev
+
+-------------------------------- END OF OUTPUT ---------------------------------
+
+## Section 3
+$ pub deps --json
+{
+  "root": "myapp",
+  "packages": [
+    {
+      "name": "myapp",
+      "version": "0.0.0",
+      "kind": "root",
+      "source": "root",
+      "dependencies": []
+    }
+  ],
+  "sdks": [
+    {
+      "name": "Dart",
+      "version": "0.1.2+3"
+    }
+  ],
+  "executables": []
+}
+
diff --git a/test/testdata/goldens/directory_option_test/commands taking a --directory~-C parameter work.txt b/test/testdata/goldens/directory_option_test/commands taking a --directory~-C parameter work.txt
new file mode 100644
index 0000000..237b3b5
--- /dev/null
+++ b/test/testdata/goldens/directory_option_test/commands taking a --directory~-C parameter work.txt
@@ -0,0 +1,126 @@
+# GENERATED BY: test/directory_option_test.dart
+
+## Section 0
+$ pub add --directory=myapp foo
+Resolving dependencies in myapp...
++ foo 1.0.0
+Changed 1 dependency in myapp!
+
+-------------------------------- END OF OUTPUT ---------------------------------
+
+## Section 1
+$ pub -C myapp add bar
+Resolving dependencies in myapp...
++ bar 1.2.3
+Changed 1 dependency in myapp!
+
+-------------------------------- END OF OUTPUT ---------------------------------
+
+## Section 2
+$ pub -C myapp/example get --directory=myapp bar
+Resolving dependencies in myapp...
+Got dependencies in myapp!
+
+-------------------------------- END OF OUTPUT ---------------------------------
+
+## Section 3
+$ pub remove bar -C myapp
+Resolving dependencies in myapp...
+These packages are no longer being depended on:
+- bar 1.2.3
+Changed 1 dependency in myapp!
+
+-------------------------------- END OF OUTPUT ---------------------------------
+
+## Section 4
+$ pub get bar -C myapp
+Resolving dependencies in myapp...
+Got dependencies in myapp!
+
+-------------------------------- END OF OUTPUT ---------------------------------
+
+## Section 5
+$ pub get bar -C myapp/example
+Resolving dependencies in myapp/example...
++ foo 1.0.0
++ test_pkg 1.0.0 from path myapp
+Changed 2 dependencies in myapp/example!
+
+-------------------------------- END OF OUTPUT ---------------------------------
+
+## Section 6
+$ pub get bar -C myapp/example2
+Resolving dependencies in myapp/example2...
+[STDERR] Error on line 1, column 9 of myapp/pubspec.yaml: "name" field doesn't match expected name "myapp".
+[STDERR]   ╷
+[STDERR] 1 │ {"name":"test_pkg","version":"1.0.0","homepage":"http://pub.dartlang.org","description":"A package, I guess.","environment":{"sdk":">=1.8.0 <=2.0.0"}, dependencies: { foo: ^1.0.0}}
+[STDERR]   │         ^^^^^^^^^^
+[STDERR]   ╵
+[EXIT CODE] 65
+
+-------------------------------- END OF OUTPUT ---------------------------------
+
+## Section 7
+$ pub get bar -C myapp/broken_dir
+[STDERR] Could not find a file named "pubspec.yaml" in "$SANDBOX/myapp/broken_dir".
+[EXIT CODE] 66
+
+-------------------------------- END OF OUTPUT ---------------------------------
+
+## Section 8
+$ pub downgrade -C myapp
+Resolving dependencies in myapp...
+  foo 1.0.0
+No dependencies changed in myapp.
+
+-------------------------------- END OF OUTPUT ---------------------------------
+
+## Section 9
+$ pub upgrade bar -C myapp
+Resolving dependencies in myapp...
+  foo 1.0.0
+No dependencies changed in myapp.
+
+-------------------------------- END OF OUTPUT ---------------------------------
+
+## Section 10
+$ pub run -C myapp bin/app.dart
+Building package executable...
+Built test_pkg:app.
+Hi
+
+-------------------------------- END OF OUTPUT ---------------------------------
+
+## Section 11
+$ pub publish -C myapp --dry-run
+Publishing test_pkg 1.0.0 to http://localhost:$PORT:
+|-- CHANGELOG.md
+|-- LICENSE
+|-- README.md
+|-- bin
+|   '-- app.dart
+|-- example
+|   '-- pubspec.yaml
+|-- example2
+|   '-- pubspec.yaml
+|-- lib
+|   '-- test_pkg.dart
+'-- pubspec.yaml
+The server may enforce additional checks.
+[STDERR] 
+[STDERR] Package has 0 warnings.
+
+-------------------------------- END OF OUTPUT ---------------------------------
+
+## Section 12
+$ pub uploader -C myapp add sigurdm@google.com
+Good job!
+
+-------------------------------- END OF OUTPUT ---------------------------------
+
+## Section 13
+$ pub deps -C myapp
+Dart SDK 1.12.0
+test_pkg 1.0.0
+'-- foo 1.0.0
+
diff --git a/test/testdata/goldens/embedding/embedding_test/run works, though hidden.txt b/test/testdata/goldens/embedding/embedding_test/run works, though hidden.txt
new file mode 100644
index 0000000..214712a
--- /dev/null
+++ b/test/testdata/goldens/embedding/embedding_test/run works, though hidden.txt
@@ -0,0 +1,11 @@
+# GENERATED BY: test/embedding/embedding_test.dart
+
+$ tool/test-bin/pub_command_runner.dart pub get
+Resolving dependencies...
+Got dependencies!
+
+-------------------------------- END OF OUTPUT ---------------------------------
+
+$ tool/test-bin/pub_command_runner.dart pub run bin/main.dart
+Hi
+
diff --git a/test/testdata/goldens/help_test/pub add --help.txt b/test/testdata/goldens/help_test/pub add --help.txt
new file mode 100644
index 0000000..5d32e5e
--- /dev/null
+++ b/test/testdata/goldens/help_test/pub add --help.txt
@@ -0,0 +1,24 @@
+# GENERATED BY: test/help_test.dart
+
+## Section 0
+$ pub add --help
+Add a dependency to pubspec.yaml.
+
+Usage: pub add <package>[:<constraint>] [options]
+-h, --help               Print this usage information.
+-d, --dev                Adds package to the development dependencies instead.
+    --git-url            Git URL of the package
+    --git-ref            Git branch or commit to be retrieved
+    --git-path           Path of git package in repository
+    --hosted-url         URL of package host server
+    --path               Local path
+    --sdk                SDK source for package
+    --[no-]offline       Use cached packages instead of accessing the network.
+-n, --dry-run            Report what dependencies would change but don't change
+                         any.
+    --[no-]precompile    Build executables in immediate dependencies.
+-C, --directory=<dir>    Run this in the directory<dir>.
+
+Run "pub help" to see global options.
+See https://dart.dev/tools/pub/cmd/pub-add for detailed documentation.
+
diff --git a/test/testdata/goldens/help_test/pub cache --help.txt b/test/testdata/goldens/help_test/pub cache --help.txt
new file mode 100644
index 0000000..fdb0b2c
--- /dev/null
+++ b/test/testdata/goldens/help_test/pub cache --help.txt
@@ -0,0 +1,17 @@
+# GENERATED BY: test/help_test.dart
+
+## Section 0
+$ pub cache --help
+Work with the system cache.
+
+Usage: pub cache [arguments...]
+-h, --help    Print this usage information.
+
+Available subcommands:
+  add      Install a package.
+  clean    Clears the global PUB_CACHE.
+  repair   Reinstall cached packages.
+
+Run "pub help" to see global options.
+See https://dart.dev/tools/pub/cmd/pub-cache for detailed documentation.
+
diff --git a/test/testdata/goldens/help_test/pub cache add --help.txt b/test/testdata/goldens/help_test/pub cache add --help.txt
new file mode 100644
index 0000000..05068f0
--- /dev/null
+++ b/test/testdata/goldens/help_test/pub cache add --help.txt
@@ -0,0 +1,14 @@
+# GENERATED BY: test/help_test.dart
+
+## Section 0
+$ pub cache add --help
+Install a package.
+
+Usage: pub cache add <package> [--version <constraint>] [--all]
+-h, --help       Print this usage information.
+    --all        Install all matching versions.
+-v, --version    Version constraint.
+
+Run "pub help" to see global options.
+See https://dart.dev/tools/pub/cmd/pub-cache for detailed documentation.
+
diff --git a/test/testdata/goldens/help_test/pub cache clean --help.txt b/test/testdata/goldens/help_test/pub cache clean --help.txt
new file mode 100644
index 0000000..71dd1d6
--- /dev/null
+++ b/test/testdata/goldens/help_test/pub cache clean --help.txt
@@ -0,0 +1,12 @@
+# GENERATED BY: test/help_test.dart
+
+## Section 0
+$ pub cache clean --help
+Clears the global PUB_CACHE.
+
+Usage: pub cache clean <subcommand> [arguments...]
+-h, --help     Print this usage information.
+-f, --force    Don't ask for confirmation.
+
+Run "pub help" to see global options.
+
diff --git a/test/testdata/goldens/help_test/pub cache repair --help.txt b/test/testdata/goldens/help_test/pub cache repair --help.txt
new file mode 100644
index 0000000..ac09115
--- /dev/null
+++ b/test/testdata/goldens/help_test/pub cache repair --help.txt
@@ -0,0 +1,12 @@
+# GENERATED BY: test/help_test.dart
+
+## Section 0
+$ pub cache repair --help
+Reinstall cached packages.
+
+Usage: pub cache repair <subcommand> [arguments...]
+-h, --help    Print this usage information.
+
+Run "pub help" to see global options.
+See https://dart.dev/tools/pub/cmd/pub-cache for detailed documentation.
+
diff --git a/test/testdata/goldens/help_test/pub deps --help.txt b/test/testdata/goldens/help_test/pub deps --help.txt
new file mode 100644
index 0000000..475353f
--- /dev/null
+++ b/test/testdata/goldens/help_test/pub deps --help.txt
@@ -0,0 +1,19 @@
+# GENERATED BY: test/help_test.dart
+
+## Section 0
+$ pub deps --help
+Print package dependencies.
+
+Usage: pub deps [arguments...]
+-h, --help               Print this usage information.
+-s, --style              How output should be displayed.
+                         [compact, tree (default), list]
+    --[no-]dev           Whether to include dev dependencies.
+                         (defaults to on)
+    --executables        List all available executables.
+    --json               Output dependency information in a json format.
+-C, --directory=<dir>    Run this in the directory<dir>.
+
+Run "pub help" to see global options.
+See https://dart.dev/tools/pub/cmd/pub-deps for detailed documentation.
+
diff --git a/test/testdata/goldens/help_test/pub downgrade --help.txt b/test/testdata/goldens/help_test/pub downgrade --help.txt
new file mode 100644
index 0000000..4497da2
--- /dev/null
+++ b/test/testdata/goldens/help_test/pub downgrade --help.txt
@@ -0,0 +1,18 @@
+# GENERATED BY: test/help_test.dart
+
+## Section 0
+$ pub downgrade --help
+Downgrade the current package's dependencies to oldest versions.
+
+
+
+Usage: pub downgrade [dependencies...]
+-h, --help               Print this usage information.
+    --[no-]offline       Use cached packages instead of accessing the network.
+-n, --dry-run            Report what dependencies would change but don't change
+                         any.
+-C, --directory=<dir>    Run this in the directory<dir>.
+
+Run "pub help" to see global options.
+See https://dart.dev/tools/pub/cmd/pub-downgrade for detailed documentation.
+
diff --git a/test/testdata/goldens/help_test/pub get --help.txt b/test/testdata/goldens/help_test/pub get --help.txt
new file mode 100644
index 0000000..74648a2
--- /dev/null
+++ b/test/testdata/goldens/help_test/pub get --help.txt
@@ -0,0 +1,17 @@
+# GENERATED BY: test/help_test.dart
+
+## Section 0
+$ pub get --help
+Get the current package's dependencies.
+
+Usage: pub get <subcommand> [arguments...]
+-h, --help               Print this usage information.
+    --[no-]offline       Use cached packages instead of accessing the network.
+-n, --dry-run            Report what dependencies would change but don't change
+                         any.
+    --[no-]precompile    Build executables in immediate dependencies.
+-C, --directory=<dir>    Run this in the directory<dir>.
+
+Run "pub help" to see global options.
+See https://dart.dev/tools/pub/cmd/pub-get for detailed documentation.
+
diff --git a/test/testdata/goldens/help_test/pub global --help.txt b/test/testdata/goldens/help_test/pub global --help.txt
new file mode 100644
index 0000000..6aa723c
--- /dev/null
+++ b/test/testdata/goldens/help_test/pub global --help.txt
@@ -0,0 +1,18 @@
+# GENERATED BY: test/help_test.dart
+
+## Section 0
+$ pub global --help
+Work with global packages.
+
+Usage: pub global [arguments...]
+-h, --help    Print this usage information.
+
+Available subcommands:
+  activate     Make a package's executables globally available.
+  deactivate   Remove a previously activated package.
+  list         List globally activated packages.
+  run          Run an executable from a globally activated package.
+
+Run "pub help" to see global options.
+See https://dart.dev/tools/pub/cmd/pub-global for detailed documentation.
+
diff --git a/test/testdata/goldens/help_test/pub global activate --help.txt b/test/testdata/goldens/help_test/pub global activate --help.txt
new file mode 100644
index 0000000..5341266
--- /dev/null
+++ b/test/testdata/goldens/help_test/pub global activate --help.txt
@@ -0,0 +1,19 @@
+# GENERATED BY: test/help_test.dart
+
+## Section 0
+$ pub global activate --help
+Make a package's executables globally available.
+
+Usage: pub global activate <package> [version-constraint]
+-h, --help              Print this usage information.
+-s, --source            The source used to find the package.
+                        [git, hosted (default), path]
+    --no-executables    Do not put executables on PATH.
+-x, --executable        Executable(s) to place on PATH.
+    --overwrite         Overwrite executables from other packages with the same
+                        name.
+-u, --hosted-url        A custom pub server URL for the package. Only applies
+                        when using the `hosted` source.
+
+Run "pub help" to see global options.
+
diff --git a/test/testdata/goldens/help_test/pub global deactivate --help.txt b/test/testdata/goldens/help_test/pub global deactivate --help.txt
new file mode 100644
index 0000000..8b8178b
--- /dev/null
+++ b/test/testdata/goldens/help_test/pub global deactivate --help.txt
@@ -0,0 +1,11 @@
+# GENERATED BY: test/help_test.dart
+
+## Section 0
+$ pub global deactivate --help
+Remove a previously activated package.
+
+Usage: pub global deactivate <package>
+-h, --help    Print this usage information.
+
+Run "pub help" to see global options.
+
diff --git a/test/testdata/goldens/help_test/pub global list --help.txt b/test/testdata/goldens/help_test/pub global list --help.txt
new file mode 100644
index 0000000..12244be
--- /dev/null
+++ b/test/testdata/goldens/help_test/pub global list --help.txt
@@ -0,0 +1,11 @@
+# GENERATED BY: test/help_test.dart
+
+## Section 0
+$ pub global list --help
+List globally activated packages.
+
+Usage: pub global list <subcommand> [arguments...]
+-h, --help    Print this usage information.
+
+Run "pub help" to see global options.
+
diff --git a/test/testdata/goldens/help_test/pub global run --help.txt b/test/testdata/goldens/help_test/pub global run --help.txt
new file mode 100644
index 0000000..f829064
--- /dev/null
+++ b/test/testdata/goldens/help_test/pub global run --help.txt
@@ -0,0 +1,18 @@
+# GENERATED BY: test/help_test.dart
+
+## Section 0
+$ pub global run --help
+Run an executable from a globally activated package.
+
+Usage: pub global run <package>:<executable> [args...]
+-h, --help                              Print this usage information.
+    --[no-]enable-asserts               Enable assert statements.
+    --enable-experiment=<experiment>    Runs the executable in a VM with the
+                                        given experiments enabled. (Will disable
+                                        snapshotting, resulting in slower
+                                        startup).
+    --[no-]sound-null-safety            Override the default null safety
+                                        execution mode.
+
+Run "pub help" to see global options.
+
diff --git a/test/testdata/goldens/help_test/pub login --help.txt b/test/testdata/goldens/help_test/pub login --help.txt
new file mode 100644
index 0000000..ce7233b
--- /dev/null
+++ b/test/testdata/goldens/help_test/pub login --help.txt
@@ -0,0 +1,11 @@
+# GENERATED BY: test/help_test.dart
+
+## Section 0
+$ pub login --help
+Log into pub.dev.
+
+Usage: pub login
+-h, --help    Print this usage information.
+
+Run "pub help" to see global options.
+
diff --git a/test/testdata/goldens/help_test/pub logout --help.txt b/test/testdata/goldens/help_test/pub logout --help.txt
new file mode 100644
index 0000000..3937ef7
--- /dev/null
+++ b/test/testdata/goldens/help_test/pub logout --help.txt
@@ -0,0 +1,11 @@
+# GENERATED BY: test/help_test.dart
+
+## Section 0
+$ pub logout --help
+Log out of pub.dev.
+
+Usage: pub logout <subcommand> [arguments...]
+-h, --help    Print this usage information.
+
+Run "pub help" to see global options.
+
diff --git a/test/outdated/goldens/helptext.txt b/test/testdata/goldens/help_test/pub outdated --help.txt
similarity index 96%
rename from test/outdated/goldens/helptext.txt
rename to test/testdata/goldens/help_test/pub outdated --help.txt
index 20a4ecc..9a7b1bc 100644
--- a/test/outdated/goldens/helptext.txt
+++ b/test/testdata/goldens/help_test/pub outdated --help.txt
@@ -1,3 +1,6 @@
+# GENERATED BY: test/help_test.dart
+
+## Section 0
 $ pub outdated --help
 Analyze your dependencies to find which ones can be upgraded.
 
diff --git a/test/testdata/goldens/help_test/pub publish --help.txt b/test/testdata/goldens/help_test/pub publish --help.txt
new file mode 100644
index 0000000..2977db0
--- /dev/null
+++ b/test/testdata/goldens/help_test/pub publish --help.txt
@@ -0,0 +1,15 @@
+# GENERATED BY: test/help_test.dart
+
+## Section 0
+$ pub publish --help
+Publish the current package to pub.dartlang.org.
+
+Usage: pub publish [options]
+-h, --help               Print this usage information.
+-n, --dry-run            Validate but do not publish the package.
+-f, --force              Publish without confirmation if there are no errors.
+-C, --directory=<dir>    Run this in the directory<dir>.
+
+Run "pub help" to see global options.
+See https://dart.dev/tools/pub/cmd/pub-lish for detailed documentation.
+
diff --git a/test/testdata/goldens/help_test/pub remove --help.txt b/test/testdata/goldens/help_test/pub remove --help.txt
new file mode 100644
index 0000000..7d14ed0
--- /dev/null
+++ b/test/testdata/goldens/help_test/pub remove --help.txt
@@ -0,0 +1,17 @@
+# GENERATED BY: test/help_test.dart
+
+## Section 0
+$ pub remove --help
+Removes a dependency from the current package.
+
+Usage: pub remove <package>
+-h, --help               Print this usage information.
+    --[no-]offline       Use cached packages instead of accessing the network.
+-n, --dry-run            Report what dependencies would change but don't change
+                         any.
+    --[no-]precompile    Precompile executables in immediate dependencies.
+-C, --directory=<dir>    Run this in the directory<dir>.
+
+Run "pub help" to see global options.
+See https://dart.dev/tools/pub/cmd/pub-remove for detailed documentation.
+
diff --git a/test/testdata/goldens/help_test/pub run --help.txt b/test/testdata/goldens/help_test/pub run --help.txt
new file mode 100644
index 0000000..f2844f3
--- /dev/null
+++ b/test/testdata/goldens/help_test/pub run --help.txt
@@ -0,0 +1,20 @@
+# GENERATED BY: test/help_test.dart
+
+## Section 0
+$ pub run --help
+Run an executable from a package.
+
+Usage: pub run <executable> [arguments...]
+-h, --help                              Print this usage information.
+    --[no-]enable-asserts               Enable assert statements.
+    --enable-experiment=<experiment>    Runs the executable in a VM with the
+                                        given experiments enabled.
+                                        (Will disable snapshotting, resulting in
+                                        slower startup).
+    --[no-]sound-null-safety            Override the default null safety
+                                        execution mode.
+-C, --directory=<dir>                   Run this in the directory<dir>.
+
+Run "pub help" to see global options.
+See https://dart.dev/tools/pub/cmd/pub-run for detailed documentation.
+
diff --git a/test/testdata/goldens/help_test/pub token --help.txt b/test/testdata/goldens/help_test/pub token --help.txt
new file mode 100644
index 0000000..fa164c5
--- /dev/null
+++ b/test/testdata/goldens/help_test/pub token --help.txt
@@ -0,0 +1,16 @@
+# GENERATED BY: test/help_test.dart
+
+## Section 0
+$ pub token --help
+Manage authentication tokens for hosted pub repositories.
+
+Usage: pub token [arguments...]
+-h, --help    Print this usage information.
+
+Available subcommands:
+  add      Add authentication tokens for a package repository.
+  list     List servers for which a token exists.
+  remove   Remove secret token for package repository.
+
+Run "pub help" to see global options.
+
diff --git a/test/testdata/goldens/help_test/pub token add --help.txt b/test/testdata/goldens/help_test/pub token add --help.txt
new file mode 100644
index 0000000..7068a5c
--- /dev/null
+++ b/test/testdata/goldens/help_test/pub token add --help.txt
@@ -0,0 +1,13 @@
+# GENERATED BY: test/help_test.dart
+
+## Section 0
+$ pub token add --help
+Add authentication tokens for a package repository.
+
+Usage: pub token add
+-h, --help       Print this usage information.
+    --env-var    Read the secret token from this environment variable when
+                 making requests.
+
+Run "pub help" to see global options.
+
diff --git a/test/testdata/goldens/help_test/pub token list --help.txt b/test/testdata/goldens/help_test/pub token list --help.txt
new file mode 100644
index 0000000..5c333b5
--- /dev/null
+++ b/test/testdata/goldens/help_test/pub token list --help.txt
@@ -0,0 +1,11 @@
+# GENERATED BY: test/help_test.dart
+
+## Section 0
+$ pub token list --help
+List servers for which a token exists.
+
+Usage: pub token list
+-h, --help    Print this usage information.
+
+Run "pub help" to see global options.
+
diff --git a/test/testdata/goldens/help_test/pub token remove --help.txt b/test/testdata/goldens/help_test/pub token remove --help.txt
new file mode 100644
index 0000000..1f79f81
--- /dev/null
+++ b/test/testdata/goldens/help_test/pub token remove --help.txt
@@ -0,0 +1,12 @@
+# GENERATED BY: test/help_test.dart
+
+## Section 0
+$ pub token remove --help
+Remove secret token for package repository.
+
+Usage: pub token remove
+-h, --help    Print this usage information.
+    --all     Remove all secret tokens.
+
+Run "pub help" to see global options.
+
diff --git a/test/testdata/goldens/help_test/pub upgrade --help.txt b/test/testdata/goldens/help_test/pub upgrade --help.txt
new file mode 100644
index 0000000..d1a29b9
--- /dev/null
+++ b/test/testdata/goldens/help_test/pub upgrade --help.txt
@@ -0,0 +1,21 @@
+# GENERATED BY: test/help_test.dart
+
+## Section 0
+$ pub upgrade --help
+Upgrade the current package's dependencies to latest versions.
+
+Usage: pub upgrade [dependencies...]
+-h, --help               Print this usage information.
+    --[no-]offline       Use cached packages instead of accessing the network.
+-n, --dry-run            Report what dependencies would change but don't change
+                         any.
+    --[no-]precompile    Precompile executables in immediate dependencies.
+    --null-safety        Upgrade constraints in pubspec.yaml to null-safety
+                         versions
+    --major-versions     Upgrades packages to their latest resolvable versions,
+                         and updates pubspec.yaml.
+-C, --directory=<dir>    Run this in the directory<dir>.
+
+Run "pub help" to see global options.
+See https://dart.dev/tools/pub/cmd/pub-upgrade for detailed documentation.
+
diff --git a/test/testdata/goldens/help_test/pub uploader --help.txt b/test/testdata/goldens/help_test/pub uploader --help.txt
new file mode 100644
index 0000000..10c9d9d
--- /dev/null
+++ b/test/testdata/goldens/help_test/pub uploader --help.txt
@@ -0,0 +1,15 @@
+# GENERATED BY: test/help_test.dart
+
+## Section 0
+$ pub uploader --help
+Manage uploaders for a package on pub.dartlang.org.
+
+Usage: pub uploader [options] {add/remove} <email>
+-h, --help               Print this usage information.
+    --package            The package whose uploaders will be modified.
+                         (defaults to the current package)
+-C, --directory=<dir>    Run this in the directory<dir>.
+
+Run "pub help" to see global options.
+See https://dart.dev/tools/pub/cmd/pub-uploader for detailed documentation.
+
diff --git a/test/testdata/goldens/help_test/pub version --help.txt b/test/testdata/goldens/help_test/pub version --help.txt
new file mode 100644
index 0000000..82e9f9f
--- /dev/null
+++ b/test/testdata/goldens/help_test/pub version --help.txt
@@ -0,0 +1,11 @@
+# GENERATED BY: test/help_test.dart
+
+## Section 0
+$ pub version --help
+Print pub version.
+
+Usage: pub version
+-h, --help    Print this usage information.
+
+Run "pub help" to see global options.
+
diff --git a/test/testdata/goldens/outdated/outdated_test/Handles SDK dependencies.txt b/test/testdata/goldens/outdated/outdated_test/Handles SDK dependencies.txt
new file mode 100644
index 0000000..c9bc73f
--- /dev/null
+++ b/test/testdata/goldens/outdated/outdated_test/Handles SDK dependencies.txt
@@ -0,0 +1,254 @@
+# GENERATED BY: test/outdated/outdated_test.dart
+
+## Section 0
+$ pub outdated --json
+{
+  "packages": [
+    {
+      "package": "foo",
+      "current": {
+        "version": "1.1.0"
+      },
+      "upgradable": {
+        "version": "1.1.0"
+      },
+      "resolvable": {
+        "version": "2.0.0"
+      },
+      "latest": {
+        "version": "2.0.0"
+      }
+    }
+  ]
+}
+
+-------------------------------- END OF OUTPUT ---------------------------------
+
+## Section 1
+$ pub outdated --no-color
+Showing outdated packages.
+[*] indicates versions that are not the latest available.
+
+Package Name  Current  Upgradable  Resolvable  Latest  
+
+direct dependencies:
+foo           *1.1.0   *1.1.0      2.0.0       2.0.0   
+
+dev_dependencies: all up-to-date.
+
+1 dependency is constrained to a version that is older than a resolvable version.
+To update it, edit pubspec.yaml, or run `flutter pub upgrade --major-versions`.
+
+-------------------------------- END OF OUTPUT ---------------------------------
+
+## Section 2
+$ pub outdated --no-color --no-transitive
+Showing outdated packages.
+[*] indicates versions that are not the latest available.
+
+Package Name  Current  Upgradable  Resolvable  Latest  
+
+direct dependencies:
+foo           *1.1.0   *1.1.0      2.0.0       2.0.0   
+
+dev_dependencies: all up-to-date.
+
+1 dependency is constrained to a version that is older than a resolvable version.
+To update it, edit pubspec.yaml, or run `flutter pub upgrade --major-versions`.
+
+-------------------------------- END OF OUTPUT ---------------------------------
+
+## Section 3
+$ pub outdated --no-color --up-to-date
+Showing outdated packages.
+[*] indicates versions that are not the latest available.
+
+Package Name  Current  Upgradable  Resolvable  Latest  
+
+direct dependencies:
+flutter       (sdk)    (sdk)       (sdk)       (sdk)   
+foo           *1.1.0   *1.1.0      2.0.0       2.0.0   
+
+dev_dependencies:
+flutter_test  (sdk)    (sdk)       (sdk)       (sdk)   
+
+1 dependency is constrained to a version that is older than a resolvable version.
+To update it, edit pubspec.yaml, or run `flutter pub upgrade --major-versions`.
+
+-------------------------------- END OF OUTPUT ---------------------------------
+
+## Section 4
+$ pub outdated --no-color --prereleases
+Showing outdated packages.
+[*] indicates versions that are not the latest available.
+
+Package Name  Current  Upgradable  Resolvable  Latest  
+
+direct dependencies:
+foo           *1.1.0   *1.1.0      2.0.0       2.0.0   
+
+dev_dependencies: all up-to-date.
+
+1 dependency is constrained to a version that is older than a resolvable version.
+To update it, edit pubspec.yaml, or run `flutter pub upgrade --major-versions`.
+
+-------------------------------- END OF OUTPUT ---------------------------------
+
+## Section 5
+$ pub outdated --no-color --no-dev-dependencies
+Showing outdated packages.
+[*] indicates versions that are not the latest available.
+
+Package Name  Current  Upgradable  Resolvable  Latest  
+
+direct dependencies:
+foo           *1.1.0   *1.1.0      2.0.0       2.0.0   
+
+1 dependency is constrained to a version that is older than a resolvable version.
+To update it, edit pubspec.yaml, or run `flutter pub upgrade --major-versions`.
+
+-------------------------------- END OF OUTPUT ---------------------------------
+
+## Section 6
+$ pub outdated --no-color --no-dependency-overrides
+Showing outdated packages.
+[*] indicates versions that are not the latest available.
+
+Package Name  Current  Upgradable  Resolvable  Latest  
+
+direct dependencies:
+foo           *1.1.0   *1.1.0      2.0.0       2.0.0   
+
+dev_dependencies: all up-to-date.
+
+1 dependency is constrained to a version that is older than a resolvable version.
+To update it, edit pubspec.yaml, or run `flutter pub upgrade --major-versions`.
+
+-------------------------------- END OF OUTPUT ---------------------------------
+
+## Section 7
+$ pub outdated --no-color --mode=null-safety
+Showing dependencies that are currently not opted in to null-safety.
+[✗] indicates versions without null safety support.
+[✓] indicates versions opting in to null safety.
+
+Package Name  Current  Upgradable  Resolvable  Latest  
+
+direct dependencies:
+foo           ✗1.1.0   ✗1.1.0      ✓2.0.0      ✓2.0.0  
+
+dev_dependencies:
+flutter_test  ✗(sdk)   ✗(sdk)      ✗(sdk)      ✗(sdk)  
+
+1 dependency is constrained to a version that is older than a resolvable version.
+To update it, edit pubspec.yaml, or run `flutter pub upgrade --null-safety`.
+
+-------------------------------- END OF OUTPUT ---------------------------------
+
+## Section 8
+$ pub outdated --no-color --mode=null-safety --transitive
+Showing dependencies that are currently not opted in to null-safety.
+[✗] indicates versions without null safety support.
+[✓] indicates versions opting in to null safety.
+
+Package Name  Current  Upgradable  Resolvable  Latest  
+
+direct dependencies:
+foo           ✗1.1.0   ✗1.1.0      ✓2.0.0      ✓2.0.0  
+
+dev_dependencies:
+flutter_test  ✗(sdk)   ✗(sdk)      ✗(sdk)      ✗(sdk)  
+
+1 dependency is constrained to a version that is older than a resolvable version.
+To update it, edit pubspec.yaml, or run `flutter pub upgrade --null-safety`.
+
+-------------------------------- END OF OUTPUT ---------------------------------
+
+## Section 9
+$ pub outdated --no-color --mode=null-safety --no-prereleases
+Showing dependencies that are currently not opted in to null-safety.
+[✗] indicates versions without null safety support.
+[✓] indicates versions opting in to null safety.
+
+Package Name  Current  Upgradable  Resolvable  Latest  
+
+direct dependencies:
+foo           ✗1.1.0   ✗1.1.0      ✓2.0.0      ✓2.0.0  
+
+dev_dependencies:
+flutter_test  ✗(sdk)   ✗(sdk)      ✗(sdk)      ✗(sdk)  
+
+1 dependency is constrained to a version that is older than a resolvable version.
+To update it, edit pubspec.yaml, or run `flutter pub upgrade --null-safety`.
+
+-------------------------------- END OF OUTPUT ---------------------------------
+
+## Section 10
+$ pub outdated --json --mode=null-safety
+{
+  "packages": [
+    {
+      "package": "flutter_test",
+      "current": {
+        "version": "1.0.0",
+        "nullSafety": false
+      },
+      "upgradable": {
+        "version": "1.0.0",
+        "nullSafety": false
+      },
+      "resolvable": {
+        "version": "1.0.0",
+        "nullSafety": false
+      },
+      "latest": {
+        "version": "1.0.0",
+        "nullSafety": false
+      }
+    },
+    {
+      "package": "foo",
+      "current": {
+        "version": "1.1.0",
+        "nullSafety": false
+      },
+      "upgradable": {
+        "version": "1.1.0",
+        "nullSafety": false
+      },
+      "resolvable": {
+        "version": "2.0.0",
+        "nullSafety": true
+      },
+      "latest": {
+        "version": "2.0.0",
+        "nullSafety": true
+      }
+    }
+  ]
+}
+
+-------------------------------- END OF OUTPUT ---------------------------------
+
+## Section 11
+$ pub outdated --json --no-dev-dependencies
+{
+  "packages": [
+    {
+      "package": "foo",
+      "current": {
+        "version": "1.1.0"
+      },
+      "upgradable": {
+        "version": "1.1.0"
+      },
+      "resolvable": {
+        "version": "2.0.0"
+      },
+      "latest": {
+        "version": "2.0.0"
+      }
+    }
+  ]
+}
+
diff --git a/test/testdata/goldens/outdated/outdated_test/circular dependency on root.txt b/test/testdata/goldens/outdated/outdated_test/circular dependency on root.txt
new file mode 100644
index 0000000..b9ab0a5
--- /dev/null
+++ b/test/testdata/goldens/outdated/outdated_test/circular dependency on root.txt
@@ -0,0 +1,214 @@
+# GENERATED BY: test/outdated/outdated_test.dart
+
+## Section 0
+$ pub outdated --json
+{
+  "packages": [
+    {
+      "package": "foo",
+      "current": {
+        "version": "1.2.3"
+      },
+      "upgradable": {
+        "version": "1.3.0"
+      },
+      "resolvable": {
+        "version": "1.3.0"
+      },
+      "latest": {
+        "version": "1.3.0"
+      }
+    }
+  ]
+}
+
+-------------------------------- END OF OUTPUT ---------------------------------
+
+## Section 1
+$ pub outdated --no-color
+Showing outdated packages.
+[*] indicates versions that are not the latest available.
+
+Package Name  Current  Upgradable  Resolvable  Latest  
+
+direct dependencies:
+foo           *1.2.3   1.3.0       1.3.0       1.3.0   
+
+1 upgradable dependency is locked (in pubspec.lock) to an older version.
+To update it, use `dart pub upgrade`.
+
+-------------------------------- END OF OUTPUT ---------------------------------
+
+## Section 2
+$ pub outdated --no-color --no-transitive
+Showing outdated packages.
+[*] indicates versions that are not the latest available.
+
+Package Name  Current  Upgradable  Resolvable  Latest  
+
+direct dependencies:
+foo           *1.2.3   1.3.0       1.3.0       1.3.0   
+
+1 upgradable dependency is locked (in pubspec.lock) to an older version.
+To update it, use `dart pub upgrade`.
+
+-------------------------------- END OF OUTPUT ---------------------------------
+
+## Section 3
+$ pub outdated --no-color --up-to-date
+Showing outdated packages.
+[*] indicates versions that are not the latest available.
+
+Package Name  Current  Upgradable  Resolvable  Latest  
+
+direct dependencies:
+foo           *1.2.3   1.3.0       1.3.0       1.3.0   
+
+1 upgradable dependency is locked (in pubspec.lock) to an older version.
+To update it, use `dart pub upgrade`.
+
+-------------------------------- END OF OUTPUT ---------------------------------
+
+## Section 4
+$ pub outdated --no-color --prereleases
+Showing outdated packages.
+[*] indicates versions that are not the latest available.
+
+Package Name  Current  Upgradable  Resolvable  Latest  
+
+direct dependencies:
+foo           *1.2.3   1.3.0       1.3.0       1.3.0   
+
+1 upgradable dependency is locked (in pubspec.lock) to an older version.
+To update it, use `dart pub upgrade`.
+
+-------------------------------- END OF OUTPUT ---------------------------------
+
+## Section 5
+$ pub outdated --no-color --no-dev-dependencies
+Showing outdated packages.
+[*] indicates versions that are not the latest available.
+
+Package Name  Current  Upgradable  Resolvable  Latest  
+
+direct dependencies:
+foo           *1.2.3   1.3.0       1.3.0       1.3.0   
+
+1 upgradable dependency is locked (in pubspec.lock) to an older version.
+To update it, use `dart pub upgrade`.
+
+-------------------------------- END OF OUTPUT ---------------------------------
+
+## Section 6
+$ pub outdated --no-color --no-dependency-overrides
+Showing outdated packages.
+[*] indicates versions that are not the latest available.
+
+Package Name  Current  Upgradable  Resolvable  Latest  
+
+direct dependencies:
+foo           *1.2.3   1.3.0       1.3.0       1.3.0   
+
+1 upgradable dependency is locked (in pubspec.lock) to an older version.
+To update it, use `dart pub upgrade`.
+
+-------------------------------- END OF OUTPUT ---------------------------------
+
+## Section 7
+$ pub outdated --no-color --mode=null-safety
+Showing dependencies that are currently not opted in to null-safety.
+[✗] indicates versions without null safety support.
+[✓] indicates versions opting in to null safety.
+
+Package Name  Current  Upgradable  Resolvable  Latest  
+
+direct dependencies:
+foo           ✗1.2.3   ✗1.3.0      ✗1.3.0      ✗1.3.0  
+
+1 upgradable dependency is locked (in pubspec.lock) to an older version.
+To update it, use `dart pub upgrade`.
+
+-------------------------------- END OF OUTPUT ---------------------------------
+
+## Section 8
+$ pub outdated --no-color --mode=null-safety --transitive
+Showing dependencies that are currently not opted in to null-safety.
+[✗] indicates versions without null safety support.
+[✓] indicates versions opting in to null safety.
+
+Package Name  Current  Upgradable  Resolvable  Latest  
+
+direct dependencies:
+foo           ✗1.2.3   ✗1.3.0      ✗1.3.0      ✗1.3.0  
+
+1 upgradable dependency is locked (in pubspec.lock) to an older version.
+To update it, use `dart pub upgrade`.
+
+-------------------------------- END OF OUTPUT ---------------------------------
+
+## Section 9
+$ pub outdated --no-color --mode=null-safety --no-prereleases
+Showing dependencies that are currently not opted in to null-safety.
+[✗] indicates versions without null safety support.
+[✓] indicates versions opting in to null safety.
+
+Package Name  Current  Upgradable  Resolvable  Latest  
+
+direct dependencies:
+foo           ✗1.2.3   ✗1.3.0      ✗1.3.0      ✗1.3.0  
+
+1 upgradable dependency is locked (in pubspec.lock) to an older version.
+To update it, use `dart pub upgrade`.
+
+-------------------------------- END OF OUTPUT ---------------------------------
+
+## Section 10
+$ pub outdated --json --mode=null-safety
+{
+  "packages": [
+    {
+      "package": "foo",
+      "current": {
+        "version": "1.2.3",
+        "nullSafety": false
+      },
+      "upgradable": {
+        "version": "1.3.0",
+        "nullSafety": false
+      },
+      "resolvable": {
+        "version": "1.3.0",
+        "nullSafety": false
+      },
+      "latest": {
+        "version": "1.3.0",
+        "nullSafety": false
+      }
+    }
+  ]
+}
+
+-------------------------------- END OF OUTPUT ---------------------------------
+
+## Section 11
+$ pub outdated --json --no-dev-dependencies
+{
+  "packages": [
+    {
+      "package": "foo",
+      "current": {
+        "version": "1.2.3"
+      },
+      "upgradable": {
+        "version": "1.3.0"
+      },
+      "resolvable": {
+        "version": "1.3.0"
+      },
+      "latest": {
+        "version": "1.3.0"
+      }
+    }
+  ]
+}
+
diff --git a/test/testdata/goldens/outdated/outdated_test/does not allow arguments - handles bad flags.txt b/test/testdata/goldens/outdated/outdated_test/does not allow arguments - handles bad flags.txt
new file mode 100644
index 0000000..6ab6163
--- /dev/null
+++ b/test/testdata/goldens/outdated/outdated_test/does not allow arguments - handles bad flags.txt
@@ -0,0 +1,64 @@
+# GENERATED BY: test/outdated/outdated_test.dart
+
+## Section 0
+$ pub outdated random_argument
+[STDERR] Command "outdated" does not take any arguments.
+[STDERR] 
+[STDERR] Usage: pub outdated [options]
+[STDERR] -h, --help                         Print this usage information.
+[STDERR]     --[no-]color                   Whether to color the output.
+[STDERR]                                    Defaults to color when connected to a
+[STDERR]                                    terminal, and no-color otherwise.
+[STDERR]     --[no-]dependency-overrides    Show resolutions with `dependency_overrides`.
+[STDERR]                                    (defaults to on)
+[STDERR]     --[no-]dev-dependencies        Take dev dependencies into account.
+[STDERR]                                    (defaults to on)
+[STDERR]     --json                         Output the results using a json format.
+[STDERR]     --mode=<PROPERTY>              Highlight versions with PROPERTY.
+[STDERR]                                    Only packages currently missing that PROPERTY
+[STDERR]                                    will be included unless --show-all.
+[STDERR]                                    [outdated (default), null-safety]
+[STDERR]     --[no-]prereleases             Include prereleases in latest version.
+[STDERR]                                    (defaults to on in --mode=null-safety).
+[STDERR]     --[no-]show-all                Include dependencies that are already
+[STDERR]                                    fullfilling --mode.
+[STDERR]     --[no-]transitive              Show transitive dependencies.
+[STDERR]                                    (defaults to off in --mode=null-safety).
+[STDERR] -C, --directory=<dir>              Run this in the directory<dir>.
+[STDERR] 
+[STDERR] Run "pub help" to see global options.
+[STDERR] See https://dart.dev/tools/pub/cmd/pub-outdated for detailed documentation.
+[EXIT CODE] 64
+
+-------------------------------- END OF OUTPUT ---------------------------------
+
+## Section 1
+$ pub outdated --bad_flag
+[STDERR] Could not find an option named "bad_flag".
+[STDERR] 
+[STDERR] Usage: pub outdated [options]
+[STDERR] -h, --help                         Print this usage information.
+[STDERR]     --[no-]color                   Whether to color the output.
+[STDERR]                                    Defaults to color when connected to a
+[STDERR]                                    terminal, and no-color otherwise.
+[STDERR]     --[no-]dependency-overrides    Show resolutions with `dependency_overrides`.
+[STDERR]                                    (defaults to on)
+[STDERR]     --[no-]dev-dependencies        Take dev dependencies into account.
+[STDERR]                                    (defaults to on)
+[STDERR]     --json                         Output the results using a json format.
+[STDERR]     --mode=<PROPERTY>              Highlight versions with PROPERTY.
+[STDERR]                                    Only packages currently missing that PROPERTY
+[STDERR]                                    will be included unless --show-all.
+[STDERR]                                    [outdated (default), null-safety]
+[STDERR]     --[no-]prereleases             Include prereleases in latest version.
+[STDERR]                                    (defaults to on in --mode=null-safety).
+[STDERR]     --[no-]show-all                Include dependencies that are already
+[STDERR]                                    fullfilling --mode.
+[STDERR]     --[no-]transitive              Show transitive dependencies.
+[STDERR]                                    (defaults to off in --mode=null-safety).
+[STDERR] -C, --directory=<dir>              Run this in the directory<dir>.
+[STDERR] 
+[STDERR] Run "pub help" to see global options.
+[STDERR] See https://dart.dev/tools/pub/cmd/pub-outdated for detailed documentation.
+[EXIT CODE] 64
+
diff --git a/test/testdata/goldens/outdated/outdated_test/latest version reported while locked on a prerelease can be a prerelease.txt b/test/testdata/goldens/outdated/outdated_test/latest version reported while locked on a prerelease can be a prerelease.txt
new file mode 100644
index 0000000..12c2ee3
--- /dev/null
+++ b/test/testdata/goldens/outdated/outdated_test/latest version reported while locked on a prerelease can be a prerelease.txt
@@ -0,0 +1,296 @@
+# GENERATED BY: test/outdated/outdated_test.dart
+
+## Section 0
+$ pub outdated --json
+{
+  "packages": [
+    {
+      "package": "foo",
+      "current": {
+        "version": "1.0.0-dev.1"
+      },
+      "upgradable": {
+        "version": "1.0.0-dev.1"
+      },
+      "resolvable": {
+        "version": "1.0.0-dev.2"
+      },
+      "latest": {
+        "version": "1.0.0-dev.2"
+      }
+    },
+    {
+      "package": "mop",
+      "current": {
+        "version": "0.10.0-dev"
+      },
+      "upgradable": {
+        "version": "0.10.0-dev"
+      },
+      "resolvable": {
+        "version": "0.10.0"
+      },
+      "latest": {
+        "version": "0.10.0"
+      }
+    }
+  ]
+}
+
+-------------------------------- END OF OUTPUT ---------------------------------
+
+## Section 1
+$ pub outdated --no-color
+Showing outdated packages.
+[*] indicates versions that are not the latest available.
+
+Package Name  Current       Upgradable    Resolvable   Latest       
+
+direct dependencies:
+foo           *1.0.0-dev.1  *1.0.0-dev.1  1.0.0-dev.2  1.0.0-dev.2  
+mop           *0.10.0-dev   *0.10.0-dev   0.10.0       0.10.0       
+
+2  dependencies are constrained to versions that are older than a resolvable version.
+To update these dependencies, edit pubspec.yaml, or run `dart pub upgrade --major-versions`.
+
+-------------------------------- END OF OUTPUT ---------------------------------
+
+## Section 2
+$ pub outdated --no-color --no-transitive
+Showing outdated packages.
+[*] indicates versions that are not the latest available.
+
+Package Name  Current       Upgradable    Resolvable   Latest       
+
+direct dependencies:
+foo           *1.0.0-dev.1  *1.0.0-dev.1  1.0.0-dev.2  1.0.0-dev.2  
+mop           *0.10.0-dev   *0.10.0-dev   0.10.0       0.10.0       
+
+2  dependencies are constrained to versions that are older than a resolvable version.
+To update these dependencies, edit pubspec.yaml, or run `dart pub upgrade --major-versions`.
+
+-------------------------------- END OF OUTPUT ---------------------------------
+
+## Section 3
+$ pub outdated --no-color --up-to-date
+Showing outdated packages.
+[*] indicates versions that are not the latest available.
+
+Package Name  Current       Upgradable    Resolvable   Latest       
+
+direct dependencies:
+bar           0.9.0         0.9.0         0.9.0        0.9.0        
+foo           *1.0.0-dev.1  *1.0.0-dev.1  1.0.0-dev.2  1.0.0-dev.2  
+mop           *0.10.0-dev   *0.10.0-dev   0.10.0       0.10.0       
+
+2  dependencies are constrained to versions that are older than a resolvable version.
+To update these dependencies, edit pubspec.yaml, or run `dart pub upgrade --major-versions`.
+
+-------------------------------- END OF OUTPUT ---------------------------------
+
+## Section 4
+$ pub outdated --no-color --prereleases
+Showing outdated packages.
+[*] indicates versions that are not the latest available.
+
+Package Name  Current       Upgradable    Resolvable   Latest       
+
+direct dependencies:
+bar           *0.9.0        *0.9.0        *0.9.0       1.0.0-dev.2  
+foo           *1.0.0-dev.1  *1.0.0-dev.1  1.0.0-dev.2  1.0.0-dev.2  
+mop           *0.10.0-dev   *0.10.0-dev   *0.10.0      1.0.0-dev    
+
+2  dependencies are constrained to versions that are older than a resolvable version.
+To update these dependencies, edit pubspec.yaml, or run `dart pub upgrade --major-versions`.
+
+-------------------------------- END OF OUTPUT ---------------------------------
+
+## Section 5
+$ pub outdated --no-color --no-dev-dependencies
+Showing outdated packages.
+[*] indicates versions that are not the latest available.
+
+Package Name  Current       Upgradable    Resolvable   Latest       
+
+direct dependencies:
+foo           *1.0.0-dev.1  *1.0.0-dev.1  1.0.0-dev.2  1.0.0-dev.2  
+mop           *0.10.0-dev   *0.10.0-dev   0.10.0       0.10.0       
+
+2  dependencies are constrained to versions that are older than a resolvable version.
+To update these dependencies, edit pubspec.yaml, or run `dart pub upgrade --major-versions`.
+
+-------------------------------- END OF OUTPUT ---------------------------------
+
+## Section 6
+$ pub outdated --no-color --no-dependency-overrides
+Showing outdated packages.
+[*] indicates versions that are not the latest available.
+
+Package Name  Current       Upgradable    Resolvable   Latest       
+
+direct dependencies:
+foo           *1.0.0-dev.1  *1.0.0-dev.1  1.0.0-dev.2  1.0.0-dev.2  
+mop           *0.10.0-dev   *0.10.0-dev   0.10.0       0.10.0       
+
+2  dependencies are constrained to versions that are older than a resolvable version.
+To update these dependencies, edit pubspec.yaml, or run `dart pub upgrade --major-versions`.
+
+-------------------------------- END OF OUTPUT ---------------------------------
+
+## Section 7
+$ pub outdated --no-color --mode=null-safety
+Showing dependencies that are currently not opted in to null-safety.
+[✗] indicates versions without null safety support.
+[✓] indicates versions opting in to null safety.
+
+Package Name  Current       Upgradable    Resolvable    Latest        
+
+direct dependencies:
+bar           ✗0.9.0        ✗0.9.0        ✗0.9.0        ✗1.0.0-dev.2  
+foo           ✗1.0.0-dev.1  ✗1.0.0-dev.1  ✗1.0.0-dev.2  ✗1.0.0-dev.2  
+mop           ✗0.10.0-dev   ✗0.10.0-dev   ✗0.10.0       ✗1.0.0-dev    
+
+2  dependencies are constrained to versions that are older than a resolvable version.
+To update these dependencies, edit pubspec.yaml, or run `dart pub upgrade --null-safety`.
+
+-------------------------------- END OF OUTPUT ---------------------------------
+
+## Section 8
+$ pub outdated --no-color --mode=null-safety --transitive
+Showing dependencies that are currently not opted in to null-safety.
+[✗] indicates versions without null safety support.
+[✓] indicates versions opting in to null safety.
+
+Package Name  Current       Upgradable    Resolvable    Latest        
+
+direct dependencies:
+bar           ✗0.9.0        ✗0.9.0        ✗0.9.0        ✗1.0.0-dev.2  
+foo           ✗1.0.0-dev.1  ✗1.0.0-dev.1  ✗1.0.0-dev.2  ✗1.0.0-dev.2  
+mop           ✗0.10.0-dev   ✗0.10.0-dev   ✗0.10.0       ✗1.0.0-dev    
+
+2  dependencies are constrained to versions that are older than a resolvable version.
+To update these dependencies, edit pubspec.yaml, or run `dart pub upgrade --null-safety`.
+
+-------------------------------- END OF OUTPUT ---------------------------------
+
+## Section 9
+$ pub outdated --no-color --mode=null-safety --no-prereleases
+Showing dependencies that are currently not opted in to null-safety.
+[✗] indicates versions without null safety support.
+[✓] indicates versions opting in to null safety.
+
+Package Name  Current       Upgradable    Resolvable    Latest        
+
+direct dependencies:
+bar           ✗0.9.0        ✗0.9.0        ✗0.9.0        ✗0.9.0        
+foo           ✗1.0.0-dev.1  ✗1.0.0-dev.1  ✗1.0.0-dev.2  ✗1.0.0-dev.2  
+mop           ✗0.10.0-dev   ✗0.10.0-dev   ✗0.10.0       ✗0.10.0       
+
+2  dependencies are constrained to versions that are older than a resolvable version.
+To update these dependencies, edit pubspec.yaml, or run `dart pub upgrade --null-safety`.
+
+-------------------------------- END OF OUTPUT ---------------------------------
+
+## Section 10
+$ pub outdated --json --mode=null-safety
+{
+  "packages": [
+    {
+      "package": "bar",
+      "current": {
+        "version": "0.9.0",
+        "nullSafety": false
+      },
+      "upgradable": {
+        "version": "0.9.0",
+        "nullSafety": false
+      },
+      "resolvable": {
+        "version": "0.9.0",
+        "nullSafety": false
+      },
+      "latest": {
+        "version": "1.0.0-dev.2",
+        "nullSafety": false
+      }
+    },
+    {
+      "package": "foo",
+      "current": {
+        "version": "1.0.0-dev.1",
+        "nullSafety": false
+      },
+      "upgradable": {
+        "version": "1.0.0-dev.1",
+        "nullSafety": false
+      },
+      "resolvable": {
+        "version": "1.0.0-dev.2",
+        "nullSafety": false
+      },
+      "latest": {
+        "version": "1.0.0-dev.2",
+        "nullSafety": false
+      }
+    },
+    {
+      "package": "mop",
+      "current": {
+        "version": "0.10.0-dev",
+        "nullSafety": false
+      },
+      "upgradable": {
+        "version": "0.10.0-dev",
+        "nullSafety": false
+      },
+      "resolvable": {
+        "version": "0.10.0",
+        "nullSafety": false
+      },
+      "latest": {
+        "version": "1.0.0-dev",
+        "nullSafety": false
+      }
+    }
+  ]
+}
+
+-------------------------------- END OF OUTPUT ---------------------------------
+
+## Section 11
+$ pub outdated --json --no-dev-dependencies
+{
+  "packages": [
+    {
+      "package": "foo",
+      "current": {
+        "version": "1.0.0-dev.1"
+      },
+      "upgradable": {
+        "version": "1.0.0-dev.1"
+      },
+      "resolvable": {
+        "version": "1.0.0-dev.2"
+      },
+      "latest": {
+        "version": "1.0.0-dev.2"
+      }
+    },
+    {
+      "package": "mop",
+      "current": {
+        "version": "0.10.0-dev"
+      },
+      "upgradable": {
+        "version": "0.10.0-dev"
+      },
+      "resolvable": {
+        "version": "0.10.0"
+      },
+      "latest": {
+        "version": "0.10.0"
+      }
+    }
+  ]
+}
+
diff --git a/test/testdata/goldens/outdated/outdated_test/mutually incompatible newer versions.txt b/test/testdata/goldens/outdated/outdated_test/mutually incompatible newer versions.txt
new file mode 100644
index 0000000..18baa88
--- /dev/null
+++ b/test/testdata/goldens/outdated/outdated_test/mutually incompatible newer versions.txt
@@ -0,0 +1,263 @@
+# GENERATED BY: test/outdated/outdated_test.dart
+
+## Section 0
+$ pub outdated --json
+{
+  "packages": [
+    {
+      "package": "bar",
+      "current": {
+        "version": "1.0.0"
+      },
+      "upgradable": {
+        "version": "1.0.0"
+      },
+      "resolvable": {
+        "version": "1.0.0"
+      },
+      "latest": {
+        "version": "2.0.0"
+      }
+    },
+    {
+      "package": "foo",
+      "current": {
+        "version": "1.0.0"
+      },
+      "upgradable": {
+        "version": "1.0.0"
+      },
+      "resolvable": {
+        "version": "1.0.0"
+      },
+      "latest": {
+        "version": "2.0.0"
+      }
+    }
+  ]
+}
+
+-------------------------------- END OF OUTPUT ---------------------------------
+
+## Section 1
+$ pub outdated --no-color
+Showing outdated packages.
+[*] indicates versions that are not the latest available.
+
+Package Name  Current  Upgradable  Resolvable  Latest  
+
+direct dependencies:
+bar           *1.0.0   *1.0.0      *1.0.0      2.0.0   
+foo           *1.0.0   *1.0.0      *1.0.0      2.0.0   
+You are already using the newest resolvable versions listed in the 'Resolvable' column.
+Newer versions, listed in 'Latest', may not be mutually compatible.
+
+-------------------------------- END OF OUTPUT ---------------------------------
+
+## Section 2
+$ pub outdated --no-color --no-transitive
+Showing outdated packages.
+[*] indicates versions that are not the latest available.
+
+Package Name  Current  Upgradable  Resolvable  Latest  
+
+direct dependencies:
+bar           *1.0.0   *1.0.0      *1.0.0      2.0.0   
+foo           *1.0.0   *1.0.0      *1.0.0      2.0.0   
+You are already using the newest resolvable versions listed in the 'Resolvable' column.
+Newer versions, listed in 'Latest', may not be mutually compatible.
+
+-------------------------------- END OF OUTPUT ---------------------------------
+
+## Section 3
+$ pub outdated --no-color --up-to-date
+Showing outdated packages.
+[*] indicates versions that are not the latest available.
+
+Package Name  Current  Upgradable  Resolvable  Latest  
+
+direct dependencies:
+bar           *1.0.0   *1.0.0      *1.0.0      2.0.0   
+foo           *1.0.0   *1.0.0      *1.0.0      2.0.0   
+You are already using the newest resolvable versions listed in the 'Resolvable' column.
+Newer versions, listed in 'Latest', may not be mutually compatible.
+
+-------------------------------- END OF OUTPUT ---------------------------------
+
+## Section 4
+$ pub outdated --no-color --prereleases
+Showing outdated packages.
+[*] indicates versions that are not the latest available.
+
+Package Name  Current  Upgradable  Resolvable  Latest  
+
+direct dependencies:
+bar           *1.0.0   *1.0.0      *1.0.0      2.0.0   
+foo           *1.0.0   *1.0.0      *1.0.0      2.0.0   
+You are already using the newest resolvable versions listed in the 'Resolvable' column.
+Newer versions, listed in 'Latest', may not be mutually compatible.
+
+-------------------------------- END OF OUTPUT ---------------------------------
+
+## Section 5
+$ pub outdated --no-color --no-dev-dependencies
+Showing outdated packages.
+[*] indicates versions that are not the latest available.
+
+Package Name  Current  Upgradable  Resolvable  Latest  
+
+direct dependencies:
+bar           *1.0.0   *1.0.0      *1.0.0      2.0.0   
+foo           *1.0.0   *1.0.0      *1.0.0      2.0.0   
+You are already using the newest resolvable versions listed in the 'Resolvable' column.
+Newer versions, listed in 'Latest', may not be mutually compatible.
+
+-------------------------------- END OF OUTPUT ---------------------------------
+
+## Section 6
+$ pub outdated --no-color --no-dependency-overrides
+Showing outdated packages.
+[*] indicates versions that are not the latest available.
+
+Package Name  Current  Upgradable  Resolvable  Latest  
+
+direct dependencies:
+bar           *1.0.0   *1.0.0      *1.0.0      2.0.0   
+foo           *1.0.0   *1.0.0      *1.0.0      2.0.0   
+You are already using the newest resolvable versions listed in the 'Resolvable' column.
+Newer versions, listed in 'Latest', may not be mutually compatible.
+
+-------------------------------- END OF OUTPUT ---------------------------------
+
+## Section 7
+$ pub outdated --no-color --mode=null-safety
+Showing dependencies that are currently not opted in to null-safety.
+[✗] indicates versions without null safety support.
+[✓] indicates versions opting in to null safety.
+
+Package Name  Current  Upgradable  Resolvable  Latest  
+
+direct dependencies:
+bar           ✗1.0.0   ✗1.0.0      ✗1.0.0      ✗2.0.0  
+foo           ✗1.0.0   ✗1.0.0      ✗1.0.0      ✗2.0.0  
+You are already using the newest resolvable versions listed in the 'Resolvable' column.
+Newer versions, listed in 'Latest', may not be mutually compatible.
+
+-------------------------------- END OF OUTPUT ---------------------------------
+
+## Section 8
+$ pub outdated --no-color --mode=null-safety --transitive
+Showing dependencies that are currently not opted in to null-safety.
+[✗] indicates versions without null safety support.
+[✓] indicates versions opting in to null safety.
+
+Package Name  Current  Upgradable  Resolvable  Latest  
+
+direct dependencies:
+bar           ✗1.0.0   ✗1.0.0      ✗1.0.0      ✗2.0.0  
+foo           ✗1.0.0   ✗1.0.0      ✗1.0.0      ✗2.0.0  
+You are already using the newest resolvable versions listed in the 'Resolvable' column.
+Newer versions, listed in 'Latest', may not be mutually compatible.
+
+-------------------------------- END OF OUTPUT ---------------------------------
+
+## Section 9
+$ pub outdated --no-color --mode=null-safety --no-prereleases
+Showing dependencies that are currently not opted in to null-safety.
+[✗] indicates versions without null safety support.
+[✓] indicates versions opting in to null safety.
+
+Package Name  Current  Upgradable  Resolvable  Latest  
+
+direct dependencies:
+bar           ✗1.0.0   ✗1.0.0      ✗1.0.0      ✗2.0.0  
+foo           ✗1.0.0   ✗1.0.0      ✗1.0.0      ✗2.0.0  
+You are already using the newest resolvable versions listed in the 'Resolvable' column.
+Newer versions, listed in 'Latest', may not be mutually compatible.
+
+-------------------------------- END OF OUTPUT ---------------------------------
+
+## Section 10
+$ pub outdated --json --mode=null-safety
+{
+  "packages": [
+    {
+      "package": "bar",
+      "current": {
+        "version": "1.0.0",
+        "nullSafety": false
+      },
+      "upgradable": {
+        "version": "1.0.0",
+        "nullSafety": false
+      },
+      "resolvable": {
+        "version": "1.0.0",
+        "nullSafety": false
+      },
+      "latest": {
+        "version": "2.0.0",
+        "nullSafety": false
+      }
+    },
+    {
+      "package": "foo",
+      "current": {
+        "version": "1.0.0",
+        "nullSafety": false
+      },
+      "upgradable": {
+        "version": "1.0.0",
+        "nullSafety": false
+      },
+      "resolvable": {
+        "version": "1.0.0",
+        "nullSafety": false
+      },
+      "latest": {
+        "version": "2.0.0",
+        "nullSafety": false
+      }
+    }
+  ]
+}
+
+-------------------------------- END OF OUTPUT ---------------------------------
+
+## Section 11
+$ pub outdated --json --no-dev-dependencies
+{
+  "packages": [
+    {
+      "package": "bar",
+      "current": {
+        "version": "1.0.0"
+      },
+      "upgradable": {
+        "version": "1.0.0"
+      },
+      "resolvable": {
+        "version": "1.0.0"
+      },
+      "latest": {
+        "version": "2.0.0"
+      }
+    },
+    {
+      "package": "foo",
+      "current": {
+        "version": "1.0.0"
+      },
+      "upgradable": {
+        "version": "1.0.0"
+      },
+      "resolvable": {
+        "version": "1.0.0"
+      },
+      "latest": {
+        "version": "2.0.0"
+      }
+    }
+  ]
+}
+
diff --git a/test/testdata/goldens/outdated/outdated_test/newer versions available.txt b/test/testdata/goldens/outdated/outdated_test/newer versions available.txt
new file mode 100644
index 0000000..d6c0ff9
--- /dev/null
+++ b/test/testdata/goldens/outdated/outdated_test/newer versions available.txt
@@ -0,0 +1,514 @@
+# GENERATED BY: test/outdated/outdated_test.dart
+
+## Section 0
+$ pub outdated --json
+{
+  "packages": [
+    {
+      "package": "builder",
+      "current": {
+        "version": "1.2.3"
+      },
+      "upgradable": {
+        "version": "1.3.0"
+      },
+      "resolvable": {
+        "version": "2.0.0"
+      },
+      "latest": {
+        "version": "2.0.0"
+      }
+    },
+    {
+      "package": "dev_trans",
+      "current": {
+        "version": "1.0.0"
+      },
+      "upgradable": null,
+      "resolvable": {
+        "version": "1.0.0"
+      },
+      "latest": {
+        "version": "2.0.0"
+      }
+    },
+    {
+      "package": "foo",
+      "current": {
+        "version": "1.2.3"
+      },
+      "upgradable": {
+        "version": "1.3.0"
+      },
+      "resolvable": {
+        "version": "2.0.0"
+      },
+      "latest": {
+        "version": "3.0.0"
+      }
+    },
+    {
+      "package": "transitive",
+      "current": {
+        "version": "1.2.3"
+      },
+      "upgradable": {
+        "version": "1.3.0"
+      },
+      "resolvable": {
+        "version": "1.3.0"
+      },
+      "latest": {
+        "version": "2.0.0"
+      }
+    },
+    {
+      "package": "transitive2",
+      "current": null,
+      "upgradable": null,
+      "resolvable": {
+        "version": "1.0.0"
+      },
+      "latest": {
+        "version": "1.0.0"
+      }
+    },
+    {
+      "package": "transitive3",
+      "current": null,
+      "upgradable": null,
+      "resolvable": {
+        "version": "1.0.0"
+      },
+      "latest": {
+        "version": "1.0.0"
+      }
+    }
+  ]
+}
+
+-------------------------------- END OF OUTPUT ---------------------------------
+
+## Section 1
+$ pub outdated --no-color
+Showing outdated packages.
+[*] indicates versions that are not the latest available.
+
+Package Name  Current  Upgradable  Resolvable  Latest  
+
+direct dependencies:
+foo           *1.2.3   *1.3.0      *2.0.0      3.0.0   
+
+dev_dependencies:
+builder       *1.2.3   *1.3.0      2.0.0       2.0.0   
+
+transitive dependencies:
+transitive    *1.2.3   *1.3.0      *1.3.0      2.0.0   
+transitive2   -        -           1.0.0       1.0.0   
+
+transitive dev_dependencies:
+dev_trans     *1.0.0   -           *1.0.0      2.0.0   
+transitive3   -        -           1.0.0       1.0.0   
+
+3 upgradable dependencies are locked (in pubspec.lock) to older versions.
+To update these dependencies, use `dart pub upgrade`.
+
+3  dependencies are constrained to versions that are older than a resolvable version.
+To update these dependencies, edit pubspec.yaml, or run `dart pub upgrade --major-versions`.
+
+-------------------------------- END OF OUTPUT ---------------------------------
+
+## Section 2
+$ pub outdated --no-color --no-transitive
+Showing outdated packages.
+[*] indicates versions that are not the latest available.
+
+Package Name  Current  Upgradable  Resolvable  Latest  
+
+direct dependencies:
+foo           *1.2.3   *1.3.0      *2.0.0      3.0.0   
+
+dev_dependencies:
+builder       *1.2.3   *1.3.0      2.0.0       2.0.0   
+
+2 upgradable dependencies are locked (in pubspec.lock) to older versions.
+To update these dependencies, use `dart pub upgrade`.
+
+2  dependencies are constrained to versions that are older than a resolvable version.
+To update these dependencies, edit pubspec.yaml, or run `dart pub upgrade --major-versions`.
+
+-------------------------------- END OF OUTPUT ---------------------------------
+
+## Section 3
+$ pub outdated --no-color --up-to-date
+Showing outdated packages.
+[*] indicates versions that are not the latest available.
+
+Package Name   Current       Upgradable    Resolvable    Latest        
+
+direct dependencies:
+bar            1.0.0         1.0.0         1.0.0         1.0.0         
+foo            *1.2.3        *1.3.0        *2.0.0        3.0.0         
+local_package  0.0.1 (path)  0.0.1 (path)  0.0.1 (path)  0.0.1 (path)  
+
+dev_dependencies:
+builder        *1.2.3        *1.3.0        2.0.0         2.0.0         
+
+transitive dependencies:
+transitive     *1.2.3        *1.3.0        *1.3.0        2.0.0         
+transitive2    -             -             1.0.0         1.0.0         
+
+transitive dev_dependencies:
+dev_trans      *1.0.0        -             *1.0.0        2.0.0         
+transitive3    -             -             1.0.0         1.0.0         
+
+3 upgradable dependencies are locked (in pubspec.lock) to older versions.
+To update these dependencies, use `dart pub upgrade`.
+
+3  dependencies are constrained to versions that are older than a resolvable version.
+To update these dependencies, edit pubspec.yaml, or run `dart pub upgrade --major-versions`.
+
+-------------------------------- END OF OUTPUT ---------------------------------
+
+## Section 4
+$ pub outdated --no-color --prereleases
+Showing outdated packages.
+[*] indicates versions that are not the latest available.
+
+Package Name  Current  Upgradable  Resolvable  Latest       
+
+direct dependencies:
+foo           *1.2.3   *1.3.0      *2.0.0      3.0.0        
+
+dev_dependencies:
+builder       *1.2.3   *1.3.0      *2.0.0      3.0.0-alpha  
+
+transitive dependencies:
+transitive    *1.2.3   *1.3.0      *1.3.0      2.0.0        
+transitive2   -        -           1.0.0       1.0.0        
+
+transitive dev_dependencies:
+dev_trans     *1.0.0   -           *1.0.0      2.0.0        
+transitive3   -        -           1.0.0       1.0.0        
+
+3 upgradable dependencies are locked (in pubspec.lock) to older versions.
+To update these dependencies, use `dart pub upgrade`.
+
+3  dependencies are constrained to versions that are older than a resolvable version.
+To update these dependencies, edit pubspec.yaml, or run `dart pub upgrade --major-versions`.
+
+-------------------------------- END OF OUTPUT ---------------------------------
+
+## Section 5
+$ pub outdated --no-color --no-dev-dependencies
+Showing outdated packages.
+[*] indicates versions that are not the latest available.
+
+Package Name  Current  Upgradable  Resolvable  Latest  
+
+direct dependencies:
+foo           *1.2.3   *1.3.0      3.0.0       3.0.0   
+
+transitive dependencies:
+transitive    *1.2.3   2.0.0       2.0.0       2.0.0   
+
+2 upgradable dependencies are locked (in pubspec.lock) to older versions.
+To update these dependencies, use `dart pub upgrade`.
+
+1 dependency is constrained to a version that is older than a resolvable version.
+To update it, edit pubspec.yaml, or run `dart pub upgrade --major-versions`.
+
+-------------------------------- END OF OUTPUT ---------------------------------
+
+## Section 6
+$ pub outdated --no-color --no-dependency-overrides
+Showing outdated packages.
+[*] indicates versions that are not the latest available.
+
+Package Name  Current  Upgradable  Resolvable  Latest  
+
+direct dependencies:
+foo           *1.2.3   *1.3.0      *2.0.0      3.0.0   
+
+dev_dependencies:
+builder       *1.2.3   *1.3.0      2.0.0       2.0.0   
+
+transitive dependencies:
+transitive    *1.2.3   *1.3.0      *1.3.0      2.0.0   
+transitive2   -        -           1.0.0       1.0.0   
+
+transitive dev_dependencies:
+dev_trans     *1.0.0   -           *1.0.0      2.0.0   
+transitive3   -        -           1.0.0       1.0.0   
+
+3 upgradable dependencies are locked (in pubspec.lock) to older versions.
+To update these dependencies, use `dart pub upgrade`.
+
+3  dependencies are constrained to versions that are older than a resolvable version.
+To update these dependencies, edit pubspec.yaml, or run `dart pub upgrade --major-versions`.
+
+-------------------------------- END OF OUTPUT ---------------------------------
+
+## Section 7
+$ pub outdated --no-color --mode=null-safety
+Showing dependencies that are currently not opted in to null-safety.
+[✗] indicates versions without null safety support.
+[✓] indicates versions opting in to null safety.
+
+Package Name   Current        Upgradable     Resolvable     Latest         
+
+direct dependencies:
+bar            ✗1.0.0         ✗1.0.0         ✗1.0.0         ✗1.0.0         
+foo            ✗1.2.3         ✗1.3.0         ✗2.0.0         ✗3.0.0         
+local_package  ✗0.0.1 (path)  ✗0.0.1 (path)  ✗0.0.1 (path)  ✗0.0.1 (path)  
+
+dev_dependencies:
+builder        ✗1.2.3         ✗1.3.0         ✗2.0.0         ✗3.0.0-alpha   
+
+2 upgradable dependencies are locked (in pubspec.lock) to older versions.
+To update these dependencies, use `dart pub upgrade`.
+
+2  dependencies are constrained to versions that are older than a resolvable version.
+To update these dependencies, edit pubspec.yaml, or run `dart pub upgrade --null-safety`.
+
+-------------------------------- END OF OUTPUT ---------------------------------
+
+## Section 8
+$ pub outdated --no-color --mode=null-safety --transitive
+Showing dependencies that are currently not opted in to null-safety.
+[✗] indicates versions without null safety support.
+[✓] indicates versions opting in to null safety.
+
+Package Name   Current        Upgradable     Resolvable     Latest         
+
+direct dependencies:
+bar            ✗1.0.0         ✗1.0.0         ✗1.0.0         ✗1.0.0         
+foo            ✗1.2.3         ✗1.3.0         ✗2.0.0         ✗3.0.0         
+local_package  ✗0.0.1 (path)  ✗0.0.1 (path)  ✗0.0.1 (path)  ✗0.0.1 (path)  
+
+dev_dependencies:
+builder        ✗1.2.3         ✗1.3.0         ✗2.0.0         ✗3.0.0-alpha   
+
+transitive dependencies:
+transitive     ✗1.2.3         ✗1.3.0         ✗1.3.0         ✗2.0.0         
+transitive2    -              -              ✗1.0.0         ✗1.0.0         
+
+transitive dev_dependencies:
+dev_trans      ✗1.0.0         -              ✗1.0.0         ✗2.0.0         
+transitive3    -              -              ✗1.0.0         ✗1.0.0         
+
+3 upgradable dependencies are locked (in pubspec.lock) to older versions.
+To update these dependencies, use `dart pub upgrade`.
+
+3  dependencies are constrained to versions that are older than a resolvable version.
+To update these dependencies, edit pubspec.yaml, or run `dart pub upgrade --null-safety`.
+
+-------------------------------- END OF OUTPUT ---------------------------------
+
+## Section 9
+$ pub outdated --no-color --mode=null-safety --no-prereleases
+Showing dependencies that are currently not opted in to null-safety.
+[✗] indicates versions without null safety support.
+[✓] indicates versions opting in to null safety.
+
+Package Name   Current        Upgradable     Resolvable     Latest         
+
+direct dependencies:
+bar            ✗1.0.0         ✗1.0.0         ✗1.0.0         ✗1.0.0         
+foo            ✗1.2.3         ✗1.3.0         ✗2.0.0         ✗3.0.0         
+local_package  ✗0.0.1 (path)  ✗0.0.1 (path)  ✗0.0.1 (path)  ✗0.0.1 (path)  
+
+dev_dependencies:
+builder        ✗1.2.3         ✗1.3.0         ✗2.0.0         ✗2.0.0         
+
+2 upgradable dependencies are locked (in pubspec.lock) to older versions.
+To update these dependencies, use `dart pub upgrade`.
+
+2  dependencies are constrained to versions that are older than a resolvable version.
+To update these dependencies, edit pubspec.yaml, or run `dart pub upgrade --null-safety`.
+
+-------------------------------- END OF OUTPUT ---------------------------------
+
+## Section 10
+$ pub outdated --json --mode=null-safety
+{
+  "packages": [
+    {
+      "package": "bar",
+      "current": {
+        "version": "1.0.0",
+        "nullSafety": false
+      },
+      "upgradable": {
+        "version": "1.0.0",
+        "nullSafety": false
+      },
+      "resolvable": {
+        "version": "1.0.0",
+        "nullSafety": false
+      },
+      "latest": {
+        "version": "1.0.0",
+        "nullSafety": false
+      }
+    },
+    {
+      "package": "builder",
+      "current": {
+        "version": "1.2.3",
+        "nullSafety": false
+      },
+      "upgradable": {
+        "version": "1.3.0",
+        "nullSafety": false
+      },
+      "resolvable": {
+        "version": "2.0.0",
+        "nullSafety": false
+      },
+      "latest": {
+        "version": "3.0.0-alpha",
+        "nullSafety": false
+      }
+    },
+    {
+      "package": "dev_trans",
+      "current": {
+        "version": "1.0.0",
+        "nullSafety": false
+      },
+      "upgradable": null,
+      "resolvable": {
+        "version": "1.0.0",
+        "nullSafety": false
+      },
+      "latest": {
+        "version": "2.0.0",
+        "nullSafety": false
+      }
+    },
+    {
+      "package": "foo",
+      "current": {
+        "version": "1.2.3",
+        "nullSafety": false
+      },
+      "upgradable": {
+        "version": "1.3.0",
+        "nullSafety": false
+      },
+      "resolvable": {
+        "version": "2.0.0",
+        "nullSafety": false
+      },
+      "latest": {
+        "version": "3.0.0",
+        "nullSafety": false
+      }
+    },
+    {
+      "package": "local_package",
+      "current": {
+        "version": "0.0.1",
+        "nullSafety": false
+      },
+      "upgradable": {
+        "version": "0.0.1",
+        "nullSafety": false
+      },
+      "resolvable": {
+        "version": "0.0.1",
+        "nullSafety": false
+      },
+      "latest": {
+        "version": "0.0.1",
+        "nullSafety": false
+      }
+    },
+    {
+      "package": "transitive",
+      "current": {
+        "version": "1.2.3",
+        "nullSafety": false
+      },
+      "upgradable": {
+        "version": "1.3.0",
+        "nullSafety": false
+      },
+      "resolvable": {
+        "version": "1.3.0",
+        "nullSafety": false
+      },
+      "latest": {
+        "version": "2.0.0",
+        "nullSafety": false
+      }
+    },
+    {
+      "package": "transitive2",
+      "current": null,
+      "upgradable": null,
+      "resolvable": {
+        "version": "1.0.0",
+        "nullSafety": false
+      },
+      "latest": {
+        "version": "1.0.0",
+        "nullSafety": false
+      }
+    },
+    {
+      "package": "transitive3",
+      "current": null,
+      "upgradable": null,
+      "resolvable": {
+        "version": "1.0.0",
+        "nullSafety": false
+      },
+      "latest": {
+        "version": "1.0.0",
+        "nullSafety": false
+      }
+    }
+  ]
+}
+
+-------------------------------- END OF OUTPUT ---------------------------------
+
+## Section 11
+$ pub outdated --json --no-dev-dependencies
+{
+  "packages": [
+    {
+      "package": "foo",
+      "current": {
+        "version": "1.2.3"
+      },
+      "upgradable": {
+        "version": "1.3.0"
+      },
+      "resolvable": {
+        "version": "3.0.0"
+      },
+      "latest": {
+        "version": "3.0.0"
+      }
+    },
+    {
+      "package": "transitive",
+      "current": {
+        "version": "1.2.3"
+      },
+      "upgradable": {
+        "version": "2.0.0"
+      },
+      "resolvable": {
+        "version": "2.0.0"
+      },
+      "latest": {
+        "version": "2.0.0"
+      }
+    }
+  ]
+}
+
diff --git a/test/testdata/goldens/outdated/outdated_test/no dependencies.txt b/test/testdata/goldens/outdated/outdated_test/no dependencies.txt
new file mode 100644
index 0000000..d256d7f
--- /dev/null
+++ b/test/testdata/goldens/outdated/outdated_test/no dependencies.txt
@@ -0,0 +1,108 @@
+# GENERATED BY: test/outdated/outdated_test.dart
+
+## Section 0
+$ pub outdated --json
+{
+  "packages": []
+}
+
+-------------------------------- END OF OUTPUT ---------------------------------
+
+## Section 1
+$ pub outdated --no-color
+Showing outdated packages.
+[*] indicates versions that are not the latest available.
+
+Found no outdated packages
+
+-------------------------------- END OF OUTPUT ---------------------------------
+
+## Section 2
+$ pub outdated --no-color --no-transitive
+Showing outdated packages.
+[*] indicates versions that are not the latest available.
+
+Found no outdated packages
+
+-------------------------------- END OF OUTPUT ---------------------------------
+
+## Section 3
+$ pub outdated --no-color --up-to-date
+Showing outdated packages.
+[*] indicates versions that are not the latest available.
+
+Found no outdated packages
+
+-------------------------------- END OF OUTPUT ---------------------------------
+
+## Section 4
+$ pub outdated --no-color --prereleases
+Showing outdated packages.
+[*] indicates versions that are not the latest available.
+
+Found no outdated packages
+
+-------------------------------- END OF OUTPUT ---------------------------------
+
+## Section 5
+$ pub outdated --no-color --no-dev-dependencies
+Showing outdated packages.
+[*] indicates versions that are not the latest available.
+
+Found no outdated packages
+
+-------------------------------- END OF OUTPUT ---------------------------------
+
+## Section 6
+$ pub outdated --no-color --no-dependency-overrides
+Showing outdated packages.
+[*] indicates versions that are not the latest available.
+
+Found no outdated packages
+
+-------------------------------- END OF OUTPUT ---------------------------------
+
+## Section 7
+$ pub outdated --no-color --mode=null-safety
+Showing dependencies that are currently not opted in to null-safety.
+[✗] indicates versions without null safety support.
+[✓] indicates versions opting in to null safety.
+
+All your dependencies declare support for null-safety.
+
+-------------------------------- END OF OUTPUT ---------------------------------
+
+## Section 8
+$ pub outdated --no-color --mode=null-safety --transitive
+Showing dependencies that are currently not opted in to null-safety.
+[✗] indicates versions without null safety support.
+[✓] indicates versions opting in to null safety.
+
+All your dependencies declare support for null-safety.
+
+-------------------------------- END OF OUTPUT ---------------------------------
+
+## Section 9
+$ pub outdated --no-color --mode=null-safety --no-prereleases
+Showing dependencies that are currently not opted in to null-safety.
+[✗] indicates versions without null safety support.
+[✓] indicates versions opting in to null safety.
+
+All your dependencies declare support for null-safety.
+
+-------------------------------- END OF OUTPUT ---------------------------------
+
+## Section 10
+$ pub outdated --json --mode=null-safety
+{
+  "packages": []
+}
+
+-------------------------------- END OF OUTPUT ---------------------------------
+
+## Section 11
+$ pub outdated --json --no-dev-dependencies
+{
+  "packages": []
+}
+
diff --git a/test/testdata/goldens/outdated/outdated_test/no lockfile.txt b/test/testdata/goldens/outdated/outdated_test/no lockfile.txt
new file mode 100644
index 0000000..7f670db
--- /dev/null
+++ b/test/testdata/goldens/outdated/outdated_test/no lockfile.txt
@@ -0,0 +1,285 @@
+# GENERATED BY: test/outdated/outdated_test.dart
+
+## Section 0
+$ pub outdated --json
+{
+  "packages": [
+    {
+      "package": "bar",
+      "current": null,
+      "upgradable": {
+        "version": "1.2.3"
+      },
+      "resolvable": {
+        "version": "2.0.0"
+      },
+      "latest": {
+        "version": "2.0.0"
+      }
+    },
+    {
+      "package": "foo",
+      "current": null,
+      "upgradable": {
+        "version": "1.2.3"
+      },
+      "resolvable": {
+        "version": "1.2.3"
+      },
+      "latest": {
+        "version": "1.2.3"
+      }
+    }
+  ]
+}
+
+-------------------------------- END OF OUTPUT ---------------------------------
+
+## Section 1
+$ pub outdated --no-color
+Showing outdated packages.
+[*] indicates versions that are not the latest available.
+
+Package Name  Current  Upgradable  Resolvable  Latest  
+
+direct dependencies:
+bar           -        *1.2.3      2.0.0       2.0.0   
+foo           -        1.2.3       1.2.3       1.2.3   
+
+No pubspec.lock found. There are no Current versions.
+Run `pub get` to create a pubspec.lock with versions matching your pubspec.yaml.
+
+1 dependency is constrained to a version that is older than a resolvable version.
+To update it, edit pubspec.yaml, or run `dart pub upgrade --major-versions`.
+
+-------------------------------- END OF OUTPUT ---------------------------------
+
+## Section 2
+$ pub outdated --no-color --no-transitive
+Showing outdated packages.
+[*] indicates versions that are not the latest available.
+
+Package Name  Current  Upgradable  Resolvable  Latest  
+
+direct dependencies:
+bar           -        *1.2.3      2.0.0       2.0.0   
+foo           -        1.2.3       1.2.3       1.2.3   
+
+No pubspec.lock found. There are no Current versions.
+Run `pub get` to create a pubspec.lock with versions matching your pubspec.yaml.
+
+1 dependency is constrained to a version that is older than a resolvable version.
+To update it, edit pubspec.yaml, or run `dart pub upgrade --major-versions`.
+
+-------------------------------- END OF OUTPUT ---------------------------------
+
+## Section 3
+$ pub outdated --no-color --up-to-date
+Showing outdated packages.
+[*] indicates versions that are not the latest available.
+
+Package Name  Current  Upgradable  Resolvable  Latest  
+
+direct dependencies:
+bar           -        *1.2.3      2.0.0       2.0.0   
+foo           -        1.2.3       1.2.3       1.2.3   
+
+No pubspec.lock found. There are no Current versions.
+Run `pub get` to create a pubspec.lock with versions matching your pubspec.yaml.
+
+1 dependency is constrained to a version that is older than a resolvable version.
+To update it, edit pubspec.yaml, or run `dart pub upgrade --major-versions`.
+
+-------------------------------- END OF OUTPUT ---------------------------------
+
+## Section 4
+$ pub outdated --no-color --prereleases
+Showing outdated packages.
+[*] indicates versions that are not the latest available.
+
+Package Name  Current  Upgradable  Resolvable  Latest  
+
+direct dependencies:
+bar           -        *1.2.3      2.0.0       2.0.0   
+foo           -        1.2.3       1.2.3       1.2.3   
+
+No pubspec.lock found. There are no Current versions.
+Run `pub get` to create a pubspec.lock with versions matching your pubspec.yaml.
+
+1 dependency is constrained to a version that is older than a resolvable version.
+To update it, edit pubspec.yaml, or run `dart pub upgrade --major-versions`.
+
+-------------------------------- END OF OUTPUT ---------------------------------
+
+## Section 5
+$ pub outdated --no-color --no-dev-dependencies
+Showing outdated packages.
+[*] indicates versions that are not the latest available.
+
+Package Name  Current  Upgradable  Resolvable  Latest  
+
+direct dependencies:
+bar           -        *1.2.3      2.0.0       2.0.0   
+foo           -        1.2.3       1.2.3       1.2.3   
+
+No pubspec.lock found. There are no Current versions.
+Run `pub get` to create a pubspec.lock with versions matching your pubspec.yaml.
+
+1 dependency is constrained to a version that is older than a resolvable version.
+To update it, edit pubspec.yaml, or run `dart pub upgrade --major-versions`.
+
+-------------------------------- END OF OUTPUT ---------------------------------
+
+## Section 6
+$ pub outdated --no-color --no-dependency-overrides
+Showing outdated packages.
+[*] indicates versions that are not the latest available.
+
+Package Name  Current  Upgradable  Resolvable  Latest  
+
+direct dependencies:
+bar           -        *1.2.3      2.0.0       2.0.0   
+foo           -        1.2.3       1.2.3       1.2.3   
+
+No pubspec.lock found. There are no Current versions.
+Run `pub get` to create a pubspec.lock with versions matching your pubspec.yaml.
+
+1 dependency is constrained to a version that is older than a resolvable version.
+To update it, edit pubspec.yaml, or run `dart pub upgrade --major-versions`.
+
+-------------------------------- END OF OUTPUT ---------------------------------
+
+## Section 7
+$ pub outdated --no-color --mode=null-safety
+Showing dependencies that are currently not opted in to null-safety.
+[✗] indicates versions without null safety support.
+[✓] indicates versions opting in to null safety.
+
+Package Name  Current  Upgradable  Resolvable  Latest  
+
+direct dependencies:
+bar           -        ✗1.2.3      ✗2.0.0      ✗2.0.0  
+foo           -        ✗1.2.3      ✗1.2.3      ✗1.2.3  
+
+No pubspec.lock found. There are no Current versions.
+Run `pub get` to create a pubspec.lock with versions matching your pubspec.yaml.
+
+1 dependency is constrained to a version that is older than a resolvable version.
+To update it, edit pubspec.yaml, or run `dart pub upgrade --null-safety`.
+
+-------------------------------- END OF OUTPUT ---------------------------------
+
+## Section 8
+$ pub outdated --no-color --mode=null-safety --transitive
+Showing dependencies that are currently not opted in to null-safety.
+[✗] indicates versions without null safety support.
+[✓] indicates versions opting in to null safety.
+
+Package Name  Current  Upgradable  Resolvable  Latest  
+
+direct dependencies:
+bar           -        ✗1.2.3      ✗2.0.0      ✗2.0.0  
+foo           -        ✗1.2.3      ✗1.2.3      ✗1.2.3  
+
+No pubspec.lock found. There are no Current versions.
+Run `pub get` to create a pubspec.lock with versions matching your pubspec.yaml.
+
+1 dependency is constrained to a version that is older than a resolvable version.
+To update it, edit pubspec.yaml, or run `dart pub upgrade --null-safety`.
+
+-------------------------------- END OF OUTPUT ---------------------------------
+
+## Section 9
+$ pub outdated --no-color --mode=null-safety --no-prereleases
+Showing dependencies that are currently not opted in to null-safety.
+[✗] indicates versions without null safety support.
+[✓] indicates versions opting in to null safety.
+
+Package Name  Current  Upgradable  Resolvable  Latest  
+
+direct dependencies:
+bar           -        ✗1.2.3      ✗2.0.0      ✗2.0.0  
+foo           -        ✗1.2.3      ✗1.2.3      ✗1.2.3  
+
+No pubspec.lock found. There are no Current versions.
+Run `pub get` to create a pubspec.lock with versions matching your pubspec.yaml.
+
+1 dependency is constrained to a version that is older than a resolvable version.
+To update it, edit pubspec.yaml, or run `dart pub upgrade --null-safety`.
+
+-------------------------------- END OF OUTPUT ---------------------------------
+
+## Section 10
+$ pub outdated --json --mode=null-safety
+{
+  "packages": [
+    {
+      "package": "bar",
+      "current": null,
+      "upgradable": {
+        "version": "1.2.3",
+        "nullSafety": false
+      },
+      "resolvable": {
+        "version": "2.0.0",
+        "nullSafety": false
+      },
+      "latest": {
+        "version": "2.0.0",
+        "nullSafety": false
+      }
+    },
+    {
+      "package": "foo",
+      "current": null,
+      "upgradable": {
+        "version": "1.2.3",
+        "nullSafety": false
+      },
+      "resolvable": {
+        "version": "1.2.3",
+        "nullSafety": false
+      },
+      "latest": {
+        "version": "1.2.3",
+        "nullSafety": false
+      }
+    }
+  ]
+}
+
+-------------------------------- END OF OUTPUT ---------------------------------
+
+## Section 11
+$ pub outdated --json --no-dev-dependencies
+{
+  "packages": [
+    {
+      "package": "bar",
+      "current": null,
+      "upgradable": {
+        "version": "1.2.3"
+      },
+      "resolvable": {
+        "version": "2.0.0"
+      },
+      "latest": {
+        "version": "2.0.0"
+      }
+    },
+    {
+      "package": "foo",
+      "current": null,
+      "upgradable": {
+        "version": "1.2.3"
+      },
+      "resolvable": {
+        "version": "1.2.3"
+      },
+      "latest": {
+        "version": "1.2.3"
+      }
+    }
+  ]
+}
+
diff --git a/test/testdata/goldens/outdated/outdated_test/no pubspec.txt b/test/testdata/goldens/outdated/outdated_test/no pubspec.txt
new file mode 100644
index 0000000..ba8858a
--- /dev/null
+++ b/test/testdata/goldens/outdated/outdated_test/no pubspec.txt
@@ -0,0 +1,7 @@
+# GENERATED BY: test/outdated/outdated_test.dart
+
+## Section 0
+$ pub outdated
+[STDERR] Could not find a file named "pubspec.yaml" in "$SANDBOX/myapp".
+[EXIT CODE] 66
+
diff --git a/test/testdata/goldens/outdated/outdated_test/null safety compliance.txt b/test/testdata/goldens/outdated/outdated_test/null safety compliance.txt
new file mode 100644
index 0000000..d345f55
--- /dev/null
+++ b/test/testdata/goldens/outdated/outdated_test/null safety compliance.txt
@@ -0,0 +1,416 @@
+# GENERATED BY: test/outdated/outdated_test.dart
+
+## Section 0
+$ pub outdated --json
+{
+  "packages": [
+    {
+      "package": "bar",
+      "current": {
+        "version": "1.0.0"
+      },
+      "upgradable": {
+        "version": "1.0.0"
+      },
+      "resolvable": {
+        "version": "2.0.0"
+      },
+      "latest": {
+        "version": "2.0.0"
+      }
+    },
+    {
+      "package": "fails_analysis",
+      "current": {
+        "version": "1.0.0"
+      },
+      "upgradable": {
+        "version": "1.0.0"
+      },
+      "resolvable": {
+        "version": "2.0.0"
+      },
+      "latest": {
+        "version": "2.0.0"
+      }
+    },
+    {
+      "package": "fails_analysis_in_dependency",
+      "current": {
+        "version": "1.0.0"
+      },
+      "upgradable": {
+        "version": "1.0.0"
+      },
+      "resolvable": {
+        "version": "2.0.0"
+      },
+      "latest": {
+        "version": "2.0.0"
+      }
+    },
+    {
+      "package": "file_in_dependency_opts_out",
+      "current": {
+        "version": "1.0.0"
+      },
+      "upgradable": {
+        "version": "1.0.0"
+      },
+      "resolvable": {
+        "version": "2.0.0"
+      },
+      "latest": {
+        "version": "2.0.0"
+      }
+    },
+    {
+      "package": "file_opts_out",
+      "current": {
+        "version": "1.0.0"
+      },
+      "upgradable": {
+        "version": "1.0.0"
+      },
+      "resolvable": {
+        "version": "2.0.0"
+      },
+      "latest": {
+        "version": "2.0.0"
+      }
+    },
+    {
+      "package": "foo",
+      "current": {
+        "version": "1.0.0"
+      },
+      "upgradable": {
+        "version": "1.0.0"
+      },
+      "resolvable": {
+        "version": "2.0.0-nullsafety.0"
+      },
+      "latest": {
+        "version": "2.0.0"
+      }
+    }
+  ]
+}
+
+-------------------------------- END OF OUTPUT ---------------------------------
+
+## Section 1
+$ pub outdated --no-color
+Showing outdated packages.
+[*] indicates versions that are not the latest available.
+
+Package Name                  Current  Upgradable  Resolvable           Latest  
+
+direct dependencies:         
+bar                           *1.0.0   *1.0.0      2.0.0                2.0.0   
+fails_analysis                *1.0.0   *1.0.0      2.0.0                2.0.0   
+fails_analysis_in_dependency  *1.0.0   *1.0.0      2.0.0                2.0.0   
+file_in_dependency_opts_out   *1.0.0   *1.0.0      2.0.0                2.0.0   
+file_opts_out                 *1.0.0   *1.0.0      2.0.0                2.0.0   
+foo                           *1.0.0   *1.0.0      *2.0.0-nullsafety.0  2.0.0   
+
+6  dependencies are constrained to versions that are older than a resolvable version.
+To update these dependencies, edit pubspec.yaml, or run `dart pub upgrade --major-versions`.
+
+-------------------------------- END OF OUTPUT ---------------------------------
+
+## Section 2
+$ pub outdated --no-color --no-transitive
+Showing outdated packages.
+[*] indicates versions that are not the latest available.
+
+Package Name                  Current  Upgradable  Resolvable           Latest  
+
+direct dependencies:         
+bar                           *1.0.0   *1.0.0      2.0.0                2.0.0   
+fails_analysis                *1.0.0   *1.0.0      2.0.0                2.0.0   
+fails_analysis_in_dependency  *1.0.0   *1.0.0      2.0.0                2.0.0   
+file_in_dependency_opts_out   *1.0.0   *1.0.0      2.0.0                2.0.0   
+file_opts_out                 *1.0.0   *1.0.0      2.0.0                2.0.0   
+foo                           *1.0.0   *1.0.0      *2.0.0-nullsafety.0  2.0.0   
+
+6  dependencies are constrained to versions that are older than a resolvable version.
+To update these dependencies, edit pubspec.yaml, or run `dart pub upgrade --major-versions`.
+
+-------------------------------- END OF OUTPUT ---------------------------------
+
+## Section 3
+$ pub outdated --no-color --up-to-date
+Showing outdated packages.
+[*] indicates versions that are not the latest available.
+
+Package Name                  Current  Upgradable  Resolvable           Latest  
+
+direct dependencies:         
+bar                           *1.0.0   *1.0.0      2.0.0                2.0.0   
+fails_analysis                *1.0.0   *1.0.0      2.0.0                2.0.0   
+fails_analysis_in_dependency  *1.0.0   *1.0.0      2.0.0                2.0.0   
+file_in_dependency_opts_out   *1.0.0   *1.0.0      2.0.0                2.0.0   
+file_opts_out                 *1.0.0   *1.0.0      2.0.0                2.0.0   
+foo                           *1.0.0   *1.0.0      *2.0.0-nullsafety.0  2.0.0   
+
+6  dependencies are constrained to versions that are older than a resolvable version.
+To update these dependencies, edit pubspec.yaml, or run `dart pub upgrade --major-versions`.
+
+-------------------------------- END OF OUTPUT ---------------------------------
+
+## Section 4
+$ pub outdated --no-color --prereleases
+Showing outdated packages.
+[*] indicates versions that are not the latest available.
+
+Package Name                  Current  Upgradable  Resolvable           Latest  
+
+direct dependencies:         
+bar                           *1.0.0   *1.0.0      2.0.0                2.0.0   
+fails_analysis                *1.0.0   *1.0.0      2.0.0                2.0.0   
+fails_analysis_in_dependency  *1.0.0   *1.0.0      2.0.0                2.0.0   
+file_in_dependency_opts_out   *1.0.0   *1.0.0      2.0.0                2.0.0   
+file_opts_out                 *1.0.0   *1.0.0      2.0.0                2.0.0   
+foo                           *1.0.0   *1.0.0      *2.0.0-nullsafety.0  2.0.0   
+
+6  dependencies are constrained to versions that are older than a resolvable version.
+To update these dependencies, edit pubspec.yaml, or run `dart pub upgrade --major-versions`.
+
+-------------------------------- END OF OUTPUT ---------------------------------
+
+## Section 5
+$ pub outdated --no-color --no-dev-dependencies
+Showing outdated packages.
+[*] indicates versions that are not the latest available.
+
+Package Name                  Current  Upgradable  Resolvable           Latest  
+
+direct dependencies:         
+bar                           *1.0.0   *1.0.0      2.0.0                2.0.0   
+fails_analysis                *1.0.0   *1.0.0      2.0.0                2.0.0   
+fails_analysis_in_dependency  *1.0.0   *1.0.0      2.0.0                2.0.0   
+file_in_dependency_opts_out   *1.0.0   *1.0.0      2.0.0                2.0.0   
+file_opts_out                 *1.0.0   *1.0.0      2.0.0                2.0.0   
+foo                           *1.0.0   *1.0.0      *2.0.0-nullsafety.0  2.0.0   
+
+6  dependencies are constrained to versions that are older than a resolvable version.
+To update these dependencies, edit pubspec.yaml, or run `dart pub upgrade --major-versions`.
+
+-------------------------------- END OF OUTPUT ---------------------------------
+
+## Section 6
+$ pub outdated --no-color --no-dependency-overrides
+Showing outdated packages.
+[*] indicates versions that are not the latest available.
+
+Package Name                  Current  Upgradable  Resolvable           Latest  
+
+direct dependencies:         
+bar                           *1.0.0   *1.0.0      2.0.0                2.0.0   
+fails_analysis                *1.0.0   *1.0.0      2.0.0                2.0.0   
+fails_analysis_in_dependency  *1.0.0   *1.0.0      2.0.0                2.0.0   
+file_in_dependency_opts_out   *1.0.0   *1.0.0      2.0.0                2.0.0   
+file_opts_out                 *1.0.0   *1.0.0      2.0.0                2.0.0   
+foo                           *1.0.0   *1.0.0      *2.0.0-nullsafety.0  2.0.0   
+
+6  dependencies are constrained to versions that are older than a resolvable version.
+To update these dependencies, edit pubspec.yaml, or run `dart pub upgrade --major-versions`.
+
+-------------------------------- END OF OUTPUT ---------------------------------
+
+## Section 7
+$ pub outdated --no-color --mode=null-safety
+Showing dependencies that are currently not opted in to null-safety.
+[✗] indicates versions without null safety support.
+[✓] indicates versions opting in to null safety.
+
+Package Name  Current  Upgradable  Resolvable           Latest  
+
+direct dependencies:
+bar           ✗1.0.0   ✗1.0.0      ✓2.0.0               ✓2.0.0  
+foo           ✗1.0.0   ✗1.0.0      ✓2.0.0-nullsafety.0  ✓2.0.0  
+
+2  dependencies are constrained to versions that are older than a resolvable version.
+To update these dependencies, edit pubspec.yaml, or run `dart pub upgrade --null-safety`.
+
+-------------------------------- END OF OUTPUT ---------------------------------
+
+## Section 8
+$ pub outdated --no-color --mode=null-safety --transitive
+Showing dependencies that are currently not opted in to null-safety.
+[✗] indicates versions without null safety support.
+[✓] indicates versions opting in to null safety.
+
+Package Name  Current  Upgradable  Resolvable           Latest  
+
+direct dependencies:
+bar           ✗1.0.0   ✗1.0.0      ✓2.0.0               ✓2.0.0  
+foo           ✗1.0.0   ✗1.0.0      ✓2.0.0-nullsafety.0  ✓2.0.0  
+
+2  dependencies are constrained to versions that are older than a resolvable version.
+To update these dependencies, edit pubspec.yaml, or run `dart pub upgrade --null-safety`.
+
+-------------------------------- END OF OUTPUT ---------------------------------
+
+## Section 9
+$ pub outdated --no-color --mode=null-safety --no-prereleases
+Showing dependencies that are currently not opted in to null-safety.
+[✗] indicates versions without null safety support.
+[✓] indicates versions opting in to null safety.
+
+Package Name  Current  Upgradable  Resolvable           Latest  
+
+direct dependencies:
+bar           ✗1.0.0   ✗1.0.0      ✓2.0.0               ✓2.0.0  
+foo           ✗1.0.0   ✗1.0.0      ✓2.0.0-nullsafety.0  ✓2.0.0  
+
+2  dependencies are constrained to versions that are older than a resolvable version.
+To update these dependencies, edit pubspec.yaml, or run `dart pub upgrade --null-safety`.
+
+-------------------------------- END OF OUTPUT ---------------------------------
+
+## Section 10
+$ pub outdated --json --mode=null-safety
+{
+  "packages": [
+    {
+      "package": "bar",
+      "current": {
+        "version": "1.0.0",
+        "nullSafety": false
+      },
+      "upgradable": {
+        "version": "1.0.0",
+        "nullSafety": false
+      },
+      "resolvable": {
+        "version": "2.0.0",
+        "nullSafety": true
+      },
+      "latest": {
+        "version": "2.0.0",
+        "nullSafety": true
+      }
+    },
+    {
+      "package": "foo",
+      "current": {
+        "version": "1.0.0",
+        "nullSafety": false
+      },
+      "upgradable": {
+        "version": "1.0.0",
+        "nullSafety": false
+      },
+      "resolvable": {
+        "version": "2.0.0-nullsafety.0",
+        "nullSafety": true
+      },
+      "latest": {
+        "version": "2.0.0",
+        "nullSafety": true
+      }
+    }
+  ]
+}
+
+-------------------------------- END OF OUTPUT ---------------------------------
+
+## Section 11
+$ pub outdated --json --no-dev-dependencies
+{
+  "packages": [
+    {
+      "package": "bar",
+      "current": {
+        "version": "1.0.0"
+      },
+      "upgradable": {
+        "version": "1.0.0"
+      },
+      "resolvable": {
+        "version": "2.0.0"
+      },
+      "latest": {
+        "version": "2.0.0"
+      }
+    },
+    {
+      "package": "fails_analysis",
+      "current": {
+        "version": "1.0.0"
+      },
+      "upgradable": {
+        "version": "1.0.0"
+      },
+      "resolvable": {
+        "version": "2.0.0"
+      },
+      "latest": {
+        "version": "2.0.0"
+      }
+    },
+    {
+      "package": "fails_analysis_in_dependency",
+      "current": {
+        "version": "1.0.0"
+      },
+      "upgradable": {
+        "version": "1.0.0"
+      },
+      "resolvable": {
+        "version": "2.0.0"
+      },
+      "latest": {
+        "version": "2.0.0"
+      }
+    },
+    {
+      "package": "file_in_dependency_opts_out",
+      "current": {
+        "version": "1.0.0"
+      },
+      "upgradable": {
+        "version": "1.0.0"
+      },
+      "resolvable": {
+        "version": "2.0.0"
+      },
+      "latest": {
+        "version": "2.0.0"
+      }
+    },
+    {
+      "package": "file_opts_out",
+      "current": {
+        "version": "1.0.0"
+      },
+      "upgradable": {
+        "version": "1.0.0"
+      },
+      "resolvable": {
+        "version": "2.0.0"
+      },
+      "latest": {
+        "version": "2.0.0"
+      }
+    },
+    {
+      "package": "foo",
+      "current": {
+        "version": "1.0.0"
+      },
+      "upgradable": {
+        "version": "1.0.0"
+      },
+      "resolvable": {
+        "version": "2.0.0-nullsafety.0"
+      },
+      "latest": {
+        "version": "2.0.0"
+      }
+    }
+  ]
+}
+
diff --git a/test/testdata/goldens/outdated/outdated_test/null-safety already migrated.txt b/test/testdata/goldens/outdated/outdated_test/null-safety already migrated.txt
new file mode 100644
index 0000000..3d227ec
--- /dev/null
+++ b/test/testdata/goldens/outdated/outdated_test/null-safety already migrated.txt
@@ -0,0 +1,157 @@
+# GENERATED BY: test/outdated/outdated_test.dart
+
+## Section 0
+$ pub outdated --json
+{
+  "packages": []
+}
+
+-------------------------------- END OF OUTPUT ---------------------------------
+
+## Section 1
+$ pub outdated --no-color
+Showing outdated packages.
+[*] indicates versions that are not the latest available.
+
+Found no outdated packages
+
+-------------------------------- END OF OUTPUT ---------------------------------
+
+## Section 2
+$ pub outdated --no-color --no-transitive
+Showing outdated packages.
+[*] indicates versions that are not the latest available.
+
+Found no outdated packages
+
+-------------------------------- END OF OUTPUT ---------------------------------
+
+## Section 3
+$ pub outdated --no-color --up-to-date
+Showing outdated packages.
+[*] indicates versions that are not the latest available.
+
+Package Name   Current  Upgradable  Resolvable  Latest  
+
+direct dependencies:
+foo            2.0.0    2.0.0       2.0.0       2.0.0   
+
+dev_dependencies:
+bar            2.0.0    2.0.0       2.0.0       2.0.0   
+
+transitive dev_dependencies:
+devTransitive  1.0.0    1.0.0       1.0.0       1.0.0   
+You are already using the newest resolvable versions listed in the 'Resolvable' column.
+Newer versions, listed in 'Latest', may not be mutually compatible.
+
+-------------------------------- END OF OUTPUT ---------------------------------
+
+## Section 4
+$ pub outdated --no-color --prereleases
+Showing outdated packages.
+[*] indicates versions that are not the latest available.
+
+Found no outdated packages
+
+-------------------------------- END OF OUTPUT ---------------------------------
+
+## Section 5
+$ pub outdated --no-color --no-dev-dependencies
+Showing outdated packages.
+[*] indicates versions that are not the latest available.
+
+Found no outdated packages
+
+-------------------------------- END OF OUTPUT ---------------------------------
+
+## Section 6
+$ pub outdated --no-color --no-dependency-overrides
+Showing outdated packages.
+[*] indicates versions that are not the latest available.
+
+Found no outdated packages
+
+-------------------------------- END OF OUTPUT ---------------------------------
+
+## Section 7
+$ pub outdated --no-color --mode=null-safety
+Showing dependencies that are currently not opted in to null-safety.
+[✗] indicates versions without null safety support.
+[✓] indicates versions opting in to null safety.
+
+Package Name  Current  Upgradable  Resolvable  Latest  
+
+direct dependencies: all support null safety.
+
+dev_dependencies: all support null safety.
+All dependencies opt in to null-safety.
+
+-------------------------------- END OF OUTPUT ---------------------------------
+
+## Section 8
+$ pub outdated --no-color --mode=null-safety --transitive
+Showing dependencies that are currently not opted in to null-safety.
+[✗] indicates versions without null safety support.
+[✓] indicates versions opting in to null safety.
+
+Package Name   Current  Upgradable  Resolvable  Latest  
+
+direct dependencies: all support null safety.
+
+dev_dependencies: all support null safety.
+
+transitive dev_dependencies:
+devTransitive  ✗1.0.0   ✗1.0.0      ✗1.0.0      ✗1.0.0  
+All dependencies opt in to null-safety.
+
+-------------------------------- END OF OUTPUT ---------------------------------
+
+## Section 9
+$ pub outdated --no-color --mode=null-safety --no-prereleases
+Showing dependencies that are currently not opted in to null-safety.
+[✗] indicates versions without null safety support.
+[✓] indicates versions opting in to null safety.
+
+Package Name  Current  Upgradable  Resolvable  Latest  
+
+direct dependencies: all support null safety.
+
+dev_dependencies: all support null safety.
+All dependencies opt in to null-safety.
+
+-------------------------------- END OF OUTPUT ---------------------------------
+
+## Section 10
+$ pub outdated --json --mode=null-safety
+{
+  "packages": [
+    {
+      "package": "devTransitive",
+      "current": {
+        "version": "1.0.0",
+        "nullSafety": false
+      },
+      "upgradable": {
+        "version": "1.0.0",
+        "nullSafety": false
+      },
+      "resolvable": {
+        "version": "1.0.0",
+        "nullSafety": false
+      },
+      "latest": {
+        "version": "1.0.0",
+        "nullSafety": false
+      }
+    }
+  ]
+}
+
+-------------------------------- END OF OUTPUT ---------------------------------
+
+## Section 11
+$ pub outdated --json --no-dev-dependencies
+{
+  "packages": []
+}
+
diff --git a/test/testdata/goldens/outdated/outdated_test/null-safety no resolution.txt b/test/testdata/goldens/outdated/outdated_test/null-safety no resolution.txt
new file mode 100644
index 0000000..1ab20ad
--- /dev/null
+++ b/test/testdata/goldens/outdated/outdated_test/null-safety no resolution.txt
@@ -0,0 +1,168 @@
+# GENERATED BY: test/outdated/outdated_test.dart
+
+## Section 0
+$ pub outdated --json
+{
+  "packages": []
+}
+
+-------------------------------- END OF OUTPUT ---------------------------------
+
+## Section 1
+$ pub outdated --no-color
+Showing outdated packages.
+[*] indicates versions that are not the latest available.
+
+Found no outdated packages
+
+-------------------------------- END OF OUTPUT ---------------------------------
+
+## Section 2
+$ pub outdated --no-color --no-transitive
+Showing outdated packages.
+[*] indicates versions that are not the latest available.
+
+Found no outdated packages
+
+-------------------------------- END OF OUTPUT ---------------------------------
+
+## Section 3
+$ pub outdated --no-color --up-to-date
+Showing outdated packages.
+[*] indicates versions that are not the latest available.
+
+Package Name  Current  Upgradable  Resolvable  Latest  
+
+direct dependencies:
+bar           1.0.0    1.0.0       1.0.0       1.0.0   
+foo           1.0.0    1.0.0       1.0.0       1.0.0   
+You are already using the newest resolvable versions listed in the 'Resolvable' column.
+Newer versions, listed in 'Latest', may not be mutually compatible.
+
+-------------------------------- END OF OUTPUT ---------------------------------
+
+## Section 4
+$ pub outdated --no-color --prereleases
+Showing outdated packages.
+[*] indicates versions that are not the latest available.
+
+Package Name  Current  Upgradable  Resolvable  Latest              
+
+direct dependencies:
+bar           *1.0.0   *1.0.0      *1.0.0      2.0.0-nullsafety.0  
+foo           *1.0.0   *1.0.0      *1.0.0      2.0.0-nullsafety.0  
+You are already using the newest resolvable versions listed in the 'Resolvable' column.
+Newer versions, listed in 'Latest', may not be mutually compatible.
+
+-------------------------------- END OF OUTPUT ---------------------------------
+
+## Section 5
+$ pub outdated --no-color --no-dev-dependencies
+Showing outdated packages.
+[*] indicates versions that are not the latest available.
+
+Found no outdated packages
+
+-------------------------------- END OF OUTPUT ---------------------------------
+
+## Section 6
+$ pub outdated --no-color --no-dependency-overrides
+Showing outdated packages.
+[*] indicates versions that are not the latest available.
+
+Found no outdated packages
+
+-------------------------------- END OF OUTPUT ---------------------------------
+
+## Section 7
+$ pub outdated --no-color --mode=null-safety
+Showing dependencies that are currently not opted in to null-safety.
+[✗] indicates versions without null safety support.
+[✓] indicates versions opting in to null safety.
+
+Package Name  Current  Upgradable  Resolvable  Latest               
+
+direct dependencies:
+bar           ✗1.0.0   ✗1.0.0      -           ✓2.0.0-nullsafety.0  
+foo           ✗1.0.0   ✗1.0.0      -           ✓2.0.0-nullsafety.0  
+No resolution was found. Try running `dart pub upgrade --null-safety --dry-run` to explore why.
+
+-------------------------------- END OF OUTPUT ---------------------------------
+
+## Section 8
+$ pub outdated --no-color --mode=null-safety --transitive
+Showing dependencies that are currently not opted in to null-safety.
+[✗] indicates versions without null safety support.
+[✓] indicates versions opting in to null safety.
+
+Package Name  Current  Upgradable  Resolvable  Latest               
+
+direct dependencies:
+bar           ✗1.0.0   ✗1.0.0      -           ✓2.0.0-nullsafety.0  
+foo           ✗1.0.0   ✗1.0.0      -           ✓2.0.0-nullsafety.0  
+No resolution was found. Try running `dart pub upgrade --null-safety --dry-run` to explore why.
+
+-------------------------------- END OF OUTPUT ---------------------------------
+
+## Section 9
+$ pub outdated --no-color --mode=null-safety --no-prereleases
+Showing dependencies that are currently not opted in to null-safety.
+[✗] indicates versions without null safety support.
+[✓] indicates versions opting in to null safety.
+
+Package Name  Current  Upgradable  Resolvable  Latest  
+
+direct dependencies:
+bar           ✗1.0.0   ✗1.0.0      -           ✗1.0.0  
+foo           ✗1.0.0   ✗1.0.0      -           ✗1.0.0  
+No resolution was found. Try running `dart pub upgrade --null-safety --dry-run` to explore why.
+
+-------------------------------- END OF OUTPUT ---------------------------------
+
+## Section 10
+$ pub outdated --json --mode=null-safety
+{
+  "packages": [
+    {
+      "package": "bar",
+      "current": {
+        "version": "1.0.0",
+        "nullSafety": false
+      },
+      "upgradable": {
+        "version": "1.0.0",
+        "nullSafety": false
+      },
+      "resolvable": null,
+      "latest": {
+        "version": "2.0.0-nullsafety.0",
+        "nullSafety": true
+      }
+    },
+    {
+      "package": "foo",
+      "current": {
+        "version": "1.0.0",
+        "nullSafety": false
+      },
+      "upgradable": {
+        "version": "1.0.0",
+        "nullSafety": false
+      },
+      "resolvable": null,
+      "latest": {
+        "version": "2.0.0-nullsafety.0",
+        "nullSafety": true
+      }
+    }
+  ]
+}
+
+-------------------------------- END OF OUTPUT ---------------------------------
+
+## Section 11
+$ pub outdated --json --no-dev-dependencies
+{
+  "packages": []
+}
+
diff --git a/test/testdata/goldens/outdated/outdated_test/overridden dependencies - no resolution.txt b/test/testdata/goldens/outdated/outdated_test/overridden dependencies - no resolution.txt
new file mode 100644
index 0000000..909ee0a
--- /dev/null
+++ b/test/testdata/goldens/outdated/outdated_test/overridden dependencies - no resolution.txt
@@ -0,0 +1,280 @@
+# GENERATED BY: test/outdated/outdated_test.dart
+
+## Section 0
+$ pub outdated --json
+{
+  "packages": [
+    {
+      "package": "bar",
+      "current": {
+        "version": "1.0.0",
+        "overridden": true
+      },
+      "upgradable": {
+        "version": "1.0.0",
+        "overridden": true
+      },
+      "resolvable": {
+        "version": "1.0.0",
+        "overridden": true
+      },
+      "latest": {
+        "version": "2.0.0"
+      }
+    },
+    {
+      "package": "foo",
+      "current": {
+        "version": "1.0.0",
+        "overridden": true
+      },
+      "upgradable": {
+        "version": "1.0.0",
+        "overridden": true
+      },
+      "resolvable": {
+        "version": "1.0.0",
+        "overridden": true
+      },
+      "latest": {
+        "version": "2.0.0"
+      }
+    }
+  ]
+}
+
+-------------------------------- END OF OUTPUT ---------------------------------
+
+## Section 1
+$ pub outdated --no-color
+Showing outdated packages.
+[*] indicates versions that are not the latest available.
+
+Package Name  Current              Upgradable           Resolvable           Latest  
+
+direct dependencies:
+bar           *1.0.0 (overridden)  *1.0.0 (overridden)  *1.0.0 (overridden)  2.0.0   
+foo           *1.0.0 (overridden)  *1.0.0 (overridden)  *1.0.0 (overridden)  2.0.0   
+You are already using the newest resolvable versions listed in the 'Resolvable' column.
+Newer versions, listed in 'Latest', may not be mutually compatible.
+
+-------------------------------- END OF OUTPUT ---------------------------------
+
+## Section 2
+$ pub outdated --no-color --no-transitive
+Showing outdated packages.
+[*] indicates versions that are not the latest available.
+
+Package Name  Current              Upgradable           Resolvable           Latest  
+
+direct dependencies:
+bar           *1.0.0 (overridden)  *1.0.0 (overridden)  *1.0.0 (overridden)  2.0.0   
+foo           *1.0.0 (overridden)  *1.0.0 (overridden)  *1.0.0 (overridden)  2.0.0   
+You are already using the newest resolvable versions listed in the 'Resolvable' column.
+Newer versions, listed in 'Latest', may not be mutually compatible.
+
+-------------------------------- END OF OUTPUT ---------------------------------
+
+## Section 3
+$ pub outdated --no-color --up-to-date
+Showing outdated packages.
+[*] indicates versions that are not the latest available.
+
+Package Name  Current              Upgradable           Resolvable           Latest  
+
+direct dependencies:
+bar           *1.0.0 (overridden)  *1.0.0 (overridden)  *1.0.0 (overridden)  2.0.0   
+foo           *1.0.0 (overridden)  *1.0.0 (overridden)  *1.0.0 (overridden)  2.0.0   
+You are already using the newest resolvable versions listed in the 'Resolvable' column.
+Newer versions, listed in 'Latest', may not be mutually compatible.
+
+-------------------------------- END OF OUTPUT ---------------------------------
+
+## Section 4
+$ pub outdated --no-color --prereleases
+Showing outdated packages.
+[*] indicates versions that are not the latest available.
+
+Package Name  Current              Upgradable           Resolvable           Latest  
+
+direct dependencies:
+bar           *1.0.0 (overridden)  *1.0.0 (overridden)  *1.0.0 (overridden)  2.0.0   
+foo           *1.0.0 (overridden)  *1.0.0 (overridden)  *1.0.0 (overridden)  2.0.0   
+You are already using the newest resolvable versions listed in the 'Resolvable' column.
+Newer versions, listed in 'Latest', may not be mutually compatible.
+
+-------------------------------- END OF OUTPUT ---------------------------------
+
+## Section 5
+$ pub outdated --no-color --no-dev-dependencies
+Showing outdated packages.
+[*] indicates versions that are not the latest available.
+
+Package Name  Current              Upgradable           Resolvable           Latest  
+
+direct dependencies:
+bar           *1.0.0 (overridden)  *1.0.0 (overridden)  *1.0.0 (overridden)  2.0.0   
+foo           *1.0.0 (overridden)  *1.0.0 (overridden)  *1.0.0 (overridden)  2.0.0   
+You are already using the newest resolvable versions listed in the 'Resolvable' column.
+Newer versions, listed in 'Latest', may not be mutually compatible.
+
+-------------------------------- END OF OUTPUT ---------------------------------
+
+## Section 6
+$ pub outdated --no-color --no-dependency-overrides
+Showing outdated packages.
+[*] indicates versions that are not the latest available.
+
+Package Name  Current              Upgradable  Resolvable  Latest  
+
+direct dependencies:
+bar           *1.0.0 (overridden)  -           -           2.0.0   
+foo           *1.0.0 (overridden)  -           -           2.0.0   
+No resolution was found. Try running `dart pub upgrade --dry-run` to explore why.
+
+-------------------------------- END OF OUTPUT ---------------------------------
+
+## Section 7
+$ pub outdated --no-color --mode=null-safety
+Showing dependencies that are currently not opted in to null-safety.
+[✗] indicates versions without null safety support.
+[✓] indicates versions opting in to null safety.
+
+Package Name  Current              Upgradable           Resolvable           Latest  
+
+direct dependencies:
+bar           ✗1.0.0 (overridden)  ✗1.0.0 (overridden)  ✗1.0.0 (overridden)  ✗2.0.0  
+foo           ✗1.0.0 (overridden)  ✗1.0.0 (overridden)  ✗1.0.0 (overridden)  ✗2.0.0  
+You are already using the newest resolvable versions listed in the 'Resolvable' column.
+Newer versions, listed in 'Latest', may not be mutually compatible.
+
+-------------------------------- END OF OUTPUT ---------------------------------
+
+## Section 8
+$ pub outdated --no-color --mode=null-safety --transitive
+Showing dependencies that are currently not opted in to null-safety.
+[✗] indicates versions without null safety support.
+[✓] indicates versions opting in to null safety.
+
+Package Name  Current              Upgradable           Resolvable           Latest  
+
+direct dependencies:
+bar           ✗1.0.0 (overridden)  ✗1.0.0 (overridden)  ✗1.0.0 (overridden)  ✗2.0.0  
+foo           ✗1.0.0 (overridden)  ✗1.0.0 (overridden)  ✗1.0.0 (overridden)  ✗2.0.0  
+You are already using the newest resolvable versions listed in the 'Resolvable' column.
+Newer versions, listed in 'Latest', may not be mutually compatible.
+
+-------------------------------- END OF OUTPUT ---------------------------------
+
+## Section 9
+$ pub outdated --no-color --mode=null-safety --no-prereleases
+Showing dependencies that are currently not opted in to null-safety.
+[✗] indicates versions without null safety support.
+[✓] indicates versions opting in to null safety.
+
+Package Name  Current              Upgradable           Resolvable           Latest  
+
+direct dependencies:
+bar           ✗1.0.0 (overridden)  ✗1.0.0 (overridden)  ✗1.0.0 (overridden)  ✗2.0.0  
+foo           ✗1.0.0 (overridden)  ✗1.0.0 (overridden)  ✗1.0.0 (overridden)  ✗2.0.0  
+You are already using the newest resolvable versions listed in the 'Resolvable' column.
+Newer versions, listed in 'Latest', may not be mutually compatible.
+
+-------------------------------- END OF OUTPUT ---------------------------------
+
+## Section 10
+$ pub outdated --json --mode=null-safety
+{
+  "packages": [
+    {
+      "package": "bar",
+      "current": {
+        "version": "1.0.0",
+        "overridden": true,
+        "nullSafety": false
+      },
+      "upgradable": {
+        "version": "1.0.0",
+        "overridden": true,
+        "nullSafety": false
+      },
+      "resolvable": {
+        "version": "1.0.0",
+        "overridden": true,
+        "nullSafety": false
+      },
+      "latest": {
+        "version": "2.0.0",
+        "nullSafety": false
+      }
+    },
+    {
+      "package": "foo",
+      "current": {
+        "version": "1.0.0",
+        "overridden": true,
+        "nullSafety": false
+      },
+      "upgradable": {
+        "version": "1.0.0",
+        "overridden": true,
+        "nullSafety": false
+      },
+      "resolvable": {
+        "version": "1.0.0",
+        "overridden": true,
+        "nullSafety": false
+      },
+      "latest": {
+        "version": "2.0.0",
+        "nullSafety": false
+      }
+    }
+  ]
+}
+
+-------------------------------- END OF OUTPUT ---------------------------------
+
+## Section 11
+$ pub outdated --json --no-dev-dependencies
+{
+  "packages": [
+    {
+      "package": "bar",
+      "current": {
+        "version": "1.0.0",
+        "overridden": true
+      },
+      "upgradable": {
+        "version": "1.0.0",
+        "overridden": true
+      },
+      "resolvable": {
+        "version": "1.0.0",
+        "overridden": true
+      },
+      "latest": {
+        "version": "2.0.0"
+      }
+    },
+    {
+      "package": "foo",
+      "current": {
+        "version": "1.0.0",
+        "overridden": true
+      },
+      "upgradable": {
+        "version": "1.0.0",
+        "overridden": true
+      },
+      "resolvable": {
+        "version": "1.0.0",
+        "overridden": true
+      },
+      "latest": {
+        "version": "2.0.0"
+      }
+    }
+  ]
+}
+
diff --git a/test/testdata/goldens/outdated/outdated_test/overridden dependencies.txt b/test/testdata/goldens/outdated/outdated_test/overridden dependencies.txt
new file mode 100644
index 0000000..49abe1b
--- /dev/null
+++ b/test/testdata/goldens/outdated/outdated_test/overridden dependencies.txt
@@ -0,0 +1,352 @@
+# GENERATED BY: test/outdated/outdated_test.dart
+
+## Section 0
+$ pub outdated --json
+{
+  "packages": [
+    {
+      "package": "bar",
+      "current": {
+        "version": "1.0.1",
+        "overridden": true
+      },
+      "upgradable": {
+        "version": "1.0.1",
+        "overridden": true
+      },
+      "resolvable": {
+        "version": "1.0.1",
+        "overridden": true
+      },
+      "latest": {
+        "version": "2.0.0"
+      }
+    },
+    {
+      "package": "baz",
+      "current": {
+        "version": "2.0.0",
+        "overridden": true
+      },
+      "upgradable": {
+        "version": "2.0.0",
+        "overridden": true
+      },
+      "resolvable": {
+        "version": "2.0.0",
+        "overridden": true
+      },
+      "latest": {
+        "version": "2.0.0"
+      }
+    },
+    {
+      "package": "foo",
+      "current": {
+        "version": "1.0.1",
+        "overridden": true
+      },
+      "upgradable": {
+        "version": "1.0.1",
+        "overridden": true
+      },
+      "resolvable": {
+        "version": "1.0.1",
+        "overridden": true
+      },
+      "latest": {
+        "version": "2.0.0"
+      }
+    }
+  ]
+}
+
+-------------------------------- END OF OUTPUT ---------------------------------
+
+## Section 1
+$ pub outdated --no-color
+Showing outdated packages.
+[*] indicates versions that are not the latest available.
+
+Package Name  Current              Upgradable           Resolvable           Latest  
+
+direct dependencies:
+bar           *1.0.1 (overridden)  *1.0.1 (overridden)  *1.0.1 (overridden)  2.0.0   
+baz           *2.0.0 (overridden)  *2.0.0 (overridden)  *2.0.0 (overridden)  2.0.0   
+foo           *1.0.1 (overridden)  *1.0.1 (overridden)  *1.0.1 (overridden)  2.0.0   
+You are already using the newest resolvable versions listed in the 'Resolvable' column.
+Newer versions, listed in 'Latest', may not be mutually compatible.
+
+-------------------------------- END OF OUTPUT ---------------------------------
+
+## Section 2
+$ pub outdated --no-color --no-transitive
+Showing outdated packages.
+[*] indicates versions that are not the latest available.
+
+Package Name  Current              Upgradable           Resolvable           Latest  
+
+direct dependencies:
+bar           *1.0.1 (overridden)  *1.0.1 (overridden)  *1.0.1 (overridden)  2.0.0   
+baz           *2.0.0 (overridden)  *2.0.0 (overridden)  *2.0.0 (overridden)  2.0.0   
+foo           *1.0.1 (overridden)  *1.0.1 (overridden)  *1.0.1 (overridden)  2.0.0   
+You are already using the newest resolvable versions listed in the 'Resolvable' column.
+Newer versions, listed in 'Latest', may not be mutually compatible.
+
+-------------------------------- END OF OUTPUT ---------------------------------
+
+## Section 3
+$ pub outdated --no-color --up-to-date
+Showing outdated packages.
+[*] indicates versions that are not the latest available.
+
+Package Name  Current              Upgradable           Resolvable           Latest  
+
+direct dependencies:
+bar           *1.0.1 (overridden)  *1.0.1 (overridden)  *1.0.1 (overridden)  2.0.0   
+baz           *2.0.0 (overridden)  *2.0.0 (overridden)  *2.0.0 (overridden)  2.0.0   
+foo           *1.0.1 (overridden)  *1.0.1 (overridden)  *1.0.1 (overridden)  2.0.0   
+You are already using the newest resolvable versions listed in the 'Resolvable' column.
+Newer versions, listed in 'Latest', may not be mutually compatible.
+
+-------------------------------- END OF OUTPUT ---------------------------------
+
+## Section 4
+$ pub outdated --no-color --prereleases
+Showing outdated packages.
+[*] indicates versions that are not the latest available.
+
+Package Name  Current              Upgradable           Resolvable           Latest  
+
+direct dependencies:
+bar           *1.0.1 (overridden)  *1.0.1 (overridden)  *1.0.1 (overridden)  2.0.0   
+baz           *2.0.0 (overridden)  *2.0.0 (overridden)  *2.0.0 (overridden)  2.0.0   
+foo           *1.0.1 (overridden)  *1.0.1 (overridden)  *1.0.1 (overridden)  2.0.0   
+You are already using the newest resolvable versions listed in the 'Resolvable' column.
+Newer versions, listed in 'Latest', may not be mutually compatible.
+
+-------------------------------- END OF OUTPUT ---------------------------------
+
+## Section 5
+$ pub outdated --no-color --no-dev-dependencies
+Showing outdated packages.
+[*] indicates versions that are not the latest available.
+
+Package Name  Current              Upgradable           Resolvable           Latest  
+
+direct dependencies:
+bar           *1.0.1 (overridden)  *1.0.1 (overridden)  *1.0.1 (overridden)  2.0.0   
+baz           *2.0.0 (overridden)  *2.0.0 (overridden)  *2.0.0 (overridden)  2.0.0   
+foo           *1.0.1 (overridden)  *1.0.1 (overridden)  *1.0.1 (overridden)  2.0.0   
+You are already using the newest resolvable versions listed in the 'Resolvable' column.
+Newer versions, listed in 'Latest', may not be mutually compatible.
+
+-------------------------------- END OF OUTPUT ---------------------------------
+
+## Section 6
+$ pub outdated --no-color --no-dependency-overrides
+Showing outdated packages.
+[*] indicates versions that are not the latest available.
+
+Package Name  Current              Upgradable  Resolvable  Latest  
+
+direct dependencies:
+bar           *1.0.1 (overridden)  2.0.0       2.0.0       2.0.0   
+baz           *2.0.0 (overridden)  *1.0.0      2.0.0       2.0.0   
+foo           *1.0.1 (overridden)  *1.0.0      *1.0.0      2.0.0   
+
+3 upgradable dependencies are locked (in pubspec.lock) to older versions.
+To update these dependencies, use `dart pub upgrade`.
+
+1 dependency is constrained to a version that is older than a resolvable version.
+To update it, edit pubspec.yaml, or run `dart pub upgrade --major-versions`.
+
+-------------------------------- END OF OUTPUT ---------------------------------
+
+## Section 7
+$ pub outdated --no-color --mode=null-safety
+Showing dependencies that are currently not opted in to null-safety.
+[✗] indicates versions without null safety support.
+[✓] indicates versions opting in to null safety.
+
+Package Name  Current              Upgradable           Resolvable           Latest  
+
+direct dependencies:
+bar           ✗1.0.1 (overridden)  ✗1.0.1 (overridden)  ✗1.0.1 (overridden)  ✗2.0.0  
+baz           ✗2.0.0 (overridden)  ✗2.0.0 (overridden)  ✗2.0.0 (overridden)  ✗2.0.0  
+foo           ✗1.0.1 (overridden)  ✗1.0.1 (overridden)  ✗1.0.1 (overridden)  ✗2.0.0  
+You are already using the newest resolvable versions listed in the 'Resolvable' column.
+Newer versions, listed in 'Latest', may not be mutually compatible.
+
+-------------------------------- END OF OUTPUT ---------------------------------
+
+## Section 8
+$ pub outdated --no-color --mode=null-safety --transitive
+Showing dependencies that are currently not opted in to null-safety.
+[✗] indicates versions without null safety support.
+[✓] indicates versions opting in to null safety.
+
+Package Name  Current              Upgradable           Resolvable           Latest  
+
+direct dependencies:
+bar           ✗1.0.1 (overridden)  ✗1.0.1 (overridden)  ✗1.0.1 (overridden)  ✗2.0.0  
+baz           ✗2.0.0 (overridden)  ✗2.0.0 (overridden)  ✗2.0.0 (overridden)  ✗2.0.0  
+foo           ✗1.0.1 (overridden)  ✗1.0.1 (overridden)  ✗1.0.1 (overridden)  ✗2.0.0  
+You are already using the newest resolvable versions listed in the 'Resolvable' column.
+Newer versions, listed in 'Latest', may not be mutually compatible.
+
+-------------------------------- END OF OUTPUT ---------------------------------
+
+## Section 9
+$ pub outdated --no-color --mode=null-safety --no-prereleases
+Showing dependencies that are currently not opted in to null-safety.
+[✗] indicates versions without null safety support.
+[✓] indicates versions opting in to null safety.
+
+Package Name  Current              Upgradable           Resolvable           Latest  
+
+direct dependencies:
+bar           ✗1.0.1 (overridden)  ✗1.0.1 (overridden)  ✗1.0.1 (overridden)  ✗2.0.0  
+baz           ✗2.0.0 (overridden)  ✗2.0.0 (overridden)  ✗2.0.0 (overridden)  ✗2.0.0  
+foo           ✗1.0.1 (overridden)  ✗1.0.1 (overridden)  ✗1.0.1 (overridden)  ✗2.0.0  
+You are already using the newest resolvable versions listed in the 'Resolvable' column.
+Newer versions, listed in 'Latest', may not be mutually compatible.
+
+-------------------------------- END OF OUTPUT ---------------------------------
+
+## Section 10
+$ pub outdated --json --mode=null-safety
+{
+  "packages": [
+    {
+      "package": "bar",
+      "current": {
+        "version": "1.0.1",
+        "overridden": true,
+        "nullSafety": false
+      },
+      "upgradable": {
+        "version": "1.0.1",
+        "overridden": true,
+        "nullSafety": false
+      },
+      "resolvable": {
+        "version": "1.0.1",
+        "overridden": true,
+        "nullSafety": false
+      },
+      "latest": {
+        "version": "2.0.0",
+        "nullSafety": false
+      }
+    },
+    {
+      "package": "baz",
+      "current": {
+        "version": "2.0.0",
+        "overridden": true,
+        "nullSafety": false
+      },
+      "upgradable": {
+        "version": "2.0.0",
+        "overridden": true,
+        "nullSafety": false
+      },
+      "resolvable": {
+        "version": "2.0.0",
+        "overridden": true,
+        "nullSafety": false
+      },
+      "latest": {
+        "version": "2.0.0",
+        "nullSafety": false
+      }
+    },
+    {
+      "package": "foo",
+      "current": {
+        "version": "1.0.1",
+        "overridden": true,
+        "nullSafety": false
+      },
+      "upgradable": {
+        "version": "1.0.1",
+        "overridden": true,
+        "nullSafety": false
+      },
+      "resolvable": {
+        "version": "1.0.1",
+        "overridden": true,
+        "nullSafety": false
+      },
+      "latest": {
+        "version": "2.0.0",
+        "nullSafety": false
+      }
+    }
+  ]
+}
+
+-------------------------------- END OF OUTPUT ---------------------------------
+
+## Section 11
+$ pub outdated --json --no-dev-dependencies
+{
+  "packages": [
+    {
+      "package": "bar",
+      "current": {
+        "version": "1.0.1",
+        "overridden": true
+      },
+      "upgradable": {
+        "version": "1.0.1",
+        "overridden": true
+      },
+      "resolvable": {
+        "version": "1.0.1",
+        "overridden": true
+      },
+      "latest": {
+        "version": "2.0.0"
+      }
+    },
+    {
+      "package": "baz",
+      "current": {
+        "version": "2.0.0",
+        "overridden": true
+      },
+      "upgradable": {
+        "version": "2.0.0",
+        "overridden": true
+      },
+      "resolvable": {
+        "version": "2.0.0",
+        "overridden": true
+      },
+      "latest": {
+        "version": "2.0.0"
+      }
+    },
+    {
+      "package": "foo",
+      "current": {
+        "version": "1.0.1",
+        "overridden": true
+      },
+      "upgradable": {
+        "version": "1.0.1",
+        "overridden": true
+      },
+      "resolvable": {
+        "version": "1.0.1",
+        "overridden": true
+      },
+      "latest": {
+        "version": "2.0.0"
+      }
+    }
+  ]
+}
+
diff --git a/test/goldens/upgrade_major_versions_example.txt b/test/testdata/goldens/upgrade/example_warns_about_major_versions_test/pub upgrade --major-versions does not update major versions in example~.txt
similarity index 60%
rename from test/goldens/upgrade_major_versions_example.txt
rename to test/testdata/goldens/upgrade/example_warns_about_major_versions_test/pub upgrade --major-versions does not update major versions in example~.txt
index 448a874..2cc96c0 100644
--- a/test/goldens/upgrade_major_versions_example.txt
+++ b/test/testdata/goldens/upgrade/example_warns_about_major_versions_test/pub upgrade --major-versions does not update major versions in example~.txt
@@ -1,3 +1,6 @@
+# GENERATED BY: test/upgrade/example_warns_about_major_versions_test.dart
+
+## Section 0
 $ pub upgrade --major-versions --example
 Resolving dependencies...
 + bar 2.0.0
@@ -7,8 +10,11 @@
   bar: ^1.0.0 -> ^2.0.0
 Resolving dependencies in ./example...
 Got dependencies in ./example.
-[ERR] Running `upgrade --major-versions` only in `.`. Run `dart pub upgrade --major-versions --directory example/` separately.
+[STDERR] Running `upgrade --major-versions` only in `.`. Run `dart pub upgrade --major-versions --directory example/` separately.
 
+-------------------------------- END OF OUTPUT ---------------------------------
+
+## Section 1
 $ pub upgrade --major-versions --directory example
 Resolving dependencies in example...
   bar 2.0.0
diff --git a/test/goldens/upgrade_null_safety_example.txt b/test/testdata/goldens/upgrade/example_warns_about_major_versions_test/pub upgrade --null-safety does not update null-safety of dependencies in example~.txt
similarity index 62%
rename from test/goldens/upgrade_null_safety_example.txt
rename to test/testdata/goldens/upgrade/example_warns_about_major_versions_test/pub upgrade --null-safety does not update null-safety of dependencies in example~.txt
index 5c5b31c..cabc0be 100644
--- a/test/goldens/upgrade_null_safety_example.txt
+++ b/test/testdata/goldens/upgrade/example_warns_about_major_versions_test/pub upgrade --null-safety does not update null-safety of dependencies in example~.txt
@@ -1,3 +1,6 @@
+# GENERATED BY: test/upgrade/example_warns_about_major_versions_test.dart
+
+## Section 0
 $ pub upgrade --null-safety --example
 Resolving dependencies...
 + bar 2.0.0
@@ -7,8 +10,11 @@
   bar: ^1.0.0 -> ^2.0.0
 Resolving dependencies in ./example...
 Got dependencies in ./example.
-[ERR] Running `upgrade --null-safety` only in `.`. Run `dart pub upgrade --null-safety --directory example/` separately.
+[STDERR] Running `upgrade --null-safety` only in `.`. Run `dart pub upgrade --null-safety --directory example/` separately.
 
+-------------------------------- END OF OUTPUT ---------------------------------
+
+## Section 1
 $ pub upgrade --null-safety --directory example
 Resolving dependencies in example...
 > bar 2.0.0 (was 1.0.0)
diff --git a/test/upgrade/example_warns_about_major_versions_test.dart b/test/upgrade/example_warns_about_major_versions_test.dart
index 0813ed2..259e787 100644
--- a/test/upgrade/example_warns_about_major_versions_test.dart
+++ b/test/upgrade/example_warns_about_major_versions_test.dart
@@ -4,16 +4,14 @@
 
 // @dart = 2.11
 
-import 'package:test/test.dart';
-
 import '../descriptor.dart' as d;
 import '../golden_file.dart';
 import '../test_pub.dart';
 
 void main() {
-  test(
+  testWithGolden(
       'pub upgrade --major-versions does not update major versions in example/',
-      () async {
+      (ctx) async {
     await servePackages((b) => b
       ..serve('foo', '1.0.0')
       ..serve('foo', '2.0.0')
@@ -36,23 +34,13 @@
       ])
     ]).create();
 
-    final buffer = StringBuffer();
-    await runPubIntoBuffer(
-      ['upgrade', '--major-versions', '--example'],
-      buffer,
-    );
-    await runPubIntoBuffer(
-      ['upgrade', '--major-versions', '--directory', 'example'],
-      buffer,
-    );
-
-    expectMatchesGoldenFile(
-        buffer.toString(), 'test/goldens/upgrade_major_versions_example.txt');
+    await ctx.run(['upgrade', '--major-versions', '--example']);
+    await ctx.run(['upgrade', '--major-versions', '--directory', 'example']);
   });
 
-  test(
+  testWithGolden(
       'pub upgrade --null-safety does not update null-safety of dependencies in example/',
-      () async {
+      (ctx) async {
     await servePackages((b) => b
       ..serve('foo', '1.0.0', pubspec: {
         'environment': {'sdk': '>=2.7.0 <3.0.0'},
@@ -86,20 +74,14 @@
       ])
     ]).create();
 
-    final buffer = StringBuffer();
-    await runPubIntoBuffer(
+    await ctx.run(
       ['upgrade', '--null-safety', '--example'],
-      buffer,
       environment: {'_PUB_TEST_SDK_VERSION': '2.13.0'},
     );
 
-    await runPubIntoBuffer(
+    await ctx.run(
       ['upgrade', '--null-safety', '--directory', 'example'],
-      buffer,
       environment: {'_PUB_TEST_SDK_VERSION': '2.13.0'},
     );
-
-    expectMatchesGoldenFile(
-        buffer.toString(), 'test/goldens/upgrade_null_safety_example.txt');
   });
 }