From 7d62cd890cb44945e772e18cdb457b1173f4f853 Mon Sep 17 00:00:00 2001 From: Jonas Herzig Date: Wed, 10 Nov 2021 09:34:39 +0100 Subject: Start adding tests --- src/test/java/a/pkg/A.java | 31 +++++++ src/test/java/a/pkg/AInterface.java | 5 ++ src/test/java/a/pkg/AParent.java | 4 + src/test/java/b/pkg/B.java | 31 +++++++ src/test/java/b/pkg/BInterface.java | 5 ++ src/test/java/b/pkg/BParent.java | 4 + .../gradle/remap/mapper/TestMixinAccessors.kt | 65 ++++++++++++++ .../gradle/remap/mapper/TestMixinAnnotation.kt | 52 ++++++++++++ .../gradle/remap/mapper/TestMixinInjections.kt | 98 ++++++++++++++++++++++ .../com/replaymod/gradle/remap/util/TestData.kt | 48 +++++++++++ .../gradle/remap/util/mappingExtensions.kt | 13 +++ src/test/resources/mappings.srg | 13 +++ 12 files changed, 369 insertions(+) create mode 100644 src/test/java/a/pkg/A.java create mode 100644 src/test/java/a/pkg/AInterface.java create mode 100644 src/test/java/a/pkg/AParent.java create mode 100644 src/test/java/b/pkg/B.java create mode 100644 src/test/java/b/pkg/BInterface.java create mode 100644 src/test/java/b/pkg/BParent.java create mode 100644 src/test/kotlin/com/replaymod/gradle/remap/mapper/TestMixinAccessors.kt create mode 100644 src/test/kotlin/com/replaymod/gradle/remap/mapper/TestMixinAnnotation.kt create mode 100644 src/test/kotlin/com/replaymod/gradle/remap/mapper/TestMixinInjections.kt create mode 100644 src/test/kotlin/com/replaymod/gradle/remap/util/TestData.kt create mode 100644 src/test/kotlin/com/replaymod/gradle/remap/util/mappingExtensions.kt create mode 100644 src/test/resources/mappings.srg (limited to 'src/test') diff --git a/src/test/java/a/pkg/A.java b/src/test/java/a/pkg/A.java new file mode 100644 index 0000000..d91a6e5 --- /dev/null +++ b/src/test/java/a/pkg/A.java @@ -0,0 +1,31 @@ +package a.pkg; + +public class A extends AParent implements AInterface { + private int aField; + + public void aMethod() { + } + + public void aOverloaded() { + } + + public void aOverloaded(int arg) { + } + + public void aOverloaded(boolean arg) { + } + + public void commonOverloaded(Object arg) { + } + + public void commonOverloaded(A arg) { + } + + @Override + public void aInterfaceMethod() { + } + + public class Inner { + private int aField; + } +} diff --git a/src/test/java/a/pkg/AInterface.java b/src/test/java/a/pkg/AInterface.java new file mode 100644 index 0000000..8786c94 --- /dev/null +++ b/src/test/java/a/pkg/AInterface.java @@ -0,0 +1,5 @@ +package a.pkg; + +public interface AInterface { + void aInterfaceMethod(); +} diff --git a/src/test/java/a/pkg/AParent.java b/src/test/java/a/pkg/AParent.java new file mode 100644 index 0000000..aaf35fb --- /dev/null +++ b/src/test/java/a/pkg/AParent.java @@ -0,0 +1,4 @@ +package a.pkg; + +public class AParent { +} diff --git a/src/test/java/b/pkg/B.java b/src/test/java/b/pkg/B.java new file mode 100644 index 0000000..48abdac --- /dev/null +++ b/src/test/java/b/pkg/B.java @@ -0,0 +1,31 @@ +package b.pkg; + +public class B extends BParent implements BInterface { + private int bField; + + public void bMethod() { + } + + public void bOverloaded() { + } + + public void bOverloaded(int arg) { + } + + public void bOverloaded(boolean arg) { + } + + public void commonOverloaded(Object arg) { + } + + public void commonOverloaded(B arg) { + } + + @Override + public void bInterfaceMethod() { + } + + public class Inner { + private int bField; + } +} diff --git a/src/test/java/b/pkg/BInterface.java b/src/test/java/b/pkg/BInterface.java new file mode 100644 index 0000000..c57c72f --- /dev/null +++ b/src/test/java/b/pkg/BInterface.java @@ -0,0 +1,5 @@ +package b.pkg; + +public interface BInterface { + void bInterfaceMethod(); +} diff --git a/src/test/java/b/pkg/BParent.java b/src/test/java/b/pkg/BParent.java new file mode 100644 index 0000000..29cae54 --- /dev/null +++ b/src/test/java/b/pkg/BParent.java @@ -0,0 +1,4 @@ +package b.pkg; + +public class BParent { +} diff --git a/src/test/kotlin/com/replaymod/gradle/remap/mapper/TestMixinAccessors.kt b/src/test/kotlin/com/replaymod/gradle/remap/mapper/TestMixinAccessors.kt new file mode 100644 index 0000000..4b9450f --- /dev/null +++ b/src/test/kotlin/com/replaymod/gradle/remap/mapper/TestMixinAccessors.kt @@ -0,0 +1,65 @@ +package com.replaymod.gradle.remap.mapper + +import com.replaymod.gradle.remap.util.TestData +import io.kotest.matchers.shouldBe +import org.junit.jupiter.api.Test + +class TestMixinAccessors { + @Test + fun `remaps @Invoker`() { + TestData.remap(""" + @org.spongepowered.asm.mixin.Mixin(a.pkg.A.class) + interface MixinA { + @org.spongepowered.asm.mixin.gen.Invoker + void invokeAMethod(); + @org.spongepowered.asm.mixin.gen.Invoker("aMethod") + void invokeBMethod(); + } + """.trimIndent()) shouldBe """ + @org.spongepowered.asm.mixin.Mixin(b.pkg.B.class) + interface MixinA { + @org.spongepowered.asm.mixin.gen.Invoker("bMethod") + void invokeAMethod(); + @org.spongepowered.asm.mixin.gen.Invoker + void invokeBMethod(); + } + """.trimIndent() + } + + @Test + fun `remaps @Accessor`() { + TestData.remap(""" + @org.spongepowered.asm.mixin.Mixin(a.pkg.A.class) + interface MixinA { + @org.spongepowered.asm.mixin.gen.Accessor + int isAField(); + @org.spongepowered.asm.mixin.gen.Accessor + int getAField(); + @org.spongepowered.asm.mixin.gen.Accessor + void setAField(int value); + @org.spongepowered.asm.mixin.gen.Accessor("aField") + int isBField(); + @org.spongepowered.asm.mixin.gen.Accessor("aField") + int getBField(); + @org.spongepowered.asm.mixin.gen.Accessor("aField") + void setBField(int value); + } + """.trimIndent()) shouldBe """ + @org.spongepowered.asm.mixin.Mixin(b.pkg.B.class) + interface MixinA { + @org.spongepowered.asm.mixin.gen.Accessor("bField") + int isAField(); + @org.spongepowered.asm.mixin.gen.Accessor("bField") + int getAField(); + @org.spongepowered.asm.mixin.gen.Accessor("bField") + void setAField(int value); + @org.spongepowered.asm.mixin.gen.Accessor + int isBField(); + @org.spongepowered.asm.mixin.gen.Accessor + int getBField(); + @org.spongepowered.asm.mixin.gen.Accessor + void setBField(int value); + } + """.trimIndent() + } +} \ No newline at end of file diff --git a/src/test/kotlin/com/replaymod/gradle/remap/mapper/TestMixinAnnotation.kt b/src/test/kotlin/com/replaymod/gradle/remap/mapper/TestMixinAnnotation.kt new file mode 100644 index 0000000..1f9a3a2 --- /dev/null +++ b/src/test/kotlin/com/replaymod/gradle/remap/mapper/TestMixinAnnotation.kt @@ -0,0 +1,52 @@ +package com.replaymod.gradle.remap.mapper + +import com.replaymod.gradle.remap.util.TestData +import io.kotest.matchers.shouldBe +import org.junit.jupiter.api.Test + +class TestMixinAnnotation { + @Test + fun `remaps with class target`() { + TestData.remap(""" + @org.spongepowered.asm.mixin.Mixin(a.pkg.A.class) + class MixinA { @Shadow private int aField; } + """.trimIndent()) shouldBe """ + @org.spongepowered.asm.mixin.Mixin(b.pkg.B.class) + class MixinA { @Shadow private int bField; } + """.trimIndent() + } + + @Test + fun `remaps with string target`() { + TestData.remap(""" + @org.spongepowered.asm.mixin.Mixin(targets = "a.pkg.A") + class MixinA { @Shadow private int aField; } + """.trimIndent()) shouldBe """ + @org.spongepowered.asm.mixin.Mixin(targets = "b.pkg.B") + class MixinA { @Shadow private int bField; } + """.trimIndent() + } + + @Test + fun `remaps with inner class string target separated by dot`() { + // FIXME should probably keep the dot? + TestData.remap(""" + @org.spongepowered.asm.mixin.Mixin(targets = "a.pkg.A.Inner") + class MixinA { @Shadow private int aField; } + """.trimIndent()) shouldBe """ + @org.spongepowered.asm.mixin.Mixin(targets = "b.pkg.B${'$'}Inner") + class MixinA { @Shadow private int bField; } + """.trimIndent() + } + + @Test + fun `remaps with inner class string target separated by dollar`() { + TestData.remap(""" + @org.spongepowered.asm.mixin.Mixin(targets = "a.pkg.A${'$'}Inner") + class MixinA { @Shadow private int aField; } + """.trimIndent()) shouldBe """ + @org.spongepowered.asm.mixin.Mixin(targets = "b.pkg.B${'$'}Inner") + class MixinA { @Shadow private int bField; } + """.trimIndent() + } +} \ No newline at end of file diff --git a/src/test/kotlin/com/replaymod/gradle/remap/mapper/TestMixinInjections.kt b/src/test/kotlin/com/replaymod/gradle/remap/mapper/TestMixinInjections.kt new file mode 100644 index 0000000..856b56e --- /dev/null +++ b/src/test/kotlin/com/replaymod/gradle/remap/mapper/TestMixinInjections.kt @@ -0,0 +1,98 @@ +package com.replaymod.gradle.remap.mapper + +import com.replaymod.gradle.remap.util.TestData +import io.kotest.matchers.collections.shouldHaveSize +import io.kotest.matchers.shouldBe +import io.kotest.matchers.string.shouldContain +import org.junit.jupiter.api.Test + +class TestMixinInjections { + private fun remaps(annotation: String) { + TestData.remap(""" + @org.spongepowered.asm.mixin.Mixin(a.pkg.A.class) + class MixinA { + @$annotation(method = "aMethod") + private void test() {} + } + """.trimIndent()) shouldBe """ + @org.spongepowered.asm.mixin.Mixin(b.pkg.B.class) + class MixinA { + @$annotation(method = "bMethod") + private void test() {} + } + """.trimIndent() + } + + @Test + fun `remaps @Inject method`() = remaps("org.spongepowered.asm.mixin.injection.Inject") + + @Test + fun `remaps @ModifyArg method`() = remaps("org.spongepowered.asm.mixin.injection.ModifyArg") + + @Test + fun `remaps @ModifyArgs method`() = remaps("org.spongepowered.asm.mixin.injection.ModifyArgs") + + @Test + fun `remaps @ModifyConstant method`() = remaps("org.spongepowered.asm.mixin.injection.ModifyConstant") + + @Test + fun `remaps @ModifyVariable method`() = remaps("org.spongepowered.asm.mixin.injection.ModifyVariable") + + @Test + fun `remaps @Redirect method`() = remaps("org.spongepowered.asm.mixin.injection.Redirect") + + @Test + fun `throws when injecting into ambiguous method`() { + val (_, errors) = TestData.remapWithErrors(""" + @org.spongepowered.asm.mixin.Mixin(a.pkg.A.class) + class MixinA { + @org.spongepowered.asm.mixin.injection.Inject(method = "aOverloaded") + private void test() {} + } + """.trimIndent()) + errors shouldHaveSize 1 + val (line, error) = errors[0] + line shouldBe 2 + error shouldContain "aOverloaded" + error shouldContain "(I)V" + error shouldContain "(Z)V" + } + + @Test + fun `remaps qualified method`() { + TestData.remap(""" + @org.spongepowered.asm.mixin.Mixin(a.pkg.A.class) + class MixinA { + @org.spongepowered.asm.mixin.injection.Inject(method = "aOverloaded()V") + private void test() {} + @org.spongepowered.asm.mixin.injection.Inject(method = "aOverloaded(I)V") + private void testArg() {} + } + """.trimIndent()) shouldBe """ + @org.spongepowered.asm.mixin.Mixin(b.pkg.B.class) + class MixinA { + @org.spongepowered.asm.mixin.injection.Inject(method = "bOverloaded()V") + private void test() {} + @org.spongepowered.asm.mixin.injection.Inject(method = "bOverloaded(I)V") + private void testArg() {} + } + """.trimIndent() + } + + @Test + fun `remaps qualified method argument`() { + TestData.remap(""" + @org.spongepowered.asm.mixin.Mixin(a.pkg.A.class) + class MixinA { + @org.spongepowered.asm.mixin.injection.Inject(method = "commonOverloaded(La/pkg/A;)V") + private void test() {} + } + """.trimIndent()) shouldBe """ + @org.spongepowered.asm.mixin.Mixin(b.pkg.B.class) + class MixinA { + @org.spongepowered.asm.mixin.injection.Inject(method = "commonOverloaded(Lb/pkg/B;)V") + private void test() {} + } + """.trimIndent() + } +} \ No newline at end of file diff --git a/src/test/kotlin/com/replaymod/gradle/remap/util/TestData.kt b/src/test/kotlin/com/replaymod/gradle/remap/util/TestData.kt new file mode 100644 index 0000000..cb0ad44 --- /dev/null +++ b/src/test/kotlin/com/replaymod/gradle/remap/util/TestData.kt @@ -0,0 +1,48 @@ +package com.replaymod.gradle.remap.util + +import com.replaymod.gradle.remap.Transformer +import com.replaymod.gradle.remap.legacy.LegacyMappingSetModelFactory +import org.cadixdev.lorenz.MappingSet +import java.net.URL +import java.nio.file.Paths +import kotlin.io.path.absolutePathString + +object TestData { + private val mappingsPath = Paths.get(javaClass.getResource("/mappings.srg")!!.toURI()) + private val mappings = mappingsPath.readMappings().let { mappings -> + val legacyCopy = MappingSet.create(LegacyMappingSetModelFactory()) + mappings.topLevelClassMappings.forEach { it.copy(legacyCopy) } + legacyCopy + } + + val transformer = Transformer(mappings).apply { + fun findClasspathEntry(cls: String): String { + val classFilePath = "/${cls.replace('.', '/')}.class" + val url = javaClass.getResource(classFilePath) + ?: throw RuntimeException("Failed to find $cls on classpath.") + + return when { + url.protocol == "jar" && url.file.endsWith("!$classFilePath") -> { + Paths.get(URL(url.file.removeSuffix("!$classFilePath")).toURI()).absolutePathString() + } + url.protocol == "file" && url.file.endsWith(classFilePath) -> { + var path = Paths.get(url.toURI()) + repeat(cls.count { it == '.' } + 1) { + path = path.parent + } + path.absolutePathString() + } + else -> { + throw RuntimeException("Do not know how to turn $url into classpath entry.") + } + } + } + classpath = arrayOf( + findClasspathEntry("org.spongepowered.asm.mixin.Mixin"), + findClasspathEntry("a.pkg.A"), + ) + } + + fun remap(content: String): String = transformer.remap(mapOf("test.java" to content))["test.java"]!!.first + fun remapWithErrors(content: String) = transformer.remap(mapOf("test.java" to content))["test.java"]!! +} \ No newline at end of file diff --git a/src/test/kotlin/com/replaymod/gradle/remap/util/mappingExtensions.kt b/src/test/kotlin/com/replaymod/gradle/remap/util/mappingExtensions.kt new file mode 100644 index 0000000..9a869d4 --- /dev/null +++ b/src/test/kotlin/com/replaymod/gradle/remap/util/mappingExtensions.kt @@ -0,0 +1,13 @@ +package com.replaymod.gradle.remap.util + +import org.cadixdev.lorenz.MappingSet +import org.cadixdev.lorenz.io.MappingFormats +import java.nio.file.Path + +fun Path.readMappings(): MappingSet { + val name = fileName.toString() + val ext = name.substring(name.lastIndexOf(".") + 1) + val format = MappingFormats.REGISTRY.values().find { it.standardFileExtension.orElse(null) == ext } + ?: throw UnsupportedOperationException("Cannot find mapping format for $this") + return format.read(this) +} diff --git a/src/test/resources/mappings.srg b/src/test/resources/mappings.srg new file mode 100644 index 0000000..22d63a9 --- /dev/null +++ b/src/test/resources/mappings.srg @@ -0,0 +1,13 @@ +CL: a/pkg/A b/pkg/B +FD: a/pkg/A/aField b/pkg/B/bField +MD: a/pkg/A/aMethod ()V b/pkg/B/bMethod ()V +MD: a/pkg/A/aOverloaded ()V b/pkg/B/bOverloaded ()V +MD: a/pkg/A/aOverloaded (I)V b/pkg/B/bOverloaded (I)V +MD: a/pkg/A/aOverloaded (Z)V b/pkg/B/bOverloaded (Z)V +MD: a/pkg/A/commonOverloaded (Ljava/lang/Object;)V b/pkg/B/commonOverloaded (Ljava/lang/Object;)V +MD: a/pkg/A/commonOverloaded (La/pkg/A;)V b/pkg/B/commonOverloaded (La/pkg/B;)V +CL: a/pkg/A$Inner b/pkg/B$Inner +FD: a/pkg/A$Inner/aField b/pkg/B$Inner/bField +CL: a/pkg/AParent b/pkg/BParent +CL: a/pkg/AInterface b/pkg/BInterface +MD: a/pkg/AInterface/aInterfaceMethod ()V b/pkg/BInterface/bInterfaceMethod ()V -- cgit