Parameter error display tests (#1895)

* Fix a bug and add more tests for parameter parsing

* dartfmt

* Hide observatory lines from downstream users

* Lines are out of order on windows
diff --git a/bin/dartdoc.dart b/bin/dartdoc.dart
index 840eef6..830624b 100644
--- a/bin/dartdoc.dart
+++ b/bin/dartdoc.dart
@@ -57,12 +57,6 @@
     // TODO(jcollins-g): use exit once dart-lang/sdk#31747 is fixed.
     exitCode = 64;
     return;
-  } on DartdocOptionError catch (e) {
-    stderr.writeln(' fatal error: ${e.message}');
-    stderr.writeln('');
-    _printUsage(optionSet.argParser);
-    exitCode = 64;
-    return;
   }
   if (optionSet['help'].valueAt(Directory.current)) {
     _printHelp(optionSet.argParser);
@@ -75,8 +69,17 @@
     return;
   }
 
-  DartdocProgramOptionContext config =
-      new DartdocProgramOptionContext(optionSet, null);
+  DartdocProgramOptionContext config;
+  try {
+    config = new DartdocProgramOptionContext(optionSet, null);
+  } on DartdocOptionError catch (e) {
+    stderr.writeln(' fatal error: ${e.message}');
+    stderr.writeln('');
+    await stderr.flush();
+    _printUsage(optionSet.argParser);
+    exitCode = 64;
+    return;
+  }
   startLogging(config);
 
   Directory outputDir = new Directory(config.output);
diff --git a/test/dartdoc_test.dart b/test/dartdoc_test.dart
index ab02d48..30d6fef 100644
--- a/test/dartdoc_test.dart
+++ b/test/dartdoc_test.dart
@@ -131,6 +131,43 @@
         await Future.wait(CoverageSubprocessLauncher.coverageResults);
       });
 
+      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, [
diff --git a/test/src/utils.dart b/test/src/utils.dart
index 3cf9b4a..fde3819 100644
--- a/test/src/utils.dart
+++ b/test/src/utils.dart
@@ -182,10 +182,11 @@
 
     Completer<String> portAsString = new Completer();
     void parsePortAsString(String line) {
-      if (perLine != null) perLine(line);
-      if (!portAsString.isCompleted) {
+      if (!portAsString.isCompleted && coverageEnabled) {
         Match m = observatoryPortRegexp.matchAsPrefix(line);
         if (m?.group(1) != null) portAsString.complete(m.group(1));
+      } else {
+        if (perLine != null) perLine(line);
       }
     }