test: extend coverage of sfsTest

This commit is contained in:
dualfroz committed 2026-09-11 18:29:09 +02:00
1 parent e1daed794e
commit ffbabfe494
1 file changed
+157
+157
View File
@@ -154,3 +154,160 @@ KTEST(sfsFileGrowsThroughIndirectBlock)
KT_EQ(t, sfsReadAt(f, 0, back, sfsBigSpan), sfsBigSpan);
KT_EQ(t, memcmp(back, pattern, sfsBigSpan), 0);
/* Overwrite a slice that straddles the direct/indirect boundary and
confirm only that slice changes. */
uint8 patch[64];
memset(patch, 0xEE, sizeof(patch));
uint64 patchOffset = 10 * sfsBlockSize - 20;
KT_EQ(t, sfsWriteAt(f, patchOffset, patch, sizeof(patch)), (int64)sizeof(patch));
KT_EQ(t, sfsReadAt(f, 0, verify, sfsBigSpan), sfsBigSpan);
KT_EQ(t, memcmp(verify + patchOffset, patch, sizeof(patch)), 0);
KT_EQ(t, memcmp(verify, pattern, patchOffset), 0);
kfree(pattern);
kfree(back);
kfree(verify);
#undef sfsBigSpan
}
KTEST(sfsNestedDirectoriesAndLookup)
{
if (!KT_TRUE(t, sfsFormat()))
return;
KT_TRUE(t, sfsCreateDir("etc") > 0);
KT_TRUE(t, sfsCreateDir("etc/sub") > 0);
int32 f = sfsCreateFile("etc/sub/leaf.txt");
KT_TRUE(t, f > 0);
KT_EQ(t, sfsWriteAt(f, 0, "leaf", 4), 4);
int32 viaLookup = sfsLookup("etc/sub/leaf.txt");
KT_EQ(t, viaLookup, f);
int32 subDir = sfsLookup("etc/sub");
KT_TRUE(t, subDir > 0);
KT_EQ(t, sfsTypeOf(subDir), sfsTypeDir);
KT_EQ(t, sfsLookup("etc/nope"), -1);
KT_EQ(t, sfsLookup("nope/at/all"), -1);
}
KTEST(sfsDuplicateCreateRejected)
{
if (!KT_TRUE(t, sfsFormat()))
return;
KT_TRUE(t, sfsCreateFile("dup.txt") > 0);
KT_EQ(t, sfsCreateFile("dup.txt"), -1);
KT_EQ(t, sfsCreateDir("dup.txt"), -1);
}
KTEST(sfsRemoveFileFreesBlocksForReuse)
{
if (!KT_TRUE(t, sfsFormat()))
return;
int32 f = sfsCreateFile("tofree.bin");
KT_TRUE(t, f > 0);
#define sfsFreeChunk (4 * sfsBlockSize)
uint8* chunk = (uint8*)kmalloc(sfsFreeChunk);
KT_NOTNULL(t, chunk);
if (!chunk)
return;
memset(chunk, 0x42, sfsFreeChunk);
KT_EQ(t, sfsWriteAt(f, 0, chunk, sfsFreeChunk), sfsFreeChunk);
kfree(chunk);
#undef sfsFreeChunk
KT_TRUE(t, sfsRemove("tofree.bin"));
KT_EQ(t, sfsLookup("tofree.bin"), -1);
/* A same-size file created afterward must succeed, proving the blocks
(and the inode slot) actually came back to the free pool rather than
leaking on every create/remove cycle. */
int32 again = sfsCreateFile("tofree.bin");
KT_TRUE(t, again > 0);
KT_EQ(t, sfsSizeOf(again), 0);
}
KTEST(sfsRmdirRequiresEmpty)
{
if (!KT_TRUE(t, sfsFormat()))
return;
KT_TRUE(t, sfsCreateDir("full") > 0);
KT_TRUE(t, sfsCreateFile("full/child.txt") > 0);
KT_FALSE(t, sfsRemove("full"));
KT_TRUE(t, sfsRemove("full/child.txt"));
KT_TRUE(t, sfsRemove("full"));
KT_EQ(t, sfsLookup("full"), -1);
}
KTEST(sfsReaddirListsAllEntriesAndSwapRemoveKeepsRest)
{
if (!KT_TRUE(t, sfsFormat()))
return;
int32 dir = sfsCreateDir("listing");
KT_TRUE(t, dir > 0);
KT_TRUE(t, sfsCreateFile("listing/a") > 0);
KT_TRUE(t, sfsCreateFile("listing/b") > 0);
KT_TRUE(t, sfsCreateFile("listing/c") > 0);
uint32 seen = 0;
char name[sfsNameMax + 1];
uint32 type;
for (uint32 i = 0; sfsReaddirAt(dir, i, name, sizeof(name), &type); i++) {
KT_EQ(t, type, sfsTypeFile);
seen++;
}
KT_EQ(t, seen, 3);
KT_TRUE(t, sfsRemove("listing/b"));
KT_NE(t, sfsLookup("listing/a"), -1);
KT_NE(t, sfsLookup("listing/c"), -1);
KT_EQ(t, sfsLookup("listing/b"), -1);
seen = 0;
for (uint32 i = 0; sfsReaddirAt(dir, i, name, sizeof(name), &type); i++)
seen++;
KT_EQ(t, seen, 2);
}
KTEST(sfsTruncateShrinksAndFreesBlocks)
{
if (!KT_TRUE(t, sfsFormat()))
return;
int32 f = sfsCreateFile("shrink.bin");
KT_TRUE(t, f > 0);
#define sfsShrinkChunk (5 * sfsBlockSize)
uint8* chunk = (uint8*)kmalloc(sfsShrinkChunk);
KT_NOTNULL(t, chunk);
if (!chunk)
return;
memset(chunk, 0x7A, sfsShrinkChunk);
KT_EQ(t, sfsWriteAt(f, 0, chunk, sfsShrinkChunk), sfsShrinkChunk);
KT_TRUE(t, sfsTruncate(f, sfsBlockSize));
KT_EQ(t, sfsSizeOf(f), sfsBlockSize);
uint8 back[sfsBlockSize];
KT_EQ(t, sfsReadAt(f, 0, back, sfsBlockSize), sfsBlockSize);
KT_EQ(t, memcmp(back, chunk, sfsBlockSize), 0);
kfree(chunk);
#undef sfsShrinkChunk
KT_TRUE(t, sfsTruncate(f, 0));
KT_EQ(t, sfsSizeOf(f), 0);
}
KTEST(sfsPersistsAcrossUnmountRemount)
{
/* The real point of this test: sfsUnmount() drops every in-memory
structure (bitmaps freed, mounted flag cleared). If sfsMount() can
still find the file and its exact bytes afterward, the filesystem is
genuinely backed by disk, not by a cache that happens to survive. */
if (!KT_TRUE(t, sfsFormat()))
return;