1 // SPDX-License-Identifier: GPL-2.0+
2 /*
3  * Tests for exit command
4  *
5  * Copyright 2022 Marek Vasut <marex@denx.de>
6  */
7 
8 #include <common.h>
9 #include <console.h>
10 #include <mapmem.h>
11 #include <asm/global_data.h>
12 #include <test/suites.h>
13 #include <test/ut.h>
14 
15 DECLARE_GLOBAL_DATA_PTR;
16 
17 /* Declare a new exit test */
18 #define EXIT_TEST(_name, _flags)	UNIT_TEST(_name, _flags, exit_test)
19 
20 /* Test 'exit addr' getting/setting address */
cmd_exit_test(struct unit_test_state * uts)21 static int cmd_exit_test(struct unit_test_state *uts)
22 {
23 	int i;
24 
25 	/*
26 	 * Test 'exit' with parameter -3, -2, -1, 0, 1, 2, 3 . Use all those
27 	 * parameters to cover also the special return value -2 that is used
28 	 * in HUSH to detect exit command.
29 	 *
30 	 * Always test whether 'exit' command:
31 	 * - exits out of the 'run' command
32 	 * - return value is propagated out of the 'run' command
33 	 * - return value can be tested on outside of 'run' command
34 	 * - return value can be printed outside of 'run' command
35 	 */
36 	for (i = -3; i <= 3; i++) {
37 		ut_assertok(console_record_reset_enable());
38 		ut_assertok(run_commandf("setenv foo 'echo bar ; exit %d ; echo baz' ; run foo ; echo $?", i));
39 		ut_assert_nextline("bar");
40 		ut_assert_nextline("%d", i > 0 ? i : 0);
41 		ut_assertok(ut_check_console_end(uts));
42 
43 		ut_assertok(console_record_reset_enable());
44 		ut_assertok(run_commandf("setenv foo 'echo bar ; exit %d ; echo baz' ; run foo && echo quux ; echo $?", i));
45 		ut_assert_nextline("bar");
46 		if (i <= 0)
47 			ut_assert_nextline("quux");
48 		ut_assert_nextline("%d", i > 0 ? i : 0);
49 		ut_assertok(ut_check_console_end(uts));
50 
51 		ut_assertok(console_record_reset_enable());
52 		ut_assertok(run_commandf("setenv foo 'echo bar ; exit %d ; echo baz' ; run foo || echo quux ; echo $?", i));
53 		ut_assert_nextline("bar");
54 		if (i > 0)
55 			ut_assert_nextline("quux");
56 		/* Either 'exit' returns 0, or 'echo quux' returns 0 */
57 		ut_assert_nextline("0");
58 		ut_assertok(ut_check_console_end(uts));
59 	}
60 
61 	/* Validate that 'exit' behaves the same way as 'exit 0' */
62 	ut_assertok(console_record_reset_enable());
63 	ut_assertok(run_commandf("setenv foo 'echo bar ; exit ; echo baz' ; run foo ; echo $?"));
64 	ut_assert_nextline("bar");
65 	ut_assert_nextline("0");
66 	ut_assertok(ut_check_console_end(uts));
67 
68 	ut_assertok(console_record_reset_enable());
69 	ut_assertok(run_commandf("setenv foo 'echo bar ; exit ; echo baz' ; run foo && echo quux ; echo $?"));
70 	ut_assert_nextline("bar");
71 	ut_assert_nextline("quux");
72 	ut_assert_nextline("0");
73 	ut_assertok(ut_check_console_end(uts));
74 
75 	ut_assertok(console_record_reset_enable());
76 	ut_assertok(run_commandf("setenv foo 'echo bar ; exit ; echo baz' ; run foo || echo quux ; echo $?"));
77 	ut_assert_nextline("bar");
78 	/* Either 'exit' returns 0, or 'echo quux' returns 0 */
79 	ut_assert_nextline("0");
80 	ut_assertok(ut_check_console_end(uts));
81 
82 	/* Validate that return value still propagates from 'run' command */
83 	ut_assertok(console_record_reset_enable());
84 	ut_assertok(run_commandf("setenv foo 'echo bar ; true' ; run foo ; echo $?"));
85 	ut_assert_nextline("bar");
86 	ut_assert_nextline("0");
87 	ut_assertok(ut_check_console_end(uts));
88 
89 	ut_assertok(console_record_reset_enable());
90 	ut_assertok(run_commandf("setenv foo 'echo bar ; true' ; run foo && echo quux ; echo $?"));
91 	ut_assert_nextline("bar");
92 	ut_assert_nextline("quux");
93 	ut_assert_nextline("0");
94 	ut_assertok(ut_check_console_end(uts));
95 
96 	ut_assertok(console_record_reset_enable());
97 	ut_assertok(run_commandf("setenv foo 'echo bar ; true' ; run foo || echo quux ; echo $?"));
98 	ut_assert_nextline("bar");
99 	/* The 'true' returns 0 */
100 	ut_assert_nextline("0");
101 	ut_assertok(ut_check_console_end(uts));
102 
103 	ut_assertok(console_record_reset_enable());
104 	ut_assertok(run_commandf("setenv foo 'echo bar ; false' ; run foo ; echo $?"));
105 	ut_assert_nextline("bar");
106 	ut_assert_nextline("1");
107 	ut_assertok(ut_check_console_end(uts));
108 
109 	ut_assertok(console_record_reset_enable());
110 	ut_assertok(run_commandf("setenv foo 'echo bar ; false' ; run foo && echo quux ; echo $?"));
111 	ut_assert_nextline("bar");
112 	ut_assert_nextline("1");
113 	ut_assertok(ut_check_console_end(uts));
114 
115 	ut_assertok(console_record_reset_enable());
116 	ut_assertok(run_commandf("setenv foo 'echo bar ; false' ; run foo || echo quux ; echo $?"));
117 	ut_assert_nextline("bar");
118 	ut_assert_nextline("quux");
119 	/* The 'echo quux' returns 0 */
120 	ut_assert_nextline("0");
121 	ut_assertok(ut_check_console_end(uts));
122 
123 	return 0;
124 }
125 
126 EXIT_TEST(cmd_exit_test, UT_TESTF_CONSOLE_REC);
127 
do_ut_exit(struct cmd_tbl * cmdtp,int flag,int argc,char * const argv[])128 int do_ut_exit(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[])
129 {
130 	struct unit_test *tests = UNIT_TEST_SUITE_START(exit_test);
131 	const int n_ents = UNIT_TEST_SUITE_COUNT(exit_test);
132 
133 	return cmd_ut_category("cmd_exit", "exit_test_", tests, n_ents,
134 			       argc, argv);
135 }
136