From c370a4560b45a37834c7bd16f0c868548420c8f6 Mon Sep 17 00:00:00 2001 From: NebelNidas Date: Fri, 6 Oct 2023 22:47:45 +0200 Subject: [PATCH] Add 3rd-party readers to verify our writers' spec-compliance --- build.gradle | 23 +++-- gradle.properties | 3 + .../net/fabricmc/mappingio/TestHelper.java | 63 ++++++++++++- .../fabricmc/mappingio/write/WriteTest.java | 92 +++++++++++++++++-- 4 files changed, 166 insertions(+), 15 deletions(-) diff --git a/build.gradle b/build.gradle index 664c9cb0..f4ac7f66 100644 --- a/build.gradle +++ b/build.gradle @@ -7,8 +7,15 @@ plugins { id "me.modmuss50.remotesign" version "0.4.0" } -sourceCompatibility = 1.8 -targetCompatibility = 1.8 +compileJava { + sourceCompatibility = 1.8 + targetCompatibility = 1.8 +} + +compileTestJava { + sourceCompatibility = 17 + targetCompatibility = 17 +} group "net.fabricmc" archivesBaseName = "mapping-io" @@ -17,10 +24,6 @@ def ENV = System.getenv() tasks.withType(JavaCompile).configureEach { it.options.encoding = "UTF-8" - - if (JavaVersion.current().isJava9Compatible()) { - it.options.release = 8 - } } checkstyle { @@ -34,6 +37,10 @@ repositories { url = 'https://maven.fabricmc.net/' } mavenCentral() + maven { + name = 'NeoForged' + url = 'https://maven.neoforged.net/' + } } dependencies { @@ -41,6 +48,10 @@ dependencies { compileOnly "org.jetbrains:annotations:${project.jetbrains_annotations_version}" implementation "net.fabricmc:tiny-remapper:${tiny_remapper_version}" + testImplementation "cuchaz:enigma:${enigma_version}" + testImplementation "net.minecraftforge:srgutils:${srgutils_version}" + testImplementation "org.cadixdev:lorenz:${lorenz_version}" + testImplementation "org.cadixdev:lorenz-io-enigma:${lorenz_version}" testImplementation "org.junit.jupiter:junit-jupiter-api:${junit_jupiter_version}" testRuntimeOnly "org.junit.jupiter:junit-jupiter-engine:${junit_jupiter_version}" } diff --git a/gradle.properties b/gradle.properties index bf9284f3..d44ac399 100644 --- a/gradle.properties +++ b/gradle.properties @@ -10,3 +10,6 @@ tiny_remapper_version = 0.8.0 jetbrains_annotations_version = 24.0.1 checkstyle_tool_version = 8.31 junit_jupiter_version = 5.9.3 +srgutils_version = 0.5.4 +lorenz_version = 0.5.8 +enigma_version = 2.3.3 diff --git a/src/test/java/net/fabricmc/mappingio/TestHelper.java b/src/test/java/net/fabricmc/mappingio/TestHelper.java index 52a0967a..4f493b11 100644 --- a/src/test/java/net/fabricmc/mappingio/TestHelper.java +++ b/src/test/java/net/fabricmc/mappingio/TestHelper.java @@ -23,6 +23,8 @@ import java.util.Arrays; import java.util.concurrent.atomic.AtomicInteger; +import net.minecraftforge.srgutils.IMappingFile; + import net.fabricmc.mappingio.format.MappingFormat; import net.fabricmc.mappingio.tree.MappingTree; import net.fabricmc.mappingio.tree.MemoryMappingTree; @@ -36,10 +38,12 @@ public static Path getResource(String slashPrefixedResourcePath) { } } - public static void writeToDir(MappingTree tree, MappingFormat format, Path dir) throws IOException { - MappingWriter writer = MappingWriter.create(dir.resolve(format.name() + "." + format.fileExt), format); + public static Path writeToDir(MappingTree tree, MappingFormat format, Path dir) throws IOException { + Path path = dir.resolve(format.name() + (format.hasSingleFile() ? "."+format.fileExt : "")); + MappingWriter writer = MappingWriter.create(path, format); tree.accept(writer); writer.close(); + return path; } // Has to be kept in sync with /resources/read/valid/* test mappings! @@ -145,6 +149,61 @@ public static MemoryMappingTree createTestTreeWithHoles() { return tree; } + public static cuchaz.enigma.translation.mapping.serde.MappingFormat toEnigmaFormat(MappingFormat format) { + switch (format) { + case TINY_FILE: + return cuchaz.enigma.translation.mapping.serde.MappingFormat.TINY_FILE; + case TINY_2_FILE: + return cuchaz.enigma.translation.mapping.serde.MappingFormat.TINY_V2; + case ENIGMA_FILE: + return cuchaz.enigma.translation.mapping.serde.MappingFormat.ENIGMA_FILE; + case ENIGMA_DIR: + return cuchaz.enigma.translation.mapping.serde.MappingFormat.ENIGMA_DIRECTORY; + case SRG_FILE: + return cuchaz.enigma.translation.mapping.serde.MappingFormat.SRG_FILE; + case PROGUARD_FILE: + return cuchaz.enigma.translation.mapping.serde.MappingFormat.PROGUARD; + default: + return null; + } + } + + public static org.cadixdev.lorenz.io.MappingFormat toLorenzFormat(MappingFormat format) { + switch (format) { + case SRG_FILE: + return org.cadixdev.lorenz.io.MappingFormats.SRG; + case TSRG_FILE: + return org.cadixdev.lorenz.io.MappingFormats.TSRG; + case ENIGMA_FILE: + return org.cadixdev.lorenz.io.MappingFormats.byId("enigma"); + default: + return null; + } + } + + public static IMappingFile.Format toSrgUtilsFormat(MappingFormat format) { + switch (format) { + case TINY_FILE: + return IMappingFile.Format.TINY1; + case TINY_2_FILE: + return IMappingFile.Format.TINY; + case SRG_FILE: + return IMappingFile.Format.SRG; + case TSRG_FILE: + return IMappingFile.Format.TSRG; + case TSRG_2_FILE: + return IMappingFile.Format.TSRG2; + case PROGUARD_FILE: + return IMappingFile.Format.PG; + case ENIGMA_FILE: + case ENIGMA_DIR: + case MCP_DIR: + return null; + default: + throw new IllegalArgumentException("Unknown format: " + format); + } + } + private static void visitClass(MemoryMappingTree tree, int... dstNs) { visitInnerClass(tree, 0, dstNs); } diff --git a/src/test/java/net/fabricmc/mappingio/write/WriteTest.java b/src/test/java/net/fabricmc/mappingio/write/WriteTest.java index 2d015650..7b833bdb 100644 --- a/src/test/java/net/fabricmc/mappingio/write/WriteTest.java +++ b/src/test/java/net/fabricmc/mappingio/write/WriteTest.java @@ -16,50 +16,128 @@ package net.fabricmc.mappingio.write; +import java.io.IOException; import java.nio.file.Path; +import java.util.HashMap; +import java.util.Map; +import cuchaz.enigma.ProgressListener; +import cuchaz.enigma.translation.mapping.serde.MappingFileNameFormat; +import cuchaz.enigma.translation.mapping.serde.MappingSaveParameters; +import net.minecraftforge.srgutils.IMappingFile; +import net.minecraftforge.srgutils.INamedMappingFile; import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.io.TempDir; +import net.fabricmc.mappingio.MappedElementKind; +import net.fabricmc.mappingio.MappingVisitor; import net.fabricmc.mappingio.TestHelper; +import net.fabricmc.mappingio.adapter.ForwardingMappingVisitor; +import net.fabricmc.mappingio.adapter.MappingNsCompleter; import net.fabricmc.mappingio.format.MappingFormat; +import net.fabricmc.mappingio.tree.MappingTree; +import net.fabricmc.mappingio.tree.MemoryMappingTree; import net.fabricmc.mappingio.tree.VisitableMappingTree; public class WriteTest { @TempDir private static Path dir; private static VisitableMappingTree tree; + private static Map treeNsAltMap = new HashMap<>(); private static VisitableMappingTree treeWithHoles; + private static Map treeWithHolesNsAltMap = new HashMap<>(); @BeforeAll public static void setup() throws Exception { tree = TestHelper.createTestTree(); + treeNsAltMap.put(tree.getDstNamespaces().get(0), tree.getSrcNamespace()); + treeNsAltMap.put(tree.getDstNamespaces().get(1), tree.getSrcNamespace()); + treeWithHoles = TestHelper.createTestTreeWithHoles(); + treeWithHolesNsAltMap.put(treeWithHoles.getDstNamespaces().get(0), treeWithHoles.getSrcNamespace()); + treeWithHolesNsAltMap.put(treeWithHoles.getDstNamespaces().get(1), treeWithHoles.getSrcNamespace()); } @Test public void enigmaFile() throws Exception { - write(MappingFormat.ENIGMA_FILE); + check(MappingFormat.ENIGMA_FILE); } @Test public void enigmaDirectory() throws Exception { - write(MappingFormat.ENIGMA_DIR); + check(MappingFormat.ENIGMA_DIR); } @Test public void tinyFile() throws Exception { - write(MappingFormat.TINY_FILE); + check(MappingFormat.TINY_FILE); } @Test public void tinyV2File() throws Exception { - write(MappingFormat.TINY_2_FILE); + check(MappingFormat.TINY_2_FILE); } - private void write(MappingFormat format) throws Exception { - TestHelper.writeToDir(tree, format, dir); - TestHelper.writeToDir(treeWithHoles, format, dir); + private void check(MappingFormat format) throws Exception { + Path path = TestHelper.writeToDir(tree, format, dir); + readWithLorenz(path, format); + readWithSrgUtils(tree, format, treeNsAltMap); + readWithEnigma(tree, format, treeNsAltMap); + + path = TestHelper.writeToDir(treeWithHoles, format, dir); + readWithLorenz(path, format); + readWithSrgUtils(treeWithHoles, format, treeWithHolesNsAltMap); + readWithEnigma(treeWithHoles, format, treeWithHolesNsAltMap); + } + + private void readWithLorenz(Path path, MappingFormat format) throws Exception { + org.cadixdev.lorenz.io.MappingFormat lorenzFormat = TestHelper.toLorenzFormat(format); + if (lorenzFormat == null) return; + lorenzFormat.read(path); + } + + private void readWithSrgUtils(MappingTree tree, MappingFormat format, Map nsAltMap) throws Exception { + IMappingFile.Format srgUtilsFormat = TestHelper.toSrgUtilsFormat(format); + if (srgUtilsFormat == null) return; + + // SrgUtils can't handle empty dst names + VisitableMappingTree dstNsCompTree = new MemoryMappingTree(); + tree.accept(new MappingNsCompleter(new Tiny2FixingVisitor(dstNsCompTree, format), nsAltMap)); + + Path path = TestHelper.writeToDir(dstNsCompTree, format, dir); + INamedMappingFile.load(path.toFile()); + } + + private void readWithEnigma(MappingTree tree, MappingFormat format, Map nsAltMap) throws Exception { + cuchaz.enigma.translation.mapping.serde.MappingFormat enigmaFormat = TestHelper.toEnigmaFormat(format); + if (enigmaFormat == null) return; + + VisitableMappingTree dstNsCompTree = new MemoryMappingTree(); + MappingVisitor visitor = new Tiny2FixingVisitor(dstNsCompTree, format); + + if (format == MappingFormat.ENIGMA_FILE || format == MappingFormat.ENIGMA_DIR) { + visitor = new MappingNsCompleter(visitor, nsAltMap); + } + + tree.accept(visitor); + Path path = TestHelper.writeToDir(dstNsCompTree, format, dir); + enigmaFormat.getReader().read(path, ProgressListener.none(), new MappingSaveParameters(MappingFileNameFormat.BY_OBF)); + } + + private class Tiny2FixingVisitor extends ForwardingMappingVisitor { + Tiny2FixingVisitor(MappingVisitor next, MappingFormat format) { + super(next); + this.format = format; + } + + @Override + public boolean visitElementContent(MappedElementKind targetKind) throws IOException { + // SrgUtil's Tiny v2 reader crashes on var sub-elements + // Enigma's Tiny v2 reader crashes on vars + return !(format == MappingFormat.TINY_2_FILE && targetKind == MappedElementKind.METHOD_VAR); + } + + private final MappingFormat format; } }