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) \
20do { \
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) \
29do { \
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
37static 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
58static 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
81static void cleanup_test(char path[PATH_MAX], struct io *io)
82{
83 zfree(&io->buf);
84 close(io->fd);
85 unlink(path);
86}
87
88static 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
112static 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
131static 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
163static 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
212static 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
244static 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
293static 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
327static 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
343DEFINE_SUITE("Test api io", api_io);
344

source code of linux/tools/perf/tests/api-io.c