Add explicit testing of resource keep rules

This is already traced in R8ResourceShrinker state

Bug: b/326564914
Change-Id: I701adce0b3891bc84b307f7323856654dbf22adb
diff --git a/src/test/java/com/android/tools/r8/androidresources/KeepXmlFilesTest.java b/src/test/java/com/android/tools/r8/androidresources/KeepXmlFilesTest.java
new file mode 100644
index 0000000..5d19a6a
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/androidresources/KeepXmlFilesTest.java
@@ -0,0 +1,92 @@
+// 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.TestBase;
+import com.android.tools.r8.TestParameters;
+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 KeepXmlFilesTest extends TestBase {
+
+  @Parameter(0)
+  public TestParameters parameters;
+
+  @Parameter(1)
+  public boolean optimized;
+
+  @Parameters(name = "{0}, optimized: {1}")
+  public static List<Object[]> data() {
+    return buildParameters(
+        getTestParameters().withDefaultDexRuntime().withAllApiLevels().build(),
+        BooleanUtils.values());
+  }
+
+  public static AndroidTestResource getTestResources(TemporaryFolder temp) throws Exception {
+    return new AndroidTestResourceBuilder()
+        .withSimpleManifestAndAppNameString()
+        .addKeepXmlFor("@string/bar", "@drawable/foobar")
+        .addRClassInitializeWithDefaultValues(R.string.class, R.drawable.class)
+        .build(temp);
+  }
+
+  @Test
+  public void testR8() throws Exception {
+    testForR8(parameters.getBackend())
+        .setMinApi(parameters)
+        .addProgramClasses(FooBar.class)
+        .addAndroidResources(getTestResources(temp))
+        .addKeepMainRule(FooBar.class)
+        .applyIf(optimized, b -> b.enableOptimizedShrinking())
+        .compile()
+        .inspectShrunkenResources(
+            resourceTableInspector -> {
+              // Referenced from keep.xml
+              resourceTableInspector.assertContainsResourceWithName("string", "bar");
+              // Referenced from code
+              resourceTableInspector.assertContainsResourceWithName("string", "foo");
+              // Referenced from keep.xml
+              resourceTableInspector.assertContainsResourceWithName("drawable", "foobar");
+              resourceTableInspector.assertDoesNotContainResourceWithName(
+                  "string", "unused_string");
+              resourceTableInspector.assertDoesNotContainResourceWithName(
+                  "drawable", "unused_drawable");
+            })
+        .run(parameters.getRuntime(), FooBar.class)
+        .assertSuccess();
+  }
+
+  public static class FooBar {
+
+    public static void main(String[] args) {
+      if (System.currentTimeMillis() == 0) {
+        System.out.println(R.string.foo);
+      }
+    }
+  }
+
+  public static class R {
+
+    public static class string {
+
+      public static int foo;
+      public static int bar;
+      public static int unused_string;
+    }
+
+    public static class drawable {
+      public static int foobar;
+      public static int unused_drawable;
+    }
+  }
+}
diff --git a/src/test/testbase/java/com/android/tools/r8/androidresources/AndroidResourceTestingUtils.java b/src/test/testbase/java/com/android/tools/r8/androidresources/AndroidResourceTestingUtils.java
index df7461e..c74d4d5 100644
--- a/src/test/testbase/java/com/android/tools/r8/androidresources/AndroidResourceTestingUtils.java
+++ b/src/test/testbase/java/com/android/tools/r8/androidresources/AndroidResourceTestingUtils.java
@@ -127,6 +127,12 @@
           + "    <item android:id=\"@+id/%s\"/>\n"
           + "</menu>";
 
+  public static String KEEP_XML =
+      "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n"
+          + "<resources xmlns:tools=\"http://schemas.android.com/tools\"\n"
+          + "    tools:keep=\"%s\"\n"
+          + "/>";
+
   public static class AndroidTestRClass {
     // The original aapt2 generated R.java class
     private final Path javaFilePath;
@@ -270,6 +276,7 @@
     private final Map<String, Integer> styleables = new TreeMap<>();
     private final Map<String, byte[]> drawables = new TreeMap<>();
     private final Map<String, String> xmlFiles = new TreeMap<>();
+    private final Map<String, String> rawXmlFiles = new TreeMap<>();
     private final List<Class<?>> classesToRemap = new ArrayList<>();
     private int packageId = 0x7f;
     private String packageName;
@@ -340,6 +347,17 @@
       return this;
     }
 
+    public AndroidTestResourceBuilder addKeepXmlFor(String... resourceReferences) {
+      addRawXml("keep.xml", String.format(KEEP_XML, String.join(",", resourceReferences)));
+      return this;
+    }
+
+    public AndroidTestResourceBuilder addRawXml(String name, String content) {
+      assert !rawXmlFiles.containsKey(name);
+      rawXmlFiles.put(name, content);
+      return this;
+    }
+
     AndroidTestResourceBuilder addExtraLanguageString(String name) {
       stringValuesWithExtraLanguage.add(name);
       return this;
@@ -400,6 +418,13 @@
         }
       }
 
+      if (rawXmlFiles.size() > 0) {
+        File rawXmlFolder = temp.newFolder("res", "raw");
+        for (Entry<String, String> entry : rawXmlFiles.entrySet()) {
+          FileUtils.writeTextFile(rawXmlFolder.toPath().resolve(entry.getKey()), entry.getValue());
+        }
+      }
+
       Path output = temp.newFile("resources.zip").toPath();
       Path rClassOutputDir = temp.newFolder("aapt_R_class").toPath();
       String aaptPackageName =