162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only
262306a36Sopenharmony_ci#include <sys/types.h>
362306a36Sopenharmony_ci#include <sys/stat.h>
462306a36Sopenharmony_ci#include <fcntl.h>
562306a36Sopenharmony_ci#include <limits.h>
662306a36Sopenharmony_ci#include <stdio.h>
762306a36Sopenharmony_ci#include <stdlib.h>
862306a36Sopenharmony_ci#include <string.h>
962306a36Sopenharmony_ci#include <unistd.h>
1062306a36Sopenharmony_ci
1162306a36Sopenharmony_ci#include "debug.h"
1262306a36Sopenharmony_ci#include "tests.h"
1362306a36Sopenharmony_ci#include <api/io.h>
1462306a36Sopenharmony_ci#include <linux/kernel.h>
1562306a36Sopenharmony_ci#include <linux/zalloc.h>
1662306a36Sopenharmony_ci
1762306a36Sopenharmony_ci#define TEMPL "/tmp/perf-test-XXXXXX"
1862306a36Sopenharmony_ci
1962306a36Sopenharmony_ci#define EXPECT_EQUAL(val, expected)                             \
2062306a36Sopenharmony_cido {								\
2162306a36Sopenharmony_ci	if (val != expected) {					\
2262306a36Sopenharmony_ci		pr_debug("%s:%d: %d != %d\n",			\
2362306a36Sopenharmony_ci			__FILE__, __LINE__, val, expected);	\
2462306a36Sopenharmony_ci		ret = -1;					\
2562306a36Sopenharmony_ci	}							\
2662306a36Sopenharmony_ci} while (0)
2762306a36Sopenharmony_ci
2862306a36Sopenharmony_ci#define EXPECT_EQUAL64(val, expected)                           \
2962306a36Sopenharmony_cido {								\
3062306a36Sopenharmony_ci	if (val != expected) {					\
3162306a36Sopenharmony_ci		pr_debug("%s:%d: %lld != %lld\n",		\
3262306a36Sopenharmony_ci			__FILE__, __LINE__, val, expected);	\
3362306a36Sopenharmony_ci		ret = -1;					\
3462306a36Sopenharmony_ci	}							\
3562306a36Sopenharmony_ci} while (0)
3662306a36Sopenharmony_ci
3762306a36Sopenharmony_cistatic int make_test_file(char path[PATH_MAX], const char *contents)
3862306a36Sopenharmony_ci{
3962306a36Sopenharmony_ci	ssize_t contents_len = strlen(contents);
4062306a36Sopenharmony_ci	int fd;
4162306a36Sopenharmony_ci
4262306a36Sopenharmony_ci	strcpy(path, TEMPL);
4362306a36Sopenharmony_ci	fd = mkstemp(path);
4462306a36Sopenharmony_ci	if (fd < 0) {
4562306a36Sopenharmony_ci		pr_debug("mkstemp failed");
4662306a36Sopenharmony_ci		return -1;
4762306a36Sopenharmony_ci	}
4862306a36Sopenharmony_ci	if (write(fd, contents, contents_len) < contents_len) {
4962306a36Sopenharmony_ci		pr_debug("short write");
5062306a36Sopenharmony_ci		close(fd);
5162306a36Sopenharmony_ci		unlink(path);
5262306a36Sopenharmony_ci		return -1;
5362306a36Sopenharmony_ci	}
5462306a36Sopenharmony_ci	close(fd);
5562306a36Sopenharmony_ci	return 0;
5662306a36Sopenharmony_ci}
5762306a36Sopenharmony_ci
5862306a36Sopenharmony_cistatic int setup_test(char path[PATH_MAX], const char *contents,
5962306a36Sopenharmony_ci		      size_t buf_size, struct io *io)
6062306a36Sopenharmony_ci{
6162306a36Sopenharmony_ci	if (make_test_file(path, contents))
6262306a36Sopenharmony_ci		return -1;
6362306a36Sopenharmony_ci
6462306a36Sopenharmony_ci	io->fd = open(path, O_RDONLY);
6562306a36Sopenharmony_ci	if (io->fd < 0) {
6662306a36Sopenharmony_ci		pr_debug("Failed to open '%s'\n", path);
6762306a36Sopenharmony_ci		unlink(path);
6862306a36Sopenharmony_ci		return -1;
6962306a36Sopenharmony_ci	}
7062306a36Sopenharmony_ci	io->buf = malloc(buf_size);
7162306a36Sopenharmony_ci	if (io->buf == NULL) {
7262306a36Sopenharmony_ci		pr_debug("Failed to allocate memory");
7362306a36Sopenharmony_ci		close(io->fd);
7462306a36Sopenharmony_ci		unlink(path);
7562306a36Sopenharmony_ci		return -1;
7662306a36Sopenharmony_ci	}
7762306a36Sopenharmony_ci	io__init(io, io->fd, io->buf, buf_size);
7862306a36Sopenharmony_ci	return 0;
7962306a36Sopenharmony_ci}
8062306a36Sopenharmony_ci
8162306a36Sopenharmony_cistatic void cleanup_test(char path[PATH_MAX], struct io *io)
8262306a36Sopenharmony_ci{
8362306a36Sopenharmony_ci	zfree(&io->buf);
8462306a36Sopenharmony_ci	close(io->fd);
8562306a36Sopenharmony_ci	unlink(path);
8662306a36Sopenharmony_ci}
8762306a36Sopenharmony_ci
8862306a36Sopenharmony_cistatic int do_test_get_char(const char *test_string, size_t buf_size)
8962306a36Sopenharmony_ci{
9062306a36Sopenharmony_ci	char path[PATH_MAX];
9162306a36Sopenharmony_ci	struct io io;
9262306a36Sopenharmony_ci	int ch, ret = 0;
9362306a36Sopenharmony_ci	size_t i;
9462306a36Sopenharmony_ci
9562306a36Sopenharmony_ci	if (setup_test(path, test_string, buf_size, &io))
9662306a36Sopenharmony_ci		return -1;
9762306a36Sopenharmony_ci
9862306a36Sopenharmony_ci	for (i = 0; i < strlen(test_string); i++) {
9962306a36Sopenharmony_ci		ch = io__get_char(&io);
10062306a36Sopenharmony_ci
10162306a36Sopenharmony_ci		EXPECT_EQUAL(ch, test_string[i]);
10262306a36Sopenharmony_ci		EXPECT_EQUAL(io.eof, false);
10362306a36Sopenharmony_ci	}
10462306a36Sopenharmony_ci	ch = io__get_char(&io);
10562306a36Sopenharmony_ci	EXPECT_EQUAL(ch, -1);
10662306a36Sopenharmony_ci	EXPECT_EQUAL(io.eof, true);
10762306a36Sopenharmony_ci
10862306a36Sopenharmony_ci	cleanup_test(path, &io);
10962306a36Sopenharmony_ci	return ret;
11062306a36Sopenharmony_ci}
11162306a36Sopenharmony_ci
11262306a36Sopenharmony_cistatic int test_get_char(void)
11362306a36Sopenharmony_ci{
11462306a36Sopenharmony_ci	int i, ret = 0;
11562306a36Sopenharmony_ci	size_t j;
11662306a36Sopenharmony_ci
11762306a36Sopenharmony_ci	static const char *const test_strings[] = {
11862306a36Sopenharmony_ci		"12345678abcdef90",
11962306a36Sopenharmony_ci		"a\nb\nc\nd\n",
12062306a36Sopenharmony_ci		"\a\b\t\v\f\r",
12162306a36Sopenharmony_ci	};
12262306a36Sopenharmony_ci	for (i = 0; i <= 10; i++) {
12362306a36Sopenharmony_ci		for (j = 0; j < ARRAY_SIZE(test_strings); j++) {
12462306a36Sopenharmony_ci			if (do_test_get_char(test_strings[j], 1 << i))
12562306a36Sopenharmony_ci				ret = -1;
12662306a36Sopenharmony_ci		}
12762306a36Sopenharmony_ci	}
12862306a36Sopenharmony_ci	return ret;
12962306a36Sopenharmony_ci}
13062306a36Sopenharmony_ci
13162306a36Sopenharmony_cistatic int do_test_get_hex(const char *test_string,
13262306a36Sopenharmony_ci			__u64 val1, int ch1,
13362306a36Sopenharmony_ci			__u64 val2, int ch2,
13462306a36Sopenharmony_ci			__u64 val3, int ch3,
13562306a36Sopenharmony_ci			bool end_eof)
13662306a36Sopenharmony_ci{
13762306a36Sopenharmony_ci	char path[PATH_MAX];
13862306a36Sopenharmony_ci	struct io io;
13962306a36Sopenharmony_ci	int ch, ret = 0;
14062306a36Sopenharmony_ci	__u64 hex;
14162306a36Sopenharmony_ci
14262306a36Sopenharmony_ci	if (setup_test(path, test_string, 4, &io))
14362306a36Sopenharmony_ci		return -1;
14462306a36Sopenharmony_ci
14562306a36Sopenharmony_ci	ch = io__get_hex(&io, &hex);
14662306a36Sopenharmony_ci	EXPECT_EQUAL64(hex, val1);
14762306a36Sopenharmony_ci	EXPECT_EQUAL(ch, ch1);
14862306a36Sopenharmony_ci
14962306a36Sopenharmony_ci	ch = io__get_hex(&io, &hex);
15062306a36Sopenharmony_ci	EXPECT_EQUAL64(hex, val2);
15162306a36Sopenharmony_ci	EXPECT_EQUAL(ch, ch2);
15262306a36Sopenharmony_ci
15362306a36Sopenharmony_ci	ch = io__get_hex(&io, &hex);
15462306a36Sopenharmony_ci	EXPECT_EQUAL64(hex, val3);
15562306a36Sopenharmony_ci	EXPECT_EQUAL(ch, ch3);
15662306a36Sopenharmony_ci
15762306a36Sopenharmony_ci	EXPECT_EQUAL(io.eof, end_eof);
15862306a36Sopenharmony_ci
15962306a36Sopenharmony_ci	cleanup_test(path, &io);
16062306a36Sopenharmony_ci	return ret;
16162306a36Sopenharmony_ci}
16262306a36Sopenharmony_ci
16362306a36Sopenharmony_cistatic int test_get_hex(void)
16462306a36Sopenharmony_ci{
16562306a36Sopenharmony_ci	int ret = 0;
16662306a36Sopenharmony_ci
16762306a36Sopenharmony_ci	if (do_test_get_hex("12345678abcdef90",
16862306a36Sopenharmony_ci				0x12345678abcdef90, -1,
16962306a36Sopenharmony_ci				0, -1,
17062306a36Sopenharmony_ci				0, -1,
17162306a36Sopenharmony_ci				true))
17262306a36Sopenharmony_ci		ret = -1;
17362306a36Sopenharmony_ci
17462306a36Sopenharmony_ci	if (do_test_get_hex("1\n2\n3\n",
17562306a36Sopenharmony_ci				1, '\n',
17662306a36Sopenharmony_ci				2, '\n',
17762306a36Sopenharmony_ci				3, '\n',
17862306a36Sopenharmony_ci				false))
17962306a36Sopenharmony_ci		ret = -1;
18062306a36Sopenharmony_ci
18162306a36Sopenharmony_ci	if (do_test_get_hex("12345678ABCDEF90;a;b",
18262306a36Sopenharmony_ci				0x12345678abcdef90, ';',
18362306a36Sopenharmony_ci				0xa, ';',
18462306a36Sopenharmony_ci				0xb, -1,
18562306a36Sopenharmony_ci				true))
18662306a36Sopenharmony_ci		ret = -1;
18762306a36Sopenharmony_ci
18862306a36Sopenharmony_ci	if (do_test_get_hex("0x1x2x",
18962306a36Sopenharmony_ci				0, 'x',
19062306a36Sopenharmony_ci				1, 'x',
19162306a36Sopenharmony_ci				2, 'x',
19262306a36Sopenharmony_ci				false))
19362306a36Sopenharmony_ci		ret = -1;
19462306a36Sopenharmony_ci
19562306a36Sopenharmony_ci	if (do_test_get_hex("x1x",
19662306a36Sopenharmony_ci				0, -2,
19762306a36Sopenharmony_ci				1, 'x',
19862306a36Sopenharmony_ci				0, -1,
19962306a36Sopenharmony_ci				true))
20062306a36Sopenharmony_ci		ret = -1;
20162306a36Sopenharmony_ci
20262306a36Sopenharmony_ci	if (do_test_get_hex("10000000000000000000000000000abcdefgh99i",
20362306a36Sopenharmony_ci				0xabcdef, 'g',
20462306a36Sopenharmony_ci				0, -2,
20562306a36Sopenharmony_ci				0x99, 'i',
20662306a36Sopenharmony_ci				false))
20762306a36Sopenharmony_ci		ret = -1;
20862306a36Sopenharmony_ci
20962306a36Sopenharmony_ci	return ret;
21062306a36Sopenharmony_ci}
21162306a36Sopenharmony_ci
21262306a36Sopenharmony_cistatic int do_test_get_dec(const char *test_string,
21362306a36Sopenharmony_ci			__u64 val1, int ch1,
21462306a36Sopenharmony_ci			__u64 val2, int ch2,
21562306a36Sopenharmony_ci			__u64 val3, int ch3,
21662306a36Sopenharmony_ci			bool end_eof)
21762306a36Sopenharmony_ci{
21862306a36Sopenharmony_ci	char path[PATH_MAX];
21962306a36Sopenharmony_ci	struct io io;
22062306a36Sopenharmony_ci	int ch, ret = 0;
22162306a36Sopenharmony_ci	__u64 dec;
22262306a36Sopenharmony_ci
22362306a36Sopenharmony_ci	if (setup_test(path, test_string, 4, &io))
22462306a36Sopenharmony_ci		return -1;
22562306a36Sopenharmony_ci
22662306a36Sopenharmony_ci	ch = io__get_dec(&io, &dec);
22762306a36Sopenharmony_ci	EXPECT_EQUAL64(dec, val1);
22862306a36Sopenharmony_ci	EXPECT_EQUAL(ch, ch1);
22962306a36Sopenharmony_ci
23062306a36Sopenharmony_ci	ch = io__get_dec(&io, &dec);
23162306a36Sopenharmony_ci	EXPECT_EQUAL64(dec, val2);
23262306a36Sopenharmony_ci	EXPECT_EQUAL(ch, ch2);
23362306a36Sopenharmony_ci
23462306a36Sopenharmony_ci	ch = io__get_dec(&io, &dec);
23562306a36Sopenharmony_ci	EXPECT_EQUAL64(dec, val3);
23662306a36Sopenharmony_ci	EXPECT_EQUAL(ch, ch3);
23762306a36Sopenharmony_ci
23862306a36Sopenharmony_ci	EXPECT_EQUAL(io.eof, end_eof);
23962306a36Sopenharmony_ci
24062306a36Sopenharmony_ci	cleanup_test(path, &io);
24162306a36Sopenharmony_ci	return ret;
24262306a36Sopenharmony_ci}
24362306a36Sopenharmony_ci
24462306a36Sopenharmony_cistatic int test_get_dec(void)
24562306a36Sopenharmony_ci{
24662306a36Sopenharmony_ci	int ret = 0;
24762306a36Sopenharmony_ci
24862306a36Sopenharmony_ci	if (do_test_get_dec("12345678abcdef90",
24962306a36Sopenharmony_ci				12345678, 'a',
25062306a36Sopenharmony_ci				0, -2,
25162306a36Sopenharmony_ci				0, -2,
25262306a36Sopenharmony_ci				false))
25362306a36Sopenharmony_ci		ret = -1;
25462306a36Sopenharmony_ci
25562306a36Sopenharmony_ci	if (do_test_get_dec("1\n2\n3\n",
25662306a36Sopenharmony_ci				1, '\n',
25762306a36Sopenharmony_ci				2, '\n',
25862306a36Sopenharmony_ci				3, '\n',
25962306a36Sopenharmony_ci				false))
26062306a36Sopenharmony_ci		ret = -1;
26162306a36Sopenharmony_ci
26262306a36Sopenharmony_ci	if (do_test_get_dec("12345678;1;2",
26362306a36Sopenharmony_ci				12345678, ';',
26462306a36Sopenharmony_ci				1, ';',
26562306a36Sopenharmony_ci				2, -1,
26662306a36Sopenharmony_ci				true))
26762306a36Sopenharmony_ci		ret = -1;
26862306a36Sopenharmony_ci
26962306a36Sopenharmony_ci	if (do_test_get_dec("0x1x2x",
27062306a36Sopenharmony_ci				0, 'x',
27162306a36Sopenharmony_ci				1, 'x',
27262306a36Sopenharmony_ci				2, 'x',
27362306a36Sopenharmony_ci				false))
27462306a36Sopenharmony_ci		ret = -1;
27562306a36Sopenharmony_ci
27662306a36Sopenharmony_ci	if (do_test_get_dec("x1x",
27762306a36Sopenharmony_ci				0, -2,
27862306a36Sopenharmony_ci				1, 'x',
27962306a36Sopenharmony_ci				0, -1,
28062306a36Sopenharmony_ci				true))
28162306a36Sopenharmony_ci		ret = -1;
28262306a36Sopenharmony_ci
28362306a36Sopenharmony_ci	if (do_test_get_dec("10000000000000000000000000000000000000000000000000000000000123456789ab99c",
28462306a36Sopenharmony_ci				123456789, 'a',
28562306a36Sopenharmony_ci				0, -2,
28662306a36Sopenharmony_ci				99, 'c',
28762306a36Sopenharmony_ci				false))
28862306a36Sopenharmony_ci		ret = -1;
28962306a36Sopenharmony_ci
29062306a36Sopenharmony_ci	return ret;
29162306a36Sopenharmony_ci}
29262306a36Sopenharmony_ci
29362306a36Sopenharmony_cistatic int test_get_line(void)
29462306a36Sopenharmony_ci{
29562306a36Sopenharmony_ci	char path[PATH_MAX];
29662306a36Sopenharmony_ci	struct io io;
29762306a36Sopenharmony_ci	char test_string[1024];
29862306a36Sopenharmony_ci	char *line = NULL;
29962306a36Sopenharmony_ci	size_t i, line_len = 0;
30062306a36Sopenharmony_ci	size_t buf_size = 128;
30162306a36Sopenharmony_ci	int ret = 0;
30262306a36Sopenharmony_ci
30362306a36Sopenharmony_ci	for (i = 0; i < 512; i++)
30462306a36Sopenharmony_ci		test_string[i] = 'a';
30562306a36Sopenharmony_ci	test_string[512] = '\n';
30662306a36Sopenharmony_ci	for (i = 513; i < 1023; i++)
30762306a36Sopenharmony_ci		test_string[i] = 'b';
30862306a36Sopenharmony_ci	test_string[1023] = '\0';
30962306a36Sopenharmony_ci
31062306a36Sopenharmony_ci	if (setup_test(path, test_string, buf_size, &io))
31162306a36Sopenharmony_ci		return -1;
31262306a36Sopenharmony_ci
31362306a36Sopenharmony_ci	EXPECT_EQUAL((int)io__getline(&io, &line, &line_len), 513);
31462306a36Sopenharmony_ci	EXPECT_EQUAL((int)strlen(line), 513);
31562306a36Sopenharmony_ci	for (i = 0; i < 512; i++)
31662306a36Sopenharmony_ci		EXPECT_EQUAL(line[i], 'a');
31762306a36Sopenharmony_ci	EXPECT_EQUAL(line[512], '\n');
31862306a36Sopenharmony_ci	EXPECT_EQUAL((int)io__getline(&io, &line, &line_len), 510);
31962306a36Sopenharmony_ci	for (i = 0; i < 510; i++)
32062306a36Sopenharmony_ci		EXPECT_EQUAL(line[i], 'b');
32162306a36Sopenharmony_ci
32262306a36Sopenharmony_ci	free(line);
32362306a36Sopenharmony_ci	cleanup_test(path, &io);
32462306a36Sopenharmony_ci	return ret;
32562306a36Sopenharmony_ci}
32662306a36Sopenharmony_ci
32762306a36Sopenharmony_cistatic int test__api_io(struct test_suite *test __maybe_unused,
32862306a36Sopenharmony_ci			int subtest __maybe_unused)
32962306a36Sopenharmony_ci{
33062306a36Sopenharmony_ci	int ret = 0;
33162306a36Sopenharmony_ci
33262306a36Sopenharmony_ci	if (test_get_char())
33362306a36Sopenharmony_ci		ret = TEST_FAIL;
33462306a36Sopenharmony_ci	if (test_get_hex())
33562306a36Sopenharmony_ci		ret = TEST_FAIL;
33662306a36Sopenharmony_ci	if (test_get_dec())
33762306a36Sopenharmony_ci		ret = TEST_FAIL;
33862306a36Sopenharmony_ci	if (test_get_line())
33962306a36Sopenharmony_ci		ret = TEST_FAIL;
34062306a36Sopenharmony_ci	return ret;
34162306a36Sopenharmony_ci}
34262306a36Sopenharmony_ci
34362306a36Sopenharmony_ciDEFINE_SUITE("Test api io", api_io);
344