Relanding "Add finished callback to StringConsumer."

This cherry-picks 197c2292f84b11632e3c5c8e9db34dc5da842231
with fixed conflicts.

The change was reverted as part of 523ef9455bab0bd029227982f0ade905d710feeb.

Bug: 140141590
Change-Id: Ie987353e02a25ad9a14bea2710f4de965247a3c3
diff --git a/build.gradle b/build.gradle
index 09f6368..a68c7a9 100644
--- a/build.gradle
+++ b/build.gradle
@@ -517,7 +517,7 @@
         options.fork = true
         // Javac often runs out of stack space when compiling the tests.
         // Increase the stack size for the javac process.
-        options.forkOptions.jvmArgs << "-Xss4m"
+        options.forkOptions.jvmArgs << "-Xss256m"
         // Test compilation is sometimes hitting the default limit at 1g, increase it.
         options.forkOptions.jvmArgs << "-Xmx2g"
         // Set the bootclass path so compilation is consistent with 1.8 target compatibility.
diff --git a/src/main/java/com/android/tools/r8/GenerateMainDexList.java b/src/main/java/com/android/tools/r8/GenerateMainDexList.java
index ea3472f..2aa0ac5 100644
--- a/src/main/java/com/android/tools/r8/GenerateMainDexList.java
+++ b/src/main/java/com/android/tools/r8/GenerateMainDexList.java
@@ -75,6 +75,7 @@
 
       if (options.mainDexListConsumer != null) {
         options.mainDexListConsumer.accept(String.join("\n", result), options.reporter);
+        options.mainDexListConsumer.finished(options.reporter);
       }
 
       R8.processWhyAreYouKeepingAndCheckDiscarded(
diff --git a/src/main/java/com/android/tools/r8/R8Command.java b/src/main/java/com/android/tools/r8/R8Command.java
index 53faa52..235882e 100644
--- a/src/main/java/com/android/tools/r8/R8Command.java
+++ b/src/main/java/com/android/tools/r8/R8Command.java
@@ -10,7 +10,6 @@
 import com.android.tools.r8.ir.desugar.DesugaredLibraryConfiguration;
 import com.android.tools.r8.origin.Origin;
 import com.android.tools.r8.origin.PathOrigin;
-import com.android.tools.r8.origin.StandardOutOrigin;
 import com.android.tools.r8.shaking.ProguardConfiguration;
 import com.android.tools.r8.shaking.ProguardConfigurationParser;
 import com.android.tools.r8.shaking.ProguardConfigurationRule;
@@ -882,10 +881,22 @@
       if (optionFile != null) {
         return new StringConsumer.FileConsumer(optionFile, optionConsumer);
       } else {
-        return new StringConsumer.StreamConsumer(
-            StandardOutOrigin.instance(), System.out, optionConsumer);
+        return new StandardOutConsumer(optionConsumer);
       }
     }
     return optionConsumer;
   }
+
+  private static class StandardOutConsumer extends StringConsumer.ForwardingConsumer {
+
+    public StandardOutConsumer(StringConsumer consumer) {
+      super(consumer);
+    }
+
+    @Override
+    public void accept(String string, DiagnosticsHandler handler) {
+      super.accept(string, handler);
+      System.out.print(string);
+    }
+  }
 }
diff --git a/src/main/java/com/android/tools/r8/StringConsumer.java b/src/main/java/com/android/tools/r8/StringConsumer.java
index 2037cda..5d02846 100644
--- a/src/main/java/com/android/tools/r8/StringConsumer.java
+++ b/src/main/java/com/android/tools/r8/StringConsumer.java
@@ -6,10 +6,8 @@
 import com.android.tools.r8.origin.Origin;
 import com.android.tools.r8.origin.PathOrigin;
 import com.android.tools.r8.utils.ExceptionDiagnostic;
-import java.io.BufferedWriter;
 import java.io.IOException;
-import java.io.OutputStream;
-import java.io.OutputStreamWriter;
+import java.io.Writer;
 import java.nio.charset.Charset;
 import java.nio.charset.StandardCharsets;
 import java.nio.file.Files;
@@ -20,17 +18,31 @@
 public interface StringConsumer {
 
   /**
-   * Callback to receive a String resource.
+   * Callback to receive part of a string resource.
    *
    * <p>The consumer is expected not to throw, but instead report any errors via the diagnostics
    * {@param handler}. If an error is reported via {@param handler} and no exceptions are thrown,
    * then the compiler guaranties to exit with an error.
    *
-   * @param string String resource.
+   * <p>Note: prior to the addition of 'finished' consumers could expect all content to be reported
+   * in one call to accept. That is no longer guaranteed.
+   *
+   * @param string Part of the string resource.
    * @param handler Diagnostics handler for reporting.
    */
   void accept(String string, DiagnosticsHandler handler);
 
+  /**
+   * Callback when no further content will be provided for the string resource.
+   *
+   * <p>The consumer is expected not to throw, but instead report any errors via the diagnostics
+   * {@param handler}. If an error is reported via {@param handler} and no exceptions are thrown,
+   * then the compiler guaranties to exit with an error.
+   *
+   * @param handler Diagnostics handler for reporting.
+   */
+  void finished(DiagnosticsHandler handler);
+
   static EmptyConsumer emptyConsumer() {
     return EmptyConsumer.EMPTY_CONSUMER;
   }
@@ -44,6 +56,11 @@
     public void accept(String string, DiagnosticsHandler handler) {
       // Ignore content.
     }
+
+    @Override
+    public void finished(DiagnosticsHandler handler) {
+      // No content so, nothing to do.
+    }
   }
 
   /** Forwarding consumer to delegate to an optional existing consumer. */
@@ -62,14 +79,22 @@
         consumer.accept(string, handler);
       }
     }
+
+    @Override
+    public void finished(DiagnosticsHandler handler) {
+      if (consumer != null) {
+        consumer.finished(handler);
+      }
+    }
   }
 
   /** File consumer to write contents to a file-system file. */
