fix: add JUnit5 dependency, new tests, StaticResource cleanup
Build & Deploy / build-and-deploy (push) Failing after 30s
Build & Deploy / build-and-deploy (push) Failing after 30s
- Added quarkus-junit5 test dependency (was missing — caused assertNull failures) - ExecutableDetectorTest: 12 tests (findAll, findMain prioritization, extender/sfx skip, setup detection) - CdImageServiceTest: 7 tests (findInDirectory, fixCueReferences, findInBundle) - ConfigPatcherTest: 8 tests (path rewriting, non-C drive skip, binary/large file skip, unix paths) - StaticResource: removed unused content types (.html/.js/.css/.conf/.txt)
This commit is contained in:
@@ -51,6 +51,12 @@
|
|||||||
<groupId>io.quarkus</groupId>
|
<groupId>io.quarkus</groupId>
|
||||||
<artifactId>quarkus-arc</artifactId>
|
<artifactId>quarkus-arc</artifactId>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
<!-- Test -->
|
||||||
|
<dependency>
|
||||||
|
<groupId>io.quarkus</groupId>
|
||||||
|
<artifactId>quarkus-junit5</artifactId>
|
||||||
|
<scope>test</scope>
|
||||||
|
</dependency>
|
||||||
</dependencies>
|
</dependencies>
|
||||||
|
|
||||||
<build>
|
<build>
|
||||||
|
|||||||
@@ -72,11 +72,7 @@ public class StaticResource {
|
|||||||
if (n.endsWith(".png")) return "image/png";
|
if (n.endsWith(".png")) return "image/png";
|
||||||
if (n.endsWith(".webp")) return "image/webp";
|
if (n.endsWith(".webp")) return "image/webp";
|
||||||
if (n.endsWith(".gif")) return "image/gif";
|
if (n.endsWith(".gif")) return "image/gif";
|
||||||
if (n.endsWith(".conf") || n.endsWith(".txt")) return "text/plain";
|
|
||||||
if (n.endsWith(".json")) return "application/json";
|
if (n.endsWith(".json")) return "application/json";
|
||||||
if (n.endsWith(".html")) return "text/html";
|
|
||||||
if (n.endsWith(".js")) return "application/javascript";
|
|
||||||
if (n.endsWith(".css")) return "text/css";
|
|
||||||
return MediaType.APPLICATION_OCTET_STREAM;
|
return MediaType.APPLICATION_OCTET_STREAM;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,103 @@
|
|||||||
|
package com.dostalgia;
|
||||||
|
|
||||||
|
import static org.junit.jupiter.api.Assertions.*;
|
||||||
|
import org.junit.jupiter.api.Test;
|
||||||
|
import org.junit.jupiter.api.io.TempDir;
|
||||||
|
|
||||||
|
import java.nio.file.Files;
|
||||||
|
import java.nio.file.Path;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
class CdImageServiceTest {
|
||||||
|
|
||||||
|
private final CdImageService service = new CdImageService();
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void findInDirectory_findsAllCdFormats(@TempDir Path dir) throws Exception {
|
||||||
|
Files.writeString(dir.resolve("game.cue"), "FILE \"game.bin\" BINARY");
|
||||||
|
Files.writeString(dir.resolve("game.bin"), "data");
|
||||||
|
Files.writeString(dir.resolve("game.iso"), "iso");
|
||||||
|
Files.writeString(dir.resolve("readme.txt"), "text");
|
||||||
|
|
||||||
|
List<String> result = service.findInDirectory(dir);
|
||||||
|
assertEquals(3, result.size());
|
||||||
|
assertTrue(result.contains("game.bin"));
|
||||||
|
assertTrue(result.contains("game.cue"));
|
||||||
|
assertTrue(result.contains("game.iso"));
|
||||||
|
assertFalse(result.contains("readme.txt"));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void findInDirectory_emptyDir(@TempDir Path dir) throws Exception {
|
||||||
|
assertTrue(service.findInDirectory(dir).isEmpty());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void findInDirectory_caseInsensitive(@TempDir Path dir) throws Exception {
|
||||||
|
Files.writeString(dir.resolve("GAME.CUE"), "data");
|
||||||
|
Files.writeString(dir.resolve("GAME.ISO"), "data");
|
||||||
|
List<String> result = service.findInDirectory(dir);
|
||||||
|
assertEquals(2, result.size());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void fixCueReferences_rewritesNonexistentReference(@TempDir Path dir) throws Exception {
|
||||||
|
// CUE references game.bin, but only game.img exists
|
||||||
|
Files.writeString(dir.resolve("game.cue"), "FILE \"game.bin\" BINARY\n TRACK 01 MODE1/2352\n INDEX 01 00:00:00");
|
||||||
|
Files.writeString(dir.resolve("game.img"), "data");
|
||||||
|
|
||||||
|
service.fixCueReferences(dir);
|
||||||
|
|
||||||
|
String fixed = Files.readString(dir.resolve("game.cue"));
|
||||||
|
assertTrue(fixed.contains("game.img"), "Should reference existing .img file");
|
||||||
|
assertFalse(fixed.contains("game.bin"), "Should no longer reference missing .bin");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void fixCueReferences_skipsWhenExists(@TempDir Path dir) throws Exception {
|
||||||
|
// CUE references game.bin — and it exists, so no change
|
||||||
|
String original = "FILE \"game.bin\" BINARY\n TRACK 01 MODE1/2352\n INDEX 01 00:00:00";
|
||||||
|
Files.writeString(dir.resolve("game.cue"), original);
|
||||||
|
Files.writeString(dir.resolve("game.bin"), "data");
|
||||||
|
|
||||||
|
service.fixCueReferences(dir);
|
||||||
|
|
||||||
|
assertEquals(original, Files.readString(dir.resolve("game.cue")).trim());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void fixCueReferences_noFileLine_noChange(@TempDir Path dir) throws Exception {
|
||||||
|
String original = "TITLE \"Test Game\"\nTRACK 01 MODE1/2352";
|
||||||
|
Files.writeString(dir.resolve("game.cue"), original);
|
||||||
|
|
||||||
|
service.fixCueReferences(dir);
|
||||||
|
|
||||||
|
assertEquals(original, Files.readString(dir.resolve("game.cue")).trim());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void findInBundle_findsCdImages(@TempDir Path dir) throws Exception {
|
||||||
|
// Create a test bundle with CD images and regular files
|
||||||
|
Path bundle = dir.resolve("test.jsdos");
|
||||||
|
try (var zos = new java.util.zip.ZipOutputStream(Files.newOutputStream(bundle))) {
|
||||||
|
zos.putNextEntry(new java.util.zip.ZipEntry("game.cue"));
|
||||||
|
zos.write("cue data".getBytes());
|
||||||
|
zos.closeEntry();
|
||||||
|
zos.putNextEntry(new java.util.zip.ZipEntry("game.iso"));
|
||||||
|
zos.write("iso data".getBytes());
|
||||||
|
zos.closeEntry();
|
||||||
|
zos.putNextEntry(new java.util.zip.ZipEntry("readme.txt"));
|
||||||
|
zos.write("text".getBytes());
|
||||||
|
zos.closeEntry();
|
||||||
|
zos.putNextEntry(new java.util.zip.ZipEntry("subdir/game.img"));
|
||||||
|
zos.write("img".getBytes());
|
||||||
|
zos.closeEntry();
|
||||||
|
}
|
||||||
|
|
||||||
|
List<String> result = service.findInBundle(bundle);
|
||||||
|
assertEquals(3, result.size());
|
||||||
|
assertTrue(result.contains("game.cue"));
|
||||||
|
assertTrue(result.contains("game.iso"));
|
||||||
|
assertTrue(result.contains("subdir/game.img"));
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,109 @@
|
|||||||
|
package com.dostalgia;
|
||||||
|
|
||||||
|
import static org.junit.jupiter.api.Assertions.*;
|
||||||
|
import org.junit.jupiter.api.Test;
|
||||||
|
import org.junit.jupiter.api.io.TempDir;
|
||||||
|
|
||||||
|
import java.nio.charset.StandardCharsets;
|
||||||
|
import java.nio.file.Files;
|
||||||
|
import java.nio.file.Path;
|
||||||
|
|
||||||
|
class ConfigPatcherTest {
|
||||||
|
|
||||||
|
private final ConfigPatcher patcher = new ConfigPatcher();
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void fixAbsolutePaths_rewritesStalePrefix(@TempDir Path dir) throws Exception {
|
||||||
|
// Create a file that references C:\FALLOUT1\MASTER.DAT
|
||||||
|
// but after flattening, MASTER.DAT is at the root
|
||||||
|
String content = "master_dat=C:\\FALLOUT1\\MASTER.DAT\ncritter_dat=C:\\FALLOUT1\\CRITTER.DAT\n";
|
||||||
|
Files.writeString(dir.resolve("FALLOUT.CFG"), content, StandardCharsets.ISO_8859_1);
|
||||||
|
|
||||||
|
// The referenced files exist at root
|
||||||
|
Files.writeString(dir.resolve("MASTER.DAT"), "data");
|
||||||
|
Files.writeString(dir.resolve("CRITTER.DAT"), "data");
|
||||||
|
|
||||||
|
patcher.fixAbsolutePaths(dir);
|
||||||
|
|
||||||
|
String fixed = Files.readString(dir.resolve("FALLOUT.CFG"), StandardCharsets.ISO_8859_1);
|
||||||
|
assertTrue(fixed.contains(".\\MASTER.DAT"), "Should rewrite to relative path");
|
||||||
|
assertTrue(fixed.contains(".\\CRITTER.DAT"), "Both files should be rewritten");
|
||||||
|
assertFalse(fixed.contains("FALLOUT1"), "Stale prefix should be removed");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void fixAbsolutePaths_leavesNonCDrives(@TempDir Path dir) throws Exception {
|
||||||
|
// D: drive references are CD-ROM — should stay
|
||||||
|
String content = "cd_path=D:\\GAMEDATA\\SOUND.DAT\n";
|
||||||
|
Files.writeString(dir.resolve("config.ini"), content, StandardCharsets.ISO_8859_1);
|
||||||
|
|
||||||
|
patcher.fixAbsolutePaths(dir);
|
||||||
|
|
||||||
|
String fixed = Files.readString(dir.resolve("config.ini"), StandardCharsets.ISO_8859_1);
|
||||||
|
assertEquals(content.trim(), fixed.trim(), "D: references should be preserved");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void fixAbsolutePaths_leavesValidPaths(@TempDir Path dir) throws Exception {
|
||||||
|
// Path exists with full structure — should stay as-is
|
||||||
|
Path sub = Files.createDirectory(dir.resolve("VALIDDIR"));
|
||||||
|
Files.writeString(sub.resolve("file.dat"), "data");
|
||||||
|
|
||||||
|
String content = "data=C:\\VALIDDIR\\file.dat\n";
|
||||||
|
Files.writeString(dir.resolve("config.ini"), content, StandardCharsets.ISO_8859_1);
|
||||||
|
|
||||||
|
patcher.fixAbsolutePaths(dir);
|
||||||
|
|
||||||
|
String fixed = Files.readString(dir.resolve("config.ini"), StandardCharsets.ISO_8859_1);
|
||||||
|
assertEquals(content.trim(), fixed.trim(), "Valid full paths should be preserved");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void fixAbsolutePaths_skipsNonTextFiles(@TempDir Path dir) throws Exception {
|
||||||
|
// Binary file with null bytes — should not be processed
|
||||||
|
byte[] binary = new byte[200];
|
||||||
|
binary[0] = 'C';
|
||||||
|
binary[1] = ':';
|
||||||
|
binary[2] = '\\';
|
||||||
|
binary[3] = 'D';
|
||||||
|
binary[10] = 0; // null byte makes it "not text"
|
||||||
|
Files.write(dir.resolve("binary.dat"), binary);
|
||||||
|
|
||||||
|
// Should not throw or modify binary files
|
||||||
|
assertDoesNotThrow(() -> patcher.fixAbsolutePaths(dir));
|
||||||
|
|
||||||
|
byte[] result = Files.readAllBytes(dir.resolve("binary.dat"));
|
||||||
|
assertArrayEquals(binary, result, "Binary file should be unchanged");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void fixAbsolutePaths_skipsLargeFiles(@TempDir Path dir) throws Exception {
|
||||||
|
// File > 100KB should be skipped
|
||||||
|
byte[] large = new byte[101 * 1024];
|
||||||
|
large[0] = 'C';
|
||||||
|
large[1] = ':';
|
||||||
|
large[2] = '\\';
|
||||||
|
Files.write(dir.resolve("large.cfg"), large);
|
||||||
|
|
||||||
|
// Should not throw
|
||||||
|
assertDoesNotThrow(() -> patcher.fixAbsolutePaths(dir));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void fixAbsolutePaths_emptyDir_noError(@TempDir Path dir) {
|
||||||
|
assertDoesNotThrow(() -> patcher.fixAbsolutePaths(dir));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void fixAbsolutePaths_unixStylePath(@TempDir Path dir) throws Exception {
|
||||||
|
// Some games use forward slashes: C:/GAME/DATA
|
||||||
|
String content = "path=C:/MYGAME/DATA.DAT\n";
|
||||||
|
Files.writeString(dir.resolve("config.cfg"), content, StandardCharsets.ISO_8859_1);
|
||||||
|
Files.writeString(dir.resolve("DATA.DAT"), "data");
|
||||||
|
|
||||||
|
patcher.fixAbsolutePaths(dir);
|
||||||
|
|
||||||
|
String fixed = Files.readString(dir.resolve("config.cfg"), StandardCharsets.ISO_8859_1);
|
||||||
|
assertTrue(fixed.contains("./DATA.DAT"), "Forward-slash paths should be fixed");
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,136 @@
|
|||||||
|
package com.dostalgia;
|
||||||
|
|
||||||
|
import static org.junit.jupiter.api.Assertions.*;
|
||||||
|
import org.junit.jupiter.api.Test;
|
||||||
|
import org.junit.jupiter.api.io.TempDir;
|
||||||
|
|
||||||
|
import java.nio.file.Files;
|
||||||
|
import java.nio.file.Path;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
class ExecutableDetectorTest {
|
||||||
|
|
||||||
|
private final ExecutableDetector detector = new ExecutableDetector();
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void findAll_findsExeComBat(@TempDir Path dir) throws Exception {
|
||||||
|
Files.writeString(dir.resolve("GAME.EXE"), "MZ");
|
||||||
|
Files.writeString(dir.resolve("helper.com"), "MZ");
|
||||||
|
Files.writeString(dir.resolve("run.bat"), "@echo off");
|
||||||
|
Files.writeString(dir.resolve("readme.txt"), "text"); // should NOT be found
|
||||||
|
|
||||||
|
List<String> result = detector.findAll(dir);
|
||||||
|
assertEquals(3, result.size());
|
||||||
|
assertTrue(result.contains("GAME.EXE"));
|
||||||
|
assertTrue(result.contains("helper.com"));
|
||||||
|
assertTrue(result.contains("run.bat"));
|
||||||
|
assertFalse(result.contains("readme.txt"));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void findMain_prefersLargestNonInstaller(@TempDir Path dir) throws Exception {
|
||||||
|
// Small installer
|
||||||
|
Files.write(dir.resolve("INSTALL.EXE"), createMZ(100));
|
||||||
|
// Large real game
|
||||||
|
Files.write(dir.resolve("GAME.EXE"), createMZ(5000));
|
||||||
|
|
||||||
|
String main = detector.findMain(dir);
|
||||||
|
assertEquals(dir.resolve("GAME.EXE").toString(), main);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void findMain_skipsExtenders(@TempDir Path dir) throws Exception {
|
||||||
|
Files.write(dir.resolve("DOS4GW.EXE"), createMZ(200));
|
||||||
|
Files.write(dir.resolve("GAME.EXE"), createMZ(1000));
|
||||||
|
|
||||||
|
String main = detector.findMain(dir);
|
||||||
|
assertEquals(dir.resolve("GAME.EXE").toString(), main);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void findMain_skipsSelfExtractors(@TempDir Path dir) throws Exception {
|
||||||
|
byte[] sfx = createMZ(500);
|
||||||
|
// Embed PKSFX string
|
||||||
|
String content = new String(sfx);
|
||||||
|
int pos = content.indexOf("MZ") + 2;
|
||||||
|
byte[] withSfx = new byte[sfx.length + 20];
|
||||||
|
System.arraycopy(sfx, 0, withSfx, 0, sfx.length);
|
||||||
|
byte[] pksfx = "PKSFX".getBytes();
|
||||||
|
System.arraycopy(pksfx, 0, withSfx, pos, pksfx.length);
|
||||||
|
Files.write(dir.resolve("GAME.EXE"), withSfx);
|
||||||
|
Files.write(dir.resolve("REAL.EXE"), createMZ(2000));
|
||||||
|
|
||||||
|
String main = detector.findMain(dir);
|
||||||
|
assertEquals(dir.resolve("REAL.EXE").toString(), main);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void findMain_emptyDir_returnsNull(@TempDir Path dir) {
|
||||||
|
assertNull(detector.findMain(dir));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void findMain_subdirectoryDeprioritized(@TempDir Path dir) throws Exception {
|
||||||
|
// Root-level large exe
|
||||||
|
Files.write(dir.resolve("GAME.EXE"), createMZ(1000));
|
||||||
|
// Subdirectory exe (should be deprioritized even if larger)
|
||||||
|
Path sub = Files.createDirectory(dir.resolve("SUBDIR"));
|
||||||
|
Files.write(sub.resolve("OTHER.EXE"), createMZ(2000));
|
||||||
|
|
||||||
|
String main = detector.findMain(dir);
|
||||||
|
assertEquals(dir.resolve("GAME.EXE").toString(), main);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void findSetup_findsSetupExe(@TempDir Path dir) throws Exception {
|
||||||
|
Files.writeString(dir.resolve("SETUP.EXE"), "MZ");
|
||||||
|
Files.writeString(dir.resolve("GAME.EXE"), "MZ");
|
||||||
|
|
||||||
|
String setup = detector.findSetup(dir);
|
||||||
|
assertEquals(dir.resolve("SETUP.EXE").toString(), setup);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void findSetup_findsInstallBat(@TempDir Path dir) throws Exception {
|
||||||
|
Files.writeString(dir.resolve("INSTALL.BAT"), "@echo off");
|
||||||
|
|
||||||
|
String setup = detector.findSetup(dir);
|
||||||
|
assertEquals(dir.resolve("INSTALL.BAT").toString(), setup);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void findSetup_noSetup_returnsNull(@TempDir Path dir) throws Exception {
|
||||||
|
Files.writeString(dir.resolve("GAME.EXE"), "MZ");
|
||||||
|
assertNull(detector.findSetup(dir));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void isLikelySelfExtractor_detectsPKSFX(@TempDir Path dir) throws Exception {
|
||||||
|
byte[] buf = new byte[1000];
|
||||||
|
buf[0] = 0x4D; // M
|
||||||
|
buf[1] = 0x5A; // Z
|
||||||
|
byte[] pksfx = "PKSFX".getBytes();
|
||||||
|
System.arraycopy(pksfx, 0, buf, 10, pksfx.length);
|
||||||
|
|
||||||
|
Path f = dir.resolve("sfx.exe");
|
||||||
|
Files.write(f, buf);
|
||||||
|
assertTrue(ExecutableDetector.isLikelySelfExtractor(f));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void isLikelySelfExtractor_plainExe_returnsFalse(@TempDir Path dir) throws Exception {
|
||||||
|
byte[] buf = createMZ(500);
|
||||||
|
Path f = dir.resolve("game.exe");
|
||||||
|
Files.write(f, buf);
|
||||||
|
assertFalse(ExecutableDetector.isLikelySelfExtractor(f));
|
||||||
|
}
|
||||||
|
|
||||||
|
// ─── helpers ─────────────────────────────────────────────────
|
||||||
|
|
||||||
|
private static byte[] createMZ(int size) {
|
||||||
|
byte[] buf = new byte[size];
|
||||||
|
buf[0] = 0x4D; // M
|
||||||
|
buf[1] = 0x5A; // Z
|
||||||
|
return buf;
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user