From ccc4054fa8ddc79d85f763c07b946bf2cbe06b68 Mon Sep 17 00:00:00 2001 From: volodya-lombrozo Date: Mon, 2 Feb 2026 15:03:12 +0300 Subject: [PATCH] feat(#4840): Add tests for transpilation cache handling and validation --- .../java/org/eolang/maven/MjTranspile.java | 18 ++-- .../java/org/eolang/maven/FpDefaultTest.java | 89 +++++++++++++++++++ 2 files changed, 102 insertions(+), 5 deletions(-) diff --git a/eo-maven-plugin/src/main/java/org/eolang/maven/MjTranspile.java b/eo-maven-plugin/src/main/java/org/eolang/maven/MjTranspile.java index 3ba6f07f0b4..4ab95c55df6 100644 --- a/eo-maven-plugin/src/main/java/org/eolang/maven/MjTranspile.java +++ b/eo-maven-plugin/src/main/java/org/eolang/maven/MjTranspile.java @@ -173,6 +173,9 @@ private int transpiled( final Supplier hsh = new TojoHash(tojo); final AtomicBoolean rewrite = new AtomicBoolean(false); final Function transform = this.transpilation(source); + final String version = this.plugin.getVersion(); + final Path tail = base.relativize(target); + final Path cdir = this.cache.toPath().resolve(MjTranspile.CACHE); new FpDefault( src -> { rewrite.compareAndSet(false, true); @@ -180,19 +183,24 @@ private int transpiled( final String res = transform.apply(xmir).toString(); Logger.debug( this, - "Transpiled %[file]s (%s) to %[file]s (%s) in %[ms]s (cache miss)", + "Transpiled %[file]s (%s) to %[file]s (%s) in %[ms]s (cache miss), version: %s, hash: %s, tail: %s, cache enabled: %b, cache dir: %[file]s", source, MjTranspile.info(source), target, MjTranspile.info(target), - System.currentTimeMillis() - start + System.currentTimeMillis() - start, + version, + hsh.get(), + tail, + this.cacheEnabled, + cdir ); return res; }, - this.cache.toPath().resolve(MjTranspile.CACHE), - this.plugin.getVersion(), + cdir, + version, hsh, - base.relativize(target), + tail, this.cacheEnabled ).apply(source, target); return this.javaGenerated(rewrite.get(), target, hsh.get()); diff --git a/eo-maven-plugin/src/test/java/org/eolang/maven/FpDefaultTest.java b/eo-maven-plugin/src/test/java/org/eolang/maven/FpDefaultTest.java index b8497e90cad..4b38bc39221 100644 --- a/eo-maven-plugin/src/test/java/org/eolang/maven/FpDefaultTest.java +++ b/eo-maven-plugin/src/test/java/org/eolang/maven/FpDefaultTest.java @@ -7,6 +7,7 @@ import com.yegor256.Mktmp; import com.yegor256.MktmpResolver; import java.io.IOException; +import java.nio.charset.StandardCharsets; import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.Paths; @@ -15,6 +16,7 @@ import org.hamcrest.MatcherAssert; import org.hamcrest.Matchers; import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Disabled; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; @@ -336,6 +338,93 @@ void cachesEvenItIsZeroVersion(@Mktmp final Path temp) throws Exception { ); } + /** + * This test was added to mitigate an issue with the transpilation cache. + * You can read more about it here: + * 4840 + * If cache is missing, then transpilation should be performed. + * @param temp Temporary directory + * @throws Exception If fails + */ + @Test + void transpilesIfCacheMiss(@Mktmp final Path temp) throws Exception { + final Path cdir = temp.resolve("cache-folder").resolve("transpiled-folder"); + Files.createDirectories(cdir); + final String content = "Source content - no cache"; + final Path source = FpDefaultTest.existedFile( + temp.resolve("target/eo/1-parse/org/eolang/examples/fibonacci.xmir"), + "old" + ); + final Path target = FpDefaultTest.notExistedTarget( + temp.resolve("target/eo/5-transpile/org/eolang/examples/fibonacci.xmir") + ); + new FpDefault( + src -> content, + cdir, + "1.0-SNAPSHOT", + () -> "94641989dbaebef167cf67906a265d925bbb4e5b", + Paths.get("org/eolang/examples/fibonacci.xmir"), + true + ).apply(source, target); + MatcherAssert.assertThat( + "We expect a cache miss to trigger transpilation", + new TextOf(target).asString(), + Matchers.equalTo(content) + ); + } + + /** + * We should use the transpilation cache if it existed before transpilation. + * Current implementation of {@link FpDefault} relies on file timestamps to decide + * whether to use the cache or not. + * If the cache file is older than the source file, then the cache is ignored, which is + * a critical issue for the transpilation step, because the source files are often + * modified (e.g. by the parser) right before transpilation, making the cache + * always older than the source files. + * @param temp Temporary directory + * @throws Exception If fails + * @todo #4840:90min Implement proper cache validation mechanism. + * Currently, FpDefault relies on file timestamps to decide whether to use + * the cache or not. This approach is not reliable in many cases. + * For example, in the transpilation step, the source files are often + * modified right before transpilation, making the cache always older + * than the source files. + */ + @Test + @Disabled + void doesNotTranspileIfCacheHitWhenCacheExistedBefore(@Mktmp final Path temp) throws Exception { + final Path cdir = temp.resolve("cache-dir").resolve("transpiled-cache"); + Files.createDirectories(cdir); + final Path cachefile = cdir + .resolve("1.0-SNAPSHOT") + .resolve("94641989dbaebef167cf67906a265d925bbb4e5b") + .resolve("org/eolang/examples/fibonacci.xmir"); + Files.createDirectories(cachefile.getParent()); + final String cached = "transpilation results from cache"; + Files.write(cachefile, cached.getBytes(StandardCharsets.UTF_8)); + FpDefaultTest.makeOlder(cdir, 1000); + final Path source = FpDefaultTest.existedFile( + temp.resolve("target/eo/1-parse/org/eolang/examples/fibonacci.xmir"), + "Source content" + ); + final Path target = temp.resolve( + "target/eo/5-transpile/org/eolang/examples/fibonacci.xmir" + ); + new FpDefault( + src -> "transpiled content", + cdir, + "1.0-SNAPSHOT", + () -> "94641989dbaebef167cf67906a265d925bbb4e5b", + Paths.get("org/eolang/examples/fibonacci.xmir"), + true + ).apply(source, target); + MatcherAssert.assertThat( + "We expect that cache is used", + new TextOf(target).asString(), + Matchers.equalTo(cached) + ); + } + /** * Returns the cache content. */