diff --git a/Makefile b/Makefile index 7b28a1a1..d27fadbf 100644 --- a/Makefile +++ b/Makefile @@ -39,7 +39,7 @@ APP = test_suite # bar/file3 # ----------------------------------------------------------------------------- -FILES_PRJ = test/test_suite +FILES_PRJ = test/test_suite printf # ------------------------------------------------------------------------------ @@ -85,7 +85,7 @@ VPATH := $(sort $(dir $(FILES_TMP))) # ------------------------------------------------------------------------------ AR = $(PATH_TOOLS_CC)ar AS = $(PATH_TOOLS_CC)g++ -CC = $(PATH_TOOLS_CC)g++ +CC = $(PATH_TOOLS_CC)gcc CL = $(PATH_TOOLS_CC)g++ NM = $(PATH_TOOLS_CC)nm GCOV = $(PATH_TOOLS_CC)gcov @@ -107,7 +107,6 @@ SED = $(PATH_TOOLS_UTIL)sed GCCFLAGS = $(C_INCLUDES) \ $(C_DEFINES) \ - -std=c++11 \ -g \ -Wall \ -pedantic \ @@ -124,10 +123,8 @@ GCCFLAGS = $(C_INCLUDES) \ -Winit-self \ -Wdouble-promotion \ -gdwarf-2 \ - -fno-exceptions \ -O2 \ -ffunction-sections \ - -ffat-lto-objects \ -fdata-sections \ -fverbose-asm \ -Wextra \ @@ -135,12 +132,12 @@ GCCFLAGS = $(C_INCLUDES) \ -Wfloat-equal CFLAGS = $(GCCFLAGS) \ - -Wunsuffixed-float-constants \ -x c \ -std=c99 CPPFLAGS = $(GCCFLAGS) \ -x c++ \ + -std=c++11 \ -fno-rtti \ -fstrict-enums \ -fno-use-cxa-atexit \ @@ -251,7 +248,7 @@ $(TRG)_nm.txt : $(TRG) # ...and Create an assembly listing using objdump # ...and Generate a dependency file (using the -MM flag) @-$(CL) $(CPPFLAGS) $< -E -o $(PATH_PRE)/$(basename $(@F)).pre - @-$(CL) $(CPPFLAGS) $< -c -o $(PATH_OBJ)/$(basename $(@F)).o 2> $(PATH_ERR)/$(basename $(@F)).err + @-$(CL) $(CPPFLAGS) -O $< -c -o $(PATH_OBJ)/$(basename $(@F)).o 2> $(PATH_ERR)/$(basename $(@F)).err @-$(SED) -e 's|.h:\([0-9]*\),|.h(\1) :|' -e 's|:\([0-9]*\):|(\1) :|' $(PATH_ERR)/$(basename $(@F)).err @-$(OBJDUMP) --disassemble --line-numbers -S $(PATH_OBJ)/$(basename $(@F)).o > $(PATH_LST)/$(basename $(@F)).lst @-$(CL) $(CPPFLAGS) $< -MM > $(PATH_OBJ)/$(basename $(@F)).d @@ -269,3 +266,4 @@ $(TRG)_nm.txt : $(TRG) @-$(SED) -e 's|.h:\([0-9]*\),|.h(\1) :|' -e 's|:\([0-9]*\):|(\1) :|' $(PATH_ERR)/$(basename $(@F)).err @-$(OBJDUMP) -S $(PATH_OBJ)/$(basename $(@F)).o > $(PATH_LST)/$(basename $(@F)).lst @-$(CC) $(CFLAGS) $< -MM > $(PATH_OBJ)/$(basename $(@F)).d + @-$(CL) $(CFLAGS) -O0 --coverage $< -c -o $(PATH_COV)/$(basename $(@F)).o 2> $(PATH_NUL) diff --git a/printf.c b/printf.c index 8a700add..1d29fb26 100644 --- a/printf.c +++ b/printf.c @@ -32,6 +32,7 @@ #include #include +#include #include "printf.h" @@ -822,16 +823,10 @@ static int _vsnprintf(out_fct_type out, char* buffer, const size_t maxlen, const case 'p' : { width = sizeof(void*) * 2U; flags |= FLAGS_ZEROPAD | FLAGS_UPPERCASE; -#if defined(PRINTF_SUPPORT_LONG_LONG) - const bool is_ll = sizeof(uintptr_t) == sizeof(long long); - if (is_ll) { - idx = _ntoa_long_long(out, buffer, idx, maxlen, (uintptr_t)va_arg(va, void*), false, 16U, precision, width, flags); - } - else { -#endif - idx = _ntoa_long(out, buffer, idx, maxlen, (unsigned long)((uintptr_t)va_arg(va, void*)), false, 16U, precision, width, flags); -#if defined(PRINTF_SUPPORT_LONG_LONG) - } +#if defined(PRINTF_SUPPORT_LONG_LONG) && (LONG_MAX < UINTPTR_MAX) + idx = _ntoa_long_long(out, buffer, idx, maxlen, (uintptr_t)va_arg(va, void*), false, 16U, precision, width, flags); +#else + idx = _ntoa_long(out, buffer, idx, maxlen, (unsigned long)((uintptr_t)va_arg(va, void*)), false, 16U, precision, width, flags); #endif format++; break; diff --git a/test/catch.hpp b/test/catch.hpp index 1850fff1..8c3a7e63 100644 --- a/test/catch.hpp +++ b/test/catch.hpp @@ -9599,6 +9599,15 @@ namespace Catch { } return names.substr(start, end - start + 1); }; + auto skipq = [&] (size_t start, char quote) { + for (auto i = start + 1; i < names.size() ; ++i) { + if (names[i] == quote) + return i; + if (names[i] == '\\') + ++i; + } + assert(0 && "Mismatched quotes"); + }; size_t start = 0; std::stack openings; @@ -9619,6 +9628,10 @@ namespace Catch { // case '>': openings.pop(); break; + case '"': + case '\'': + pos = skipq(pos, c); + break; case ',': if (start != pos && openings.size() == 0) { m_messages.emplace_back(macroName, lineInfo, resultType); diff --git a/test/test_suite.cpp b/test/test_suite.cpp index 5507c3bd..1c1c7f1c 100644 --- a/test/test_suite.cpp +++ b/test/test_suite.cpp @@ -33,20 +33,43 @@ #include #include #include +#include +// PRIi32 etc. macros +// printf should provide its own version +#include -namespace test { - // use functions in own test namespace to avoid stdio conflicts - #include "../printf.h" - #include "../printf.c" -} // namespace test +using Catch::Matchers::Equals; +// store pointers to library functions before they are masked by macro +int (*lib_sprintf)(char * buffer, const char* fmt, ...) = sprintf; +int (*lib_snprintf)(char * buffer, size_t count, const char* fmt, ...) = snprintf; + +#include "../printf.h" + +int (*our_sprintf)(char * buffer, const char* fmt, ...) = sprintf; +int (*our_snprintf)(char * buffer, size_t count, const char* fmt, ...) = snprintf; + + +// pointers to tested versions +// allows running tests against standard library implementation +int (*tested_sprintf)(char * buffer, const char* fmt, ...) = our_sprintf; +int (*tested_snprintf)(char * buffer, size_t count, const char* fmt, ...) = our_snprintf; + + +// some assumptions about implementation +#define PRINTF_FLOAT_PREC 9 +#define PRINTF_FLOAT_DECIMALS 9 +#define PRINTF_POINTER_0XHEX 0 + +// enable failing but valid tests +#define ENABLE_FAILING 0 // dummy putchar static char printf_buffer[100]; static size_t printf_idx = 0U; -void test::_putchar(char character) +void _putchar(char character) { printf_buffer[printf_idx++] = character; } @@ -57,11 +80,12 @@ void _out_fct(char character, void* arg) printf_buffer[printf_idx++] = character; } +// run basic sanity tests TEST_CASE("printf", "[]" ) { printf_idx = 0U; memset(printf_buffer, 0xCC, 100U); - REQUIRE(test::printf("% d", 4232) == 5); + REQUIRE(printf("% d", 4232) == 5); REQUIRE(printf_buffer[5] == (char)0xCC); printf_buffer[5] = 0; REQUIRE(!strcmp(printf_buffer, " 4232")); @@ -70,8 +94,9 @@ TEST_CASE("printf", "[]" ) { TEST_CASE("fctprintf", "[]" ) { printf_idx = 0U; - memset(printf_buffer, 0xCC, 100U); - test::fctprintf(&_out_fct, nullptr, "This is a test of %X", 0x12EFU); + memset(printf_buffer, 0xCC, sizeof(printf_buffer)); + int ret = fctprintf(&_out_fct, nullptr, "This is a test of %X", 0x12EFU); + REQUIRE(ret == 22U); REQUIRE(!strncmp(printf_buffer, "This is a test of 12EF", 22U)); REQUIRE(printf_buffer[22] == (char)0xCC); } @@ -79,19 +104,19 @@ TEST_CASE("fctprintf", "[]" ) { TEST_CASE("snprintf", "[]" ) { char buffer[100]; + memset(buffer, 0xCC, sizeof(buffer)); + snprintf(buffer, 100U, "%d", -1000); + REQUIRE_THAT(buffer, Equals("-1000")); - test::snprintf(buffer, 100U, "%d", -1000); - REQUIRE(!strcmp(buffer, "-1000")); - - test::snprintf(buffer, 3U, "%d", -1000); - REQUIRE(!strcmp(buffer, "-1")); + snprintf(buffer, 3U, "%d", -1000); + REQUIRE_THAT(buffer, Equals("-1")); } static void vprintf_builder_1(char* buffer, ...) { va_list args; va_start(args, buffer); - test::vprintf("%d", args); + vprintf("%d", args); va_end(args); } @@ -99,7 +124,7 @@ static void vsnprintf_builder_1(char* buffer, ...) { va_list args; va_start(args, buffer); - test::vsnprintf(buffer, 100U, "%d", args); + vsnprintf(buffer, 100U, "%d", args); va_end(args); } @@ -107,7 +132,7 @@ static void vsnprintf_builder_3(char* buffer, ...) { va_list args; va_start(args, buffer); - test::vsnprintf(buffer, 100U, "%d %d %s", args); + vsnprintf(buffer, 100U, "%d %d %s", args); va_end(args); } @@ -127,1387 +152,1942 @@ TEST_CASE("vsnprintf", "[]" ) { char buffer[100]; vsnprintf_builder_1(buffer, -1); - REQUIRE(!strcmp(buffer, "-1")); + REQUIRE_THAT(buffer, Equals("-1")); vsnprintf_builder_3(buffer, 3, -1000, "test"); - REQUIRE(!strcmp(buffer, "3 -1000 test")); + REQUIRE_THAT(buffer, Equals("3 -1000 test")); } +// macros to wrap tests +// variables with result are available for further test cases +#define TEST_DEF \ + char buffer[100]; \ + int ret; \ + (void)buffer; (void)ret; \ + struct dummy \ + /**/ + +// use prefix T_ so that lininsanity macros do not collide +#define T_SPRINTF(expected, ...) \ + do { \ + CAPTURE(__VA_ARGS__); \ + ret = tested_sprintf(buffer, __VA_ARGS__); \ + CHECK_THAT(buffer, Equals(expected)); \ + (void)ret; \ + } while (0) \ + /**/ + +#define T_SNPRINTF(expected, retval, ...) \ + do { \ + CAPTURE(__VA_ARGS__); \ + ret = tested_snprintf(buffer, __VA_ARGS__); \ + if (expected) \ + CHECK_THAT(buffer, Equals(expected)); \ + CHECK(ret == retval); \ + } while (0) \ + /**/ -TEST_CASE("space flag", "[]" ) { - char buffer[100]; - test::sprintf(buffer, "% d", 42); - REQUIRE(!strcmp(buffer, " 42")); - test::sprintf(buffer, "% d", -42); - REQUIRE(!strcmp(buffer, "-42")); +TEST_CASE("space flag", "[]" ) { + TEST_DEF; + + T_SPRINTF(" 42", + "% d", 42); + + T_SPRINTF("-42", + "% d", -42); + T_SPRINTF(" 42", + "% 5d", 42); + T_SPRINTF(" -42", + "% 5d", -42); + T_SPRINTF(" 42", + "% 15d", 42); + T_SPRINTF(" -42", + "% 15d", -42); + T_SPRINTF(" -42", + "% 15d", -42); + T_SPRINTF(" -42.987", + "% 15.3f", -42.987); + T_SPRINTF(" 42.987", + "% 15.3f", 42.987); + T_SPRINTF("Hello testing", + "% s", "Hello testing"); + T_SPRINTF(" 1024", + "% d", 1024); + T_SPRINTF("-1024", + "% d", -1024); + T_SPRINTF(" 1024", + "% i", 1024); + T_SPRINTF("-1024", + "% i", -1024); + T_SPRINTF("1024", + "% u", 1024); + T_SPRINTF("4294966272", + "% u", 4294966272U); + T_SPRINTF("777", + "% o", 511); + T_SPRINTF("37777777001", + "% o", 4294966785U); + T_SPRINTF("1234abcd", + "% x", 305441741); + T_SPRINTF("edcb5433", + "% x", 3989525555U); + T_SPRINTF("1234ABCD", + "% X", 305441741); + T_SPRINTF("EDCB5433", + "% X", 3989525555U); + T_SPRINTF("x", + "% c", 'x'); +} - test::sprintf(buffer, "% 5d", 42); - REQUIRE(!strcmp(buffer, " 42")); - test::sprintf(buffer, "% 5d", -42); - REQUIRE(!strcmp(buffer, " -42")); +TEST_CASE("+ flag", "[]" ) { + TEST_DEF; + + T_SPRINTF("+42", + "%+d", 42); + T_SPRINTF("-42", + "%+d", -42); + T_SPRINTF(" +42", + "%+5d", 42); + T_SPRINTF(" -42", + "%+5d", -42); + T_SPRINTF(" +42", + "%+15d", 42); + T_SPRINTF(" -42", + "%+15d", -42); + T_SPRINTF("Hello testing", + "%+s", "Hello testing"); + T_SPRINTF("+1024", + "%+d", 1024); + T_SPRINTF("-1024", + "%+d", -1024); + T_SPRINTF("+1024", + "%+i", 1024); + T_SPRINTF("-1024", + "%+i", -1024); + T_SPRINTF("1024", + "%+u", 1024); + T_SPRINTF("4294966272", + "%+u", 4294966272U); + T_SPRINTF("777", + "%+o", 511); + T_SPRINTF("37777777001", + "%+o", 4294966785U); + T_SPRINTF("1234abcd", + "%+x", 305441741); + T_SPRINTF("edcb5433", + "%+x", 3989525555U); + T_SPRINTF("1234ABCD", + "%+X", 305441741); + T_SPRINTF("EDCB5433", + "%+X", 3989525555U); + T_SPRINTF("x", + "%+c", 'x'); + T_SPRINTF("+", + "%+.0d", 0); +} - test::sprintf(buffer, "% 15d", 42); - REQUIRE(!strcmp(buffer, " 42")); - test::sprintf(buffer, "% 15d", -42); - REQUIRE(!strcmp(buffer, " -42")); +TEST_CASE("0 flag", "[]" ) { + TEST_DEF; + + T_SPRINTF("42", + "%0d", 42); + T_SPRINTF("42", + "%0ld", 42L); + T_SPRINTF("-42", + "%0d", -42); + T_SPRINTF("00042", + "%05d", 42); + T_SPRINTF("-0042", + "%05d", -42); + T_SPRINTF("000000000000042", + "%015d", 42); + T_SPRINTF("-00000000000042", + "%015d", -42); + T_SPRINTF("000000000042.12", + "%015.2f", 42.1234); + T_SPRINTF("00000000042.988", + "%015.3f", 42.9876); + T_SPRINTF("-00000042.98760", + "%015.5f", -42.9876);} - test::sprintf(buffer, "% 15d", -42); - REQUIRE(!strcmp(buffer, " -42")); - test::sprintf(buffer, "% 15.3f", -42.987); - REQUIRE(!strcmp(buffer, " -42.987")); +TEST_CASE("- flag", "[]" ) { + TEST_DEF; + + T_SPRINTF("42", + "%-d", 42); + T_SPRINTF("-42", + "%-d", -42); + T_SPRINTF("42 ", + "%-5d", 42); + T_SPRINTF("-42 ", + "%-5d", -42); + T_SPRINTF("42 ", + "%-15d", 42); + T_SPRINTF("-42 ", + "%-15d", -42); + T_SPRINTF("42", + "%-0d", 42); + T_SPRINTF("-42", + "%-0d", -42); + T_SPRINTF("42 ", + "%-05d", 42); + T_SPRINTF("-42 ", + "%-05d", -42); + T_SPRINTF("42 ", + "%-015d", 42); + T_SPRINTF("-42 ", + "%-015d", -42); + T_SPRINTF("42", + "%0-d", 42); + T_SPRINTF("-42", + "%0-d", -42); + T_SPRINTF("42 ", + "%0-5d", 42); + T_SPRINTF("-42 ", + "%0-5d", -42); + T_SPRINTF("42 ", + "%0-15d", 42); + T_SPRINTF("-42 ", + "%0-15d", -42); +#ifndef PRINTF_DISABLE_SUPPORT_EXPONENTIAL + T_SPRINTF("-4.200e+01 ", + "%0-15.3e", -42.); +#else + T_SPRINTF("-4.200e+01 ", + "e", -42.); +#endif - test::sprintf(buffer, "% 15.3f", 42.987); - REQUIRE(!strcmp(buffer, " 42.987")); +#ifndef PRINTF_DISABLE_SUPPORT_EXPONENTIAL + T_SPRINTF("-42.0 ", + "%0-15.3g", -42.); +#else + T_SPRINTF("g", + "%0-15.3g", -42.); +#endif +} - test::sprintf(buffer, "% s", "Hello testing"); - REQUIRE(!strcmp(buffer, "Hello testing")); - test::sprintf(buffer, "% d", 1024); - REQUIRE(!strcmp(buffer, " 1024")); +TEST_CASE("# flag", "[]" ) { + TEST_DEF; + + T_SPRINTF("", + "%#.0x", 0); + T_SPRINTF("0", + "%#.1x", 0); + T_SPRINTF("", + "%#.0llx", (long long)0); + T_SPRINTF("0x0000614e", + "%#.8x", 0x614e); + T_SPRINTF("0b110", + "%#b", 6); +#if ENABLE_FAILING + T_SPRINTF("0x1234", + "%#4x", 0x1234); +#endif +} - test::sprintf(buffer, "% d", -1024); - REQUIRE(!strcmp(buffer, "-1024")); - test::sprintf(buffer, "% i", 1024); - REQUIRE(!strcmp(buffer, " 1024")); +TEST_CASE("specifier", "[]" ) { + TEST_DEF; + + T_SPRINTF("Hello testing", + "Hello testing"); + T_SPRINTF("Hello testing", + "%s", "Hello testing"); + T_SPRINTF("1024", + "%d", 1024); + T_SPRINTF("-1024", + "%d", -1024); + T_SPRINTF("1024", + "%i", 1024); + T_SPRINTF("-1024", + "%i", -1024); + T_SPRINTF("1024", + "%u", 1024); + T_SPRINTF("4294966272", + "%u", 4294966272U); + T_SPRINTF("777", + "%o", 511); + T_SPRINTF("37777777001", + "%o", 4294966785U); + T_SPRINTF("1234abcd", + "%x", 305441741); + T_SPRINTF("edcb5433", + "%x", 3989525555U); + T_SPRINTF("1234ABCD", + "%X", 305441741); + T_SPRINTF("EDCB5433", + "%X", 3989525555U); + T_SPRINTF("%", + "%%"); +} - test::sprintf(buffer, "% i", -1024); - REQUIRE(!strcmp(buffer, "-1024")); - test::sprintf(buffer, "% u", 1024); - REQUIRE(!strcmp(buffer, "1024")); +TEST_CASE("width", "[]" ) { + TEST_DEF; + + T_SPRINTF("Hello testing", + "%1s", "Hello testing"); + T_SPRINTF("1024", + "%1d", 1024); + T_SPRINTF("-1024", + "%1d", -1024); + T_SPRINTF("1024", + "%1i", 1024); + T_SPRINTF("-1024", + "%1i", -1024); + T_SPRINTF("1024", + "%1u", 1024); + T_SPRINTF("4294966272", + "%1u", 4294966272U); + T_SPRINTF("777", + "%1o", 511); + T_SPRINTF("37777777001", + "%1o", 4294966785U); + T_SPRINTF("1234abcd", + "%1x", 305441741); + T_SPRINTF("edcb5433", + "%1x", 3989525555U); + T_SPRINTF("1234ABCD", + "%1X", 305441741); + T_SPRINTF("EDCB5433", + "%1X", 3989525555U); + T_SPRINTF("x", + "%1c", 'x'); +} - test::sprintf(buffer, "% u", 4294966272U); - REQUIRE(!strcmp(buffer, "4294966272")); - test::sprintf(buffer, "% o", 511); - REQUIRE(!strcmp(buffer, "777")); +TEST_CASE("width 20", "[]" ) { + TEST_DEF; + + T_SPRINTF(" Hello", + "%20s", "Hello"); + T_SPRINTF(" 1024", + "%20d", 1024); + T_SPRINTF(" -1024", + "%20d", -1024); + T_SPRINTF(" 1024", + "%20i", 1024); + T_SPRINTF(" -1024", + "%20i", -1024); + T_SPRINTF(" 1024", + "%20u", 1024); + T_SPRINTF(" 4294966272", + "%20u", 4294966272U); + T_SPRINTF(" 777", + "%20o", 511); + T_SPRINTF(" 37777777001", + "%20o", 4294966785U); + T_SPRINTF(" 1234abcd", + "%20x", 305441741); + T_SPRINTF(" edcb5433", + "%20x", 3989525555U); + T_SPRINTF(" 1234ABCD", + "%20X", 305441741); + T_SPRINTF(" EDCB5433", + "%20X", 3989525555U); + T_SPRINTF(" x", + "%20c", 'x'); +} - test::sprintf(buffer, "% o", 4294966785U); - REQUIRE(!strcmp(buffer, "37777777001")); - test::sprintf(buffer, "% x", 305441741); - REQUIRE(!strcmp(buffer, "1234abcd")); +TEST_CASE("width *20", "[]" ) { + TEST_DEF; + + T_SPRINTF(" Hello", + "%*s", 20, "Hello"); + T_SPRINTF(" 1024", + "%*d", 20, 1024); + T_SPRINTF(" -1024", + "%*d", 20, -1024); + T_SPRINTF(" 1024", + "%*i", 20, 1024); + T_SPRINTF(" -1024", + "%*i", 20, -1024); + T_SPRINTF(" 1024", + "%*u", 20, 1024); + T_SPRINTF(" 4294966272", + "%*u", 20, 4294966272U); + T_SPRINTF(" 777", + "%*o", 20, 511); + T_SPRINTF(" 37777777001", + "%*o", 20, 4294966785U); + T_SPRINTF(" 1234abcd", + "%*x", 20, 305441741); + T_SPRINTF(" edcb5433", + "%*x", 20, 3989525555U); + T_SPRINTF(" 1234ABCD", + "%*X", 20, 305441741); + T_SPRINTF(" EDCB5433", + "%*X", 20, 3989525555U); + T_SPRINTF(" x", + "%*c", 20,'x'); +} - test::sprintf(buffer, "% x", 3989525555U); - REQUIRE(!strcmp(buffer, "edcb5433")); - test::sprintf(buffer, "% X", 305441741); - REQUIRE(!strcmp(buffer, "1234ABCD")); +TEST_CASE("width -20", "[]" ) { + TEST_DEF; + + T_SPRINTF("Hello ", + "%-20s", "Hello"); + T_SPRINTF("1024 ", + "%-20d", 1024); + T_SPRINTF("-1024 ", + "%-20d", -1024); + T_SPRINTF("1024 ", + "%-20i", 1024); + T_SPRINTF("-1024 ", + "%-20i", -1024); + T_SPRINTF("1024 ", + "%-20u", 1024); + T_SPRINTF("1024.1234 ", + "%-20.4f", 1024.1234); + T_SPRINTF("4294966272 ", + "%-20u", 4294966272U); + T_SPRINTF("777 ", + "%-20o", 511); + T_SPRINTF("37777777001 ", + "%-20o", 4294966785U); + T_SPRINTF("1234abcd ", + "%-20x", 305441741); + T_SPRINTF("edcb5433 ", + "%-20x", 3989525555U); + T_SPRINTF("1234ABCD ", + "%-20X", 305441741); + T_SPRINTF("EDCB5433 ", + "%-20X", 3989525555U); + T_SPRINTF("x ", + "%-20c", 'x'); + T_SPRINTF("| 9| |9 | | 9|", + "|%5d| |%-2d| |%5d|", 9, 9, 9); + T_SPRINTF("| 10| |10| | 10|", + "|%5d| |%-2d| |%5d|", 10, 10, 10); + T_SPRINTF("| 9| |9 | | 9|", + "|%5d| |%-12d| |%5d|", 9, 9, 9); + T_SPRINTF("| 10| |10 | | 10|", + "|%5d| |%-12d| |%5d|", 10, 10, 10); +} - test::sprintf(buffer, "% X", 3989525555U); - REQUIRE(!strcmp(buffer, "EDCB5433")); - test::sprintf(buffer, "% c", 'x'); - REQUIRE(!strcmp(buffer, "x")); +TEST_CASE("width 0-20", "[]" ) { + TEST_DEF; + + T_SPRINTF("Hello ", + "%0-20s", "Hello"); + T_SPRINTF("1024 ", + "%0-20d", 1024); + T_SPRINTF("-1024 ", + "%0-20d", -1024); + T_SPRINTF("1024 ", + "%0-20i", 1024); + T_SPRINTF("-1024 ", + "%0-20i", -1024); + T_SPRINTF("1024 ", + "%0-20u", 1024); + T_SPRINTF("4294966272 ", + "%0-20u", 4294966272U); + T_SPRINTF("777 ", + "%0-20o", 511); + T_SPRINTF("37777777001 ", + "%0-20o", 4294966785U); + T_SPRINTF("1234abcd ", + "%0-20x", 305441741); + T_SPRINTF("edcb5433 ", + "%0-20x", 3989525555U); + T_SPRINTF("1234ABCD ", + "%0-20X", 305441741); + T_SPRINTF("EDCB5433 ", + "%0-20X", 3989525555U); + T_SPRINTF("x ", + "%0-20c", 'x'); } -TEST_CASE("+ flag", "[]" ) { - char buffer[100]; - - test::sprintf(buffer, "%+d", 42); - REQUIRE(!strcmp(buffer, "+42")); +TEST_CASE("padding 20", "[]" ) { + TEST_DEF; + + T_SPRINTF("00000000000000001024", + "%020d", 1024); + T_SPRINTF("-0000000000000001024", + "%020d", -1024); + T_SPRINTF("00000000000000001024", + "%020i", 1024); + T_SPRINTF("-0000000000000001024", + "%020i", -1024); + T_SPRINTF("00000000000000001024", + "%020u", 1024); + T_SPRINTF("00000000004294966272", + "%020u", 4294966272U); + T_SPRINTF("00000000000000000777", + "%020o", 511); + T_SPRINTF("00000000037777777001", + "%020o", 4294966785U); + T_SPRINTF("0000000000001234abcd", + "%020x", 305441741); + T_SPRINTF("000000000000edcb5433", + "%020x", 3989525555U); + T_SPRINTF("0000000000001234ABCD", + "%020X", 305441741); + T_SPRINTF("000000000000EDCB5433", + "%020X", 3989525555U); +} - test::sprintf(buffer, "%+d", -42); - REQUIRE(!strcmp(buffer, "-42")); - test::sprintf(buffer, "%+5d", 42); - REQUIRE(!strcmp(buffer, " +42")); +TEST_CASE("padding .20", "[]" ) { + TEST_DEF; + + T_SPRINTF("00000000000000001024", + "%.20d", 1024); + T_SPRINTF("-00000000000000001024", + "%.20d", -1024); + T_SPRINTF("00000000000000001024", + "%.20i", 1024); + T_SPRINTF("-00000000000000001024", + "%.20i", -1024); + T_SPRINTF("00000000000000001024", + "%.20u", 1024); + T_SPRINTF("00000000004294966272", + "%.20u", 4294966272U); + T_SPRINTF("00000000000000000777", + "%.20o", 511); + T_SPRINTF("00000000037777777001", + "%.20o", 4294966785U); + T_SPRINTF("0000000000001234abcd", + "%.20x", 305441741); + T_SPRINTF("000000000000edcb5433", + "%.20x", 3989525555U); + T_SPRINTF("0000000000001234ABCD", + "%.20X", 305441741); + T_SPRINTF("000000000000EDCB5433", + "%.20X", 3989525555U); +} - test::sprintf(buffer, "%+5d", -42); - REQUIRE(!strcmp(buffer, " -42")); - test::sprintf(buffer, "%+15d", 42); - REQUIRE(!strcmp(buffer, " +42")); +TEST_CASE("padding #020", "[]" ) { + TEST_DEF; + + T_SPRINTF("00000000000000001024", + "%#020d", 1024); + T_SPRINTF("-0000000000000001024", + "%#020d", -1024); + T_SPRINTF("00000000000000001024", + "%#020i", 1024); + T_SPRINTF("-0000000000000001024", + "%#020i", -1024); + T_SPRINTF("00000000000000001024", + "%#020u", 1024); + T_SPRINTF("00000000004294966272", + "%#020u", 4294966272U); + T_SPRINTF("00000000000000000777", + "%#020o", 511); + T_SPRINTF("00000000037777777001", + "%#020o", 4294966785U); + T_SPRINTF("0x00000000001234abcd", + "%#020x", 305441741); + T_SPRINTF("0x0000000000edcb5433", + "%#020x", 3989525555U); + T_SPRINTF("0X00000000001234ABCD", + "%#020X", 305441741); + T_SPRINTF("0X0000000000EDCB5433", + "%#020X", 3989525555U); +} - test::sprintf(buffer, "%+15d", -42); - REQUIRE(!strcmp(buffer, " -42")); - test::sprintf(buffer, "%+s", "Hello testing"); - REQUIRE(!strcmp(buffer, "Hello testing")); +TEST_CASE("padding #20", "[]" ) { + TEST_DEF; + + T_SPRINTF(" 1024", + "%#20d", 1024); + T_SPRINTF(" -1024", + "%#20d", -1024); + T_SPRINTF(" 1024", + "%#20i", 1024); + T_SPRINTF(" -1024", + "%#20i", -1024); + T_SPRINTF(" 1024", + "%#20u", 1024); + T_SPRINTF(" 4294966272", + "%#20u", 4294966272U); + T_SPRINTF(" 0777", + "%#20o", 511); + T_SPRINTF(" 037777777001", + "%#20o", 4294966785U); + T_SPRINTF(" 0x1234abcd", + "%#20x", 305441741); + T_SPRINTF(" 0xedcb5433", + "%#20x", 3989525555U); + T_SPRINTF(" 0X1234ABCD", + "%#20X", 305441741); + T_SPRINTF(" 0XEDCB5433", + "%#20X", 3989525555U); +} - test::sprintf(buffer, "%+d", 1024); - REQUIRE(!strcmp(buffer, "+1024")); - test::sprintf(buffer, "%+d", -1024); - REQUIRE(!strcmp(buffer, "-1024")); +TEST_CASE("padding 20.5", "[]" ) { + TEST_DEF; + + T_SPRINTF(" 01024", + "%20.5d", 1024); + T_SPRINTF(" -01024", + "%20.5d", -1024); + T_SPRINTF(" 01024", + "%20.5i", 1024); + T_SPRINTF(" -01024", + "%20.5i", -1024); + T_SPRINTF(" 01024", + "%20.5u", 1024); + T_SPRINTF(" 4294966272", + "%20.5u", 4294966272U); + T_SPRINTF(" 00777", + "%20.5o", 511); + T_SPRINTF(" 37777777001", + "%20.5o", 4294966785U); + T_SPRINTF(" 1234abcd", + "%20.5x", 305441741); + T_SPRINTF(" 00edcb5433", + "%20.10x", 3989525555U); + T_SPRINTF(" 1234ABCD", + "%20.5X", 305441741); + T_SPRINTF(" 00EDCB5433", + "%20.10X", 3989525555U); +} - test::sprintf(buffer, "%+i", 1024); - REQUIRE(!strcmp(buffer, "+1024")); +TEST_CASE("padding -20.5", "[]" ) { + TEST_DEF; +#if ENABLE_FAILING + T_SPRINTF("01024 ", + "%-20.5d", 1024); + T_SPRINTF("-01024 ", + "%-20.5d", -1024); +#endif +} - test::sprintf(buffer, "%+i", -1024); - REQUIRE(!strcmp(buffer, "-1024")); +TEST_CASE("padding neg numbers", "[]" ) { + TEST_DEF; - test::sprintf(buffer, "%+u", 1024); - REQUIRE(!strcmp(buffer, "1024")); + // space padding + T_SPRINTF("-5", + "% 1d", -5); + T_SPRINTF("-5", + "% 2d", -5); + T_SPRINTF(" -5", + "% 3d", -5); + T_SPRINTF(" -5", + "% 4d", -5); + // zero padding + T_SPRINTF("-5", + "%01d", -5); + T_SPRINTF("-5", + "%02d", -5); + T_SPRINTF("-05", + "%03d", -5); + T_SPRINTF("-005", + "%04d", -5); +} - test::sprintf(buffer, "%+u", 4294966272U); - REQUIRE(!strcmp(buffer, "4294966272")); - test::sprintf(buffer, "%+o", 511); - REQUIRE(!strcmp(buffer, "777")); +TEST_CASE("float padding neg numbers", "[]" ) { + TEST_DEF; - test::sprintf(buffer, "%+o", 4294966785U); - REQUIRE(!strcmp(buffer, "37777777001")); + // space padding + T_SPRINTF("-5.0", + "% 3.1f", -5.); + T_SPRINTF("-5.0", + "% 4.1f", -5.); + T_SPRINTF(" -5.0", + "% 5.1f", -5.); +#ifndef PRINTF_DISABLE_SUPPORT_EXPONENTIAL + T_SPRINTF(" -5", + "% 6.1g", -5.); + T_SPRINTF("-5.0e+00", + "% 6.1e", -5.); + T_SPRINTF(" -5.0e+00", + "% 10.1e", -5.); +#endif - test::sprintf(buffer, "%+x", 305441741); - REQUIRE(!strcmp(buffer, "1234abcd")); + // zero padding + T_SPRINTF("-5.0", + "%03.1f", -5.); + T_SPRINTF("-5.0", + "%04.1f", -5.); + T_SPRINTF("-05.0", + "%05.1f", -5.); + // zero padding no decimal point + T_SPRINTF("-5", + "%01.0f", -5.); + T_SPRINTF("-5", + "%02.0f", -5.); + T_SPRINTF("-05", + "%03.0f", -5.); +#ifndef PRINTF_DISABLE_SUPPORT_EXPONENTIAL + T_SPRINTF("-005.0e+00", + "%010.1e", -5.); + T_SPRINTF("-05E+00", + "%07.0E", -5.); + T_SPRINTF("-05", + "%03.0g", -5.); +#endif +} - test::sprintf(buffer, "%+x", 3989525555U); - REQUIRE(!strcmp(buffer, "edcb5433")); +TEST_CASE("length", "[]" ) { + TEST_DEF; + + T_SPRINTF("", + "%.0s", "Hello testing"); + T_SPRINTF(" ", + "%20.0s", "Hello testing"); + T_SPRINTF("", + "%.s", "Hello testing"); + T_SPRINTF(" ", + "%20.s", "Hello testing"); + T_SPRINTF(" 1024", + "%20.0d", 1024); + T_SPRINTF(" -1024", + "%20.0d", -1024); + T_SPRINTF(" ", + "%20.d", 0); + T_SPRINTF(" 1024", + "%20.0i", 1024); + T_SPRINTF(" -1024", + "%20.i", -1024); + T_SPRINTF(" ", + "%20.i", 0); + T_SPRINTF(" 1024", + "%20.u", 1024); + T_SPRINTF(" 4294966272", + "%20.0u", 4294966272U); + T_SPRINTF(" ", + "%20.u", 0U); + T_SPRINTF(" 777", + "%20.o", 511); + T_SPRINTF(" 37777777001", + "%20.0o", 4294966785U); + T_SPRINTF(" ", + "%20.o", 0U); + T_SPRINTF(" 1234abcd", + "%20.x", 305441741); + T_SPRINTF(" 1234abcd", + "%50.x", 305441741); + T_SPRINTF(" 1234abcd 12345", + "%50.x%10.u", 305441741, 12345); + T_SPRINTF(" edcb5433", + "%20.0x", 3989525555U); + T_SPRINTF(" ", + "%20.x", 0U); + T_SPRINTF(" 1234ABCD", + "%20.X", 305441741); + T_SPRINTF(" EDCB5433", + "%20.0X", 3989525555U); + T_SPRINTF(" ", + "%20.X", 0U); + T_SPRINTF(" ", + "%02.0u", 0U); + T_SPRINTF(" ", + "%02.0d", 0); +} - test::sprintf(buffer, "%+X", 305441741); - REQUIRE(!strcmp(buffer, "1234ABCD")); - test::sprintf(buffer, "%+X", 3989525555U); - REQUIRE(!strcmp(buffer, "EDCB5433")); +TEST_CASE("float", "[]" ) { + TEST_DEF; - test::sprintf(buffer, "%+c", 'x'); - REQUIRE(!strcmp(buffer, "x")); + // test special-case floats using math.h macros + T_SPRINTF(" nan", + "%8f", NAN); + T_SPRINTF(" inf", + "%8f", (double)INFINITY); + T_SPRINTF("-inf ", + "%-8f", (double)-INFINITY); +#ifndef PRINTF_DISABLE_SUPPORT_EXPONENTIAL + T_SPRINTF(" +inf", + "%+8e", (double)INFINITY); +#endif - test::sprintf(buffer, "%+.0d", 0); - REQUIRE(!strcmp(buffer, "+")); -} + T_SPRINTF("3.1415", + "%.4f", 3.1415354); + T_SPRINTF("30343.142", + "%.3f", 30343.1415354); + T_SPRINTF("34", + "%.0f", 34.1415354); + T_SPRINTF("1", + "%.0f", 1.3); + T_SPRINTF("2", + "%.0f", 1.55); + T_SPRINTF("1.6", + "%.1f", 1.64); + T_SPRINTF("42.90", + "%.2f", 42.8952); + T_SPRINTF("42.895200000", + "%.9f", 42.8952); + T_SPRINTF("42.8952230000", + "%.10f", 42.895223); + // this testcase checks, that the precision is truncated to 9 digits. + // a perfect working float should return the whole number + T_SPRINTF("42.895223123000", + "%.12f", 42.89522312345678); + // this testcase checks, that the precision is truncated AND rounded to 9 digits. + // a perfect working float should return the whole number + T_SPRINTF("42.895223877000", + "%.12f", 42.89522387654321); + T_SPRINTF(" 42.90", + "%6.2f", 42.8952); + T_SPRINTF("+42.90", + "%+6.2f", 42.8952); + T_SPRINTF("+42.9", + "%+5.1f", 42.9252); + T_SPRINTF("42.500000", + "%f", 42.5); + T_SPRINTF("42.5", + "%.1f", 42.5); + T_SPRINTF("42167.000000", + "%f", 42167.0); + T_SPRINTF("-12345.987654321", + "%.9f", -12345.987654321); + T_SPRINTF("4.0", + "%.1f", 3.999); + T_SPRINTF("4", + "%.0f", 3.5); + T_SPRINTF("4", + "%.0f", 4.5); + T_SPRINTF("3", + "%.0f", 3.49); + T_SPRINTF("3.5", + "%.1f", 3.49); + T_SPRINTF("a0.5 ", + "a%-5.1f", 0.5); + T_SPRINTF("a0.5 end", + "a%-5.1fend", 0.5); +#ifndef PRINTF_DISABLE_SUPPORT_EXPONENTIAL + T_SPRINTF("12345.7", + "%G", 12345.678); + T_SPRINTF("12345.68", + "%.7G", 12345.678); + T_SPRINTF("1.2346E+08", + "%.5G", 123456789.); + T_SPRINTF("12345.0", + "%.6G", 12345.); + T_SPRINTF(" +1.235e+08", + "%+12.4g", 123456789.); + T_SPRINTF("0.0012", + "%.2G", 0.001234); + T_SPRINTF(" +0.001234", + "%+10.4G", 0.001234); + T_SPRINTF("+001.234e-05", + "%+012.4g", 0.00001234); + T_SPRINTF("-1.23e-308", + "%.3g", -1.2345e-308); + T_SPRINTF("+1.230E+308", + "%+.3E", 1.23e+308); +#endif + // out of range for float: should switch to exp notation if supported, else empty +#ifndef PRINTF_DISABLE_SUPPORT_EXPONENTIAL + T_SPRINTF("1.0e+20", + "%.1f", 1E20); +#else + T_SPRINTF("", + "%.1f", 1E20); +#endif -TEST_CASE("0 flag", "[]" ) { - char buffer[100]; + // brute force float + do { + bool fail = false; + std::stringstream str; + str.precision(5); + for (float i = -100000; i < 100000; i += 1) { + tested_sprintf(buffer, "%.5f", (double)i / 10000); + str.str(""); + str << std::fixed << i / 10000; + fail = fail || !!strcmp(buffer, str.str().c_str()); + } + REQUIRE(!fail); + } while (0); - test::sprintf(buffer, "%0d", 42); - REQUIRE(!strcmp(buffer, "42")); +#ifndef PRINTF_DISABLE_SUPPORT_EXPONENTIAL + do { + bool fail = false; + std::stringstream str; + // brute force exp + str.precision(5); + str.setf(std::ios::scientific, std::ios::floatfield); + for (float i = -1e20; i < 1e20f; i += 1e15f) { + tested_sprintf(buffer, "%.5f", (double)i); + str.str(""); + str << i; + fail = fail || !!strcmp(buffer, str.str().c_str()); + } + REQUIRE(!fail); + } while (0); +#endif +} - test::sprintf(buffer, "%0ld", 42L); - REQUIRE(!strcmp(buffer, "42")); +TEST_CASE("float rounding", "[]") { + TEST_DEF; - test::sprintf(buffer, "%0d", -42); - REQUIRE(!strcmp(buffer, "-42")); +#if ENABLE_FAILING + // improper handling of round when decimals is affected + T_SPRINTF("1.0", + "%.1f", 0.95); +#endif +#if ENABLE_FAILING + // rounding is not working correctly + // brute-force float rounding + do { + bool fail = false; + std::stringstream str; + str.precision(5); + for (double i = -100000.5; !fail && i < 100000; i += 1) { + tested_sprintf(buffer, "%.5f", (double)i / 100000); + str.str(""); + str << std::fixed << i / 100000; + if ((fail = strcmp(buffer, str.str().c_str()))) { + // repeat the failing case to catch2 it + T_SPRINTF(str.str(), + "%.5f", i / 100000); + } + } + // count it as test case + REQUIRE(!fail); + } while (0); +#endif +} - test::sprintf(buffer, "%05d", 42); - REQUIRE(!strcmp(buffer, "00042")); +TEST_CASE("types", "[]" ) { + TEST_DEF; + + T_SPRINTF("0", + "%i", 0); + T_SPRINTF("1234", + "%i", 1234); + T_SPRINTF("32767", + "%i", 32767); + T_SPRINTF("-32767", + "%i", -32767); + T_SPRINTF("30", + "%li", 30L); + T_SPRINTF("-2147483647", + "%li", -2147483647L); + T_SPRINTF("2147483647", + "%li", 2147483647L); + T_SPRINTF("30", + "%lli", 30LL); + T_SPRINTF("-9223372036854775807", + "%lli", -9223372036854775807LL); + T_SPRINTF("9223372036854775807", + "%lli", 9223372036854775807LL); + T_SPRINTF("100000", + "%lu", 100000L); + T_SPRINTF("4294967295", + "%lu", 0xFFFFFFFFL); + T_SPRINTF("281474976710656", + "%llu", 281474976710656LLU); + T_SPRINTF("18446744073709551615", + "%llu", 18446744073709551615LLU); + T_SPRINTF("2147483647", + "%zu", 2147483647UL); + T_SPRINTF("2147483647", + "%zd", 2147483647UL); + if (sizeof(size_t) == sizeof(long)) { + T_SPRINTF("-2147483647", + "%zi", -2147483647L); + } + else { + T_SPRINTF("-2147483647", + "%zi", -2147483647LL); + } - test::sprintf(buffer, "%05d", -42); - REQUIRE(!strcmp(buffer, "-0042")); + T_SPRINTF("1110101001100000", + "%b", 60000); + T_SPRINTF("101111000110000101001110", + "%lb", 12345678L); + T_SPRINTF("165140", + "%o", 60000); + T_SPRINTF("57060516", + "%lo", 12345678L); + T_SPRINTF("12345678", + "%lx", 0x12345678L); + T_SPRINTF("1234567891234567", + "%llx", 0x1234567891234567LLU); + T_SPRINTF("abcdefab", + "%lx", 0xabcdefabL); + T_SPRINTF("ABCDEFAB", + "%lX", 0xabcdefabL); + T_SPRINTF("v", + "%c", 'v'); + T_SPRINTF("wv", + "%cv", 'w'); + T_SPRINTF("A Test", + "%s", "A Test"); + T_SPRINTF("255", + "%hhu", 0xFFFFUL); + T_SPRINTF("13398", + "%hu", 0x123456UL); + T_SPRINTF("Test16 65535", + "%s%hhi %hu", "Test", 10000, 0xFFFFFFFF); + T_SPRINTF("a", + "%tx", &buffer[10] - &buffer[0]); +// TBD + if (sizeof(intmax_t) == sizeof(long)) { + T_SPRINTF("-2147483647", + "%ji", -2147483647L); + } + else { + T_SPRINTF("-2147483647", + "%ji", -2147483647LL); + } +} - test::sprintf(buffer, "%015d", 42); - REQUIRE(!strcmp(buffer, "000000000000042")); - test::sprintf(buffer, "%015d", -42); - REQUIRE(!strcmp(buffer, "-00000000000042")); +TEST_CASE("pointer", "[]" ) { + TEST_DEF; - test::sprintf(buffer, "%015.2f", 42.1234); - REQUIRE(!strcmp(buffer, "000000000042.12")); + if (sizeof(void*) == 4U) { + T_SPRINTF("00001234", + "%p", (void*)0x1234U); + } + else { + T_SPRINTF("0000000000001234", + "%p", (void*)0x1234U); + } - test::sprintf(buffer, "%015.3f", 42.9876); - REQUIRE(!strcmp(buffer, "00000000042.988")); + if (sizeof(void*) == 4U) { + T_SPRINTF("12345678", + "%p", (void*)0x12345678U); + } + else { + T_SPRINTF("0000000012345678", + "%p", (void*)0x12345678U); + } - test::sprintf(buffer, "%015.5f", -42.9876); - REQUIRE(!strcmp(buffer, "-00000042.98760")); + if (sizeof(void*) == 4U) { + T_SPRINTF("12345678-7EDCBA98", + "%p-%p", (void*)0x12345678U, (void*)0x7EDCBA98U); + } + else { + T_SPRINTF("0000000012345678-000000007EDCBA98", + "%p-%p", (void*)0x12345678U, (void*)0x7EDCBA98U); + } + if (sizeof(uintptr_t) == sizeof(uint64_t)) { + T_SPRINTF("00000000FFFFFFFF", + "%p", (void*)(uintptr_t)0xFFFFFFFFU); + } + else { + T_SPRINTF("FFFFFFFF", + "%p", (void*)(uintptr_t)0xFFFFFFFFU); + } } -TEST_CASE("- flag", "[]" ) { - char buffer[100]; - - test::sprintf(buffer, "%-d", 42); - REQUIRE(!strcmp(buffer, "42")); - - test::sprintf(buffer, "%-d", -42); - REQUIRE(!strcmp(buffer, "-42")); +TEST_CASE("unknown flag", "[]" ) { + TEST_DEF; - test::sprintf(buffer, "%-5d", 42); - REQUIRE(!strcmp(buffer, "42 ")); + T_SPRINTF("kmarco", + "%kmarco", 42, 37); +} - test::sprintf(buffer, "%-5d", -42); - REQUIRE(!strcmp(buffer, "-42 ")); - test::sprintf(buffer, "%-15d", 42); - REQUIRE(!strcmp(buffer, "42 ")); +TEST_CASE("string length", "[]" ) { + TEST_DEF; + + T_SPRINTF("This", + "%.4s", "This is a test"); + T_SPRINTF("test", + "%.4s", "test"); + T_SPRINTF("123", + "%.7s", "123"); + T_SPRINTF("", + "%.7s", ""); + T_SPRINTF("1234ab", + "%.4s%.2s", "123456", "abcdef"); + T_SPRINTF(".2s", + "%.4.2s", "123456"); + T_SPRINTF("123", + "%.*s", 3, "123456"); +} - test::sprintf(buffer, "%-15d", -42); - REQUIRE(!strcmp(buffer, "-42 ")); - test::sprintf(buffer, "%-0d", 42); - REQUIRE(!strcmp(buffer, "42")); +TEST_CASE("buffer length", "[]" ) { + TEST_DEF; - test::sprintf(buffer, "%-0d", -42); - REQUIRE(!strcmp(buffer, "-42")); + ret = tested_snprintf(nullptr, 10, "%s", "Test"); + REQUIRE(ret == 4); + ret = tested_snprintf(nullptr, 0, "%s", "Test"); + REQUIRE(ret == 4); - test::sprintf(buffer, "%-05d", 42); - REQUIRE(!strcmp(buffer, "42 ")); + buffer[0] = (char)0xA5; + ret = tested_snprintf(buffer, 0, "%s", "Test"); + REQUIRE(buffer[0] == (char)0xA5); + REQUIRE(ret == 4); - test::sprintf(buffer, "%-05d", -42); - REQUIRE(!strcmp(buffer, "-42 ")); + buffer[0] = (char)0xCC; + tested_snprintf(buffer, 1, "%s", "Test"); + REQUIRE(buffer[0] == '\0'); - test::sprintf(buffer, "%-015d", 42); - REQUIRE(!strcmp(buffer, "42 ")); + T_SNPRINTF("H", 5, + 2, "%s", "Hello"); +} - test::sprintf(buffer, "%-015d", -42); - REQUIRE(!strcmp(buffer, "-42 ")); - test::sprintf(buffer, "%0-d", 42); - REQUIRE(!strcmp(buffer, "42")); +TEST_CASE("ret value", "[]" ) { + TEST_DEF; - test::sprintf(buffer, "%0-d", -42); - REQUIRE(!strcmp(buffer, "-42")); + T_SNPRINTF("01234", 5, + 6, "0%s", "1234"); - test::sprintf(buffer, "%0-5d", 42); - REQUIRE(!strcmp(buffer, "42 ")); + T_SNPRINTF("01234", 6, // '5' is truncated + 6, "0%s", "12345"); - test::sprintf(buffer, "%0-5d", -42); - REQUIRE(!strcmp(buffer, "-42 ")); + T_SNPRINTF("01234", 8, // '567' are truncated + 6, "0%s", "1234567"); - test::sprintf(buffer, "%0-15d", 42); - REQUIRE(!strcmp(buffer, "42 ")); + T_SNPRINTF(NULL, 12, + 10, "hello, world"); - test::sprintf(buffer, "%0-15d", -42); - REQUIRE(!strcmp(buffer, "-42 ")); + T_SNPRINTF("10", 5, + 3, "%d", 10000); +} - test::sprintf(buffer, "%0-15.3e", -42.); -#ifndef PRINTF_DISABLE_SUPPORT_EXPONENTIAL - REQUIRE(!strcmp(buffer, "-4.200e+01 ")); -#else - REQUIRE(!strcmp(buffer, "e")); -#endif - test::sprintf(buffer, "%0-15.3g", -42.); +TEST_CASE("misc", "[]" ) { + TEST_DEF; + + T_SPRINTF("53000atest-20 bit", + "%u%u%ctest%d %s", 5, 3000, 'a', -20, "bit"); + T_SPRINTF("0.33", + "%.*f", 2, 0.33333333); + T_SPRINTF("1", + "%.*d", -1, 1); + T_SPRINTF("foo", + "%.3s", "foobar"); + T_SPRINTF(" ", + "% .0d", 0); + T_SPRINTF(" 00004", + "%10.5d", 4); + T_SPRINTF("hi x", + "%*sx", -3, "hi"); #ifndef PRINTF_DISABLE_SUPPORT_EXPONENTIAL - REQUIRE(!strcmp(buffer, "-42.0 ")); -#else - REQUIRE(!strcmp(buffer, "g")); + T_SPRINTF("0.33", + "%.*g", 2, 0.33333333); + T_SPRINTF("3.33e-01", + "%.*e", 2, 0.33333333); #endif } -TEST_CASE("# flag", "[]" ) { - char buffer[100]; +// libinsanity printf tests +// from https://github.com/wm4/libinsanity/blob/master/tests/printf_test.c +// 4363908964d0d890fedf47b8d130bb10f800ef14 - test::sprintf(buffer, "%#.0x", 0); - REQUIRE(!strcmp(buffer, "")); - test::sprintf(buffer, "%#.1x", 0); - REQUIRE(!strcmp(buffer, "0")); - test::sprintf(buffer, "%#.0llx", (long long)0); - REQUIRE(!strcmp(buffer, "")); - test::sprintf(buffer, "%#.8x", 0x614e); - REQUIRE(!strcmp(buffer, "0x0000614e")); - test::sprintf(buffer,"%#b", 6); - REQUIRE(!strcmp(buffer, "0b110")); +/////////////////////////////////////////////////////////////////////////////// +// (c) Marco Paland (info@paland.com) +// 2017-2018, PALANDesign Hannover, Germany +// +// The MIT License (MIT) +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS INx +// THE SOFTWARE. +// +// Additional tests from libc-testsuite (musl) +// a9baddd7d07b9fe15e212985a808a79773ec72e4 + + +#define REQUIRE_STR_EQ(got, expect) REQUIRE_THAT(got, Equals(expect)) +#define REQUIRE_INT_EQ(got, expect) REQUIRE((got) == (expect)) + +// Some tests use redundant format specifier flags (against which gcc warns, +// and which OS libc will usually not support). +#define TEST_NON_STANDARD 1 + +// Tests redundant flags, against which gcc warns. It's possible that testing +// this would be worth anyway, because the standard does not forbid passing +// them. Normally they just cause noise with -Wformat (which you should always +// enable). +#define TEST_REDUNDANT_FLAGS 1 + +// Implementation defined formatting (%p in particular). +#define TEST_IMPL_DEFINED 1 +// explicit argument size specifiers ("%I64d" etc) +#define TEST_IMPL_EXPLICITSIZE 0 + +#define EXP(...) __VA_ARGS__ + +// Require that printf(args) outputs res. +#define TEST_SNPRINTF(args, expected) \ + do { \ + CAPTURE(EXP args); \ + ret = tested_sprintf(buffer, EXP args); \ + CHECK_THAT(buffer, Equals(expected)); \ + (void)ret; \ + } while (0) \ + /**/ + +// Require that snprintf(..., 0, args) returns res. +#define TEST_SNPRINTF_N(args, res) \ + do { \ + CAPTURE(EXP args); \ + ret = tested_sprintf(buffer, EXP args); \ + CHECK(ret == res); \ + (void)ret; \ + } while (0) \ + /**/ + +TEST_CASE("lin:basic sanity", "[libinsanity]" ) { + TEST_DEF; + TEST_SNPRINTF(("%d", -1000), "-1000"); + tested_snprintf(buffer, 3U, "%d", -1000); + REQUIRE_STR_EQ(buffer, "-1"); + TEST_SNPRINTF(("%d", -1), "-1"); + + tested_snprintf(buffer, sizeof(buffer), "%d %d %s", 3, -1000, "test"); + REQUIRE_STR_EQ(buffer, "3 -1000 test"); } +TEST_CASE("lin:space+width", "[libinsanity]" ) { + TEST_DEF; + + TEST_SNPRINTF(("% d", 42), " 42"); + TEST_SNPRINTF(("% d", -42), "-42"); + TEST_SNPRINTF(("% 5d", 42), " 42"); + TEST_SNPRINTF(("% 5d", -42), " -42"); + TEST_SNPRINTF(("% 15d", 42), " 42"); + TEST_SNPRINTF(("% 15d", -42), " -42"); + TEST_SNPRINTF(("% 15d", -42), " -42"); + TEST_SNPRINTF(("% 15.3f", -42.987), " -42.987"); + TEST_SNPRINTF(("% 15.3f", 42.987), " 42.987"); +#if TEST_REDUNDANT_FLAGS + TEST_SNPRINTF(("% s", "Hello testing"), "Hello testing"); +#endif +} -TEST_CASE("specifier", "[]" ) { - char buffer[100]; +TEST_CASE("lin:space", "[libinsanity]" ) { + TEST_DEF; + + TEST_SNPRINTF(("% d", 1024), " 1024"); + TEST_SNPRINTF(("% d", -1024), "-1024"); + TEST_SNPRINTF(("% i", 1024), " 1024"); + TEST_SNPRINTF(("% i", -1024), "-1024"); +#if TEST_REDUNDANT_FLAGS + TEST_SNPRINTF(("% u", 1024), "1024"); + TEST_SNPRINTF(("% u", 4294966272U), "4294966272"); + TEST_SNPRINTF(("% o", 511), "777"); + TEST_SNPRINTF(("% o", 4294966785U), "37777777001"); + TEST_SNPRINTF(("% x", 305441741), "1234abcd"); + TEST_SNPRINTF(("% x", 3989525555U), "edcb5433"); + TEST_SNPRINTF(("% X", 305441741), "1234ABCD"); + TEST_SNPRINTF(("% X", 3989525555U), "EDCB5433"); + TEST_SNPRINTF(("% c", 'x'), "x"); +#endif +} - test::sprintf(buffer, "Hello testing"); - REQUIRE(!strcmp(buffer, "Hello testing")); +TEST_CASE("lin:plus", "[libinsanity]" ) { + TEST_DEF; + + TEST_SNPRINTF(("%+d", 42), "+42"); + TEST_SNPRINTF(("%+d", -42), "-42"); + TEST_SNPRINTF(("%+5d", 42), " +42"); + TEST_SNPRINTF(("%+5d", -42), " -42"); + TEST_SNPRINTF(("%+15d", 42), " +42"); + TEST_SNPRINTF(("%+15d", -42), " -42"); +#if TEST_REDUNDANT_FLAGS + TEST_SNPRINTF(("%+s", "Hello testing"), "Hello testing"); +#endif - test::sprintf(buffer, "%s", "Hello testing"); - REQUIRE(!strcmp(buffer, "Hello testing")); + TEST_SNPRINTF(("%+d", 1024), "+1024"); + TEST_SNPRINTF(("%+d", -1024), "-1024"); + TEST_SNPRINTF(("%+i", 1024), "+1024"); + TEST_SNPRINTF(("%+i", -1024), "-1024"); +#if TEST_REDUNDANT_FLAGS + TEST_SNPRINTF(("%+u", 1024), "1024"); + TEST_SNPRINTF(("%+u", 4294966272U), "4294966272"); + TEST_SNPRINTF(("%+o", 511), "777"); + TEST_SNPRINTF(("%+o", 4294966785U), "37777777001"); + TEST_SNPRINTF(("%+x", 305441741), "1234abcd"); + TEST_SNPRINTF(("%+x", 3989525555U), "edcb5433"); + TEST_SNPRINTF(("%+X", 305441741), "1234ABCD"); + TEST_SNPRINTF(("%+X", 3989525555U), "EDCB5433"); + TEST_SNPRINTF(("%+c", 'x'), "x"); +#endif +} - test::sprintf(buffer, "%d", 1024); - REQUIRE(!strcmp(buffer, "1024")); +TEST_CASE("lin:zero", "[libinsanity]" ) { + TEST_DEF; + TEST_SNPRINTF(("%0d", 42), "42"); + TEST_SNPRINTF(("%0ld", 42L), "42"); + TEST_SNPRINTF(("%0d", -42), "-42"); + TEST_SNPRINTF(("%05d", 42), "00042"); + TEST_SNPRINTF(("%05d", -42), "-0042"); + TEST_SNPRINTF(("%015d", 42), "000000000000042"); + TEST_SNPRINTF(("%015d", -42), "-00000000000042"); + TEST_SNPRINTF(("%015.2f", 42.1234), "000000000042.12"); + TEST_SNPRINTF(("%015.3f", 42.9876), "00000000042.988"); + TEST_SNPRINTF(("%015.5f", -42.9876), "-00000042.98760"); +} - test::sprintf(buffer, "%d", -1024); - REQUIRE(!strcmp(buffer, "-1024")); +TEST_CASE("lin:minus", "[libinsanity]" ) { + TEST_DEF; + + TEST_SNPRINTF(("%-d", 42), "42"); + TEST_SNPRINTF(("%-d", -42), "-42"); + TEST_SNPRINTF(("%-5d", 42), "42 "); + TEST_SNPRINTF(("%-5d", -42), "-42 "); + TEST_SNPRINTF(("%-15d", 42), "42 "); + TEST_SNPRINTF(("%-15d", -42), "-42 "); +#if TEST_REDUNDANT_FLAGS + TEST_SNPRINTF(("%-0d", 42), "42"); + TEST_SNPRINTF(("%-0d", -42), "-42"); + TEST_SNPRINTF(("%-05d", 42), "42 "); + TEST_SNPRINTF(("%-05d", -42), "-42 "); + TEST_SNPRINTF(("%-015d", 42), "42 "); + TEST_SNPRINTF(("%-015d", -42), "-42 "); + TEST_SNPRINTF(("%0-d", 42), "42"); + TEST_SNPRINTF(("%0-d", -42), "-42"); + TEST_SNPRINTF(("%0-5d", 42), "42 "); + TEST_SNPRINTF(("%0-5d", -42), "-42 "); + TEST_SNPRINTF(("%0-15d", 42), "42 "); + TEST_SNPRINTF(("%0-15d", -42), "-42 "); +#endif +} - test::sprintf(buffer, "%i", 1024); - REQUIRE(!strcmp(buffer, "1024")); +TEST_CASE("lin:basic specifiers", "[libinsanity]" ) { + TEST_DEF; + + tested_snprintf(buffer, sizeof(buffer), "Hello testing"); + REQUIRE_STR_EQ(buffer, "Hello testing"); + + TEST_SNPRINTF(("%s", "Hello testing"), "Hello testing"); + TEST_SNPRINTF(("%d", 1024), "1024"); + TEST_SNPRINTF(("%d", -1024), "-1024"); + TEST_SNPRINTF(("%i", 1024), "1024"); + TEST_SNPRINTF(("%i", -1024), "-1024"); + TEST_SNPRINTF(("%u", 1024), "1024"); + TEST_SNPRINTF(("%u", 4294966272U), "4294966272"); + TEST_SNPRINTF(("%o", 511), "777"); + TEST_SNPRINTF(("%o", 4294966785U), "37777777001"); + TEST_SNPRINTF(("%x", 305441741), "1234abcd"); + TEST_SNPRINTF(("%x", 3989525555U), "edcb5433"); + TEST_SNPRINTF(("%X", 305441741), "1234ABCD"); + TEST_SNPRINTF(("%X", 3989525555U), "EDCB5433"); + TEST_SNPRINTF(("%%"), "%"); +} - test::sprintf(buffer, "%i", -1024); - REQUIRE(!strcmp(buffer, "-1024")); +TEST_CASE("lin:width", "[libinsanity]" ) { + TEST_DEF; + TEST_SNPRINTF(("%ls", "Hello testing"), "Hello testing"); + TEST_SNPRINTF(("%1d", 1024), "1024"); + TEST_SNPRINTF(("%1d", -1024), "-1024"); + TEST_SNPRINTF(("%1i", 1024), "1024"); + TEST_SNPRINTF(("%1i", -1024), "-1024"); + TEST_SNPRINTF(("%1u", 1024), "1024"); + TEST_SNPRINTF(("%1u", 4294966272U), "4294966272"); + TEST_SNPRINTF(("%1o", 511), "777"); + TEST_SNPRINTF(("%1o", 4294966785U), "37777777001"); + TEST_SNPRINTF(("%1x", 305441741), "1234abcd"); + TEST_SNPRINTF(("%1x", 3989525555U), "edcb5433"); + TEST_SNPRINTF(("%1X", 305441741), "1234ABCD"); + TEST_SNPRINTF(("%1X", 3989525555U), "EDCB5433"); + TEST_SNPRINTF(("%1c", 'x'), "x"); + TEST_SNPRINTF(("%20s", "Hello"), " Hello"); + TEST_SNPRINTF(("%20d", 1024), " 1024"); + TEST_SNPRINTF(("%20d", -1024), " -1024"); + TEST_SNPRINTF(("%20i", 1024), " 1024"); + TEST_SNPRINTF(("%20i", -1024), " -1024"); + TEST_SNPRINTF(("%20u", 1024), " 1024"); + TEST_SNPRINTF(("%20u", 4294966272U), " 4294966272"); + TEST_SNPRINTF(("%20o", 511), " 777"); + TEST_SNPRINTF(("%20o", 4294966785U), " 37777777001"); + TEST_SNPRINTF(("%20x", 305441741), " 1234abcd"); + TEST_SNPRINTF(("%20x", 3989525555U), " edcb5433"); + TEST_SNPRINTF(("%20X", 305441741), " 1234ABCD"); + TEST_SNPRINTF(("%20X", 3989525555U), " EDCB5433"); + TEST_SNPRINTF(("%20c", 'x'), " x"); +} +TEST_CASE("lin:width *", "[libinsanity]" ) { + TEST_DEF; + + TEST_SNPRINTF(("%*s", 20, "Hello"), " Hello"); + TEST_SNPRINTF(("%*d", 20, 1024), " 1024"); + TEST_SNPRINTF(("%*d", 20, -1024), " -1024"); + TEST_SNPRINTF(("%*i", 20, 1024), " 1024"); + TEST_SNPRINTF(("%*i", 20, -1024), " -1024"); + TEST_SNPRINTF(("%*u", 20, 1024), " 1024"); + TEST_SNPRINTF(("%*u", 20, 4294966272U), " 4294966272"); + TEST_SNPRINTF(("%*o", 20, 511), " 777"); + TEST_SNPRINTF(("%*o", 20, 4294966785U), " 37777777001"); + TEST_SNPRINTF(("%*x", 20, 305441741), " 1234abcd"); + TEST_SNPRINTF(("%*x", 20, 3989525555U), " edcb5433"); + TEST_SNPRINTF(("%*X", 20, 305441741), " 1234ABCD"); + TEST_SNPRINTF(("%*X", 20, 3989525555U), " EDCB5433"); + TEST_SNPRINTF(("%*c", 20, 'x'), " x"); +} +TEST_CASE("lin:minus+width", "[libinsanity]" ) { + TEST_DEF; + + TEST_SNPRINTF(("%-20s", "Hello"), "Hello "); + TEST_SNPRINTF(("%-20d", 1024), "1024 "); + TEST_SNPRINTF(("%-20d", -1024), "-1024 "); + TEST_SNPRINTF(("%-20i", 1024), "1024 "); + TEST_SNPRINTF(("%-20i", -1024), "-1024 "); + TEST_SNPRINTF(("%-20u", 1024), "1024 "); + TEST_SNPRINTF(("%-20.4f", 1024.1234), "1024.1234 "); + TEST_SNPRINTF(("%-20u", 4294966272U), "4294966272 "); + TEST_SNPRINTF(("%-20o", 511), "777 "); + TEST_SNPRINTF(("%-20o", 4294966785U), "37777777001 "); + TEST_SNPRINTF(("%-20x", 305441741), "1234abcd "); + TEST_SNPRINTF(("%-20x", 3989525555U), "edcb5433 "); + TEST_SNPRINTF(("%-20X", 305441741), "1234ABCD "); + TEST_SNPRINTF(("%-20X", 3989525555U), "EDCB5433 "); + TEST_SNPRINTF(("%-20c", 'x'), "x "); + TEST_SNPRINTF(("|%5d| |%-2d| |%5d|", 9, 9, 9), "| 9| |9 | | 9|"); + TEST_SNPRINTF(("|%5d| |%-2d| |%5d|", 10, 10, 10), "| 10| |10| | 10|"); + TEST_SNPRINTF(("|%5d| |%-12d| |%5d|", 9, 9, 9), + "| 9| |9 | | 9|"); + TEST_SNPRINTF(("|%5d| |%-12d| |%5d|", 10, 10, 10), + "| 10| |10 | | 10|"); +} - test::sprintf(buffer, "%u", 1024); - REQUIRE(!strcmp(buffer, "1024")); +TEST_CASE("lin:zero+minus", "[libinsanity]" ) { + TEST_DEF; + +#if TEST_REDUNDANT_FLAGS + TEST_SNPRINTF(("%0-20s", "Hello"), "Hello "); + TEST_SNPRINTF(("%0-20d", 1024), "1024 "); + TEST_SNPRINTF(("%0-20d", -1024), "-1024 "); + TEST_SNPRINTF(("%0-20i", 1024), "1024 "); + TEST_SNPRINTF(("%0-20i", -1024), "-1024 "); + TEST_SNPRINTF(("%0-20u", 1024), "1024 "); + TEST_SNPRINTF(("%0-20u", 4294966272U), "4294966272 "); + TEST_SNPRINTF(("%0-20o", 511), "777 "); + TEST_SNPRINTF(("%0-20o", 4294966785U), "37777777001 "); + TEST_SNPRINTF(("%0-20x", 305441741), "1234abcd "); + TEST_SNPRINTF(("%0-20x", 3989525555U), "edcb5433 "); + TEST_SNPRINTF(("%0-20X", 305441741), "1234ABCD "); + TEST_SNPRINTF(("%0-20X", 3989525555U), "EDCB5433 "); + TEST_SNPRINTF(("%0-20c", 'x'), "x "); +#endif +} - test::sprintf(buffer, "%u", 4294966272U); - REQUIRE(!strcmp(buffer, "4294966272")); +TEST_CASE("lin:zero+width", "[libinsanity]" ) { + TEST_DEF; + + TEST_SNPRINTF(("%020d", 1024), "00000000000000001024"); + TEST_SNPRINTF(("%020d", -1024), "-0000000000000001024"); + TEST_SNPRINTF(("%020i", 1024), "00000000000000001024"); + TEST_SNPRINTF(("%020i", -1024), "-0000000000000001024"); + TEST_SNPRINTF(("%020u", 1024), "00000000000000001024"); + TEST_SNPRINTF(("%020u", 4294966272U), "00000000004294966272"); + TEST_SNPRINTF(("%020o", 511), "00000000000000000777"); + TEST_SNPRINTF(("%020o", 4294966785U), "00000000037777777001"); + TEST_SNPRINTF(("%020x", 305441741), "0000000000001234abcd"); + TEST_SNPRINTF(("%020x", 3989525555U), "000000000000edcb5433"); + TEST_SNPRINTF(("%020X", 305441741), "0000000000001234ABCD"); + TEST_SNPRINTF(("%020X", 3989525555U), "000000000000EDCB5433"); +} - test::sprintf(buffer, "%o", 511); - REQUIRE(!strcmp(buffer, "777")); +TEST_CASE("lin:prec", "[libinsanity]" ) { + TEST_DEF; + + TEST_SNPRINTF(("%.20d", 1024), "00000000000000001024"); + TEST_SNPRINTF(("%.20d", -1024), "-00000000000000001024"); + TEST_SNPRINTF(("%.20i", 1024), "00000000000000001024"); + TEST_SNPRINTF(("%.20i", -1024), "-00000000000000001024"); + TEST_SNPRINTF(("%.20u", 1024), "00000000000000001024"); + TEST_SNPRINTF(("%.20u", 4294966272U), "00000000004294966272"); + TEST_SNPRINTF(("%.20o", 511), "00000000000000000777"); + TEST_SNPRINTF(("%.20o", 4294966785U), "00000000037777777001"); + TEST_SNPRINTF(("%.20x", 305441741), "0000000000001234abcd"); + TEST_SNPRINTF(("%.20x", 3989525555U), "000000000000edcb5433"); + TEST_SNPRINTF(("%.20X", 305441741), "0000000000001234ABCD"); + TEST_SNPRINTF(("%.20X", 3989525555U), "000000000000EDCB5433"); +#if TEST_REDUNDANT_FLAGS + TEST_SNPRINTF(("%#020d", 1024), "00000000000000001024"); + TEST_SNPRINTF(("%#020d", -1024), "-0000000000000001024"); + TEST_SNPRINTF(("%#020i", 1024), "00000000000000001024"); + TEST_SNPRINTF(("%#020i", -1024), "-0000000000000001024"); + TEST_SNPRINTF(("%#020u", 1024), "00000000000000001024"); + TEST_SNPRINTF(("%#020u", 4294966272U), "00000000004294966272"); +#endif +} - test::sprintf(buffer, "%o", 4294966785U); - REQUIRE(!strcmp(buffer, "37777777001")); +TEST_CASE("lin:hash", "[libinsanity]" ) { + TEST_DEF; + + TEST_SNPRINTF(("%#020o", 511), "00000000000000000777"); + TEST_SNPRINTF(("%#020o", 4294966785U), "00000000037777777001"); + TEST_SNPRINTF(("%#020x", 305441741), "0x00000000001234abcd"); + TEST_SNPRINTF(("%#020x", 3989525555U), "0x0000000000edcb5433"); + TEST_SNPRINTF(("%#020X", 305441741), "0X00000000001234ABCD"); + TEST_SNPRINTF(("%#020X", 3989525555U), "0X0000000000EDCB5433"); +#if TEST_REDUNDANT_FLAGS + TEST_SNPRINTF(("%#20d", 1024), " 1024"); + TEST_SNPRINTF(("%#20d", -1024), " -1024"); + TEST_SNPRINTF(("%#20i", 1024), " 1024"); + TEST_SNPRINTF(("%#20i", -1024), " -1024"); + TEST_SNPRINTF(("%#20u", 1024), " 1024"); + TEST_SNPRINTF(("%#20u", 4294966272U), " 4294966272"); +#endif - test::sprintf(buffer, "%x", 305441741); - REQUIRE(!strcmp(buffer, "1234abcd")); + TEST_SNPRINTF(("%#20o", 511), " 0777"); + TEST_SNPRINTF(("%#20o", 4294966785U), " 037777777001"); + TEST_SNPRINTF(("%#20x", 305441741), " 0x1234abcd"); + TEST_SNPRINTF(("%#20x", 3989525555U), " 0xedcb5433"); + TEST_SNPRINTF(("%#20X", 305441741), " 0X1234ABCD"); + TEST_SNPRINTF(("%#20X", 3989525555U), " 0XEDCB5433"); +} - test::sprintf(buffer, "%x", 3989525555U); - REQUIRE(!strcmp(buffer, "edcb5433")); +TEST_CASE("lin:width+prec", "[libinsanity]" ) { + TEST_DEF; + + TEST_SNPRINTF(("%20.5d", 1024), " 01024"); + TEST_SNPRINTF(("%20.5d", -1024), " -01024"); + TEST_SNPRINTF(("%20.5i", 1024), " 01024"); + TEST_SNPRINTF(("%20.5i", -1024), " -01024"); + TEST_SNPRINTF(("%20.5u", 1024), " 01024"); + TEST_SNPRINTF(("%20.5u", 4294966272U), " 4294966272"); + TEST_SNPRINTF(("%20.5o", 511), " 00777"); + TEST_SNPRINTF(("%20.5o", 4294966785U), " 37777777001"); + TEST_SNPRINTF(("%20.5x", 305441741), " 1234abcd"); + TEST_SNPRINTF(("%20.10x", 3989525555U), " 00edcb5433"); + TEST_SNPRINTF(("%20.5X", 305441741), " 1234ABCD"); + TEST_SNPRINTF(("%20.10X", 3989525555U), " 00EDCB5433"); + TEST_SNPRINTF(("%.0s", "Hello testing"), ""); + TEST_SNPRINTF(("%20.0s", "Hello testing"), " "); + TEST_SNPRINTF(("%.s", "Hello testing"), ""); + TEST_SNPRINTF(("%20.s", "Hello testing"), " "); + TEST_SNPRINTF(("%20.0d", 1024), " 1024"); + TEST_SNPRINTF(("%20.0d", -1024), " -1024"); + TEST_SNPRINTF(("%20.d", 0), " "); + TEST_SNPRINTF(("%20.0i", 1024), " 1024"); + TEST_SNPRINTF(("%20.i", -1024), " -1024"); + TEST_SNPRINTF(("%20.i", 0), " "); + TEST_SNPRINTF(("%20.u", 1024), " 1024"); + TEST_SNPRINTF(("%20.0u", 4294966272U), " 4294966272"); + TEST_SNPRINTF(("%20.u", 0U), " "); + TEST_SNPRINTF(("%20.o", 511), " 777"); + TEST_SNPRINTF(("%20.0o", 4294966785U), " 37777777001"); + TEST_SNPRINTF(("%20.o", 0U), " "); + TEST_SNPRINTF(("%20.x", 305441741), " 1234abcd"); + TEST_SNPRINTF(("%50.x", 305441741), + " 1234abcd"); + TEST_SNPRINTF(("%50.x%10.u", 305441741, 12345), + " 1234abcd 12345"); + TEST_SNPRINTF(("%20.0x", 3989525555U), " edcb5433"); + TEST_SNPRINTF(("%20.x", 0U), " "); + TEST_SNPRINTF(("%20.X", 305441741), " 1234ABCD"); + TEST_SNPRINTF(("%20.0X", 3989525555U), " EDCB5433"); + TEST_SNPRINTF(("%20.X", 0U), " "); +} - test::sprintf(buffer, "%X", 305441741); - REQUIRE(!strcmp(buffer, "1234ABCD")); +TEST_CASE("lin:%f width/prec", "[libinsanity]" ) { + TEST_DEF; + + TEST_SNPRINTF(("%.4f", 3.1415354), "3.1415"); + TEST_SNPRINTF(("%.3f", 30343.1415354), "30343.142"); + TEST_SNPRINTF(("%.0f", 34.1415354), "34"); + TEST_SNPRINTF(("%.2f", 42.8952), "42.90"); + TEST_SNPRINTF(("%.9f", 42.8952), "42.895200000"); + TEST_SNPRINTF(("%.10f", 42.895223), "42.8952230000"); +#if PRINTF_FLOAT_PREC > 9 + TEST_SNPRINTF(("%.12f", 42.89522312345678), "42.895223123457"); + TEST_SNPRINTF(("%.12f", 42.89522387654321), "42.895223876543"); +#else + // precision is limited to 9 + TEST_SNPRINTF(("%.12f", 42.89522312345678), "42.895223123000"); + TEST_SNPRINTF(("%.12f", 42.89522387654321), "42.895223877000"); +#endif + TEST_SNPRINTF(("%6.2f", 42.8952), " 42.90"); + TEST_SNPRINTF(("%+6.2f", 42.8952), "+42.90"); + TEST_SNPRINTF(("%+5.1f", 42.9252), "+42.9"); + TEST_SNPRINTF(("%f", 42.5), "42.500000"); + TEST_SNPRINTF(("%.1f", 42.5), "42.5"); + TEST_SNPRINTF(("%f", 42167.0), "42167.000000"); + TEST_SNPRINTF(("%.9f", -12345.987654321), "-12345.987654321"); + TEST_SNPRINTF(("%.1f", 3.999), "4.0"); + TEST_SNPRINTF(("%.0f", 3.5), "4"); + TEST_SNPRINTF(("%.0f", 3.49), "3"); + TEST_SNPRINTF(("%.1f", 3.49), "3.5"); +#if PRINTF_FLOAT_DECIMALS >= 20 + TEST_SNPRINTF(("%.1f", 1E20), "100000000000000000000.0"); +#else + // out of range for float: should switch to exp notation if supported, else empty +# ifndef PRINTF_DISABLE_SUPPORT_EXPONENTIAL + TEST_SNPRINTF(("%.1f", 1E20), "1.0e+20"); +# else + TEST_SNPRINTF(("%.1f", 1E20), ""); +# endif +#endif + TEST_SNPRINTF(("a%-5.1f", 0.5), "a0.5 "); +} - test::sprintf(buffer, "%X", 3989525555U); - REQUIRE(!strcmp(buffer, "EDCB5433")); +TEST_CASE("lin:size", "[libinsanity]" ) { + TEST_DEF; + + TEST_SNPRINTF(("%i", 0), "0"); + TEST_SNPRINTF(("%i", 1234), "1234"); + TEST_SNPRINTF(("%i", 32767), "32767"); + TEST_SNPRINTF(("%i", -32767), "-32767"); + TEST_SNPRINTF(("%li", 30L), "30"); + TEST_SNPRINTF(("%li", -2147483647L), "-2147483647"); + TEST_SNPRINTF(("%li", 2147483647L), "2147483647"); + TEST_SNPRINTF(("%lli", 30LL), "30"); + TEST_SNPRINTF(("%lli", -9223372036854775807LL), "-9223372036854775807"); + TEST_SNPRINTF(("%lli", 9223372036854775807LL), "9223372036854775807"); + TEST_SNPRINTF(("%lu", 100000L), "100000"); + TEST_SNPRINTF(("%lu", 0xFFFFFFFFL), "4294967295"); + TEST_SNPRINTF(("%llu", 281474976710656LLU), "281474976710656"); + TEST_SNPRINTF(("%llu", 18446744073709551615LLU), "18446744073709551615"); + TEST_SNPRINTF(("%zu", (size_t)2147483647UL), "2147483647"); + TEST_SNPRINTF(("%zd", (ptrdiff_t)2147483647UL), "2147483647"); + TEST_SNPRINTF(("%tu", (size_t)2147483647UL), "2147483647"); + TEST_SNPRINTF(("%td", (ptrdiff_t)2147483647UL), "2147483647"); +#if TEST_NON_STANDARD + // Unportable extension in original printf implementation. + TEST_SNPRINTF(("%b", 60000), "1110101001100000"); + TEST_SNPRINTF(("%lb", 12345678L), "101111000110000101001110"); + TEST_SNPRINTF(("%#b", 60000), "0b1110101001100000"); +#endif - test::sprintf(buffer, "%%"); - REQUIRE(!strcmp(buffer, "%")); + TEST_SNPRINTF(("%o", 60000), "165140"); + TEST_SNPRINTF(("%lo", 12345678L), "57060516"); + TEST_SNPRINTF(("%lx", 0x12345678L), "12345678"); + TEST_SNPRINTF(("%llx", 0x1234567891234567LLU), "1234567891234567"); + TEST_SNPRINTF(("%lx", 0xabcdefabL), "abcdefab"); + TEST_SNPRINTF(("%lX", 0xabcdefabL), "ABCDEFAB"); + TEST_SNPRINTF(("%c", 'v'), "v"); + TEST_SNPRINTF(("%cv", 'w'), "wv"); + TEST_SNPRINTF(("%s", "A Test"), "A Test"); + TEST_SNPRINTF(("%hhu", (unsigned char)0xFFFFU), "255"); + TEST_SNPRINTF(("%hu", (unsigned short)0x123456U), "13398"); + TEST_SNPRINTF(("%s%hhi %hu", "Test", 10000, 0xFFFFFFFF), "Test16 65535"); + TEST_SNPRINTF(("%tx", &buffer[10] - &buffer[0]), "a"); + TEST_SNPRINTF(("%ji", (intmax_t)-2147483647L), "-2147483647"); + TEST_SNPRINTF(("%ju", (uintmax_t)2147483647UL), "2147483647"); + + TEST_SNPRINTF(("%hhd", -1), "-1"); } +TEST_CASE("lin:prec *", "[libinsanity]" ) { + TEST_DEF; -TEST_CASE("width", "[]" ) { - char buffer[100]; + TEST_SNPRINTF(("%.*d", -1, 1), "1"); +#if ENABLE_FAILING + // negative precision as if no precision is given + TEST_SNPRINTF(("%.*d", -1, 0), "0"); +#endif +} - test::sprintf(buffer, "%1s", "Hello testing"); - REQUIRE(!strcmp(buffer, "Hello testing")); +TEST_CASE("lin:%p", "[libinsanity]" ) { + TEST_DEF; - test::sprintf(buffer, "%1d", 1024); - REQUIRE(!strcmp(buffer, "1024")); +#if TEST_IMPL_DEFINED && PRINTF_POINTER_0XHEX + tested_snprintf(buffer, sizeof(buffer), "%p", (void *)(uintptr_t)0x1234U); + REQUIRE_STR_EQ(buffer, "0x1234"); - test::sprintf(buffer, "%1d", -1024); - REQUIRE(!strcmp(buffer, "-1024")); + tested_snprintf(buffer, sizeof(buffer), "%p", (void *)(uintptr_t)0x12345678U); + REQUIRE_STR_EQ(buffer, "0x12345678"); - test::sprintf(buffer, "%1i", 1024); - REQUIRE(!strcmp(buffer, "1024")); + tested_snprintf(buffer, sizeof(buffer), "%p-%p", (void *)0x12345678U, + (void *)(uintptr_t)0x7EDCBA98U); + REQUIRE_STR_EQ(buffer, "0x12345678-0x7edcba98"); - test::sprintf(buffer, "%1i", -1024); - REQUIRE(!strcmp(buffer, "-1024")); + tested_snprintf(buffer, sizeof(buffer), "%p", + (void *)(uintptr_t)0xFFFFFFFFU); + REQUIRE_STR_EQ(buffer, "0xffffffff"); +#endif +} - test::sprintf(buffer, "%1u", 1024); - REQUIRE(!strcmp(buffer, "1024")); +TEST_CASE("lin:snprintf maxlength", "[libinsanity]" ) { + TEST_DEF; - test::sprintf(buffer, "%1u", 4294966272U); - REQUIRE(!strcmp(buffer, "4294966272")); + buffer[0] = (char)0xA5; + ret = tested_snprintf(buffer, 0, "%s", "Test"); + REQUIRE(buffer[0] == (char)0xA5); + REQUIRE(ret == 4); - test::sprintf(buffer, "%1o", 511); - REQUIRE(!strcmp(buffer, "777")); + buffer[0] = (char)0xCC; + tested_snprintf(buffer, 1, "%s", "Test"); + REQUIRE(buffer[0] == '\0'); - test::sprintf(buffer, "%1o", 4294966785U); - REQUIRE(!strcmp(buffer, "37777777001")); + tested_snprintf(buffer, 2, "%s", "Hello"); + REQUIRE_STR_EQ(buffer, "H"); - test::sprintf(buffer, "%1x", 305441741); - REQUIRE(!strcmp(buffer, "1234abcd")); + ret = tested_snprintf(buffer, 6, "0%s", "1234"); + REQUIRE_STR_EQ(buffer, "01234"); + REQUIRE(ret == 5); - test::sprintf(buffer, "%1x", 3989525555U); - REQUIRE(!strcmp(buffer, "edcb5433")); + ret = tested_snprintf(buffer, 6, "0%s", "12345"); + REQUIRE_STR_EQ(buffer, "01234"); + REQUIRE(ret == 6); // '5' is truncated - test::sprintf(buffer, "%1X", 305441741); - REQUIRE(!strcmp(buffer, "1234ABCD")); + ret = tested_snprintf(buffer, 6, "0%s", "1234567"); + REQUIRE_STR_EQ(buffer, "01234"); + REQUIRE(ret == 8); // '567' are truncated - test::sprintf(buffer, "%1X", 3989525555U); - REQUIRE(!strcmp(buffer, "EDCB5433")); + ret = tested_snprintf(buffer, 10, "hello, world"); + REQUIRE(ret == 12); - test::sprintf(buffer, "%1c", 'x'); - REQUIRE(!strcmp(buffer, "x")); + ret = tested_snprintf(buffer, 3, "%d", 10000); + REQUIRE(ret == 5); + REQUIRE(strlen(buffer) == 2U); + REQUIRE(buffer[0] == '1'); + REQUIRE(buffer[1] == '0'); + REQUIRE(buffer[2] == '\0'); } +TEST_CASE("lin:extreme values", "[libinsanity]" ) { + TEST_DEF; -TEST_CASE("width 20", "[]" ) { - char buffer[100]; - - test::sprintf(buffer, "%20s", "Hello"); - REQUIRE(!strcmp(buffer, " Hello")); - - test::sprintf(buffer, "%20d", 1024); - REQUIRE(!strcmp(buffer, " 1024")); - - test::sprintf(buffer, "%20d", -1024); - REQUIRE(!strcmp(buffer, " -1024")); - - test::sprintf(buffer, "%20i", 1024); - REQUIRE(!strcmp(buffer, " 1024")); - - test::sprintf(buffer, "%20i", -1024); - REQUIRE(!strcmp(buffer, " -1024")); +#if INT_MAX == 2147483647 + TEST_SNPRINTF(("%d", INT_MAX), "2147483647"); +#if ENABLE_FAILING + // undefined behavior of -INT_MIN + TEST_SNPRINTF(("%d", INT_MIN), "-2147483648"); +#endif + TEST_SNPRINTF(("%u", UINT_MAX), "4294967295"); +#endif +#if LONG_MAX == 2147483647L + TEST_SNPRINTF(("%ld", LONG_MAX), "2147483647"); + TEST_SNPRINTF(("%ld", LONG_MIN), "-2147483648"); + TEST_SNPRINTF(("%lu", ULONG_MAX), "4294967295"); +#endif +#if LONG_MAX == 9223372036854775807L + TEST_SNPRINTF(("%ld", LONG_MAX), "9223372036854775807"); + TEST_SNPRINTF(("%ld", LONG_MIN), "-9223372036854775808"); + TEST_SNPRINTF(("%lu", ULONG_MAX), "18446744073709551615"); +#endif + TEST_SNPRINTF(("%" PRIi32, INT32_MAX), "2147483647"); +#if ENABLE_FAILING + // undefined behavior of -INT_MIN + TEST_SNPRINTF(("%" PRIi32, INT32_MIN), "-2147483648"); +#endif + TEST_SNPRINTF(("%" PRIi64, INT64_MAX), "9223372036854775807"); + TEST_SNPRINTF(("%" PRIi64, INT64_MIN), "-9223372036854775808"); + TEST_SNPRINTF(("%" PRIu64, UINT64_MAX), "18446744073709551615"); + +#if TEST_IMPL_DEFINED && TEST_IMPL_EXPLICITSIZE + // libinsanity/Microsoft extensions for explicitly sized integer types + TEST_SNPRINTF(("%I64d", INT64_MIN), "-9223372036854775808"); + TEST_SNPRINTF(("%I32d", INT32_MIN), "-2147483648"); + TEST_SNPRINTF(("%Id", (ptrdiff_t)-123), "-123"); + TEST_SNPRINTF(("%Iu", (size_t)123), "123"); + // libinsanity only extensions + TEST_SNPRINTF(("%I8u", 10000), "16"); + TEST_SNPRINTF(("%I8d", 255), "-1"); + TEST_SNPRINTF(("%I16u", 100000), "34464"); + TEST_SNPRINTF(("%I16d", 65535), "-1"); + TEST_SNPRINTF_N(("%I34d", 123), -1); // expect error return value +#endif +} - test::sprintf(buffer, "%20u", 1024); - REQUIRE(!strcmp(buffer, " 1024")); +TEST_CASE("lin:%x", "[libinsanity]" ) { + TEST_DEF; + + TEST_SNPRINTF(("%x", 0), "0"); + TEST_SNPRINTF(("%#x", 0), "0"); + TEST_SNPRINTF(("%#04x", 0), "0000"); + TEST_SNPRINTF(("%#08x", 0x614e), "0x00614e"); + TEST_SNPRINTF(("%#.3x", 0x614e), "0x614e"); + TEST_SNPRINTF(("%#.4x", 0x614e), "0x614e"); + TEST_SNPRINTF(("%#.5x", 0x614e), "0x0614e"); + TEST_SNPRINTF(("%#.6x", 0x614e), "0x00614e"); + TEST_SNPRINTF(("%#.7x", 0x614e), "0x000614e"); +} - test::sprintf(buffer, "%20u", 4294966272U); - REQUIRE(!strcmp(buffer, " 4294966272")); +TEST_CASE("lin:%o", "[libinsanity]" ) { + TEST_DEF; + + TEST_SNPRINTF(("%o", 00), "0"); + TEST_SNPRINTF(("%#o", 00), "0"); + TEST_SNPRINTF(("%#04o", 0), "0000"); + TEST_SNPRINTF(("%#08o", 06143), "00006143"); + TEST_SNPRINTF(("%#.3o", 06143), "06143"); + TEST_SNPRINTF(("%#.4o", 06143), "06143"); +#if ENABLE_FAILING + // # modified should not output '0' whenre width already supplied one + TEST_SNPRINTF(("%#.5o", 06143), "06143"); + TEST_SNPRINTF(("%#.6o", 06143), "006143"); + TEST_SNPRINTF(("%#.7o", 06143), "0006143"); +#endif +} + // libc-testsuite tests + +TEST_CASE("libc:width/prec/minus", "[libc]" ) { + TEST_DEF; + + /* width, precision, alignment */ + TEST_SNPRINTF(("%04d", 12), "0012"); + TEST_SNPRINTF(("%.3d", 12), "012"); + TEST_SNPRINTF(("%3d", 12), " 12"); + TEST_SNPRINTF(("%-3d", 12), "12 "); + TEST_SNPRINTF(("%+3d", 12), "+12"); + TEST_SNPRINTF(("%+-5d", 12), "+12 "); +#if TEST_REDUNDANT_FLAGS + TEST_SNPRINTF(("%+- 5d", 12), "+12 "); +#endif + TEST_SNPRINTF(("%- 5d", 12), " 12 "); + TEST_SNPRINTF(("% d", 12), " 12"); +#if TEST_REDUNDANT_FLAGS + TEST_SNPRINTF(("%0-5d", 12), "12 "); + TEST_SNPRINTF(("%-05d", 12), "12 "); +#endif +} - test::sprintf(buffer, "%20o", 511); - REQUIRE(!strcmp(buffer, " 777")); +TEST_CASE("libc:prec=0", "[libc]") { + TEST_DEF; - test::sprintf(buffer, "%20o", 4294966785U); - REQUIRE(!strcmp(buffer, " 37777777001")); + /* ...explicit precision of 0 shall be no characters. */ + TEST_SNPRINTF(("%.0d", 0), ""); + TEST_SNPRINTF(("%.0o", 0), ""); +#if TEST_REDUNDANT_FLAGS + TEST_SNPRINTF(("%#.0d", 0), ""); +#endif + // Note: the original libc-testsuite specifies "" as expected. +#if ENABLE_FAILING + // octal prefix should be respected + TEST_SNPRINTF(("%#.0o", 0), "0"); +#endif + TEST_SNPRINTF(("%#.0x", 0), ""); + TEST_SNPRINTF(("%#3.0x", 0), " "); + + /* ...but it still has to honor width and flags. */ + TEST_SNPRINTF(("%2.0u", 0), " "); +#if TEST_REDUNDANT_FLAGS + TEST_SNPRINTF(("%02.0u", 0), " "); + TEST_SNPRINTF(("%02.0d", 0), " "); +#endif + TEST_SNPRINTF(("%2.0d", 0), " "); + TEST_SNPRINTF(("% .0d", 0), " "); + TEST_SNPRINTF(("%+.0d", 0), "+"); +} - test::sprintf(buffer, "%20x", 305441741); - REQUIRE(!strcmp(buffer, " 1234abcd")); +TEST_CASE("libc:%x", "[libc]") { + TEST_DEF; - test::sprintf(buffer, "%20x", 3989525555U); - REQUIRE(!strcmp(buffer, " edcb5433")); + /* hex: test alt form and case */ + TEST_SNPRINTF(("%x", 63), "3f"); + TEST_SNPRINTF(("%#x", 63), "0x3f"); + TEST_SNPRINTF(("%X", 63), "3F"); +} - test::sprintf(buffer, "%20X", 305441741); - REQUIRE(!strcmp(buffer, " 1234ABCD")); + TEST_CASE("libc:%o", "[libc]") { + TEST_DEF; + /* octal: test alt form */ + TEST_SNPRINTF(("%o", 15), "17"); + TEST_SNPRINTF(("%#o", 15), "017"); + } - test::sprintf(buffer, "%20X", 3989525555U); - REQUIRE(!strcmp(buffer, " EDCB5433")); +TEST_CASE("libc:%e %f %g", "[libc]") { + TEST_DEF; - test::sprintf(buffer, "%20c", 'x'); - REQUIRE(!strcmp(buffer, " x")); + /* basic form, handling of exponent/precision for 0 */ +#if ENABLE_FAILING + // zero has exponent 0 + TEST_SNPRINTF(("%e", 0.0), "0.000000e+00"); +#endif + TEST_SNPRINTF(("%f", 0.0), "0.000000"); +#if ENABLE_FAILING + // zero has exponent 0 + TEST_SNPRINTF(("%g", 0.0), "0"); + TEST_SNPRINTF(("%#g", 0.0), "0.00000"); +#endif + /* rounding */ + TEST_SNPRINTF(("%f", 1.1), "1.100000"); + TEST_SNPRINTF(("%f", 1.2), "1.200000"); + TEST_SNPRINTF(("%f", 1.3), "1.300000"); + TEST_SNPRINTF(("%f", 1.4), "1.400000"); + TEST_SNPRINTF(("%f", 1.5), "1.500000"); + // Note: the original libc-testsuite test specifies "1.0612" as expected. + TEST_SNPRINTF(("%.4f", 1.06125), "1.0613"); + TEST_SNPRINTF(("%.2f", 1.375), "1.38"); + TEST_SNPRINTF(("%.1f", 1.375), "1.4"); + TEST_SNPRINTF(("%.15f", 1.1), "1.100000000000000"); +#if PRINTF_FLOAT_PREC >= 16 + TEST_SNPRINTF(("%.16f", 1.1), "1.1000000000000001"); +#endif +#if PRINTF_FLOAT_PREC >= 17 + TEST_SNPRINTF(("%.17f", 1.1), "1.10000000000000009"); +#endif + TEST_SNPRINTF(("%.2e", 1500001.0), "1.50e+06"); + TEST_SNPRINTF(("%.2e", 1505000.0), "1.50e+06"); + TEST_SNPRINTF(("%.2e", 1505000.00000095367431640625), "1.51e+06"); + TEST_SNPRINTF(("%.2e", 1505001.0), "1.51e+06"); + TEST_SNPRINTF(("%.2e", 1506000.0), "1.51e+06"); + + /* correctness in DBL_DIG places */ +#if PRINTF_FLOAT_PREC >= 15 + TEST_SNPRINTF(("%.15g", 1.23456789012345), "1.23456789012345"); +#endif + /* correct choice of notation for %g */ +#if ENABLE_FAILING + // %g uses shortest representation, no trailing zeroes even when using %f notation + TEST_SNPRINTF(("%g", 0.0001), "0.0001"); +#endif +#if ENABLE_FAILING + // %g uses shortest representation, no trailing zeroes + TEST_SNPRINTF(("%g", 0.00001), "1e-05"); +#endif + TEST_SNPRINTF(("%g", 123456.0), "123456"); +#if ENABLE_FAILING + // %g - precision is number of significant digits + TEST_SNPRINTF(("%g", 1234567.0), "1.23457e+06"); +#endif +#if ENABLE_FAILING + // %g - use %f when precision allows it + TEST_SNPRINTF(("%.7g", 1234567.0), "1234567"); +#endif + TEST_SNPRINTF(("%.7g", 12345678.0), "1.234568e+07"); +#if ENABLE_FAILING + // %g uses shortest representation, no trailing zeroes + TEST_SNPRINTF(("%.8g", 0.1), "0.1"); + TEST_SNPRINTF(("%.9g", 0.1), "0.1"); + TEST_SNPRINTF(("%.10g", 0.1), "0.1"); + TEST_SNPRINTF(("%.11g", 0.1), "0.1"); +#endif + /* pi in double precision, printed to a few extra places */ +#if PRINTF_FLOAT_PREC >= 15 + TEST_SNPRINTF(("%.15f", M_PI), "3.141592653589793"); +#endif +#if PRINTF_FLOAT_PREC >= 18 + TEST_SNPRINTF(("%.18f", M_PI), "3.141592653589793116"); +#endif +#if PRINTF_FLOAT_DECIMALS >= 39 + /* exact conversion of large integers */ + TEST_SNPRINTF(("%.0f", 340282366920938463463374607431768211456.0), + "340282366920938463463374607431768211456"); +#endif } +TEST_CASE("libc:snprintf retval", "[libc]") { + TEST_DEF; -TEST_CASE("width *20", "[]" ) { - char buffer[100]; - - test::sprintf(buffer, "%*s", 20, "Hello"); - REQUIRE(!strcmp(buffer, " Hello")); - - test::sprintf(buffer, "%*d", 20, 1024); - REQUIRE(!strcmp(buffer, " 1024")); - - test::sprintf(buffer, "%*d", 20, -1024); - REQUIRE(!strcmp(buffer, " -1024")); - - test::sprintf(buffer, "%*i", 20, 1024); - REQUIRE(!strcmp(buffer, " 1024")); - - test::sprintf(buffer, "%*i", 20, -1024); - REQUIRE(!strcmp(buffer, " -1024")); - - test::sprintf(buffer, "%*u", 20, 1024); - REQUIRE(!strcmp(buffer, " 1024")); - - test::sprintf(buffer, "%*u", 20, 4294966272U); - REQUIRE(!strcmp(buffer, " 4294966272")); - - test::sprintf(buffer, "%*o", 20, 511); - REQUIRE(!strcmp(buffer, " 777")); - - test::sprintf(buffer, "%*o", 20, 4294966785U); - REQUIRE(!strcmp(buffer, " 37777777001")); - - test::sprintf(buffer, "%*x", 20, 305441741); - REQUIRE(!strcmp(buffer, " 1234abcd")); - - test::sprintf(buffer, "%*x", 20, 3989525555U); - REQUIRE(!strcmp(buffer, " edcb5433")); - - test::sprintf(buffer, "%*X", 20, 305441741); - REQUIRE(!strcmp(buffer, " 1234ABCD")); - - test::sprintf(buffer, "%*X", 20, 3989525555U); - REQUIRE(!strcmp(buffer, " EDCB5433")); - - test::sprintf(buffer, "%*c", 20,'x'); - REQUIRE(!strcmp(buffer, " x")); -} - - -TEST_CASE("width -20", "[]" ) { - char buffer[100]; - - test::sprintf(buffer, "%-20s", "Hello"); - REQUIRE(!strcmp(buffer, "Hello ")); - - test::sprintf(buffer, "%-20d", 1024); - REQUIRE(!strcmp(buffer, "1024 ")); - - test::sprintf(buffer, "%-20d", -1024); - REQUIRE(!strcmp(buffer, "-1024 ")); - - test::sprintf(buffer, "%-20i", 1024); - REQUIRE(!strcmp(buffer, "1024 ")); - - test::sprintf(buffer, "%-20i", -1024); - REQUIRE(!strcmp(buffer, "-1024 ")); - - test::sprintf(buffer, "%-20u", 1024); - REQUIRE(!strcmp(buffer, "1024 ")); - - test::sprintf(buffer, "%-20.4f", 1024.1234); - REQUIRE(!strcmp(buffer, "1024.1234 ")); - - test::sprintf(buffer, "%-20u", 4294966272U); - REQUIRE(!strcmp(buffer, "4294966272 ")); - - test::sprintf(buffer, "%-20o", 511); - REQUIRE(!strcmp(buffer, "777 ")); - - test::sprintf(buffer, "%-20o", 4294966785U); - REQUIRE(!strcmp(buffer, "37777777001 ")); - - test::sprintf(buffer, "%-20x", 305441741); - REQUIRE(!strcmp(buffer, "1234abcd ")); - - test::sprintf(buffer, "%-20x", 3989525555U); - REQUIRE(!strcmp(buffer, "edcb5433 ")); - - test::sprintf(buffer, "%-20X", 305441741); - REQUIRE(!strcmp(buffer, "1234ABCD ")); - - test::sprintf(buffer, "%-20X", 3989525555U); - REQUIRE(!strcmp(buffer, "EDCB5433 ")); - - test::sprintf(buffer, "%-20c", 'x'); - REQUIRE(!strcmp(buffer, "x ")); - - test::sprintf(buffer, "|%5d| |%-2d| |%5d|", 9, 9, 9); - REQUIRE(!strcmp(buffer, "| 9| |9 | | 9|")); - - test::sprintf(buffer, "|%5d| |%-2d| |%5d|", 10, 10, 10); - REQUIRE(!strcmp(buffer, "| 10| |10| | 10|")); - - test::sprintf(buffer, "|%5d| |%-12d| |%5d|", 9, 9, 9); - REQUIRE(!strcmp(buffer, "| 9| |9 | | 9|")); - - test::sprintf(buffer, "|%5d| |%-12d| |%5d|", 10, 10, 10); - REQUIRE(!strcmp(buffer, "| 10| |10 | | 10|")); -} - - -TEST_CASE("width 0-20", "[]" ) { - char buffer[100]; - - test::sprintf(buffer, "%0-20s", "Hello"); - REQUIRE(!strcmp(buffer, "Hello ")); - - test::sprintf(buffer, "%0-20d", 1024); - REQUIRE(!strcmp(buffer, "1024 ")); - - test::sprintf(buffer, "%0-20d", -1024); - REQUIRE(!strcmp(buffer, "-1024 ")); - - test::sprintf(buffer, "%0-20i", 1024); - REQUIRE(!strcmp(buffer, "1024 ")); - - test::sprintf(buffer, "%0-20i", -1024); - REQUIRE(!strcmp(buffer, "-1024 ")); - - test::sprintf(buffer, "%0-20u", 1024); - REQUIRE(!strcmp(buffer, "1024 ")); - - test::sprintf(buffer, "%0-20u", 4294966272U); - REQUIRE(!strcmp(buffer, "4294966272 ")); - - test::sprintf(buffer, "%0-20o", 511); - REQUIRE(!strcmp(buffer, "777 ")); - - test::sprintf(buffer, "%0-20o", 4294966785U); - REQUIRE(!strcmp(buffer, "37777777001 ")); - - test::sprintf(buffer, "%0-20x", 305441741); - REQUIRE(!strcmp(buffer, "1234abcd ")); - - test::sprintf(buffer, "%0-20x", 3989525555U); - REQUIRE(!strcmp(buffer, "edcb5433 ")); - - test::sprintf(buffer, "%0-20X", 305441741); - REQUIRE(!strcmp(buffer, "1234ABCD ")); - - test::sprintf(buffer, "%0-20X", 3989525555U); - REQUIRE(!strcmp(buffer, "EDCB5433 ")); - - test::sprintf(buffer, "%0-20c", 'x'); - REQUIRE(!strcmp(buffer, "x ")); -} - - -TEST_CASE("padding 20", "[]" ) { - char buffer[100]; - - test::sprintf(buffer, "%020d", 1024); - REQUIRE(!strcmp(buffer, "00000000000000001024")); - - test::sprintf(buffer, "%020d", -1024); - REQUIRE(!strcmp(buffer, "-0000000000000001024")); - - test::sprintf(buffer, "%020i", 1024); - REQUIRE(!strcmp(buffer, "00000000000000001024")); - - test::sprintf(buffer, "%020i", -1024); - REQUIRE(!strcmp(buffer, "-0000000000000001024")); - - test::sprintf(buffer, "%020u", 1024); - REQUIRE(!strcmp(buffer, "00000000000000001024")); - - test::sprintf(buffer, "%020u", 4294966272U); - REQUIRE(!strcmp(buffer, "00000000004294966272")); - - test::sprintf(buffer, "%020o", 511); - REQUIRE(!strcmp(buffer, "00000000000000000777")); - - test::sprintf(buffer, "%020o", 4294966785U); - REQUIRE(!strcmp(buffer, "00000000037777777001")); - - test::sprintf(buffer, "%020x", 305441741); - REQUIRE(!strcmp(buffer, "0000000000001234abcd")); - - test::sprintf(buffer, "%020x", 3989525555U); - REQUIRE(!strcmp(buffer, "000000000000edcb5433")); - - test::sprintf(buffer, "%020X", 305441741); - REQUIRE(!strcmp(buffer, "0000000000001234ABCD")); - - test::sprintf(buffer, "%020X", 3989525555U); - REQUIRE(!strcmp(buffer, "000000000000EDCB5433")); -} - - -TEST_CASE("padding .20", "[]" ) { - char buffer[100]; - - test::sprintf(buffer, "%.20d", 1024); - REQUIRE(!strcmp(buffer, "00000000000000001024")); - - test::sprintf(buffer, "%.20d", -1024); - REQUIRE(!strcmp(buffer, "-00000000000000001024")); - - test::sprintf(buffer, "%.20i", 1024); - REQUIRE(!strcmp(buffer, "00000000000000001024")); - - test::sprintf(buffer, "%.20i", -1024); - REQUIRE(!strcmp(buffer, "-00000000000000001024")); - - test::sprintf(buffer, "%.20u", 1024); - REQUIRE(!strcmp(buffer, "00000000000000001024")); - - test::sprintf(buffer, "%.20u", 4294966272U); - REQUIRE(!strcmp(buffer, "00000000004294966272")); - - test::sprintf(buffer, "%.20o", 511); - REQUIRE(!strcmp(buffer, "00000000000000000777")); - - test::sprintf(buffer, "%.20o", 4294966785U); - REQUIRE(!strcmp(buffer, "00000000037777777001")); - - test::sprintf(buffer, "%.20x", 305441741); - REQUIRE(!strcmp(buffer, "0000000000001234abcd")); - - test::sprintf(buffer, "%.20x", 3989525555U); - REQUIRE(!strcmp(buffer, "000000000000edcb5433")); - - test::sprintf(buffer, "%.20X", 305441741); - REQUIRE(!strcmp(buffer, "0000000000001234ABCD")); - - test::sprintf(buffer, "%.20X", 3989525555U); - REQUIRE(!strcmp(buffer, "000000000000EDCB5433")); -} - - -TEST_CASE("padding #020", "[]" ) { - char buffer[100]; - - test::sprintf(buffer, "%#020d", 1024); - REQUIRE(!strcmp(buffer, "00000000000000001024")); - - test::sprintf(buffer, "%#020d", -1024); - REQUIRE(!strcmp(buffer, "-0000000000000001024")); - - test::sprintf(buffer, "%#020i", 1024); - REQUIRE(!strcmp(buffer, "00000000000000001024")); - - test::sprintf(buffer, "%#020i", -1024); - REQUIRE(!strcmp(buffer, "-0000000000000001024")); - - test::sprintf(buffer, "%#020u", 1024); - REQUIRE(!strcmp(buffer, "00000000000000001024")); - - test::sprintf(buffer, "%#020u", 4294966272U); - REQUIRE(!strcmp(buffer, "00000000004294966272")); - - test::sprintf(buffer, "%#020o", 511); - REQUIRE(!strcmp(buffer, "00000000000000000777")); - - test::sprintf(buffer, "%#020o", 4294966785U); - REQUIRE(!strcmp(buffer, "00000000037777777001")); - - test::sprintf(buffer, "%#020x", 305441741); - REQUIRE(!strcmp(buffer, "0x00000000001234abcd")); - - test::sprintf(buffer, "%#020x", 3989525555U); - REQUIRE(!strcmp(buffer, "0x0000000000edcb5433")); - - test::sprintf(buffer, "%#020X", 305441741); - REQUIRE(!strcmp(buffer, "0X00000000001234ABCD")); - - test::sprintf(buffer, "%#020X", 3989525555U); - REQUIRE(!strcmp(buffer, "0X0000000000EDCB5433")); -} - - -TEST_CASE("padding #20", "[]" ) { - char buffer[100]; - - test::sprintf(buffer, "%#20d", 1024); - REQUIRE(!strcmp(buffer, " 1024")); - - test::sprintf(buffer, "%#20d", -1024); - REQUIRE(!strcmp(buffer, " -1024")); - - test::sprintf(buffer, "%#20i", 1024); - REQUIRE(!strcmp(buffer, " 1024")); - - test::sprintf(buffer, "%#20i", -1024); - REQUIRE(!strcmp(buffer, " -1024")); - - test::sprintf(buffer, "%#20u", 1024); - REQUIRE(!strcmp(buffer, " 1024")); - - test::sprintf(buffer, "%#20u", 4294966272U); - REQUIRE(!strcmp(buffer, " 4294966272")); - - test::sprintf(buffer, "%#20o", 511); - REQUIRE(!strcmp(buffer, " 0777")); - - test::sprintf(buffer, "%#20o", 4294966785U); - REQUIRE(!strcmp(buffer, " 037777777001")); - - test::sprintf(buffer, "%#20x", 305441741); - REQUIRE(!strcmp(buffer, " 0x1234abcd")); - - test::sprintf(buffer, "%#20x", 3989525555U); - REQUIRE(!strcmp(buffer, " 0xedcb5433")); - - test::sprintf(buffer, "%#20X", 305441741); - REQUIRE(!strcmp(buffer, " 0X1234ABCD")); - - test::sprintf(buffer, "%#20X", 3989525555U); - REQUIRE(!strcmp(buffer, " 0XEDCB5433")); -} - - -TEST_CASE("padding 20.5", "[]" ) { - char buffer[100]; - - test::sprintf(buffer, "%20.5d", 1024); - REQUIRE(!strcmp(buffer, " 01024")); - - test::sprintf(buffer, "%20.5d", -1024); - REQUIRE(!strcmp(buffer, " -01024")); - - test::sprintf(buffer, "%20.5i", 1024); - REQUIRE(!strcmp(buffer, " 01024")); - - test::sprintf(buffer, "%20.5i", -1024); - REQUIRE(!strcmp(buffer, " -01024")); - - test::sprintf(buffer, "%20.5u", 1024); - REQUIRE(!strcmp(buffer, " 01024")); - - test::sprintf(buffer, "%20.5u", 4294966272U); - REQUIRE(!strcmp(buffer, " 4294966272")); - - test::sprintf(buffer, "%20.5o", 511); - REQUIRE(!strcmp(buffer, " 00777")); - - test::sprintf(buffer, "%20.5o", 4294966785U); - REQUIRE(!strcmp(buffer, " 37777777001")); - - test::sprintf(buffer, "%20.5x", 305441741); - REQUIRE(!strcmp(buffer, " 1234abcd")); - - test::sprintf(buffer, "%20.10x", 3989525555U); - REQUIRE(!strcmp(buffer, " 00edcb5433")); - - test::sprintf(buffer, "%20.5X", 305441741); - REQUIRE(!strcmp(buffer, " 1234ABCD")); - - test::sprintf(buffer, "%20.10X", 3989525555U); - REQUIRE(!strcmp(buffer, " 00EDCB5433")); -} - - -TEST_CASE("padding neg numbers", "[]" ) { - char buffer[100]; - - // space padding - test::sprintf(buffer, "% 1d", -5); - REQUIRE(!strcmp(buffer, "-5")); - - test::sprintf(buffer, "% 2d", -5); - REQUIRE(!strcmp(buffer, "-5")); - - test::sprintf(buffer, "% 3d", -5); - REQUIRE(!strcmp(buffer, " -5")); - - test::sprintf(buffer, "% 4d", -5); - REQUIRE(!strcmp(buffer, " -5")); - - // zero padding - test::sprintf(buffer, "%01d", -5); - REQUIRE(!strcmp(buffer, "-5")); - - test::sprintf(buffer, "%02d", -5); - REQUIRE(!strcmp(buffer, "-5")); - - test::sprintf(buffer, "%03d", -5); - REQUIRE(!strcmp(buffer, "-05")); - - test::sprintf(buffer, "%04d", -5); - REQUIRE(!strcmp(buffer, "-005")); -} - - -TEST_CASE("float padding neg numbers", "[]" ) { - char buffer[100]; - - // space padding - test::sprintf(buffer, "% 3.1f", -5.); - REQUIRE(!strcmp(buffer, "-5.0")); - - test::sprintf(buffer, "% 4.1f", -5.); - REQUIRE(!strcmp(buffer, "-5.0")); - - test::sprintf(buffer, "% 5.1f", -5.); - REQUIRE(!strcmp(buffer, " -5.0")); - -#ifndef PRINTF_DISABLE_SUPPORT_EXPONENTIAL - test::sprintf(buffer, "% 6.1g", -5.); - REQUIRE(!strcmp(buffer, " -5")); - - test::sprintf(buffer, "% 6.1e", -5.); - REQUIRE(!strcmp(buffer, "-5.0e+00")); - - test::sprintf(buffer, "% 10.1e", -5.); - REQUIRE(!strcmp(buffer, " -5.0e+00")); -#endif - - // zero padding - test::sprintf(buffer, "%03.1f", -5.); - REQUIRE(!strcmp(buffer, "-5.0")); - - test::sprintf(buffer, "%04.1f", -5.); - REQUIRE(!strcmp(buffer, "-5.0")); - - test::sprintf(buffer, "%05.1f", -5.); - REQUIRE(!strcmp(buffer, "-05.0")); - - // zero padding no decimal point - test::sprintf(buffer, "%01.0f", -5.); - REQUIRE(!strcmp(buffer, "-5")); - - test::sprintf(buffer, "%02.0f", -5.); - REQUIRE(!strcmp(buffer, "-5")); - - test::sprintf(buffer, "%03.0f", -5.); - REQUIRE(!strcmp(buffer, "-05")); - -#ifndef PRINTF_DISABLE_SUPPORT_EXPONENTIAL - test::sprintf(buffer, "%010.1e", -5.); - REQUIRE(!strcmp(buffer, "-005.0e+00")); - - test::sprintf(buffer, "%07.0E", -5.); - REQUIRE(!strcmp(buffer, "-05E+00")); - - test::sprintf(buffer, "%03.0g", -5.); - REQUIRE(!strcmp(buffer, "-05")); -#endif -} - -TEST_CASE("length", "[]" ) { - char buffer[100]; - - test::sprintf(buffer, "%.0s", "Hello testing"); - REQUIRE(!strcmp(buffer, "")); - - test::sprintf(buffer, "%20.0s", "Hello testing"); - REQUIRE(!strcmp(buffer, " ")); - - test::sprintf(buffer, "%.s", "Hello testing"); - REQUIRE(!strcmp(buffer, "")); - - test::sprintf(buffer, "%20.s", "Hello testing"); - REQUIRE(!strcmp(buffer, " ")); - - test::sprintf(buffer, "%20.0d", 1024); - REQUIRE(!strcmp(buffer, " 1024")); - - test::sprintf(buffer, "%20.0d", -1024); - REQUIRE(!strcmp(buffer, " -1024")); - - test::sprintf(buffer, "%20.d", 0); - REQUIRE(!strcmp(buffer, " ")); - - test::sprintf(buffer, "%20.0i", 1024); - REQUIRE(!strcmp(buffer, " 1024")); - - test::sprintf(buffer, "%20.i", -1024); - REQUIRE(!strcmp(buffer, " -1024")); - - test::sprintf(buffer, "%20.i", 0); - REQUIRE(!strcmp(buffer, " ")); - - test::sprintf(buffer, "%20.u", 1024); - REQUIRE(!strcmp(buffer, " 1024")); - - test::sprintf(buffer, "%20.0u", 4294966272U); - REQUIRE(!strcmp(buffer, " 4294966272")); - - test::sprintf(buffer, "%20.u", 0U); - REQUIRE(!strcmp(buffer, " ")); - - test::sprintf(buffer, "%20.o", 511); - REQUIRE(!strcmp(buffer, " 777")); - - test::sprintf(buffer, "%20.0o", 4294966785U); - REQUIRE(!strcmp(buffer, " 37777777001")); - - test::sprintf(buffer, "%20.o", 0U); - REQUIRE(!strcmp(buffer, " ")); - - test::sprintf(buffer, "%20.x", 305441741); - REQUIRE(!strcmp(buffer, " 1234abcd")); - - test::sprintf(buffer, "%50.x", 305441741); - REQUIRE(!strcmp(buffer, " 1234abcd")); - - test::sprintf(buffer, "%50.x%10.u", 305441741, 12345); - REQUIRE(!strcmp(buffer, " 1234abcd 12345")); - - test::sprintf(buffer, "%20.0x", 3989525555U); - REQUIRE(!strcmp(buffer, " edcb5433")); - - test::sprintf(buffer, "%20.x", 0U); - REQUIRE(!strcmp(buffer, " ")); + TEST_SNPRINTF_N(("%d", 123456), 6); + TEST_SNPRINTF_N(("%.4s", "hello"), 4); + TEST_SNPRINTF_N(("%.0s", "goodbye"), 0); - test::sprintf(buffer, "%20.X", 305441741); - REQUIRE(!strcmp(buffer, " 1234ABCD")); - - test::sprintf(buffer, "%20.0X", 3989525555U); - REQUIRE(!strcmp(buffer, " EDCB5433")); - - test::sprintf(buffer, "%20.X", 0U); - REQUIRE(!strcmp(buffer, " ")); - - test::sprintf(buffer, "%02.0u", 0U); - REQUIRE(!strcmp(buffer, " ")); - - test::sprintf(buffer, "%02.0d", 0); - REQUIRE(!strcmp(buffer, " ")); -} - - -TEST_CASE("float", "[]" ) { - char buffer[100]; - - // test special-case floats using math.h macros - test::sprintf(buffer, "%8f", NAN); - REQUIRE(!strcmp(buffer, " nan")); - - test::sprintf(buffer, "%8f", INFINITY); - REQUIRE(!strcmp(buffer, " inf")); - - test::sprintf(buffer, "%-8f", -INFINITY); - REQUIRE(!strcmp(buffer, "-inf ")); - -#ifndef PRINTF_DISABLE_SUPPORT_EXPONENTIAL - test::sprintf(buffer, "%+8e", INFINITY); - REQUIRE(!strcmp(buffer, " +inf")); -#endif - - test::sprintf(buffer, "%.4f", 3.1415354); - REQUIRE(!strcmp(buffer, "3.1415")); - - test::sprintf(buffer, "%.3f", 30343.1415354); - REQUIRE(!strcmp(buffer, "30343.142")); - - test::sprintf(buffer, "%.0f", 34.1415354); - REQUIRE(!strcmp(buffer, "34")); - - test::sprintf(buffer, "%.0f", 1.3); - REQUIRE(!strcmp(buffer, "1")); - - test::sprintf(buffer, "%.0f", 1.55); - REQUIRE(!strcmp(buffer, "2")); - - test::sprintf(buffer, "%.1f", 1.64); - REQUIRE(!strcmp(buffer, "1.6")); - - test::sprintf(buffer, "%.2f", 42.8952); - REQUIRE(!strcmp(buffer, "42.90")); - - test::sprintf(buffer, "%.9f", 42.8952); - REQUIRE(!strcmp(buffer, "42.895200000")); - - test::sprintf(buffer, "%.10f", 42.895223); - REQUIRE(!strcmp(buffer, "42.8952230000")); - - // this testcase checks, that the precision is truncated to 9 digits. - // a perfect working float should return the whole number - test::sprintf(buffer, "%.12f", 42.89522312345678); - REQUIRE(!strcmp(buffer, "42.895223123000")); - - // this testcase checks, that the precision is truncated AND rounded to 9 digits. - // a perfect working float should return the whole number - test::sprintf(buffer, "%.12f", 42.89522387654321); - REQUIRE(!strcmp(buffer, "42.895223877000")); - - test::sprintf(buffer, "%6.2f", 42.8952); - REQUIRE(!strcmp(buffer, " 42.90")); - - test::sprintf(buffer, "%+6.2f", 42.8952); - REQUIRE(!strcmp(buffer, "+42.90")); - - test::sprintf(buffer, "%+5.1f", 42.9252); - REQUIRE(!strcmp(buffer, "+42.9")); - - test::sprintf(buffer, "%f", 42.5); - REQUIRE(!strcmp(buffer, "42.500000")); - - test::sprintf(buffer, "%.1f", 42.5); - REQUIRE(!strcmp(buffer, "42.5")); - - test::sprintf(buffer, "%f", 42167.0); - REQUIRE(!strcmp(buffer, "42167.000000")); - - test::sprintf(buffer, "%.9f", -12345.987654321); - REQUIRE(!strcmp(buffer, "-12345.987654321")); - - test::sprintf(buffer, "%.1f", 3.999); - REQUIRE(!strcmp(buffer, "4.0")); - - test::sprintf(buffer, "%.0f", 3.5); - REQUIRE(!strcmp(buffer, "4")); - - test::sprintf(buffer, "%.0f", 4.5); - REQUIRE(!strcmp(buffer, "4")); - - test::sprintf(buffer, "%.0f", 3.49); - REQUIRE(!strcmp(buffer, "3")); - - test::sprintf(buffer, "%.1f", 3.49); - REQUIRE(!strcmp(buffer, "3.5")); - - test::sprintf(buffer, "a%-5.1f", 0.5); - REQUIRE(!strcmp(buffer, "a0.5 ")); - - test::sprintf(buffer, "a%-5.1fend", 0.5); - REQUIRE(!strcmp(buffer, "a0.5 end")); - -#ifndef PRINTF_DISABLE_SUPPORT_EXPONENTIAL - test::sprintf(buffer, "%G", 12345.678); - REQUIRE(!strcmp(buffer, "12345.7")); - - test::sprintf(buffer, "%.7G", 12345.678); - REQUIRE(!strcmp(buffer, "12345.68")); - - test::sprintf(buffer, "%.5G", 123456789.); - REQUIRE(!strcmp(buffer, "1.2346E+08")); - - test::sprintf(buffer, "%.6G", 12345.); - REQUIRE(!strcmp(buffer, "12345.0")); - - test::sprintf(buffer, "%+12.4g", 123456789.); - REQUIRE(!strcmp(buffer, " +1.235e+08")); - - test::sprintf(buffer, "%.2G", 0.001234); - REQUIRE(!strcmp(buffer, "0.0012")); - - test::sprintf(buffer, "%+10.4G", 0.001234); - REQUIRE(!strcmp(buffer, " +0.001234")); - - test::sprintf(buffer, "%+012.4g", 0.00001234); - REQUIRE(!strcmp(buffer, "+001.234e-05")); - - test::sprintf(buffer, "%.3g", -1.2345e-308); - REQUIRE(!strcmp(buffer, "-1.23e-308")); - - test::sprintf(buffer, "%+.3E", 1.23e+308); - REQUIRE(!strcmp(buffer, "+1.230E+308")); -#endif - - // out of range for float: should switch to exp notation if supported, else empty - test::sprintf(buffer, "%.1f", 1E20); -#ifndef PRINTF_DISABLE_SUPPORT_EXPONENTIAL - REQUIRE(!strcmp(buffer, "1.0e+20")); -#else - REQUIRE(!strcmp(buffer, "")); -#endif - - // brute force float - bool fail = false; - std::stringstream str; - str.precision(5); - for (float i = -100000; i < 100000; i += 1) { - test::sprintf(buffer, "%.5f", i / 10000); - str.str(""); - str << std::fixed << i / 10000; - fail = fail || !!strcmp(buffer, str.str().c_str()); - } - REQUIRE(!fail); - - -#ifndef PRINTF_DISABLE_SUPPORT_EXPONENTIAL - // brute force exp - str.setf(std::ios::scientific, std::ios::floatfield); - for (float i = -1e20; i < 1e20; i += 1e15) { - test::sprintf(buffer, "%.5f", i); - str.str(""); - str << i; - fail = fail || !!strcmp(buffer, str.str().c_str()); - } - REQUIRE(!fail); -#endif -} - - -TEST_CASE("types", "[]" ) { - char buffer[100]; - - test::sprintf(buffer, "%i", 0); - REQUIRE(!strcmp(buffer, "0")); - - test::sprintf(buffer, "%i", 1234); - REQUIRE(!strcmp(buffer, "1234")); - - test::sprintf(buffer, "%i", 32767); - REQUIRE(!strcmp(buffer, "32767")); - - test::sprintf(buffer, "%i", -32767); - REQUIRE(!strcmp(buffer, "-32767")); - - test::sprintf(buffer, "%li", 30L); - REQUIRE(!strcmp(buffer, "30")); - - test::sprintf(buffer, "%li", -2147483647L); - REQUIRE(!strcmp(buffer, "-2147483647")); - - test::sprintf(buffer, "%li", 2147483647L); - REQUIRE(!strcmp(buffer, "2147483647")); - - test::sprintf(buffer, "%lli", 30LL); - REQUIRE(!strcmp(buffer, "30")); - - test::sprintf(buffer, "%lli", -9223372036854775807LL); - REQUIRE(!strcmp(buffer, "-9223372036854775807")); - - test::sprintf(buffer, "%lli", 9223372036854775807LL); - REQUIRE(!strcmp(buffer, "9223372036854775807")); - - test::sprintf(buffer, "%lu", 100000L); - REQUIRE(!strcmp(buffer, "100000")); - - test::sprintf(buffer, "%lu", 0xFFFFFFFFL); - REQUIRE(!strcmp(buffer, "4294967295")); - - test::sprintf(buffer, "%llu", 281474976710656LLU); - REQUIRE(!strcmp(buffer, "281474976710656")); - - test::sprintf(buffer, "%llu", 18446744073709551615LLU); - REQUIRE(!strcmp(buffer, "18446744073709551615")); - - test::sprintf(buffer, "%zu", 2147483647UL); - REQUIRE(!strcmp(buffer, "2147483647")); - - test::sprintf(buffer, "%zd", 2147483647UL); - REQUIRE(!strcmp(buffer, "2147483647")); - - if (sizeof(size_t) == sizeof(long)) { - test::sprintf(buffer, "%zi", -2147483647L); - REQUIRE(!strcmp(buffer, "-2147483647")); - } - else { - test::sprintf(buffer, "%zi", -2147483647LL); - REQUIRE(!strcmp(buffer, "-2147483647")); + { + char b[] = "xxxxxxxx"; + const char *s = "%d"; + int res = tested_snprintf(b, 4, s, 123456); + REQUIRE(res == 6); + REQUIRE_STR_EQ(b, "123"); + REQUIRE(b[5] == 'x'); // buffer overrun } - - test::sprintf(buffer, "%b", 60000); - REQUIRE(!strcmp(buffer, "1110101001100000")); - - test::sprintf(buffer, "%lb", 12345678L); - REQUIRE(!strcmp(buffer, "101111000110000101001110")); - - test::sprintf(buffer, "%o", 60000); - REQUIRE(!strcmp(buffer, "165140")); - - test::sprintf(buffer, "%lo", 12345678L); - REQUIRE(!strcmp(buffer, "57060516")); - - test::sprintf(buffer, "%lx", 0x12345678L); - REQUIRE(!strcmp(buffer, "12345678")); - - test::sprintf(buffer, "%llx", 0x1234567891234567LLU); - REQUIRE(!strcmp(buffer, "1234567891234567")); - - test::sprintf(buffer, "%lx", 0xabcdefabL); - REQUIRE(!strcmp(buffer, "abcdefab")); - - test::sprintf(buffer, "%lX", 0xabcdefabL); - REQUIRE(!strcmp(buffer, "ABCDEFAB")); - - test::sprintf(buffer, "%c", 'v'); - REQUIRE(!strcmp(buffer, "v")); - - test::sprintf(buffer, "%cv", 'w'); - REQUIRE(!strcmp(buffer, "wv")); - - test::sprintf(buffer, "%s", "A Test"); - REQUIRE(!strcmp(buffer, "A Test")); - - test::sprintf(buffer, "%hhu", 0xFFFFUL); - REQUIRE(!strcmp(buffer, "255")); - - test::sprintf(buffer, "%hu", 0x123456UL); - REQUIRE(!strcmp(buffer, "13398")); - - test::sprintf(buffer, "%s%hhi %hu", "Test", 10000, 0xFFFFFFFF); - REQUIRE(!strcmp(buffer, "Test16 65535")); - - test::sprintf(buffer, "%tx", &buffer[10] - &buffer[0]); - REQUIRE(!strcmp(buffer, "a")); - -// TBD - if (sizeof(intmax_t) == sizeof(long)) { - test::sprintf(buffer, "%ji", -2147483647L); - REQUIRE(!strcmp(buffer, "-2147483647")); - } - else { - test::sprintf(buffer, "%ji", -2147483647LL); - REQUIRE(!strcmp(buffer, "-2147483647")); - } -} - - -TEST_CASE("pointer", "[]" ) { - char buffer[100]; - - test::sprintf(buffer, "%p", (void*)0x1234U); - if (sizeof(void*) == 4U) { - REQUIRE(!strcmp(buffer, "00001234")); - } - else { - REQUIRE(!strcmp(buffer, "0000000000001234")); - } - - test::sprintf(buffer, "%p", (void*)0x12345678U); - if (sizeof(void*) == 4U) { - REQUIRE(!strcmp(buffer, "12345678")); - } - else { - REQUIRE(!strcmp(buffer, "0000000012345678")); - } - - test::sprintf(buffer, "%p-%p", (void*)0x12345678U, (void*)0x7EDCBA98U); - if (sizeof(void*) == 4U) { - REQUIRE(!strcmp(buffer, "12345678-7EDCBA98")); - } - else { - REQUIRE(!strcmp(buffer, "0000000012345678-000000007EDCBA98")); - } - - if (sizeof(uintptr_t) == sizeof(uint64_t)) { - test::sprintf(buffer, "%p", (void*)(uintptr_t)0xFFFFFFFFU); - REQUIRE(!strcmp(buffer, "00000000FFFFFFFF")); - } - else { - test::sprintf(buffer, "%p", (void*)(uintptr_t)0xFFFFFFFFU); - REQUIRE(!strcmp(buffer, "FFFFFFFF")); - } -} - - -TEST_CASE("unknown flag", "[]" ) { - char buffer[100]; - - test::sprintf(buffer, "%kmarco", 42, 37); - REQUIRE(!strcmp(buffer, "kmarco")); -} - - -TEST_CASE("string length", "[]" ) { - char buffer[100]; - - test::sprintf(buffer, "%.4s", "This is a test"); - REQUIRE(!strcmp(buffer, "This")); - - test::sprintf(buffer, "%.4s", "test"); - REQUIRE(!strcmp(buffer, "test")); - - test::sprintf(buffer, "%.7s", "123"); - REQUIRE(!strcmp(buffer, "123")); - - test::sprintf(buffer, "%.7s", ""); - REQUIRE(!strcmp(buffer, "")); - - test::sprintf(buffer, "%.4s%.2s", "123456", "abcdef"); - REQUIRE(!strcmp(buffer, "1234ab")); - - test::sprintf(buffer, "%.4.2s", "123456"); - REQUIRE(!strcmp(buffer, ".2s")); - - test::sprintf(buffer, "%.*s", 3, "123456"); - REQUIRE(!strcmp(buffer, "123")); -} - - -TEST_CASE("buffer length", "[]" ) { - char buffer[100]; - int ret; - - ret = test::snprintf(nullptr, 10, "%s", "Test"); - REQUIRE(ret == 4); - ret = test::snprintf(nullptr, 0, "%s", "Test"); - REQUIRE(ret == 4); - - buffer[0] = (char)0xA5; - ret = test::snprintf(buffer, 0, "%s", "Test"); - REQUIRE(buffer[0] == (char)0xA5); - REQUIRE(ret == 4); - - buffer[0] = (char)0xCC; - test::snprintf(buffer, 1, "%s", "Test"); - REQUIRE(buffer[0] == '\0'); - - test::snprintf(buffer, 2, "%s", "Hello"); - REQUIRE(!strcmp(buffer, "H")); -} - - -TEST_CASE("ret value", "[]" ) { - char buffer[100] ; - int ret; - - ret = test::snprintf(buffer, 6, "0%s", "1234"); - REQUIRE(!strcmp(buffer, "01234")); - REQUIRE(ret == 5); - - ret = test::snprintf(buffer, 6, "0%s", "12345"); - REQUIRE(!strcmp(buffer, "01234")); - REQUIRE(ret == 6); // '5' is truncated - - ret = test::snprintf(buffer, 6, "0%s", "1234567"); - REQUIRE(!strcmp(buffer, "01234")); - REQUIRE(ret == 8); // '567' are truncated - - ret = test::snprintf(buffer, 10, "hello, world"); - REQUIRE(ret == 12); - - ret = test::snprintf(buffer, 3, "%d", 10000); - REQUIRE(ret == 5); - REQUIRE(strlen(buffer) == 2U); - REQUIRE(buffer[0] == '1'); - REQUIRE(buffer[1] == '0'); - REQUIRE(buffer[2] == '\0'); -} - - -TEST_CASE("misc", "[]" ) { - char buffer[100]; - - test::sprintf(buffer, "%u%u%ctest%d %s", 5, 3000, 'a', -20, "bit"); - REQUIRE(!strcmp(buffer, "53000atest-20 bit")); - - test::sprintf(buffer, "%.*f", 2, 0.33333333); - REQUIRE(!strcmp(buffer, "0.33")); - - test::sprintf(buffer, "%.*d", -1, 1); - REQUIRE(!strcmp(buffer, "1")); - - test::sprintf(buffer, "%.3s", "foobar"); - REQUIRE(!strcmp(buffer, "foo")); - - test::sprintf(buffer, "% .0d", 0); - REQUIRE(!strcmp(buffer, " ")); - - test::sprintf(buffer, "%10.5d", 4); - REQUIRE(!strcmp(buffer, " 00004")); - - test::sprintf(buffer, "%*sx", -3, "hi"); - REQUIRE(!strcmp(buffer, "hi x")); - -#ifndef PRINTF_DISABLE_SUPPORT_EXPONENTIAL - test::sprintf(buffer, "%.*g", 2, 0.33333333); - REQUIRE(!strcmp(buffer, "0.33")); - - test::sprintf(buffer, "%.*e", 2, 0.33333333); - REQUIRE(!strcmp(buffer, "3.33e-01")); -#endif }