-  @Keep // TODO(b/121121779) Extend keep-annotation to public inner classes and remove this.
+  @Keep // TODO(b/121121779) Consider deprecating the R8 provided file writing.
   class FileConsumer extends ForwardingConsumer {
 
     private final Path outputPath;
     private Charset encoding = StandardCharsets.UTF_8;
+    private WriterConsumer delegate = null;
 
     /** Consumer that writes to {@param outputPath}. */
     public FileConsumer(Path outputPath) {
@@ -90,6 +115,9 @@
     /** Set the output encoding. Defaults to UTF8. */
     public void setEncoding(Charset encoding) {
       assert encoding != null;
+      if (delegate != null) {
+        throw new IllegalStateException("Invalid call to set encoding after file stream is opened");
+      }
       this.encoding = encoding;
     }
 
@@ -101,57 +129,61 @@
     @Override
     public void accept(String string, DiagnosticsHandler handler) {
       super.accept(string, handler);
+      ensureDelegate(handler);
+      delegate.accept(string, handler);
+    }
+
+    @Override
+    public void finished(DiagnosticsHandler handler) {
+      super.finished(handler);
+      if (delegate != null) {
+        delegate.finished(handler);
+        delegate = null;
+      }
+    }
+
+    private void ensureDelegate(DiagnosticsHandler handler) {
+      if (delegate != null) {
+        return;
+      }
+      PathOrigin origin = new PathOrigin(outputPath);
       try {
         Path parent = outputPath.getParent();
         if (parent != null && !parent.toFile().exists()) {
           Files.createDirectories(parent);
         }
-        com.google.common.io.Files.asCharSink(outputPath.toFile(), encoding).write(string);
+        delegate = new WriterConsumer(origin, Files.newBufferedWriter(outputPath, encoding));
       } catch (IOException e) {
-        Origin origin = new PathOrigin(outputPath);
         handler.error(new ExceptionDiagnostic(e, origin));
       }
     }
   }
 
   /**
-   * Stream consumer to write contents to an output stream.
+   * String consumer to write contents to a Writer.
    *
-   * <p>Note: No close events are given to this stream so it should either be a permanent stream or
-   * the closing needs to happen outside of the compilation itself. If the stream is not one of the
-   * standard streams, i.e., System.out or System.err, you should likely implement yor own consumer.
+   * <p>Note: The writer is closed when the consumer receives its 'finished' callback.
    */
-  class StreamConsumer extends ForwardingConsumer {
+  class WriterConsumer extends ForwardingConsumer {
 
     private final Origin origin;
-    private final OutputStream outputStream;
-    private Charset encoding = StandardCharsets.UTF_8;
+    private Writer writer;
 
-    /** Consumer that writes to {@param outputStream}. */
-    public StreamConsumer(Origin origin, OutputStream outputStream) {
-      this(origin, outputStream, null);
+    /** Consumer that writes to {@param writer}. */
+    public WriterConsumer(Origin origin, Writer writer) {
+      this(origin, writer, null);
     }
 
-    /** Consumer that forwards to {@param consumer} and also writes to {@param outputStream}. */
-    public StreamConsumer(Origin origin, OutputStream outputStream, StringConsumer consumer) {
+    /** Consumer that forwards to {@param consumer} and also writes to {@param writer}. */
+    public WriterConsumer(Origin origin, Writer writer, StringConsumer consumer) {
       super(consumer);
       this.origin = origin;
-      this.outputStream = outputStream;
-    }
-
-    /** Set the encoding. Defaults to UTF8. */
-    public void setEncoding(Charset encoding) {
-      assert encoding != null;
-      this.encoding = encoding;
+      this.writer = writer;
     }
 
     @Override
     public void accept(String string, DiagnosticsHandler handler) {
       super.accept(string, handler);
-      // Don't close this writer as it will close the underlying stream, which we specifically do
-      // not want.
-      BufferedWriter writer =
-          new BufferedWriter(new OutputStreamWriter(outputStream, encoding.newEncoder()));
       try {
         writer.write(string);
         writer.flush();
@@ -159,5 +191,15 @@
         handler.error(new ExceptionDiagnostic(e, origin));
       }
     }
+
+    @Override
+    public void finished(DiagnosticsHandler handler) {
+      super.finished(handler);
+      try {
+        writer.close();
+      } catch (IOException e) {
+        handler.error(new ExceptionDiagnostic(e, origin));
+      }
+    }
   }
 }
diff --git a/src/main/java/com/android/tools/r8/dex/ApplicationWriter.java b/src/main/java/com/android/tools/r8/dex/ApplicationWriter.java
index a3b6888..eb5fa29 100644
--- a/src/main/java/com/android/tools/r8/dex/ApplicationWriter.java
+++ b/src/main/java/com/android/tools/r8/dex/ApplicationWriter.java
@@ -374,19 +374,24 @@
       ExceptionUtils.withConsumeResourceHandler(
           options.reporter, options.configurationConsumer,
           options.getProguardConfiguration().getParsedConfiguration());
+      ExceptionUtils.withFinishedResourceHandler(options.reporter, options.configurationConsumer);
     }
     if (options.usageInformationConsumer != null && deadCode != null) {
       ExceptionUtils.withConsumeResourceHandler(
           options.reporter, options.usageInformationConsumer, deadCode);
+      ExceptionUtils.withFinishedResourceHandler(
+          options.reporter, options.usageInformationConsumer);
     }
     if (proguardMapContent != null) {
       assert validateProguardMapParses(proguardMapContent);
       ExceptionUtils.withConsumeResourceHandler(
           options.reporter, options.proguardMapConsumer, proguardMapContent);
+      ExceptionUtils.withFinishedResourceHandler(options.reporter, options.proguardMapConsumer);
     }
     if (options.mainDexListConsumer != null) {
       ExceptionUtils.withConsumeResourceHandler(
           options.reporter, options.mainDexListConsumer, writeMainDexList(application, namingLens));
+      ExceptionUtils.withFinishedResourceHandler(options.reporter, options.mainDexListConsumer);
     }
     DataResourceConsumer dataResourceConsumer = options.dataResourceConsumer;
     if (dataResourceConsumer != null) {
diff --git a/src/main/java/com/android/tools/r8/dex/CodeToKeep.java b/src/main/java/com/android/tools/r8/dex/CodeToKeep.java
index 4f3f442..6e44735 100644
--- a/src/main/java/com/android/tools/r8/dex/CodeToKeep.java
+++ b/src/main/java/com/android/tools/r8/dex/CodeToKeep.java
@@ -145,6 +145,7 @@
         sb.append("}").append(cr);
       }
       options.desugaredLibraryKeepRuleConsumer.accept(sb.toString(), options.reporter);
+      options.desugaredLibraryKeepRuleConsumer.finished(options.reporter);
     }
   }
 
