| #include "../../unity/unity.h" |
| #include <stdlib.h> |
| #include <string.h> |
| #include <stdio.h> |
| #include <gmp.h> |
|
|
| |
| void setUp(void) { |
| |
| } |
| void tearDown(void) { |
| |
| } |
|
|
| |
| |
| |
| static char *make_dec_from_limbs(mp_limb_t hi, mp_limb_t lo) |
| { |
| mpz_t z; |
| mpz_init(z); |
| mp_limb_t limbs[2]; |
| limbs[0] = hi; |
| limbs[1] = lo; |
| |
| mpz_import(z, 2, 1, sizeof(mp_limb_t), 0, 0, limbs); |
|
|
| |
| size_t need = mpz_sizeinbase(z, 10) + 2; |
| char *buf = (char *)malloc(need); |
| TEST_ASSERT_NOT_NULL(buf); |
| mpz_get_str(buf, 10, z); |
| mpz_clear(z); |
| return buf; |
| } |
|
|
| |
| static char *make_dec_pow2(size_t bits) |
| { |
| mpz_t z; |
| mpz_init(z); |
| mpz_set_ui(z, 1); |
| mpz_mul_2exp(z, z, bits); |
| size_t need = mpz_sizeinbase(z, 10) + 2; |
| char *buf = (char *)malloc(need); |
| TEST_ASSERT_NOT_NULL(buf); |
| mpz_get_str(buf, 10, z); |
| mpz_clear(z); |
| return buf; |
| } |
|
|
| |
| static char *make_dec_pow2_minus1(size_t bits) |
| { |
| mpz_t z; |
| mpz_init(z); |
| mpz_set_ui(z, 1); |
| mpz_mul_2exp(z, z, bits); |
| mpz_sub_ui(z, z, 1); |
| size_t need = mpz_sizeinbase(z, 10) + 2; |
| char *buf = (char *)malloc(need); |
| TEST_ASSERT_NOT_NULL(buf); |
| mpz_get_str(buf, 10, z); |
| mpz_clear(z); |
| return buf; |
| } |
|
|
| |
| static void assert_parse_ok_to_limbs(const char *dec, mp_limb_t exphi, mp_limb_t exlo) |
| { |
| uuint out; |
| strtol_error e = strtouuint(&out, dec); |
| TEST_ASSERT_EQUAL_INT_MESSAGE(LONGINT_OK, e, "Expected LONGINT_OK"); |
| TEST_ASSERT_MESSAGE(hi(out) == exphi, "High limb mismatch"); |
| TEST_ASSERT_MESSAGE(lo(out) == exlo, "Low limb mismatch"); |
| } |
|
|
| |
| static void assert_parse_error(const char *dec, strtol_error expected) |
| { |
| uuint out; |
| strtol_error e = strtouuint(&out, dec); |
| TEST_ASSERT_EQUAL_INT(expected, e); |
| } |
|
|
| |
| static void test_strtouuint_parses_key_boundaries(void) |
| { |
| |
| char *s_bminus1 = make_dec_pow2_minus1(W_TYPE_SIZE); |
| assert_parse_ok_to_limbs(s_bminus1, 0, MP_LIMB_MAX); |
| free(s_bminus1); |
|
|
| |
| char *s_b = make_dec_pow2(W_TYPE_SIZE); |
| assert_parse_ok_to_limbs(s_b, 1, 0); |
| free(s_b); |
|
|
| |
| char *s_b2minus1 = make_dec_pow2_minus1(2 * (size_t)W_TYPE_SIZE); |
| assert_parse_ok_to_limbs(s_b2minus1, MP_LIMB_MAX, MP_LIMB_MAX); |
| free(s_b2minus1); |
| } |
|
|
| |
| static void test_strtouuint_overflow_at_B2(void) |
| { |
| |
| char *s_b2 = make_dec_pow2(2 * (size_t)W_TYPE_SIZE); |
| assert_parse_error(s_b2, LONGINT_OVERFLOW); |
| free(s_b2); |
| } |
|
|
| |
| static void test_strtouuint_invalid_inputs(void) |
| { |
| assert_parse_error("", LONGINT_INVALID); |
| assert_parse_error("abc", LONGINT_INVALID); |
| assert_parse_error("123abc", LONGINT_INVALID); |
| assert_parse_error("+123", LONGINT_INVALID); |
| assert_parse_error(" 123", LONGINT_INVALID); |
| assert_parse_error("12+3", LONGINT_INVALID); |
| assert_parse_error("123 ", LONGINT_INVALID); |
| } |
|
|
| |
| static void test_strtouuint_leading_zeros(void) |
| { |
| assert_parse_ok_to_limbs("0", 0, 0); |
| assert_parse_ok_to_limbs("0000", 0, 0); |
| assert_parse_ok_to_limbs("000123", 0, 123); |
| } |
|
|
| |
| static void test_strtouuint_various_composed_values(void) |
| { |
| struct { |
| mp_limb_t hi; |
| mp_limb_t lo; |
| } cases[] = { |
| {0, 0}, |
| {0, 1}, |
| {0, 9}, |
| {0, 10}, |
| {0, 123456}, |
| {0, MP_LIMB_MAX}, |
| {1, 0}, |
| {1, 12345}, |
| {MP_LIMB_MAX, 1}, |
| {MP_LIMB_MAX, MP_LIMB_MAX} |
| }; |
|
|
| for (size_t i = 0; i < sizeof(cases)/sizeof(cases[0]); i++) { |
| char *dec = make_dec_from_limbs(cases[i].hi, cases[i].lo); |
| assert_parse_ok_to_limbs(dec, cases[i].hi, cases[i].lo); |
| free(dec); |
| } |
| } |
|
|
| int main(void) |
| { |
| UNITY_BEGIN(); |
| RUN_TEST(test_strtouuint_parses_key_boundaries); |
| RUN_TEST(test_strtouuint_overflow_at_B2); |
| RUN_TEST(test_strtouuint_invalid_inputs); |
| RUN_TEST(test_strtouuint_leading_zeros); |
| RUN_TEST(test_strtouuint_various_composed_values); |
| return UNITY_END(); |
| } |