#define _CRT_SECURE_NO_WARNINGS #include #include #include #include "../archive/test.h" #include "libipc/imp/fmt.h" #include "libipc/imp/byte.h" #include "libipc/imp/span.h" #include "libipc/imp/result.h" TEST(fmt, spec) { EXPECT_STREQ(ipc::spec("hello")(123).fstr.data(), "hello"); EXPECT_EQ(ipc::spec("hello")(123).param , 123); EXPECT_STREQ(ipc::spec("hello")("world").fstr.data(), "hello"); EXPECT_STREQ(ipc::spec("hello")("world").param , "world"); } TEST(fmt, to_string) { std::string joined; ipc::fmt_context ctx(joined); auto check = [&](auto &&txt, auto &&...val) { ctx.reset(); EXPECT_TRUE(ipc::to_string(ctx, std::forward(val)...)); ctx.finish(); EXPECT_EQ(joined, std::forward(txt)); }; /// \brief string check("", ""); check("%what%", "%what%"); check(" %what%", "%what%", "10"); check("%what% ", "%what%", "-10"); /// \brief character check("A", 'A'); check("A", L'A'); check("A", u'A'); check("A", U'A'); /// \brief numeric check("123" , (signed char)123 ); check("-65" , (signed char)-321 ); check("123" , (unsigned char)123 ); check("65" , (unsigned char)321 ); check("123" , (short)123 ); check("-321" , (short)-321 ); check("123" , (unsigned short)123 ); check("321" , (unsigned short)321 ); check("-7949" , (short)123123 ); check("6359" , (short)-321321 ); check("57587" , (unsigned short)123123); check("59177" , (unsigned short)321321); check("123123" , 123123 ); check("-321321" , -321321 ); check("123123" , 123123u ); check("321321" , 321321u ); check("123123" , 123123ll ); check("-321321" , -321321ll ); check("123123" , 123123ull ); check("321321" , 321321ull ); check("1e0f3" , 123123, "x" ); check("1e0f3" , 123123u, "x" ); check("1CAAB5C3B3", 123123123123ll, "X" ); check("1CAAB5C3B3", 123123123123ull, "X" ); /// \brief floating point check("123.123" , 123.123f, ".3"); check("0123.12300" , 123.123, "010.5"); check("123.123000" , 123.123l, "010.6"); check("1.500000e+00", 1.5, "e"); check("1.500000E+00", 1.5, "E"); double r = 0.0; ctx.reset(); EXPECT_TRUE(ipc::to_string(ctx, 0.0/r)); ctx.finish(); std::cout << joined << "\n"; ctx.reset(); EXPECT_TRUE(ipc::to_string(ctx, 1.0/r)); ctx.finish(); std::cout << joined << "\n"; /// \brief pointer check("null", nullptr); int *p = (int *)0x0f013a04; ctx.reset(); EXPECT_TRUE(ipc::to_string(ctx, (void *)p)); ctx.finish(); std::cout << joined << "\n"; /// \brief date and time auto tp = std::chrono::system_clock::now(); auto tt = std::chrono::system_clock::to_time_t(tp); auto tm = *std::localtime(&tt); ctx.reset(); EXPECT_TRUE(ipc::to_string(ctx, tm)); ctx.finish(); std::cout << joined << "\n"; std::string tm_str = joined; ctx.reset(); EXPECT_TRUE(ipc::to_string(ctx, tp)); ctx.finish(); EXPECT_EQ(tm_str, joined); } TEST(fmt, fmt) { char const txt[] = "hello world."; /// \brief hello world auto s = ipc::fmt("hello", " ", "world", "."); EXPECT_EQ(s, txt); /// \brief chrono std::cout << ipc::fmt('[', std::chrono::system_clock::now(), "] ", s) << "\n"; /// \brief long string s = ipc::fmt(ipc::spec("4096")(txt)); std::string test(4096, ' '); std::memcpy(&test[test.size() - sizeof(txt) + 1], txt, sizeof(txt) - 1); EXPECT_EQ(s, test); EXPECT_EQ(ipc::fmt("", 1, "", '2', "", 3.0), "123.000000"); char const * nc = nullptr; EXPECT_EQ(ipc::fmt(nc, 1, "", '2', "", 3.0), "123.000000"); std::string empty; EXPECT_EQ(ipc::fmt(empty, 1, "", '2', "", 3.0), "123.000000"); } namespace { class foo {}; bool tag_invoke(decltype(ipc::fmt_to), ipc::fmt_context &, foo arg) noexcept(false) { throw arg; return {}; } } // namespace TEST(fmt, throw) { EXPECT_THROW(std::ignore = ipc::fmt(foo{}), foo); } TEST(fmt, byte) { { ipc::byte b1{}, b2(31); EXPECT_EQ(ipc::fmt(b1), "00"); EXPECT_EQ(ipc::fmt(b2), "1f"); EXPECT_EQ(ipc::fmt(ipc::spec("03X")(b2)), "01F"); } { ipc::byte bs[] {31, 32, 33, 34, 35, 36, 37, 38}; EXPECT_EQ(ipc::fmt(ipc::make_span(bs)), "1f 20 21 22 23 24 25 26"); } } TEST(fmt, span) { EXPECT_EQ(ipc::fmt(ipc::span{}), ""); EXPECT_EQ(ipc::fmt(ipc::make_span({1, 3, 2, 4, 5, 6, 7})), "1 3 2 4 5 6 7"); } TEST(fmt, result) { { ipc::result r1; EXPECT_EQ(ipc::fmt(r1), ipc::fmt("fail, error = ", std::error_code(-1, std::generic_category()))); ipc::result r2(65537); EXPECT_EQ(ipc::fmt(r2), "succ, value = 65537"); ipc::result r3(0); EXPECT_EQ(ipc::fmt(r3), "succ, value = 0"); } { ipc::result r0; EXPECT_EQ(ipc::fmt(r0), ipc::fmt(ipc::result())); ipc::result r1 {std::error_code(-1, std::generic_category())}; EXPECT_EQ(ipc::fmt(r1), ipc::fmt("fail, error = ", std::error_code(-1, std::generic_category()))); ipc::result r2 {&r1}; EXPECT_EQ(ipc::fmt(r2), ipc::fmt("succ, value = ", (void *)&r1)); int aaa {}; ipc::result r3 {&aaa}; EXPECT_EQ(ipc::fmt(r3), ipc::fmt("succ, value = ", (void *)&aaa)); ipc::result r4 {nullptr}; EXPECT_EQ(ipc::fmt(r4), ipc::fmt("fail, error = ", std::error_code(-1, std::generic_category()))); r4 = std::error_code(1234, std::generic_category()); EXPECT_EQ(ipc::fmt(r4), ipc::fmt("fail, error = ", std::error_code(1234, std::generic_category()))); ipc::result r5; EXPECT_EQ(ipc::fmt(r5), ipc::fmt("fail, error = ", std::error_code(-1, std::generic_category()))); } { ipc::result r1 {-123}; EXPECT_EQ(ipc::fmt(r1), ipc::fmt("succ, value = ", -123)); } { ipc::result r1; EXPECT_EQ(ipc::fmt(r1), ipc::fmt("fail, error = ", std::error_code(-1, std::generic_category()))); r1 = std::error_code{}; EXPECT_TRUE(r1); EXPECT_EQ(ipc::fmt(r1), ipc::fmt("succ, error = ", std::error_code())); } } /// \brief Test case for issue #171: Compiler failures under MinGW /// \see https://github.com/mutouyun/cpp-ipc/issues/171 /// /// The issue is that std::hex and std::dec (I/O manipulators) were incorrectly /// used with ipc::fmt. These are function pointers of type: /// std::ios_base& (*)(std::ios_base&) /// which ipc::fmt does not support. /// /// The correct way to output hexadecimal values with ipc::fmt is to use ipc::spec. TEST(fmt, hex_output_with_spec) { /// \brief Basic hexadecimal formatting using ipc::spec /// This is the correct way to format hex values (instead of std::hex) { unsigned int val = 255; EXPECT_EQ(ipc::fmt(ipc::spec("x")(val)), "ff"); EXPECT_EQ(ipc::fmt(ipc::spec("X")(val)), "FF"); EXPECT_EQ(ipc::fmt(ipc::spec("08x")(val)), "000000ff"); EXPECT_EQ(ipc::fmt(ipc::spec("08X")(val)), "000000FF"); } /// \brief Hex formatting with prefix (simulating "0x" prefix like std::hex would produce) { unsigned int val = 0xDEADBEEF; // Correct way: use string concatenation with ipc::spec for hex format EXPECT_EQ(ipc::fmt("0x", ipc::spec("x")(val)), "0xdeadbeef"); EXPECT_EQ(ipc::fmt("0x", ipc::spec("X")(val)), "0xDEADBEEF"); EXPECT_EQ(ipc::fmt("0x", ipc::spec("08x")(val)), "0xdeadbeef"); } /// \brief Mixed decimal and hex output (simulating the problematic log pattern from issue #171) /// Original problematic code pattern was: /// log.error("fail WaitForSingleObject[", ::GetLastError(), "]: 0x", std::hex, ret, std::dec); /// Correct pattern should be: /// log.error("fail WaitForSingleObject[", ::GetLastError(), "]: ", ipc::spec("08x")(ret)); { unsigned long error_code = 5; // ERROR_ACCESS_DENIED unsigned int ret = 0x00000102; // WAIT_TIMEOUT value // Correct way to format the log message auto msg = ipc::fmt("fail WaitForSingleObject[", error_code, "]: ", ipc::spec("08x")(ret)); EXPECT_EQ(msg, "fail WaitForSingleObject[5]: 00000102"); // Alternative with "0x" prefix auto msg2 = ipc::fmt("fail WaitForSingleObject[", error_code, "]: 0x", ipc::spec("x")(ret)); EXPECT_EQ(msg2, "fail WaitForSingleObject[5]: 0x102"); } /// \brief Various integer types with hex formatting /// Note: ipc::spec format string should NOT include length modifiers (like "ll"). /// The to_string function automatically adds the correct length modifier based on /// the argument type. Just use "x" or "X" for hex conversion. { EXPECT_EQ(ipc::fmt(ipc::spec("x")((unsigned char)0xAB)), "ab"); EXPECT_EQ(ipc::fmt(ipc::spec("x")((unsigned short)0xABCD)), "abcd"); EXPECT_EQ(ipc::fmt(ipc::spec("x")((unsigned int)0xABCDEF01)), "abcdef01"); EXPECT_EQ(ipc::fmt(ipc::spec("x")((unsigned long)0xABCDEF01)), "abcdef01"); // For unsigned long long, just use "x" - the length modifier is added automatically EXPECT_EQ(ipc::fmt(ipc::spec("x")((unsigned long long)0xABCDEF0123456789ULL)), "abcdef0123456789"); } /// \brief Width and padding with hex { unsigned int val = 0x1F; EXPECT_EQ(ipc::fmt(ipc::spec("2x")(val)), "1f"); EXPECT_EQ(ipc::fmt(ipc::spec("4x")(val)), " 1f"); EXPECT_EQ(ipc::fmt(ipc::spec("04x")(val)), "001f"); EXPECT_EQ(ipc::fmt(ipc::spec("8x")(val)), " 1f"); EXPECT_EQ(ipc::fmt(ipc::spec("08x")(val)), "0000001f"); } }