diff --git a/src/main/java/com/android/tools/r8/utils/AndroidAppConsumers.java b/src/main/java/com/android/tools/r8/utils/AndroidAppConsumers.java
index b7beb82..06fef54 100644
--- a/src/main/java/com/android/tools/r8/utils/AndroidAppConsumers.java
+++ b/src/main/java/com/android/tools/r8/utils/AndroidAppConsumers.java
@@ -70,10 +70,23 @@
     if (consumer != null) {
       proguardMapConsumer =
           new StringConsumer.ForwardingConsumer(consumer) {
+            StringBuilder stringBuilder = null;
+
             @Override
             public void accept(String string, DiagnosticsHandler handler) {
               super.accept(string, handler);
-              builder.setProguardMapOutputData(string);
+              if (stringBuilder == null) {
+                stringBuilder = new StringBuilder();
+              }
+              stringBuilder.append(string);
+            }
+
+            @Override
+            public void finished(DiagnosticsHandler handler) {
+              super.finished(handler);
+              if (stringBuilder != null) {
+                builder.setProguardMapOutputData(stringBuilder.toString());
+              }
             }
           };
     }
diff --git a/src/main/java/com/android/tools/r8/utils/ExceptionUtils.java b/src/main/java/com/android/tools/r8/utils/ExceptionUtils.java
index 8b4b602..16bde83 100644
--- a/src/main/java/com/android/tools/r8/utils/ExceptionUtils.java
+++ b/src/main/java/com/android/tools/r8/utils/ExceptionUtils.java
@@ -25,6 +25,10 @@
     withConsumeResourceHandler(reporter, handler -> consumer.accept(data, handler));
   }
 
+  public static void withFinishedResourceHandler(Reporter reporter, StringConsumer consumer) {
+    withConsumeResourceHandler(reporter, consumer::finished);
+  }
+
   public static void withConsumeResourceHandler(
       Reporter reporter, Consumer<DiagnosticsHandler> consumer) {
     // Unchecked exceptions simply propagate out, aborting the compilation forcefully.
diff --git a/src/test/java/com/android/tools/r8/D8CommandTest.java b/src/test/java/com/android/tools/r8/D8CommandTest.java
index ec83a9b..a35a7d7 100644
--- a/src/test/java/com/android/tools/r8/D8CommandTest.java
+++ b/src/test/java/com/android/tools/r8/D8CommandTest.java
@@ -21,7 +21,6 @@
 import com.android.tools.r8.origin.Origin;
 import com.android.tools.r8.utils.AndroidApiLevel;
 import com.android.tools.r8.utils.AndroidApp;
-import com.android.tools.r8.utils.Box;
 import com.android.tools.r8.utils.FileUtils;
 import com.android.tools.r8.utils.ZipUtils;
 import com.google.common.collect.ImmutableList;
@@ -87,8 +86,7 @@
 
   @Test
   public void desugaredLibraryKeepRuleConsumer() throws Exception {
-    Box<String> holder = new Box<>("");
-    StringConsumer stringConsumer = (string, handler) -> holder.set(holder.get() + string);
+    StringConsumer stringConsumer = StringConsumer.emptyConsumer();
     D8Command command =
         D8Command.builder()
             .setProgramConsumer(DexIndexedConsumer.emptyConsumer())
diff --git a/src/test/java/com/android/tools/r8/ProguardMapMarkerTest.java b/src/test/java/com/android/tools/r8/ProguardMapMarkerTest.java
index c5961e8..59f6159 100644
--- a/src/test/java/com/android/tools/r8/ProguardMapMarkerTest.java
+++ b/src/test/java/com/android/tools/r8/ProguardMapMarkerTest.java
@@ -70,11 +70,12 @@
             .addLibraryFiles(ToolHelper.getAndroidJar(minApiLevel))
             .setMinApiLevel(minApiLevel.getLevel())
             .setProguardMapConsumer(
-                (proguardMap, handler) -> {
-                  proguardMapIds.fromMap =
-                      verifyMarkersGetPgMapId(
-                          proguardMap, minApiLevel.getLevel(), EXPECTED_NUMBER_OF_KEYS_DEX);
-                })
+                ToolHelper.consumeString(
+                    proguardMap -> {
+                      proguardMapIds.fromMap =
+                          verifyMarkersGetPgMapId(
+                              proguardMap, minApiLevel.getLevel(), EXPECTED_NUMBER_OF_KEYS_DEX);
+                    }))
             .build());
     verifyProguardMapIds(proguardMapIds);
   }
@@ -113,10 +114,11 @@
                 })
             .addLibraryFiles(ToolHelper.getJava8RuntimeJar())
             .setProguardMapConsumer(
-                (proguardMap, handler) -> {
-                  buildIds.fromMap =
-                      verifyMarkersGetPgMapId(proguardMap, null, EXPECTED_NUMBER_OF_KEYS_CF);
-                })
+                ToolHelper.consumeString(
+                    proguardMap -> {
+                      buildIds.fromMap =
+                          verifyMarkersGetPgMapId(proguardMap, null, EXPECTED_NUMBER_OF_KEYS_CF);
+                    }))
             .build());
     verifyProguardMapIds(buildIds);
   }
diff --git a/src/test/java/com/android/tools/r8/R8TestBuilder.java b/src/test/java/com/android/tools/r8/R8TestBuilder.java
index 955e75c..afa408d 100644
--- a/src/test/java/com/android/tools/r8/R8TestBuilder.java
+++ b/src/test/java/com/android/tools/r8/R8TestBuilder.java
@@ -66,7 +66,18 @@
     StringBuilder proguardMapBuilder = new StringBuilder();
     builder.setDisableTreeShaking(!enableTreeShaking);
     builder.setDisableMinification(!enableMinification);
