diff --git a/build.gradle.kts b/build.gradle.kts index 84ab27cc..4b839418 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -1,4 +1,3 @@ -import org.gradle.api.tasks.testing.logging.TestLogEvent import xyz.wagyourtail.gradle.shadow.ShadowJar plugins { @@ -10,6 +9,8 @@ plugins { application id("io.github.sgtsilvio.gradle.metadata") version "0.5.0" id("com.gradleup.nmcp") version "0.0.7" + + id ("com.dorongold.task-tree") version "4.0.0" } allprojects { @@ -44,14 +45,17 @@ allprojects { } java { - if (project.name != "downgradetest") { + if (!project.path.startsWith(":testing")) { withSourcesJar() withJavadocJar() } } - version = - if (project.hasProperty("version_snapshot")) "${project.properties["version"]}-SNAPSHOT" else project.properties["version"] as String + version = if (project.hasProperty("version_snapshot")) { + "${project.properties["version"]}-SNAPSHOT" + } else { + project.properties["version"] as String + } group = project.properties["maven_group"] as String base { @@ -119,13 +123,6 @@ sourceSets { } dependencies { - testImplementation("org.junit.jupiter:junit-jupiter:5.10.2") - testRuntimeOnly("org.junit.platform:junit-platform-launcher") - - testImplementation("com.google.code.gson:gson:2.10") - testImplementation("org.apache.commons:commons-compress:1.26.1") - testImplementation("io.github.java-diff-utils:java-diff-utils:4.12") - val api by configurations.getting api("org.ow2.asm:asm:${project.properties["asm_version"]}") @@ -177,49 +174,6 @@ tasks.javadoc { source = sourceSets.main.get().allJava + sourceSets["shared"].allJava } -val testVersion = project.properties["testVersion"] as String -val testTargetVersion = project.properties["testTargetVersion"] as String - -tasks.compileTestJava { - options.encoding = "UTF-8" - - javaCompiler = javaToolchains.compilerFor { - languageVersion.set(JavaLanguageVersion.of(testVersion.toInt())) - } -} - -tasks.test { - useJUnitPlatform() - - dependsOn( - project(":downgradetest").tasks.build, - project(":java-api").tasks.named("testJar") - ) - javaLauncher = javaToolchains.launcherFor { - languageVersion.set(JavaLanguageVersion.of(testVersion.toInt())) - } - - val versions = listOf(testVersion, testTargetVersion, "7").associateWith { - javaToolchains.launcherFor { - languageVersion.set(JavaLanguageVersion.of(it.toInt())) - }.get().executablePath.toString() - } - - jvmArgs( - "-Djvmdg.test.version=$version", - "-Djvmdg.test.originalVersion=$testVersion", - "-Djvmdg.test.javaVersion=${versions.keys.joinToString(File.pathSeparator)}", - "-Djvmdg.test.launcher=${versions.values.joinToString(File.pathSeparator)}", - "-Djvmdg.test.downgradeClasspath=${shared.compileClasspath.joinToString(File.pathSeparator) { it.absolutePath }}", - ) - - testLogging { - events.add(TestLogEvent.PASSED) - events.add(TestLogEvent.SKIPPED) - events.add(TestLogEvent.FAILED) - } -} - project.evaluationDependsOnChildren() val shadowJar by tasks.registering(ShadowJar::class) { diff --git a/settings.gradle.kts b/settings.gradle.kts index 4c42eb33..e6e47fab 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -2,10 +2,13 @@ plugins { id("org.gradle.toolchains.foojay-resolver-convention") version ("0.7.0") } -include("downgradetest") include("gradle-plugin") include("java-api") include("site") +include("testing") +include("testing:downgrade") +include("testing:multi-version") + rootProject.name = "JvmDowngrader" diff --git a/src/main/java/xyz/wagyourtail/jvmdg/cli/Flags.java b/src/main/java/xyz/wagyourtail/jvmdg/cli/Flags.java index 164116d0..4a821647 100644 --- a/src/main/java/xyz/wagyourtail/jvmdg/cli/Flags.java +++ b/src/main/java/xyz/wagyourtail/jvmdg/cli/Flags.java @@ -122,6 +122,8 @@ public Flags copy() { flags.printDebug = printDebug; flags.debugSkipStubs = new HashSet<>(debugSkipStubs); flags.debugDumpClasses = debugDumpClasses; + flags.multiReleaseOriginal = multiReleaseOriginal; + flags.multiReleaseVersions = new HashSet<>(multiReleaseVersions); return flags; } diff --git a/testing/build.gradle.kts b/testing/build.gradle.kts new file mode 100644 index 00000000..99f1e7eb --- /dev/null +++ b/testing/build.gradle.kts @@ -0,0 +1,77 @@ +import org.gradle.api.tasks.testing.logging.TestLogEvent + +plugins { + java +} + +val testVersion = JavaVersion.toVersion(project.properties["testVersion"] as String) + +java { + sourceCompatibility = testVersion + targetCompatibility = testVersion + toolchain { + languageVersion.set(JavaLanguageVersion.of(testVersion.majorVersion)) + } +} + + +repositories { + mavenCentral() +} + +sourceSets { + test { + compileClasspath += rootProject.sourceSets.main.get().compileClasspath + rootProject.sourceSets.main.get().output + runtimeClasspath += rootProject.sourceSets.main.get().runtimeClasspath + rootProject.sourceSets.main.get().output + } +} + +dependencies { + testImplementation("org.junit.jupiter:junit-jupiter:5.10.2") + testRuntimeOnly("org.junit.platform:junit-platform-launcher") + + testImplementation("com.google.code.gson:gson:2.10") + testImplementation("org.apache.commons:commons-compress:1.26.1") + testImplementation("io.github.java-diff-utils:java-diff-utils:4.12") +} + +val testTargetVersion = JavaVersion.toVersion(project.properties["testTargetVersion"] as String) + +tasks.test { + useJUnitPlatform() + + dependsOn( + project(":testing:downgrade").tasks.build, + project(":testing:multi-version").tasks.build, + project(":java-api").tasks.named("testJar") + ) + + val versions = listOf( + testVersion, + testTargetVersion, + JavaVersion.VERSION_1_7, + JavaVersion.VERSION_11, + JavaVersion.VERSION_17 + ).associateWith { + javaToolchains.launcherFor { + languageVersion.set(JavaLanguageVersion.of(it.majorVersion)) + }.get().executablePath.toString() + } + + jvmArgs( + "-Djvmdg.test.version=$version", + "-Djvmdg.test.originalVersion=$testVersion", + "-Djvmdg.test.javaVersion=${versions.keys.joinToString(File.pathSeparator) { it.majorVersion }}", + "-Djvmdg.test.launcher=${versions.values.joinToString(File.pathSeparator)}", + "-Djvmdg.test.downgradeClasspath=${rootProject.sourceSets["shared"].compileClasspath.joinToString(File.pathSeparator) { it.absolutePath }}", + "-Djvmdg.test.downgradePath=${project(":testing:downgrade").tasks.jar.get().outputs.files.singleFile.absolutePath}", + "-Djvmdg.test.multiVersionPath=${project(":testing:multi-version").tasks.jar.get().outputs.files.singleFile.absolutePath}", + "-Djvmdg.test.javaApiPath=${project(":java-api").tasks.named("testJar").get().outputs.files.singleFile.absolutePath}", + ) + + testLogging { + events.add(TestLogEvent.PASSED) + events.add(TestLogEvent.SKIPPED) + events.add(TestLogEvent.FAILED) + } +} \ No newline at end of file diff --git a/downgradetest/build.gradle.kts b/testing/downgrade/build.gradle.kts similarity index 100% rename from downgradetest/build.gradle.kts rename to testing/downgrade/build.gradle.kts diff --git a/downgradetest/src/main/java/xyz/wagyourtail/downgradetest/TestBuffer.java b/testing/downgrade/src/main/java/xyz/wagyourtail/downgradetest/TestBuffer.java similarity index 100% rename from downgradetest/src/main/java/xyz/wagyourtail/downgradetest/TestBuffer.java rename to testing/downgrade/src/main/java/xyz/wagyourtail/downgradetest/TestBuffer.java diff --git a/downgradetest/src/main/java/xyz/wagyourtail/downgradetest/TestClass.java b/testing/downgrade/src/main/java/xyz/wagyourtail/downgradetest/TestClass.java similarity index 100% rename from downgradetest/src/main/java/xyz/wagyourtail/downgradetest/TestClass.java rename to testing/downgrade/src/main/java/xyz/wagyourtail/downgradetest/TestClass.java diff --git a/downgradetest/src/main/java/xyz/wagyourtail/downgradetest/TestCollection.java b/testing/downgrade/src/main/java/xyz/wagyourtail/downgradetest/TestCollection.java similarity index 100% rename from downgradetest/src/main/java/xyz/wagyourtail/downgradetest/TestCollection.java rename to testing/downgrade/src/main/java/xyz/wagyourtail/downgradetest/TestCollection.java diff --git a/downgradetest/src/main/java/xyz/wagyourtail/downgradetest/TestException.java b/testing/downgrade/src/main/java/xyz/wagyourtail/downgradetest/TestException.java similarity index 100% rename from downgradetest/src/main/java/xyz/wagyourtail/downgradetest/TestException.java rename to testing/downgrade/src/main/java/xyz/wagyourtail/downgradetest/TestException.java diff --git a/downgradetest/src/main/java/xyz/wagyourtail/downgradetest/TestFile.java b/testing/downgrade/src/main/java/xyz/wagyourtail/downgradetest/TestFile.java similarity index 100% rename from downgradetest/src/main/java/xyz/wagyourtail/downgradetest/TestFile.java rename to testing/downgrade/src/main/java/xyz/wagyourtail/downgradetest/TestFile.java diff --git a/downgradetest/src/main/java/xyz/wagyourtail/downgradetest/TestFuture.java b/testing/downgrade/src/main/java/xyz/wagyourtail/downgradetest/TestFuture.java similarity index 100% rename from downgradetest/src/main/java/xyz/wagyourtail/downgradetest/TestFuture.java rename to testing/downgrade/src/main/java/xyz/wagyourtail/downgradetest/TestFuture.java diff --git a/downgradetest/src/main/java/xyz/wagyourtail/downgradetest/TestHttpClient.java b/testing/downgrade/src/main/java/xyz/wagyourtail/downgradetest/TestHttpClient.java similarity index 100% rename from downgradetest/src/main/java/xyz/wagyourtail/downgradetest/TestHttpClient.java rename to testing/downgrade/src/main/java/xyz/wagyourtail/downgradetest/TestHttpClient.java diff --git a/downgradetest/src/main/java/xyz/wagyourtail/downgradetest/TestInterface.java b/testing/downgrade/src/main/java/xyz/wagyourtail/downgradetest/TestInterface.java similarity index 100% rename from downgradetest/src/main/java/xyz/wagyourtail/downgradetest/TestInterface.java rename to testing/downgrade/src/main/java/xyz/wagyourtail/downgradetest/TestInterface.java diff --git a/downgradetest/src/main/java/xyz/wagyourtail/downgradetest/TestLambda.java b/testing/downgrade/src/main/java/xyz/wagyourtail/downgradetest/TestLambda.java similarity index 100% rename from downgradetest/src/main/java/xyz/wagyourtail/downgradetest/TestLambda.java rename to testing/downgrade/src/main/java/xyz/wagyourtail/downgradetest/TestLambda.java diff --git a/downgradetest/src/main/java/xyz/wagyourtail/downgradetest/TestMatch.java b/testing/downgrade/src/main/java/xyz/wagyourtail/downgradetest/TestMatch.java similarity index 100% rename from downgradetest/src/main/java/xyz/wagyourtail/downgradetest/TestMatch.java rename to testing/downgrade/src/main/java/xyz/wagyourtail/downgradetest/TestMatch.java diff --git a/downgradetest/src/main/java/xyz/wagyourtail/downgradetest/TestNests.java b/testing/downgrade/src/main/java/xyz/wagyourtail/downgradetest/TestNests.java similarity index 100% rename from downgradetest/src/main/java/xyz/wagyourtail/downgradetest/TestNests.java rename to testing/downgrade/src/main/java/xyz/wagyourtail/downgradetest/TestNests.java diff --git a/downgradetest/src/main/java/xyz/wagyourtail/downgradetest/TestPrintWriter.java b/testing/downgrade/src/main/java/xyz/wagyourtail/downgradetest/TestPrintWriter.java similarity index 100% rename from downgradetest/src/main/java/xyz/wagyourtail/downgradetest/TestPrintWriter.java rename to testing/downgrade/src/main/java/xyz/wagyourtail/downgradetest/TestPrintWriter.java diff --git a/downgradetest/src/main/java/xyz/wagyourtail/downgradetest/TestRandom.java b/testing/downgrade/src/main/java/xyz/wagyourtail/downgradetest/TestRandom.java similarity index 100% rename from downgradetest/src/main/java/xyz/wagyourtail/downgradetest/TestRandom.java rename to testing/downgrade/src/main/java/xyz/wagyourtail/downgradetest/TestRandom.java diff --git a/downgradetest/src/main/java/xyz/wagyourtail/downgradetest/TestRecord.java b/testing/downgrade/src/main/java/xyz/wagyourtail/downgradetest/TestRecord.java similarity index 100% rename from downgradetest/src/main/java/xyz/wagyourtail/downgradetest/TestRecord.java rename to testing/downgrade/src/main/java/xyz/wagyourtail/downgradetest/TestRecord.java diff --git a/downgradetest/src/main/java/xyz/wagyourtail/downgradetest/TestSeal.java b/testing/downgrade/src/main/java/xyz/wagyourtail/downgradetest/TestSeal.java similarity index 100% rename from downgradetest/src/main/java/xyz/wagyourtail/downgradetest/TestSeal.java rename to testing/downgrade/src/main/java/xyz/wagyourtail/downgradetest/TestSeal.java diff --git a/downgradetest/src/main/java/xyz/wagyourtail/downgradetest/TestStackWalker.java b/testing/downgrade/src/main/java/xyz/wagyourtail/downgradetest/TestStackWalker.java similarity index 100% rename from downgradetest/src/main/java/xyz/wagyourtail/downgradetest/TestStackWalker.java rename to testing/downgrade/src/main/java/xyz/wagyourtail/downgradetest/TestStackWalker.java diff --git a/downgradetest/src/main/java/xyz/wagyourtail/downgradetest/TestStream.java b/testing/downgrade/src/main/java/xyz/wagyourtail/downgradetest/TestStream.java similarity index 100% rename from downgradetest/src/main/java/xyz/wagyourtail/downgradetest/TestStream.java rename to testing/downgrade/src/main/java/xyz/wagyourtail/downgradetest/TestStream.java diff --git a/downgradetest/src/main/java/xyz/wagyourtail/downgradetest/TestString.java b/testing/downgrade/src/main/java/xyz/wagyourtail/downgradetest/TestString.java similarity index 100% rename from downgradetest/src/main/java/xyz/wagyourtail/downgradetest/TestString.java rename to testing/downgrade/src/main/java/xyz/wagyourtail/downgradetest/TestString.java diff --git a/downgradetest/src/main/java/xyz/wagyourtail/downgradetest/TestSwitch.java b/testing/downgrade/src/main/java/xyz/wagyourtail/downgradetest/TestSwitch.java similarity index 100% rename from downgradetest/src/main/java/xyz/wagyourtail/downgradetest/TestSwitch.java rename to testing/downgrade/src/main/java/xyz/wagyourtail/downgradetest/TestSwitch.java diff --git a/downgradetest/src/main/java/xyz/wagyourtail/downgradetest/TestTime.java b/testing/downgrade/src/main/java/xyz/wagyourtail/downgradetest/TestTime.java similarity index 100% rename from downgradetest/src/main/java/xyz/wagyourtail/downgradetest/TestTime.java rename to testing/downgrade/src/main/java/xyz/wagyourtail/downgradetest/TestTime.java diff --git a/downgradetest/src/main/java/xyz/wagyourtail/downgradetest/TestVersion.java b/testing/downgrade/src/main/java/xyz/wagyourtail/downgradetest/TestVersion.java similarity index 100% rename from downgradetest/src/main/java/xyz/wagyourtail/downgradetest/TestVersion.java rename to testing/downgrade/src/main/java/xyz/wagyourtail/downgradetest/TestVersion.java diff --git a/downgradetest/src/main/java/xyz/wagyourtail/downgradetest/TestWasAbstract.java b/testing/downgrade/src/main/java/xyz/wagyourtail/downgradetest/TestWasAbstract.java similarity index 100% rename from downgradetest/src/main/java/xyz/wagyourtail/downgradetest/TestWasAbstract.java rename to testing/downgrade/src/main/java/xyz/wagyourtail/downgradetest/TestWasAbstract.java diff --git a/downgradetest/src/main/resources/test/testResource2.txt b/testing/downgrade/src/main/resources/test/testResource2.txt similarity index 100% rename from downgradetest/src/main/resources/test/testResource2.txt rename to testing/downgrade/src/main/resources/test/testResource2.txt diff --git a/downgradetest/src/main/resources/testResource.txt b/testing/downgrade/src/main/resources/testResource.txt similarity index 100% rename from downgradetest/src/main/resources/testResource.txt rename to testing/downgrade/src/main/resources/testResource.txt diff --git a/testing/multi-version/build.gradle.kts b/testing/multi-version/build.gradle.kts new file mode 100644 index 00000000..ef8c8135 --- /dev/null +++ b/testing/multi-version/build.gradle.kts @@ -0,0 +1,32 @@ +plugins { + java +} + +base { + archivesName = "multi-version" +} +version = "1.0.0" + +val testVersion = JavaVersion.toVersion(project.properties["testVersion"] as String) + +java { + sourceCompatibility = testVersion + targetCompatibility = testVersion + toolchain { + languageVersion.set(JavaLanguageVersion.of(testVersion.majorVersion)) + } +} + +tasks.compileJava { + options.encoding = "UTF-8" +} + +val removeLibs by tasks.registering { + doLast { + delete(fileTree("dir" to "build/libs", "include" to "**/*.jar")) + } +} + +tasks.jar { + dependsOn(removeLibs) +} \ No newline at end of file diff --git a/testing/multi-version/src/main/java/xyz/wagyourtail/multiversion/MatchExcJ21.java b/testing/multi-version/src/main/java/xyz/wagyourtail/multiversion/MatchExcJ21.java new file mode 100644 index 00000000..db466f02 --- /dev/null +++ b/testing/multi-version/src/main/java/xyz/wagyourtail/multiversion/MatchExcJ21.java @@ -0,0 +1,9 @@ +package xyz.wagyourtail.multiversion; + +public class MatchExcJ21 { + + public static void main(String[] args) { + throw new MatchException("This is a test", null); + } + +} diff --git a/src/test/java/xyz/wagyourtail/jvmdg/test/JavaRunner.java b/testing/src/test/java/xyz/wagyourtail/jvmdg/test/JavaRunner.java similarity index 100% rename from src/test/java/xyz/wagyourtail/jvmdg/test/JavaRunner.java rename to testing/src/test/java/xyz/wagyourtail/jvmdg/test/JavaRunner.java diff --git a/testing/src/test/java/xyz/wagyourtail/jvmdg/test/integration/BaseIntegrationTests.java b/testing/src/test/java/xyz/wagyourtail/jvmdg/test/integration/BaseIntegrationTests.java new file mode 100644 index 00000000..2e024014 --- /dev/null +++ b/testing/src/test/java/xyz/wagyourtail/jvmdg/test/integration/BaseIntegrationTests.java @@ -0,0 +1,84 @@ +package xyz.wagyourtail.jvmdg.test.integration; + +import xyz.wagyourtail.jvmdg.ClassDowngrader; +import xyz.wagyourtail.jvmdg.cli.Flags; +import xyz.wagyourtail.jvmdg.compile.ZipDowngrader; +import xyz.wagyourtail.jvmdg.test.JavaRunner; + +import java.io.File; +import java.io.IOException; +import java.io.UncheckedIOException; +import java.nio.file.Path; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.concurrent.ConcurrentHashMap; +import java.util.stream.Collectors; +import java.util.stream.Stream; + +public abstract class BaseIntegrationTests { + private static final String JVMDG_VERSION_KEY = "jvmdg.test.version"; + private static final String ORIGINAL_VERSION_KEY = "jvmdg.test.originalVersion"; + private static final String JAVA_VERSION_KEY = "jvmdg.test.javaVersion"; + private static final String LAUNCHER_KEY = "jvmdg.test.launcher"; + private static final String DOWNGRADE_CLASSPATH = "jvmdg.test.downgradeClasspath"; + + private static final String JAVA_API_PATH = "jvmdg.test.javaApiPath"; + + public static final Path javaApi = Path.of(System.getProperty(JAVA_API_PATH)); + public static final List downgradeClasspath = Arrays.stream(System.getProperty(DOWNGRADE_CLASSPATH).split(File.pathSeparator)).map(Path::of).toList(); + + public static final Flags flags = new Flags(); + + public static final JavaRunner.JavaVersion originalVersion = JavaRunner.JavaVersion.fromMajor(Integer.parseInt(System.getProperty(ORIGINAL_VERSION_KEY))); + + private static final List javaVersions = Arrays.stream(System.getProperty(JAVA_VERSION_KEY).split(File.pathSeparator)).map(e -> JavaRunner.JavaVersion.fromMajor(Integer.parseInt(e))).toList(); + private static final List launchers = Arrays.stream(System.getProperty(LAUNCHER_KEY).split(File.pathSeparator)).map(Path::of).toList(); + + public static final Map launchersByVersion = zip(javaVersions.stream(), launchers.stream()).collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue)); + + static { + flags.api = List.of(javaApi.toFile()); + } + + + private static Stream> zip(Stream a, Stream b) { + Iterator aIt = a.iterator(); + Iterator bIt = b.iterator(); + List> out = new ArrayList<>(); + while (aIt.hasNext() && bIt.hasNext()) { + out.add(Map.entry(aIt.next(), bIt.next())); + } + return out.stream(); + } + + private static final Map apiPaths = new ConcurrentHashMap<>(); + + public static Path getApiPath(FlagsAndRunner flags) { + String fName = javaApi.getFileName().toString(); + String withoutExt = fName.substring(0, fName.lastIndexOf('.')); + String ext = fName.substring(fName.lastIndexOf('.')); + return Path.of("./build/tmp/test/" + withoutExt + "-downgrade-" + flags.readableSlug() + ext); + } + + public static synchronized Path getApiJar(FlagsAndRunner flags) { + return apiPaths.computeIfAbsent(flags, e -> { + try { + Path target = getApiPath(flags); + ZipDowngrader.downgradeZip( + ClassDowngrader.downgradeTo(flags.flags()), + javaApi, + Set.of(), + target + ); + return target; + } catch (IOException ex) { + throw new UncheckedIOException(ex); + } + }); + } + +} diff --git a/src/test/java/xyz/wagyourtail/jvmdg/test/integration/ClassRunner.java b/testing/src/test/java/xyz/wagyourtail/jvmdg/test/integration/DowngradeTests.java similarity index 72% rename from src/test/java/xyz/wagyourtail/jvmdg/test/integration/ClassRunner.java rename to testing/src/test/java/xyz/wagyourtail/jvmdg/test/integration/DowngradeTests.java index 84fe2d2e..5117ced6 100644 --- a/src/test/java/xyz/wagyourtail/jvmdg/test/integration/ClassRunner.java +++ b/testing/src/test/java/xyz/wagyourtail/jvmdg/test/integration/DowngradeTests.java @@ -14,10 +14,10 @@ import xyz.wagyourtail.jvmdg.cli.Flags; import xyz.wagyourtail.jvmdg.compile.ApiShader; import xyz.wagyourtail.jvmdg.compile.ZipDowngrader; +import xyz.wagyourtail.jvmdg.logging.Logger; import xyz.wagyourtail.jvmdg.test.JavaRunner; import xyz.wagyourtail.jvmdg.util.Utils; -import java.io.File; import java.io.IOException; import java.io.InputStream; import java.io.UncheckedIOException; @@ -33,43 +33,13 @@ import static org.junit.jupiter.api.Assertions.assertEquals; -public class ClassRunner { - private static final String JVMDG_VERSION_KEY = "jvmdg.test.version"; - private static final String ORIGINAL_VERSION_KEY = "jvmdg.test.originalVersion"; - private static final String JAVA_VERSION_KEY = "jvmdg.test.javaVersion"; - private static final String LAUNCHER_KEY = "jvmdg.test.launcher"; - private static final String DOWNGRADE_CLASSPATH = "jvmdg.test.downgradeClasspath"; - - - private static final Path original = Path.of("./downgradetest/build/libs/downgradetest-1.0.0.jar"); - private static final Path javaApi = Path.of("./java-api/build/tmp/testJar/jvmdowngrader-java-api-" + System.getProperty(JVMDG_VERSION_KEY) + ".jar"); - private static final Path sharedClasses = Path.of("./build/classes/java/shared"); - - private static final List downgradeClasspath = Arrays.stream(System.getProperty(DOWNGRADE_CLASSPATH).split(File.pathSeparator)).map(Path::of).toList(); - - private static final Flags flags = new Flags(); - - private static final JavaRunner.JavaVersion originalVersion = JavaRunner.JavaVersion.fromMajor(Integer.parseInt(System.getProperty(ORIGINAL_VERSION_KEY))); - - private static final List javaVersions = Arrays.stream(System.getProperty(JAVA_VERSION_KEY).split(File.pathSeparator)).map(e -> JavaRunner.JavaVersion.fromMajor(Integer.parseInt(e))).toList(); - private static final List launchers = Arrays.stream(System.getProperty(LAUNCHER_KEY).split(File.pathSeparator)).map(Path::of).toList(); - - private static final Map launchersByVersion = zip(javaVersions.stream(), launchers.stream()).collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue)); - - private static Stream> zip(Stream a, Stream b) { - Iterator aIt = a.iterator(); - Iterator bIt = b.iterator(); - List> out = new ArrayList<>(); - while (aIt.hasNext() && bIt.hasNext()) { - out.add(Map.entry(aIt.next(), bIt.next())); - } - return out.stream(); - } +public class DowngradeTests extends BaseIntegrationTests { + private static final String DOWNGRADE_PATH = "jvmdg.test.downgradePath"; + private static final Path original = Path.of(System.getProperty(DOWNGRADE_PATH)); private static Stream flags() { - Flags flags = ClassRunner.flags.copy(); - flags.quiet = true; - flags.api = List.of(javaApi.toFile()); + Flags flags = BaseIntegrationTests.flags.copy(); + flags.logLevel = Logger.Level.FATAL; return Stream.of( new FlagsAndRunner(flags.copy(e -> e.classVersion = JavaRunner.JavaVersion.V1_8.toOpcode()), JavaRunner.JavaVersion.V1_8) @@ -78,7 +48,7 @@ private static Stream flags() { // e.debugSkipStubs = Set.of(JavaRunner.JavaVersion.V1_8.toOpcode()); // }), JavaRunner.JavaVersion.V1_8), // new FlagsAndRunner(flags.copy(e -> e.classVersion = JavaRunner.JavaVersion.V1_7.toOpcode()), JavaRunner.JavaVersion.V1_7) - ).filter(e -> javaVersions.contains(e.targetVersion)); + ).filter(e -> launchersByVersion.containsKey(e.targetVersion())); } private static List mainClasses() throws IOException { @@ -139,21 +109,12 @@ private static Path getDowngradedPath(FlagsAndRunner flags) { return original.resolveSibling(withoutExt + "-downgrade-" + flags.readableSlug() + ext); } - private static final Map shadedPaths = new ConcurrentHashMap<>(); - - private static Path getShadedPath(FlagsAndRunner flags) { - String fName = original.getFileName().toString(); - String withoutExt = fName.substring(0, fName.lastIndexOf('.')); - String ext = fName.substring(fName.lastIndexOf('.')); - return original.resolveSibling(withoutExt + "-shade-" + flags.readableSlug() + ext); - } - private static synchronized Path getDowngradedJar(FlagsAndRunner flags) { - return shadedPaths.computeIfAbsent(flags, e -> { + return downgradedPaths.computeIfAbsent(flags, e -> { try { Path target = getDowngradedPath(flags); ZipDowngrader.downgradeZip( - ClassDowngrader.downgradeTo(flags.flags), + ClassDowngrader.downgradeTo(flags.flags()), original, Set.of(), target @@ -165,14 +126,21 @@ private static synchronized Path getDowngradedJar(FlagsAndRunner flags) { }); } - private static final Map apiPaths = new ConcurrentHashMap<>(); + private static final Map shadedPaths = new ConcurrentHashMap<>(); + + private static Path getShadedPath(FlagsAndRunner flags) { + String fName = original.getFileName().toString(); + String withoutExt = fName.substring(0, fName.lastIndexOf('.')); + String ext = fName.substring(fName.lastIndexOf('.')); + return original.resolveSibling(withoutExt + "-shade-" + flags.readableSlug() + ext); + } private static synchronized Path getShadedJar(FlagsAndRunner flags) { - return apiPaths.computeIfAbsent(flags, e -> { + return shadedPaths.computeIfAbsent(flags, e -> { try { Path target = getShadedPath(flags); ApiShader.shadeApis( - flags.flags, + flags.flags(), "downgradetest", getDowngradedJar(flags).toFile(), target.toFile(), @@ -185,30 +153,6 @@ private static synchronized Path getShadedJar(FlagsAndRunner flags) { }); } - private static Path getApiPath(FlagsAndRunner flags) { - String fName = javaApi.getFileName().toString(); - String withoutExt = fName.substring(0, fName.lastIndexOf('.')); - String ext = fName.substring(fName.lastIndexOf('.')); - return Path.of("./build/tmp/test/" + withoutExt + "-downgrade-" + flags.readableSlug() + ext); - } - - private static synchronized Path getApiJar(FlagsAndRunner flags) { - return downgradedPaths.computeIfAbsent(flags, e -> { - try { - Path target = getApiPath(flags); - ZipDowngrader.downgradeZip( - ClassDowngrader.downgradeTo(flags.flags), - javaApi, - Set.of(), - target - ); - return target; - } catch (IOException ex) { - throw new UncheckedIOException(ex); - } - }); - } - @BeforeAll public static void clearPrevious() throws IOException { for (FlagsAndRunner flag : flags().toList()) { @@ -219,7 +163,7 @@ public static void clearPrevious() throws IOException { } @ParameterizedTest - @MethodSource({"xyz.wagyourtail.jvmdg.test.integration.ClassRunner#arguments"}) + @MethodSource({"arguments"}) @Execution(ExecutionMode.CONCURRENT) public void testDowngrade(String mainClass, FlagsAndRunner javaVersion) throws IOException, InterruptedException { System.out.println("TEST_DOWNGRADE: Running " + mainClass + " on " + javaVersion.readableSlug()); @@ -228,8 +172,8 @@ public void testDowngrade(String mainClass, FlagsAndRunner javaVersion) throws I System.out.println(original.getValue()); System.out.println("Exit code: " + original.getKey()); - if (javaVersion.flags.classVersion <= 51) { - try (ZipFile zf = new ZipFile(ClassRunner.original.toFile())) { + if (javaVersion.flags().classVersion <= 51) { + try (ZipFile zf = new ZipFile(DowngradeTests.original.toFile())) { ZipEntry entry = zf.getEntry(mainClass.replace(".", "/") + ".class"); try (InputStream is = zf.getInputStream(entry)) { ClassReader cr = new ClassReader(is); @@ -247,12 +191,12 @@ public void testDowngrade(String mainClass, FlagsAndRunner javaVersion) throws I getDowngradedJar(javaVersion), new String[]{}, mainClass, - Stream.concat(Stream.of(getApiJar(javaVersion), sharedClasses), downgradeClasspath.stream()).collect(Collectors.toSet()), + Stream.concat(Stream.of(getApiJar(javaVersion)), downgradeClasspath.stream()).collect(Collectors.toSet()), Path.of("."), Map.of(), true, List.of(), - launchersByVersion.get(javaVersion.targetVersion), + launchersByVersion.get(javaVersion.targetVersion()), (String it) -> { downgradedLog.append(it).append("\n"); System.out.println(it); @@ -284,8 +228,8 @@ public void testShade(String mainClass, FlagsAndRunner javaVersion) throws IOExc System.out.println(original.getValue()); System.out.println("Exit code: " + original.getKey()); - if (javaVersion.flags.classVersion <= 51) { - try (ZipFile zf = new ZipFile(ClassRunner.original.toFile())) { + if (javaVersion.flags().classVersion <= 51) { + try (ZipFile zf = new ZipFile(DowngradeTests.original.toFile())) { ZipEntry entry = zf.getEntry(mainClass.replace(".", "/") + ".class"); try (InputStream is = zf.getInputStream(entry)) { ClassReader cr = new ClassReader(is); @@ -308,7 +252,7 @@ public void testShade(String mainClass, FlagsAndRunner javaVersion) throws IOExc Map.of(), true, List.of(), - launchersByVersion.get(javaVersion.targetVersion), + launchersByVersion.get(javaVersion.targetVersion()), (String it) -> { shadedLog.append(it).append("\n"); System.out.println(it); @@ -356,7 +300,7 @@ public void testRuntime(String mainClass, FlagsAndRunner javaVersion) throws IOE "--quiet", "bootstrap", "--classpath", - ClassRunner.original.toAbsolutePath().toString(), + DowngradeTests.original.toAbsolutePath().toString(), "-m", mainClass }, @@ -366,7 +310,7 @@ public void testRuntime(String mainClass, FlagsAndRunner javaVersion) throws IOE Map.of(), true, List.of(), - launchersByVersion.get(javaVersion.targetVersion), + launchersByVersion.get(javaVersion.targetVersion()), (String it) -> { runtimeLog.append(it).append("\n"); System.out.println(it); @@ -395,16 +339,4 @@ public static void compareResults(String mainClass, FlagsAndRunner javaVersion, assertEquals(originalResult.getKey(), downgradedResult.getKey(), "Exit code mismatch for " + mainClass + " on " + javaVersion.readableSlug()); } - public record FlagsAndRunner(Flags flags, JavaRunner.JavaVersion targetVersion) { - - public String readableSlug() { - if (flags.debugSkipStubs.isEmpty()) { - return Integer.toString(targetVersion.getMajorVersion()); - } else { - return targetVersion.getMajorVersion() + "-fake-" + flags.debugSkipStubs.stream().map(e -> Integer.toString(JavaRunner.JavaVersion.fromOpcode(e).getMajorVersion())).collect(Collectors.joining("-")); - } - } - - } - } diff --git a/testing/src/test/java/xyz/wagyourtail/jvmdg/test/integration/FlagsAndRunner.java b/testing/src/test/java/xyz/wagyourtail/jvmdg/test/integration/FlagsAndRunner.java new file mode 100644 index 00000000..75012403 --- /dev/null +++ b/testing/src/test/java/xyz/wagyourtail/jvmdg/test/integration/FlagsAndRunner.java @@ -0,0 +1,18 @@ +package xyz.wagyourtail.jvmdg.test.integration; + +import xyz.wagyourtail.jvmdg.cli.Flags; +import xyz.wagyourtail.jvmdg.test.JavaRunner; + +import java.util.stream.Collectors; + +public record FlagsAndRunner(Flags flags, JavaRunner.JavaVersion targetVersion) { + + public String readableSlug() { + if (flags.debugSkipStubs.isEmpty()) { + return Integer.toString(targetVersion.getMajorVersion()); + } else { + return targetVersion.getMajorVersion() + "-fake-" + flags.debugSkipStubs.stream().map(e -> Integer.toString(JavaRunner.JavaVersion.fromOpcode(e).getMajorVersion())).collect(Collectors.joining("-")); + } + } + +} diff --git a/testing/src/test/java/xyz/wagyourtail/jvmdg/test/integration/MultiVersionTests.java b/testing/src/test/java/xyz/wagyourtail/jvmdg/test/integration/MultiVersionTests.java new file mode 100644 index 00000000..88f8f885 --- /dev/null +++ b/testing/src/test/java/xyz/wagyourtail/jvmdg/test/integration/MultiVersionTests.java @@ -0,0 +1,173 @@ +package xyz.wagyourtail.jvmdg.test.integration; + +import org.apache.commons.io.function.IOStream; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.parallel.Execution; +import org.junit.jupiter.api.parallel.ExecutionMode; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.Arguments; +import org.junit.jupiter.params.provider.MethodSource; +import org.objectweb.asm.ClassReader; +import org.objectweb.asm.tree.ClassNode; +import xyz.wagyourtail.jvmdg.ClassDowngrader; +import xyz.wagyourtail.jvmdg.compile.ZipDowngrader; +import xyz.wagyourtail.jvmdg.test.JavaRunner; +import xyz.wagyourtail.jvmdg.util.Utils; + +import java.io.IOException; +import java.nio.file.FileSystem; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.concurrent.ConcurrentHashMap; +import java.util.regex.Matcher; +import java.util.regex.Pattern; +import java.util.stream.Collectors; +import java.util.stream.Stream; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotEquals; + +public class MultiVersionTests extends BaseIntegrationTests { + private static final String MULTIVERSION_PATH = "jvmdg.test.multiVersionPath"; + private static final Path original = Path.of(System.getProperty(MULTIVERSION_PATH)); + + private static final FlagsAndRunner flagsAndRunner = new FlagsAndRunner(flags.copy(f -> { + f.multiReleaseOriginal = true; + f.multiReleaseVersions = Set.of(JavaRunner.JavaVersion.V11.toOpcode(), JavaRunner.JavaVersion.V17.toOpcode()); + }), JavaRunner.JavaVersion.V1_8); + + private static List mainClasses() throws IOException { + try (FileSystem fs = Utils.openZipFileSystem(original, false)) { + Path root = fs.getPath("/"); + return IOStream.adapt(Files.walk(root)) + .filter(e -> Files.isRegularFile(e) && e.getFileName().toString().endsWith(".class")) + .map(e -> root.relativize(e).toString().replaceAll("\\.class$", "").replace("/", ".")) + .filter(e -> { + ClassReader cr = new ClassReader(Files.readAllBytes(fs.getPath(e.replace(".", "/") + ".class"))); + ClassNode cn = new ClassNode(); + cr.accept(cn, ClassReader.SKIP_CODE); + return cn.methods.stream().anyMatch(m -> m.name.equals("main") && m.desc.equals("([Ljava/lang/String;)V")); + }) + .unwrap().toList(); + } + } + + private static synchronized Path getDowngradedJar() throws IOException { + Path target = original.resolveSibling("multi-version-downgraded-" + flagsAndRunner.readableSlug() + ".jar"); + if (!Files.exists(target)) { + ZipDowngrader.downgradeZip( + ClassDowngrader.downgradeTo(flagsAndRunner.flags()), + original, + Set.of(), + target + ); + } + return target; + } + + @BeforeAll + public static void deleteExisting() throws IOException { + Files.deleteIfExists(original.resolveSibling("downgraded-" + flagsAndRunner.readableSlug())); + } + + + private static final Map> originalResults = new ConcurrentHashMap<>(); + + @BeforeAll + public static void runOriginal() throws IOException, InterruptedException { + for (String main : mainClasses()) { + StringBuilder originalLog = new StringBuilder(); + Integer exitCode = JavaRunner.runJarInSubprocess( + original, + new String[0], + main, + Set.of(), + Path.of("."), + Map.of(), + true, + List.of(), + launchersByVersion.get(originalVersion), + (String it) -> originalLog.append(it).append("\n"), + (String it) -> originalLog.append(it).append("\n") + ); + assert exitCode != null; + originalResults.put(main, Map.entry(exitCode, originalLog.toString())); + } + } + + private static final Map> fullDowngradeResults = new ConcurrentHashMap<>(); + + @BeforeAll + public static void runOnTestTarget() throws IOException, InterruptedException { + + FlagsAndRunner downgraded = new FlagsAndRunner(flags.copy(f -> f.quiet = true), JavaRunner.JavaVersion.V1_8); + + for (String main : mainClasses()) { + StringBuilder fullDowngradeLog = new StringBuilder(); + Integer exitCode = JavaRunner.runJarInSubprocess( + getDowngradedJar(), + new String[0], + main, + Stream.concat(Stream.of(getApiJar(downgraded)), downgradeClasspath.stream()).collect(Collectors.toSet()), + Path.of("."), + Map.of(), + true, + List.of(), + launchersByVersion.get(JavaRunner.JavaVersion.V1_8), + (String it) -> fullDowngradeLog.append(it).append("\n"), + (String it) -> fullDowngradeLog.append(it).append("\n") + ); + assert exitCode != null; + fullDowngradeResults.put(main, Map.entry(exitCode, fullDowngradeLog.toString())); + } + } + + public static Stream arguments() throws IOException { + return mainClasses().stream().map(Arguments::of); + } + + public static JavaRunner.JavaVersion getVersionOf(String main) { + Matcher m = Pattern.compile("J(\\d+)$").matcher(main); + if (!m.find()) { + throw new IllegalArgumentException("Invalid main class name: " + main); + } + return JavaRunner.JavaVersion.fromMajor(Integer.parseInt(m.group(1))); + } + + @ParameterizedTest + @MethodSource({"arguments"}) + @Execution(ExecutionMode.CONCURRENT) + public void testMultiVersion(String main) throws IOException, InterruptedException { + JavaRunner.JavaVersion version = getVersionOf(main); + JavaRunner.JavaVersion aboveTarget = launchersByVersion.keySet().stream().filter(e -> e.getMajorVersion() >= version.getMajorVersion()).findFirst().orElseThrow(); + + Map.Entry originalResult = originalResults.get(main); + Map.Entry fullDowngradeResult = fullDowngradeResults.get(main); + + FlagsAndRunner downgraded = new FlagsAndRunner(flags.copy(f -> f.quiet = true), JavaRunner.JavaVersion.V1_8); + + assertNotEquals(originalResult, fullDowngradeResult); + + StringBuilder aboveTargetLog = new StringBuilder(); + Integer aboveTargetExitCode = JavaRunner.runJarInSubprocess( + getDowngradedJar(), + new String[0], + main, + Stream.concat(Stream.of(getApiJar(downgraded)), downgradeClasspath.stream()).collect(Collectors.toSet()), + Path.of("."), + Map.of(), + true, + List.of(), + launchersByVersion.get(aboveTarget), + (String it) -> aboveTargetLog.append(it).append("\n"), + (String it) -> aboveTargetLog.append(it).append("\n") + ); + + assert aboveTargetExitCode != null; + assertEquals(originalResult, Map.entry(aboveTargetExitCode, aboveTargetLog.toString())); + } + +} diff --git a/src/test/java/xyz/wagyourtail/jvmdg/test/unit/TestFlags.java b/testing/src/test/java/xyz/wagyourtail/jvmdg/test/unit/TestFlags.java similarity index 100% rename from src/test/java/xyz/wagyourtail/jvmdg/test/unit/TestFlags.java rename to testing/src/test/java/xyz/wagyourtail/jvmdg/test/unit/TestFlags.java diff --git a/src/test/resources/junit-platform.properties b/testing/src/test/resources/junit-platform.properties similarity index 100% rename from src/test/resources/junit-platform.properties rename to testing/src/test/resources/junit-platform.properties