Shard dartdoc_test and remove parallelization constraint on Travis (#1910)

* basic non-documenting mode works

* Basically works now, needs tests

* Add a test

* dartfmt

* Cleanup

* Add test for doc generation presence/absence with --quiet

* Fix packages output parsing problem

* Fix up some test tech-debt

* De-nest groups in integration test

* fine tune timeouts for increased paralellization on travis

* Fix lib name and copyright date
diff --git a/test/dartdoc_integration_test.dart b/test/dartdoc_integration_test.dart
new file mode 100644
index 0000000..e34ba1e
--- /dev/null
+++ b/test/dartdoc_integration_test.dart
@@ -0,0 +1,235 @@
+// Copyright (c) 2019, 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.
+
+library dartdoc.dartdoc_integration_test;
+
+import 'dart:async';
+import 'dart:io';
+import 'dart:mirrors';
+
+import 'package:dartdoc/dartdoc.dart';
+import 'package:path/path.dart' as pathLib;
+import 'package:test/test.dart';
+
+import 'src/utils.dart';
+
+Uri get _currentFileUri =>
+    (reflect(main) as ClosureMirror).function.location.sourceUri;
+String get _testPackagePath =>
+    pathLib.fromUri(_currentFileUri.resolve('../testing/test_package'));
+String get _testPackageFlutterPluginPath => pathLib
+    .fromUri(_currentFileUri.resolve('../testing/test_package_flutter_plugin'));
+
+void main() {
+  group('Invoking command-line dartdoc', () {
+    String dartdocPath =
+        pathLib.canonicalize(pathLib.join('bin', 'dartdoc.dart'));
+    CoverageSubprocessLauncher subprocessLauncher;
+    Directory tempDir;
+
+    setUpAll(() async {
+      tempDir =
+          Directory.systemTemp.createTempSync('dartdoc_integration_test.');
+      subprocessLauncher = new CoverageSubprocessLauncher(
+          'dartdoc_integration_test-subprocesses');
+    });
+
+    tearDown(() async {
+      tempDir.listSync().forEach((FileSystemEntity f) {
+        f.deleteSync(recursive: true);
+      });
+    });
+
+    tearDownAll(() async {
+      await Future.wait(CoverageSubprocessLauncher.coverageResults);
+    });
+
+    test('running --no-generate-docs is quiet and does not generate docs',
+        () async {
+      Directory outputDir =
+          await Directory.systemTemp.createTemp('dartdoc.testEmpty.');
+      List<String> outputLines = [];
+      await subprocessLauncher.runStreamed(Platform.resolvedExecutable,
+          [dartdocPath, '--output', outputDir.path, '--no-generate-docs'],
+          perLine: outputLines.add, workingDirectory: _testPackagePath);
+      expect(outputLines, isNot(contains(matches('^parsing'))));
+      expect(outputLines, contains(matches('^  warning:')));
+      expect(outputLines.last, matches(r'^found \d+ warnings and \d+ errors'));
+      expect(outputDir.listSync(), isEmpty);
+    });
+
+    test('running --quiet is quiet and does generate docs', () async {
+      Directory outputDir =
+          await Directory.systemTemp.createTemp('dartdoc.testEmpty.');
+      List<String> outputLines = [];
+      await subprocessLauncher.runStreamed(Platform.resolvedExecutable,
+          [dartdocPath, '--output', outputDir.path, '--quiet'],
+          perLine: outputLines.add, workingDirectory: _testPackagePath);
+      expect(outputLines, isNot(contains(matches('^parsing'))));
+      expect(outputLines, contains(matches('^  warning:')));
+      expect(outputLines.last, matches(r'^found \d+ warnings and \d+ errors'));
+      expect(outputDir.listSync(), isNotEmpty);
+    });
+
+    test('invalid parameters return non-zero and print a fatal-error',
+        () async {
+      List outputLines = [];
+      await expectLater(
+          () => subprocessLauncher.runStreamed(
+              Platform.resolvedExecutable,
+              [
+                dartdocPath,
+                '--nonexisting',
+              ],
+              perLine: outputLines.add),
+          throwsA(const TypeMatcher<ProcessException>()));
+      expect(
+          outputLines.firstWhere((l) => l.startsWith(' fatal')),
+          equals(
+              ' fatal error: Could not find an option named "nonexisting".'));
+    });
+
+    test('missing a required file path prints a fatal-error', () async {
+      List outputLines = [];
+      String impossiblePath = pathLib.join(dartdocPath, 'impossible');
+      await expectLater(
+          () => subprocessLauncher.runStreamed(
+              Platform.resolvedExecutable,
+              [
+                dartdocPath,
+                '--input',
+                impossiblePath,
+              ],
+              perLine: outputLines.add),
+          throwsA(const TypeMatcher<ProcessException>()));
+      expect(
+          outputLines.firstWhere((l) => l.startsWith(' fatal')),
+          startsWith(
+              ' fatal error: Argument --input, set to ${impossiblePath}, resolves to missing path: '));
+    });
+
+    test('errors cause non-zero exit when warnings are off', () async {
+      expect(
+          () => subprocessLauncher.runStreamed(Platform.resolvedExecutable, [
+                dartdocPath,
+                '--input=${testPackageToolError.path}',
+                '--output=${pathLib.join(tempDir.absolute.path, 'test_package_tool_error')}'
+              ]),
+          throwsA(const TypeMatcher<ProcessException>()));
+    });
+
+    test('help prints command line args', () async {
+      List<String> outputLines = [];
+      await subprocessLauncher.runStreamed(
+          Platform.resolvedExecutable, [dartdocPath, '--help'],
+          perLine: outputLines.add);
+      expect(outputLines,
+          contains('Generate HTML documentation for Dart libraries.'));
+      expect(
+          outputLines.join('\n'),
+          contains(new RegExp('^-h, --help[ ]+Show command help.',
+              multiLine: true)));
+    });
+
+    test('Validate missing FLUTTER_ROOT exception is clean', () async {
+      StringBuffer output = new StringBuffer();
+      var args = <String>[dartdocPath];
+      Future run = subprocessLauncher.runStreamed(
+          Platform.resolvedExecutable, args,
+          environment: new Map.from(Platform.environment)
+            ..remove('FLUTTER_ROOT'),
+          includeParentEnvironment: false,
+          workingDirectory: _testPackageFlutterPluginPath, perLine: (s) {
+        output.writeln(s);
+      });
+      // Asynchronous exception, but we still need the output, too.
+      expect(run, throwsA(new TypeMatcher<ProcessException>()));
+      try {
+        await run;
+      } on ProcessException catch (_) {}
+
+      expect(
+          output.toString(),
+          contains(new RegExp(
+              'Top level package requires Flutter but FLUTTER_ROOT environment variable not set|test_package_flutter_plugin requires the Flutter SDK, version solving failed')));
+      expect(output.toString(), isNot(contains('asynchronous gap')));
+    });
+
+    test("Validate --version works", () async {
+      StringBuffer output = new StringBuffer();
+      var args = <String>[dartdocPath, '--version'];
+      await subprocessLauncher.runStreamed(Platform.resolvedExecutable, args,
+          workingDirectory: _testPackagePath,
+          perLine: (s) => output.writeln(s));
+      PackageMeta dartdocMeta = new PackageMeta.fromFilename(dartdocPath);
+      expect(output.toString(),
+          endsWith('dartdoc version: ${dartdocMeta.version}\n'));
+    });
+
+    test('Check for sample code in examples', () async {
+      StringBuffer output = new StringBuffer();
+      var args = <String>[
+        dartdocPath,
+        '--include',
+        'ex',
+        '--no-include-source',
+        '--output',
+        tempDir.path
+      ];
+
+      await subprocessLauncher.runStreamed(Platform.resolvedExecutable, args,
+          workingDirectory: _testPackagePath,
+          perLine: (s) => output.writeln(s));
+
+      // Examples are reported as unfound because we (purposefully)
+      // did not use --example-path-prefix above.
+      final sep = '.'; // We don't care what the path separator character is
+      final firstUnfoundExample = new RegExp('warning: lib${sep}example.dart: '
+          '@example file not found.*test_package${sep}dog${sep}food.md');
+      if (!output.toString().contains(firstUnfoundExample)) {
+        fail('Should warn about unfound @example files');
+      }
+    });
+
+    test('Validate JSON output', () async {
+      var args = <String>[
+        dartdocPath,
+        '--include',
+        'ex',
+        '--no-include-source',
+        '--output',
+        tempDir.path,
+        '--json'
+      ];
+
+      Iterable<Map> jsonValues = await subprocessLauncher.runStreamed(
+          Platform.resolvedExecutable, args,
+          workingDirectory: _testPackagePath);
+
+      expect(jsonValues, isNotEmpty,
+          reason: 'All STDOUT lines should be JSON-encoded maps.');
+    }, timeout: new Timeout.factor(2));
+
+    test('--footer-text includes text', () async {
+      String footerTextPath =
+          pathLib.join(Directory.systemTemp.path, 'footer.txt');
+      new File(footerTextPath).writeAsStringSync(' footer text include ');
+
+      var args = <String>[
+        dartdocPath,
+        '--footer-text=${footerTextPath}',
+        '--include',
+        'ex',
+        '--output',
+        tempDir.path
+      ];
+
+      await subprocessLauncher.runStreamed(Platform.resolvedExecutable, args,
+          workingDirectory: _testPackagePath);
+
+      File outFile = new File(pathLib.join(tempDir.path, 'index.html'));
+      expect(outFile.readAsStringSync(), contains('footer text include'));
+    });
+  }, timeout: new Timeout.factor(4));
+}
diff --git a/test/dartdoc_test.dart b/test/dartdoc_test.dart
index 70b7cd1..82c27b9 100644
--- a/test/dartdoc_test.dart
+++ b/test/dartdoc_test.dart
@@ -6,7 +6,6 @@
 
 import 'dart:async';
 import 'dart:io';
-import 'dart:mirrors';
 
 import 'package:dartdoc/dartdoc.dart';
 import 'package:dartdoc/src/logging.dart';
@@ -18,13 +17,6 @@
 
 import 'src/utils.dart';
 
-Uri get _currentFileUri =>
-    (reflect(main) as ClosureMirror).function.location.sourceUri;
-String get _testPackagePath =>
-    pathLib.fromUri(_currentFileUri.resolve('../testing/test_package'));
-String get _testPackageFlutterPluginPath => pathLib
-    .fromUri(_currentFileUri.resolve('../testing/test_package_flutter_plugin'));
-
 class DartdocLoggingOptionContext extends DartdocGeneratorOptionContext
     with LoggingContext {
   DartdocLoggingOptionContext(DartdocOptionSet optionSet, Directory dir)
@@ -117,212 +109,6 @@
           contains('Tool "drill" returned non-zero exit code'));
     });
 
