test: extend coverage of sfsTest
This commit is contained in:
1 parent
e1daed794e
commit
ffbabfe494
1 file changed
+157
+157
@@ -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;
|
||||
|
||||
Reference in new issue
Block a user