From 111675890264cbf9d32ea60494fd1686bd242c51 Mon Sep 17 00:00:00 2001 From: Naofal Date: Sat, 29 Mar 2025 00:33:44 +0300 Subject: [PATCH] Add test snapshot utility --- Build.java | 6 +-- nobuild/NoBuild.java | 1 - src/test/java/TestJtags.java | 20 +++----- src/test/java/notest/Test.java | 51 +++++++++++++++++++ ...asicExample.1 => TestJtags.basicExample.1} | 6 +-- 5 files changed, 63 insertions(+), 21 deletions(-) rename src/test/java/snapshots/{BasicExample.basicExample.1 => TestJtags.basicExample.1} (63%) diff --git a/Build.java b/Build.java index ab6a191..d395e65 100644 --- a/Build.java +++ b/Build.java @@ -63,7 +63,7 @@ public class Build { case "test": buildJtags(mainClass, sourcePaths, classPaths); - runTests(); + runTests(arguments.toArray(String[]::new)); break; default: @@ -96,7 +96,7 @@ public class Build { "."); } - static void runTests() { + static void runTests(String[] args) { String mainClass = "TestJtags"; String[] sourcePaths = glob("src/test/java/**.java"); @@ -107,6 +107,6 @@ public class Build { } } - System.exit(runJava(new String[0], new String[] {"-enableassertions"}, mainClass)); + System.exit(runJava(new String[0], new String[] {"-enableassertions"}, mainClass, args)); } } diff --git a/nobuild/NoBuild.java b/nobuild/NoBuild.java index f335aa7..cfe3ae7 100644 --- a/nobuild/NoBuild.java +++ b/nobuild/NoBuild.java @@ -33,7 +33,6 @@ import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; -import java.lang.ProcessBuilder.Redirect; import java.net.URI; import java.net.URL; import java.nio.file.FileSystems; diff --git a/src/test/java/TestJtags.java b/src/test/java/TestJtags.java index 837d121..f724131 100644 --- a/src/test/java/TestJtags.java +++ b/src/test/java/TestJtags.java @@ -1,9 +1,6 @@ import static notest.Test.Util.*; -import java.io.BufferedReader; -import java.io.FileReader; import java.io.IOException; -import java.nio.file.Path; import notest.Test; class TestJtags { @@ -17,19 +14,14 @@ class TestJtags { static void basicExample() throws IOException { var process = runJava( - new String[] {"-Dlogger.level=CONFIG"}, - Jtags, - "-o", - "-", - "src/test/java/examples/BasicExample.java"); + new String[] {"-Dlogger.level=CONFIG"}, + Jtags, + "-o", + "-", + "src/test/java/examples/BasicExample.java"); var tags = readAllLines(process.inputReader()); - Diff.diff( - tags, - readAllLines(new BufferedReader(new FileReader( - Path.of("src", "test", "java", "snapshots", "BasicExample.basicExample.1") - .toFile())))) - .assertEqual(); + getSnapshot().assertEquals(tags); } } diff --git a/src/test/java/notest/Test.java b/src/test/java/notest/Test.java index a6ee9a0..71adcc0 100644 --- a/src/test/java/notest/Test.java +++ b/src/test/java/notest/Test.java @@ -39,10 +39,13 @@ import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.PathMatcher; import java.nio.file.Paths; +import java.util.ArrayDeque; import java.util.ArrayList; import java.util.Arrays; +import java.util.HashMap; import java.util.IntSummaryStatistics; import java.util.List; +import java.util.Map; import java.util.Optional; import java.util.stream.Collectors; import java.util.stream.Stream; @@ -57,9 +60,27 @@ public @interface Test { public static Path javaHome = Paths.get(System.getProperty("java.home")); public static String javaClassPath = System.getProperty("java.class.path"); public static String javaBin = javaHome.resolve("bin", "java").toString(); + public static Path snapshotsPath = Path.of("src", "test", "java", "snapshots"); + + private static class Options { + boolean updateSnapshots = false; + } + + private static Options options = new Options(); /** Runs all tests in {@code testClass} */ public static void runTests(Class testClass, String[] args) { + var arguments = new ArrayDeque(Arrays.asList(args)); + + switch (arguments.poll()) { + case "-u", "-update-snapshots": + options.updateSnapshots = true; + break; + case null: + default: + break; + } + System.exit(doRunTests(testClass) ? 0 : 1); } @@ -173,6 +194,11 @@ public @interface Test { /** Creates a {@code Diff} representing changes from {@code a} to {@code b} */ public static Diff diff(List a, List b) { + if (a.equals(b)) return new Diff(List.of()); + + if (a.isEmpty()) a = List.of(""); + if (b.isEmpty()) b = List.of(""); + int diffSize = 0; // longest common subsequence algorithm int[][] dp = new int[a.size() + 1][b.size() + 1]; @@ -251,6 +277,31 @@ public @interface Test { return lines; } + public static record Snapshot(Path path) { + public void assertEquals(List result) throws IOException { + var lines = Files.readAllLines(path); + if (options.updateSnapshots && !lines.equals(result)) { + Files.write(path, result); + return; + } + Diff.diff(lines, result).assertEqual(); + } + } + + private static Map snapshotCount = new HashMap<>(); + + public static Snapshot getSnapshot() throws IOException { + var stackFrame = new Throwable().getStackTrace()[1]; + var className = stackFrame.getClassName(); + var methodName = stackFrame.getMethodName(); + var prefix = className + "." + methodName; + var snapshotNumber = snapshotCount.compute(prefix, (k, v) -> v == null ? 1 : ++v); + Path path = snapshotsPath.resolve(prefix + "." + snapshotNumber); + if (!snapshotsPath.toFile().exists()) snapshotsPath.toFile().mkdirs(); + if (!path.toFile().exists()) Files.write(path, List.of()); + return new Snapshot(path); + } + /** * Pads string to center. * diff --git a/src/test/java/snapshots/BasicExample.basicExample.1 b/src/test/java/snapshots/TestJtags.basicExample.1 similarity index 63% rename from src/test/java/snapshots/BasicExample.basicExample.1 rename to src/test/java/snapshots/TestJtags.basicExample.1 index 81781cf..3aa0e4a 100644 --- a/src/test/java/snapshots/BasicExample.basicExample.1 +++ b/src/test/java/snapshots/TestJtags.basicExample.1 @@ -1,9 +1,9 @@ ABC !_TAG_FILE_ENCODING utf-8 !_TAG_FILE_SORTED 2 /0=unsorted, 1=sorted, 2=foldcase/ -BasicExample src/test/java/examples/BasicExample.java /^public class BasicExample {$/;" Cls package:examples InnerClass src/test/java/examples/BasicExample.java /^ class InnerClass {$/;" Cls package:examples class:BasicExample method1 src/test/java/examples/BasicExample.java /^ private boolean method1() {$/;" mthd class:BasicExample -ABC lorem ipsum dolor -method2 src/test/java/examples/BasicExample.java /^ public static void method2($/;" mthd file: class:BasicExample +method2 src/test/java/examples/BasicExample.java /^ void method2() {}$/;" mthd class:(Anonymous) +methodX src/test/java/examples/BasicExample.java /^ public static void method2($/;" mthd file: class:BasicExample +method3 src/test/java/examples/BasicExample.java /^ void method3() {}$/;" mthd class:InnerClass method4 src/test/java/examples/BasicExample.java /^ private void method4() {}$/;" mthd class:InnerClass