test: test more of shellTest

This commit is contained in:
dualfroz committed 2026-09-11 22:56:13 +02:00
1 parent 6f07fe8429
commit 916fd5decc
1 file changed
+188
+188
View File
@@ -622,3 +622,191 @@ KTEST(shellIsStatusVarTokenRejectsTrailingGarbage)
KT_FALSE(t, shellIsStatusVarToken("$?x")); KT_FALSE(t, shellIsStatusVarToken("$?x"));
} }
KTEST(shellIsStatusVarTokenRejectsLeadingGarbage)
{
KT_FALSE(t, shellIsStatusVarToken("x$?"));
}
/* shellGlobMatch/shellTokenHasGlob/shellSplitGlobToken (shell.c) are the
pure-logic half of the shell's new wildcard glob expansion
(shellExpandGlobs, which actually walks the VFS and is not KTEST-able
here for the same pre-scheduler reason shellExpandArgv's own VFS/thread
lookups are not) -- the same "pure logic here, thread/VFS-touching glue
stays static in shell.c" split every other pure function above already
follows. */
KTEST(shellGlobMatchExactLiteral)
{
KT_TRUE(t, shellGlobMatch("hello", "hello"));
KT_FALSE(t, shellGlobMatch("hello", "hellox"));
KT_FALSE(t, shellGlobMatch("hello", "hell"));
}
KTEST(shellGlobMatchStarMatchesAnySuffix)
{
KT_TRUE(t, shellGlobMatch("a*", "a"));
KT_TRUE(t, shellGlobMatch("a*", "abc"));
KT_FALSE(t, shellGlobMatch("a*", "xabc"));
}
KTEST(shellGlobMatchStarMatchesAnyPrefix)
{
KT_TRUE(t, shellGlobMatch("*.txt", "a.txt"));
KT_TRUE(t, shellGlobMatch("*.txt", ".txt"));
KT_FALSE(t, shellGlobMatch("*.txt", "a.log"));
}
KTEST(shellGlobMatchStarInTheMiddle)
{
KT_TRUE(t, shellGlobMatch("a*b", "ab"));
KT_TRUE(t, shellGlobMatch("a*b", "axxxb"));
KT_FALSE(t, shellGlobMatch("a*b", "axxxc"));
}
KTEST(shellGlobMatchMultipleStars)
{
KT_TRUE(t, shellGlobMatch("*a*b*", "aXbY"));
KT_TRUE(t, shellGlobMatch("*a*b*", "ab"));
KT_FALSE(t, shellGlobMatch("*a*b*", "ba"));
}
KTEST(shellGlobMatchBareStarMatchesEverythingIncludingEmpty)
{
KT_TRUE(t, shellGlobMatch("*", ""));
KT_TRUE(t, shellGlobMatch("*", "anything"));
}
KTEST(shellGlobMatchQuestionMarkMatchesExactlyOneChar)
{
KT_TRUE(t, shellGlobMatch("a?c", "abc"));
KT_FALSE(t, shellGlobMatch("a?c", "ac"));
KT_FALSE(t, shellGlobMatch("a?c", "abbc"));
}
KTEST(shellGlobMatchEmptyPatternOnlyMatchesEmptyName)
{
KT_TRUE(t, shellGlobMatch("", ""));
KT_FALSE(t, shellGlobMatch("", "x"));
}
KTEST(shellTokenHasGlobDetectsStarAndQuestionMark)
{
KT_TRUE(t, shellTokenHasGlob("*.txt"));
KT_TRUE(t, shellTokenHasGlob("file?.log"));
KT_FALSE(t, shellTokenHasGlob("plain.txt"));
KT_FALSE(t, shellTokenHasGlob(""));
}
KTEST(shellSplitGlobTokenNoSlashYieldsEmptyDir)
{
char dir[64];
char pattern[64];
shellSplitGlobToken("*.txt", dir, sizeof(dir), pattern, sizeof(pattern));
KT_STREQ(t, dir, "");
KT_STREQ(t, pattern, "*.txt");
}
KTEST(shellSplitGlobTokenSplitsAtLastSlashIncludingIt)
{
char dir[64];
char pattern[64];
shellSplitGlobToken("/tmp/gd/*.txt", dir, sizeof(dir), pattern, sizeof(pattern));
KT_STREQ(t, dir, "/tmp/gd/");
KT_STREQ(t, pattern, "*.txt");
}
KTEST(shellSplitGlobTokenNoGlobCharStillSplitsCleanly)
{
/* shellSplitGlobToken itself does not care whether the pattern half
actually contains a glob character -- that gate is
shellTokenHasGlob's own job, called first by shellExpandGlobs. */
char dir[64];
char pattern[64];
shellSplitGlobToken("/tmp/gd/plain.txt", dir, sizeof(dir), pattern, sizeof(pattern));
KT_STREQ(t, dir, "/tmp/gd/");
KT_STREQ(t, pattern, "plain.txt");
}
/* shellFindCommandSubst (shell.c) is the pure-syntax half of the shell's
new `$(cmd [args])` command-substitution expansion -- the impure glue
that actually spawns and captures a command's output (shellExpandCommandSubst,
static in shell.c) needs a real jobctl spawn, off limits for KTEST's
pre-scheduler context, so only the locate-and-extract half is covered
here, the same "pure logic here, thread/VFS-touching glue stays static
in shell.c" split every other shell.h syntax function already gets. */
KTEST(shellFindCommandSubstNoDollarParenReturnsNotFound)
{
int start, end;
char cmd[32];
KT_TRUE(t, shellFindCommandSubst("echo hello", &start, &end, cmd, sizeof(cmd)));
KT_EQ(t, start, -1);
}
KTEST(shellFindCommandSubstWholeToken)
{
int start, end;
char cmd[32];
KT_TRUE(t, shellFindCommandSubst("$(date)", &start, &end, cmd, sizeof(cmd)));
KT_EQ(t, start, 0);
KT_EQ(t, end, 7);
KT_STREQ(t, cmd, "date");
}
KTEST(shellFindCommandSubstEmbeddedInLargerLine)
{
int start, end;
char cmd[32];
KT_TRUE(t, shellFindCommandSubst("echo $(date) done", &start, &end, cmd, sizeof(cmd)));
KT_EQ(t, start, 5);
KT_EQ(t, end, 12);
KT_STREQ(t, cmd, "date");
}
KTEST(shellFindCommandSubstCapturesMultiWordCommand)
{
int start, end;
char cmd[32];
KT_TRUE(t, shellFindCommandSubst("argecho $(argecho a b)", &start, &end, cmd, sizeof(cmd)));
KT_STREQ(t, cmd, "argecho a b");
}
KTEST(shellFindCommandSubstUnterminatedIsMalformed)
{
int start, end;
char cmd[32];
KT_FALSE(t, shellFindCommandSubst("echo $(date", &start, &end, cmd, sizeof(cmd)));
}
KTEST(shellFindCommandSubstEmptyParensYieldsEmptyCommand)
{
int start, end;
char cmd[32];
KT_TRUE(t, shellFindCommandSubst("$()", &start, &end, cmd, sizeof(cmd)));
KT_EQ(t, start, 0);
KT_EQ(t, end, 3);
KT_STREQ(t, cmd, "");
}
KTEST(shellFindCommandSubstTruncatesToCapacity)
{
int start, end;
char cmd[4];
KT_TRUE(t, shellFindCommandSubst("$(longcommand)", &start, &end, cmd, sizeof(cmd)));
KT_STREQ(t, cmd, "lon");
}
KTEST(shellFindCommandSubstOnlyMatchesFirstOccurrence)
{
/* No nested-paren support (documented in shell.h) -- the very NEXT ')'
after the opening '$(' ends the match, so a second, unrelated
`$(...)` later in the line is left completely untouched for a
caller's own repeat scan (shellExpandCommandSubst's own loop) to
find on a later pass, never folded into this one's own cmdOut. */
int start, end;
char cmd[32];
KT_TRUE(t, shellFindCommandSubst("$(a) $(b)", &start, &end, cmd, sizeof(cmd)));
KT_EQ(t, start, 0);
KT_EQ(t, end, 4);
KT_STREQ(t, cmd, "a");
}