test: strengthen tests for shellTest

This commit is contained in:
dualfroz committed 2026-09-11 21:27:14 +02:00
1 parent c5f5c74a37
commit 6f07fe8429
1 file changed
+158
+158
View File
@@ -464,3 +464,161 @@ KTEST(shellExtractRedirectsDanglingErrOperatorFailsWithoutMutating)
KT_STREQ(t, argv[2], "2>"); KT_STREQ(t, argv[2], "2>");
} }
/* `<<<` (here-string) is a third, independent fd-0 operator alongside `<` --
covered on its own (basic recognition, combined with real args and `>`,
dangling), plus the two last-one-wins cases proving `<` and `<<<` share
ownership of the SAME fd 0 (whichever comes later in the line wins,
clearing the other field entirely) rather than being two unrelated
fields a caller could accidentally read both of at once. */
KTEST(shellExtractRedirectsHereStringBasic)
{
char text[] = "cat <<< hello";
char* argv[8];
int argc = shellTokenize(text, argv, 8);
ShellRedirect redirect;
bool ok = shellExtractRedirects(argv, &argc, &redirect);
KT_TRUE(t, ok);
KT_EQ(t, argc, 1);
KT_STREQ(t, argv[0], "cat");
KT_STREQ(t, redirect.hereString, "hello");
KT_NULL(t, redirect.inPath);
}
KTEST(shellExtractRedirectsHereStringWithRealArgsAndOutput)
{
char text[] = "sort -r <<< hello > out.txt";
char* argv[8];
int argc = shellTokenize(text, argv, 8);
ShellRedirect redirect;
bool ok = shellExtractRedirects(argv, &argc, &redirect);
KT_TRUE(t, ok);
KT_EQ(t, argc, 2);
KT_STREQ(t, argv[0], "sort");
KT_STREQ(t, argv[1], "-r");
KT_STREQ(t, redirect.hereString, "hello");
KT_STREQ(t, redirect.outPath, "out.txt");
KT_NULL(t, redirect.inPath);
}
KTEST(shellExtractRedirectsDanglingHereStringFailsWithoutMutating)
{
char text[] = "cat <<<";
char* argv[8];
int argc = shellTokenize(text, argv, 8);
int originalArgc = argc;
ShellRedirect redirect;
bool ok = shellExtractRedirects(argv, &argc, &redirect);
KT_FALSE(t, ok);
KT_EQ(t, argc, originalArgc);
KT_STREQ(t, argv[0], "cat");
KT_STREQ(t, argv[1], "<<<");
}
KTEST(shellExtractRedirectsHereStringAfterFileRedirectWins)
{
char text[] = "cat < a.txt <<< b";
char* argv[8];
int argc = shellTokenize(text, argv, 8);
ShellRedirect redirect;
bool ok = shellExtractRedirects(argv, &argc, &redirect);
KT_TRUE(t, ok);
KT_EQ(t, argc, 1);
KT_STREQ(t, redirect.hereString, "b");
KT_NULL(t, redirect.inPath);
}
KTEST(shellExtractRedirectsFileRedirectAfterHereStringWins)
{
char text[] = "cat <<< b < a.txt";
char* argv[8];
int argc = shellTokenize(text, argv, 8);
ShellRedirect redirect;
bool ok = shellExtractRedirects(argv, &argc, &redirect);
KT_TRUE(t, ok);
KT_EQ(t, argc, 1);
KT_STREQ(t, redirect.inPath, "a.txt");
KT_NULL(t, redirect.hereString);
}
/* shellParseVarRef (shell.c) is the pure-syntax half of the shell's new
`$NAME` unquoted parameter expansion -- recognizing the "$" + name-chars
shape, never touching sched.h's Thread.env (that lookup is
shellExpandArgv's job, not KTEST-able here for the same pre-scheduler
reason shellTokenize's own file comment gives). */
KTEST(shellParseVarRefAcceptsPlainName)
{
char name[16];
bool ok = shellParseVarRef("$HOME", name, sizeof(name));
KT_TRUE(t, ok);
KT_STREQ(t, name, "HOME");
}
KTEST(shellParseVarRefAcceptsDigitsAndUnderscore)
{
char name[16];
bool ok = shellParseVarRef("$_var_2", name, sizeof(name));
KT_TRUE(t, ok);
KT_STREQ(t, name, "_var_2");
}
KTEST(shellParseVarRefRejectsBareDollarSign)
{
char name[16];
KT_FALSE(t, shellParseVarRef("$", name, sizeof(name)));
}
KTEST(shellParseVarRefRejectsTokenWithoutLeadingDollar)
{
char name[16];
KT_FALSE(t, shellParseVarRef("HOME", name, sizeof(name)));
}
KTEST(shellParseVarRefRejectsEmbeddedPunctuation)
{
char name[16];
KT_FALSE(t, shellParseVarRef("$FOO=bar", name, sizeof(name)));
KT_FALSE(t, shellParseVarRef("$FOO/bar", name, sizeof(name)));
}
KTEST(shellParseVarRefRejectsNameTooLongForCapacity)
{
char name[4];
KT_FALSE(t, shellParseVarRef("$TOOLONG", name, sizeof(name)));
}
/* shellParseVarRef must never accept `$?` itself -- '?' is not in its own
[A-Za-z0-9_] name-character set -- so the two token classes
(shellIsStatusVarToken below and shellParseVarRef above) can never
both claim the same token. */
KTEST(shellParseVarRefRejectsQuestionMark)
{
char name[16];
KT_FALSE(t, shellParseVarRef("$?", name, sizeof(name)));
}
/* shellIsStatusVarToken (shell.c) is the pure-syntax half of the shell's
new `$?` special parameter -- recognizing the EXACT two-character token
"$?", never touching this file's own file-scope `lastStatus` (that
substitution is shellExpandToken's job, not KTEST-able here for the
same pre-scheduler reason shellExpandArgv's own env lookups are not). */
KTEST(shellIsStatusVarTokenAcceptsExactMatch)
{
KT_TRUE(t, shellIsStatusVarToken("$?"));
}
KTEST(shellIsStatusVarTokenRejectsBareDollarSign)
{
KT_FALSE(t, shellIsStatusVarToken("$"));
}
KTEST(shellIsStatusVarTokenRejectsBareQuestionMark)
{
KT_FALSE(t, shellIsStatusVarToken("?"));
}
KTEST(shellIsStatusVarTokenRejectsTrailingGarbage)
{
KT_FALSE(t, shellIsStatusVarToken("$?x"));
}