Add testing of using features for multiapk

This includes testing that we run with overlapping resource files, as long as they are the same

Change-Id: I1c2eda0a6f39e16d03aab84a989eb380d820036d
diff --git a/src/test/java/com/android/tools/r8/androidresources/ResourceShrinkingMultiApkAsFeaturesplits.java b/src/test/java/com/android/tools/r8/androidresources/ResourceShrinkingMultiApkAsFeaturesplits.java
new file mode 100644
index 0000000..97534c6
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/androidresources/ResourceShrinkingMultiApkAsFeaturesplits.java
@@ -0,0 +1,121 @@
+// Copyright (c) 2024, the R8 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.
+package com.android.tools.r8.androidresources;
+
+import com.android.tools.r8.R8FullTestBuilder;
+import com.android.tools.r8.TestBase;
+import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.ToolHelper;
+import com.android.tools.r8.androidresources.AndroidResourceTestingUtils.AndroidTestResource;
+import com.android.tools.r8.androidresources.AndroidResourceTestingUtils.AndroidTestResourceBuilder;
+import com.android.tools.r8.utils.BooleanUtils;
+import java.util.List;
+import org.junit.Test;
+import org.junit.rules.TemporaryFolder;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+import org.junit.runners.Parameterized.Parameter;
+import org.junit.runners.Parameterized.Parameters;
+
+@RunWith(Parameterized.class)
+public class ResourceShrinkingMultiApkAsFeaturesplits extends TestBase {
+
+  @Parameter(0)
+  public TestParameters parameters;
+
+  @Parameter(1)
+  public boolean optimized;
+
+  public static String VIEW =
+      "<view xmlns:android=\"http://schemas.android.com/apk/res/android\"/>\n";
+
+  @Parameters(name = "{0}, optimized: {1}")
+  public static List<Object[]> data() {
+    return buildParameters(
+        getTestParameters().withDefaultDexRuntime().withAllApiLevels().build(),
+        BooleanUtils.values());
+  }
+
+  public static AndroidTestResource getTestResources(TemporaryFolder temp, boolean base, String xml)
+      throws Exception {
+    AndroidTestResourceBuilder androidTestResourceBuilder =
+        new AndroidTestResourceBuilder()
+            .withSimpleManifestAndAppNameString()
+            .addRClassInitializeWithDefaultValues(base, R.string.class, R.xml.class)
+            .addXml("both_used.xml", VIEW)
+            .addXml("both_unused.xml", VIEW);
+    if (base) {
+      androidTestResourceBuilder.addXml("only_in_base.xml", VIEW);
+    }
+    return androidTestResourceBuilder.build(temp);
+  }
+
+  @Test
+  public void test() throws Exception {
+    TemporaryFolder featureSplitTemp = ToolHelper.getTemporaryFolderForTest();
+    featureSplitTemp.create();
+    String featureSplitName = "featuresplit";
+    testForR8(parameters.getBackend())
+        .setMinApi(parameters)
+        .addProgramClasses(Base.class)
+        .addAndroidResources(getTestResources(temp, true, VIEW))
+        .addFeatureSplitAndroidResources(
+            // For the feature, we don't add the R class (we already have it in the base)
+            // and to test we add one less xml file.
+            getTestResources(featureSplitTemp, false, VIEW), featureSplitName)
+        .applyIf(optimized, R8FullTestBuilder::enableOptimizedShrinking)
+        .addKeepMainRule(Base.class)
+        .compile()
+        .inspectShrunkenResources(
+            resourceTableInspector -> {
+              resourceTableInspector.assertContainsResourceWithName("string", "used");
+              resourceTableInspector.assertDoesNotContainResourceWithName("string", "unused");
+              resourceTableInspector.assertContainsResourceWithName("xml", "both_used");
+              resourceTableInspector.assertDoesNotContainResourceWithName("xml", "both_unused");
+              resourceTableInspector.assertContainsResourceWithName("xml", "only_in_base");
+            })
+        .inspectShrunkenResourcesForFeature(
+            resourceTableInspector -> {
+              resourceTableInspector.assertContainsResourceWithName("string", "used");
+              resourceTableInspector.assertDoesNotContainResourceWithName("string", "unused");
+              resourceTableInspector.assertContainsResourceWithName("xml", "both_used");
+              resourceTableInspector.assertDoesNotContainResourceWithName("xml", "both_unused");
+              resourceTableInspector.assertDoesNotContainResourceWithName("xml", "only_in_base");
+            },
+            featureSplitName)
+        .assertResourceFile("res/xml/both_used.xml", true)
+        .assertResourceFile("res/xml/only_in_base.xml", true)
+        .assertResourceFile("res/xml/both_unused.xml", false)
+        .assertFeatureResourceFile("res/xml/both_used.xml", true, featureSplitName)
+        .assertFeatureResourceFile("res/xml/both_unused.xml", false, featureSplitName)
+        .assertFeatureResourceFile("res/xml/only_in_base.xml", false, featureSplitName)
+        .run(parameters.getRuntime(), Base.class)
+        .assertSuccess();
+  }
+
+  public static class Base {
+
+    public static void main(String[] args) {
+      if (System.currentTimeMillis() == 0) {
+        System.out.println(R.string.used);
+        System.out.println(R.xml.both_used);
+        System.out.println(R.xml.only_in_base);
+      }
+    }
+  }
+
+  public static class R {
+
+    public static class string {
+      public static int used;
+      public static int unused;
+    }
+
+    public static class xml {
+      public static int both_used;
+      public static int both_unused;
+      public static int only_in_base;
+    }
+  }
+}
diff --git a/src/test/testbase/java/com/android/tools/r8/R8TestCompileResult.java b/src/test/testbase/java/com/android/tools/r8/R8TestCompileResult.java
index 942cc92..172fb2b 100644
--- a/src/test/testbase/java/com/android/tools/r8/R8TestCompileResult.java
+++ b/src/test/testbase/java/com/android/tools/r8/R8TestCompileResult.java
@@ -195,6 +195,20 @@
     return self();
   }
 
+  public <E extends Throwable> R8TestCompileResult assertResourceFile(String name, boolean present)
+      throws IOException {
+    assertNotNull(resourceShrinkerOutput);
+    assertEquals(ZipUtils.containsEntry(resourceShrinkerOutput, name), present);
+    return self();
+  }
+
+  public <E extends Throwable> R8TestCompileResult assertFeatureResourceFile(
+      String name, boolean present, String featureName) throws IOException {
+    Path path = resourceShrinkerOutputForFeatures.get(featureName);
+    assertEquals(ZipUtils.containsEntry(path, name), present);
+    return self();
+  }
+
   public String dumpResources() throws IOException {
     ProcessResult processResult = AndroidResourceTestingUtils.dumpWithAapt2(resourceShrinkerOutput);
     assert processResult.exitCode == 0;