-    builder.setProguardMapConsumer((string, ignore) -> proguardMapBuilder.append(string));
+    builder.setProguardMapConsumer(
+        new StringConsumer() {
+          @Override
+          public void accept(String string, DiagnosticsHandler handler) {
+            proguardMapBuilder.append(string);
+          }
+
+          @Override
+          public void finished(DiagnosticsHandler handler) {
+            // Nothing to do.
+          }
+        });
 
     if (!applyMappingMaps.isEmpty()) {
       try {
diff --git a/src/test/java/com/android/tools/r8/ToolHelper.java b/src/test/java/com/android/tools/r8/ToolHelper.java
index f7cca02..f9636bd 100644
--- a/src/test/java/com/android/tools/r8/ToolHelper.java
+++ b/src/test/java/com/android/tools/r8/ToolHelper.java
@@ -167,6 +167,28 @@
         || (backend == Backend.DEX && outputMode != OutputMode.ClassFile);
   }
 
+  public static StringConsumer consumeString(Consumer<String> consumer) {
+    return new StringConsumer() {
+
+      private StringBuilder builder;
+
+      @Override
+      public void accept(String string, DiagnosticsHandler handler) {
+        if (builder == null) {
+          builder = new StringBuilder();
+        }
+        builder.append(string);
+      }
+
+      @Override
+      public void finished(DiagnosticsHandler handler) {
+        if (builder != null) {
+          consumer.accept(builder.toString());
+        }
+      }
+    };
+  }
+
   public enum DexVm {
     ART_4_0_4_TARGET(Version.V4_0_4, Kind.TARGET),
     ART_4_0_4_HOST(Version.V4_0_4, Kind.HOST),
diff --git a/src/test/java/com/android/tools/r8/classmerging/VerticalClassMergerTest.java b/src/test/java/com/android/tools/r8/classmerging/VerticalClassMergerTest.java
index d14e230..6b4f17d 100644
--- a/src/test/java/com/android/tools/r8/classmerging/VerticalClassMergerTest.java
+++ b/src/test/java/com/android/tools/r8/classmerging/VerticalClassMergerTest.java
@@ -519,8 +519,10 @@
           options.enableVerticalClassMerging = false;
           options.testing.validInliningReasons = ImmutableSet.of(Reason.FORCE);
           options.proguardMapConsumer =
-              (proguardMap, handler) ->
-                  assertThat(proguardMap, containsString(expectedProguardMapWithoutClassMerging));
+              ToolHelper.consumeString(
+                  proguardMap ->
+                      assertThat(
+                          proguardMap, containsString(expectedProguardMapWithoutClassMerging)));
         });
 
     // Try with vertical class merging.
@@ -547,8 +549,9 @@
           configure(options);
           options.testing.validInliningReasons = ImmutableSet.of(Reason.FORCE);
           options.proguardMapConsumer =
-              (proguardMap, handler) ->
-                  assertThat(proguardMap, containsString(expectedProguardMapWithClassMerging));
+              ToolHelper.consumeString(
+                  proguardMap ->
+                      assertThat(proguardMap, containsString(expectedProguardMapWithClassMerging)));
         });
   }
 
@@ -584,8 +587,10 @@
           options.enableVerticalClassMerging = false;
           options.testing.validInliningReasons = ImmutableSet.of(Reason.FORCE);
           options.proguardMapConsumer =
-              (proguardMap, handler) ->
-                  assertThat(proguardMap, containsString(expectedProguardMapWithoutClassMerging));
+              ToolHelper.consumeString(
+                  proguardMap ->
+                      assertThat(
+                          proguardMap, containsString(expectedProguardMapWithoutClassMerging)));
         });
 
     // Try with vertical class merging.
@@ -615,8 +620,9 @@
           configure(options);
           options.testing.validInliningReasons = ImmutableSet.of(Reason.FORCE);
           options.proguardMapConsumer =
-              (proguardMap, handler) ->
-                  assertThat(proguardMap, containsString(expectedProguardMapWithClassMerging));
+              ToolHelper.consumeString(
+                  proguardMap ->
+                      assertThat(proguardMap, containsString(expectedProguardMapWithClassMerging)));
         });
   }
 
@@ -655,8 +661,10 @@
           options.enableVerticalClassMerging = false;
           options.testing.validInliningReasons = ImmutableSet.of(Reason.FORCE);
           options.proguardMapConsumer =
-              (proguardMap, handler) ->
-                  assertThat(proguardMap, containsString(expectedProguardMapWithoutClassMerging));
+              ToolHelper.consumeString(
+                  proguardMap ->
+                      assertThat(
+                          proguardMap, containsString(expectedProguardMapWithoutClassMerging)));
         });
 
     // Try with vertical class merging.
@@ -685,8 +693,9 @@
           configure(options);
           options.testing.validInliningReasons = ImmutableSet.of(Reason.FORCE);
           options.proguardMapConsumer =
-              (proguardMap, handler) ->
-                  assertThat(proguardMap, containsString(expectedProguardMapWithClassMerging));
+              ToolHelper.consumeString(
+                  proguardMap ->
+                      assertThat(proguardMap, containsString(expectedProguardMapWithClassMerging)));
         });
   }
 
diff --git a/src/test/java/com/android/tools/r8/desugar/corelib/CoreLibDesugarTestBase.java b/src/test/java/com/android/tools/r8/desugar/corelib/CoreLibDesugarTestBase.java
index a5f8124..57e3231 100644
--- a/src/test/java/com/android/tools/r8/desugar/corelib/CoreLibDesugarTestBase.java
+++ b/src/test/java/com/android/tools/r8/desugar/corelib/CoreLibDesugarTestBase.java
@@ -134,6 +134,11 @@
     public void accept(String string, DiagnosticsHandler handler) {
       throw new Unreachable("No desugaring on high API levels");
     }
