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