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
30 #include <atf-c.h>
31 #include <assert.h>
32 #include <limits.h>
33 #include <stdbool.h>
34 #include <stddef.h>
35 #include <string.h>
36
37 enum {
38 MAXALIGN = 16, /* test all offsets from this alignment */
39 MAXBUF = 64, /* test up to this buffer length */
40 };
41
42 enum { NOMATCH, MATCH };
43
44 #ifdef STRSPN
45 #define STRXSPN strspn
46 #else
47 #define STRXSPN strcspn
48 #endif
49
50 static void
testcase(char * buf,size_t buflen,char * set,size_t setlen,int want_match)51 testcase(char *buf, size_t buflen, char *set, size_t setlen, int want_match)
52 {
53 size_t i, outcome, expected;
54
55 assert(setlen < UCHAR_MAX - 2);
56
57 for (i = 0; i < buflen; i++)
58 #ifdef STRSPN
59 buf[i] = UCHAR_MAX - i % (setlen > 0 ? setlen : 1);
60 #else /* strcspn */
61 buf[i] = 1 + i % (UCHAR_MAX - setlen - 1);
62 #endif
63
64 buf[i] = '\0';
65
66 for (i = 0; i < setlen; i++)
67 set[i] = UCHAR_MAX - i;
68
69 set[i] = '\0';
70
71 #ifdef STRSPN
72 if (setlen == 0)
73 expected = 0;
74 else if (want_match == MATCH && buflen > 0) {
75 buf[buflen - 1] = 1;
76 expected = buflen - 1;
77 } else
78 expected = buflen;
79 #else /* strcspn */
80 if (want_match == MATCH && buflen > 0 && setlen > 0) {
81 buf[buflen - 1] = UCHAR_MAX;
82 expected = buflen - 1;
83 } else
84 expected = buflen;
85 #endif
86
87 outcome = STRXSPN(buf, set);
88 ATF_CHECK_EQ_MSG(expected, outcome, "%s(%p[%zu], %p[%zu]) = %zu != %zu",
89 __XSTRING(STRXSPN), buf, buflen, set, setlen, outcome, expected);
90 }
91
92 /* test set with all alignments and lengths of buf */
93 static void
test_buf_alignments(char * set,size_t setlen,int want_match)94 test_buf_alignments(char *set, size_t setlen, int want_match)
95 {
96 char buf[MAXALIGN + MAXBUF + 1];
97 size_t i, j;
98
99 for (i = 0; i < MAXALIGN; i++)
100 for (j = 0; j <= MAXBUF; j++)
101 testcase(buf + i, j, set, setlen, want_match);
102 }
103
104 /* test buf with all alignments and lengths of set */
105 static void
test_set_alignments(char * buf,size_t buflen,int want_match)106 test_set_alignments(char *buf, size_t buflen, int want_match)
107 {
108 char set[MAXALIGN + MAXBUF + 1];
109 size_t i, j;
110
111 for (i = 0; i < MAXALIGN; i++)
112 for (j = 0; j <= MAXBUF; j++)
113 testcase(buf, buflen, set + i, j, want_match);
114 }
115
116 ATF_TC_WITHOUT_HEAD(buf_alignments);
ATF_TC_BODY(buf_alignments,tc)117 ATF_TC_BODY(buf_alignments, tc)
118 {
119 char set[41];
120
121 test_buf_alignments(set, 0, MATCH);
122 test_buf_alignments(set, 1, MATCH);
123 test_buf_alignments(set, 5, MATCH);
124 test_buf_alignments(set, 20, MATCH);
125 test_buf_alignments(set, 40, MATCH);
126
127 test_buf_alignments(set, 0, NOMATCH);
128 test_buf_alignments(set, 1, NOMATCH);
129 test_buf_alignments(set, 5, NOMATCH);
130 test_buf_alignments(set, 20, NOMATCH);
131 test_buf_alignments(set, 40, NOMATCH);
132 }
133
134 ATF_TC_WITHOUT_HEAD(set_alignments);
ATF_TC_BODY(set_alignments,tc)135 ATF_TC_BODY(set_alignments, tc)
136 {
137 char buf[31];
138
139 test_set_alignments(buf, 0, MATCH);
140 test_set_alignments(buf, 10, MATCH);
141 test_set_alignments(buf, 20, MATCH);
142 test_set_alignments(buf, 30, MATCH);
143
144 test_set_alignments(buf, 0, NOMATCH);
145 test_set_alignments(buf, 10, NOMATCH);
146 test_set_alignments(buf, 20, NOMATCH);
147 test_set_alignments(buf, 30, NOMATCH);
148 }
149
150 #ifndef STRSPN
151 /* test all positions in which set could match buf */
152 static void
test_match_positions(char * buf,char * set,size_t buflen,size_t setlen)153 test_match_positions(char *buf, char *set, size_t buflen, size_t setlen)
154 {
155 size_t i, j, outcome;
156
157 memset(buf, '-', buflen);
158
159 for (i = 0; i < setlen; i++)
160 set[i] = 'A' + i;
161
162 buf[buflen] = '\0';
163 set[setlen] = '\0';
164
165 /*
166 * Check for (mis)match at buffer position i
167 * against set position j.
168 */
169 for (i = 0; i < buflen; i++) {
170 for (j = 0; j < setlen; j++) {
171 buf[i] = set[j];
172
173 outcome = strcspn(buf, set);
174 ATF_CHECK_EQ_MSG(i, outcome,
175 "strcspn(\"%s\", \"%s\") = %zu != %zu",
176 buf, set, outcome, i);
177 }
178
179 buf[i] = '-';
180 }
181 }
182
183 ATF_TC_WITHOUT_HEAD(match_positions);
ATF_TC_BODY(match_positions,tc)184 ATF_TC_BODY(match_positions, tc)
185 {
186 char buf[129], set[65];
187
188 test_match_positions(buf, set, 128, 64);
189 test_match_positions(buf, set, 64, 64);
190 test_match_positions(buf, set, 32, 64);
191 test_match_positions(buf, set, 16, 64);
192 test_match_positions(buf, set, 8, 64);
193 test_match_positions(buf, set, 128, 32);
194 test_match_positions(buf, set, 64, 32);
195 test_match_positions(buf, set, 32, 32);
196 test_match_positions(buf, set, 16, 32);
197 test_match_positions(buf, set, 8, 32);
198 test_match_positions(buf, set, 128, 16);
199 test_match_positions(buf, set, 64, 16);
200 test_match_positions(buf, set, 32, 16);
201 test_match_positions(buf, set, 16, 16);
202 test_match_positions(buf, set, 8, 16);
203 test_match_positions(buf, set, 128, 8);
204 test_match_positions(buf, set, 64, 8);
205 test_match_positions(buf, set, 32, 8);
206 test_match_positions(buf, set, 16, 8);
207 test_match_positions(buf, set, 8, 8);
208 }
209
210 /* if there are two matches, check that the earlier match is taken */
211 static void
test_match_order(char * buf,char * set,size_t buflen,size_t setlen)212 test_match_order(char *buf, char *set, size_t buflen, size_t setlen)
213 {
214 size_t i, j, k, l, outcome;
215
216 memset(buf, '-', buflen);
217
218 for (i = 0; i < setlen; i++)
219 set[i] = 'A' + i;
220
221 buf[buflen] = '\0';
222 set[setlen] = '\0';
223
224 for (i = 0; i < setlen; i++)
225 for (j = 0; j < setlen; j++)
226 for (k = 0; k + 1 < buflen; k++)
227 for (l = k + 1; l < buflen; l++) {
228 buf[k] = set[i];
229 buf[l] = set[j];
230 outcome = strcspn(buf, set);
231 ATF_CHECK_EQ_MSG(k, outcome,
232 "strcspn(\"%s\", \"%s\") = %zu != %zu",
233 buf, set, outcome, k);
234 buf[k] = '-';
235 buf[l] = '-';
236 }
237 }
238
239 ATF_TC_WITHOUT_HEAD(match_order);
ATF_TC_BODY(match_order,tc)240 ATF_TC_BODY(match_order, tc)
241 {
242 char buf[33], set[65];
243
244 test_match_order(buf, set, 32, 64);
245 test_match_order(buf, set, 16, 64);
246 test_match_order(buf, set, 8, 64);
247 test_match_order(buf, set, 32, 32);
248 test_match_order(buf, set, 16, 32);
249 test_match_order(buf, set, 8, 32);
250 test_match_order(buf, set, 32, 16);
251 test_match_order(buf, set, 16, 16);
252 test_match_order(buf, set, 8, 16);
253 test_match_order(buf, set, 32, 8);
254 test_match_order(buf, set, 16, 8);
255 test_match_order(buf, set, 8, 8);
256 }
257 #endif /* !defined(STRSPN) */
258
ATF_TP_ADD_TCS(tp)259 ATF_TP_ADD_TCS(tp)
260 {
261 ATF_TP_ADD_TC(tp, buf_alignments);
262 ATF_TP_ADD_TC(tp, set_alignments);
263 #ifndef STRSPN
264 ATF_TP_ADD_TC(tp, match_positions);
265 ATF_TP_ADD_TC(tp, match_order);
266 #endif
267
268 return (atf_no_error());
269 }
270