1 1.14 riastrad /* $NetBSD: t_vis.c,v 1.14 2023/08/12 12:48:53 riastradh Exp $ */ 2 1.1 pgoyette 3 1.1 pgoyette /*- 4 1.1 pgoyette * Copyright (c) 2002 The NetBSD Foundation, Inc. 5 1.1 pgoyette * All rights reserved. 6 1.1 pgoyette * 7 1.1 pgoyette * This code was contributed to The NetBSD Foundation by Christos Zoulas. 8 1.1 pgoyette * 9 1.1 pgoyette * Redistribution and use in source and binary forms, with or without 10 1.1 pgoyette * modification, are permitted provided that the following conditions 11 1.1 pgoyette * are met: 12 1.1 pgoyette * 1. Redistributions of source code must retain the above copyright 13 1.1 pgoyette * notice, this list of conditions and the following disclaimer. 14 1.1 pgoyette * 2. Redistributions in binary form must reproduce the above copyright 15 1.1 pgoyette * notice, this list of conditions and the following disclaimer in the 16 1.1 pgoyette * documentation and/or other materials provided with the distribution. 17 1.1 pgoyette * 18 1.1 pgoyette * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 19 1.1 pgoyette * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 20 1.1 pgoyette * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 21 1.1 pgoyette * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 22 1.1 pgoyette * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 23 1.1 pgoyette * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 24 1.1 pgoyette * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 25 1.1 pgoyette * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 26 1.1 pgoyette * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 27 1.1 pgoyette * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 28 1.1 pgoyette * POSSIBILITY OF SUCH DAMAGE. 29 1.1 pgoyette */ 30 1.1 pgoyette 31 1.1 pgoyette #include <atf-c.h> 32 1.1 pgoyette 33 1.1 pgoyette #include <string.h> 34 1.1 pgoyette #include <stdlib.h> 35 1.8 christos #include <locale.h> 36 1.1 pgoyette #include <err.h> 37 1.1 pgoyette #include <vis.h> 38 1.1 pgoyette 39 1.1 pgoyette static int styles[] = { 40 1.1 pgoyette VIS_OCTAL, 41 1.1 pgoyette VIS_CSTYLE, 42 1.1 pgoyette VIS_SP, 43 1.1 pgoyette VIS_TAB, 44 1.1 pgoyette VIS_NL, 45 1.1 pgoyette VIS_WHITE, 46 1.1 pgoyette VIS_SAFE, 47 1.1 pgoyette #if 0 /* Not reversible */ 48 1.1 pgoyette VIS_NOSLASH, 49 1.1 pgoyette #endif 50 1.2 christos VIS_HTTP1808, 51 1.2 christos VIS_MIMESTYLE, 52 1.5 christos #if 0 /* Not supported by vis(3) */ 53 1.2 christos VIS_HTTP1866, 54 1.5 christos #endif 55 1.1 pgoyette }; 56 1.1 pgoyette 57 1.1 pgoyette #define SIZE 256 58 1.1 pgoyette 59 1.3 jruoho ATF_TC(strvis_basic); 60 1.3 jruoho ATF_TC_HEAD(strvis_basic, tc) 61 1.1 pgoyette { 62 1.1 pgoyette 63 1.1 pgoyette atf_tc_set_md_var(tc, "descr", "Test strvis(3)"); 64 1.1 pgoyette } 65 1.1 pgoyette 66 1.3 jruoho ATF_TC_BODY(strvis_basic, tc) 67 1.1 pgoyette { 68 1.1 pgoyette char *srcbuf, *dstbuf, *visbuf; 69 1.1 pgoyette unsigned int i, j; 70 1.1 pgoyette 71 1.4 christos ATF_REQUIRE((dstbuf = malloc(SIZE)) != NULL); 72 1.4 christos ATF_REQUIRE((srcbuf = malloc(SIZE)) != NULL); 73 1.4 christos ATF_REQUIRE((visbuf = malloc(SIZE * 4 + 1)) != NULL); 74 1.1 pgoyette 75 1.1 pgoyette for (i = 0; i < SIZE; i++) 76 1.1 pgoyette srcbuf[i] = (char)i; 77 1.1 pgoyette 78 1.1 pgoyette for (i = 0; i < __arraycount(styles); i++) { 79 1.5 christos ATF_REQUIRE(strsvisx(visbuf, srcbuf, SIZE, styles[i], "") > 0); 80 1.6 christos memset(dstbuf, 0, SIZE); 81 1.6 christos ATF_REQUIRE(strunvisx(dstbuf, visbuf, 82 1.6 christos styles[i] & (VIS_HTTP1808|VIS_MIMESTYLE)) > 0); 83 1.1 pgoyette for (j = 0; j < SIZE; j++) 84 1.1 pgoyette if (dstbuf[j] != (char)j) 85 1.1 pgoyette atf_tc_fail_nonfatal("Failed for style %x, " 86 1.1 pgoyette "char %d [%d]", styles[i], j, dstbuf[j]); 87 1.1 pgoyette } 88 1.4 christos free(dstbuf); 89 1.4 christos free(srcbuf); 90 1.4 christos free(visbuf); 91 1.4 christos } 92 1.4 christos 93 1.7 christos ATF_TC(strvis_null); 94 1.7 christos ATF_TC_HEAD(strvis_null, tc) 95 1.7 christos { 96 1.7 christos atf_tc_set_md_var(tc, "descr", "Test strvis(3) NULL"); 97 1.7 christos } 98 1.7 christos 99 1.7 christos ATF_TC_BODY(strvis_null, tc) 100 1.7 christos { 101 1.7 christos char dst[] = "fail"; 102 1.7 christos strvis(dst, NULL, VIS_SAFE); 103 1.7 christos ATF_REQUIRE(dst[0] == '\0' && dst[1] == 'a'); 104 1.7 christos } 105 1.7 christos 106 1.7 christos ATF_TC(strvis_empty); 107 1.7 christos ATF_TC_HEAD(strvis_empty, tc) 108 1.7 christos { 109 1.7 christos atf_tc_set_md_var(tc, "descr", "Test strvis(3) empty"); 110 1.7 christos } 111 1.7 christos 112 1.7 christos ATF_TC_BODY(strvis_empty, tc) 113 1.7 christos { 114 1.7 christos char dst[] = "fail"; 115 1.7 christos strvis(dst, "", VIS_SAFE); 116 1.7 christos ATF_REQUIRE(dst[0] == '\0' && dst[1] == 'a'); 117 1.7 christos } 118 1.7 christos 119 1.12 riastrad ATF_TC(strnvis_empty_empty); 120 1.12 riastrad ATF_TC_HEAD(strnvis_empty_empty, tc) 121 1.12 riastrad { 122 1.12 riastrad atf_tc_set_md_var(tc, "descr", 123 1.12 riastrad "Test strnvis(3) with empty source and destination"); 124 1.12 riastrad } 125 1.12 riastrad 126 1.12 riastrad ATF_TC_BODY(strnvis_empty_empty, tc) 127 1.12 riastrad { 128 1.12 riastrad char dst[] = "fail"; 129 1.12 riastrad int n; 130 1.12 riastrad 131 1.12 riastrad n = strnvis(dst, 0, "", VIS_SAFE); 132 1.12 riastrad ATF_CHECK(memcmp(dst, "fail", sizeof(dst)) == 0); 133 1.12 riastrad ATF_CHECK_EQ_MSG(n, -1, "n=%d", n); 134 1.12 riastrad } 135 1.12 riastrad 136 1.4 christos ATF_TC(strunvis_hex); 137 1.4 christos ATF_TC_HEAD(strunvis_hex, tc) 138 1.4 christos { 139 1.4 christos atf_tc_set_md_var(tc, "descr", "Test strunvis(3) \\xXX"); 140 1.4 christos } 141 1.4 christos 142 1.4 christos ATF_TC_BODY(strunvis_hex, tc) 143 1.4 christos { 144 1.4 christos static const struct { 145 1.4 christos const char *e; 146 1.4 christos const char *d; 147 1.4 christos int error; 148 1.4 christos } ed[] = { 149 1.4 christos { "\\xff", "\xff", 1 }, 150 1.4 christos { "\\x1", "\x1", 1 }, 151 1.4 christos { "\\x1\\x02", "\x1\x2", 2 }, 152 1.4 christos { "\\x1x", "\x1x", 2 }, 153 1.4 christos { "\\xx", "", -1 }, 154 1.4 christos }; 155 1.4 christos char uv[10]; 156 1.4 christos 157 1.4 christos for (size_t i = 0; i < __arraycount(ed); i++) { 158 1.4 christos ATF_REQUIRE(strunvis(uv, ed[i].e) == ed[i].error); 159 1.4 christos if (ed[i].error > 0) 160 1.4 christos ATF_REQUIRE(memcmp(ed[i].d, uv, ed[i].error) == 0); 161 1.4 christos } 162 1.1 pgoyette } 163 1.1 pgoyette 164 1.9 christos #ifdef VIS_NOLOCALE 165 1.8 christos ATF_TC(strvis_locale); 166 1.8 christos ATF_TC_HEAD(strvis_locale, tc) 167 1.8 christos { 168 1.8 christos atf_tc_set_md_var(tc, "descr", "Test strvis(3) with locale"); 169 1.8 christos } 170 1.8 christos 171 1.8 christos ATF_TC_BODY(strvis_locale, tc) 172 1.8 christos { 173 1.8 christos char s[256], cd[sizeof(s) * 4 + 1], jd[sizeof(cd)], *ol; 174 1.8 christos int jr, cr; 175 1.8 christos 176 1.8 christos for (size_t i = 0; i < sizeof(s) - 1; i++) 177 1.8 christos s[i] = i + 1; 178 1.8 christos s[sizeof(s) - 1] = '\0'; 179 1.8 christos 180 1.8 christos ol = setlocale(LC_CTYPE, "ja_JP.UTF-8"); 181 1.8 christos ATF_REQUIRE(ol != NULL); 182 1.8 christos jr = strvisx(jd, s, sizeof(s), VIS_WHITE | VIS_NOLOCALE); 183 1.8 christos ATF_REQUIRE(jr != -1); 184 1.8 christos ol = strdup(ol); 185 1.8 christos ATF_REQUIRE(ol != NULL); 186 1.8 christos ATF_REQUIRE(setlocale(LC_CTYPE, "C") != NULL); 187 1.8 christos cr = strvisx(cd, s, sizeof(s), VIS_WHITE); 188 1.8 christos ATF_REQUIRE(jr == cr); 189 1.8 christos ATF_REQUIRE(memcmp(jd, cd, jr) == 0); 190 1.8 christos setlocale(LC_CTYPE, ol); 191 1.8 christos free(ol); 192 1.8 christos } 193 1.9 christos #endif /* VIS_NOLOCALE */ 194 1.8 christos 195 1.11 riastrad #define STRVIS_OVERFLOW_MARKER ((char)0xff) /* Arbitrary */ 196 1.10 riastrad 197 1.10 riastrad #ifdef VIS_NOLOCALE 198 1.10 riastrad ATF_TC(strvis_overflow_mb); 199 1.10 riastrad ATF_TC_HEAD(strvis_overflow_mb, tc) 200 1.10 riastrad { 201 1.10 riastrad atf_tc_set_md_var(tc, "descr", "Test strvis(3) multi-byte overflow"); 202 1.10 riastrad } 203 1.10 riastrad 204 1.10 riastrad ATF_TC_BODY(strvis_overflow_mb, tc) 205 1.10 riastrad { 206 1.10 riastrad const char src[] = "\xf0\x9f\xa5\x91"; 207 1.10 riastrad /* Extra byte to detect overflow */ 208 1.10 riastrad char dst[sizeof(src) + 1]; 209 1.11 riastrad unsigned i; 210 1.10 riastrad int n; 211 1.10 riastrad 212 1.10 riastrad setlocale(LC_CTYPE, "en_US.UTF-8"); 213 1.10 riastrad 214 1.11 riastrad for (i = 0; i < sizeof(dst) - 1; i++) { 215 1.11 riastrad memset(dst, STRVIS_OVERFLOW_MARKER, sizeof(dst)); 216 1.11 riastrad n = strnvis(dst, i, src, VIS_SAFE); 217 1.11 riastrad ATF_CHECK_EQ_MSG(dst[i], STRVIS_OVERFLOW_MARKER, 218 1.11 riastrad "[%u] dst=[%02hhx %02hhx %02hhx %02hhx %02hhx]" 219 1.11 riastrad " STRVIS_OVERFLOW_MARKER=%02hhx", 220 1.11 riastrad i, dst[0], dst[1], dst[2], dst[3], dst[4], 221 1.11 riastrad STRVIS_OVERFLOW_MARKER); 222 1.11 riastrad ATF_CHECK_EQ_MSG(n, -1, "[%u] n=%d", i, n); 223 1.11 riastrad } 224 1.11 riastrad 225 1.10 riastrad memset(dst, STRVIS_OVERFLOW_MARKER, sizeof(dst)); 226 1.11 riastrad n = strnvis(dst, sizeof(dst) - 1, src, VIS_SAFE); 227 1.11 riastrad ATF_CHECK_EQ_MSG(dst[sizeof(dst) - 1], STRVIS_OVERFLOW_MARKER, 228 1.11 riastrad "[%u] dst=[%02hhx %02hhx %02hhx %02hhx %02hhx %02hhx]" 229 1.11 riastrad " STRVIS_OVERFLOW_MARKER=%02hhx", 230 1.11 riastrad i, dst[0], dst[1], dst[2], dst[3], dst[4], dst[5], 231 1.11 riastrad STRVIS_OVERFLOW_MARKER); 232 1.11 riastrad ATF_CHECK_EQ_MSG(n, (int)sizeof(dst) - 2, "n=%d", n); 233 1.10 riastrad } 234 1.10 riastrad #endif 235 1.10 riastrad 236 1.10 riastrad ATF_TC(strvis_overflow_c); 237 1.10 riastrad ATF_TC_HEAD(strvis_overflow_c, tc) 238 1.10 riastrad { 239 1.10 riastrad atf_tc_set_md_var(tc, "descr", "Test strvis(3) C locale overflow"); 240 1.10 riastrad } 241 1.10 riastrad 242 1.10 riastrad ATF_TC_BODY(strvis_overflow_c, tc) 243 1.10 riastrad { 244 1.10 riastrad const char src[] = "AAAA"; 245 1.10 riastrad /* Extra byte to detect overflow */ 246 1.10 riastrad char dst[sizeof(src) + 1]; 247 1.11 riastrad unsigned i; 248 1.10 riastrad int n; 249 1.10 riastrad 250 1.11 riastrad for (i = 0; i < sizeof(dst) - 1; i++) { 251 1.11 riastrad memset(dst, STRVIS_OVERFLOW_MARKER, sizeof(dst)); 252 1.11 riastrad n = strnvis(dst, i, src, VIS_SAFE | VIS_NOLOCALE); 253 1.11 riastrad ATF_CHECK_EQ_MSG(dst[i], STRVIS_OVERFLOW_MARKER, 254 1.11 riastrad "[%u] dst=[%02hhx %02hhx %02hhx %02hhx %02hhx]" 255 1.11 riastrad " STRVIS_OVERFLOW_MARKER=%02hhx", 256 1.11 riastrad i, dst[0], dst[1], dst[2], dst[3], dst[4], 257 1.11 riastrad STRVIS_OVERFLOW_MARKER); 258 1.11 riastrad ATF_CHECK_EQ_MSG(n, -1, "[%u] n=%d", i, n); 259 1.11 riastrad } 260 1.11 riastrad 261 1.10 riastrad memset(dst, STRVIS_OVERFLOW_MARKER, sizeof(dst)); 262 1.11 riastrad n = strnvis(dst, sizeof(dst) - 1, src, VIS_SAFE | VIS_NOLOCALE); 263 1.11 riastrad ATF_CHECK_EQ_MSG(dst[sizeof(dst) - 1], STRVIS_OVERFLOW_MARKER, 264 1.11 riastrad "[%u] dst=[%02hhx %02hhx %02hhx %02hhx %02hhx %02hhx]" 265 1.11 riastrad " STRVIS_OVERFLOW_MARKER=%02hhx", 266 1.11 riastrad i, dst[0], dst[1], dst[2], dst[3], dst[4], dst[5], 267 1.11 riastrad STRVIS_OVERFLOW_MARKER); 268 1.11 riastrad ATF_CHECK_EQ_MSG(n, (int)sizeof(dst) - 2, "n=%d", n); 269 1.10 riastrad } 270 1.10 riastrad 271 1.1 pgoyette ATF_TP_ADD_TCS(tp) 272 1.1 pgoyette { 273 1.1 pgoyette 274 1.3 jruoho ATF_TP_ADD_TC(tp, strvis_basic); 275 1.7 christos ATF_TP_ADD_TC(tp, strvis_null); 276 1.7 christos ATF_TP_ADD_TC(tp, strvis_empty); 277 1.12 riastrad ATF_TP_ADD_TC(tp, strnvis_empty_empty); 278 1.4 christos ATF_TP_ADD_TC(tp, strunvis_hex); 279 1.9 christos #ifdef VIS_NOLOCALE 280 1.8 christos ATF_TP_ADD_TC(tp, strvis_locale); 281 1.10 riastrad ATF_TP_ADD_TC(tp, strvis_overflow_mb); 282 1.9 christos #endif /* VIS_NOLOCALE */ 283 1.10 riastrad ATF_TP_ADD_TC(tp, strvis_overflow_c); 284 1.1 pgoyette 285 1.1 pgoyette return atf_no_error(); 286 1.1 pgoyette } 287