coreutils / tests /factor /tests_for_strtouuint.c
AryaWu's picture
Upload folder using huggingface_hub
78d2150 verified
#include "../../unity/unity.h"
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <gmp.h>
/* Unity setUp/tearDown */
void setUp(void) {
/* Setup code here, or leave empty */
}
void tearDown(void) {
/* Cleanup code here, or leave empty */
}
/* Helper: allocate decimal string for a number represented by two limbs (hi, lo).
Uses mpz_import to construct the number hi*B + lo, then returns its base-10 string.
Caller must free the returned string. */
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; /* most significant limb */
limbs[1] = lo; /* least significant limb */
/* order=1 (most significant first), size=sizeof(mp_limb_t), endian=0 (native), nails=0 */
mpz_import(z, 2, 1, sizeof(mp_limb_t), 0, 0, limbs);
/* Allocate buffer of appropriate size and get decimal string */
size_t need = mpz_sizeinbase(z, 10) + 2; /* +2 for sign and NUL safety */
char *buf = (char *)malloc(need);
TEST_ASSERT_NOT_NULL(buf);
mpz_get_str(buf, 10, z);
mpz_clear(z);
return buf;
}
/* Helper: allocate decimal string for 2^bits. Caller must free. */
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;
}
/* Helper: allocate decimal string for 2^bits - 1. Caller must free. */
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;
}
/* Helper: assert that strtouuint parses `dec` to (exphi,exlo) with LONGINT_OK */
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");
}
/* Helper: assert that strtouuint(dec) returns the specified error code. */
static void assert_parse_error(const char *dec, strtol_error expected)
{
uuint out; /* unused on error */
strtol_error e = strtouuint(&out, dec);
TEST_ASSERT_EQUAL_INT(expected, e);
}
/* Test: basic limb decomposition across key boundaries using dynamically built decimal strings. */
static void test_strtouuint_parses_key_boundaries(void)
{
/* B-1 => (hi=0, lo=MP_LIMB_MAX) */
char *s_bminus1 = make_dec_pow2_minus1(W_TYPE_SIZE);
assert_parse_ok_to_limbs(s_bminus1, 0, MP_LIMB_MAX);
free(s_bminus1);
/* B => (hi=1, lo=0) */
char *s_b = make_dec_pow2(W_TYPE_SIZE);
assert_parse_ok_to_limbs(s_b, 1, 0);
free(s_b);
/* B^2 - 1 => (hi=MP_LIMB_MAX, lo=MP_LIMB_MAX) */
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);
}
/* Test: overflow exactly at B^2 and beyond. */
static void test_strtouuint_overflow_at_B2(void)
{
/* B^2 should overflow (does not fit two limbs). */
char *s_b2 = make_dec_pow2(2 * (size_t)W_TYPE_SIZE);
assert_parse_error(s_b2, LONGINT_OVERFLOW);
free(s_b2);
}
/* Test: invalid inputs (non-digit, empty, trailing/leading junk). */
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);
}
/* Test: leading zeros are accepted and produce correct values. */
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);
}
/* Test: various limb-composed values roundtrip via decimal strings. */
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}, /* B - 1 */
{1, 0}, /* B */
{1, 12345}, /* B + 12345 */
{MP_LIMB_MAX, 1}, /* B^2 - B + 1 */
{MP_LIMB_MAX, MP_LIMB_MAX} /* B^2 - 1 */
};
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();
}