| | #include "../../unity/unity.h" |
| | #include <string.h> |
| | #include <stdio.h> |
| | #include <stdlib.h> |
| | #include <locale.h> |
| | #include <limits.h> |
| | #include <stdint.h> |
| |
|
| | |
| | |
| | |
| | |
| | |
| | |
| |
|
| | static print_function_type expected_print_fn_integral(enum size_spec size_spec, |
| | enum output_format fmt) |
| | { |
| | |
| | if (size_spec == INT) |
| | return print_int; |
| | else if (SHORT < INT && size_spec == SHORT) |
| | return (fmt == SIGNED_DECIMAL ? print_s_short : print_short); |
| | else if (CHAR < SHORT && size_spec == CHAR) |
| | return (fmt == SIGNED_DECIMAL ? print_s_char : print_char); |
| | else if (INT < LONG && size_spec == LONG) |
| | return print_long; |
| | else if (LONG < INTMAX && size_spec == INTMAX) |
| | return print_intmax; |
| | else if (LONG < LONG_LONG && LONG_LONG < INTMAX && size_spec == LONG_LONG) |
| | return print_long_long; |
| | |
| | return (print_function_type)0; |
| | } |
| |
|
| | static int fp_size_supported(size_t sz) |
| | { |
| | |
| | if (sz >= countof(fp_type_size)) |
| | return 0; |
| | if (fp_type_size[sz] == NO_SIZE) |
| | return 0; |
| | #if !FLOAT16_SUPPORTED && BF16_SUPPORTED |
| | |
| | if (sz == sizeof(bfloat16)) |
| | return 0; |
| | #endif |
| | return 1; |
| | } |
| |
|
| | void setUp(void) { |
| | |
| | } |
| |
|
| | void tearDown(void) { |
| | |
| | } |
| |
|
| | static void init_tspec_pattern(struct tspec *t, unsigned char pat) |
| | { |
| | memset(t, pat, sizeof(*t)); |
| | } |
| |
|
| | static void assert_tspec_unchanged(struct tspec const *orig, struct tspec const *now) |
| | { |
| | TEST_ASSERT_EQUAL_UINT8_ARRAY(orig, now, sizeof(*orig)); |
| | } |
| |
|
| | void test_decode_one_format_invalid_character(void) |
| | { |
| | const char *s = "q"; |
| | const char *next = (const char*)0xDEADBEEF; |
| | struct tspec t, before; |
| | init_tspec_pattern(&t, 0xA5); |
| | before = t; |
| |
|
| | bool ok = decode_one_format(s, s, &next, &t); |
| | TEST_ASSERT_FALSE(ok); |
| | TEST_ASSERT_EQUAL_PTR((const char*)0xDEADBEEF, next); |
| | assert_tspec_unchanged(&before, &t); |
| | } |
| |
|
| | void test_decode_one_format_signed_decimal_default_int(void) |
| | { |
| | const char *s = "d"; |
| | const char *next = NULL; |
| | struct tspec t; |
| | memset(&t, 0, sizeof t); |
| |
|
| | bool ok = decode_one_format(s, s, &next, &t); |
| | TEST_ASSERT_TRUE(ok); |
| | TEST_ASSERT_EQUAL_PTR(s + 1, next); |
| |
|
| | TEST_ASSERT_EQUAL_INT(SIGNED_DECIMAL, t.fmt); |
| |
|
| | int sz = (int)sizeof(unsigned int); |
| | TEST_ASSERT_TRUE(sz < (int)countof(integral_type_size)); |
| | enum size_spec ss = integral_type_size[sz]; |
| | TEST_ASSERT_EQUAL_INT(ss, t.size); |
| |
|
| | |
| | TEST_ASSERT_EQUAL_PTR(expected_print_fn_integral(ss, SIGNED_DECIMAL), t.print_function); |
| |
|
| | int expected_width = INT_BITS_STRLEN_BOUND(CHAR_BIT * sz - 1) + 1; |
| | TEST_ASSERT_EQUAL_INT(expected_width, t.field_width); |
| |
|
| | char expected_fmt[FMT_BYTES_ALLOCATED]; |
| | sprintf(expected_fmt, "%%*%s", |
| | ispec_to_format(ss, "d", "ld", "lld", "jd")); |
| | TEST_ASSERT_EQUAL_STRING(expected_fmt, t.fmt_string); |
| |
|
| | TEST_ASSERT_FALSE(t.hexl_mode_trailer); |
| | } |
| |
|
| | void test_decode_one_format_octal_size_2(void) |
| | { |
| | const char *s = "o2"; |
| | const char *next = NULL; |
| | struct tspec t; |
| | memset(&t, 0, sizeof t); |
| |
|
| | bool ok = decode_one_format(s, s, &next, &t); |
| | TEST_ASSERT_TRUE(ok); |
| | TEST_ASSERT_EQUAL_PTR(s + 2, next); |
| |
|
| | TEST_ASSERT_EQUAL_INT(OCTAL, t.fmt); |
| |
|
| | int sz = 2; |
| | TEST_ASSERT_TRUE(sz < (int)countof(integral_type_size)); |
| | enum size_spec ss = integral_type_size[sz]; |
| | TEST_ASSERT_NOT_EQUAL(NO_SIZE, ss); |
| | TEST_ASSERT_EQUAL_INT(ss, t.size); |
| |
|
| | TEST_ASSERT_EQUAL_PTR(expected_print_fn_integral(ss, OCTAL), t.print_function); |
| |
|
| | int expected_width = (CHAR_BIT * sz + 2) / 3; |
| | TEST_ASSERT_EQUAL_INT(expected_width, t.field_width); |
| |
|
| | char expected_fmt[FMT_BYTES_ALLOCATED]; |
| | sprintf(expected_fmt, "%%*.%d%s", expected_width, |
| | ispec_to_format(ss, "o", "lo", "llo", "jo")); |
| | TEST_ASSERT_EQUAL_STRING(expected_fmt, t.fmt_string); |
| |
|
| | TEST_ASSERT_FALSE(t.hexl_mode_trailer); |
| | } |
| |
|
| | void test_decode_one_format_hex_with_trailer_z(void) |
| | { |
| | const char *s = "x1zREST"; |
| | const char *next = NULL; |
| | struct tspec t; |
| | memset(&t, 0, sizeof t); |
| |
|
| | bool ok = decode_one_format(s, s, &next, &t); |
| | TEST_ASSERT_TRUE(ok); |
| |
|
| | |
| | TEST_ASSERT_EQUAL_PTR(s + 3, next); |
| |
|
| | TEST_ASSERT_EQUAL_INT(HEXADECIMAL, t.fmt); |
| | TEST_ASSERT_TRUE(t.hexl_mode_trailer); |
| | } |
| |
|
| | void test_decode_one_format_named_character_a(void) |
| | { |
| | const char *s = "a"; |
| | const char *next = NULL; |
| | struct tspec t; |
| | memset(&t, 0, sizeof t); |
| |
|
| | bool ok = decode_one_format(s, s, &next, &t); |
| | TEST_ASSERT_TRUE(ok); |
| | TEST_ASSERT_EQUAL_PTR(s + 1, next); |
| |
|
| | TEST_ASSERT_EQUAL_INT(NAMED_CHARACTER, t.fmt); |
| | TEST_ASSERT_EQUAL_INT(CHAR, t.size); |
| | TEST_ASSERT_EQUAL_PTR(print_named_ascii, t.print_function); |
| | TEST_ASSERT_EQUAL_INT(3, t.field_width); |
| | TEST_ASSERT_FALSE(t.hexl_mode_trailer); |
| | } |
| |
|
| | void test_decode_one_format_ascii_c(void) |
| | { |
| | const char *s = "c"; |
| | const char *next = NULL; |
| | struct tspec t; |
| | memset(&t, 0, sizeof t); |
| |
|
| | bool ok = decode_one_format(s, s, &next, &t); |
| | TEST_ASSERT_TRUE(ok); |
| | TEST_ASSERT_EQUAL_PTR(s + 1, next); |
| |
|
| | TEST_ASSERT_EQUAL_INT(CHARACTER, t.fmt); |
| | TEST_ASSERT_EQUAL_INT(CHAR, t.size); |
| | TEST_ASSERT_EQUAL_PTR(print_ascii, t.print_function); |
| | TEST_ASSERT_EQUAL_INT(3, t.field_width); |
| | TEST_ASSERT_FALSE(t.hexl_mode_trailer); |
| | } |
| |
|
| | void test_decode_one_format_float_default_double(void) |
| | { |
| | const char *s = "f"; |
| | const char *next = NULL; |
| | struct tspec t; |
| | memset(&t, 0, sizeof t); |
| |
|
| | bool ok = decode_one_format(s, s, &next, &t); |
| | TEST_ASSERT_TRUE(ok); |
| | TEST_ASSERT_EQUAL_PTR(s + 1, next); |
| |
|
| | TEST_ASSERT_EQUAL_INT(FLOATING_POINT, t.fmt); |
| |
|
| | size_t sz = sizeof(double); |
| | TEST_ASSERT_TRUE(fp_size_supported(sz)); |
| |
|
| | enum size_spec ss = fp_type_size[sz]; |
| | TEST_ASSERT_EQUAL_INT(ss, t.size); |
| | TEST_ASSERT_EQUAL_PTR(print_double, t.print_function); |
| |
|
| | struct lconv const *lc = localeconv(); |
| | size_t dp_len = (lc->decimal_point[0] ? strlen(lc->decimal_point) : 1); |
| | int expected_width = DBL_STRLEN_BOUND_L(dp_len); |
| | TEST_ASSERT_EQUAL_INT(expected_width, t.field_width); |
| | } |
| |
|
| | void test_decode_one_format_float_F_handling(void) |
| | { |
| | const char *s = "fF"; |
| | const char *next = NULL; |
| | struct tspec t, before; |
| | init_tspec_pattern(&t, 0xCC); |
| | before = t; |
| |
|
| | size_t sz = sizeof(float); |
| | int supported = fp_size_supported(sz); |
| |
|
| | bool ok = decode_one_format(s, s, &next, &t); |
| | if (supported) { |
| | TEST_ASSERT_TRUE(ok); |
| | TEST_ASSERT_EQUAL_PTR(s + 2, next); |
| | TEST_ASSERT_EQUAL_INT(FLOATING_POINT, t.fmt); |
| | TEST_ASSERT_EQUAL_INT(fp_type_size[sz], t.size); |
| | TEST_ASSERT_EQUAL_PTR(print_float, t.print_function); |
| | struct lconv const *lc = localeconv(); |
| | size_t dp_len = (lc->decimal_point[0] ? strlen(lc->decimal_point) : 1); |
| | int expected_width = FLT_STRLEN_BOUND_L(dp_len); |
| | TEST_ASSERT_EQUAL_INT(expected_width, t.field_width); |
| | } else { |
| | TEST_ASSERT_FALSE(ok); |
| | TEST_ASSERT_EQUAL_PTR(NULL, next); |
| | assert_tspec_unchanged(&before, &t); |
| | } |
| | } |
| |
|
| | void test_decode_one_format_float_L_handling(void) |
| | { |
| | const char *s = "fL"; |
| | const char *next = NULL; |
| | struct tspec t, before; |
| | init_tspec_pattern(&t, 0xDD); |
| | before = t; |
| |
|
| | size_t sz = sizeof(long double); |
| | int supported = fp_size_supported(sz); |
| |
|
| | bool ok = decode_one_format(s, s, &next, &t); |
| | if (supported) { |
| | TEST_ASSERT_TRUE(ok); |
| | TEST_ASSERT_EQUAL_PTR(s + 2, next); |
| | TEST_ASSERT_EQUAL_INT(FLOATING_POINT, t.fmt); |
| | TEST_ASSERT_EQUAL_INT(fp_type_size[sz], t.size); |
| | TEST_ASSERT_EQUAL_PTR(print_long_double, t.print_function); |
| | struct lconv const *lc = localeconv(); |
| | size_t dp_len = (lc->decimal_point[0] ? strlen(lc->decimal_point) : 1); |
| | int expected_width = LDBL_STRLEN_BOUND_L(dp_len); |
| | TEST_ASSERT_EQUAL_INT(expected_width, t.field_width); |
| | } else { |
| | TEST_ASSERT_FALSE(ok); |
| | TEST_ASSERT_EQUAL_PTR(NULL, next); |
| | assert_tspec_unchanged(&before, &t); |
| | } |
| | } |
| |
|
| | void test_decode_one_format_invalid_integral_size_3(void) |
| | { |
| | const char *s = "d3"; |
| | const char *next = (const char*)0xABCD; |
| | struct tspec t, before; |
| | init_tspec_pattern(&t, 0xEE); |
| | before = t; |
| |
|
| | bool ok = decode_one_format(s, s, &next, &t); |
| | TEST_ASSERT_FALSE(ok); |
| | TEST_ASSERT_EQUAL_PTR((const char*)0xABCD, next); |
| | assert_tspec_unchanged(&before, &t); |
| | } |
| |
|
| | void test_decode_one_format_integer_size_overflow_digits(void) |
| | { |
| | |
| | const char *s = "d999999999999999999999"; |
| | const char *next = (const char*)0xFEED; |
| | struct tspec t, before; |
| | init_tspec_pattern(&t, 0x77); |
| | before = t; |
| |
|
| | bool ok = decode_one_format(s, s, &next, &t); |
| | TEST_ASSERT_FALSE(ok); |
| | TEST_ASSERT_EQUAL_PTR((const char*)0xFEED, next); |
| | assert_tspec_unchanged(&before, &t); |
| | } |
| |
|
| | void test_decode_one_format_integral_letter_sizes(void) |
| | { |
| | |
| | struct { const char *spec; enum output_format fmt; char typech; size_t bytes; } cases[] = { |
| | { "uC", UNSIGNED_DECIMAL, 'C', sizeof(unsigned char) }, |
| | { "xS", HEXADECIMAL, 'S', sizeof(unsigned short) }, |
| | { "dI", SIGNED_DECIMAL, 'I', sizeof(unsigned int) }, |
| | { "oL", OCTAL, 'L', sizeof(unsigned long) }, |
| | }; |
| |
|
| | for (size_t i = 0; i < sizeof(cases)/sizeof(cases[0]); ++i) { |
| | const char *s = cases[i].spec; |
| | const char *next = NULL; |
| | struct tspec t; |
| | memset(&t, 0, sizeof t); |
| |
|
| | bool ok = decode_one_format(s, s, &next, &t); |
| | TEST_ASSERT_TRUE(ok); |
| | TEST_ASSERT_EQUAL_PTR(s + 2, next); |
| | TEST_ASSERT_EQUAL_INT(cases[i].fmt, t.fmt); |
| |
|
| | size_t sz = cases[i].bytes; |
| | TEST_ASSERT_TRUE(sz < countof(integral_type_size)); |
| | enum size_spec ss = integral_type_size[sz]; |
| | TEST_ASSERT_NOT_EQUAL(NO_SIZE, ss); |
| | TEST_ASSERT_EQUAL_INT(ss, t.size); |
| |
|
| | TEST_ASSERT_EQUAL_PTR(expected_print_fn_integral(ss, cases[i].fmt), t.print_function); |
| |
|
| | int expected_width = 0; |
| | char expected_fmt[FMT_BYTES_ALLOCATED]; |
| | if (cases[i].fmt == SIGNED_DECIMAL) { |
| | expected_width = INT_BITS_STRLEN_BOUND(CHAR_BIT * sz - 1) + 1; |
| | sprintf(expected_fmt, "%%*%s", |
| | ispec_to_format(ss, "d", "ld", "lld", "jd")); |
| | } else if (cases[i].fmt == UNSIGNED_DECIMAL) { |
| | expected_width = INT_BITS_STRLEN_BOUND(CHAR_BIT * sz); |
| | sprintf(expected_fmt, "%%*%s", |
| | ispec_to_format(ss, "u", "lu", "llu", "ju")); |
| | } else if (cases[i].fmt == OCTAL) { |
| | expected_width = (CHAR_BIT * sz + 2) / 3; |
| | sprintf(expected_fmt, "%%*.%d%s", expected_width, |
| | ispec_to_format(ss, "o", "lo", "llo", "jo")); |
| | } else if (cases[i].fmt == HEXADECIMAL) { |
| | expected_width = (CHAR_BIT * sz + 3) / 4; |
| | sprintf(expected_fmt, "%%*.%d%s", expected_width, |
| | ispec_to_format(ss, "x", "lx", "llx", "jx")); |
| | } |
| | TEST_ASSERT_EQUAL_INT(expected_width, t.field_width); |
| | TEST_ASSERT_EQUAL_STRING(expected_fmt, t.fmt_string); |
| | TEST_ASSERT_FALSE(t.hexl_mode_trailer); |
| | } |
| | } |
| |
|
| | int main(void) |
| | { |
| | UNITY_BEGIN(); |
| |
|
| | RUN_TEST(test_decode_one_format_invalid_character); |
| | RUN_TEST(test_decode_one_format_signed_decimal_default_int); |
| | RUN_TEST(test_decode_one_format_octal_size_2); |
| | RUN_TEST(test_decode_one_format_hex_with_trailer_z); |
| | RUN_TEST(test_decode_one_format_named_character_a); |
| | RUN_TEST(test_decode_one_format_ascii_c); |
| | RUN_TEST(test_decode_one_format_float_default_double); |
| | RUN_TEST(test_decode_one_format_float_F_handling); |
| | RUN_TEST(test_decode_one_format_float_L_handling); |
| | RUN_TEST(test_decode_one_format_invalid_integral_size_3); |
| | RUN_TEST(test_decode_one_format_integer_size_overflow_digits); |
| | RUN_TEST(test_decode_one_format_integral_letter_sizes); |
| |
|
| | return UNITY_END(); |
| | } |