Add a test module for JDK-22

Change-Id: I6f95d08c47eead70776edc23d49738de93f27bc6
diff --git a/d8_r8/test/build.gradle.kts b/d8_r8/test/build.gradle.kts
index 52b3748..1e7ac2b 100644
--- a/d8_r8/test/build.gradle.kts
+++ b/d8_r8/test/build.gradle.kts
@@ -52,6 +52,7 @@
     dependsOn(gradle.includedBuild("tests_java_11").task(":clean"))
     dependsOn(gradle.includedBuild("tests_java_17").task(":clean"))
     dependsOn(gradle.includedBuild("tests_java_21").task(":clean"))
+    dependsOn(gradle.includedBuild("tests_java_22").task(":clean"))
   }
 
   val packageTests by registering(Jar::class) {
diff --git a/d8_r8/test/settings.gradle.kts b/d8_r8/test/settings.gradle.kts
index 52121d0..2ff9d56 100644
--- a/d8_r8/test/settings.gradle.kts
+++ b/d8_r8/test/settings.gradle.kts
@@ -36,3 +36,4 @@
 includeBuild(root.resolve("test_modules").resolve("tests_java_11"))
 includeBuild(root.resolve("test_modules").resolve("tests_java_17"))
 includeBuild(root.resolve("test_modules").resolve("tests_java_21"))
+includeBuild(root.resolve("test_modules").resolve("tests_java_22"))
diff --git a/d8_r8/test_modules/tests_java_22/build.gradle.kts b/d8_r8/test_modules/tests_java_22/build.gradle.kts
new file mode 100644
index 0000000..546d795
--- /dev/null
+++ b/d8_r8/test_modules/tests_java_22/build.gradle.kts
@@ -0,0 +1,52 @@
+// 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.
+
+import org.gradle.api.JavaVersion
+
+plugins {
+  `kotlin-dsl`
+  `java-library`
+  id("dependencies-plugin")
+}
+
+val root = getRoot()
+
+java {
+  sourceSets.test.configure {
+    java.srcDir(root.resolveAll("src", "test", "java22"))
+  }
+  sourceCompatibility = JavaVersion.VERSION_22
+  targetCompatibility = JavaVersion.VERSION_22
+}
+
+val testbaseJavaCompileTask = projectTask("testbase", "compileJava")
+val testbaseDepsJarTask = projectTask("testbase", "depsJar")
+val mainCompileTask = projectTask("main", "compileJava")
+
+dependencies {
+  implementation(files(testbaseDepsJarTask.outputs.files.getSingleFile()))
+  implementation(testbaseJavaCompileTask.outputs.files)
+  implementation(mainCompileTask.outputs.files)
+}
+
+tasks {
+  withType<JavaCompile> {
+    dependsOn(gradle.includedBuild("shared").task(":downloadDeps"))
+    options.setFork(true)
+    options.forkOptions.memoryMaximumSize = "3g"
+    options.forkOptions.executable = getCompilerPath(Jdk.JDK_22)
+  }
+
+  withType<Test> {
+    notCompatibleWithConfigurationCache(
+      "Failure storing the configuration cache: cannot serialize object of type 'org.gradle.api.internal.project.DefaultProject', a subtype of 'org.gradle.api.Project', as these are not supported with the configuration cache")
+    TestingState.setUpTestingState(this)
+    javaLauncher = getJavaLauncher(Jdk.JDK_22)
+    systemProperty("TEST_DATA_LOCATION",
+                   layout.buildDirectory.dir("classes/java/test").get().toString())
+    systemProperty("TESTBASE_DATA_LOCATION",
+                   testbaseJavaCompileTask.outputs.files.getAsPath().split(File.pathSeparator)[0])
+  }
+}
+
diff --git a/d8_r8/test_modules/tests_java_22/settings.gradle.kts b/d8_r8/test_modules/tests_java_22/settings.gradle.kts
new file mode 100644
index 0000000..057fa4a
--- /dev/null
+++ b/d8_r8/test_modules/tests_java_22/settings.gradle.kts
@@ -0,0 +1,29 @@
+// 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.
+
+pluginManagement {
+  repositories {
+    maven {
+      url = uri("file:../../../third_party/dependencies_plugin")
+    }
+    maven {
+      url = uri("file:../../../third_party/dependencies")
+    }
+  }
+}
+
+dependencyResolutionManagement {
+  repositories {
+    maven {
+      url = uri("file:../../../third_party/dependencies")
+    }
+  }
+}
+
+rootProject.name = "tests_java_22"
+val root = rootProject.projectDir.parentFile.parentFile
+
+includeBuild(root.resolve("shared"))
+includeBuild(root.resolve("main"))
+includeBuild(root.resolve("test_modules").resolve("testbase"))
\ No newline at end of file
diff --git a/src/test/java22/com/android/tools/r8/java22/Java22ValidationTest.java b/src/test/java22/com/android/tools/r8/java22/Java22ValidationTest.java
new file mode 100644
index 0000000..5343ad9
--- /dev/null
+++ b/src/test/java22/com/android/tools/r8/java22/Java22ValidationTest.java
@@ -0,0 +1,102 @@
+// 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.java22;
+
+import static com.android.tools.r8.utils.InternalOptions.ASM_VERSION;
+import static junit.framework.TestCase.assertEquals;
+
+import com.android.tools.r8.TestBase;
+import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.TestParametersCollection;
+import com.android.tools.r8.TestRuntime.CfVm;
+import com.android.tools.r8.ToolHelper;
+import com.android.tools.r8.cf.CfVersion;
+import com.android.tools.r8.utils.StringUtils;
+import java.io.IOException;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+import org.objectweb.asm.Attribute;
+import org.objectweb.asm.ClassReader;
+import org.objectweb.asm.ClassVisitor;
+
+// Test to validate that the tests_java_22 module is built with JDK-22.
+@RunWith(Parameterized.class)
+public class Java22ValidationTest extends TestBase {
+
+  static final String EXPECTED = StringUtils.lines("Hello, world");
+
+  private final TestParameters parameters;
+
+  @Parameterized.Parameters(name = "{0}")
+  public static TestParametersCollection data() {
+    return getTestParameters().withCfRuntimes().build();
+  }
+
+  public Java22ValidationTest(TestParameters parameters) {
+    this.parameters = parameters;
+  }
+
+  protected static CfVersion extractClassFileVersion(Path classFile) throws IOException {
+    class ClassFileVersionExtractor extends ClassVisitor {
+      private int version;
+
+      private ClassFileVersionExtractor() {
+        super(ASM_VERSION);
+      }
+
+      @Override
+      public void visit(
+          int version,
+          int access,
+          String name,
+          String signature,
+          String superName,
+          String[] interfaces) {
+        this.version = version;
+      }
+
+      @Override
+      public void visitAttribute(Attribute attribute) {}
+
+      CfVersion getClassFileVersion() {
+        return CfVersion.fromRaw(version);
+      }
+    }
+
+    ClassReader reader = new ClassReader(Files.newInputStream(classFile));
+    ClassFileVersionExtractor extractor = new ClassFileVersionExtractor();
+    reader.accept(
+        extractor, ClassReader.SKIP_CODE | ClassReader.SKIP_DEBUG | ClassReader.SKIP_FRAMES);
+    return extractor.getClassFileVersion();
+  }
+
+  @Test
+  public void testTestClassClassFileVersion() throws Exception {
+    assertEquals(
+        CfVersion.V22,
+        extractClassFileVersion(ToolHelper.getClassFileForTestClass(TestClass.class)));
+  }
+
+  @Test
+  public void testRunning() throws Exception {
+    testForJvm(parameters)
+        .addInnerClasses(getClass())
+        .run(parameters.getRuntime(), TestClass.class)
+        .applyIf(
+            parameters.getCfRuntime().isOlderThan(CfVm.JDK22),
+            r -> r.assertFailureWithErrorThatThrows(UnsupportedClassVersionError.class),
+            r -> r.assertSuccessWithOutput(EXPECTED));
+  }
+
+  static class TestClass {
+
+    public static void main(String[] args) {
+      System.out.println("Hello, world");
+    }
+  }
+}