Home | History | Annotate | Line # | Download | only in stdlib
t_strtoi.c revision 1.5
      1 /*	$NetBSD: t_strtoi.c,v 1.5 2024/07/24 09:26:06 kre Exp $	*/
      2 
      3 /*-
      4  * Copyright (c) 2015 The NetBSD Foundation, Inc.
      5  * All rights reserved.
      6  *
      7  * This code is derived from software contributed to The NetBSD Foundation
      8  * by Jukka Ruohonen.
      9  *
     10  * Redistribution and use in source and binary forms, with or without
     11  * modification, are permitted provided that the following conditions
     12  * are met:
     13  * 1. Redistributions of source code must retain the above copyright
     14  *    notice, this list of conditions and the following disclaimer.
     15  * 2. Redistributions in binary form must reproduce the above copyright
     16  *    notice, this list of conditions and the following disclaimer in the
     17  *    documentation and/or other materials provided with the distribution.
     18  *
     19  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
     20  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
     21  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
     22  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
     23  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
     24  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
     25  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
     26  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
     27  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
     28  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
     29  * POSSIBILITY OF SUCH DAMAGE.
     30  */
     31 
     32 /*
     33  * Created by Kamil Rytarowski, based on ID:
     34  * NetBSD: t_strtol.c,v 1.5 2011/06/14 02:45:58 jruoho Exp
     35  */
     36 
     37 #include <sys/cdefs.h>
     38 __RCSID("$NetBSD: t_strtoi.c,v 1.5 2024/07/24 09:26:06 kre Exp $");
     39 
     40 #include <atf-c.h>
     41 #include <errno.h>
     42 #include <inttypes.h>
     43 #include <stdlib.h>
     44 #include <string.h>
     45 #include <limits.h>
     46 
     47 struct test {
     48 	const char	*str;
     49 	intmax_t	 res;
     50 	int		 base;
     51 	const char	*end;
     52 	intmax_t	 lo;
     53 	intmax_t	 hi;
     54 	int		 rstatus;
     55 };
     56 
     57 static void	check(struct test *, intmax_t, char *, int);
     58 
     59 static void
     60 check(struct test *t, intmax_t rv, char *end, int rstatus)
     61 {
     62 
     63 	if (rv != t->res)
     64 		atf_tc_fail_nonfatal("strtoi(\"%s\", &end, %d, %jd, %jd, "
     65 		    "&rstatus) failed (rv = %jd)", t->str, t->base,
     66 		    t->lo, t->hi, rv);
     67 
     68 	if (rstatus != t->rstatus) {
     69 		char *emsg;
     70 
     71 		if (rstatus != 0) {
     72 			emsg = strerror(rstatus);
     73 			if (emsg != NULL) {
     74 				emsg = strdup(emsg);
     75 				if (emsg == NULL) {
     76 					atf_tc_fail("Out of Memory");
     77 					return;
     78 				}
     79 			}
     80 		} else
     81 			emsg = NULL;
     82 
     83 		atf_tc_fail_nonfatal("strtoi(\"%s\", &end, %d, %jd, %jd, &rstatus)"
     84 		    " failed (rstatus: %d %s%s%sexpected %d%s%s%s)",
     85 		    t->str, t->base, t->lo, t->hi, rstatus, rstatus ? "('" : "",
     86 		    emsg != NULL ? emsg : "", rstatus ? "') " : "", t->rstatus,
     87 		    t->rstatus ? " ('" : "", t->rstatus ? strerror(t->rstatus)
     88 		    : "", t->rstatus ? "')" : "");
     89 
     90 		free(emsg);
     91 	}
     92 
     93 	if ((t->end != NULL && strcmp(t->end, end) != 0) ||
     94 	    (t->end == NULL && *end != '\0'))
     95 		atf_tc_fail_nonfatal("invalid end pointer ('%s') from "
     96 		    "strtoi(\"%s\", &end, %d, %jd, %jd, &rstatus), "
     97 		    "expected '%s'", end, t->str, t->base, t->lo, t->hi,
     98 		     t->end != NULL ? t->end : "\\0");
     99 }
    100 
    101 static void
    102 check_errno(int e)
    103 {
    104 	if (e != 0)
    105 		atf_tc_fail("strtoi(3) changed errno to %d ('%s')",
    106 			            e, strerror(e));
    107 }
    108 
    109 ATF_TC(strtoi_base);
    110 ATF_TC_HEAD(strtoi_base, tc)
    111 {
    112 	atf_tc_set_md_var(tc, "descr", "Test strtoi(3) with different bases");
    113 }
    114 
    115 ATF_TC_BODY(strtoi_base, tc)
    116 {
    117 	struct test t[] = {
    118 		{ "123456789",                  123456789,	0,	NULL,
    119 		  INTMAX_MIN,	INTMAX_MAX,	0	},
    120 		{ "111010110111100110100010101",123456789,	2,	NULL,
    121 		  INTMAX_MIN,	INTMAX_MAX,	0	},
    122 		{ "22121022020212200",          123456789,	3,	NULL,
    123 		  INTMAX_MIN,	INTMAX_MAX,	0	},
    124 		{ "13112330310111",	        123456789,	4,	NULL,
    125 		  INTMAX_MIN,	INTMAX_MAX,	0	},
    126 		{ "223101104124",               123456789,	5,	NULL,
    127 		  INTMAX_MIN,	INTMAX_MAX,	0	},
    128 		{ "20130035113",                123456789,	6,	NULL,
    129 		  INTMAX_MIN,	INTMAX_MAX,	0	},
    130 		{ "3026236221",	                123456789,	7,	NULL,
    131 		  INTMAX_MIN,	INTMAX_MAX,	0	},
    132 		{ "726746425",                  123456789,	8,	NULL,
    133 		  INTMAX_MIN,	INTMAX_MAX,	0	},
    134 		{ "277266780",                  123456789,	9,	NULL,
    135 		  INTMAX_MIN,	INTMAX_MAX,	0	},
    136 		{ "123456789",                  123456789,	10,	NULL,
    137 		  INTMAX_MIN,	INTMAX_MAX,	0	},
    138 		{ "63762A05",                   123456789,	11,	NULL,
    139 		  INTMAX_MIN,	INTMAX_MAX,	0	},
    140 		{ "35418A99",                   123456789,	12,	NULL,
    141 		  INTMAX_MIN,	INTMAX_MAX,	0	},
    142 		{ "1C767471",                   123456789,	13,	NULL,
    143 		  INTMAX_MIN,	INTMAX_MAX,	0	},
    144 		{ "12579781",                   123456789,	14,	NULL,
    145 		  INTMAX_MIN,	INTMAX_MAX,	0	},
    146 		{ "AC89BC9",                    123456789,	15,	NULL,
    147 		  INTMAX_MIN,	INTMAX_MAX,	0	},
    148 		{ "75BCD15",                    123456789,	16,	NULL,
    149 		  INTMAX_MIN,	INTMAX_MAX,	0	},
    150 		{ "1234567",                       342391,	8,	NULL,
    151 		  INTMAX_MIN,	INTMAX_MAX,	0	},
    152 		{ "01234567",                      342391,	0,	NULL,
    153 		  INTMAX_MIN,	INTMAX_MAX,	0	},
    154 		{ "0123456789",                 123456789,	10,	NULL,
    155 		  INTMAX_MIN,	INTMAX_MAX,	0	},
    156 		{ "0x75bcd15",                  123456789,	0,	NULL,
    157 		  INTMAX_MIN,	INTMAX_MAX,	0	},
    158 	};
    159 	struct test f[] = {
    160 		{ "1",                                  0,	1,	"1",
    161 		  INTMAX_MIN,	INTMAX_MAX,	EINVAL	},
    162 		{ "2",                                  0,	-1,	"2",
    163 		  INTMAX_MIN,	INTMAX_MAX,	EINVAL	},
    164 		{ "3",                                  0,	37,	"3",
    165 		  INTMAX_MIN,	INTMAX_MAX,	EINVAL	},
    166 		{ "4",                                  0,	-1,	"4",
    167 		  INTMAX_MIN,	INTMAX_MAX,	EINVAL	},
    168 		{ "0x",                                  0,	 0,	"x",
    169 		  INTMAX_MIN,	INTMAX_MAX,	ENOTSUP	},
    170 	};
    171 
    172 	intmax_t rv;
    173 	char *end;
    174 	int e;
    175 	size_t i;
    176 
    177 	for (i = 0; i < __arraycount(t); i++) {
    178 
    179 		errno = 0;
    180 		rv = strtoi(t[i].str, &end, t[i].base, t[i].lo, t[i].hi, &e);
    181 
    182 		check_errno(errno);
    183 
    184 		check(&t[i], rv, end, e);
    185 	}
    186 
    187 	for (i = 0; i < __arraycount(f); i++) {
    188 
    189 		end = NULL;
    190 		errno = 0;
    191 		e = -99;
    192 
    193 		rv = strtoi(f[i].str, &end, f[i].base, f[i].lo, f[i].hi, &e);
    194 
    195 		check_errno(errno);
    196 
    197 		check(&f[i], rv, end, e);
    198 	}
    199 }
    200 
    201 ATF_TC(strtoi_case);
    202 ATF_TC_HEAD(strtoi_case, tc)
    203 {
    204 	atf_tc_set_md_var(tc, "descr", "Case insensitivity with strtoi(3)");
    205 }
    206 
    207 ATF_TC_BODY(strtoi_case, tc)
    208 {
    209 	struct test t[] = {
    210 		{ "abcd",	0xabcd,	16,	NULL,
    211 		  INTMAX_MIN,	INTMAX_MAX,	0	},
    212 		{ "     dcba",	0xdcba,	16,	NULL,
    213 		  INTMAX_MIN,	INTMAX_MAX,	0	},
    214 		{ "abcd dcba",	0xabcd,	16,	" dcba",
    215 		  INTMAX_MIN,	INTMAX_MAX,	ENOTSUP	},
    216 		{ "abc0x123",	0xabc0, 16,	"x123",
    217 		  INTMAX_MIN,	INTMAX_MAX,	ENOTSUP	},
    218 		{ "abcd\0x123",	0xabcd, 16,	"\0x123",
    219 		  INTMAX_MIN,	INTMAX_MAX,	0	},
    220 		{ "ABCD",	0xabcd, 16,	NULL,
    221 		  INTMAX_MIN,	INTMAX_MAX,	0	},
    222 		{ "aBcD",	0xabcd, 16,	NULL,
    223 		  INTMAX_MIN,	INTMAX_MAX,	0	},
    224 		{ "0xABCD",	0xabcd, 16,	NULL,
    225 		  INTMAX_MIN,	INTMAX_MAX,	0	},
    226 		{ "0xABCDX",	0xabcd, 16,	"X",
    227 		  INTMAX_MIN,	INTMAX_MAX,	ENOTSUP},
    228 	};
    229 
    230 	intmax_t rv;
    231 	char *end;
    232 	int e;
    233 	size_t i;
    234 
    235 	for (i = 0; i < __arraycount(t); i++) {
    236 
    237 		errno = 0;
    238 		rv = strtoi(t[i].str, &end, t[i].base, t[i].lo, t[i].hi, &e);
    239 
    240 		check_errno(errno);
    241 
    242 		check(&t[i], rv, end, e);
    243 	}
    244 }
    245 
    246 ATF_TC(strtoi_range);
    247 ATF_TC_HEAD(strtoi_range, tc)
    248 {
    249 	atf_tc_set_md_var(tc, "descr", "Test ERANGE from strtoi(3)");
    250 }
    251 
    252 ATF_TC_BODY(strtoi_range, tc)
    253 {
    254 	struct test t[] = {
    255 #if INTMAX_MAX == 0x7fffffffffffffff
    256 		{ "1000000000000000000000", INTMAX_MAX, 8, NULL,
    257 		  INTMAX_MIN,	INTMAX_MAX,	ERANGE },
    258 		{ "9223372036854775808",    INTMAX_MAX, 10, NULL,
    259 		  INTMAX_MIN,	INTMAX_MAX,	ERANGE },
    260 		{ "8000000000000000",       INTMAX_MAX, 16, NULL,
    261 		  INTMAX_MIN,	INTMAX_MAX,	ERANGE },
    262 #else
    263 #error extend this test to your platform!
    264 #endif
    265 		{ "10",		 1,	10,	NULL,
    266 		  -1,	 1,	ERANGE			},
    267 		{ "10",		11,	10,	NULL,
    268 		  11,	20,	ERANGE			},
    269 		{ "7",		 7,	0,	NULL,
    270 		   7,	 7,	0			},
    271 		{ "6",		 7,	0,	NULL,
    272 		   7,	 7,	ERANGE			},
    273 		{ "8",		 7,	0,	NULL,
    274 		   7,	 7,	ERANGE			},
    275 		{ "7x",		 7,	0,	"x",
    276 		   7,	 7,	ENOTSUP			},
    277 		{ "8x",		 7,	0,	"x",
    278 		   7,	 7,	ERANGE			},
    279 		{ "Z",		11,	10,	"Z",
    280 		  11,	20,	ECANCELED		},
    281 	};
    282 
    283 	intmax_t rv;
    284 	char *end;
    285 	int e;
    286 	size_t i;
    287 
    288 	for (i = 0; i < __arraycount(t); i++) {
    289 
    290 		errno = 0;
    291 		rv = strtoi(t[i].str, &end, t[i].base, t[i].lo, t[i].hi, &e);
    292 
    293 		if (errno != 0)
    294 			atf_tc_fail("Range test %zd set errno=%d", i, errno);
    295 		check_errno(errno);
    296 
    297 		check(&t[i], rv, end, e);
    298 	}
    299 }
    300 
    301 ATF_TC(strtoi_range_trail);
    302 ATF_TC_HEAD(strtoi_range_trail, tc)
    303 {
    304 	atf_tc_set_md_var(tc, "descr", "Test ERANGE from strtoi(3) "
    305 		"with trailing characters");
    306 }
    307 
    308 ATF_TC_BODY(strtoi_range_trail, tc)
    309 {
    310 	struct test t[] = {
    311 		{ "11x",    9, 10, "x",  0, 9, ERANGE },
    312 		{ " -3y",  -2, 10, "y", -2, 1, ERANGE },
    313 		{ "11111z", 9, 10, "z",  0, 9, ERANGE },
    314 		{ "+0xAq",  9, 16, "q",  0, 9, ERANGE },
    315 		{ "-0xBAr", 0, 16, "r",  0, 9, ERANGE },
    316 	};
    317 
    318 	intmax_t rv;
    319 	char *end;
    320 	int e;
    321 	size_t i;
    322 
    323 	for (i = 0; i < __arraycount(t); i++) {
    324 
    325 		errno = 0;
    326 		rv = strtoi(t[i].str, &end, t[i].base, t[i].lo, t[i].hi, &e);
    327 
    328 		check_errno(errno);
    329 
    330 		check(&t[i], rv, end, e);
    331 	}
    332 }
    333 
    334 ATF_TC(strtoi_signed);
    335 ATF_TC_HEAD(strtoi_signed, tc)
    336 {
    337 	atf_tc_set_md_var(tc, "descr", "A basic test of strtoi(3)");
    338 }
    339 
    340 ATF_TC_BODY(strtoi_signed, tc)
    341 {
    342 	struct test t[] = {
    343 		{ "1",		 1, 0, NULL,
    344 		  INTMAX_MIN,	INTMAX_MAX,	0 },
    345 		{ " 2",		 2, 0, NULL,
    346 		  INTMAX_MIN,	INTMAX_MAX,	0 },
    347 		{ "  3",	 3, 0, NULL,
    348 		  INTMAX_MIN,	INTMAX_MAX,	0 },
    349 		{ " -3",	-3, 0, NULL,
    350 		  INTMAX_MIN,	INTMAX_MAX,	0 },
    351 		{ "--1",	 0, 0, "--1",
    352 		  INTMAX_MIN,	INTMAX_MAX,	ECANCELED },
    353 		{ "+-2",	 0, 0, "+-2",
    354 		  INTMAX_MIN,	INTMAX_MAX,	ECANCELED },
    355 		{ "++3",	 0, 0, "++3",
    356 		  INTMAX_MIN,	INTMAX_MAX,	ECANCELED },
    357 		{ "+9",		 9, 0, NULL,
    358 		  INTMAX_MIN,	INTMAX_MAX,	0 },
    359 		{ "+123",      123, 0, NULL,
    360 		  INTMAX_MIN,	INTMAX_MAX,	0 },
    361 		{ "-1 3",       -1, 0, " 3",
    362 		  INTMAX_MIN,	INTMAX_MAX,	ENOTSUP },
    363 		{ "-1.3",       -1, 0, ".3",
    364 		  INTMAX_MIN,	INTMAX_MAX,	ENOTSUP },
    365 		{ "-  3",        0, 0, "-  3",
    366 		  INTMAX_MIN,	INTMAX_MAX,	ECANCELED },
    367 		{ "+33.",       33, 0, ".",
    368 		  INTMAX_MIN,	INTMAX_MAX,	ENOTSUP },
    369 		{ "30x0",       30, 0, "x0",
    370 		  INTMAX_MIN,	INTMAX_MAX,	ENOTSUP },
    371 	};
    372 
    373 	intmax_t rv;
    374 	char *end;
    375 	int e;
    376 	size_t i;
    377 
    378 	for (i = 0; i < __arraycount(t); i++) {
    379 
    380 		errno = 0;
    381 		rv = strtoi(t[i].str, &end, t[i].base, t[i].lo, t[i].hi, &e);
    382 
    383 		check_errno(errno);
    384 
    385 		check(&t[i], rv, end, e);
    386 	}
    387 }
    388 
    389 ATF_TP_ADD_TCS(tp)
    390 {
    391 
    392 	ATF_TP_ADD_TC(tp, strtoi_base);
    393 	ATF_TP_ADD_TC(tp, strtoi_case);
    394 	ATF_TP_ADD_TC(tp, strtoi_range);
    395 	ATF_TP_ADD_TC(tp, strtoi_range_trail);
    396 	ATF_TP_ADD_TC(tp, strtoi_signed);
    397 
    398 	return atf_no_error();
    399 }
    400