-    group('Invoking command-line dartdoc', () {
-      String dartdocPath =
-          pathLib.canonicalize(pathLib.join('bin', 'dartdoc.dart'));
-      CoverageSubprocessLauncher subprocessLauncher;
-
-      setUpAll(() {
-        subprocessLauncher =
-            new CoverageSubprocessLauncher('dartdoc_test-subprocesses');
-      });
-
-      tearDownAll(() async {
-        await Future.wait(CoverageSubprocessLauncher.coverageResults);
-      });
-
-      test('running --no-generate-docs is quiet and does not generate docs',
-          () async {
-        Directory outputDir =
-            await Directory.systemTemp.createTemp('dartdoc.testEmpty.');
-        List<String> outputLines = [];
-        await subprocessLauncher.runStreamed(Platform.resolvedExecutable,
-            [dartdocPath, '--output', outputDir.path, '--no-generate-docs'],
-            perLine: outputLines.add, workingDirectory: _testPackagePath);
-        expect(outputLines, isNot(contains(matches('^parsing'))));
-        expect(outputLines, contains(matches('^  warning:')));
-        expect(
-            outputLines.last, matches(r'^found \d+ warnings and \d+ errors'));
-        expect(outputDir.listSync(), isEmpty);
-      });
-
-      test('running --quiet is quiet and does generate docs',
-          () async {
-        Directory outputDir =
-        await Directory.systemTemp.createTemp('dartdoc.testEmpty.');
-        List<String> outputLines = [];
-        await subprocessLauncher.runStreamed(Platform.resolvedExecutable,
-          [dartdocPath, '--output', outputDir.path, '--quiet'],
-          perLine: outputLines.add, workingDirectory: _testPackagePath);
-        expect(outputLines, isNot(contains(matches('^parsing'))));
-        expect(outputLines, contains(matches('^  warning:')));
-        expect(
-          outputLines.last, matches(r'^found \d+ warnings and \d+ errors'));
-        expect(outputDir.listSync(), isNotEmpty);
-      });
-
-      test('invalid parameters return non-zero and print a fatal-error',
-          () async {
-        List outputLines = [];
-        await expectLater(
-            () => subprocessLauncher.runStreamed(
-                Platform.resolvedExecutable,
-                [
-                  dartdocPath,
-                  '--nonexisting',
-                ],
-                perLine: outputLines.add),
-            throwsA(const TypeMatcher<ProcessException>()));
-        expect(
-            outputLines.firstWhere((l) => l.startsWith(' fatal')),
-            equals(
-                ' fatal error: Could not find an option named "nonexisting".'));
-      });
-
-      test('missing a required file path prints a fatal-error', () async {
-        List outputLines = [];
-        String impossiblePath = pathLib.join(dartdocPath, 'impossible');
-        await expectLater(
-            () => subprocessLauncher.runStreamed(
-                Platform.resolvedExecutable,
-                [
-                  dartdocPath,
-                  '--input',
-                  impossiblePath,
-                ],
-                perLine: outputLines.add),
-            throwsA(const TypeMatcher<ProcessException>()));
-        expect(
-            outputLines.firstWhere((l) => l.startsWith(' fatal')),
-            startsWith(
-                ' fatal error: Argument --input, set to ${impossiblePath}, resolves to missing path: '));
-      });
-
-      test('errors cause non-zero exit when warnings are off', () async {
-        expect(
-            () => subprocessLauncher.runStreamed(Platform.resolvedExecutable, [
-                  dartdocPath,
-                  '--input=${testPackageToolError.path}',
-                  '--output=${pathLib.join(tempDir.absolute.path, 'test_package_tool_error')}'
-                ]),
-            throwsA(const TypeMatcher<ProcessException>()));
-      });
-
-      test('help prints command line args', () async {
-        List<String> outputLines = [];
-        await subprocessLauncher.runStreamed(
-            Platform.resolvedExecutable, [dartdocPath, '--help'],
-            perLine: outputLines.add);
-        expect(outputLines,
-            contains('Generate HTML documentation for Dart libraries.'));
-        expect(
-            outputLines.join('\n'),
-            contains(new RegExp('^-h, --help[ ]+Show command help.',
-                multiLine: true)));
-      });
-
-      test('Validate missing FLUTTER_ROOT exception is clean', () async {
-        StringBuffer output = new StringBuffer();
-        var args = <String>[dartdocPath];
-        Future run = subprocessLauncher.runStreamed(
-            Platform.resolvedExecutable, args,
-            environment: new Map.from(Platform.environment)
-              ..remove('FLUTTER_ROOT'),
-            includeParentEnvironment: false,
-            workingDirectory: _testPackageFlutterPluginPath, perLine: (s) {
-          output.writeln(s);
-        });
-        // Asynchronous exception, but we still need the output, too.
-        expect(run, throwsA(new TypeMatcher<ProcessException>()));
-        try {
-          await run;
-        } on ProcessException catch (_) {}
-
-        expect(
-            output.toString(),
-            contains(new RegExp(
-                'Top level package requires Flutter but FLUTTER_ROOT environment variable not set|test_package_flutter_plugin requires the Flutter SDK, version solving failed')));
-        expect(output.toString(), isNot(contains('asynchronous gap')));
-      });
-
-      test("Validate --version works", () async {
-        StringBuffer output = new StringBuffer();
-        var args = <String>[dartdocPath, '--version'];
-        await subprocessLauncher.runStreamed(Platform.resolvedExecutable, args,
-            workingDirectory: _testPackagePath,
-            perLine: (s) => output.writeln(s));
-        PackageMeta dartdocMeta = new PackageMeta.fromFilename(dartdocPath);
-        expect(output.toString(),
-            endsWith('dartdoc version: ${dartdocMeta.version}\n'));
-      });
-
-      test('Check for sample code in examples', () async {
-        StringBuffer output = new StringBuffer();
-        var args = <String>[
-          dartdocPath,
-          '--include',
-          'ex',
-          '--no-include-source',
-          '--output',
-          tempDir.path
-        ];
-
-        await subprocessLauncher.runStreamed(Platform.resolvedExecutable, args,
-            workingDirectory: _testPackagePath,
-            perLine: (s) => output.writeln(s));
-
-        // Examples are reported as unfound because we (purposefully)
-        // did not use --example-path-prefix above.
-        final sep = '.'; // We don't care what the path separator character is
-        final firstUnfoundExample =
-            new RegExp('warning: lib${sep}example.dart: '
-                '@example file not found.*test_package${sep}dog${sep}food.md');
-        if (!output.toString().contains(firstUnfoundExample)) {
-          fail('Should warn about unfound @example files');
-        }
-      });
-
-      test('Validate JSON output', () async {
-        var args = <String>[
-          dartdocPath,
-          '--include',
-          'ex',
-          '--no-include-source',
-          '--output',
-          tempDir.path,
-          '--json'
-        ];
-
-        Iterable<Map> jsonValues = await subprocessLauncher.runStreamed(
-            Platform.resolvedExecutable, args,
-            workingDirectory: _testPackagePath);
-
-        expect(jsonValues, isNotEmpty,
-            reason: 'All STDOUT lines should be JSON-encoded maps.');
-      }, timeout: new Timeout.factor(2));
-
-      test('--footer-text includes text', () async {
-        String footerTextPath =
-            pathLib.join(Directory.systemTemp.path, 'footer.txt');
-        new File(footerTextPath).writeAsStringSync(' footer text include ');
-
-        var args = <String>[
-          dartdocPath,
-          '--footer-text=${footerTextPath}',
-          '--include',
-          'ex',
-          '--output',
-          tempDir.path
-        ];
-
-        await subprocessLauncher.runStreamed(Platform.resolvedExecutable, args,
-            workingDirectory: _testPackagePath);
-
-        File outFile = new File(pathLib.join(tempDir.path, 'index.html'));
-        expect(outFile.readAsStringSync(), contains('footer text include'));
-      });
-    }, timeout: new Timeout.factor(3));
-
     group('Option handling with cross-linking', () {
       DartdocResults results;
       Package testPackageOptions;
diff --git a/tool/grind.dart b/tool/grind.dart
index 3d786ca..d707afc 100644
--- a/tool/grind.dart
+++ b/tool/grind.dart
@@ -38,10 +38,8 @@
     Platform.environment['PUB_CACHE'] ?? resolveTildePath('~/.pub-cache');
 
 /// Run no more than the number of processors available in parallel.
-final MultiFutureTracker testFutures = new MultiFutureTracker(
-    Platform.environment.containsKey('TRAVIS')
-        ? 1
-        : Platform.numberOfProcessors);
+final MultiFutureTracker testFutures =
+    new MultiFutureTracker(Platform.numberOfProcessors);
 
 // Directory.systemTemp is not a constant.  So wrap it.
 Directory createTempSync(String prefix) =>
@@ -829,10 +827,8 @@
 @Task('Dry run of publish to pub.dartlang')
 @Depends(checkChangelogHasVersion)
 Future<void> tryPublish() async {
-  log('FIXME:  tryPublish() disabled until dependency_override is removed'
-      ' (#1765)');
-  //var launcher = new SubprocessLauncher('try-publish');
-  //await launcher.runStreamed(sdkBin('pub'), ['publish', '-n']);
+  var launcher = new SubprocessLauncher('try-publish');
+  await launcher.runStreamed(sdkBin('pub'), ['publish', '-n']);
 }
 
 @Task('Run all the tests.')
@@ -841,12 +837,6 @@
   await testFutures.wait();
 }
 
-List<File> get binFiles => new Directory('bin')
-    .listSync(recursive: true)
-    .where((e) => e is File && e.path.endsWith('.dart'))
-    .cast<File>()
-    .toList();
-
 List<File> get testFiles => new Directory('test')
     .listSync(recursive: true)
     .where((e) => e is File && e.path.endsWith('test.dart'))
@@ -866,18 +856,7 @@
               ..add(dartFile.path)));
   }
 
-  for (File dartFile in binFiles) {
-    await testFutures.addFutureFromClosure(() => new CoverageSubprocessLauncher(
-            'dart2-bin-${pathLib.basename(dartFile.path)}-help')
-        .runStreamed(
-            Platform.resolvedExecutable,
-            <String>[]
-              ..addAll(parameters)
-              ..add(dartFile.path)
-              ..add('--help')));
-  }
-
-  return await CoverageSubprocessLauncher.generateCoverageToFile(
+  return CoverageSubprocessLauncher.generateCoverageToFile(
       new File('lcov.info'));
 }