diff --git a/test/test_format/format.cpp b/test/test_format/format.cpp index d2bdbbc..3ff3530 100644 --- a/test/test_format/format.cpp +++ b/test/test_format/format.cpp @@ -7,287 +7,168 @@ #include #include "test_format.hpp" -TEST(format, plain_text) +TYPED_TEST(format_suite, plain_text) { using namespace papilio; - EXPECT_EQ(PAPILIO_NS format(""), ""); - EXPECT_EQ(PAPILIO_NS format("plain text"), "plain text"); - EXPECT_EQ(PAPILIO_NS format("{{plain text}}"), "{plain text}"); - - EXPECT_EQ(PAPILIO_NS format(L""), L""); - EXPECT_EQ(PAPILIO_NS format(L"plain text"), L"plain text"); - EXPECT_EQ(PAPILIO_NS format(L"{{plain text}}"), L"{plain text}"); -} - -TEST(format, format_to) -{ - using namespace papilio; + using string_view_type = typename TestFixture::string_view_type; { - std::vector result; - auto it = PAPILIO_NS format_to(std::back_inserter(result), "vec"); - *it = '\0'; - EXPECT_EQ(result.size(), 4); - EXPECT_STREQ(result.data(), "vec"); - } - - { - auto loc = test_format::attach_yes_no(); - - std::vector result; - auto it = PAPILIO_NS format_to(std::back_inserter(result), loc, "{:L}", true); - *it = '\0'; - EXPECT_EQ(result.size(), 4); - EXPECT_STREQ(result.data(), "yes"); - } -} + string_view_type empty_fmt{}; -TEST(format, formatted_size) -{ - using namespace papilio; - - EXPECT_EQ(PAPILIO_NS formatted_size(""), 0); - EXPECT_EQ(PAPILIO_NS formatted_size("hello"), 5); - EXPECT_EQ(PAPILIO_NS formatted_size("{{hello}}"), 7); - - { - auto loc = test_format::attach_yes_no(); - EXPECT_EQ(PAPILIO_NS formatted_size(loc, "{:L}", true), 3); + EXPECT_EQ( + PAPILIO_NS format(empty_fmt), + string_view_type() + ); } -} - -TEST(format, format_to_n) -{ - using namespace papilio; { - std::string str; - str.resize(5); - auto result = PAPILIO_NS format_to_n(str.begin(), str.size(), "hello world"); + string_view_type plain_text = PAPILIO_TSTRING_VIEW(TypeParam, "plain text"); - EXPECT_EQ(result.out, str.begin() + str.size()); - EXPECT_EQ(result.size, str.size()); - EXPECT_EQ(result.size, 5); - EXPECT_EQ(str, "hello"); + EXPECT_EQ( + PAPILIO_NS format(plain_text), + plain_text + ); } { - auto loc = test_format::attach_yes_no(); + string_view_type esc_seq = PAPILIO_TSTRING_VIEW(TypeParam, "{{plain text}}"); + string_view_type expected_str = PAPILIO_TSTRING_VIEW(TypeParam, "{plain text}"); - std::string str; - str.resize(4); - auto result = PAPILIO_NS format_to_n(str.begin(), str.size(), loc, "{:L}!!", true); - - EXPECT_EQ(result.out, str.begin() + str.size()); - EXPECT_EQ(result.size, str.size()); - EXPECT_EQ(result.size, 4); - EXPECT_EQ(str, "yes!"); + EXPECT_EQ( + PAPILIO_NS format(esc_seq), + expected_str + ); } } -TEST(format, exception) +TYPED_TEST(format_suite, format_to) { using namespace papilio; - EXPECT_THROW((void)PAPILIO_NS format("{"), papilio::format_error); - EXPECT_THROW((void)PAPILIO_NS format("}"), papilio::format_error); -} - -TEST(format, script) -{ - using namespace papilio; - - EXPECT_EQ(PAPILIO_NS format("{$ {}: 'true'}", 1), "true"); - EXPECT_EQ(PAPILIO_NS format("{$ !{}: 'false'}", 0), "false"); - EXPECT_EQ(PAPILIO_NS format("{$ {val}: 'true'}", "val"_a = 1), "true"); - - EXPECT_EQ(PAPILIO_NS format("{$ {} == {}: 'eq'}", 1, 1), "eq"); - EXPECT_EQ(PAPILIO_NS format("{$ {} != {}: 'ne'}", 1, 2), "ne"); - - EXPECT_EQ(PAPILIO_NS format("{$ {} > {}: 'gt'}", 2, 1), "gt"); - EXPECT_EQ(PAPILIO_NS format("{$ {} < {}: 'lt'}", 1, 2), "lt"); - - EXPECT_EQ(PAPILIO_NS format("{$ {} >= {}: 'ge'}", 2, 1), "ge"); - EXPECT_EQ(PAPILIO_NS format("{$ {} <= {}: 'le'}", 1, 2), "le"); - EXPECT_EQ(PAPILIO_NS format("{$ {} >= {}: 'ge'}", 1, 1), "ge"); - EXPECT_EQ(PAPILIO_NS format("{$ {} <= {}: 'le'}", 1, 1), "le"); - { - std::string_view script = "{$ {}: 'a': ${}: 'b' : 'c'}"; + const auto vec_str = PAPILIO_TSTRING(TypeParam, "vec"); - EXPECT_EQ(PAPILIO_NS format(script, true, true), "a"); - EXPECT_EQ(PAPILIO_NS format(script, true, false), "a"); - EXPECT_THROW((void)PAPILIO_NS format(script, true), std::out_of_range); + std::vector result; + auto it = PAPILIO_NS format_to( + std::back_inserter(result), + vec_str + ); + *it = '\0'; - EXPECT_EQ(PAPILIO_NS format(script, false, true), "b"); - EXPECT_EQ(PAPILIO_NS format(script, false, false), "c"); + EXPECT_EQ(result.size(), 4); + EXPECT_STREQ(result.data(), vec_str); } { - std::string_view script = "{$ {}: 'a': ${}: 'b' : ${} : 'c'}"; + std::locale loc = test_format::attach_yes_no(); - EXPECT_EQ(PAPILIO_NS format(script, true, true, false), "a"); - EXPECT_EQ(PAPILIO_NS format(script, true, false, false), "a"); + std::vector result; + auto it = PAPILIO_NS format_to( + std::back_inserter(result), + loc, + PAPILIO_TSTRING_VIEW(TypeParam, "{:L}"), + true + ); + *it = '\0'; - EXPECT_EQ(PAPILIO_NS format(script, false, true, true), "b"); - EXPECT_EQ(PAPILIO_NS format(script, false, false, true), "c"); - EXPECT_EQ(PAPILIO_NS format(script, false, false, false), ""); + EXPECT_EQ(result.size(), 4); + EXPECT_STREQ( + result.data(), + test_format::yes_no_numpunct::yes_string + ); } } -TEST(format, composite) +TYPED_TEST(format_suite, formatted_size) { using namespace papilio; - EXPECT_EQ(PAPILIO_NS format("{} {}", 182375, 182376), "182375 182376"); - - EXPECT_EQ(PAPILIO_NS format("{.length:*>4}", "hello"), "***5"); - EXPECT_EQ(PAPILIO_NS format("length is {.length}", "hello"), "length is 5"); - - { - std::string_view fmt = "{0} warning{${0}>1:'s'}"; - - EXPECT_EQ(PAPILIO_NS format(fmt, 1), "1 warning"); - EXPECT_EQ(PAPILIO_NS format(fmt, 2), "2 warnings"); - } - - { - std::string_view fmt = - "There" - " {${0} != 1: 'are' : 'is'} " - "{0}" - " apple{${0} != 1: 's'}"; - - EXPECT_EQ(PAPILIO_NS format(fmt, 1), "There is 1 apple"); - EXPECT_EQ(PAPILIO_NS format(fmt, 2), "There are 2 apples"); - } - - { - std::string_view fmt = "{${0}==0: 'zero' : {0}}"; + using string_view_type = typename TestFixture::string_view_type; - EXPECT_EQ(PAPILIO_NS format(fmt, 0), "zero"); - EXPECT_EQ(PAPILIO_NS format(fmt, 1), "1"); - EXPECT_EQ(PAPILIO_NS format(fmt, 2), "2"); - } -} + EXPECT_EQ(PAPILIO_NS formatted_size(string_view_type()), 0); -namespace test_format -{ -class stream_only -{ -public: - friend std::ostream& operator<<(std::ostream& os, const stream_only&) { - os << "stream only"; - return os; + string_view_type fmt = PAPILIO_TSTRING_VIEW(TypeParam, "hello"); + EXPECT_EQ(PAPILIO_NS formatted_size(fmt), 5); } - friend std::wostream& operator<<(std::wostream& os, const stream_only&) { - os << L"stream only"; - return os; + string_view_type fmt = PAPILIO_TSTRING_VIEW(TypeParam, "{{hello}}"); + EXPECT_EQ(PAPILIO_NS formatted_size(fmt), 7); // Size of "{hello}" } -}; -} // namespace test_format - -TEST(format, ostream_compat) -{ - using namespace papilio; { - test_format::stream_only val; + std::locale loc = test_format::attach_yes_no(); - EXPECT_EQ(PAPILIO_NS format("{}", val), "stream only"); + string_view_type fmt = PAPILIO_TSTRING_VIEW(TypeParam, "{:L}"); + EXPECT_EQ(PAPILIO_NS formatted_size(loc, fmt, true), 3); // Size of "yes" } } -TEST(format, wchar_t) +TYPED_TEST(format_suite, format_to_n) { using namespace papilio; - EXPECT_EQ(PAPILIO_NS format(L""), L""); - EXPECT_EQ(PAPILIO_NS format(L"plain text"), L"plain text"); - EXPECT_EQ(PAPILIO_NS format(L"{{plain text}}"), L"{plain text}"); - - EXPECT_EQ(PAPILIO_NS format(L"{.length:*>4}", L"hello"), L"***5"); - EXPECT_EQ(PAPILIO_NS format(L"length is {.length}", L"hello"), L"length is 5"); - - { - std::vector result; - auto it = PAPILIO_NS format_to(std::back_inserter(result), L"vec"); - *it = L'\0'; - EXPECT_EQ(result.size(), 4); - EXPECT_STREQ(result.data(), L"vec"); - } - - { - auto loc = test_format::attach_yes_no(); - - std::vector result; - auto it = PAPILIO_NS format_to(std::back_inserter(result), loc, L"{:L}", true); - *it = L'\0'; - EXPECT_EQ(result.size(), 4); - EXPECT_STREQ(result.data(), L"yes"); - } + using string_type = typename TestFixture::string_type; + using string_view_type = typename TestFixture::string_view_type; { - std::wstring str; + string_type str{}; str.resize(5); - auto result = PAPILIO_NS format_to_n(str.begin(), str.size(), L"hello world"); + auto result = PAPILIO_NS format_to_n( + str.begin(), + str.size(), + PAPILIO_TSTRING_VIEW(TypeParam, "hello world") + ); EXPECT_EQ(result.out, str.begin() + str.size()); EXPECT_EQ(result.size, str.size()); EXPECT_EQ(result.size, 5); - EXPECT_EQ(str, L"hello"); + + const auto expected_str = PAPILIO_TSTRING_VIEW(TypeParam, "hello"); + EXPECT_EQ(str, expected_str); } { - auto loc = test_format::attach_yes_no(); + std::locale loc = test_format::attach_yes_no(); - std::wstring str; + string_type str{}; str.resize(4); - auto result = PAPILIO_NS format_to_n(str.begin(), str.size(), loc, L"{:L}!!", true); + auto result = PAPILIO_NS format_to_n( + str.begin(), + str.size(), + loc, + PAPILIO_TSTRING_VIEW(TypeParam, "{:L}!!"), + true + ); EXPECT_EQ(result.out, str.begin() + str.size()); EXPECT_EQ(result.size, str.size()); EXPECT_EQ(result.size, 4); - EXPECT_EQ(str, L"yes!"); - } - - EXPECT_EQ(PAPILIO_NS formatted_size(L""), 0); - EXPECT_EQ(PAPILIO_NS formatted_size(L"hello"), 5); - EXPECT_EQ(PAPILIO_NS formatted_size(L"{{hello}}"), 7); - - { - test_format::stream_only val; - EXPECT_EQ(PAPILIO_NS format(L"{}", val), L"stream only"); + const auto expected_str = PAPILIO_TSTRING_VIEW(TypeParam, "yes!"); + EXPECT_EQ(str, expected_str); } +} - { - std::wstring_view fmt = L"{0} warning{${0}>1:'s'}"; - - EXPECT_EQ(PAPILIO_NS format(fmt, 1), L"1 warning"); - EXPECT_EQ(PAPILIO_NS format(fmt, 2), L"2 warnings"); - } +TYPED_TEST(format_suite, exception) +{ + using namespace papilio; - { - std::wstring_view fmt = L"{${0}==0: 'zero' : {0}}"; + using string_view_type = typename TestFixture::string_view_type; - EXPECT_EQ(PAPILIO_NS format(fmt, 0), L"zero"); - EXPECT_EQ(PAPILIO_NS format(fmt, 1), L"1"); - EXPECT_EQ(PAPILIO_NS format(fmt, 2), L"2"); - } + const string_view_type bad_fmts[]{ + PAPILIO_TSTRING_VIEW(TypeParam, "{"), + PAPILIO_TSTRING_VIEW(TypeParam, "}") + }; + for(string_view_type f : bad_fmts) { - std::wstring_view script = L"{$ {}: 'a': ${}: 'b' : 'c'}"; - - EXPECT_EQ(PAPILIO_NS format(script, true, true), L"a"); - EXPECT_EQ(PAPILIO_NS format(script, true, false), L"a"); - EXPECT_THROW((void)PAPILIO_NS format(script, true), std::out_of_range); - - EXPECT_EQ(PAPILIO_NS format(script, false, true), L"b"); - EXPECT_EQ(PAPILIO_NS format(script, false, false), L"c"); + EXPECT_THROW( + (void)PAPILIO_NS format(f), + papilio::format_error + ) << "f = " + << std::quoted(utf::basic_string_ref(f).to_string()); } } diff --git a/test/test_format/formatter.cpp b/test/test_format/formatter.cpp index 70f69f2..3c93496 100644 --- a/test/test_format/formatter.cpp +++ b/test/test_format/formatter.cpp @@ -5,107 +5,160 @@ #include #include "test_format.hpp" -namespace test_format -{ -template -void test_int_formatter() +template +class int_formatter_suite : public ::testing::Test +{}; + +using int_types = ::testing::Types< + int, + unsigned int, + long long int, + unsigned long long int>; +TYPED_TEST_SUITE(int_formatter_suite, int_types); + +TYPED_TEST(int_formatter_suite, basic) { using namespace papilio; - EXPECT_EQ(PAPILIO_NS format("{}", T(0)), "0"); - EXPECT_EQ(PAPILIO_NS format(L"{}", T(0)), L"0"); + for(TypeParam i : {0, 1, 2, 7, 8, 15, 16}) + { + EXPECT_EQ( + PAPILIO_NS format("{}", i), + std::to_string(i) + ) << "i = " + << i; - EXPECT_EQ(PAPILIO_NS format("{:6}", T(42)), " 42"); - EXPECT_EQ(PAPILIO_NS format(L"{:6}", T(42)), L" 42"); + EXPECT_EQ( + PAPILIO_NS format(L"{}", i), + std::to_wstring(i) + ) << "i = " + << i; + } +} + +TYPED_TEST(int_formatter_suite, fill_and_align) +{ + using namespace papilio; - EXPECT_EQ(PAPILIO_NS format("{0:},{0:+},{0:-},{0: }", T(1)), "1,+1,1, 1"); - EXPECT_EQ(PAPILIO_NS format(L"{0:},{0:+},{0:-},{0: }", T(1)), L"1,+1,1, 1"); - if constexpr(std::is_signed_v) + EXPECT_EQ(PAPILIO_NS format("{:6}", TypeParam(42)), " 42"); + EXPECT_EQ(PAPILIO_NS format(L"{:6}", TypeParam(42)), L" 42"); + + EXPECT_EQ(PAPILIO_NS format("{0:},{0:+},{0:-},{0: }", TypeParam(1)), "1,+1,1, 1"); + EXPECT_EQ(PAPILIO_NS format(L"{0:},{0:+},{0:-},{0: }", TypeParam(1)), L"1,+1,1, 1"); + if constexpr(std::is_signed_v) { - EXPECT_EQ(PAPILIO_NS format("{0:},{0:+},{0:-},{0: }", T(-1)), "-1,-1,-1,-1"); - EXPECT_EQ(PAPILIO_NS format(L"{0:},{0:+},{0:-},{0: }", T(-1)), L"-1,-1,-1,-1"); + EXPECT_EQ(PAPILIO_NS format("{0:},{0:+},{0:-},{0: }", TypeParam(-1)), "-1,-1,-1,-1"); + EXPECT_EQ(PAPILIO_NS format(L"{0:},{0:+},{0:-},{0: }", TypeParam(-1)), L"-1,-1,-1,-1"); } - EXPECT_EQ(PAPILIO_NS format("{:+06d}", T(42)), "+00042"); - EXPECT_EQ(PAPILIO_NS format(L"{:+06d}", T(42)), L"+00042"); - EXPECT_EQ(PAPILIO_NS format("{:#06x}", T(0xa)), "0x000a"); - EXPECT_EQ(PAPILIO_NS format(L"{:#06x}", T(0xa)), L"0x000a"); - if constexpr(std::is_signed_v) + EXPECT_EQ(PAPILIO_NS format("{:+06d}", TypeParam(42)), "+00042"); + EXPECT_EQ(PAPILIO_NS format(L"{:+06d}", TypeParam(42)), L"+00042"); + EXPECT_EQ(PAPILIO_NS format("{:#06x}", TypeParam(0xa)), "0x000a"); + EXPECT_EQ(PAPILIO_NS format(L"{:#06x}", TypeParam(0xa)), L"0x000a"); + if constexpr(std::is_signed_v) { - EXPECT_EQ(PAPILIO_NS format("{:<06}", T(-42)), "-42 "); - EXPECT_EQ(PAPILIO_NS format(L"{:<06}", T(-42)), L"-42 "); + EXPECT_EQ(PAPILIO_NS format("{:<06}", TypeParam(-42)), "-42 "); + EXPECT_EQ(PAPILIO_NS format(L"{:<06}", TypeParam(-42)), L"-42 "); } - EXPECT_EQ(PAPILIO_NS format("{:{}d}", T(42), 4), " 42"); - EXPECT_EQ(PAPILIO_NS format(L"{:{}d}", T(42), 4), L" 42"); + EXPECT_EQ(PAPILIO_NS format("{:{}d}", TypeParam(42), 4), " 42"); + EXPECT_EQ(PAPILIO_NS format(L"{:{}d}", TypeParam(42), 4), L" 42"); - EXPECT_EQ(PAPILIO_NS format("{:d>6}", T(42)), "dddd42"); - EXPECT_EQ(PAPILIO_NS format(L"{:d>6}", T(42)), L"dddd42"); + EXPECT_EQ(PAPILIO_NS format("{:d>6}", TypeParam(42)), "dddd42"); + EXPECT_EQ(PAPILIO_NS format(L"{:d>6}", TypeParam(42)), L"dddd42"); - EXPECT_EQ(PAPILIO_NS format("{:^5c}", T(97)), " a "); - EXPECT_EQ(PAPILIO_NS format(L"{:^5c}", T(97)), L" a "); + EXPECT_EQ(PAPILIO_NS format("{:^5c}", TypeParam(97)), " a "); + EXPECT_EQ(PAPILIO_NS format(L"{:^5c}", TypeParam(97)), L" a "); } -template -void test_float_formatter() +template +class float_formatter_suite : public ::testing::Test { - using namespace papilio; - - EXPECT_EQ(PAPILIO_NS format("{}", T(3.14L)), "3.14"); - EXPECT_EQ(PAPILIO_NS format(L"{}", T(3.14L)), L"3.14"); - +public: + static T create_inf() noexcept { - const T inf = std::numeric_limits::infinity(); - - EXPECT_EQ(PAPILIO_NS format("{0:},{0:+},{0:-},{0: }", inf), "inf,+inf,inf, inf"); - EXPECT_EQ(PAPILIO_NS format(L"{0:},{0:+},{0:-},{0: }", inf), L"inf,+inf,inf, inf"); - - EXPECT_EQ(PAPILIO_NS format("{0:},{0:+},{0:-},{0: }", -inf), "-inf,-inf,-inf,-inf"); - EXPECT_EQ(PAPILIO_NS format(L"{0:},{0:+},{0:-},{0: }", -inf), L"-inf,-inf,-inf,-inf"); + return std::numeric_limits::infinity(); } + static T create_nan() noexcept { - const T nan = std::numeric_limits::quiet_NaN(); - - EXPECT_EQ(PAPILIO_NS format("{}", nan), "nan"); - EXPECT_EQ(PAPILIO_NS format(L"{}", nan), L"nan"); + return std::numeric_limits::quiet_NaN(); } -} -} // namespace test_format +}; -TEST(formatter, int) +using float_types = ::testing::Types; +TYPED_TEST_SUITE(float_formatter_suite, float_types); + +TYPED_TEST(float_formatter_suite, basic) { - using test_format::test_int_formatter; + using namespace papilio; - test_int_formatter(); - test_int_formatter(); - test_int_formatter(); - test_int_formatter(); + EXPECT_EQ(PAPILIO_NS format("{}", TypeParam(0.0L)), "0"); + EXPECT_EQ(PAPILIO_NS format(L"{}", TypeParam(0.0L)), L"0"); + + EXPECT_EQ(PAPILIO_NS format("{}", TypeParam(-0.0L)), "-0"); + EXPECT_EQ(PAPILIO_NS format(L"{}", TypeParam(-0.0L)), L"-0"); + + EXPECT_EQ(PAPILIO_NS format("{}", TypeParam(3.14L)), "3.14"); + EXPECT_EQ(PAPILIO_NS format(L"{}", TypeParam(3.14L)), L"3.14"); + + EXPECT_EQ(PAPILIO_NS format("{}", TypeParam(-3.14L)), "-3.14"); + EXPECT_EQ(PAPILIO_NS format(L"{}", TypeParam(-3.14L)), L"-3.14"); } -TEST(formatter, float) +TYPED_TEST(float_formatter_suite, fill_and_align) { - using test_format::test_float_formatter; + if constexpr(std::is_same_v) + { + const float pi = 3.14f; - test_float_formatter(); - test_float_formatter(); - test_float_formatter(); + EXPECT_EQ(PAPILIO_NS format("{:10f}", pi), " 3.140000"); + EXPECT_EQ(PAPILIO_NS format(L"{:10f}", pi), L" 3.140000"); - using namespace papilio; + EXPECT_EQ(PAPILIO_NS format("{:.5f}", pi), "3.14000"); + EXPECT_EQ(PAPILIO_NS format(L"{:.5f}", pi), L"3.14000"); - const float pi = 3.14f; + EXPECT_EQ(PAPILIO_NS format("{:10.5f}", pi), " 3.14000"); + EXPECT_EQ(PAPILIO_NS format(L"{:10.5f}", pi), L" 3.14000"); + } - EXPECT_EQ(PAPILIO_NS format("{:10f}", pi), " 3.140000"); - EXPECT_EQ(PAPILIO_NS format(L"{:10f}", pi), L" 3.140000"); + { + const TypeParam inf = TestFixture::create_inf(); - EXPECT_EQ(PAPILIO_NS format("{:.5f}", pi), "3.14000"); - EXPECT_EQ(PAPILIO_NS format(L"{:.5f}", pi), L"3.14000"); + EXPECT_EQ( + PAPILIO_NS format("{0:},{0:+},{0:-},{0: }", inf), + "inf,+inf,inf, inf" + ); + EXPECT_EQ( + PAPILIO_NS format(L"{0:},{0:+},{0:-},{0: }", inf), + L"inf,+inf,inf, inf" + ); + + EXPECT_EQ( + PAPILIO_NS format("{0:},{0:+},{0:-},{0: }", -inf), + "-inf,-inf,-inf,-inf" + ); + EXPECT_EQ( + PAPILIO_NS format(L"{0:},{0:+},{0:-},{0: }", -inf), + L"-inf,-inf,-inf,-inf" + ); + } - EXPECT_EQ(PAPILIO_NS format("{:10.5f}", pi), " 3.14000"); - EXPECT_EQ(PAPILIO_NS format(L"{:10.5f}", pi), L" 3.14000"); + { + const TypeParam nan = TestFixture::create_nan(); + + EXPECT_EQ( + PAPILIO_NS format("{}", nan), + "nan" + ); + EXPECT_EQ( + PAPILIO_NS format(L"{}", nan), + L"nan" + ); + } } -TEST(formatter, codepoint) +TEST(fundamental_formatter, codepoint) { using namespace papilio; @@ -116,7 +169,7 @@ TEST(formatter, codepoint) EXPECT_EQ(PAPILIO_NS format(L"{:d}", L'a'), L"97"); } -TEST(formatter, string) +TEST(fundamental_formatter, string) { using namespace papilio; @@ -133,7 +186,7 @@ TEST(formatter, string) EXPECT_EQ(PAPILIO_NS format(L"{:^8.5}", L"hello!"), L" hello "); } -TEST(formatter, bool) +TEST(fundamental_formatter, bool) { using namespace papilio; @@ -148,19 +201,19 @@ TEST(formatter, bool) EXPECT_EQ(PAPILIO_NS format(L"{:#x}", true), L"0x1"); { - auto loc = test_format::attach_yes_no(); + std::locale loc = test_format::attach_yes_no(); EXPECT_EQ(PAPILIO_NS format(loc, "{:L}", true), "yes"); EXPECT_EQ(PAPILIO_NS format(loc, "{:L}", false), "no"); } { - auto loc = test_format::attach_yes_no(); + std::locale loc = test_format::attach_yes_no(); EXPECT_EQ(PAPILIO_NS format(loc, L"{:L}", true), L"yes"); EXPECT_EQ(PAPILIO_NS format(loc, L"{:L}", false), L"no"); } } -TEST(formatter, pointer) +TEST(fundamental_formatter, pointer) { using namespace papilio; @@ -211,7 +264,7 @@ TEST(formatter, pointer) } } -TEST(format, magic_enum) +TEST(fundamental_formatter, magic_enum) { using namespace papilio; @@ -229,48 +282,3 @@ TEST(format, magic_enum) EXPECT_EQ(PAPILIO_NS format(L"{}", dog), L"dog"); EXPECT_EQ(PAPILIO_NS format(L"{:d}", cat), L"1"); } - -TEST(format, join) -{ - using namespace papilio; - - { - int arr[4] = {1, 2, 3, 4}; - EXPECT_EQ( - PAPILIO_NS format("{}", PAPILIO_NS join(arr)), - "1, 2, 3, 4" - ); - EXPECT_EQ( - PAPILIO_NS format(L"{}", PAPILIO_NS join(arr)), - L"1, 2, 3, 4" - ); - } - - { - int arr[4] = {1, 2, 3, 4}; - EXPECT_EQ( - PAPILIO_NS format("{}", PAPILIO_NS join(arr, " | ")), - "1 | 2 | 3 | 4" - ); - EXPECT_EQ( - PAPILIO_NS format(L"{}", PAPILIO_NS join(arr, L" | ")), - L"1 | 2 | 3 | 4" - ); - } - - { - int arr[4] = {1, 2, 3, 4}; - - static_assert(formattable); - static_assert(formattable); - - EXPECT_EQ( - PAPILIO_NS format("{:02}", PAPILIO_NS join(arr, " | ")), - "01 | 02 | 03 | 04" - ); - EXPECT_EQ( - PAPILIO_NS format(L"{:02}", PAPILIO_NS join(arr, L" | ")), - L"01 | 02 | 03 | 04" - ); - } -} diff --git a/test/test_format/misc.cpp b/test/test_format/misc.cpp index ac3f168..047fb74 100644 --- a/test/test_format/misc.cpp +++ b/test/test_format/misc.cpp @@ -1,6 +1,51 @@ #include #include +TEST(misc_formatter, join) +{ + using namespace papilio; + + { + int arr[4] = {1, 2, 3, 4}; + EXPECT_EQ( + PAPILIO_NS format("{}", PAPILIO_NS join(arr)), + "1, 2, 3, 4" + ); + EXPECT_EQ( + PAPILIO_NS format(L"{}", PAPILIO_NS join(arr)), + L"1, 2, 3, 4" + ); + } + + { + int arr[4] = {1, 2, 3, 4}; + EXPECT_EQ( + PAPILIO_NS format("{}", PAPILIO_NS join(arr, " | ")), + "1 | 2 | 3 | 4" + ); + EXPECT_EQ( + PAPILIO_NS format(L"{}", PAPILIO_NS join(arr, L" | ")), + L"1 | 2 | 3 | 4" + ); + } + + { + int arr[4] = {1, 2, 3, 4}; + + static_assert(formattable); + static_assert(formattable); + + EXPECT_EQ( + PAPILIO_NS format("{:02}", PAPILIO_NS join(arr, " | ")), + "01 | 02 | 03 | 04" + ); + EXPECT_EQ( + PAPILIO_NS format(L"{:02}", PAPILIO_NS join(arr, L" | ")), + L"01 | 02 | 03 | 04" + ); + } +} + TEST(misc_formatter, thread_id) { using namespace papilio; @@ -17,7 +62,7 @@ TEST(misc_formatter, thread_id) EXPECT_EQ(PAPILIO_NS format("{}", id), expected_str); } - + { const std::wstring wexpected_str = [&]() { diff --git a/test/test_format/script.cpp b/test/test_format/script.cpp new file mode 100644 index 0000000..cbdfe76 --- /dev/null +++ b/test/test_format/script.cpp @@ -0,0 +1,227 @@ +#include +#include +#include "test_format.hpp" + +TYPED_TEST(format_suite, script_bool_op) +{ + using namespace papilio; + + using string_view_type = typename TestFixture::string_view_type; + +#define PAPILIO_CHECK_SCRIPT_BOOL_OP(fmt, val, expected_str) \ + do \ + { \ + string_view_type fmt_sv = \ + PAPILIO_TSTRING_VIEW(TypeParam, fmt); \ + string_view_type expected_str_sv = \ + PAPILIO_TSTRING_VIEW(TypeParam, expected_str); \ + EXPECT_EQ( \ + PAPILIO_NS format(fmt_sv, val), expected_str_sv \ + ) << "fmt = " \ + << std::quoted(fmt) \ + << ", val = " << #val; \ + } while(0) + + PAPILIO_CHECK_SCRIPT_BOOL_OP("{$ {}: 'true'}", 1, "true"); + PAPILIO_CHECK_SCRIPT_BOOL_OP("{$ !{}: 'false'}", 0, "false"); + + if constexpr(std::is_same_v) + { + PAPILIO_CHECK_SCRIPT_BOOL_OP("{$ {}: 'true'}", "nonempty", "true"); + PAPILIO_CHECK_SCRIPT_BOOL_OP("{$ !{}: 'false'}", "", "false"); + + PAPILIO_CHECK_SCRIPT_BOOL_OP("{$ {val}: 'true'}", "val"_a = 1, "true"); + } + else if constexpr(std::is_same_v) + { + PAPILIO_CHECK_SCRIPT_BOOL_OP("{$ {}: 'true'}", L"nonempty", "true"); + PAPILIO_CHECK_SCRIPT_BOOL_OP("{$ !{}: 'false'}", L"", "false"); + + PAPILIO_CHECK_SCRIPT_BOOL_OP("{$ {val}: 'true'}", L"val"_a = 1, "true"); + } +} + +TYPED_TEST(format_suite, script_cmp_op) +{ + using namespace papilio; + + using string_view_type = typename TestFixture::string_view_type; + +#define PAPILIO_CHECK_SCRIPT_CMP_OP(fmt, lhs, rhs, expected_str) \ + do \ + { \ + string_view_type fmt_sv = \ + PAPILIO_TSTRING_VIEW(TypeParam, fmt); \ + string_view_type expected_str_sv = \ + PAPILIO_TSTRING_VIEW(TypeParam, expected_str); \ + EXPECT_EQ( \ + PAPILIO_NS format(fmt_sv, lhs, rhs), expected_str_sv \ + ) << "lhs = " \ + << lhs \ + << ", rhs = " \ + << rhs; \ + } while(0) + +#define PAPILIO_CHECK_SCRIPT_EQ_OP(lhs, rhs) \ + PAPILIO_CHECK_SCRIPT_CMP_OP("{$ {} == {}: 'eq'}", lhs, rhs, "eq") + + PAPILIO_CHECK_SCRIPT_EQ_OP(0, 0); + PAPILIO_CHECK_SCRIPT_EQ_OP(1, 1); + +#define PAPILIO_CHECK_SCRIPT_NE_OP(lhs, rhs) \ + PAPILIO_CHECK_SCRIPT_CMP_OP("{$ {} != {}: 'ne'}", lhs, rhs, "ne") + + PAPILIO_CHECK_SCRIPT_NE_OP(1, 2); + PAPILIO_CHECK_SCRIPT_NE_OP(2, 1); + +#define PAPILIO_CHECK_SCRIPT_LT_OP(lhs, rhs) \ + PAPILIO_CHECK_SCRIPT_CMP_OP("{$ {} < {}: 'lt'}", lhs, rhs, "lt") +#define PAPILIO_CHECK_SCRIPT_GT_OP(lhs, rhs) \ + PAPILIO_CHECK_SCRIPT_CMP_OP("{$ {} > {}: 'gt'}", lhs, rhs, "gt") + + PAPILIO_CHECK_SCRIPT_LT_OP(1, 2); + PAPILIO_CHECK_SCRIPT_GT_OP(2, 1); + +#define PAPILIO_CHECK_SCRIPT_LE_OP(lhs, rhs) \ + PAPILIO_CHECK_SCRIPT_CMP_OP("{$ {} <= {}: 'le'}", lhs, rhs, "le") +#define PAPILIO_CHECK_SCRIPT_GE_OP(lhs, rhs) \ + PAPILIO_CHECK_SCRIPT_CMP_OP("{$ {} >= {}: 'ge'}", lhs, rhs, "ge") + + PAPILIO_CHECK_SCRIPT_LE_OP(1, 2); + PAPILIO_CHECK_SCRIPT_GE_OP(2, 1); + PAPILIO_CHECK_SCRIPT_LE_OP(1, 1); + PAPILIO_CHECK_SCRIPT_GE_OP(1, 1); +} + +TYPED_TEST(format_suite, script_branch) +{ + using namespace papilio; + + using string_view_type = typename TestFixture::string_view_type; + + const TypeParam expected_a[] = {'a', '\0'}; + const TypeParam expected_b[] = {'b', '\0'}; + const TypeParam expected_c[] = {'c', '\0'}; + + { + string_view_type script = + PAPILIO_TSTRING_VIEW(TypeParam, "{$ {}: 'a': ${}: 'b' : 'c'}"); + + EXPECT_EQ(PAPILIO_NS format(script, true, true), expected_a); + EXPECT_EQ(PAPILIO_NS format(script, true, false), expected_a); + EXPECT_THROW((void)PAPILIO_NS format(script, true), std::out_of_range); + + EXPECT_EQ(PAPILIO_NS format(script, false, true), expected_b); + EXPECT_EQ(PAPILIO_NS format(script, false, false), expected_c); + } + + { + string_view_type script = + PAPILIO_TSTRING_VIEW(TypeParam, "{$ {}: 'a': ${}: 'b' : ${} : 'c'}"); + + EXPECT_EQ(PAPILIO_NS format(script, true, true, false), expected_a); + EXPECT_EQ(PAPILIO_NS format(script, true, false, false), expected_a); + + EXPECT_EQ(PAPILIO_NS format(script, false, true, true), expected_b); + EXPECT_EQ(PAPILIO_NS format(script, false, false, true), expected_c); + EXPECT_EQ(PAPILIO_NS format(script, false, false, false), string_view_type()); + } +} + +TYPED_TEST(format_suite, script_composite) +{ + using namespace papilio; + + using string_view_type = typename TestFixture::string_view_type; + +#define PAPILIO_CHECK_FORMAT_EQ(expected_str, fmt, ...) \ + do \ + { \ + string_view_type fmt_sv = \ + PAPILIO_TSTRING_VIEW(TypeParam, fmt); \ + string_view_type expected_str_sv = \ + PAPILIO_TSTRING_VIEW(TypeParam, expected_str); \ + EXPECT_EQ( \ + PAPILIO_NS format(fmt_sv, __VA_ARGS__), \ + expected_str_sv \ + ); \ + } while(0) + + PAPILIO_CHECK_FORMAT_EQ( + "182375 182376", "{} {}", 182375, 182376 + ); + + { + const auto hello_str = PAPILIO_TSTRING(TypeParam, "hello"); + + PAPILIO_CHECK_FORMAT_EQ( + "***5", "{.length:*>4}", hello_str + ); + PAPILIO_CHECK_FORMAT_EQ( + "length is 5", "length is {.length}", hello_str + ); + } + + { + const string_view_type expected_results[]{ + PAPILIO_TSTRING_VIEW(TypeParam, "0 warnings"), + PAPILIO_TSTRING_VIEW(TypeParam, "1 warning"), + PAPILIO_TSTRING_VIEW(TypeParam, "2 warnings"), + }; + + string_view_type fmt = PAPILIO_TSTRING_VIEW(TypeParam, "{0} warning{${0}!=1:'s'}"); + + for(std::size_t i : {0, 1, 2}) + { + EXPECT_EQ( + PAPILIO_NS format(fmt, i), + expected_results[i] + ) << "i = " + << i; + } + } + + { + const string_view_type expected_results[]{ + PAPILIO_TSTRING_VIEW(TypeParam, "There are 0 apples"), + PAPILIO_TSTRING_VIEW(TypeParam, "There is 1 apple"), + PAPILIO_TSTRING_VIEW(TypeParam, "There are 2 apples"), + }; + + string_view_type fmt = PAPILIO_TSTRING_VIEW( + TypeParam, + "There" + " {${0} != 1: 'are' : 'is'} " + "{0}" + " apple{${0} != 1: 's'}" + ); + + for(int i : {0, 1, 2}) + { + EXPECT_EQ( + PAPILIO_NS format(fmt, i), + expected_results[i] + ) << "i = " + << i; + } + } + + { + const string_view_type expected_results[]{ + PAPILIO_TSTRING_VIEW(TypeParam, "zero"), + PAPILIO_TSTRING_VIEW(TypeParam, "1"), + PAPILIO_TSTRING_VIEW(TypeParam, "2"), + }; + + string_view_type fmt = PAPILIO_TSTRING_VIEW(TypeParam, "{${0}==0: 'zero' : {0}}"); + + for(int i : {0, 1, 2}) + { + EXPECT_EQ( + PAPILIO_NS format(fmt, i), + expected_results[i] + ) << "i = " + << i; + } + } +} diff --git a/test/test_format/test_format.cpp b/test/test_format/test_format.cpp index e51dd55..d5921d0 100644 --- a/test/test_format/test_format.cpp +++ b/test/test_format/test_format.cpp @@ -1,6 +1,21 @@ #include #include "test_format.hpp" +namespace test_format +{ +std::ostream& operator<<(std::ostream& os, const stream_only&) +{ + os << "stream only"; + return os; +} + +std::wostream& operator<<(std::wostream& os, const stream_only&) +{ + os << L"stream only"; + return os; +} +} // namespace test_format + int main(int argc, char* argv[]) { testing::InitGoogleTest(&argc, argv); diff --git a/test/test_format/test_format.hpp b/test/test_format/test_format.hpp index 5bff9f1..f474cbc 100644 --- a/test/test_format/test_format.hpp +++ b/test/test_format/test_format.hpp @@ -5,6 +5,7 @@ #include #include +#include namespace test_format { @@ -16,20 +17,30 @@ class yes_no_numpunct : public std::numpunct public: using string_type = typename my_base::string_type; + static constexpr CharT yes_string[] = {'y', 'e', 's', '\0'}; + + static constexpr CharT no_string[] = {'n', 'o', '\0'}; + protected: string_type do_truename() const override { - const CharT yes_str[] = {'y', 'e', 's'}; - return string_type(yes_str, std::size(yes_str)); + return yes_string; } string_type do_falsename() const override { - const CharT no_str[] = {'n', 'o'}; - return string_type(no_str, std::size(no_str)); + return no_string; } }; +class stream_only +{ +public: + friend std::ostream& operator<<(std::ostream& os, const stream_only&); + + friend std::wostream& operator<<(std::wostream& os, const stream_only&); +}; + class format_disabled { public: @@ -55,4 +66,15 @@ struct formatter : public disabled_formatte {}; } // namespace papilio +template +class format_suite : public ::testing::Test +{ +public: + using string_type = std::basic_string; + using string_view_type = std::basic_string_view; +}; + +using char_types = ::testing::Types; +TYPED_TEST_SUITE(format_suite, char_types); + #endif diff --git a/test/test_format/tuple_formatter.cpp b/test/test_format/tuple_formatter.cpp index d2f5097..f1397ed 100644 --- a/test/test_format/tuple_formatter.cpp +++ b/test/test_format/tuple_formatter.cpp @@ -1,7 +1,7 @@ #include #include -TEST(formatter, tuple) +TEST(tuple_formatter, basic) { using namespace papilio;