diff options
Diffstat (limited to 'test/printf.c')
-rw-r--r-- | test/printf.c | 706 |
1 files changed, 545 insertions, 161 deletions
diff --git a/test/printf.c b/test/printf.c index f7e9b9dd2d..728aa9b4a8 100644 --- a/test/printf.c +++ b/test/printf.c @@ -1,4 +1,4 @@ -/* Copyright 2019 The Chromium OS Authors. All rights reserved. +/* Copyright 2019 The ChromiumOS Authors * Use of this source code is governed by a BSD-style license that can be * found in the LICENSE file. */ @@ -12,14 +12,31 @@ #include "test_util.h" #include "util.h" +#ifdef USE_BUILTIN_STDLIB +/* + * When USE_BUILTIN_STDLIB is defined, we want to test the EC printf + * implementation. We need to include the builtin header file directly so + * that we can call the EC version (crec_vsnprintf) when linking with the + * standard library on the host. + */ +#include "builtin/stdio.h" +#define VSNPRINTF crec_vsnprintf +#define SNPRINTF crec_snprintf +static const bool use_builtin_stdlib = true; +#else +#include <stdio.h> +#define VSNPRINTF vsnprintf +#define SNPRINTF snprintf +static const bool use_builtin_stdlib = false; +#endif + #define INIT_VALUE 0x5E #define NO_BYTES_TOUCHED NULL static const char err_str[] = "ERROR"; static char output[1024]; -int run(int expect_ret, const char *expect, - bool output_null, size_t size_limit, +int run(int expect_ret, const char *expect, bool output_null, size_t size_limit, const char *format, va_list args) { size_t expect_size = expect ? strlen(expect) + 1 : 0; @@ -34,10 +51,8 @@ int run(int expect_ret, const char *expect, TEST_ASSERT(expect_size <= size_limit); memset(output, INIT_VALUE, sizeof(output)); - rv = vsnprintf(output_null ? NULL : output, size_limit, - format, args); - ccprintf("received='%.*s' | ret =%d\n", - 30, output, rv); + rv = VSNPRINTF(output_null ? NULL : output, size_limit, format, args); + ccprintf("received='%.*s' | ret =%d\n", 30, output, rv); TEST_ASSERT_ARRAY_EQ(output, expect, expect_size); TEST_ASSERT_MEMSET(&output[expect_size], INIT_VALUE, @@ -59,252 +74,621 @@ int expect_success(const char *expect, const char *format, ...) int rv; va_start(args, format); - rv = run(EC_SUCCESS, expect, - false, sizeof(output), - format, args); + rv = run(EC_SUCCESS, expect, false, sizeof(output), format, args); va_end(args); return rv; } -int expect(int expect_ret, const char *expect, - bool output_null, size_t size_limit, - const char *format, ...) +int expect(int expect_ret, const char *expect, bool output_null, + size_t size_limit, const char *format, ...) { va_list args; int rv; va_start(args, format); - rv = run(expect_ret, expect, - output_null, size_limit, - format, args); + rv = run(expect_ret, expect, output_null, size_limit, format, args); va_end(args); return rv; } -#define T(n) \ - do { \ - int rv = (n); \ - if (rv != EC_SUCCESS) \ - return rv; \ +#define T(n) \ + do { \ + int rv = (n); \ + if (rv != EC_SUCCESS) \ + return rv; \ } while (0) test_static int test_vsnprintf_args(void) { - T(expect_success("", "")); - T(expect_success("a", "a")); - - T(expect(/* expect an invalid args error */ - EC_ERROR_INVAL, NO_BYTES_TOUCHED, - /* given 0 as output size limit */ - false, 0, "")); + T(expect_success("", "")); + T(expect_success("a", "a")); + + if (use_builtin_stdlib) { + /* + * TODO(b/239233116): This differs from the C standard library + * behavior and should probably be changed. + */ + T(expect(/* expect an invalid args error */ + EC_ERROR_INVAL, NO_BYTES_TOUCHED, + /* given 0 as output size limit */ + false, 0, "")); + T(expect(/* expect an overflow error */ + EC_ERROR_OVERFLOW, "", + /* given 1 as output size limit with a non-blank format + */ + false, 1, "a")); + T(expect(/* expect an invalid args error */ + EC_ERROR_INVAL, NO_BYTES_TOUCHED, + /* given NULL as the output buffer */ + true, sizeof(output), "")); + T(expect(/* expect an invalid args error */ + EC_ERROR_INVAL, NO_BYTES_TOUCHED, + /* given a NULL format string */ + false, sizeof(output), NULL)); + } T(expect(/* expect SUCCESS */ EC_SUCCESS, "", /* given 1 as output size limit and a blank format */ false, 1, "")); - T(expect(/* expect an overflow error */ - EC_ERROR_OVERFLOW, "", - /* given 1 as output size limit with a non-blank format */ - false, 1, "a")); - - T(expect(/* expect an invalid args error */ - EC_ERROR_INVAL, NO_BYTES_TOUCHED, - /* given NULL as the output buffer */ - true, sizeof(output), "")); - T(expect(/* expect an invalid args error */ - EC_ERROR_INVAL, NO_BYTES_TOUCHED, - /* given a NULL format string */ - false, sizeof(output), NULL)); return EC_SUCCESS; } test_static int test_vsnprintf_int(void) { - T(expect_success("123", "%d", 123)); - T(expect_success("-123", "%d", -123)); - T(expect_success("+123", "%+d", 123)); - T(expect_success("-123", "%+d", -123)); - T(expect_success("123", "%-d", 123)); - T(expect_success("-123", "%-d", -123)); - - T(expect_success(" 123", "%5d", 123)); - T(expect_success(" +123", "%+5d", 123)); - T(expect_success("00123", "%05d", 123)); - T(expect_success("00123", "%005d", 123)); - /* - * TODO(crbug.com/974084): This odd behavior should be fixed. - * T(expect_success("+0123", "%+05d", 123)); - * Actual: "0+123" - * T(expect_success("+0123", "%+005d", 123)); - * Actual: "0+123" - */ + T(expect_success("123", "%d", 123)); + T(expect_success("-123", "%d", -123)); + T(expect_success("+123", "%+d", 123)); + T(expect_success("-123", "%+d", -123)); + T(expect_success("123", "%-d", 123)); + T(expect_success("-123", "%-d", -123)); + + T(expect_success(" 123", "%5d", 123)); + T(expect_success(" +123", "%+5d", 123)); + T(expect_success("00123", "%05d", 123)); + T(expect_success("00123", "%005d", 123)); + + if (use_builtin_stdlib) { + /* + * TODO(b/239233116): These are incorrect and should be fixed. + */ + /* Fixed point. */ + T(expect_success("0.00123", "%.5d", 123)); + T(expect_success("12.3", "%2.1d", 123)); + /* Precision or width larger than buffer should fail. */ + T(expect(EC_ERROR_OVERFLOW, " 1", false, 4, "%5d", 123)); + T(expect(EC_ERROR_OVERFLOW, " ", false, 4, "%10d", 123)); + T(expect(EC_ERROR_OVERFLOW, "123", false, 4, "%-10d", 123)); + T(expect(EC_ERROR_OVERFLOW, "0.0", false, 4, "%.10d", 123)); + } else { + int ret; + + T(expect_success("00123", "%.5d", 123)); + T(expect_success("123", "%2.1d", 123)); + + /* + * From the man page: The functions snprintf() and vsnprintf() + * do not write more than size bytes (including the + * terminating null byte ('\0')). If the output was truncated + * due to this limit, then the return value is the number of + * characters (excluding the terminating null byte) which + * would have been written to the final string if enough + * space had been available. Thus, a return value of size or + * more means that the output was truncated. + */ +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wformat-truncation" + ret = SNPRINTF(output, 4, "%5d", 123); + TEST_ASSERT_ARRAY_EQ(output, " 1", 4); + TEST_EQ(ret, 5, "%d"); + + ret = SNPRINTF(output, 4, "%10d", 123); + TEST_ASSERT_ARRAY_EQ(output, " ", 4); + TEST_EQ(ret, 10, "%d"); + + ret = SNPRINTF(output, 4, "%-10d", 123); + TEST_ASSERT_ARRAY_EQ(output, "123", 4); + TEST_EQ(ret, 10, "%d"); + + ret = SNPRINTF(output, 4, "%.10d", 123); + TEST_ASSERT_ARRAY_EQ(output, "000", 4); + TEST_EQ(ret, 10, "%d"); +#pragma GCC diagnostic pop + } - T(expect_success(" 123", "%*d", 5, 123)); - T(expect_success(" +123", "%+*d", 5, 123)); - T(expect_success("00123", "%0*d", 5, 123)); - /* - * TODO(crbug.com/974084): This odd behavior should be fixed. - * T(expect_success("00123", "%00*d", 5, 123)); - * Actual: "ERROR" - */ - T(expect_success("0+123", "%+0*d", 5, 123)); - /* - * TODO(crbug.com/974084): This odd behavior should be fixed. - * T(expect_success("0+123", "%+00*d", 5, 123)); - * Actual: "ERROR" - */ + if (use_builtin_stdlib) { + /* + * TODO(b/239233116): These are incorrect and should be fixed. + */ + T(expect_success("0+123", "%+05d", 123)); + T(expect_success("0+123", "%+005d", 123)); + } else { + T(expect_success("+0123", "%+05d", 123)); + T(expect_success("+0123", "%+005d", 123)); + } + + T(expect_success(" 123", "%*d", 5, 123)); + T(expect_success(" +123", "%+*d", 5, 123)); + T(expect_success("00123", "%0*d", 5, 123)); - T(expect_success("123 ", "%-5d", 123)); - T(expect_success("+123 ", "%-+5d", 123)); - T(expect_success(err_str, "%+-5d", 123)); - T(expect_success("123 ", "%-05d", 123)); - T(expect_success("123 ", "%-005d", 123)); - T(expect_success("+123 ", "%-+05d", 123)); - T(expect_success("+123 ", "%-+005d", 123)); - - T(expect_success("0.00123", "%.5d", 123)); - T(expect_success("+0.00123", "%+.5d", 123)); - T(expect_success("0.00123", "%7.5d", 123)); - T(expect_success(" 0.00123", "%9.5d", 123)); - T(expect_success(" +0.00123", "%+9.5d", 123)); - - T(expect_success("123", "%u", 123)); - T(expect_success("4294967295", "%u", -1)); + if (use_builtin_stdlib) { + /* + * TODO(b/239233116): This incorrect and should be fixed. + */ + T(expect_success(err_str, "%00*d", 5, 123)); + } else { + T(expect_success("00123", "%00*d", 5, 123)); + } + + if (use_builtin_stdlib) { + /* + * TODO(b/239233116): This is incorrect and should be fixed. + */ + T(expect_success("0+123", "%+0*d", 5, 123)); + } else { + T(expect_success("+0123", "%+0*d", 5, 123)); + } + + if (use_builtin_stdlib) { + /* + * TODO(b/239233116): This is incorrect and should be fixed. + */ + T(expect_success(err_str, "%+00*d", 5, 123)); + } else { + T(expect_success("+0123", "%+00*d", 5, 123)); + } + + T(expect_success("123 ", "%-5d", 123)); + T(expect_success("+123 ", "%-+5d", 123)); + if (use_builtin_stdlib) { + /* + * TODO(b/239233116): This incorrect and should be fixed. + */ + T(expect_success(err_str, "%+-5d", 123)); + } else { + T(expect_success("+123 ", "%+-5d", 123)); + } + T(expect_success("123 ", "%-05d", 123)); + T(expect_success("123 ", "%-005d", 123)); + T(expect_success("+123 ", "%-+05d", 123)); + T(expect_success("+123 ", "%-+005d", 123)); + + if (use_builtin_stdlib) { + /* + * TODO(b/239233116): These are incorrect and should be fixed. + */ + T(expect_success("0.00123", "%.5d", 123)); + T(expect_success("+0.00123", "%+.5d", 123)); + T(expect_success("0.00123", "%7.5d", 123)); + T(expect_success(" 0.00123", "%9.5d", 123)); + T(expect_success(" +0.00123", "%+9.5d", 123)); + } else { + T(expect_success("00123", "%.5d", 123)); + T(expect_success("+00123", "%+.5d", 123)); + T(expect_success(" 00123", "%7.5d", 123)); + T(expect_success(" 00123", "%9.5d", 123)); + T(expect_success(" +00123", "%+9.5d", 123)); + } + + T(expect_success("123", "%u", 123)); + T(expect_success("4294967295", "%u", -1)); T(expect_success("18446744073709551615", "%llu", (uint64_t)-1)); - T(expect_success("0", "%x", 0)); - T(expect_success("0", "%X", 0)); - T(expect_success("5e", "%x", 0X5E)); - T(expect_success("5E", "%X", 0X5E)); + T(expect_success("0", "%x", 0)); + T(expect_success("0", "%X", 0)); + T(expect_success("5e", "%x", 0X5E)); + T(expect_success("5E", "%X", 0X5E)); + + return EC_SUCCESS; +} + +test_static int test_printf_long32_enabled(void) +{ + bool use_l32 = IS_ENABLED(CONFIG_PRINTF_LONG_IS_32BITS); + + if (IS_ENABLED(BOARD_BLOONCHIPPER) || IS_ENABLED(BOARD_DARTMONKEY)) + TEST_ASSERT(use_l32); + else + TEST_ASSERT(!use_l32); + return EC_SUCCESS; +} + +test_static int test_vsnprintf_32bit_long_supported(void) +{ + long long_min = INT32_MIN; + long long_max = INT32_MAX; + unsigned long ulong_max = UINT32_MAX; + char const *long_min_str = "-2147483648"; + char const *long_max_str = "2147483647"; + char const *ulong_max_str = "4294967295"; + char const *long_min_hexstr = "80000000"; + char const *long_max_hexstr = "7fffffff"; + char const *ulong_max_hexstr = "ffffffff"; + + T(expect_success(long_min_str, "%ld", long_min)); + T(expect_success(long_min_hexstr, "%lx", long_min)); + T(expect_success(long_max_str, "%ld", long_max)); + T(expect_success(long_max_hexstr, "%lx", long_max)); + T(expect_success(ulong_max_str, "%lu", ulong_max)); + T(expect_success(ulong_max_hexstr, "%lx", ulong_max)); + T(expect_success(long_max_str, "%ld", long_max)); + + T(expect_success(" +123", "%+*ld", 5, 123)); + T(expect_success("00000123", "%08lu", 123)); + T(expect_success("131415", "%d%lu%d", 13, 14L, 15)); /* - * %l is deprecated on 32-bit systems (see crbug.com/984041), but is - * is still functional on 64-bit systems. + * %i and %li are only supported via the CONFIG_PRINTF_LONG_IS_32BITS + * configuration (see https://issuetracker.google.com/issues/172210614). */ - if (sizeof(long) == sizeof(uint32_t)) { - T(expect_success(err_str, "%lx", 0x7b)); - T(expect_success(err_str, "%08lu", 0x7b)); - T(expect_success("13ERROR", "%d%lu", 13, 14)); + T(expect_success("123", "%i", 123)); + T(expect_success("123", "%li", 123)); + + return EC_SUCCESS; +} + +test_static int test_vsnprintf_64bit_long_supported(void) +{ + /* These lines are only executed when sizeof(long) is 64-bits but are + * still compiled by systems with 32-bit longs, so the casts are needed + * to avoid compilation errors. + */ + long long_min = (long)INT64_MIN; + long long_max = (long)INT64_MAX; + unsigned long ulong_max = (unsigned long)UINT64_MAX; + char const *long_min_str = "-9223372036854775808"; + char const *long_max_str = "9223372036854775807"; + char const *ulong_max_str = "18446744073709551615"; + char const *long_min_hexstr = "8000000000000000"; + char const *long_max_hexstr = "7fffffffffffffff"; + char const *ulong_max_hexstr = "ffffffffffffffff"; + + T(expect_success(long_min_str, "%ld", long_min)); + T(expect_success(long_min_hexstr, "%lx", long_min)); + T(expect_success(long_max_str, "%ld", long_max)); + T(expect_success(long_max_hexstr, "%lx", long_max)); + T(expect_success(ulong_max_str, "%lu", ulong_max)); + T(expect_success(ulong_max_hexstr, "%lx", ulong_max)); + T(expect_success(long_max_str, "%ld", long_max)); + + T(expect_success(" +123", "%+*ld", 5, 123)); + T(expect_success("00000123", "%08lu", 123)); + T(expect_success("131415", "%d%lu%d", 13, 14L, 15)); + + if (use_builtin_stdlib) { + /* + * TODO(b/239233116): These are incorrect and should be fixed. + */ + T(expect_success(err_str, "%i", 123)); + T(expect_success(err_str, "%li", 123)); } else { - T(expect_success("7b", "%lx", 0x7b)); - T(expect_success("00000123", "%08lu", 123)); - T(expect_success("131415", "%d%lu%d", 13, 14L, 15)); + T(expect_success("123", "%i", 123)); + T(expect_success("123", "%li", 123)); } return EC_SUCCESS; } +test_static int test_vsnprintf_long_not_supported(void) +{ + T(expect_success(err_str, "%ld", 0x7b)); + T(expect_success(err_str, "%li", 0x7b)); + T(expect_success(err_str, "%lu", 0x7b)); + T(expect_success(err_str, "%lx", 0x7b)); + T(expect_success(err_str, "%08lu", 123)); + T(expect_success("13ERROR", "%d%lu%d", 13, 14L, 15)); + + T(expect_success(err_str, "%i", 123)); + T(expect_success(err_str, "%li", 123)); + + return EC_SUCCESS; +} + +test_static int test_vsnprintf_long(void) +{ + /* + * %l is functional on 64-bit systems but is not supported on 32-bit + * systems (see https://issuetracker.google.com/issues/172210614) unless + * explicitly enabled via configuration. + */ + if (IS_ENABLED(CONFIG_PRINTF_LONG_IS_32BITS)) + return test_vsnprintf_32bit_long_supported(); + else if (sizeof(long) == sizeof(uint64_t)) + return test_vsnprintf_64bit_long_supported(); + else + return test_vsnprintf_long_not_supported(); +} + test_static int test_vsnprintf_pointers(void) { void *ptr = (void *)0x55005E00; - unsigned int val = 0; - - T(expect_success("55005e00", "%pP", ptr)); - T(expect_success(err_str, "%P", ptr)); - /* %p by itself is invalid */ - T(expect(EC_ERROR_INVAL, NO_BYTES_TOUCHED, - false, 0, "%p")); - /* %p with an unknown suffix is invalid */ - T(expect(EC_ERROR_INVAL, NO_BYTES_TOUCHED, - false, 0, "%p ")); - /* %p with an unknown suffix is invalid */ - T(expect(EC_ERROR_INVAL, NO_BYTES_TOUCHED, - false, 0, "%pQ")); - - /* Test %pb, binary format */ - T(expect_success("0", "%pb", BINARY_VALUE(val, 0))); - val = 0x5E; - T(expect_success("1011110", "%pb", BINARY_VALUE(val, 0))); - T(expect_success("0000000001011110", "%pb", BINARY_VALUE(val, 16))); - val = 0x12345678; - T(expect_success("10010001101000101011001111000", "%pb", - BINARY_VALUE(val, 0))); - val = 0xFEDCBA90; - /* Test a number that makes the longest string possible */ - T(expect_success("11111110110111001011101010010000", "%pb", - BINARY_VALUE(val, 0))); + + if (use_builtin_stdlib) { + /* + * TODO(b/239233116): This incorrect and should be fixed. + */ + T(expect_success("55005e00", "%p", ptr)); + } else { + T(expect_success("0x55005e00", "%p", ptr)); + } + return EC_SUCCESS; } test_static int test_vsnprintf_chars(void) { - T(expect_success("a", "%c", 'a')); - T(expect_success("*", "%c", '*')); + T(expect_success("a", "%c", 'a')); + T(expect_success("*", "%c", '*')); return EC_SUCCESS; } test_static int test_vsnprintf_strings(void) { - T(expect_success("abc", "%s", "abc")); - T(expect_success(" abc", "%5s", "abc")); - T(expect_success("abc", "%0s", "abc")); - T(expect_success("abc ", "%-5s", "abc")); - T(expect_success("abc", "%*s", 0, "abc")); - T(expect_success("a", "%.1s", "abc")); - T(expect_success("a", "%.*s", 1, "abc")); - T(expect_success("", "%.0s", "abc")); - T(expect_success("", "%.*s", 0, "abc")); - /* - * TODO(crbug.com/974084): - * Ignoring the padding parameter is slightly - * odd behavior and could use a review. - */ - T(expect_success("ab", "%5.2s", "abc")); - T(expect_success("abc", "%.4s", "abc")); + T(expect_success("abc", "%s", "abc")); + T(expect_success(" abc", "%5s", "abc")); + T(expect_success("abc", "%0s", "abc")); + T(expect_success("abc ", "%-5s", "abc")); + T(expect_success("abc", "%*s", 0, "abc")); + T(expect_success("a", "%.1s", "abc")); + T(expect_success("a", "%.*s", 1, "abc")); + T(expect_success("", "%.0s", "abc")); + T(expect_success("", "%.*s", 0, "abc")); + if (use_builtin_stdlib) { + /* + * TODO(b/239233116): This incorrect and should be fixed. + */ + T(expect_success("ab", "%5.2s", "abc")); + } else { + T(expect_success(" ab", "%5.2s", "abc")); + } + T(expect_success("abc", "%.4s", "abc")); /* * Given a malformed string (address 0x1 is a good example), * if we ask for zero precision, expect no bytes to be read * from the malformed address and a blank output string. */ - T(expect_success("", "%.0s", (char *)1)); + T(expect_success("", "%.0s", (char *)1)); return EC_SUCCESS; } -test_static int test_vsnprintf_timestamps(void) +test_static int test_snprintf_timestamp(void) { + char str[PRINTF_TIMESTAMP_BUF_SIZE]; + int size; + int ret; uint64_t ts = 0; - T(expect_success("0.000000", "%pT", &ts)); + /* Success cases. */ + + ret = snprintf_timestamp(str, sizeof(str), ts); + TEST_EQ(ret, 8, "%d"); + TEST_ASSERT_ARRAY_EQ(str, "0.000000", sizeof("0.000000")); + ts = 123456; - T(expect_success("0.123456", "%pT", &ts)); + ret = snprintf_timestamp(str, sizeof(str), ts); + TEST_EQ(ret, 8, "%d"); + TEST_ASSERT_ARRAY_EQ(str, "0.123456", sizeof("0.123456")); + ts = 9999999000000; - T(expect_success("9999999.000000", "%pT", &ts)); + ret = snprintf_timestamp(str, sizeof(str), ts); + TEST_EQ(ret, 14, "%d"); + TEST_ASSERT_ARRAY_EQ(str, "9999999.000000", sizeof("9999999.000000")); + + ts = UINT64_MAX; + ret = snprintf_timestamp(str, sizeof(str), ts); + TEST_EQ(ret, 21, "%d"); + TEST_ASSERT_ARRAY_EQ(str, "18446744073709.551615", + sizeof("18446744073709.551615")); + + /* Error cases. */ + + /* Buffer is too small by one. */ + size = 21; + ts = UINT64_MAX; + str[0] = 'f'; + ret = snprintf_timestamp(str, size, ts); + TEST_EQ(ret, -EC_ERROR_OVERFLOW, "%d"); + TEST_EQ(str[0], '\0', "%d"); + + /* Size is zero. */ + size = 0; + ts = UINT64_MAX; + str[0] = 'f'; + ret = snprintf_timestamp(str, size, ts); + TEST_EQ(ret, -EC_ERROR_INVAL, "%d"); + TEST_EQ(str[0], 'f', "%d"); + + /* Size is one. */ + size = 1; + ts = UINT64_MAX; + str[0] = 'f'; + ret = snprintf_timestamp(str, size, ts); + TEST_EQ(ret, -EC_ERROR_OVERFLOW, "%d"); + TEST_EQ(str[0], '\0', "%d"); + return EC_SUCCESS; } -test_static int test_vsnprintf_hexdump(void) +test_static int test_snprintf_hex_buffer(void) { - const char bytes[] = {0x00, 0x5E}; + const uint8_t bytes[] = { 0xAB, 0x5E }; + char str_buf[5]; + int rv; + + /* Success cases. */ + + memset(str_buf, 0xff, sizeof(str_buf)); + rv = snprintf_hex_buffer(str_buf, sizeof(str_buf), HEX_BUF(bytes, 2)); + TEST_ASSERT_ARRAY_EQ(str_buf, "ab5e", sizeof("ab5e")); + TEST_EQ(rv, 4, "%d"); + + memset(str_buf, 0xff, sizeof(str_buf)); + rv = snprintf_hex_buffer(str_buf, sizeof(str_buf), HEX_BUF(bytes, 0)); + TEST_ASSERT_ARRAY_EQ(str_buf, "", sizeof("")); + TEST_EQ(rv, 0, "%d"); + + memset(str_buf, 0xff, sizeof(str_buf)); + rv = snprintf_hex_buffer(str_buf, sizeof(str_buf), HEX_BUF(bytes, 1)); + TEST_ASSERT_ARRAY_EQ(str_buf, "ab", sizeof("ab")); + TEST_EQ(rv, 2, "%d"); + + /* Error cases. */ + + /* Zero for buffer size argument is an error. */ + memset(str_buf, 0xff, sizeof(str_buf)); + TEST_ASSERT_MEMSET(str_buf, (char)0xff, sizeof(str_buf)); + rv = snprintf_hex_buffer(str_buf, 0, HEX_BUF(bytes, 2)); + TEST_EQ(rv, -EC_ERROR_INVAL, "%d"); + TEST_ASSERT_MEMSET(str_buf, (char)0xff, sizeof(str_buf)); + + /* Buffer only has space for terminating '\0'. */ + memset(str_buf, 0xff, sizeof(str_buf)); + TEST_ASSERT_MEMSET(str_buf, (char)0xff, sizeof(str_buf)); + rv = snprintf_hex_buffer(str_buf, 1, HEX_BUF(bytes, 1)); + TEST_ASSERT_ARRAY_EQ(str_buf, "", sizeof("")); + TEST_EQ(rv, -EC_ERROR_OVERFLOW, "%d"); + + /* Buffer only has space for one character and '\0'. */ + memset(str_buf, 0xff, sizeof(str_buf)); + TEST_ASSERT_MEMSET(str_buf, (char)0xff, sizeof(str_buf)); + rv = snprintf_hex_buffer(str_buf, 2, HEX_BUF(bytes, 1)); + TEST_ASSERT_ARRAY_EQ(str_buf, "a", sizeof("a")); + TEST_EQ(rv, -EC_ERROR_OVERFLOW, "%d"); - T(expect_success("005e", "%ph", HEX_BUF(bytes, 2))); - T(expect_success("", "%ph", HEX_BUF(bytes, 0))); - T(expect_success("00", "%ph", HEX_BUF(bytes, 1))); return EC_SUCCESS; } test_static int test_vsnprintf_combined(void) { - T(expect_success("abc", "%c%s", 'a', "bc")); - T(expect_success("12\tbc", "%d\t%s", 12, "bc")); + T(expect_success("abc", "%c%s", 'a', "bc")); + T(expect_success("12\tbc", "%d\t%s", 12, "bc")); + return EC_SUCCESS; +} + +test_static int test_uint64_to_str(void) +{ + /* Longest uin64 in decimal = 20, plus terminating NUL. */ + char buf[21]; + char *str; + + str = uint64_to_str(buf, sizeof(buf), /*val=*/0, /*precision=*/-1, + /*base=*/10, /*uppercase=*/false); + TEST_ASSERT_ARRAY_EQ(str, "0", sizeof("0")); + + str = uint64_to_str(buf, sizeof(buf), /*val=*/UINT64_MAX, + /*precision=*/-1, /*base=*/10, + /*uppercase=*/false); + TEST_ASSERT_ARRAY_EQ(str, "18446744073709551615", + sizeof("18446744073709551615")); + + /* Buffer too small by 1. */ + str = uint64_to_str(buf, /*buf_len=*/20, /*val=*/UINT64_MAX, + /*precision=*/-1, /*base=*/10, /*uppercase=*/false); + TEST_ASSERT(str == NULL); + + /* lower case hex */ + str = uint64_to_str(buf, sizeof(buf), /*val=*/0, /*precision=*/-1, + /*base=*/16, /*uppercase=*/false); + TEST_ASSERT_ARRAY_EQ(str, "0", sizeof("0")); + + /* lower case hex */ + str = uint64_to_str(buf, sizeof(buf), /*val=*/UINT64_MAX, + /*precision=*/-1, /*base=*/16, + /*uppercase=*/false); + TEST_ASSERT_ARRAY_EQ(str, "ffffffffffffffff", + sizeof("fffffffffffffff")); + + /* upper case hex */ + str = uint64_to_str(buf, sizeof(buf), /*val=*/0, /*precision=*/-1, + /*base=*/16, /*uppercase=*/true); + TEST_ASSERT_ARRAY_EQ(str, "0", sizeof("0")); + + str = uint64_to_str(buf, sizeof(buf), /*val=*/UINT64_MAX, + /*precision=*/-1, /*base=*/16, + /*uppercase=*/true); + TEST_ASSERT_ARRAY_EQ(str, "FFFFFFFFFFFFFFFF", + sizeof("FFFFFFFFFFFFFFF")); + + /* precision 0 */ + str = uint64_to_str(buf, sizeof(buf), /*val=*/1, /*precision=*/0, + /*base=*/10, /*uppercase=*/false); + TEST_ASSERT_ARRAY_EQ(str, "1.", sizeof("1.")); + + /* precision 6 */ + str = uint64_to_str(buf, sizeof(buf), /*val=*/1, /*precision=*/6, + /*base=*/10, /*uppercase=*/false); + TEST_ASSERT_ARRAY_EQ(str, "0.000001", sizeof("0.000001")); + + /* Reduced precision due to buffer that is too small. */ + str = uint64_to_str(buf, /*buf_len=*/8, /*val=*/1, /*precision=*/6, + /*base=*/10, /*uppercase=*/false); + TEST_ASSERT_ARRAY_EQ(str, "0.00001", sizeof("0.00001")); + + /* + * Reduced precision due to buffer that is too small, so precision + * gets changed to 0. + */ + str = uint64_to_str(buf, /*buf_len=*/3, /*val=*/1, /*precision=*/6, + /*base=*/10, /*uppercase=*/false); + TEST_ASSERT_ARRAY_EQ(str, "1.", sizeof("1.")); + + /* Precision is unable to fit in provided buffer. */ + str = uint64_to_str(buf, /*buf_len=*/2, /*val=*/1, /*precision=*/6, + /*base=*/10, /*uppercase=*/false); + TEST_ASSERT(str == NULL); + + /* Negative base. */ + str = uint64_to_str(buf, sizeof(buf), /*val=*/0, /*precision=*/-1, + /*base=*/-1, /*uppercase=*/false); + TEST_ASSERT(str == NULL); + + /* Base zero. */ + str = uint64_to_str(buf, sizeof(buf), /*val=*/1, /*precision=*/-1, + /*base=*/0, /*uppercase=*/false); + TEST_ASSERT(str == NULL); + + /* Base one. */ + str = uint64_to_str(buf, sizeof(buf), /*val=*/1, /*precision=*/-1, + /*base=*/1, /*uppercase=*/false); + TEST_ASSERT(str == NULL); + + /* Buffer size 1. */ + str = uint64_to_str(buf, /*buf_len=*/1, /*val=*/0, /*precision=*/-1, + /*base=*/10, /*uppercase=*/false); + TEST_ASSERT(str == NULL); + + /* Buffer size 0. */ + str = uint64_to_str(buf, /*buf_len=*/0, /*val=*/0, /*precision=*/-1, + /*base=*/10, /*uppercase=*/false); + TEST_ASSERT(str == NULL); + + /* Buffer size -1. */ + str = uint64_to_str(buf, /*buf_len=*/-1, /*val=*/0, /*precision=*/-1, + /*base=*/10, /*uppercase=*/false); + TEST_ASSERT(str == NULL); + return EC_SUCCESS; } -void run_test(int argc, char **argv) +void run_test(int argc, const char **argv) { test_reset(); RUN_TEST(test_vsnprintf_args); RUN_TEST(test_vsnprintf_int); + RUN_TEST(test_printf_long32_enabled); + RUN_TEST(test_vsnprintf_long); RUN_TEST(test_vsnprintf_pointers); RUN_TEST(test_vsnprintf_chars); RUN_TEST(test_vsnprintf_strings); - RUN_TEST(test_vsnprintf_timestamps); - RUN_TEST(test_vsnprintf_hexdump); RUN_TEST(test_vsnprintf_combined); + RUN_TEST(test_uint64_to_str); + RUN_TEST(test_snprintf_timestamp); + RUN_TEST(test_snprintf_hex_buffer); test_print_result(); } |