From 26acb56fb542d762905188c1086cd269daf78695 Mon Sep 17 00:00:00 2001 From: Sebastian Hartte Date: Sat, 30 Dec 2023 21:21:27 +0100 Subject: [PATCH] Support Sugarcane data files by support differently named JSON files at the root of a Parchment ZIP-File. --- build.gradle | 6 - parchment/build.gradle | 7 ++ .../parchment/ParchmentDatabase.java | 22 ++++ .../parchment/ParchmentDatabaseTest.java | 105 ++++++++++++++++++ 4 files changed, 134 insertions(+), 6 deletions(-) create mode 100644 parchment/src/test/java/net/neoforged/jst/parchment/namesanddocs/parchment/ParchmentDatabaseTest.java diff --git a/build.gradle b/build.gradle index 736940d..d84659d 100644 --- a/build.gradle +++ b/build.gradle @@ -12,12 +12,6 @@ project.version = gradleutils.version println "Version ${project.version}" -allprojects { - java.toolchain { - languageVersion = JavaLanguageVersion.of(17) - } -} - subprojects { group = rootProject.group version = rootProject.version diff --git a/parchment/build.gradle b/parchment/build.gradle index e9ed8d7..8b365c0 100644 --- a/parchment/build.gradle +++ b/parchment/build.gradle @@ -6,4 +6,11 @@ dependencies { implementation project(":api") implementation 'org.parchmentmc.feather:io-gson:1.1.0' implementation 'net.neoforged:srgutils:1.0.0' + + testImplementation platform("org.junit:junit-bom:$junit_version") + testImplementation 'org.junit.jupiter:junit-jupiter' +} + +test { + useJUnitPlatform() } diff --git a/parchment/src/main/java/net/neoforged/jst/parchment/namesanddocs/parchment/ParchmentDatabase.java b/parchment/src/main/java/net/neoforged/jst/parchment/namesanddocs/parchment/ParchmentDatabase.java index 799f181..26790e8 100644 --- a/parchment/src/main/java/net/neoforged/jst/parchment/namesanddocs/parchment/ParchmentDatabase.java +++ b/parchment/src/main/java/net/neoforged/jst/parchment/namesanddocs/parchment/ParchmentDatabase.java @@ -16,6 +16,7 @@ import java.nio.charset.StandardCharsets; import java.nio.file.Files; import java.nio.file.Path; +import java.util.zip.ZipEntry; import java.util.zip.ZipFile; public class ParchmentDatabase implements NamesAndDocsDatabase { @@ -38,6 +39,10 @@ public NamesAndDocsForClass getClass(String className) { public static ParchmentDatabase loadZip(Path parchmentFile) throws IOException { try (var zf = new ZipFile(parchmentFile.toFile())) { var parchmentJsonEntry = zf.getEntry("parchment.json"); + if (parchmentJsonEntry == null) { + parchmentJsonEntry = findFallbackEntryJson(parchmentFile, zf); + } + if (parchmentJsonEntry == null || parchmentJsonEntry.isDirectory()) { throw new FileNotFoundException("Could not locate parchment.json at the root of ZIP-File " + parchmentFile); } @@ -48,6 +53,23 @@ public static ParchmentDatabase loadZip(Path parchmentFile) throws IOException { } } + private static ZipEntry findFallbackEntryJson(Path parchmentFile, ZipFile zf) throws FileNotFoundException { + // Fall back to any JSON file in the root if there is only one. + var entries = zf.entries().asIterator(); + ZipEntry parchmentJsonEntry = null; + while (entries.hasNext()) { + var entry = entries.next(); + if (!entry.getName().contains("/") && entry.getName().endsWith(".json")) { + if (parchmentJsonEntry != null) { + throw new FileNotFoundException("Could not locate parchment.json at the root of ZIP-File " + parchmentFile + + " and there are multiple other JSON files present in the root."); + } + parchmentJsonEntry = entry; + } + } + return parchmentJsonEntry; + } + public static ParchmentDatabase loadJson(Path parchmentFile) throws IOException { try (var reader = Files.newBufferedReader(parchmentFile)) { return loadJson(reader); diff --git a/parchment/src/test/java/net/neoforged/jst/parchment/namesanddocs/parchment/ParchmentDatabaseTest.java b/parchment/src/test/java/net/neoforged/jst/parchment/namesanddocs/parchment/ParchmentDatabaseTest.java new file mode 100644 index 0000000..ba19acd --- /dev/null +++ b/parchment/src/test/java/net/neoforged/jst/parchment/namesanddocs/parchment/ParchmentDatabaseTest.java @@ -0,0 +1,105 @@ +package net.neoforged.jst.parchment.namesanddocs.parchment; + +import org.intellij.lang.annotations.Language; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.io.TempDir; + +import java.io.FileNotFoundException; +import java.io.IOException; +import java.io.StringReader; +import java.nio.charset.StandardCharsets; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.Map; +import java.util.zip.ZipEntry; +import java.util.zip.ZipOutputStream; + +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertThrows; + +class ParchmentDatabaseTest { + // A minimal Parchment JSON to validate that it loaded *something* + @Language("JSON") + private static final String EXAMPLE_JSON = """ + { + "version": "1.1.0", + "classes": [ + { + "name": "TestClass" + } + ] + } + """; + + @TempDir + Path tempDir; + + @Test + void testLoadFromJsonReader() { + var db = ParchmentDatabase.loadJson(new StringReader(EXAMPLE_JSON)); + assertNotNull(db.getClass("TestClass")); + } + + @Test + void testLoadFromJsonFile() throws IOException { + var tempFile = tempDir.resolve("test.json"); + Files.writeString(tempFile, EXAMPLE_JSON); + + var db = ParchmentDatabase.loadJson(tempFile); + assertNotNull(db.getClass("TestClass")); + } + + @Test + void testLoadFromZipWithParchmentJson() throws IOException { + var tempFile = tempDir.resolve("temp.zip"); + writeZip(tempFile, Map.of( + "unrelated/parchment.json", "INVALID", + "parchment.json", EXAMPLE_JSON + )); + + var db = ParchmentDatabase.loadZip(tempFile); + assertNotNull(db.getClass("TestClass")); + } + + @Test + void testLoadFromZipWithOtherJson() throws IOException { + var tempFile = tempDir.resolve("temp.zip"); + writeZip(tempFile, Map.of( + "unrelated/parchment.json", "INVALID", + "other.json", EXAMPLE_JSON + )); + + var db = ParchmentDatabase.loadZip(tempFile); + assertNotNull(db.getClass("TestClass")); + } + + @Test + void testLoadFromZipWithMultipleOtherJson() throws IOException { + var tempFile = tempDir.resolve("temp.zip"); + writeZip(tempFile, Map.of( + "unrelated/parchment.json", "INVALID", + "other.json", EXAMPLE_JSON, + "yet_another_json.json", EXAMPLE_JSON + )); + + assertThrows(FileNotFoundException.class, () -> ParchmentDatabase.loadZip(tempFile)); + } + + @Test + void testLoadFromEmptyZip() throws IOException { + var tempFile = tempDir.resolve("temp.zip"); + writeZip(tempFile, Map.of()); + + assertThrows(FileNotFoundException.class, () -> ParchmentDatabase.loadZip(tempFile)); + } + + private static void writeZip(Path tempFile, Map entries) throws IOException { + try (var zf = new ZipOutputStream(Files.newOutputStream(tempFile))) { + for (var entry : entries.entrySet()) { + zf.putNextEntry(new ZipEntry(entry.getKey())); + zf.write(entry.getValue().getBytes(StandardCharsets.UTF_8)); + zf.closeEntry(); + } + } + } +}