Add API tests for program-resource providers.

Change-Id: Id7958af556aa6cf3c9c6de28c73a73e1ebe1b909
diff --git a/src/test/apiUsageSample/com/android/tools/apiusagesample/D8ApiUsageSample.java b/src/test/apiUsageSample/com/android/tools/apiusagesample/D8ApiUsageSample.java
index e0a0b5b..363b80c 100644
--- a/src/test/apiUsageSample/com/android/tools/apiusagesample/D8ApiUsageSample.java
+++ b/src/test/apiUsageSample/com/android/tools/apiusagesample/D8ApiUsageSample.java
@@ -4,6 +4,7 @@
 package com.android.tools.apiusagesample;
 
 import com.android.tools.r8.ArchiveClassFileProvider;
+import com.android.tools.r8.ArchiveProgramResourceProvider;
 import com.android.tools.r8.CompilationFailedException;
 import com.android.tools.r8.CompilationMode;
 import com.android.tools.r8.D8;
@@ -11,9 +12,14 @@
 import com.android.tools.r8.DexFilePerClassFileConsumer;
 import com.android.tools.r8.DexIndexedConsumer;
 import com.android.tools.r8.DiagnosticsHandler;
+import com.android.tools.r8.ProgramResource;
+import com.android.tools.r8.ProgramResource.Kind;
+import com.android.tools.r8.ProgramResourceProvider;
+import com.android.tools.r8.ResourceException;
 import com.android.tools.r8.origin.ArchiveEntryOrigin;
 import com.android.tools.r8.origin.Origin;
 import com.android.tools.r8.origin.PathOrigin;
+import com.android.tools.r8.utils.StringDiagnostic;
 import java.io.ByteArrayOutputStream;
 import java.io.IOException;
 import java.io.InputStream;
@@ -22,6 +28,7 @@
 import java.nio.file.Paths;
 import java.util.ArrayList;
 import java.util.Collection;
+import java.util.Collections;
 import java.util.List;
 import java.util.Set;
 import java.util.zip.ZipEntry;
@@ -93,6 +100,7 @@
     useProgramFileBuilder(CompilationMode.DEBUG, minApiLevel, libraries, classpath, inputs);
     useProgramFileBuilder(CompilationMode.RELEASE, minApiLevel, libraries, classpath, inputs);
     useProgramDataBuilder(minApiLevel, libraries, classpath, inputs);
+    useProgramProvider(minApiLevel, libraries, classpath, inputs);
     useLibraryAndClasspathProvider(minApiLevel, libraries, classpath, inputs);
     useMainDexListFiles(minApiLevel, libraries, classpath, inputs, mainDexList);
     useMainDexClasses(minApiLevel, libraries, classpath, inputs, mainDexList);
@@ -111,7 +119,7 @@
           D8Command.builder(handler)
               .setMode(mode)
               .setMinApiLevel(minApiLevel)
-              .setProgramConsumer(DexIndexedConsumer.emptyConsumer())
+              .setProgramConsumer(new EnsureOutputConsumer())
               .addLibraryFiles(libraries)
               .addClasspathFiles(classpath)
               .addProgramFiles(inputs)
@@ -131,7 +139,7 @@
       D8Command.Builder builder =
           D8Command.builder(handler)
               .setMinApiLevel(minApiLevel)
-              .setProgramConsumer(DexIndexedConsumer.emptyConsumer())
+              .setProgramConsumer(new EnsureOutputConsumer())
               .addLibraryFiles(libraries)
               .addClasspathFiles(classpath);
       for (ClassFileContent classfile : readClassFiles(inputs)) {
@@ -145,6 +153,40 @@
     }
   }
 
