/** * @file convert.c * @brief Tests the strict string-to-number converters. * * These exist because libakstdlib's aksl_ato* family cannot report a conversion * failure. Every assertion here is one that family would get wrong. */ #include #include #include #include "testutil.h" int main(void) { int64_t i = 0; double d = 0.0; TEST_REQUIRE_OK(akbasic_error_register()); /* Valid decimal, hex and negative. */ TEST_REQUIRE_OK(akbasic_str_to_int64("1234", 10, &i)); TEST_REQUIRE_INT(i, 1234); TEST_REQUIRE_OK(akbasic_str_to_int64("0xff", 16, &i)); TEST_REQUIRE_INT(i, 255); TEST_REQUIRE_OK(akbasic_str_to_int64("-256", 10, &i)); TEST_REQUIRE_INT(i, -256); /* * The whole point: aksl_atoi returns success with 0 for each of these. */ TEST_REQUIRE_STATUS(akbasic_str_to_int64("", 10, &i), AKBASIC_ERR_VALUE); TEST_REQUIRE_STATUS(akbasic_str_to_int64("not a number", 10, &i), AKBASIC_ERR_VALUE); TEST_REQUIRE_STATUS(akbasic_str_to_int64("12abc", 10, &i), AKBASIC_ERR_VALUE); TEST_REQUIRE_STATUS(akbasic_str_to_int64("12 ", 10, &i), AKBASIC_ERR_VALUE); TEST_REQUIRE_STATUS(akbasic_str_to_int64("99999999999999999999999", 10, &i), ERANGE); TEST_REQUIRE_STATUS(akbasic_str_to_int64(NULL, 10, &i), AKERR_NULLPOINTER); TEST_REQUIRE_STATUS(akbasic_str_to_int64("1", 10, NULL), AKERR_NULLPOINTER); /* Floats. */ TEST_REQUIRE_OK(akbasic_str_to_double("123.456", &d)); TEST_REQUIRE_FEQ(d, 123.456); TEST_REQUIRE_OK(akbasic_str_to_double("-2.5", &d)); TEST_REQUIRE_FEQ(d, -2.5); TEST_REQUIRE_OK(akbasic_str_to_double("32", &d)); TEST_REQUIRE_FEQ(d, 32.0); TEST_REQUIRE_STATUS(akbasic_str_to_double("", &d), AKBASIC_ERR_VALUE); TEST_REQUIRE_STATUS(akbasic_str_to_double("garbage", &d), AKBASIC_ERR_VALUE); TEST_REQUIRE_STATUS(akbasic_str_to_double("1.5x", &d), AKBASIC_ERR_VALUE); /* * errno hygiene. strtoll and strtod do not clear errno on success, so a * stale ERANGE left by some earlier call would make a perfectly valid * conversion raise. That is what the `errno = 0` before each call is for. * * Found by mutation testing: deleting that line, or setting errno to * something non-zero, survived the suite until these four assertions * existed. */ errno = ERANGE; TEST_REQUIRE_OK(akbasic_str_to_int64("42", 10, &i)); TEST_REQUIRE_INT(i, 42); errno = ERANGE; TEST_REQUIRE_OK(akbasic_str_to_double("2.5", &d)); TEST_REQUIRE_FEQ(d, 2.5); return akbasic_test_failures; }