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