+
+    @Override
+    public void finished(DiagnosticsHandler handler) {
+      throw new Unreachable("No desugaring on high API levels");
+    }
   }
 
   public static class PresentKeepRuleConsumer implements KeepRuleConsumer {
diff --git a/src/test/java/com/android/tools/r8/desugar/corelib/CustomCollectionTest.java b/src/test/java/com/android/tools/r8/desugar/corelib/CustomCollectionTest.java
index 36ea940..a60cbd2 100644
--- a/src/test/java/com/android/tools/r8/desugar/corelib/CustomCollectionTest.java
+++ b/src/test/java/com/android/tools/r8/desugar/corelib/CustomCollectionTest.java
@@ -10,12 +10,20 @@
 import com.android.tools.r8.D8TestRunResult;
 import com.android.tools.r8.R8TestRunResult;
 import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.ToolHelper;
 import com.android.tools.r8.utils.BooleanUtils;
+import com.android.tools.r8.utils.Box;
 import com.android.tools.r8.utils.codeinspector.CodeInspector;
 import com.android.tools.r8.utils.codeinspector.InstructionSubject;
 import com.android.tools.r8.utils.codeinspector.InstructionSubject.JumboStringMode;
 import com.android.tools.r8.utils.codeinspector.MethodSubject;
-import java.util.*;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.Iterator;
+import java.util.List;
+import java.util.SortedSet;
 import java.util.stream.Stream;
 import org.jetbrains.annotations.NotNull;
 import org.jetbrains.annotations.Nullable;
@@ -47,18 +55,22 @@
 
   @Test
   public void testCustomCollectionD8() throws Exception {
-    KeepRuleConsumer keepRuleConsumer = createKeepRuleConsumer(parameters);
+    Box<String> keepRulesHolder = new Box<>("");
     D8TestRunResult d8TestRunResult =
         testForD8()
             .addInnerClasses(CustomCollectionTest.class)
             .setMinApi(parameters.getApiLevel())
-            .enableCoreLibraryDesugaring(parameters.getApiLevel(), keepRuleConsumer)
+            .addOptionsModification(
+                options ->
+                    options.desugaredLibraryKeepRuleConsumer =
+                        ToolHelper.consumeString(keepRulesHolder::set))
+            .enableCoreLibraryDesugaring(parameters.getApiLevel())
             .compile()
             .inspect(inspector -> this.assertCustomCollectionCallsCorrect(inspector, false))
             .addDesugaredCoreLibraryRunClassPath(
                 this::buildDesugaredLibrary,
                 parameters.getApiLevel(),
-                keepRuleConsumer.get(),
+                keepRulesHolder.get(),
                 shrinkCoreLibrary)
             .run(parameters.getRuntime(), EXECUTOR)
             .assertSuccess();
@@ -77,7 +89,7 @@
 
   @Test
   public void testCustomCollectionR8() throws Exception {
-    KeepRuleConsumer keepRuleConsumer = createKeepRuleConsumer(parameters);
+    Box<String> keepRulesHolder = new Box<>("");
     R8TestRunResult r8TestRunResult =
         testForR8(Backend.DEX)
             .addInnerClasses(CustomCollectionTest.class)
@@ -88,13 +100,17 @@
                   // TODO(b/140233505): Allow devirtualization once fixed.
                   options.enableDevirtualization = false;
                 })
-            .enableCoreLibraryDesugaring(parameters.getApiLevel(), keepRuleConsumer)
+            .addOptionsModification(
+                options ->
+                    options.desugaredLibraryKeepRuleConsumer =
+                        ToolHelper.consumeString(keepRulesHolder::set))
+            .enableCoreLibraryDesugaring(parameters.getApiLevel())
             .compile()
             .inspect(inspector -> this.assertCustomCollectionCallsCorrect(inspector, true))
             .addDesugaredCoreLibraryRunClassPath(
                 this::buildDesugaredLibrary,
                 parameters.getApiLevel(),
-                keepRuleConsumer.get(),
+                keepRulesHolder.get(),
                 shrinkCoreLibrary)
             .run(parameters.getRuntime(), EXECUTOR)
             .assertSuccess();
diff --git a/src/test/java/com/android/tools/r8/desugar/corelib/JavaTimeTest.java b/src/test/java/com/android/tools/r8/desugar/corelib/JavaTimeTest.java
index 34ab55c..1c4f47a 100644
--- a/src/test/java/com/android/tools/r8/desugar/corelib/JavaTimeTest.java
+++ b/src/test/java/com/android/tools/r8/desugar/corelib/JavaTimeTest.java
@@ -9,7 +9,9 @@
 import static org.junit.Assert.assertTrue;
 
 import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.ToolHelper;
 import com.android.tools.r8.utils.BooleanUtils;
+import com.android.tools.r8.utils.Box;
 import com.android.tools.r8.utils.StringUtils;
 import com.android.tools.r8.utils.codeinspector.ClassSubject;
 import com.android.tools.r8.utils.codeinspector.CodeInspector;
@@ -54,17 +56,21 @@
 
   @Test
   public void testTimeD8() throws Exception {
-    KeepRuleConsumer keepRuleConsumer = createKeepRuleConsumer(parameters);
+    Box<String> keepRulesHolder = new Box<>("");
     testForD8()
         .addInnerClasses(JavaTimeTest.class)
         .setMinApi(parameters.getApiLevel())
-        .enableCoreLibraryDesugaring(parameters.getApiLevel(), keepRuleConsumer)
+        .enableCoreLibraryDesugaring(parameters.getApiLevel())
+        .addOptionsModification(
+            options ->
+                options.desugaredLibraryKeepRuleConsumer =
+                    ToolHelper.consumeString(keepRulesHolder::set))
         .compile()
         .inspect(this::checkRewrittenInvokes)
         .addDesugaredCoreLibraryRunClassPath(
             this::buildDesugaredLibrary,
             parameters.getApiLevel(),
-            keepRuleConsumer.get(),
+            keepRulesHolder.get(),
             shrinkCoreLibrary)
         .run(parameters.getRuntime(), TestClass.class)
         .assertSuccessWithOutput(expectedOutput);
@@ -72,18 +78,22 @@
 
   @Test
   public void testTimeR8() throws Exception {
-    KeepRuleConsumer keepRuleConsumer = createKeepRuleConsumer(parameters);
+    Box<String> keepRulesHolder = new Box<>("");
     testForR8(parameters.getBackend())
         .addInnerClasses(JavaTimeTest.class)
         .addKeepMainRule(TestClass.class)
         .setMinApi(parameters.getApiLevel())
-        .enableCoreLibraryDesugaring(parameters.getApiLevel(), keepRuleConsumer)
+        .enableCoreLibraryDesugaring(parameters.getApiLevel())
+        .addOptionsModification(
+            options ->
+                options.desugaredLibraryKeepRuleConsumer =
+                    ToolHelper.consumeString(keepRulesHolder::set))
         .compile()
         .inspect(this::checkRewrittenInvokes)
         .addDesugaredCoreLibraryRunClassPath(
             this::buildDesugaredLibrary,
             parameters.getApiLevel(),
-            keepRuleConsumer.get(),
+            keepRulesHolder.get(),
             shrinkCoreLibrary)
         .run(parameters.getRuntime(), TestClass.class)
         .assertSuccessWithOutput(expectedOutput);
diff --git a/src/test/java/com/android/tools/r8/desugar/corelib/ProgramRewritingTest.java b/src/test/java/com/android/tools/r8/desugar/corelib/ProgramRewritingTest.java
index f9778df..deb0bd4 100644
--- a/src/test/java/com/android/tools/r8/desugar/corelib/ProgramRewritingTest.java
+++ b/src/test/java/com/android/tools/r8/desugar/corelib/ProgramRewritingTest.java
@@ -19,6 +19,7 @@
 import com.android.tools.r8.ToolHelper;
 import com.android.tools.r8.ToolHelper.DexVm;
 import com.android.tools.r8.utils.BooleanUtils;
+import com.android.tools.r8.utils.Box;
 import com.android.tools.r8.utils.StringUtils;
 import com.android.tools.r8.utils.codeinspector.ClassSubject;
 import com.android.tools.r8.utils.codeinspector.CodeInspector;
@@ -56,30 +57,35 @@
   @Test
   public void testProgramD8() throws Exception {
     Assume.assumeTrue("No desugaring for high API levels", requiresCoreLibDesugaring(parameters));
+
     ArrayList<Path> coreLambdaStubs = new ArrayList<>();
     coreLambdaStubs.add(ToolHelper.getCoreLambdaStubs());
+    Box<String> keepRulesHolder = new Box<>("");
     for (Boolean coreLambdaStubsActive : BooleanUtils.values()) {
-      KeepRuleConsumer keepRuleConsumer = createKeepRuleConsumer(parameters);
       D8TestRunResult d8TestRunResult =
           testForD8()
               .addProgramFiles(Paths.get(ToolHelper.EXAMPLES_JAVA9_BUILD_DIR + "stream.jar"))
               .setMinApi(parameters.getApiLevel())
-              .enableCoreLibraryDesugaring(parameters.getApiLevel(), keepRuleConsumer)
+              .enableCoreLibraryDesugaring(parameters.getApiLevel())
+              .addOptionsModification(
+                  options ->
+                      options.desugaredLibraryKeepRuleConsumer =
+                          ToolHelper.consumeString(keepRulesHolder::set))
               .compile()
               .inspect(this::checkRewrittenInvokes)
               .addRunClasspathFiles(
                   coreLambdaStubsActive
                       ? buildDesugaredLibrary(
                           parameters.getApiLevel(),
-                          keepRuleConsumer.get(),
+                          keepRulesHolder.get(),
                           shrinkCoreLibrary,
                           coreLambdaStubs)
                       : buildDesugaredLibrary(
-                          parameters.getApiLevel(), keepRuleConsumer.get(), shrinkCoreLibrary))
+                          parameters.getApiLevel(), keepRulesHolder.get(), shrinkCoreLibrary))
               .run(parameters.getRuntime(), TEST_CLASS)
               .assertSuccess();
       assertLines2By2Correct(d8TestRunResult.getStdOut());
-      assertGeneratedKeepRulesAreCorrect(keepRuleConsumer.get());
+      assertGeneratedKeepRulesAreCorrect(keepRulesHolder.get());
       String stdErr = d8TestRunResult.getStdErr();
       if (parameters.getRuntime().asDex().getVm().isOlderThanOrEqual(DexVm.ART_4_4_4_HOST)) {
         // Flaky: There might be a missing method on lambda deserialization.
@@ -96,7 +102,7 @@
   public void testProgramR8() throws Exception {
     Assume.assumeTrue("No desugaring for high API levels", requiresCoreLibDesugaring(parameters));
     for (Boolean minifying : BooleanUtils.values()) {
-      KeepRuleConsumer keepRuleConsumer = createKeepRuleConsumer(parameters);
+      Box<String> keepRulesHolder = new Box<>("");
       R8TestRunResult r8TestRunResult =
           testForR8(parameters.getBackend())
               .minification(minifying)
@@ -108,16 +114,20 @@
                     // TODO(b/140233505): Allow devirtualization once fixed.
                     options.enableDevirtualization = false;
                   })
-              .enableCoreLibraryDesugaring(parameters.getApiLevel(), keepRuleConsumer)
+              .addOptionsModification(
+                  options ->
+                      options.desugaredLibraryKeepRuleConsumer =
+                          ToolHelper.consumeString(keepRulesHolder::set))
+              .enableCoreLibraryDesugaring(parameters.getApiLevel())
               .compile()
               .inspect(this::checkRewrittenInvokes)
               .addRunClasspathFiles(
                   buildDesugaredLibrary(
-                      parameters.getApiLevel(), keepRuleConsumer.get(), shrinkCoreLibrary))
+                      parameters.getApiLevel(), keepRulesHolder.get(), shrinkCoreLibrary))
               .run(parameters.getRuntime(), TEST_CLASS)
               .assertSuccess();
       assertLines2By2Correct(r8TestRunResult.getStdOut());
-      assertGeneratedKeepRulesAreCorrect(keepRuleConsumer.get());
+      assertGeneratedKeepRulesAreCorrect(keepRulesHolder.get());
       if (parameters.getRuntime().asDex().getVm().isOlderThanOrEqual(DexVm.ART_4_4_4_HOST)) {
         // Flaky: There might be a missing method on lambda deserialization.
         r8TestRunResult.assertStderrMatches(
diff --git a/src/test/java/com/android/tools/r8/internal/R8GMSCoreDeterministicTest.java b/src/test/java/com/android/tools/r8/internal/R8GMSCoreDeterministicTest.java
index 1d0a1ba..a16962d 100644
--- a/src/test/java/com/android/tools/r8/internal/R8GMSCoreDeterministicTest.java
+++ b/src/test/java/com/android/tools/r8/internal/R8GMSCoreDeterministicTest.java
@@ -46,7 +46,7 @@
               options.ignoreMissingClasses = true;
               // Store the generated Proguard map.
               options.proguardMapConsumer =
-                  (proguardMap, handler) -> result.proguardMap = proguardMap;
+                  ToolHelper.consumeString(proguardMap -> result.proguardMap = proguardMap);
             });
     return result;
   }
diff --git a/src/test/java/com/android/tools/r8/internal/R8GMSCoreLatestTreeShakeJarVerificationTest.java b/src/test/java/com/android/tools/r8/internal/R8GMSCoreLatestTreeShakeJarVerificationTest.java
index a8da699..0168988 100644
--- a/src/test/java/com/android/tools/r8/internal/R8GMSCoreLatestTreeShakeJarVerificationTest.java
+++ b/src/test/java/com/android/tools/r8/internal/R8GMSCoreLatestTreeShakeJarVerificationTest.java
@@ -32,7 +32,7 @@
             additionalProguardConfiguration,
             options -> {
               options.proguardMapConsumer =
-                  (proguardMap, handler) -> this.proguardMap1 = proguardMap;
+                  ToolHelper.consumeString(proguardMap -> this.proguardMap1 = proguardMap);
             });
     AndroidApp app2 =
         buildAndTreeShakeFromDeployJar(
@@ -43,7 +43,7 @@
             additionalProguardConfiguration,
             options -> {
               options.proguardMapConsumer =
-                  (proguardMap, handler) -> this.proguardMap2 = proguardMap;
+                  ToolHelper.consumeString(proguardMap -> this.proguardMap2 = proguardMap);
             });
 
     // Verify that the result of the two compilations was the same.
