1/*-
2 * SPDX-License-Identifier: BSD-2-Clause
3 *
4 * Copyright (c) 2023 Robert Clausecker
5 */
6
7#include <sys/cdefs.h>
8
9#include <dlfcn.h>
10#include <limits.h>
11#include <string.h>
12
13#include <atf-c.h>
14
15static void *(*memrchr_fn)(const void *, int, size_t);
16
17ATF_TC_WITHOUT_HEAD(null);
18ATF_TC_BODY(null, tc)
19{
20	ATF_CHECK_EQ(memrchr_fn(NULL, 42, 0), NULL);
21}
22
23ATF_TC_WITHOUT_HEAD(not_found);
24ATF_TC_BODY(not_found, tc)
25{
26	size_t i, j;
27	char buf[1+15+64+1]; /* offset [0..15] + 64 buffer bytes + sentinels */
28
29	buf[0] = 'X';
30	memset(buf + 1, '-', sizeof(buf) - 1);
31
32	for (i = 0; i < 16; i++)
33		for (j = 0; j < 64; j++) {
34			buf[i + j + 1] = 'X';
35			ATF_CHECK_EQ(memrchr_fn(buf + i + 1, 'X', j), NULL);
36			buf[i + j + 1] = '-';
37		}
38}
39
40static void
41do_found_test(char buf[], size_t len, size_t first, size_t second)
42{
43	/* invariant: first <= second */
44
45	buf[first] = 'X';
46	buf[second] = 'X';
47	ATF_CHECK_EQ(memrchr_fn(buf, 'X', len), buf + second);
48	buf[first] = '-';
49	buf[second] = '-';
50}
51
52ATF_TC_WITHOUT_HEAD(found);
53ATF_TC_BODY(found, tc)
54{
55	size_t i, j, k, l;
56	char buf[1+15+64+1];
57
58	buf[0] = 'X';
59	memset(buf + 1, '-', sizeof(buf) - 1);
60
61	for (i = 0; i < 16; i++)
62		for (j = 0; j < 64; j++)
63			for (k = 0; k < j; k++)
64				for (l = 0; l <= k; l++) {
65					buf[i + j + 1] = 'X';
66					do_found_test(buf + i + 1, j, l, k);
67					buf[i + j + 1] = '-';
68				}
69}
70
71/* check that the right character is found */
72static void
73do_values_test(unsigned char buf[], size_t len, size_t i, int c)
74{
75	/* sentinels */
76	buf[-1] = c;
77	buf[len] = c;
78	memset(buf, c + 1, len);
79
80	if (i < len) {
81		buf[i] = c;
82		ATF_CHECK_EQ(memrchr_fn(buf, c, len), buf + i);
83	} else
84		ATF_CHECK_EQ(memrchr_fn(buf, c, len), NULL);
85}
86
87ATF_TC_WITHOUT_HEAD(values);
88ATF_TC_BODY(values, tc)
89{
90	size_t i, j, k;
91	int c;
92	unsigned char buf[1+15+64+1];
93
94	for (i = 0; i < 16; i++)
95		for (j = 0; j < 64; j++)
96			for (k = 0; k <= j; k++)
97				for (c = 0; c <= UCHAR_MAX; c++)
98					do_values_test(buf + i + 1, j, k, c);
99}
100
101ATF_TP_ADD_TCS(tp)
102{
103	void *dl_handle;
104
105	dl_handle = dlopen(NULL, RTLD_LAZY);
106	memrchr_fn = dlsym(dl_handle, "test_memrchr");
107	if (memrchr_fn == NULL)
108		memrchr_fn = memrchr;
109
110	ATF_TP_ADD_TC(tp, null);
111	ATF_TP_ADD_TC(tp, not_found);
112	ATF_TP_ADD_TC(tp, found);
113	ATF_TP_ADD_TC(tp, values);
114
115	return (atf_no_error());
116}
117