+  // Check API support for compiling Java class-files from a program provider abstraction.
+  private static void useProgramProvider(
+      int minApiLevel,
+      Collection<Path> libraries,
+      Collection<Path> classpath,
+      Collection<Path> inputs) {
+    try {
+      D8Command.Builder builder =
+          D8Command.builder(handler)
+              .setMinApiLevel(minApiLevel)
+              .setProgramConsumer(new EnsureOutputConsumer())
+              .addLibraryFiles(libraries)
+              .addClasspathFiles(classpath);
+      for (Path input : inputs) {
+        if (isArchive(input)) {
+          builder.addProgramResourceProvider(
+              ArchiveProgramResourceProvider.fromArchive(
+                  input, ArchiveProgramResourceProvider::includeClassFileEntries));
+        } else {
+          builder.addProgramResourceProvider(
+              new ProgramResourceProvider() {
+                @Override
+                public Collection<ProgramResource> getProgramResources() throws ResourceException {
+                  return Collections.singleton(ProgramResource.fromFile(Kind.CF, input));
+                }
+              });
+        }
+      }
+      D8.run(builder.build());
+    } catch (CompilationFailedException e) {
+      throw new RuntimeException("Unexpected compilation exceptions", e);
+    }
+  }
+
   private static void useLibraryAndClasspathProvider(
       int minApiLevel,
       Collection<Path> libraries,
@@ -154,7 +196,7 @@
       D8Command.Builder builder =
           D8Command.builder(handler)
               .setMinApiLevel(minApiLevel)
-              .setProgramConsumer(DexIndexedConsumer.emptyConsumer())
+              .setProgramConsumer(new EnsureOutputConsumer())
               .addProgramFiles(inputs);
       for (Path library : libraries) {
         builder.addLibraryResourceProvider(new ArchiveClassFileProvider(library));
@@ -180,7 +222,7 @@
       D8.run(
           D8Command.builder(handler)
               .setMinApiLevel(minApiLevel)
-              .setProgramConsumer(DexIndexedConsumer.emptyConsumer())
+              .setProgramConsumer(new EnsureOutputConsumer())
               .addLibraryFiles(libraries)
               .addClasspathFiles(classpath)
               .addProgramFiles(inputs)
@@ -211,7 +253,7 @@
       D8.run(
           D8Command.builder(handler)
               .setMinApiLevel(minApiLevel)
-              .setProgramConsumer(DexIndexedConsumer.emptyConsumer())
+              .setProgramConsumer(new EnsureOutputConsumer())
               .addLibraryFiles(libraries)
               .addClasspathFiles(classpath)
               .addProgramFiles(inputs)
@@ -284,7 +326,7 @@
     D8Command.Builder builder =
         D8Command.builder(handler)
             .setMinApiLevel(minApiLevel)
-            .setProgramConsumer(DexIndexedConsumer.emptyConsumer());
+            .setProgramConsumer(new EnsureOutputConsumer());
     for (byte[] intermediate : intermediates) {
       builder.addDexProgramData(intermediate, Origin.unknown());
     }
@@ -387,4 +429,21 @@
     @Override
     public void finished(DiagnosticsHandler handler) {}
   }
+
+  private static class EnsureOutputConsumer implements DexIndexedConsumer {
+    boolean hasOutput = false;
+
+    @Override
+    public synchronized void accept(
+        int fileIndex, byte[] data, Set<String> descriptors, DiagnosticsHandler handler) {
+      hasOutput = true;
+    }
+
+    @Override
+    public void finished(DiagnosticsHandler handler) {
+      if (!hasOutput) {
+        handler.error(new StringDiagnostic("Expected to produce output but had none"));
+      }
+    }
+  }
 }
diff --git a/src/test/apiUsageSample/com/android/tools/apiusagesample/R8ApiUsageSample.java b/src/test/apiUsageSample/com/android/tools/apiusagesample/R8ApiUsageSample.java
index be7e207..d069d05 100644
--- a/src/test/apiUsageSample/com/android/tools/apiusagesample/R8ApiUsageSample.java
+++ b/src/test/apiUsageSample/com/android/tools/apiusagesample/R8ApiUsageSample.java
@@ -4,12 +4,17 @@
 package com.android.tools.apiusagesample;
 
 import com.android.tools.r8.ArchiveClassFileProvider;
+import com.android.tools.r8.ArchiveProgramResourceProvider;
 import com.android.tools.r8.CompilationFailedException;
 import com.android.tools.r8.CompilationMode;
 import com.android.tools.r8.DexIndexedConsumer;
 import com.android.tools.r8.DiagnosticsHandler;
+import com.android.tools.r8.ProgramResource;
+import com.android.tools.r8.ProgramResource.Kind;
+import com.android.tools.r8.ProgramResourceProvider;
 import com.android.tools.r8.R8;
 import com.android.tools.r8.R8Command;
+import com.android.tools.r8.ResourceException;
 import com.android.tools.r8.origin.ArchiveEntryOrigin;
 import com.android.tools.r8.origin.Origin;
 import com.android.tools.r8.origin.PathOrigin;
@@ -22,6 +27,7 @@
 import java.nio.file.Paths;
 import java.util.ArrayList;
 import java.util.Collection;
+import java.util.Collections;
 import java.util.List;
 import java.util.Set;
 import java.util.zip.ZipEntry;
@@ -98,6 +104,7 @@
     useProgramFileBuilder(CompilationMode.DEBUG, minApiLevel, libraries, inputs);
     useProgramFileBuilder(CompilationMode.RELEASE, minApiLevel, libraries, inputs);
     useProgramDataBuilder(minApiLevel, libraries, inputs);
+    useProgramProvider(minApiLevel, libraries, inputs);
     useLibraryProvider(minApiLevel, libraries, inputs);
     useMainDexListFiles(minApiLevel, libraries, inputs, mainDexList);
     useMainDexClasses(minApiLevel, libraries, inputs, mainDexList);
@@ -115,7 +122,7 @@
           R8Command.builder(handler)
               .setMode(mode)
               .setMinApiLevel(minApiLevel)
-              .setProgramConsumer(DexIndexedConsumer.emptyConsumer())
+              .setProgramConsumer(new EnsureOutputConsumer())
               .addLibraryFiles(libraries)
               .addProgramFiles(inputs)
               .build());
@@ -131,7 +138,7 @@
       R8Command.Builder builder =
           R8Command.builder(handler)
               .setMinApiLevel(minApiLevel)
-              .setProgramConsumer(DexIndexedConsumer.emptyConsumer())
+              .setProgramConsumer(new EnsureOutputConsumer())
               .addLibraryFiles(libraries);
       for (ClassFileContent classfile : readClassFiles(inputs)) {
         builder.addClassProgramData(classfile.data, classfile.origin);
@@ -144,13 +151,43 @@
     }
   }
 