diff --git a/src/test/java/com/android/tools/r8/internal/R8GMSCoreV10DeployJarVerificationTest.java b/src/test/java/com/android/tools/r8/internal/R8GMSCoreV10DeployJarVerificationTest.java
index 5803355..be62787 100644
--- a/src/test/java/com/android/tools/r8/internal/R8GMSCoreV10DeployJarVerificationTest.java
+++ b/src/test/java/com/android/tools/r8/internal/R8GMSCoreV10DeployJarVerificationTest.java
@@ -7,12 +7,11 @@
 import static org.junit.Assert.assertEquals;
 
 import com.android.tools.r8.CompilationMode;
-import com.android.tools.r8.DexIndexedConsumer;
 import com.android.tools.r8.DexIndexedConsumer.ArchiveConsumer;
 import com.android.tools.r8.R8RunArtTestsTest.CompilerUnderTest;
+import com.android.tools.r8.ToolHelper;
 import com.android.tools.r8.utils.AndroidApp;
 import java.io.File;
-import java.util.function.Supplier;
 import org.junit.Test;
 
 public class R8GMSCoreV10DeployJarVerificationTest extends GMSCoreDeployJarVerificationTest {
@@ -34,8 +33,8 @@
             false,
             options ->
                 options.proguardMapConsumer =
-                    (proguardMap, handler) -> this.proguardMap1 = proguardMap,
-            ()-> new ArchiveConsumer(app1Zip.toPath(), true));
+                    ToolHelper.consumeString(proguardMap -> this.proguardMap1 = proguardMap),
+            () -> new ArchiveConsumer(app1Zip.toPath(), true));
     AndroidApp app2 =
         buildFromDeployJar(
             CompilerUnderTest.R8,
@@ -44,10 +43,8 @@
             false,
             options ->
                 options.proguardMapConsumer =
-                    (proguardMap, handler) -> this.proguardMap2 = proguardMap,
-            ()-> new ArchiveConsumer(app2Zip.toPath(), true));
-
-
+                    ToolHelper.consumeString(proguardMap -> this.proguardMap2 = proguardMap),
+            () -> new ArchiveConsumer(app2Zip.toPath(), true));
 
     // Verify that the result of the two compilations was the same.
     assertIdenticalApplications(app1, app2);
