Changed the result in ProcessRunnerException to be a ProcessRunnerResult

* Breaking change to change the result given in the ProcessRunnerException
  to be a ProcessRunnerResult instead of a ProcessResult, which can't
  include the interleaved stdout/stderr output for failed commands.

* Modified the ProcessPool to set the result correctly on failed jobs.

* Added tests to verify that failed jobs return results.
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 6eca3d2..66f3b55 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,5 +1,12 @@
 # Change Log for `process_runner`
 
+## 3.0.0
+
+* Breaking change to change the `result` given in the `ProcessRunnerException`
+  to be a `ProcessRunnerResult` instead of a `ProcessResult`, which can't
+  include the interleaved stdout/stderr output for failed commands.
+* Modified the `ProcessPool` to set the result correctly on failed jobs.
+
 ## 2.0.5
 
 * Added `WorkerJob.failOk` so that failure message of failed worker jobs is
diff --git a/lib/src/process_pool.dart b/lib/src/process_pool.dart
index a0256f1..5873c9c 100644
--- a/lib/src/process_pool.dart
+++ b/lib/src/process_pool.dart
@@ -190,6 +190,7 @@
       if (!job.failOk) {
         stderr.writeln('\nJob $job failed: $e');
       }
+      job.result = e.result;
       _failedJobs.add(job);
     } finally {
       _inProgressJobs--;
diff --git a/lib/src/process_runner.dart b/lib/src/process_runner.dart
index 80cbb2f..35aefb5 100644
--- a/lib/src/process_runner.dart
+++ b/lib/src/process_runner.dart
@@ -19,7 +19,7 @@
   ProcessRunnerException(this.message, {this.result});
 
   final String message;
-  final ProcessResult result;
+  final ProcessRunnerResult result;
 
   int get exitCode => result?.exitCode ?? -1;
 
@@ -27,7 +27,7 @@
   String toString() {
     String output = runtimeType.toString();
     output += ': $message';
-    final String stderr = (result?.stderr ?? '') as String;
+    final String stderr = result?.stderr ?? '';
     if (stderr.isNotEmpty) {
       output += ':\n$stderr';
     }
@@ -249,14 +249,15 @@
     final int exitCode = await allComplete();
     if (exitCode != 0 && !failOk) {
       final String message =
-          'Running "${commandLine.join(' ')}" in ${workingDirectory.path} failed';
+          'Running "${commandLine.join(' ')}" in ${workingDirectory.path} exited with code $exitCode\n${decoder.decode(combinedOutput)}';
       throw ProcessRunnerException(
         message,
-        result: ProcessResult(
-          0,
+        result: ProcessRunnerResult(
           exitCode,
-          null,
-          'exited with code $exitCode\n${decoder.decode(combinedOutput)}',
+          stdoutOutput,
+          stderrOutput,
+          combinedOutput,
+          decoder: decoder,
         ),
       );
     }
diff --git a/pubspec.yaml b/pubspec.yaml
index 1476a39..64c5514 100644
--- a/pubspec.yaml
+++ b/pubspec.yaml
@@ -3,7 +3,7 @@
 # found in the LICENSE file.
 
 name: process_runner
-version: 2.0.5
+version: 3.0.0
 description: A process invocation astraction for Dart that manages a multiprocess queue.
 homepage: https://github.com/google/process_runner
 
diff --git a/test/src/process_pool_test.dart b/test/src/process_pool_test.dart
index 73a3e14..dfd8fd0 100644
--- a/test/src/process_pool_test.dart
+++ b/test/src/process_pool_test.dart
@@ -49,5 +49,21 @@
       await processPool.runToCompletion(jobs);
       fakeProcessManager.verifyCalls(calls.keys);
     });
+    test('failed tests report results', () async {
+      final Map<List<String>, List<ProcessResult>> calls = <List<String>, List<ProcessResult>>{
+        <String>['command', 'arg1', 'arg2']: <ProcessResult>[
+          ProcessResult(0, -1, 'output1', 'stderr1'),
+        ],
+      };
+      fakeProcessManager.fakeResults = calls;
+      final List<WorkerJob> jobs = <WorkerJob>[
+        WorkerJob(<String>['command', 'arg1', 'arg2'], name: 'job 1'),
+      ];
+      final List<WorkerJob> completed = await processPool.runToCompletion(jobs);
+      expect(completed.first.result.exitCode, equals(-1));
+      expect(completed.first.result.stdout, equals('output1'));
+      expect(completed.first.result.stderr, equals('stderr1'));
+      expect(completed.first.result.output, equals('output1stderr1'));
+    });
   });
 }
diff --git a/test/src/process_runner_test.dart b/test/src/process_runner_test.dart
index b507da4..6d7ea1e 100644
--- a/test/src/process_runner_test.dart
+++ b/test/src/process_runner_test.dart
@@ -54,5 +54,18 @@
       fakeProcessManager.fakeResults = calls;
       await expectLater(() => processRunner.runProcess(calls.keys.first), throwsException);
     });
+    test('runProcess returns the failed results properly', () async {
+      final Map<List<String>, List<ProcessResult>> calls = <List<String>, List<ProcessResult>>{
+        <String>['command', 'arg1', 'arg2']: <ProcessResult>[
+          ProcessResult(0, -1, 'output1', 'stderr1'),
+        ],
+      };
+      fakeProcessManager.fakeResults = calls;
+      final ProcessRunnerResult result =
+          await processRunner.runProcess(calls.keys.first, failOk: true);
+      expect(result.stdout, equals('output1'));
+      expect(result.stderr, equals('stderr1'));
+      expect(result.output, equals('output1stderr1'));
+    });
   });
 }