1 // SPDX-License-Identifier: GPL-2.0
2 /*
3 * (C) Copyright 2021
4 * Francis Laniel, Amarula Solutions, francis.laniel@amarulasolutions.com
5 */
6
7 #include <command.h>
8 #include <env.h>
9 #include <env_attr.h>
10 #include <test/hush.h>
11 #include <test/ut.h>
12 #include <asm/global_data.h>
13
14 DECLARE_GLOBAL_DATA_PTR;
15
hush_test_simple_dollar(struct unit_test_state * uts)16 static int hush_test_simple_dollar(struct unit_test_state *uts)
17 {
18 ut_assertok(run_command("echo $dollar_foo", 0));
19 ut_assert_nextline_empty();
20 ut_assert_console_end();
21
22 ut_assertok(run_command("echo ${dollar_foo}", 0));
23 ut_assert_nextline_empty();
24 ut_assert_console_end();
25
26 ut_assertok(run_command("dollar_foo=bar", 0));
27
28 ut_assertok(run_command("echo $dollar_foo", 0));
29 ut_assert_nextline("bar");
30 ut_assert_console_end();
31
32 ut_assertok(run_command("echo ${dollar_foo}", 0));
33 ut_assert_nextline("bar");
34 ut_assert_console_end();
35
36 ut_assertok(run_command("dollar_foo=\\$bar", 0));
37
38 ut_assertok(run_command("echo $dollar_foo", 0));
39 ut_assert_nextline("$bar");
40 ut_assert_console_end();
41
42 ut_assertok(run_command("dollar_foo='$bar'", 0));
43
44 ut_assertok(run_command("echo $dollar_foo", 0));
45 ut_assert_nextline("$bar");
46 ut_assert_console_end();
47
48 ut_asserteq(1, run_command("dollar_foo=bar quux", 0));
49 /* Next line contains error message */
50 ut_assert_skipline();
51 ut_assert_console_end();
52
53 ut_asserteq(1, run_command("dollar_foo='bar quux", 0));
54 /* Next line contains error message */
55 ut_assert_skipline();
56 ut_assert_console_end();
57
58 ut_asserteq(1, run_command("dollar_foo=bar quux\"", 0));
59 /* Next line contains error message */
60 ut_assert_skipline();
61 /*
62 * Old parser prints the error message on two lines:
63 * Unknown command 'quux
64 * ' - try 'help'
65 * While the new only prints it on one:
66 * syntax error: unterminated \"
67 */
68 if (gd->flags & GD_FLG_HUSH_OLD_PARSER) {
69 ut_assert_skipline();
70 }
71 ut_assert_console_end();
72
73 ut_assertok(run_command("dollar_foo='bar \"quux'", 0));
74
75 ut_assertok(run_command("echo $dollar_foo", 0));
76 /*
77 * This one is buggy.
78 * ut_assert_nextline("bar \"quux");
79 * ut_assert_console_end();
80 *
81 * So, let's reset output:
82 */
83 console_record_reset_enable();
84
85 if (gd->flags & GD_FLG_HUSH_MODERN_PARSER) {
86 /*
87 * Old parser returns an error because it waits for closing
88 * '\'', but this behavior is wrong as the '\'' is surrounded by
89 * '"', so no need to wait for a closing one.
90 */
91 ut_assertok(run_command("dollar_foo=\"bar 'quux\"", 0));
92
93 ut_assertok(run_command("echo $dollar_foo", 0));
94 ut_assert_nextline("bar 'quux");
95 ut_assert_console_end();
96 } else if (gd->flags & GD_FLG_HUSH_OLD_PARSER) {
97 ut_asserteq(1, run_command("dollar_foo=\"bar 'quux\"", 0));
98 /* Next line contains error message */
99 ut_assert_skipline();
100 ut_assert_console_end();
101 }
102
103 ut_assertok(run_command("dollar_foo='bar quux'", 0));
104 ut_assertok(run_command("echo $dollar_foo", 0));
105 ut_assert_nextline("bar quux");
106 ut_assert_console_end();
107
108 if (gd->flags & GD_FLG_HUSH_MODERN_PARSER) {
109 /* Reset local variable. */
110 ut_assertok(run_command("dollar_foo=", 0));
111 } else if (gd->flags & GD_FLG_HUSH_OLD_PARSER) {
112 puts("Beware: this test set local variable dollar_foo and it cannot be unset!\n");
113 }
114
115 return 0;
116 }
117 HUSH_TEST(hush_test_simple_dollar, UTF_CONSOLE);
118
hush_test_env_dollar(struct unit_test_state * uts)119 static int hush_test_env_dollar(struct unit_test_state *uts)
120 {
121 env_set("env_foo", "bar");
122
123 ut_assertok(run_command("echo $env_foo", 0));
124 ut_assert_nextline("bar");
125 ut_assert_console_end();
126
127 ut_assertok(run_command("echo ${env_foo}", 0));
128 ut_assert_nextline("bar");
129 ut_assert_console_end();
130
131 /* Environment variables have priority over local variable */
132 ut_assertok(run_command("env_foo=quux", 0));
133 ut_assertok(run_command("echo ${env_foo}", 0));
134 ut_assert_nextline("bar");
135 ut_assert_console_end();
136
137 /* Clean up setting the variable */
138 env_set("env_foo", NULL);
139
140 if (gd->flags & GD_FLG_HUSH_MODERN_PARSER) {
141 /* Reset local variable. */
142 ut_assertok(run_command("env_foo=", 0));
143 } else if (gd->flags & GD_FLG_HUSH_OLD_PARSER) {
144 puts("Beware: this test set local variable env_foo and it cannot be unset!\n");
145 }
146
147 return 0;
148 }
149 HUSH_TEST(hush_test_env_dollar, UTF_CONSOLE);
150
hush_test_command_dollar(struct unit_test_state * uts)151 static int hush_test_command_dollar(struct unit_test_state *uts)
152 {
153 ut_assertok(run_command("dollar_bar=\"echo bar\"", 0));
154
155 ut_assertok(run_command("$dollar_bar", 0));
156 ut_assert_nextline("bar");
157 ut_assert_console_end();
158
159 ut_assertok(run_command("${dollar_bar}", 0));
160 ut_assert_nextline("bar");
161 ut_assert_console_end();
162
163 ut_assertok(run_command("dollar_bar=\"echo\nbar\"", 0));
164
165 ut_assertok(run_command("$dollar_bar", 0));
166 ut_assert_nextline("bar");
167 ut_assert_console_end();
168
169 ut_assertok(run_command("dollar_bar='echo bar\n'", 0));
170
171 ut_assertok(run_command("$dollar_bar", 0));
172 ut_assert_nextline("bar");
173 ut_assert_console_end();
174
175 ut_assertok(run_command("dollar_bar='echo bar\\n'", 0));
176
177 ut_assertok(run_command("$dollar_bar", 0));
178
179 if (gd->flags & GD_FLG_HUSH_MODERN_PARSER) {
180 /*
181 * This difference seems to come from a bug solved in Busybox
182 * hush.
183 * Behavior of hush 2021 is coherent with bash and other shells.
184 */
185 ut_assert_nextline("bar\\n");
186 } else if (gd->flags & GD_FLG_HUSH_OLD_PARSER) {
187 ut_assert_nextline("barn");
188 }
189
190 ut_assert_console_end();
191
192 ut_assertok(run_command("dollar_bar='echo $bar'", 0));
193
194 ut_assertok(run_command("$dollar_bar", 0));
195 ut_assert_nextline("$bar");
196 ut_assert_console_end();
197
198 ut_assertok(run_command("dollar_quux=quux", 0));
199 ut_assertok(run_command("dollar_bar=\"echo $dollar_quux\"", 0));
200
201 ut_assertok(run_command("$dollar_bar", 0));
202 ut_assert_nextline("quux");
203 ut_assert_console_end();
204
205 if (gd->flags & GD_FLG_HUSH_MODERN_PARSER) {
206 /* Reset local variables. */
207 ut_assertok(run_command("dollar_bar=", 0));
208 ut_assertok(run_command("dollar_quux=", 0));
209 } else if (gd->flags & GD_FLG_HUSH_OLD_PARSER) {
210 puts("Beware: this test sets local variable dollar_bar and "
211 "dollar_quux and they cannot be unset!\n");
212 }
213
214 return 0;
215 }
216 HUSH_TEST(hush_test_command_dollar, UTF_CONSOLE);
217