diff --git a/src/test/java/com/android/tools/r8/internal/R8GMSCoreV10TreeShakeJarVerificationTest.java b/src/test/java/com/android/tools/r8/internal/R8GMSCoreV10TreeShakeJarVerificationTest.java
index 4374d0e..00a751a 100644
--- a/src/test/java/com/android/tools/r8/internal/R8GMSCoreV10TreeShakeJarVerificationTest.java
+++ b/src/test/java/com/android/tools/r8/internal/R8GMSCoreV10TreeShakeJarVerificationTest.java
@@ -6,6 +6,7 @@
 import static org.junit.Assert.assertEquals;
 
 import com.android.tools.r8.CompilationMode;
+import com.android.tools.r8.ToolHelper;
 import com.android.tools.r8.utils.AndroidApp;
 import org.junit.Test;
 
@@ -26,7 +27,7 @@
             GMSCORE_V10_MAX_SIZE,
             options ->
                 options.proguardMapConsumer =
-                    (proguardMap, handler) -> this.proguardMap1 = proguardMap);
+                    ToolHelper.consumeString(proguardMap -> this.proguardMap1 = proguardMap));
     AndroidApp app2 =
         buildAndTreeShakeFromDeployJar(
             CompilationMode.RELEASE,
@@ -35,7 +36,7 @@
             GMSCORE_V10_MAX_SIZE,
             options ->
                 options.proguardMapConsumer =
-                    (proguardMap, handler) -> this.proguardMap2 = proguardMap);
+                    ToolHelper.consumeString(proguardMap -> this.proguardMap2 = proguardMap));
 
     // Verify that the result of the two compilations was the same.
     assertIdenticalApplications(app1, app2);
