1// SPDX-License-Identifier: GPL-2.1+
2/*
3 * Copyright (C) 2021 Sean Anderson <seanga2@gmail.com>
4 * Copyright (C) 2011-2021 Free Software Foundation, Inc.
5 *
6 * These tests adapted from glibc's string/test-strncat.c
7 */
8
9#include <common.h>
10#include <test/lib.h>
11#include <test/test.h>
12#include <test/ut.h>
13
14#define BUF_SIZE 4096
15char buf1[BUF_SIZE], buf2[BUF_SIZE];
16
17static int do_test_strlcat(struct unit_test_state *uts, int line, size_t align1,
18			   size_t align2, size_t len1, size_t len2, size_t n)
19{
20	char *s1, *s2;
21	size_t i, len, expected, actual;
22
23	align1 &= 7;
24	if (align1 + len1 >= BUF_SIZE)
25		return 0;
26	if (align1 + n > BUF_SIZE)
27		return 0;
28
29	align2 &= 7;
30	if (align2 + len1 + len2 >= BUF_SIZE)
31		return 0;
32	if (align2 + len1 + n > BUF_SIZE)
33		return 0;
34
35	s1 = buf1 + align1;
36	s2 = buf2 + align2;
37
38	for (i = 0; i < len1 - 1; i++)
39		s1[i] = 32 + 23 * i % (127 - 32);
40	s1[len1 - 1] = '\0';
41
42	for (i = 0; i < len2 - 1; i++)
43		s2[i] = 32 + 23 * i % (127 - 32);
44	s2[len2 - 1] = '\0';
45
46	expected = min(strlen(s2), n) + strlen(s1);
47	actual = strlcat(s2, s1, n);
48	if (expected != actual) {
49		ut_failf(uts, __FILE__, line, __func__,
50			 "strlcat(s2, s1, n) == min(len2, n) + len1",
51			 "Expected %#zx (%zd), got %#zx (%zd)",
52			 expected, expected, actual, actual);
53		return CMD_RET_FAILURE;
54	}
55
56	len = min3(len1, n - len2, (size_t)0);
57	if (memcmp(s2 + len2, s1, len)) {
58		ut_failf(uts, __FILE__, line, __func__,
59			 "s2 + len1 == s1",
60			 "Expected \"%.*s\", got \"%.*s\"",
61			 (int)len, s1, (int)len, s2 + len2);
62		return CMD_RET_FAILURE;
63	}
64
65	i = min(n, len1 + len2 - 1) - 1;
66	if (len2 < n && s2[i] != '\0') {
67		ut_failf(uts, __FILE__, line, __func__,
68			 "n < len1 && s2[len2 + n] == '\\0'",
69			 "Expected s2[%zd] = '\\0', got %d ('%c')",
70			 i, s2[i], s2[i]);
71		return CMD_RET_FAILURE;
72	}
73
74	return 0;
75}
76
77#define test_strlcat(align1, align2, len1, len2, n) do { \
78	int ret = do_test_strlcat(uts, __LINE__, align1, align2, len1, len2, \
79				  n); \
80	if (ret) \
81		return ret; \
82} while (0)
83
84static int lib_test_strlcat(struct unit_test_state *uts)
85{
86	size_t i, n;
87
88	test_strlcat(0, 2, 2, 2, SIZE_MAX);
89	test_strlcat(0, 0, 4, 4, SIZE_MAX);
90	test_strlcat(4, 0, 4, 4, SIZE_MAX);
91	test_strlcat(0, 0, 8, 8, SIZE_MAX);
92	test_strlcat(0, 8, 8, 8, SIZE_MAX);
93
94	for (i = 1; i < 8; i++) {
95		test_strlcat(0, 0, 8 << i, 8 << i, SIZE_MAX);
96		test_strlcat(8 - i, 2 * i, 8 << i, 8 << i, SIZE_MAX);
97		test_strlcat(0, 0, 8 << i, 2 << i, SIZE_MAX);
98		test_strlcat(8 - i, 2 * i, 8 << i, 2 << i, SIZE_MAX);
99
100		test_strlcat(i, 2 * i, 8 << i, 1, SIZE_MAX);
101		test_strlcat(2 * i, i, 8 << i, 1, SIZE_MAX);
102		test_strlcat(i, i, 8 << i, 10, SIZE_MAX);
103	}
104
105	for (n = 2; n <= 2048; n *= 4) {
106		test_strlcat(0, 2, 2, 2, n);
107		test_strlcat(0, 0, 4, 4, n);
108		test_strlcat(4, 0, 4, 4, n);
109		test_strlcat(0, 0, 8, 8, n);
110		test_strlcat(0, 8, 8, 8, n);
111
112		for (i = 1; i < 8; i++) {
113			test_strlcat(0, 0, 8 << i, 8 << i, n);
114			test_strlcat(8 - i, 2 * i, 8 << i, 8 << i, n);
115			test_strlcat(0, 0, 8 << i, 2 << i, n);
116			test_strlcat(8 - i, 2 * i, 8 << i, 2 << i, n);
117
118			test_strlcat(i, 2 * i, 8 << i, 1, n);
119			test_strlcat(2 * i, i, 8 << i, 1, n);
120			test_strlcat(i, i, 8 << i, 10, n);
121		}
122	}
123
124	return 0;
125}
126LIB_TEST(lib_test_strlcat, 0);
127