From ee752e324a16298c3669d693f82ca48d2bc4d6bb Mon Sep 17 00:00:00 2001 From: Evan Sarkar Date: Mon, 29 Jun 2026 01:07:21 +0530 Subject: [PATCH 1/2] test(core): back the README usage example with a round-trip test The README "Usage example" (format -> open -> writeFile -> list -> readFile = "hello fat12") wasn't compiled or run by anything, so it could silently bit-rot as the API evolves. Add ReadmeExampleTest mirroring that exact flow against the in-memory device fixture at the documented 1.44 MB floppy geometry, asserting the round-tripped bytes equal "hello fat12". The snippet matches the current public API verbatim, so no code change to the README was needed; a one-line note points readers at the backing test. Fixes #5 --- README.md | 3 ++ .../com/ams/fat12ex/core/ReadmeExampleTest.kt | 51 +++++++++++++++++++ 2 files changed, 54 insertions(+) create mode 100644 core/src/test/kotlin/com/ams/fat12ex/core/ReadmeExampleTest.kt diff --git a/README.md b/README.md index e0192c4..3c68b7a 100644 --- a/README.md +++ b/README.md @@ -91,6 +91,9 @@ All write operations return a sealed `Fat12Result` (`Ok`, `NotFound`, `NameConfl `DiskFull`, `InvalidName`, ...); unrecoverable I/O or verify faults roll back and surface as exceptions after the volume has been restored to its pre-operation bytes. +This round-trip is exercised by the build (`ReadmeExampleTest`) so the snippet stays in +sync with the public API. + ## Claims and the tests that substantiate them The engine makes three substantiable correctness claims. Each maps to specific `:core` diff --git a/core/src/test/kotlin/com/ams/fat12ex/core/ReadmeExampleTest.kt b/core/src/test/kotlin/com/ams/fat12ex/core/ReadmeExampleTest.kt new file mode 100644 index 0000000..69c9bca --- /dev/null +++ b/core/src/test/kotlin/com/ams/fat12ex/core/ReadmeExampleTest.kt @@ -0,0 +1,51 @@ +package com.ams.fat12ex.core + +import com.ams.fat12ex.core.testutil.InMemoryBlockDevice +import org.junit.jupiter.api.Assertions.assertEquals +import org.junit.jupiter.api.Assertions.assertInstanceOf +import org.junit.jupiter.api.Assertions.assertTrue +import org.junit.jupiter.api.Test + +/** + * Executes the README "Usage example" round-trip against the build so the + * documented snippet cannot silently bit-rot as the public API evolves. + * + * Mirrors the README flow: format -> open -> writeFile("/HELLO.TXT") -> + * list("/") -> readFile("/HELLO.TXT"), asserting the round-tripped bytes equal + * "hello fat12". Uses the in-memory device fixture at the README's 1.44 MB + * floppy geometry (2880 * 512-byte sectors) in place of the snippet's + * hand-written MemoryBlockDevice. + */ +class ReadmeExampleTest { + + @Test + fun readmeUsageExample_roundTrips() { + // A minimal in-memory BlockDevice at 1.44 MB floppy geometry. + val device = InMemoryBlockDevice(blockSize = 512, blocks = 2880L).also { it.init() } + val volume = Fat12Volume(device) + + // Format a fresh FAT12 volume, then open it. + volume.format("DEMO") + assertInstanceOf(Fat12Result.Ok::class.java, volume.open()) + + // Atomic, verify-after-write streaming write of a file into the root directory. + val payload = "hello fat12".toByteArray() + val write = volume.writeFile("/HELLO.TXT", sequenceOf(payload)) + assertInstanceOf(Fat12Result.Ok::class.java, write) + + // List the root directory — HELLO.TXT must be present at the written size. + val listing = volume.list("/") + assertInstanceOf(Fat12Result.Ok::class.java, listing) + val entry = (listing as Fat12Result.Ok).value + .firstOrNull { it.name.equals("HELLO.TXT", ignoreCase = true) } + assertTrue(entry != null, "HELLO.TXT must appear in the root listing") + assertEquals(payload.size.toLong(), entry!!.size) + + // Read the file back — the bytes must round-trip. + val read = volume.readFile("/HELLO.TXT") + assertInstanceOf(Fat12Result.Ok::class.java, read) + assertEquals("hello fat12", String((read as Fat12Result.Ok).value)) + + volume.close() + } +} From 25e589af2fa3de57109c9ed15472dc9a5e24af22 Mon Sep 17 00:00:00 2001 From: Evan Sarkar Date: Mon, 29 Jun 2026 02:40:35 +0530 Subject: [PATCH 2/2] test(core): assert raw payload bytes round-trip in README example test Compare the bytes read back against the original payload directly with assertArrayEquals, keeping the String decode as the human-facing check the README shows. Locks the raw-byte contract, not just the decoded text. Addresses CodeRabbit review feedback on this PR. --- .../test/kotlin/com/ams/fat12ex/core/ReadmeExampleTest.kt | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/core/src/test/kotlin/com/ams/fat12ex/core/ReadmeExampleTest.kt b/core/src/test/kotlin/com/ams/fat12ex/core/ReadmeExampleTest.kt index 69c9bca..38ca1f5 100644 --- a/core/src/test/kotlin/com/ams/fat12ex/core/ReadmeExampleTest.kt +++ b/core/src/test/kotlin/com/ams/fat12ex/core/ReadmeExampleTest.kt @@ -1,6 +1,7 @@ package com.ams.fat12ex.core import com.ams.fat12ex.core.testutil.InMemoryBlockDevice +import org.junit.jupiter.api.Assertions.assertArrayEquals import org.junit.jupiter.api.Assertions.assertEquals import org.junit.jupiter.api.Assertions.assertInstanceOf import org.junit.jupiter.api.Assertions.assertTrue @@ -41,10 +42,13 @@ class ReadmeExampleTest { assertTrue(entry != null, "HELLO.TXT must appear in the root listing") assertEquals(payload.size.toLong(), entry!!.size) - // Read the file back — the bytes must round-trip. + // Read the file back — the raw bytes must round-trip exactly (the README's + // String(read.value) decode is the human-facing view of that same payload). val read = volume.readFile("/HELLO.TXT") assertInstanceOf(Fat12Result.Ok::class.java, read) - assertEquals("hello fat12", String((read as Fat12Result.Ok).value)) + val readBytes = (read as Fat12Result.Ok).value + assertArrayEquals(payload, readBytes) + assertEquals("hello fat12", String(readBytes)) volume.close() }