1 // SPDX-License-Identifier: GPL-2.0-only
2 #include <sys/types.h>
3 #include <sys/stat.h>
4 #include <fcntl.h>
5 #include <limits.h>
6 #include <stdio.h>
7 #include <stdlib.h>
8 #include <string.h>
9 #include <unistd.h>
10 
11 #include "debug.h"
12 #include "tests.h"
13 #include <api/io.h>
14 #include <linux/kernel.h>
15 
16 #define TEMPL "/tmp/perf-test-XXXXXX"
17 
18 #define EXPECT_EQUAL(val, expected)                             \
19 do {								\
20 	if (val != expected) {					\
21 		pr_debug("%s:%d: %d != %d\n",			\
22 			__FILE__, __LINE__, val, expected);	\
23 		ret = -1;					\
24 	}							\
25 } while (0)
26 
27 #define EXPECT_EQUAL64(val, expected)                           \
28 do {								\
29 	if (val != expected) {					\
30 		pr_debug("%s:%d: %lld != %lld\n",		\
31 			__FILE__, __LINE__, val, expected);	\
32 		ret = -1;					\
33 	}							\
34 } while (0)
35 
make_test_file(char path[PATH_MAX],const char * contents)36 static int make_test_file(char path[PATH_MAX], const char *contents)
37 {
38 	ssize_t contents_len = strlen(contents);
39 	int fd;
40 
41 	strcpy(path, TEMPL);
42 	fd = mkstemp(path);
43 	if (fd < 0) {
44 		pr_debug("mkstemp failed");
45 		return -1;
46 	}
47 	if (write(fd, contents, contents_len) < contents_len) {
48 		pr_debug("short write");
49 		close(fd);
50 		unlink(path);
51 		return -1;
52 	}
53 	close(fd);
54 	return 0;
55 }
56 
setup_test(char path[PATH_MAX],const char * contents,size_t buf_size,struct io * io)57 static int setup_test(char path[PATH_MAX], const char *contents,
58 		      size_t buf_size, struct io *io)
59 {
60 	if (make_test_file(path, contents))
61 		return -1;
62 
63 	io->fd = open(path, O_RDONLY);
64 	if (io->fd < 0) {
65 		pr_debug("Failed to open '%s'\n", path);
66 		unlink(path);
67 		return -1;
68 	}
69 	io->buf = malloc(buf_size);
70 	if (io->buf == NULL) {
71 		pr_debug("Failed to allocate memory");
72 		close(io->fd);
73 		unlink(path);
74 		return -1;
75 	}
76 	io__init(io, io->fd, io->buf, buf_size);
77 	return 0;
78 }
79 
cleanup_test(char path[PATH_MAX],struct io * io)80 static void cleanup_test(char path[PATH_MAX], struct io *io)
81 {
82 	free(io->buf);
83 	close(io->fd);
84 	unlink(path);
85 }
86 
do_test_get_char(const char * test_string,size_t buf_size)87 static int do_test_get_char(const char *test_string, size_t buf_size)
88 {
89 	char path[PATH_MAX];
90 	struct io io;
91 	int ch, ret = 0;
92 	size_t i;
93 
94 	if (setup_test(path, test_string, buf_size, &io))
95 		return -1;
96 
97 	for (i = 0; i < strlen(test_string); i++) {
98 		ch = io__get_char(&io);
99 
100 		EXPECT_EQUAL(ch, test_string[i]);
101 		EXPECT_EQUAL(io.eof, false);
102 	}
103 	ch = io__get_char(&io);
104 	EXPECT_EQUAL(ch, -1);
105 	EXPECT_EQUAL(io.eof, true);
106 
107 	cleanup_test(path, &io);
108 	return ret;
109 }
110 
test_get_char(void)111 static int test_get_char(void)
112 {
113 	int i, ret = 0;
114 	size_t j;
115 
116 	static const char *const test_strings[] = {
117 		"12345678abcdef90",
118 		"a\nb\nc\nd\n",
119 		"\a\b\t\v\f\r",
120 	};
121 	for (i = 0; i <= 10; i++) {
122 		for (j = 0; j < ARRAY_SIZE(test_strings); j++) {
123 			if (do_test_get_char(test_strings[j], 1 << i))
124 				ret = -1;
125 		}
126 	}
127 	return ret;
128 }
129 
do_test_get_hex(const char * test_string,__u64 val1,int ch1,__u64 val2,int ch2,__u64 val3,int ch3,bool end_eof)130 static int do_test_get_hex(const char *test_string,
131 			__u64 val1, int ch1,
132 			__u64 val2, int ch2,
133 			__u64 val3, int ch3,
134 			bool end_eof)
135 {
136 	char path[PATH_MAX];
137 	struct io io;
138 	int ch, ret = 0;
139 	__u64 hex;
140 
141 	if (setup_test(path, test_string, 4, &io))
142 		return -1;
143 
144 	ch = io__get_hex(&io, &hex);
145 	EXPECT_EQUAL64(hex, val1);
146 	EXPECT_EQUAL(ch, ch1);
147 
148 	ch = io__get_hex(&io, &hex);
149 	EXPECT_EQUAL64(hex, val2);
150 	EXPECT_EQUAL(ch, ch2);
151 
152 	ch = io__get_hex(&io, &hex);
153 	EXPECT_EQUAL64(hex, val3);
154 	EXPECT_EQUAL(ch, ch3);
155 
156 	EXPECT_EQUAL(io.eof, end_eof);
157 
158 	cleanup_test(path, &io);
159 	return ret;
160 }
161 
test_get_hex(void)162 static int test_get_hex(void)
163 {
164 	int ret = 0;
165 
166 	if (do_test_get_hex("12345678abcdef90",
167 				0x12345678abcdef90, -1,
168 				0, -1,
169 				0, -1,
170 				true))
171 		ret = -1;
172 
173 	if (do_test_get_hex("1\n2\n3\n",
174 				1, '\n',
175 				2, '\n',
176 				3, '\n',
177 				false))
178 		ret = -1;
179 
180 	if (do_test_get_hex("12345678ABCDEF90;a;b",
181 				0x12345678abcdef90, ';',
182 				0xa, ';',
183 				0xb, -1,
184 				true))
185 		ret = -1;
186 
187 	if (do_test_get_hex("0x1x2x",
188 				0, 'x',
189 				1, 'x',
190 				2, 'x',
191 				false))
192 		ret = -1;
193 
194 	if (do_test_get_hex("x1x",
195 				0, -2,
196 				1, 'x',
197 				0, -1,
198 				true))
199 		ret = -1;
200 
201 	if (do_test_get_hex("10000000000000000000000000000abcdefgh99i",
202 				0xabcdef, 'g',
203 				0, -2,
204 				0x99, 'i',
205 				false))
206 		ret = -1;
207 
208 	return ret;
209 }
210 
do_test_get_dec(const char * test_string,__u64 val1,int ch1,__u64 val2,int ch2,__u64 val3,int ch3,bool end_eof)211 static int do_test_get_dec(const char *test_string,
212 			__u64 val1, int ch1,
213 			__u64 val2, int ch2,
214 			__u64 val3, int ch3,
215 			bool end_eof)
216 {
217 	char path[PATH_MAX];
218 	struct io io;
219 	int ch, ret = 0;
220 	__u64 dec;
221 
222 	if (setup_test(path, test_string, 4, &io))
223 		return -1;
224 
225 	ch = io__get_dec(&io, &dec);
226 	EXPECT_EQUAL64(dec, val1);
227 	EXPECT_EQUAL(ch, ch1);
228 
229 	ch = io__get_dec(&io, &dec);
230 	EXPECT_EQUAL64(dec, val2);
231 	EXPECT_EQUAL(ch, ch2);
232 
233 	ch = io__get_dec(&io, &dec);
234 	EXPECT_EQUAL64(dec, val3);
235 	EXPECT_EQUAL(ch, ch3);
236 
237 	EXPECT_EQUAL(io.eof, end_eof);
238 
239 	cleanup_test(path, &io);
240 	return ret;
241 }
242 
test_get_dec(void)243 static int test_get_dec(void)
244 {
245 	int ret = 0;
246 
247 	if (do_test_get_dec("12345678abcdef90",
248 				12345678, 'a',
249 				0, -2,
250 				0, -2,
251 				false))
252 		ret = -1;
253 
254 	if (do_test_get_dec("1\n2\n3\n",
255 				1, '\n',
256 				2, '\n',
257 				3, '\n',
258 				false))
259 		ret = -1;
260 
261 	if (do_test_get_dec("12345678;1;2",
262 				12345678, ';',
263 				1, ';',
264 				2, -1,
265 				true))
266 		ret = -1;
267 
268 	if (do_test_get_dec("0x1x2x",
269 				0, 'x',
270 				1, 'x',
271 				2, 'x',
272 				false))
273 		ret = -1;
274 
275 	if (do_test_get_dec("x1x",
276 				0, -2,
277 				1, 'x',
278 				0, -1,
279 				true))
280 		ret = -1;
281 
282 	if (do_test_get_dec("10000000000000000000000000000000000000000000000000000000000123456789ab99c",
283 				123456789, 'a',
284 				0, -2,
285 				99, 'c',
286 				false))
287 		ret = -1;
288 
289 	return ret;
290 }
291 
test__api_io(struct test * test __maybe_unused,int subtest __maybe_unused)292 int test__api_io(struct test *test __maybe_unused,
293 		int subtest __maybe_unused)
294 {
295 	int ret = 0;
296 
297 	if (test_get_char())
298 		ret = TEST_FAIL;
299 	if (test_get_hex())
300 		ret = TEST_FAIL;
301 	if (test_get_dec())
302 		ret = TEST_FAIL;
303 	return ret;
304 }
305