1 // SPDX-License-Identifier: GPL-2.0+
2 /*
3  * Simple unit test library
4  *
5  * Copyright (c) 2013 Google, Inc
6  */
7 
8 #include <console.h>
9 #include <malloc.h>
10 #ifdef CONFIG_SANDBOX
11 #include <asm/state.h>
12 #endif
13 #include <asm/global_data.h>
14 #include <test/test.h>
15 #include <test/ut.h>
16 
17 DECLARE_GLOBAL_DATA_PTR;
18 
ut_fail(struct unit_test_state * uts,const char * fname,int line,const char * func,const char * cond)19 void ut_fail(struct unit_test_state *uts, const char *fname, int line,
20 	     const char *func, const char *cond)
21 {
22 	gd->flags &= ~(GD_FLG_SILENT | GD_FLG_RECORD);
23 	printf("%s:%d, %s(): %s\n", fname, line, func, cond);
24 	uts->cur.fail_count++;
25 }
26 
ut_failf(struct unit_test_state * uts,const char * fname,int line,const char * func,const char * cond,const char * fmt,...)27 void ut_failf(struct unit_test_state *uts, const char *fname, int line,
28 	      const char *func, const char *cond, const char *fmt, ...)
29 {
30 	va_list args;
31 
32 	gd->flags &= ~(GD_FLG_SILENT | GD_FLG_RECORD);
33 	printf("%s:%d, %s(): %s: ", fname, line, func, cond);
34 	va_start(args, fmt);
35 	vprintf(fmt, args);
36 	va_end(args);
37 	putc('\n');
38 	uts->cur.fail_count++;
39 }
40 
ut_check_free(void)41 ulong ut_check_free(void)
42 {
43 	struct mallinfo info = mallinfo();
44 
45 	return info.uordblks;
46 }
47 
ut_check_delta(ulong last)48 long ut_check_delta(ulong last)
49 {
50 	return ut_check_free() - last;
51 }
52 
readline_check(struct unit_test_state * uts)53 static int readline_check(struct unit_test_state *uts)
54 {
55 	int ret;
56 
57 	ret = console_record_readline(uts->actual_str, sizeof(uts->actual_str));
58 	if (ret == -ENOSPC) {
59 		ut_fail(uts, __FILE__, __LINE__, __func__,
60 			"Console record buffer too small - increase CONFIG_CONSOLE_RECORD_OUT_SIZE");
61 		return ret;
62 	} else if (ret == -ENOENT) {
63 		strcpy(uts->actual_str, "<no-more-output>");
64 	}
65 
66 	return ret;
67 }
68 
ut_check_console_line(struct unit_test_state * uts,const char * fmt,...)69 int ut_check_console_line(struct unit_test_state *uts, const char *fmt, ...)
70 {
71 	va_list args;
72 	int len;
73 	int ret;
74 
75 	va_start(args, fmt);
76 	len = vsnprintf(uts->expect_str, sizeof(uts->expect_str), fmt, args);
77 	va_end(args);
78 	if (len >= sizeof(uts->expect_str)) {
79 		ut_fail(uts, __FILE__, __LINE__, __func__,
80 			"unit_test_state->expect_str too small");
81 		return -EOVERFLOW;
82 	}
83 	ret = readline_check(uts);
84 	if (ret == -ENOENT)
85 		return 1;
86 
87 	return strcmp(uts->expect_str, uts->actual_str);
88 }
89 
ut_check_console_linen(struct unit_test_state * uts,const char * fmt,...)90 int ut_check_console_linen(struct unit_test_state *uts, const char *fmt, ...)
91 {
92 	va_list args;
93 	int len;
94 	int ret;
95 
96 	va_start(args, fmt);
97 	len = vsnprintf(uts->expect_str, sizeof(uts->expect_str), fmt, args);
98 	va_end(args);
99 	if (len >= sizeof(uts->expect_str)) {
100 		ut_fail(uts, __FILE__, __LINE__, __func__,
101 			"unit_test_state->expect_str too small");
102 		return -EOVERFLOW;
103 	}
104 	ret = readline_check(uts);
105 	if (ret < 0)
106 		return ret;
107 
108 	return strncmp(uts->expect_str, uts->actual_str,
109 		       strlen(uts->expect_str));
110 }
111 
ut_check_skipline(struct unit_test_state * uts)112 int ut_check_skipline(struct unit_test_state *uts)
113 {
114 	int ret;
115 
116 	if (!console_record_avail())
117 		return -ENFILE;
118 	ret = readline_check(uts);
119 	if (ret < 0)
120 		return ret;
121 
122 	return 0;
123 }
124 
ut_check_skip_to_linen(struct unit_test_state * uts,const char * fmt,...)125 int ut_check_skip_to_linen(struct unit_test_state *uts, const char *fmt, ...)
126 {
127 	va_list args;
128 	int len;
129 	int ret;
130 
131 	va_start(args, fmt);
132 	len = vsnprintf(uts->expect_str, sizeof(uts->expect_str), fmt, args);
133 	va_end(args);
134 	if (len >= sizeof(uts->expect_str)) {
135 		ut_fail(uts, __FILE__, __LINE__, __func__,
136 			"unit_test_state->expect_str too small");
137 		return -EOVERFLOW;
138 	}
139 	while (1) {
140 		if (!console_record_avail())
141 			return -ENOENT;
142 		ret = readline_check(uts);
143 		if (ret < 0)
144 			return ret;
145 
146 		if (!strncmp(uts->expect_str, uts->actual_str,
147 			     strlen(uts->expect_str)))
148 			return 0;
149 	}
150 }
151 
ut_check_skip_to_line(struct unit_test_state * uts,const char * fmt,...)152 int ut_check_skip_to_line(struct unit_test_state *uts, const char *fmt, ...)
153 {
154 	va_list args;
155 	int len;
156 	int ret;
157 
158 	va_start(args, fmt);
159 	len = vsnprintf(uts->expect_str, sizeof(uts->expect_str), fmt, args);
160 	va_end(args);
161 	if (len >= sizeof(uts->expect_str)) {
162 		ut_fail(uts, __FILE__, __LINE__, __func__,
163 			"unit_test_state->expect_str too small");
164 		return -EOVERFLOW;
165 	}
166 	while (1) {
167 		if (!console_record_avail())
168 			return -ENOENT;
169 		ret = readline_check(uts);
170 		if (ret < 0)
171 			return ret;
172 
173 		if (!strcmp(uts->expect_str, uts->actual_str))
174 			return 0;
175 	}
176 }
177 
ut_check_console_end(struct unit_test_state * uts)178 int ut_check_console_end(struct unit_test_state *uts)
179 {
180 	int ret;
181 
182 	if (!console_record_avail())
183 		return 0;
184 	ret = readline_check(uts);
185 	if (ret < 0)
186 		return ret;
187 
188 	return 1;
189 }
190 
ut_check_console_dump(struct unit_test_state * uts,int total_bytes)191 int ut_check_console_dump(struct unit_test_state *uts, int total_bytes)
192 {
193 	char *str = uts->actual_str;
194 	int upto;
195 
196 	/* Handle empty dump */
197 	if (!total_bytes)
198 		return 0;
199 
200 	for (upto = 0; upto < total_bytes;) {
201 		int len;
202 		int bytes;
203 
204 		len = console_record_readline(str, sizeof(uts->actual_str));
205 		if (str[8] != ':' || str[9] != ' ')
206 			return 1;
207 
208 		bytes = len - 8 - 2 - 3 * 16 - 2;
209 		upto += bytes;
210 	}
211 
212 	return upto == total_bytes ? 0 : 1;
213 }
214 
ut_silence_console(struct unit_test_state * uts)215 void ut_silence_console(struct unit_test_state *uts)
216 {
217 #ifdef CONFIG_SANDBOX
218 	struct sandbox_state *state = state_get_current();
219 
220 	if (!state->show_test_output)
221 		gd->flags |= GD_FLG_SILENT;
222 #endif
223 }
224 
ut_unsilence_console(struct unit_test_state * uts)225 void ut_unsilence_console(struct unit_test_state *uts)
226 {
227 	gd->flags &= ~(GD_FLG_SILENT | GD_FLG_RECORD);
228 }
229 
ut_set_skip_delays(struct unit_test_state * uts,bool skip_delays)230 void ut_set_skip_delays(struct unit_test_state *uts, bool skip_delays)
231 {
232 #ifdef CONFIG_SANDBOX
233 	state_set_skip_delays(skip_delays);
234 #endif
235 }
236