#include "strprintf.h" #include #include #include "3rd-party/catch.hpp" using namespace newsboat; TEST_CASE("strprintf::fmt()", "[strprintf]") { REQUIRE(strprintf::fmt("") == ""); REQUIRE(strprintf::fmt("%s", "") == ""); REQUIRE(strprintf::fmt("%u", 0) == "0"); REQUIRE(strprintf::fmt("%s", nullptr) == "(null)"); REQUIRE(strprintf::fmt("%u-%s-%c", 23, "hello world", 'X') == "23-hello world-X"); REQUIRE(strprintf::fmt("%%") == "%"); std::string long_input_without_formats(240000, 'x'); REQUIRE(strprintf::fmt(long_input_without_formats) == long_input_without_formats); } TEST_CASE("strprintf::split_format()", "[strprintf]") { std::string first, rest; SECTION("empty format string") { std::tie(first, rest) = strprintf::split_format(""); REQUIRE(first == ""); REQUIRE(rest == ""); } SECTION("string without formats") { const std::string input = "hello world!"; std::tie(first, rest) = strprintf::split_format(input); REQUIRE(first == input); REQUIRE(rest == ""); } SECTION("string with a couple formats") { const std::string input = "hello %i world %s haha"; std::tie(first, rest) = strprintf::split_format(input); REQUIRE(first == "hello %i world "); REQUIRE(rest == "%s haha"); std::tie(first, rest) = strprintf::split_format(rest); REQUIRE(first == "%s haha"); REQUIRE(rest == ""); } SECTION("string with %% (escaped percent sign)") { SECTION("before any formats") { const std::string input = "a 100%% rel%iable e%xamp%le"; std::tie(first, rest) = strprintf::split_format(input); REQUIRE(first == "a 100%% rel%iable e"); REQUIRE(rest == "%xamp%le"); std::tie(first, rest) = strprintf::split_format(rest); REQUIRE(first == "%xamp"); REQUIRE(rest == "%le"); std::tie(first, rest) = strprintf::split_format(rest); REQUIRE(first == "%le"); REQUIRE(rest == ""); } SECTION("after all formats") { const std::string input = "%3u %% "; std::tie(first, rest) = strprintf::split_format(input); REQUIRE(first == "%3u "); REQUIRE(rest == "%% "); std::tie(first, rest) = strprintf::split_format(rest); REQUIRE(first == "%% "); REQUIRE(rest == ""); } SECTION("consecutive escaped percent signs") { const std::string input = "%3u %% %% %i"; std::tie(first, rest) = strprintf::split_format(input); REQUIRE(first == "%3u "); REQUIRE(rest == "%% %% %i"); std::tie(first, rest) = strprintf::split_format(rest); REQUIRE(first == "%% %% %i"); REQUIRE(rest == ""); } } } TEST_CASE("strprintf::fmt() formats char* as a string", "[strprintf]") { const char* input = "Hello, world!"; REQUIRE(strprintf::fmt("%s", input) == std::string(input)); REQUIRE(strprintf::fmt("%15s", input) == " Hello, world!"); REQUIRE(strprintf::fmt("%-15s", input) == "Hello, world! "); } TEST_CASE("strprintf::fmt() formats int32_t", "[strprintf]") { const int32_t input = 42; REQUIRE(strprintf::fmt("%" PRIi32, input) == "42"); REQUIRE(strprintf::fmt("%" PRId32, input) == "42"); const auto i32_min = std::numeric_limits::min(); REQUIRE(strprintf::fmt("%" PRIi32, i32_min) == "-2147483648"); REQUIRE(strprintf::fmt("%" PRId32, i32_min) == "-2147483648"); const auto i32_max = std::numeric_limits::max(); REQUIRE(strprintf::fmt("%" PRIi32, i32_max) == "2147483647"); REQUIRE(strprintf::fmt("%" PRId32, i32_max) == "2147483647"); } TEST_CASE("strprintf::fmt() formats uint32_t", "[strprintf]") { const std::uint32_t input = 42; REQUIRE(strprintf::fmt("%" PRIu32, input) == "42"); const std::uint32_t zero = 0; REQUIRE(strprintf::fmt("%" PRIu32, zero) == "0"); const std::uint32_t u32_max = std::numeric_limits::max(); REQUIRE(strprintf::fmt("%" PRIu32, u32_max) == "4294967295"); } TEST_CASE("strprintf::fmt() formats int64_t", "[strprintf]") { const int64_t input = 42; REQUIRE(strprintf::fmt("%" PRIi64, input) == "42"); REQUIRE(strprintf::fmt("%" PRId64, input) == "42"); const auto i64_min = std::numeric_limits::min(); REQUIRE(strprintf::fmt("%" PRIi64, i64_min) == "-9223372036854775808"); REQUIRE(strprintf::fmt("%" PRId64, i64_min) == "-9223372036854775808"); const auto i64_max = std::numeric_limits::max(); REQUIRE(strprintf::fmt("%" PRIi64, i64_max) == "9223372036854775807"); REQUIRE(strprintf::fmt("%" PRId64, i64_max) == "9223372036854775807"); } TEST_CASE("strprintf::fmt() formats uint64_t", "[strprintf]") { const uint64_t input = 42; REQUIRE(strprintf::fmt("%" PRIu64, input) == "42"); const uint64_t zero = 0; REQUIRE(strprintf::fmt("%" PRIu64, zero) == "0"); const uint64_t u64_max = std::numeric_limits::max(); REQUIRE(strprintf::fmt("%" PRIu64, u64_max) == "18446744073709551615"); } TEST_CASE("strprintf::fmt() formats pointers", "[strprintf]") { const auto x = 42; const auto x_ptr = &x; const auto x_ptr_formatted = strprintf::fmt("%p", x_ptr); const auto x_ptr_void = reinterpret_cast(x_ptr); const auto x_ptr_void_formatted = strprintf::fmt("%p", x_ptr_void); REQUIRE_FALSE(x_ptr_formatted == ""); REQUIRE(x_ptr_formatted == x_ptr_void_formatted); } TEST_CASE("strprintf::fmt() formats null pointers the same", "[strprintf]") { const auto int_ptr_fmt = strprintf::fmt("%p", static_cast(nullptr)); const auto uint_ptr_fmt = strprintf::fmt("%p", static_cast(nullptr)); const auto long_ptr_fmt = strprintf::fmt("%p", static_cast(nullptr)); const auto ulong_ptr_fmt = strprintf::fmt("%p", static_cast(nullptr)); const auto llong_ptr_fmt = strprintf::fmt("%p", static_cast(nullptr)); const auto ullong_ptr_fmt = strprintf::fmt("%p", static_cast(nullptr)); REQUIRE_FALSE(int_ptr_fmt == ""); REQUIRE(int_ptr_fmt == uint_ptr_fmt); REQUIRE(uint_ptr_fmt == long_ptr_fmt); REQUIRE(long_ptr_fmt == ulong_ptr_fmt); REQUIRE(ulong_ptr_fmt == llong_ptr_fmt); REQUIRE(llong_ptr_fmt == ullong_ptr_fmt); } TEST_CASE("strprintf::fmt() formats double", "[strprintf]") { const auto x = 42.0; REQUIRE(strprintf::fmt("%f", x) == "42.000000"); REQUIRE(strprintf::fmt("%.3f", x) == "42.000"); const auto y = 42e138; REQUIRE(strprintf::fmt("%e", y) == "4.200000e+139"); REQUIRE(strprintf::fmt("%.3e", y) == "4.200e+139"); } TEST_CASE("strprintf::fmt() formats float", "[strprintf]") { const auto x = 42.0f; REQUIRE(strprintf::fmt("%f", x) == "42.000000"); REQUIRE(strprintf::fmt("%.3f", x) == "42.000"); const auto y = 42e3f; REQUIRE(strprintf::fmt("%e", y) == "4.200000e+04"); REQUIRE(strprintf::fmt("%.3e", y) == "4.200e+04"); } TEST_CASE("strprintf::fmt() formats std::string", "[strprintf]") { const auto input = std::string("Hello, world!"); REQUIRE(strprintf::fmt("%s", input) == input); REQUIRE(strprintf::fmt("%15s", input) == " Hello, world!"); REQUIRE(strprintf::fmt("%-15s", input) == "Hello, world! "); } TEST_CASE("strprintf::fmt() formats std::string*", "[strprintf]") { const auto input = std::string("Hello, world!"); REQUIRE(strprintf::fmt("%s", &input) == input); REQUIRE(strprintf::fmt("%15s", input) == " Hello, world!"); REQUIRE(strprintf::fmt("%-15s", input) == "Hello, world! "); } TEST_CASE("strprintf::fmt() works fine with 2MB format string", "[strprintf]") { const auto spacer = std::string(1024 * 1024, ' '); const auto format = spacer + "%i" + spacer + "%i"; const auto expected = spacer + "42" + spacer + "100500"; REQUIRE(strprintf::fmt(format, 42, 100500) == expected); }