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