blob: 85803eb54b8c7e726bca77666554c631f79a9a27 [file] [log] [blame]
Simon Glass663a2c12020-11-01 14:15:35 -07001// SPDX-License-Identifier: GPL-2.0+
2/*
3 * Tests for setexpr command
4 *
5 * Copyright 2020 Google LLC
6 * Written by Simon Glass <sjg@chromium.org>
7 */
8
Simon Glass663a2c12020-11-01 14:15:35 -07009#include <console.h>
10#include <mapmem.h>
11#include <dm/test.h>
Simon Glass663a2c12020-11-01 14:15:35 -070012#include <test/ut.h>
13
14#define BUF_SIZE 0x100
15
Bin Meng0bcbec72021-02-17 17:04:06 +080016/* Declare a new setexpr test */
Simon Glassb15512c2025-01-20 14:25:32 -070017#define SETEXPR_TEST(_name, _flags) UNIT_TEST(_name, _flags, setexpr)
Simon Glass663a2c12020-11-01 14:15:35 -070018
19/* Test 'setexpr' command with simply setting integers */
20static int setexpr_test_int(struct unit_test_state *uts)
21{
22 u8 *buf;
23
24 buf = map_sysmem(0, BUF_SIZE);
25 memset(buf, '\xff', BUF_SIZE);
26
27 /* byte */
28 buf[0x0] = 0x12;
29 ut_assertok(run_command("setexpr.b fred 0", 0));
30 ut_asserteq_str("0", env_get("fred"));
31 ut_assertok(run_command("setexpr.b fred *0", 0));
32 ut_asserteq_str("12", env_get("fred"));
33
34 /* 16-bit */
35 *(short *)buf = 0x2345;
36 ut_assertok(run_command("setexpr.w fred 0", 0));
37 ut_asserteq_str("0", env_get("fred"));
38 ut_assertok(run_command("setexpr.w fred *0", 0));
39 ut_asserteq_str("2345", env_get("fred"));
40
41 /* 32-bit */
42 *(u32 *)buf = 0x3456789a;
43 ut_assertok(run_command("setexpr.l fred 0", 0));
44 ut_asserteq_str("0", env_get("fred"));
45 ut_assertok(run_command("setexpr.l fred *0", 0));
Simon Glass7c19edf2020-11-01 14:15:37 -070046 ut_asserteq_str("3456789a", env_get("fred"));
Simon Glass663a2c12020-11-01 14:15:35 -070047
48 /* 64-bit */
49 *(u64 *)buf = 0x456789abcdef0123;
50 ut_assertok(run_command("setexpr.q fred 0", 0));
51 ut_asserteq_str("0", env_get("fred"));
52 ut_assertok(run_command("setexpr.q fred *0", 0));
53 ut_asserteq_str("456789abcdef0123", env_get("fred"));
54
55 /* default */
56 ut_assertok(run_command("setexpr fred 0", 0));
57 ut_asserteq_str("0", env_get("fred"));
58 ut_assertok(run_command("setexpr fred *0", 0));
Simon Glass7c19edf2020-11-01 14:15:37 -070059 ut_asserteq_str("cdef0123", env_get("fred"));
Simon Glass663a2c12020-11-01 14:15:35 -070060
61 unmap_sysmem(buf);
62
63 return 0;
64}
Simon Glass11fcfa32024-08-22 07:57:50 -060065SETEXPR_TEST(setexpr_test_int, UTF_CONSOLE);
Simon Glass663a2c12020-11-01 14:15:35 -070066
67/* Test 'setexpr' command with + operator */
68static int setexpr_test_plus(struct unit_test_state *uts)
69{
70 char *buf;
71
72 buf = map_sysmem(0, BUF_SIZE);
73 memset(buf, '\xff', BUF_SIZE);
74
75 /* byte */
76 buf[0x0] = 0x12;
77 buf[0x10] = 0x34;
78 ut_assertok(run_command("setexpr.b fred *0 + *10", 0));
79 ut_asserteq_str("46", env_get("fred"));
80
81 /* 16-bit */
82 *(short *)buf = 0x2345;
83 *(short *)(buf + 0x10) = 0xf012;
84 ut_assertok(run_command("setexpr.w fred *0 + *10", 0));
85 ut_asserteq_str("11357", env_get("fred"));
86
87 /* 32-bit */
88 *(u32 *)buf = 0x3456789a;
89 *(u32 *)(buf + 0x10) = 0xc3384235;
90 ut_assertok(run_command("setexpr.l fred *0 + *10", 0));
Simon Glass7c19edf2020-11-01 14:15:37 -070091 ut_asserteq_str("f78ebacf", env_get("fred"));
Simon Glass663a2c12020-11-01 14:15:35 -070092
93 /* 64-bit */
94 *(u64 *)buf = 0x456789abcdef0123;
95 *(u64 *)(buf + 0x10) = 0x4987328372849283;
96 ut_assertok(run_command("setexpr.q fred *0 + *10", 0));
97 ut_asserteq_str("8eeebc2f407393a6", env_get("fred"));
98
99 /* default */
100 ut_assertok(run_command("setexpr fred *0 + *10", 0));
Simon Glass7c19edf2020-11-01 14:15:37 -0700101 ut_asserteq_str("1407393a6", env_get("fred"));
Simon Glass663a2c12020-11-01 14:15:35 -0700102
103 unmap_sysmem(buf);
104
105 return 0;
106}
Simon Glass11fcfa32024-08-22 07:57:50 -0600107SETEXPR_TEST(setexpr_test_plus, UTF_CONSOLE);
Simon Glass663a2c12020-11-01 14:15:35 -0700108
109/* Test 'setexpr' command with other operators */
110static int setexpr_test_oper(struct unit_test_state *uts)
111{
112 char *buf;
113
114 buf = map_sysmem(0, BUF_SIZE);
115 memset(buf, '\xff', BUF_SIZE);
116
117 *(u32 *)buf = 0x1234;
118 *(u32 *)(buf + 0x10) = 0x560000;
119
120 /* Quote | to avoid confusing hush */
121 ut_assertok(run_command("setexpr fred *0 \"|\" *10", 0));
Simon Glass7c19edf2020-11-01 14:15:37 -0700122 ut_asserteq_str("561234", env_get("fred"));
Simon Glass663a2c12020-11-01 14:15:35 -0700123
124 *(u32 *)buf = 0x561200;
125 *(u32 *)(buf + 0x10) = 0x1234;
126
127 /* Quote & to avoid confusing hush */
128 ut_assertok(run_command("setexpr.l fred *0 \"&\" *10", 0));
Simon Glass7c19edf2020-11-01 14:15:37 -0700129 ut_asserteq_str("1200", env_get("fred"));
Simon Glass663a2c12020-11-01 14:15:35 -0700130
131 ut_assertok(run_command("setexpr.l fred *0 ^ *10", 0));
132 ut_asserteq_str("560034", env_get("fred"));
133
134 ut_assertok(run_command("setexpr.l fred *0 - *10", 0));
135 ut_asserteq_str("55ffcc", env_get("fred"));
136
137 ut_assertok(run_command("setexpr.l fred *0 * *10", 0));
Simon Glass7c19edf2020-11-01 14:15:37 -0700138 ut_asserteq_str("61ebfa800", env_get("fred"));
Simon Glass663a2c12020-11-01 14:15:35 -0700139
140 ut_assertok(run_command("setexpr.l fred *0 / *10", 0));
Simon Glass7c19edf2020-11-01 14:15:37 -0700141 ut_asserteq_str("4ba", env_get("fred"));
Simon Glass663a2c12020-11-01 14:15:35 -0700142
143 ut_assertok(run_command("setexpr.l fred *0 % *10", 0));
Simon Glass7c19edf2020-11-01 14:15:37 -0700144 ut_asserteq_str("838", env_get("fred"));
Simon Glass663a2c12020-11-01 14:15:35 -0700145
146 unmap_sysmem(buf);
147
148 return 0;
149}
Simon Glass11fcfa32024-08-22 07:57:50 -0600150SETEXPR_TEST(setexpr_test_oper, UTF_CONSOLE);
Simon Glass663a2c12020-11-01 14:15:35 -0700151
Simon Glassbbcdba82020-11-01 14:15:38 -0700152/* Test 'setexpr' command with regex */
153static int setexpr_test_regex(struct unit_test_state *uts)
154{
155 char *buf, *val;
156
157 buf = map_sysmem(0, BUF_SIZE);
158
159 /* Single substitution */
160 ut_assertok(run_command("setenv fred 'this is a test'", 0));
161 ut_assertok(run_command("setexpr fred sub is us", 0));
162 val = env_get("fred");
163 ut_asserteq_str("thus is a test", val);
164
165 /* Global substitution */
166 ut_assertok(run_command("setenv fred 'this is a test'", 0));
Simon Glass7a114862020-11-01 14:15:42 -0700167 ut_assertok(run_command("setexpr fred gsub is us", 0));
168 val = env_get("fred");
169 ut_asserteq_str("thus us a test", val);
170
Simon Glassbbcdba82020-11-01 14:15:38 -0700171 /* Global substitution */
172 ut_assertok(run_command("setenv fred 'this is a test'", 0));
173 ut_assertok(run_command("setenv mary 'this is a test'", 0));
174 ut_assertok(run_command("setexpr fred gsub is us \"${mary}\"", 0));
175 val = env_get("fred");
176 ut_asserteq_str("thus us a test", val);
177 val = env_get("mary");
178 ut_asserteq_str("this is a test", val);
179
Massimiliano Minella847f69c2024-02-08 15:58:27 +0100180 /* No match */
181 ut_assertok(run_command("setenv fred 'this is a test'", 0));
182 ut_assertok(run_command("setenv mary ''", 0));
183 ut_assertok(run_command("setexpr fred gsub us is \"${fred}\"", 0));
184 ut_assertok(run_command("setexpr mary gsub us is \"${fred}\"", 0));
185 val = env_get("fred");
186 ut_asserteq_str("this is a test", val);
187 val = env_get("mary");
188 ut_asserteq_str("this is a test", val);
189
Simon Glassbbcdba82020-11-01 14:15:38 -0700190 unmap_sysmem(buf);
191
192 return 0;
193}
Simon Glass11fcfa32024-08-22 07:57:50 -0600194SETEXPR_TEST(setexpr_test_regex, UTF_CONSOLE);
Simon Glassbbcdba82020-11-01 14:15:38 -0700195
196/* Test 'setexpr' command with regex replacement that expands the string */
197static int setexpr_test_regex_inc(struct unit_test_state *uts)
198{
199 char *buf, *val;
200
201 buf = map_sysmem(0, BUF_SIZE);
202
203 ut_assertok(run_command("setenv fred 'this is a test'", 0));
Simon Glass7a114862020-11-01 14:15:42 -0700204 ut_assertok(run_command("setexpr fred gsub is much_longer_string", 0));
205 val = env_get("fred");
206 ut_asserteq_str("thmuch_longer_string much_longer_string a test", val);
Simon Glassbbcdba82020-11-01 14:15:38 -0700207 unmap_sysmem(buf);
208
209 return 0;
210}
Simon Glass11fcfa32024-08-22 07:57:50 -0600211SETEXPR_TEST(setexpr_test_regex_inc, UTF_CONSOLE);
Simon Glassbbcdba82020-11-01 14:15:38 -0700212
Simon Glass00e44192020-11-01 14:15:40 -0700213/* Test setexpr_regex_sub() directly to check buffer usage */
214static int setexpr_test_sub(struct unit_test_state *uts)
215{
216 char *buf, *nbuf;
217 int i;
218
219 buf = map_sysmem(0, BUF_SIZE);
220 nbuf = map_sysmem(0x1000, BUF_SIZE);
221
222 /* Add a pattern so we can check the buffer limits */
223 memset(buf, '\xff', BUF_SIZE);
224 memset(nbuf, '\xff', BUF_SIZE);
225 for (i = BUF_SIZE; i < 0x1000; i++) {
226 buf[i] = i & 0xff;
227 nbuf[i] = i & 0xff;
228 }
229 strcpy(buf, "this is a test");
230
231 /*
232 * This is a regression test, since a bug was found in the use of
233 * memmove() in setexpr
234 */
235 ut_assertok(setexpr_regex_sub(buf, BUF_SIZE, nbuf, BUF_SIZE, "is",
236 "us it is longer", true));
237 ut_asserteq_str("thus it is longer us it is longer a test", buf);
Simon Glass00e44192020-11-01 14:15:40 -0700238 for (i = BUF_SIZE; i < 0x1000; i++) {
239 ut_assertf(buf[i] == (char)i,
240 "buf byte at %x should be %02x, got %02x)\n",
241 i, i & 0xff, (u8)buf[i]);
242 ut_assertf(nbuf[i] == (char)i,
243 "nbuf byte at %x should be %02x, got %02x)\n",
244 i, i & 0xff, (u8)nbuf[i]);
245 }
246
247 unmap_sysmem(buf);
248
249 return 0;
250}
Simon Glass11fcfa32024-08-22 07:57:50 -0600251SETEXPR_TEST(setexpr_test_sub, UTF_CONSOLE);
Simon Glass00e44192020-11-01 14:15:40 -0700252
253/* Test setexpr_regex_sub() with back references */
254static int setexpr_test_backref(struct unit_test_state *uts)
255{
256 char *buf, *nbuf;
257 int i;
258
259 buf = map_sysmem(0, BUF_SIZE);
260 nbuf = map_sysmem(0x1000, BUF_SIZE);
261
262 /* Add a pattern so we can check the buffer limits */
263 memset(buf, '\xff', BUF_SIZE);
264 memset(nbuf, '\xff', BUF_SIZE);
265 for (i = BUF_SIZE; i < 0x1000; i++) {
266 buf[i] = i & 0xff;
267 nbuf[i] = i & 0xff;
268 }
269 strcpy(buf, "this is surely a test is it? yes this is indeed a test");
270
271 /*
272 * This is a regression test, since a bug was found in the use of
273 * memmove() in setexpr
274 */
275 ut_assertok(setexpr_regex_sub(buf, BUF_SIZE, nbuf, BUF_SIZE,
276 "(this) (is) (surely|indeed)",
277 "us \\1 \\2 \\3!", true));
Simon Glass00e44192020-11-01 14:15:40 -0700278 ut_asserteq_str("us this is surely! a test is it? yes us this is indeed! a test",
279 buf);
280
281 for (i = BUF_SIZE; i < 0x1000; i++) {
282 ut_assertf(buf[i] == (char)i,
283 "buf byte at %x should be %02x, got %02x)\n",
284 i, i & 0xff, (u8)buf[i]);
285 ut_assertf(nbuf[i] == (char)i,
286 "nbuf byte at %x should be %02x, got %02x)\n",
287 i, i & 0xff, (u8)nbuf[i]);
288 }
289
290 unmap_sysmem(buf);
291
292 return 0;
293}
Simon Glass11fcfa32024-08-22 07:57:50 -0600294SETEXPR_TEST(setexpr_test_backref, UTF_CONSOLE);
Simon Glass00e44192020-11-01 14:15:40 -0700295
Simon Glass580a7a52020-11-01 14:15:44 -0700296/* Test 'setexpr' command with setting strings */
297static int setexpr_test_str(struct unit_test_state *uts)
298{
Simon Glass580a7a52020-11-01 14:15:44 -0700299 char *buf;
300
301 buf = map_sysmem(0, BUF_SIZE);
302 memset(buf, '\xff', BUF_SIZE);
303
Simon Glass580a7a52020-11-01 14:15:44 -0700304 ut_assertok(env_set("fred", "x"));
Heinrich Schuchardt6cd06542025-02-03 16:10:29 +0100305 ut_asserteq(0, run_command("setexpr.s fred 0", 0));
306 ut_asserteq_str("0", env_get("fred"));
Simon Glass580a7a52020-11-01 14:15:44 -0700307
Heinrich Schuchardtbbc2bb92025-02-03 16:10:26 +0100308 strcpy(buf, "hello");
Simon Glass580a7a52020-11-01 14:15:44 -0700309 ut_assertok(env_set("fred", "12345"));
310 ut_assertok(run_command("setexpr.s fred *0", 0));
311 ut_asserteq_str("hello", env_get("fred"));
Simon Glass580a7a52020-11-01 14:15:44 -0700312
313 unmap_sysmem(buf);
314
315 return 0;
316}
Simon Glass11fcfa32024-08-22 07:57:50 -0600317SETEXPR_TEST(setexpr_test_str, UTF_CONSOLE);
Simon Glass580a7a52020-11-01 14:15:44 -0700318
Simon Glass580a7a52020-11-01 14:15:44 -0700319/* Test 'setexpr' command with concatenating strings */
320static int setexpr_test_str_oper(struct unit_test_state *uts)
321{
Simon Glass580a7a52020-11-01 14:15:44 -0700322 char *buf;
323
Heinrich Schuchardt6cd06542025-02-03 16:10:29 +0100324 /* Test concatenation of strings */
325 ut_assertok(run_command("setexpr.s fred '1' + '3'", 0));
326 ut_asserteq_str("13", env_get("fred"));
327
Simon Glass580a7a52020-11-01 14:15:44 -0700328 buf = map_sysmem(0, BUF_SIZE);
329 memset(buf, '\xff', BUF_SIZE);
330 strcpy(buf, "hello");
331 strcpy(buf + 0x10, " there");
332
Simon Glass580a7a52020-11-01 14:15:44 -0700333 ut_asserteq(1, run_command("setexpr.s fred *0 * *10", 0));
Simon Glass580a7a52020-11-01 14:15:44 -0700334 ut_assert_nextline("invalid op");
335 ut_assert_console_end();
336
Simon Glass580a7a52020-11-01 14:15:44 -0700337 ut_assertok(env_set("fred", "12345012345"));
Simon Glass580a7a52020-11-01 14:15:44 -0700338 ut_assertok(run_command("setexpr.s fred *0 + *10", 0));
339 ut_asserteq_str("hello there", env_get("fred"));
Simon Glass8f05ec42021-03-07 17:34:44 -0700340
Simon Glass580a7a52020-11-01 14:15:44 -0700341 unmap_sysmem(buf);
342
343 return 0;
344}
Simon Glass11fcfa32024-08-22 07:57:50 -0600345SETEXPR_TEST(setexpr_test_str_oper, UTF_CONSOLE);
Simon Glass580a7a52020-11-01 14:15:44 -0700346
347/* Test 'setexpr' command with a string that is too long */
348static int setexpr_test_str_long(struct unit_test_state *uts)
349{
350 const int size = 128 << 10; /* setexpr strings are a max of 64KB */
351 char *buf, *val;
352
353 buf = map_sysmem(0, size);
354 memset(buf, 'a', size);
355
356 /* String should be truncated to 64KB */
357 ut_assertok(run_command("setexpr.s fred *0", 0));
358 val = env_get("fred");
359 ut_asserteq(64 << 10, strlen(val));
360
361 unmap_sysmem(buf);
362
363 return 0;
364}
Simon Glass11fcfa32024-08-22 07:57:50 -0600365SETEXPR_TEST(setexpr_test_str_long, UTF_CONSOLE);
Simon Glass580a7a52020-11-01 14:15:44 -0700366
Roland Gaudig63582072021-07-23 12:29:23 +0000367#ifdef CONFIG_CMD_SETEXPR_FMT
368/* Test 'setexpr' command with simply setting integers */
369static int setexpr_test_fmt(struct unit_test_state *uts)
370{
371 u8 *buf;
372
373 buf = map_sysmem(0, BUF_SIZE);
374 memset(buf, '\xff', BUF_SIZE);
375
376 /* Test decimal conversion */
377 ut_assertok(run_command("setexpr fred fmt %d 0xff", 0));
378 ut_asserteq_str("255", env_get("fred"));
379 /* Test hexadecimal conversion with 0x prefix and 4 digits */
380 ut_assertok(run_command("setexpr fred fmt 0x%04x 257", 0));
381 ut_asserteq_str("0x0257", env_get("fred"));
382 /* Test octal conversion with % prefix */
383 ut_assertok(run_command("setexpr fred fmt %%%o 8", 0));
384 ut_asserteq_str("%10", env_get("fred"));
385 /* Test argument surrounded by %% */
386 ut_assertok(run_command("setexpr fred fmt %%%x%% 0xff", 0));
387 ut_asserteq_str("%ff%", env_get("fred"));
388 /* Test escape sequence */
389 ut_assertok(run_command("setexpr fred fmt \"hello\\040world\"", 0));
390 ut_asserteq_str("hello world", env_get("fred"));
391 /* Test %b with string containing octal escape sequence */
392 ut_assertok(run_command("setexpr fred fmt oh%bno \137", 0));
393 ut_asserteq_str("oh_no", env_get("fred"));
394 /* Test %b with string containing \c escape sequence */
395 ut_assertok(run_command("setexpr fred fmt hello%bworld \"\\c\"", 0));
396 ut_asserteq_str("hello", env_get("fred"));
397 /* Test multiple arguments referencing environment varialbes */
398 ut_assertok(run_command("setenv a eff", 0));
399 ut_assertok(run_command("setenv b hello", 0));
400 ut_assertok(run_command("setenv c 0x63", 0));
401 ut_assertok(run_command("setenv d world", 0));
402 ut_assertok(run_command("setexpr fred fmt \"0x%08x-%s-%d-%s\" $a $b $c $d", 0));
403 ut_asserteq_str("0x00000eff-hello-99-world", env_get("fred"));
404 /* Test with two format specifiers, but only one argument */
405 ut_assertok(run_command("setexpr fred fmt %d_%x 100", 0));
406 ut_asserteq_str("256_0", env_get("fred"));
407 /* Test maximum string length */
408 ut_assertok(run_command("setexpr fred fmt \"%0127d\" 7b", 0));
409 ut_asserteq_str("0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000123", env_get("fred"));
410 /* Test maximum unsigned integer size */
411 ut_assertok(run_command("setexpr fred fmt %u ffffffffffffffff", 0));
412 ut_asserteq_str("18446744073709551615", env_get("fred"));
413 /* Test maximum positive integer size */
414 ut_assertok(run_command("setexpr fred fmt %d 7fffffffffffffff", 0));
415 ut_asserteq_str("9223372036854775807", env_get("fred"));
416 /* Test maximum negative integer size */
417 ut_assertok(run_command("setexpr fred fmt %d 8000000000000000", 0));
418 ut_asserteq_str("-9223372036854775808", env_get("fred"));
419 /* Test minimum negative integer size */
420 ut_assertok(run_command("setexpr fred fmt %d ffffffffffffffff", 0));
421 ut_asserteq_str("-1", env_get("fred"));
422 /* Test signed value with + sign */
423 ut_assertok(run_command("setexpr fred fmt %d +5", 0));
424 ut_asserteq_str("5", env_get("fred"));
425 /* Test signed value with - sign */
426 ut_assertok(run_command("setexpr fred fmt %d -4", 0));
427 ut_asserteq_str("-4", env_get("fred"));
428 /* Test unsigned value with + sign */
429 ut_assertok(run_command("setexpr fred fmt %u +3", 0));
430 ut_asserteq_str("3", env_get("fred"));
431 /* Test unsigned value with - sign */
432 ut_assertok(run_command("setexpr fred fmt %x -2", 0));
433 ut_asserteq_str("fffffffffffffffe", env_get("fred"));
434 /* Error test with missing format specifier */
435 ut_asserteq(1, run_command("setexpr fred fmd hello 0xff", 0));
436 /* Error test with invalid format type */
437 ut_asserteq(1, run_command("setexpr fred fmt %a 0xff", 0));
438 /* Error test with incomplete format specifier */
439 ut_asserteq(1, run_command("setexpr fred fmt hello% bf", 0));
440 /* Error exceeding maximum string length */
441 ut_asserteq(1, run_command("setexpr fred fmt \"%0128d\" 456", 0));
442
443 unmap_sysmem(buf);
444
445 return 0;
446}
Simon Glass11fcfa32024-08-22 07:57:50 -0600447SETEXPR_TEST(setexpr_test_fmt, UTF_CONSOLE);
Roland Gaudig63582072021-07-23 12:29:23 +0000448#endif