u-boot-brain/test/command_ut.c
Stephen Warren fe9ca3d328 hush: fix some quoted variable expansion issues
The following shell command fails:

if test -z "$x"; then echo "zero"; else echo "non-zero"; fi

(assuming $x does not exist, it prints "non-zero" rather than "zero").

... since "$x" expands to nothing, and the argument is completely
dropped, causing too few to be passed to -z, causing cmd_test() to
error out early.

This is because when variable expansions are processed by make_string(),
the expanded results are concatenated back into a new string. However,
no quoting is applied when doing so, so any empty variables simply don't
generate any parameter when the combined string is parsed again.

Fix this by explicitly replacing quoting any argument that was originally
quoted when re-generating a string from the already-parsed argument list.

This also fixes loss of whitespace in commands such as:

setenv space " "
setenv var " 1${space}${space} 2 "
echo ">>${var}<<"

Reported-by: Russell King <linux@arm.linux.org.uk>
Acked-by: Simon Glass <sjg@chromium.org>
Signed-off-by: Stephen Warren <swarren@wwwdotorg.org>
2014-03-07 10:59:06 -05:00

177 lines
5.3 KiB
C

/*
* Copyright (c) 2012, The Chromium Authors
*
* SPDX-License-Identifier: GPL-2.0+
*/
#define DEBUG
#include <common.h>
static const char test_cmd[] = "setenv list 1\n setenv list ${list}2; "
"setenv list ${list}3\0"
"setenv list ${list}4";
static int do_ut_cmd(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
{
printf("%s: Testing commands\n", __func__);
run_command("env default -f -a", 0);
/* run a single command */
run_command("setenv single 1", 0);
assert(!strcmp("1", getenv("single")));
/* make sure that compound statements work */
#ifdef CONFIG_SYS_HUSH_PARSER
run_command("if test -n ${single} ; then setenv check 1; fi", 0);
assert(!strcmp("1", getenv("check")));
run_command("setenv check", 0);
#endif
/* commands separated by ; */
run_command_list("setenv list 1; setenv list ${list}1", -1, 0);
assert(!strcmp("11", getenv("list")));
/* commands separated by \n */
run_command_list("setenv list 1\n setenv list ${list}1", -1, 0);
assert(!strcmp("11", getenv("list")));
/* command followed by \n and nothing else */
run_command_list("setenv list 1${list}\n", -1, 0);
assert(!strcmp("111", getenv("list")));
/* three commands in a row */
run_command_list("setenv list 1\n setenv list ${list}2; "
"setenv list ${list}3", -1, 0);
assert(!strcmp("123", getenv("list")));
/* a command string with \0 in it. Stuff after \0 should be ignored */
run_command("setenv list", 0);
run_command_list(test_cmd, sizeof(test_cmd), 0);
assert(!strcmp("123", getenv("list")));
/*
* a command list where we limit execution to only the first command
* using the length parameter.
*/
run_command_list("setenv list 1\n setenv list ${list}2; "
"setenv list ${list}3", strlen("setenv list 1"), 0);
assert(!strcmp("1", getenv("list")));
#ifdef CONFIG_SYS_HUSH_PARSER
/* Test the 'test' command */
#define HUSH_TEST(name, expr, expected_result) \
run_command("if test " expr " ; then " \
"setenv " #name "_" #expected_result " y; else " \
"setenv " #name "_" #expected_result " n; fi", 0); \
assert(!strcmp(#expected_result, getenv(#name "_" #expected_result))); \
setenv(#name "_" #expected_result, NULL);
/* Basic operators */
HUSH_TEST(streq, "aaa = aaa", y);
HUSH_TEST(streq, "aaa = bbb", n);
HUSH_TEST(strneq, "aaa != bbb", y);
HUSH_TEST(strneq, "aaa != aaa", n);
HUSH_TEST(strlt, "aaa < bbb", y);
HUSH_TEST(strlt, "bbb < aaa", n);
HUSH_TEST(strgt, "bbb > aaa", y);
HUSH_TEST(strgt, "aaa > bbb", n);
HUSH_TEST(eq, "123 -eq 123", y);
HUSH_TEST(eq, "123 -eq 456", n);
HUSH_TEST(ne, "123 -ne 456", y);
HUSH_TEST(ne, "123 -ne 123", n);
HUSH_TEST(lt, "123 -lt 456", y);
HUSH_TEST(lt_eq, "123 -lt 123", n);
HUSH_TEST(lt, "456 -lt 123", n);
HUSH_TEST(le, "123 -le 456", y);
HUSH_TEST(le_eq, "123 -le 123", y);
HUSH_TEST(le, "456 -le 123", n);
HUSH_TEST(gt, "456 -gt 123", y);
HUSH_TEST(gt_eq, "123 -gt 123", n);
HUSH_TEST(gt, "123 -gt 456", n);
HUSH_TEST(ge, "456 -ge 123", y);
HUSH_TEST(ge_eq, "123 -ge 123", y);
HUSH_TEST(ge, "123 -ge 456", n);
HUSH_TEST(z, "-z \"\"", y);
HUSH_TEST(z, "-z \"aaa\"", n);
HUSH_TEST(n, "-n \"aaa\"", y);
HUSH_TEST(n, "-n \"\"", n);
/* Inversion of simple tests */
HUSH_TEST(streq_inv, "! aaa = aaa", n);
HUSH_TEST(streq_inv, "! aaa = bbb", y);
HUSH_TEST(streq_inv_inv, "! ! aaa = aaa", y);
HUSH_TEST(streq_inv_inv, "! ! aaa = bbb", n);
/* Binary operators */
HUSH_TEST(or_0_0, "aaa != aaa -o bbb != bbb", n);
HUSH_TEST(or_0_1, "aaa != aaa -o bbb = bbb", y);
HUSH_TEST(or_1_0, "aaa = aaa -o bbb != bbb", y);
HUSH_TEST(or_1_1, "aaa = aaa -o bbb = bbb", y);
HUSH_TEST(and_0_0, "aaa != aaa -a bbb != bbb", n);
HUSH_TEST(and_0_1, "aaa != aaa -a bbb = bbb", n);
HUSH_TEST(and_1_0, "aaa = aaa -a bbb != bbb", n);
HUSH_TEST(and_1_1, "aaa = aaa -a bbb = bbb", y);
/* Inversion within binary operators */
HUSH_TEST(or_0_0_inv, "! aaa != aaa -o ! bbb != bbb", y);
HUSH_TEST(or_0_1_inv, "! aaa != aaa -o ! bbb = bbb", y);
HUSH_TEST(or_1_0_inv, "! aaa = aaa -o ! bbb != bbb", y);
HUSH_TEST(or_1_1_inv, "! aaa = aaa -o ! bbb = bbb", n);
HUSH_TEST(or_0_0_inv_inv, "! ! aaa != aaa -o ! ! bbb != bbb", n);
HUSH_TEST(or_0_1_inv_inv, "! ! aaa != aaa -o ! ! bbb = bbb", y);
HUSH_TEST(or_1_0_inv_inv, "! ! aaa = aaa -o ! ! bbb != bbb", y);
HUSH_TEST(or_1_1_inv_inv, "! ! aaa = aaa -o ! ! bbb = bbb", y);
setenv("ut_var_nonexistent", NULL);
setenv("ut_var_exists", "1");
HUSH_TEST(z_varexp_quoted, "-z \"$ut_var_nonexistent\"", y);
HUSH_TEST(z_varexp_quoted, "-z \"$ut_var_exists\"", n);
setenv("ut_var_exists", NULL);
run_command("setenv ut_var_space \" \"", 0);
assert(!strcmp(getenv("ut_var_space"), " "));
run_command("setenv ut_var_test $ut_var_space", 0);
assert(!getenv("ut_var_test"));
run_command("setenv ut_var_test \"$ut_var_space\"", 0);
assert(!strcmp(getenv("ut_var_test"), " "));
run_command("setenv ut_var_test \" 1${ut_var_space}${ut_var_space} 2 \"", 0);
assert(!strcmp(getenv("ut_var_test"), " 1 2 "));
setenv("ut_var_space", NULL);
setenv("ut_var_test", NULL);
#ifdef CONFIG_SANDBOX
/*
* File existence
* This assume U-Boot sandbox is run from the U-Boot build directory
*/
HUSH_TEST(e, "-e host - u-boot", y);
HUSH_TEST(e, "-e host - creating_this_file_breaks_uboot_unit_test", n);
#endif
#endif
printf("%s: Everything went swimmingly\n", __func__);
return 0;
}
U_BOOT_CMD(
ut_cmd, 5, 1, do_ut_cmd,
"Very basic test of command parsers",
""
);