xref: /freebsd/lib/libc/tests/string/strcspn_test.c (revision 580d00f42fdd94ce43583cc45fe3f1d9fdff47d4)
1 /*-
2  * Copyright (c) 2023 The FreeBSD Foundation
3  *
4  * This software was developed by Robert Clausecker <fuz@FreeBSD.org>
5  * under sponsorship from the FreeBSD Foundation.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  * 1. Redistributions of source code must retain the above copyright
11  *    notice, this list of conditions and the following disclaimer.
12  * 2. Redistributions in binary form must reproduce the above copyright
13  *    notice, this list of conditions and the following disclaimer in the
14  *    documentation and/or other materials provided with the distribution.
15  *
16  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ''AS IS'' AND
17  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19  * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
20  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26  * SUCH DAMAGE
27  */
28 
29 #include <sys/cdefs.h>
30 
31 #include <atf-c.h>
32 #include <assert.h>
33 #include <limits.h>
34 #include <stdbool.h>
35 #include <stddef.h>
36 #include <string.h>
37 
38 enum {
39 	MAXALIGN = 16,	/* test all offsets from this alignment */
40 	MAXBUF = 64,	/* test up to this buffer length */
41 };
42 
43 enum { NOMATCH, MATCH };
44 
45 #ifdef STRSPN
46 #define STRXSPN strspn
47 #else
48 #define STRXSPN strcspn
49 #endif
50 
51 static void
52 testcase(char *buf, size_t buflen, char *set, size_t setlen, int want_match)
53 {
54 	size_t i, outcome, expected;
55 
56 	assert(setlen < UCHAR_MAX - 2);
57 
58 	for (i = 0; i < buflen; i++)
59 #ifdef STRSPN
60 		buf[i] = UCHAR_MAX - i % (setlen > 0 ? setlen : 1);
61 #else /* strcspn */
62 		buf[i] = 1 + i % (UCHAR_MAX - setlen - 1);
63 #endif
64 
65 	buf[i] = '\0';
66 
67 	for (i = 0; i < setlen; i++)
68 		set[i] = UCHAR_MAX - i;
69 
70 	set[i] = '\0';
71 
72 #ifdef STRSPN
73 	if (setlen == 0)
74 		expected = 0;
75 	else if (want_match == MATCH && buflen > 0) {
76 		buf[buflen - 1] = 1;
77 		expected = buflen - 1;
78 	} else
79 		expected = buflen;
80 #else /* strcspn */
81 	if (want_match == MATCH && buflen > 0 && setlen > 0) {
82 		buf[buflen - 1] = UCHAR_MAX;
83 		expected = buflen - 1;
84 	} else
85 		expected = buflen;
86 #endif
87 
88 	outcome = STRXSPN(buf, set);
89 	ATF_CHECK_EQ_MSG(expected, outcome, "%s(%p[%zu], %p[%zu]) = %zu != %zu",
90 	    __XSTRING(STRXSPN), buf, buflen, set, setlen, outcome, expected);
91 }
92 
93 /* test set with all alignments and lengths of buf */
94 static void
95 test_buf_alignments(char *set, size_t setlen, int want_match)
96 {
97 	char buf[MAXALIGN + MAXBUF + 1];
98 	size_t i, j;
99 
100 	for (i = 0; i < MAXALIGN; i++)
101 		for (j = 0; j <= MAXBUF; j++)
102 			testcase(buf + i, j, set, setlen, want_match);
103 }
104 
105 /* test buf with all alignments and lengths of set */
106 static void
107 test_set_alignments(char *buf, size_t buflen, int want_match)
108 {
109 	char set[MAXALIGN + MAXBUF + 1];
110 	size_t i, j;
111 
112 	for (i = 0; i < MAXALIGN; i++)
113 		for (j = 0; j <= MAXBUF; j++)
114 			testcase(buf, buflen, set + i, j, want_match);
115 }
116 
117 ATF_TC_WITHOUT_HEAD(buf_alignments);
118 ATF_TC_BODY(buf_alignments, tc)
119 {
120 	char set[41];
121 
122 	test_buf_alignments(set, 0, MATCH);
123 	test_buf_alignments(set, 1, MATCH);
124 	test_buf_alignments(set, 5, MATCH);
125 	test_buf_alignments(set, 20, MATCH);
126 	test_buf_alignments(set, 40, MATCH);
127 
128 	test_buf_alignments(set, 0, NOMATCH);
129 	test_buf_alignments(set, 1, NOMATCH);
130 	test_buf_alignments(set, 5, NOMATCH);
131 	test_buf_alignments(set, 20, NOMATCH);
132 	test_buf_alignments(set, 40, NOMATCH);
133 }
134 
135 ATF_TC_WITHOUT_HEAD(set_alignments);
136 ATF_TC_BODY(set_alignments, tc)
137 {
138 	char buf[31];
139 
140 	test_set_alignments(buf,  0, MATCH);
141 	test_set_alignments(buf, 10, MATCH);
142 	test_set_alignments(buf, 20, MATCH);
143 	test_set_alignments(buf, 30, MATCH);
144 
145 	test_set_alignments(buf,  0, NOMATCH);
146 	test_set_alignments(buf, 10, NOMATCH);
147 	test_set_alignments(buf, 20, NOMATCH);
148 	test_set_alignments(buf, 30, NOMATCH);
149 }
150 
151 #ifndef STRSPN
152 /* test all positions in which set could match buf */
153 static void
154 test_match_positions(char *buf,  char *set, size_t buflen, size_t setlen)
155 {
156 	size_t i, j, outcome;
157 
158 	memset(buf, '-', buflen);
159 
160 	for (i = 0; i < setlen; i++)
161 		set[i] = 'A' + i;
162 
163 	buf[buflen] = '\0';
164 	set[setlen] = '\0';
165 
166 	/*
167 	 * Check for (mis)match at buffer position i
168 	 * against set position j.
169 	 */
170 	for (i = 0; i < buflen; i++) {
171 		for (j = 0; j < setlen; j++) {
172 			buf[i] = set[j];
173 
174 			outcome = strcspn(buf, set);
175 			ATF_CHECK_EQ_MSG(i, outcome,
176 			    "strcspn(\"%s\", \"%s\") = %zu != %zu",
177 			    buf, set, outcome, i);
178 		}
179 
180 		buf[i] = '-';
181 	}
182 }
183 
184 ATF_TC_WITHOUT_HEAD(match_positions);
185 ATF_TC_BODY(match_positions, tc)
186 {
187 	char buf[129], set[65];
188 
189 	test_match_positions(buf, set, 128, 64);
190 	test_match_positions(buf, set, 64, 64);
191 	test_match_positions(buf, set, 32, 64);
192 	test_match_positions(buf, set, 16, 64);
193 	test_match_positions(buf, set, 8, 64);
194 	test_match_positions(buf, set, 128, 32);
195 	test_match_positions(buf, set, 64, 32);
196 	test_match_positions(buf, set, 32, 32);
197 	test_match_positions(buf, set, 16, 32);
198 	test_match_positions(buf, set, 8, 32);
199 	test_match_positions(buf, set, 128, 16);
200 	test_match_positions(buf, set, 64, 16);
201 	test_match_positions(buf, set, 32, 16);
202 	test_match_positions(buf, set, 16, 16);
203 	test_match_positions(buf, set, 8, 16);
204 	test_match_positions(buf, set, 128, 8);
205 	test_match_positions(buf, set, 64, 8);
206 	test_match_positions(buf, set, 32, 8);
207 	test_match_positions(buf, set, 16, 8);
208 	test_match_positions(buf, set, 8, 8);
209 }
210 #endif /* !defined(STRSPN) */
211 
212 ATF_TP_ADD_TCS(tp)
213 {
214 	ATF_TP_ADD_TC(tp, buf_alignments);
215 	ATF_TP_ADD_TC(tp, set_alignments);
216 #ifndef STRSPN
217 	ATF_TP_ADD_TC(tp, match_positions);
218 #endif
219 
220 	return (atf_no_error());
221 }
222