diff options
| author | Michael Williamson <mike@zwobble.org> | 2026-06-12 11:41:56 +0100 |
|---|---|---|
| committer | Michael Williamson <mike@zwobble.org> | 2026-06-12 11:41:56 +0100 |
| commit | 4455f5d14c3f80d13758f10e726e422d183b5f31 (patch) | |
| tree | 9ffa8f92bf29042c9a9f0a6f2c186c453b9c8d6b /src/test | |
| parent | 99ab27fa29de27fc4dfe26eda4de070a83101b25 (diff) | |
Skip running example if example is unchanged
Diffstat (limited to 'src/test')
| -rw-r--r-- | src/test/java/org/zwobble/hobgoblin/compiler/ExampleTests.java | 114 |
1 files changed, 108 insertions, 6 deletions
diff --git a/src/test/java/org/zwobble/hobgoblin/compiler/ExampleTests.java b/src/test/java/org/zwobble/hobgoblin/compiler/ExampleTests.java index fd38a84..999ae83 100644 --- a/src/test/java/org/zwobble/hobgoblin/compiler/ExampleTests.java +++ b/src/test/java/org/zwobble/hobgoblin/compiler/ExampleTests.java @@ -5,7 +5,12 @@ import org.junit.jupiter.api.TestFactory; import org.zwobble.hobgoblin.compiler.testing.TestProcessRunner; import java.io.IOException; -import java.util.List; +import java.nio.charset.StandardCharsets; +import java.nio.file.*; +import java.nio.file.attribute.BasicFileAttributes; +import java.security.MessageDigest; +import java.security.NoSuchAlgorithmException; +import java.util.*; import java.util.stream.Stream; public class ExampleTests { @@ -18,14 +23,111 @@ public class ExampleTests { )); } - private void runTest(ExampleSet exampleSet) throws IOException, InterruptedException { + private void runTest(ExampleSet exampleSet) throws IOException, InterruptedException, NoSuchAlgorithmException { var javaProjectPath = exampleSet.path().resolve("output/java"); HobgoblinCompiler.compile(exampleSet.path()); - TestProcessRunner.command(List.of("mvn", "compile")) - .cwd(javaProjectPath) - .runCaptureOutput() - .throwOnError(); + var currentHash = hashJavaProject(javaProjectPath); + + var lastTestRunPath = javaProjectPath.resolve("last-test-run.properties"); + var lastTestRun = readLastTestRun(lastTestRunPath); + + if (lastTestRun.isPresent() && lastTestRun.get().pass && lastTestRun.get().hash.equals(currentHash)) { + return; + } + + try { + TestProcessRunner.command(List.of("mvn", "compile")) + .cwd(javaProjectPath) + .runCaptureOutput() + .throwOnError(); + writeLastTestRun(lastTestRunPath, new LastTestRun(currentHash, true)); + } catch (Throwable exception) { + writeLastTestRun(lastTestRunPath, new LastTestRun(currentHash, false)); + throw exception; + } + } + + private record LastTestRun(String hash, boolean pass) {} + + private Optional<LastTestRun> readLastTestRun(Path path) throws IOException { + var properties = new Properties(); + try (var reader = Files.newBufferedReader(path)) { + properties.load(reader); + var hash = properties.getProperty("hash"); + var pass = properties.getProperty("result").equals("PASS"); + return Optional.of(new LastTestRun(hash, pass)); + } catch (NoSuchFileException exception) { + return Optional.empty(); + } + } + + private void writeLastTestRun(Path path, LastTestRun lastTestRun) throws IOException { + var properties = new Properties(); + properties.setProperty("hash", lastTestRun.hash); + properties.setProperty("result", lastTestRun.pass ? "PASS" : "FAIL"); + try (var writer = Files.newBufferedWriter(path)) { + properties.store(writer, null); + } + } + + private String hashJavaProject(Path javaProjectPath) throws NoSuchAlgorithmException, IOException { + var paths = collectJavaProjectSourcePaths(javaProjectPath); + + var digest = MessageDigest.getInstance("sha256"); + + for (var path : paths) { + digest.update(path.toString().getBytes(StandardCharsets.UTF_8)); + digest.update(new byte[]{0}); + var contents = Files.readAllBytes(path); + digest.update(contents); + digest.update(new byte[]{0}); + } + + return bytesToHex(digest.digest()); + } + + private static String bytesToHex(byte[] bytes) { + var hexString = new StringBuilder(2 * bytes.length); + for (var b : bytes) { + var hex = Integer.toHexString(0xff & b); + if (hex.length() == 1) { + hexString.append('0'); + } + hexString.append(hex); + } + return hexString.toString(); + } + + private static List<Path> collectJavaProjectSourcePaths(Path javaProjectPath) throws IOException { + var paths = new ArrayList<Path>(); + + Files.walkFileTree( + javaProjectPath, new SimpleFileVisitor<>() { + @Override + public FileVisitResult visitFile( + Path file, + BasicFileAttributes attrs + ) { + if (!javaProjectPath.relativize(file).toString().equals("last-test-run.properties")) { + paths.add(file); + } + return FileVisitResult.CONTINUE; + } + + @Override + public FileVisitResult preVisitDirectory(Path dir, BasicFileAttributes attrs) throws IOException { + if (javaProjectPath.relativize(dir).startsWith("target")) { + return FileVisitResult.SKIP_SUBTREE; + } else { + return FileVisitResult.CONTINUE; + } + } + }); + + paths.sort(Comparator.naturalOrder()); + + return paths; } } |