+  // Check API support for compiling Java class-files from a program provider abstraction.
+  private static void useProgramProvider(
+      int minApiLevel, Collection<Path> libraries, Collection<Path> inputs) {
+    try {
+      R8Command.Builder builder =
+          R8Command.builder(handler)
+              .setMinApiLevel(minApiLevel)
+              .setProgramConsumer(new EnsureOutputConsumer())
+              .addLibraryFiles(libraries);
+      for (Path input : inputs) {
+        if (isArchive(input)) {
+          builder.addProgramResourceProvider(
+              ArchiveProgramResourceProvider.fromArchive(
+                  input, ArchiveProgramResourceProvider::includeClassFileEntries));
+        } else {
+          builder.addProgramResourceProvider(
+              new ProgramResourceProvider() {
+                @Override
+                public Collection<ProgramResource> getProgramResources() throws ResourceException {
+                  return Collections.singleton(ProgramResource.fromFile(Kind.CF, input));
+                }
+              });
+        }
+      }
+      R8.run(builder.build());
+    } catch (CompilationFailedException e) {
+      throw new RuntimeException("Unexpected compilation exceptions", e);
+    }
+  }
+
   private static void useLibraryProvider(
       int minApiLevel, Collection<Path> libraries, Collection<Path> inputs) {
     try {
       R8Command.Builder builder =
           R8Command.builder(handler)
               .setMinApiLevel(minApiLevel)
-              .setProgramConsumer(DexIndexedConsumer.emptyConsumer())
+              .setProgramConsumer(new EnsureOutputConsumer())
               .addProgramFiles(inputs);
       for (Path library : libraries) {
         builder.addLibraryResourceProvider(new ArchiveClassFileProvider(library));
@@ -172,7 +209,7 @@
       R8.run(
           R8Command.builder(handler)
               .setMinApiLevel(minApiLevel)
-              .setProgramConsumer(DexIndexedConsumer.emptyConsumer())
+              .setProgramConsumer(new EnsureOutputConsumer())
               .addLibraryFiles(libraries)
               .addProgramFiles(inputs)
               .addMainDexListFiles(mainDexList)
@@ -201,7 +238,7 @@
       R8.run(
           R8Command.builder(handler)
               .setMinApiLevel(minApiLevel)
-              .setProgramConsumer(DexIndexedConsumer.emptyConsumer())
+              .setProgramConsumer(new EnsureOutputConsumer())
               .addLibraryFiles(libraries)
               .addProgramFiles(inputs)
               .addMainDexClasses(mainDexClasses)
@@ -222,7 +259,7 @@
       R8.run(
           R8Command.builder(handler)
               .setMinApiLevel(minApiLevel)
-              .setProgramConsumer(DexIndexedConsumer.emptyConsumer())
+              .setProgramConsumer(new EnsureOutputConsumer())
               .addLibraryFiles(libraries)
               .addProgramFiles(inputs)
               .addMainDexRulesFiles(mainDexRules)
@@ -241,7 +278,7 @@
       R8Command.Builder builder =
           R8Command.builder(handler)
               .setMinApiLevel(minApiLevel)
-              .setProgramConsumer(DexIndexedConsumer.emptyConsumer())
+              .setProgramConsumer(new EnsureOutputConsumer())
               .addLibraryFiles(libraries)
               .addProgramFiles(inputs);
       for (Path mainDexRulesFile : mainDexRulesFiles) {
diff --git a/tests/d8_api_usage_sample.jar b/tests/d8_api_usage_sample.jar
index 5913594..3f78a93 100644
--- a/tests/d8_api_usage_sample.jar
+++ b/tests/d8_api_usage_sample.jar
Binary files differ
diff --git a/tests/r8_api_usage_sample.jar b/tests/r8_api_usage_sample.jar
index 55c5e83..e0456f6 100644
--- a/tests/r8_api_usage_sample.jar
+++ b/tests/r8_api_usage_sample.jar
Binary files differ