diff --git a/src/test/java/com/android/tools/r8/maindexlist/MainDexListOutputTest.java b/src/test/java/com/android/tools/r8/maindexlist/MainDexListOutputTest.java
index 33a8bf3..123744d 100644
--- a/src/test/java/com/android/tools/r8/maindexlist/MainDexListOutputTest.java
+++ b/src/test/java/com/android/tools/r8/maindexlist/MainDexListOutputTest.java
@@ -51,10 +51,17 @@
 
   private static class TestMainDexListConsumer implements StringConsumer {
     public boolean called = false;
+    public StringBuilder builder = new StringBuilder();
 
     @Override
     public void accept(String string, DiagnosticsHandler handler) {
       called = true;
+      builder.append(string);
+    }
+
+    @Override
+    public void finished(DiagnosticsHandler handler) {
+      String string = builder.toString();
       assertTrue(string.contains(testClassMainDexName));
       assertTrue(string.contains("Lambda"));
     }
diff --git a/src/test/java/com/android/tools/r8/maindexlist/MainDexTracingTest.java b/src/test/java/com/android/tools/r8/maindexlist/MainDexTracingTest.java
index c23e3fe..3806c05 100644
--- a/src/test/java/com/android/tools/r8/maindexlist/MainDexTracingTest.java
+++ b/src/test/java/com/android/tools/r8/maindexlist/MainDexTracingTest.java
@@ -311,7 +311,7 @@
             .addProgramFiles(inputJar)
             .addProgramFiles(Paths.get(EXAMPLE_BUILD_DIR, "multidexfakeframeworks" + JAR_EXTENSION))
             .addMainDexRulesFiles(mainDexRules)
-            .setMainDexListConsumer((string, handler) -> mainDexListOutput.set(string))
+            .setMainDexListConsumer(ToolHelper.consumeString(mainDexListOutput::set))
             .build();
     GenerateMainDexList.run(mdlCommand);
     List<String> mainDexGeneratorMainDexListFromConsumer =
@@ -332,7 +332,7 @@
         .setMinApi(minSdk)
         .noMinification()
         .noTreeShaking()
-        .setMainDexListConsumer((string, handler) -> r8MainDexListOutput.set(string))
+        .setMainDexListConsumer(ToolHelper.consumeString(r8MainDexListOutput::set))
         .compile()
         .writeToZip(out);
 
diff --git a/src/test/java/com/android/tools/r8/maindexlist/b72312389/B72312389.java b/src/test/java/com/android/tools/r8/maindexlist/b72312389/B72312389.java
index b1c93c1..1978867 100644
--- a/src/test/java/com/android/tools/r8/maindexlist/b72312389/B72312389.java
+++ b/src/test/java/com/android/tools/r8/maindexlist/b72312389/B72312389.java
@@ -84,7 +84,7 @@
             .addProguardConfiguration(ImmutableList.of("-dontobfuscate"), Origin.unknown())
             .addMainDexRules(keepInstrumentationTestCaseRules, Origin.unknown())
             .setProgramConsumer(DexIndexedConsumer.emptyConsumer())
-            .setMainDexListConsumer((string, handler) -> mainDexList.set(string))
+            .setMainDexListConsumer(ToolHelper.consumeString(mainDexList::set))
             .build();
     CodeInspector inspector = new CodeInspector(ToolHelper.runR8(command));
     assertTrue(inspector.clazz("instrumentationtest.InstrumentationTest").isPresent());
diff --git a/src/test/java/com/android/tools/r8/naming/AdaptResourceFileNamesTest.java b/src/test/java/com/android/tools/r8/naming/AdaptResourceFileNamesTest.java
index 3ae9fbf..188e58d 100644
--- a/src/test/java/com/android/tools/r8/naming/AdaptResourceFileNamesTest.java
+++ b/src/test/java/com/android/tools/r8/naming/AdaptResourceFileNamesTest.java
@@ -16,7 +16,6 @@
 import com.android.tools.r8.DataEntryResource;
 import com.android.tools.r8.DataResourceConsumer;
 import com.android.tools.r8.DataResourceProvider.Visitor;
-import com.android.tools.r8.DiagnosticsHandler;
 import com.android.tools.r8.R8Command;
 import com.android.tools.r8.StringConsumer;
 import com.android.tools.r8.ToolHelper;
@@ -115,7 +114,9 @@
   public void testEnabled() throws Exception {
     DataResourceConsumerForTesting dataResourceConsumer = new DataResourceConsumerForTesting();
     compileWithR8(
-        getProguardConfigWithNeverInline(true, null), dataResourceConsumer, this::checkR8Renamings);
+        getProguardConfigWithNeverInline(true, null),
+        dataResourceConsumer,
+        ToolHelper.consumeString(this::checkR8Renamings));
     // Check that the generated resources have the expected names.
     for (DataEntryResource dataResource : getOriginalDataResources()) {
       assertNotNull(
@@ -130,7 +131,7 @@
     compileWithR8(
         getProguardConfigWithNeverInline(true, "**.md"),
         dataResourceConsumer,
-        this::checkR8Renamings);
+        ToolHelper.consumeString(this::checkR8Renamings));
     // Check that the generated resources have the expected names.
     Map<String, String> expectedRenamings =
         ImmutableMap.of("adaptresourcefilenames/B.md", "adaptresourcefilenames/b.md");
@@ -160,7 +161,7 @@
     compileWithR8(
         getProguardConfigWithNeverInline(true, null),
         dataResourceConsumer,
-        this::checkR8Renamings,
+        ToolHelper.consumeString(this::checkR8Renamings),
         ImmutableList.<DataEntryResource>builder()
             .addAll(getOriginalDataResources())
             .add(
@@ -274,7 +275,7 @@
         });
   }
 
-  private void checkR8Renamings(String proguardMap, DiagnosticsHandler handler) {
+  private void checkR8Renamings(String proguardMap) {
     try {
       // Check that the renamings are as expected. These exact renamings are not important as
       // such, but the test expectations rely on them.
diff --git a/src/test/java/com/android/tools/r8/shaking/UsageInformationConsumerTest.java b/src/test/java/com/android/tools/r8/shaking/UsageInformationConsumerTest.java
index 341d696..4c9b057 100644
--- a/src/test/java/com/android/tools/r8/shaking/UsageInformationConsumerTest.java
+++ b/src/test/java/com/android/tools/r8/shaking/UsageInformationConsumerTest.java
@@ -5,11 +5,11 @@
 
 import static org.junit.Assert.assertEquals;
 
-import com.android.tools.r8.DiagnosticsHandler;
-import com.android.tools.r8.StringConsumer;
 import com.android.tools.r8.TestBase;
 import com.android.tools.r8.TestParameters;
 import com.android.tools.r8.TestParametersCollection;
+import com.android.tools.r8.ToolHelper;
+import com.android.tools.r8.utils.Box;
 import com.android.tools.r8.utils.StringUtils;
 import java.io.ByteArrayOutputStream;
 import java.io.PrintStream;
@@ -33,26 +33,18 @@
     this.parameters = parameters;
   }
 
-  public static class UsageConsumer implements StringConsumer {
-    String data = null;
-
-    @Override
-    public void accept(String string, DiagnosticsHandler handler) {
-      data = string;
-    }
-  };
-
   @Test
   public void testConsumer() throws Exception {
-    UsageConsumer usageConsumer = new UsageConsumer();
+    Box<String> usageData = new Box<>();
     testForR8(parameters.getBackend())
         .addProgramClasses(TestClass.class, UnusedClass.class)
         .addKeepClassAndMembersRules(TestClass.class)
-        .apply(b -> b.getBuilder().setProguardUsageConsumer(usageConsumer))
+        .apply(
+            b -> b.getBuilder().setProguardUsageConsumer(ToolHelper.consumeString(usageData::set)))
         .setMinApi(parameters.getApiLevel())
         .run(parameters.getRuntime(), TestClass.class)
         .assertSuccessWithOutput(EXPECTED);
-    assertEquals(StringUtils.lines(UnusedClass.class.getTypeName()), usageConsumer.data);
+    assertEquals(StringUtils.lines(UnusedClass.class.getTypeName()), usageData.get());
   }
 
   @Test