diff options
author | dakovalkov <dakovalkov@yandex-team.com> | 2023-02-17 12:41:41 +0300 |
---|---|---|
committer | dakovalkov <dakovalkov@yandex-team.com> | 2023-02-17 12:41:41 +0300 |
commit | cd21459f6ea789b57cb76b39cb52553923024abd (patch) | |
tree | 332cedd2db0f9ce57952887c19c1ce97e775cd52 /contrib/libs/fmt/test | |
parent | 14530b5eb2df23bc3b0027fdd6d07e0035bafe2e (diff) | |
download | ydb-cd21459f6ea789b57cb76b39cb52553923024abd.tar.gz |
Update fmtlib to 8.1.1 + spdlog to 1.11.0 + jinja2cpp to 1.2.1
Diffstat (limited to 'contrib/libs/fmt/test')
30 files changed, 4226 insertions, 3254 deletions
diff --git a/contrib/libs/fmt/test/args-test.cc b/contrib/libs/fmt/test/args-test.cc new file mode 100644 index 0000000000..aa01fa4e08 --- /dev/null +++ b/contrib/libs/fmt/test/args-test.cc @@ -0,0 +1,186 @@ +// Formatting library for C++ - dynamic argument store tests +// +// Copyright (c) 2012 - present, Victor Zverovich +// All rights reserved. +// +// For the license information refer to format.h. + +#include "fmt/args.h" + +#include <memory> + +#include "gtest/gtest.h" + +TEST(args_test, basic) { + fmt::dynamic_format_arg_store<fmt::format_context> store; + store.push_back(42); + store.push_back("abc1"); + store.push_back(1.5f); + EXPECT_EQ("42 and abc1 and 1.5", fmt::vformat("{} and {} and {}", store)); +} + +TEST(args_test, strings_and_refs) { + // Unfortunately the tests are compiled with old ABI so strings use COW. + fmt::dynamic_format_arg_store<fmt::format_context> store; + char str[] = "1234567890"; + store.push_back(str); + store.push_back(std::cref(str)); + store.push_back(fmt::string_view{str}); + str[0] = 'X'; + + auto result = fmt::vformat("{} and {} and {}", store); + EXPECT_EQ("1234567890 and X234567890 and X234567890", result); +} + +struct custom_type { + int i = 0; +}; + +FMT_BEGIN_NAMESPACE +template <> struct formatter<custom_type> { + auto parse(format_parse_context& ctx) const -> decltype(ctx.begin()) { + return ctx.begin(); + } + + template <typename FormatContext> + auto format(const custom_type& p, FormatContext& ctx) -> decltype(ctx.out()) { + return format_to(ctx.out(), "cust={}", p.i); + } +}; +FMT_END_NAMESPACE + +TEST(args_test, custom_format) { + fmt::dynamic_format_arg_store<fmt::format_context> store; + auto c = custom_type(); + store.push_back(c); + ++c.i; + store.push_back(c); + ++c.i; + store.push_back(std::cref(c)); + ++c.i; + auto result = fmt::vformat("{} and {} and {}", store); + EXPECT_EQ("cust=0 and cust=1 and cust=3", result); +} + +struct to_stringable { + friend fmt::string_view to_string_view(to_stringable) { return {}; } +}; + +FMT_BEGIN_NAMESPACE +template <> struct formatter<to_stringable> { + auto parse(format_parse_context& ctx) const -> decltype(ctx.begin()) { + return ctx.begin(); + } + + auto format(to_stringable, format_context& ctx) -> decltype(ctx.out()) { + return ctx.out(); + } +}; +FMT_END_NAMESPACE + +TEST(args_test, to_string_and_formatter) { + fmt::dynamic_format_arg_store<fmt::format_context> store; + auto s = to_stringable(); + store.push_back(s); + store.push_back(std::cref(s)); + fmt::vformat("", store); +} + +TEST(args_test, named_int) { + fmt::dynamic_format_arg_store<fmt::format_context> store; + store.push_back(fmt::arg("a1", 42)); + EXPECT_EQ("42", fmt::vformat("{a1}", store)); +} + +TEST(args_test, named_strings) { + fmt::dynamic_format_arg_store<fmt::format_context> store; + char str[] = "1234567890"; + store.push_back(fmt::arg("a1", str)); + store.push_back(fmt::arg("a2", std::cref(str))); + str[0] = 'X'; + EXPECT_EQ("1234567890 and X234567890", fmt::vformat("{a1} and {a2}", store)); +} + +TEST(args_test, named_arg_by_ref) { + fmt::dynamic_format_arg_store<fmt::format_context> store; + char band[] = "Rolling Stones"; + store.push_back(fmt::arg("band", std::cref(band))); + band[9] = 'c'; // Changing band affects the output. + EXPECT_EQ(fmt::vformat("{band}", store), "Rolling Scones"); +} + +TEST(args_test, named_custom_format) { + fmt::dynamic_format_arg_store<fmt::format_context> store; + auto c = custom_type(); + store.push_back(fmt::arg("c1", c)); + ++c.i; + store.push_back(fmt::arg("c2", c)); + ++c.i; + store.push_back(fmt::arg("c_ref", std::cref(c))); + ++c.i; + auto result = fmt::vformat("{c1} and {c2} and {c_ref}", store); + EXPECT_EQ("cust=0 and cust=1 and cust=3", result); +} + +TEST(args_test, clear) { + fmt::dynamic_format_arg_store<fmt::format_context> store; + store.push_back(42); + + auto result = fmt::vformat("{}", store); + EXPECT_EQ("42", result); + + store.push_back(43); + result = fmt::vformat("{} and {}", store); + EXPECT_EQ("42 and 43", result); + + store.clear(); + store.push_back(44); + result = fmt::vformat("{}", store); + EXPECT_EQ("44", result); +} + +TEST(args_test, reserve) { + fmt::dynamic_format_arg_store<fmt::format_context> store; + store.reserve(2, 1); + store.push_back(1.5f); + store.push_back(fmt::arg("a1", 42)); + auto result = fmt::vformat("{a1} and {}", store); + EXPECT_EQ("42 and 1.5", result); +} + +struct copy_throwable { + copy_throwable() {} + copy_throwable(const copy_throwable&) { throw "deal with it"; } +}; + +FMT_BEGIN_NAMESPACE +template <> struct formatter<copy_throwable> { + auto parse(format_parse_context& ctx) const -> decltype(ctx.begin()) { + return ctx.begin(); + } + auto format(copy_throwable, format_context& ctx) -> decltype(ctx.out()) { + return ctx.out(); + } +}; +FMT_END_NAMESPACE + +TEST(args_test, throw_on_copy) { + fmt::dynamic_format_arg_store<fmt::format_context> store; + store.push_back(std::string("foo")); + try { + store.push_back(copy_throwable()); + } catch (...) { + } + EXPECT_EQ(fmt::vformat("{}", store), "foo"); +} + +TEST(args_test, move_constructor) { + using store_type = fmt::dynamic_format_arg_store<fmt::format_context>; + auto store = std::unique_ptr<store_type>(new store_type()); + store->push_back(42); + store->push_back(std::string("foo")); + store->push_back(fmt::arg("a1", "foo")); + auto moved_store = std::move(*store); + store.reset(); + EXPECT_EQ(fmt::vformat("{} {} {a1}", moved_store), "42 foo foo"); +} diff --git a/contrib/libs/fmt/test/assert-test.cc b/contrib/libs/fmt/test/assert-test.cc index 73f622e56b..c74e617e68 100644 --- a/contrib/libs/fmt/test/assert-test.cc +++ b/contrib/libs/fmt/test/assert-test.cc @@ -10,9 +10,9 @@ // For the license information refer to format.h. #include "fmt/core.h" -#include <gtest/gtest.h> +#include "gtest/gtest.h" -TEST(AssertTest, Fail) { +TEST(assert_test, fail) { #if GTEST_HAS_DEATH_TEST EXPECT_DEBUG_DEATH(FMT_ASSERT(false, "don't panic!"), "don't panic!"); #else @@ -20,9 +20,8 @@ TEST(AssertTest, Fail) { #endif } -bool test_condition = false; - -TEST(AssertTest, DanglingElse) { +TEST(assert_test, dangling_else) { + bool test_condition = false; bool executed_else = false; if (test_condition) FMT_ASSERT(true, ""); diff --git a/contrib/libs/fmt/test/chrono-test.cc b/contrib/libs/fmt/test/chrono-test.cc index fa383c1446..42360e5f12 100644 --- a/contrib/libs/fmt/test/chrono-test.cc +++ b/contrib/libs/fmt/test/chrono-test.cc @@ -5,77 +5,221 @@ // // For the license information refer to format.h. -#ifdef WIN32 -# define _CRT_SECURE_NO_WARNINGS -#endif - #include "fmt/chrono.h" -#include <iomanip> +#include <ctime> +#include <vector> + +#include "gtest-extra.h" // EXPECT_THROW_MSG +#include "util.h" // get_locale + +using fmt::runtime; -#include "gtest-extra.h" +using testing::Contains; -std::tm make_tm() { +auto make_tm() -> std::tm { auto time = std::tm(); time.tm_mday = 1; return time; } -std::tm make_hour(int h) { +auto make_hour(int h) -> std::tm { auto time = make_tm(); time.tm_hour = h; return time; } -std::tm make_minute(int m) { +auto make_minute(int m) -> std::tm { auto time = make_tm(); time.tm_min = m; return time; } -std::tm make_second(int s) { +auto make_second(int s) -> std::tm { auto time = make_tm(); time.tm_sec = s; return time; } -std::string format_tm(const std::tm& time, const char* spec, - const std::locale& loc) { +std::string system_strftime(const std::string& format, const std::tm* timeptr, + std::locale* locptr = nullptr) { + auto loc = locptr ? *locptr : std::locale::classic(); auto& facet = std::use_facet<std::time_put<char>>(loc); std::ostringstream os; os.imbue(loc); - facet.put(os, os, ' ', &time, spec, spec + std::strlen(spec)); + facet.put(os, os, ' ', timeptr, format.c_str(), + format.c_str() + format.size()); +#ifdef _WIN32 + // Workaround a bug in older versions of Universal CRT. + auto str = os.str(); + if (str == "-0000") str = "+0000"; + return str; +#else return os.str(); +#endif +} + +FMT_CONSTEXPR std::tm make_tm(int year, int mon, int mday, int hour, int min, + int sec) { + auto tm = std::tm(); + tm.tm_sec = sec; + tm.tm_min = min; + tm.tm_hour = hour; + tm.tm_mday = mday; + tm.tm_mon = mon - 1; + tm.tm_year = year - 1900; + return tm; } -TEST(TimeTest, Format) { - std::tm tm = std::tm(); +TEST(chrono_test, format_tm) { + auto tm = std::tm(); tm.tm_year = 116; tm.tm_mon = 3; tm.tm_mday = 25; - EXPECT_EQ("The date is 2016-04-25.", - fmt::format("The date is {:%Y-%m-%d}.", tm)); + tm.tm_hour = 11; + tm.tm_min = 22; + tm.tm_sec = 33; + EXPECT_EQ(fmt::format("The date is {:%Y-%m-%d %H:%M:%S}.", tm), + "The date is 2016-04-25 11:22:33."); + EXPECT_EQ(fmt::format("{:%Y}", tm), "2016"); + EXPECT_EQ(fmt::format("{:%C}", tm), "20"); + EXPECT_EQ(fmt::format("{:%C%y}", tm), fmt::format("{:%Y}", tm)); + EXPECT_EQ(fmt::format("{:%e}", tm), "25"); + EXPECT_EQ(fmt::format("{:%D}", tm), "04/25/16"); + EXPECT_EQ(fmt::format("{:%F}", tm), "2016-04-25"); + EXPECT_EQ(fmt::format("{:%T}", tm), "11:22:33"); + + // Short year + tm.tm_year = 999 - 1900; + tm.tm_mon = 0; // for %G + tm.tm_mday = 2; // for %G + tm.tm_wday = 3; // for %G + tm.tm_yday = 1; // for %G + EXPECT_EQ(fmt::format("{:%Y}", tm), "0999"); + EXPECT_EQ(fmt::format("{:%C%y}", tm), "0999"); + EXPECT_EQ(fmt::format("{:%G}", tm), "0999"); + + tm.tm_year = 27 - 1900; + EXPECT_EQ(fmt::format("{:%Y}", tm), "0027"); + EXPECT_EQ(fmt::format("{:%C%y}", tm), "0027"); + + // Overflow year + tm.tm_year = 2147483647; + EXPECT_EQ(fmt::format("{:%Y}", tm), "2147485547"); + + tm.tm_year = -2147483648; + EXPECT_EQ(fmt::format("{:%Y}", tm), "-2147481748"); + + // for week on the year + // https://www.cl.cam.ac.uk/~mgk25/iso-time.html + std::vector<std::tm> tm_list = { + make_tm(1975, 12, 29, 12, 14, 16), // W01 + make_tm(1977, 1, 2, 12, 14, 16), // W53 + make_tm(1999, 12, 27, 12, 14, 16), // W52 + make_tm(1999, 12, 31, 12, 14, 16), // W52 + make_tm(2000, 1, 1, 12, 14, 16), // W52 + make_tm(2000, 1, 2, 12, 14, 16), // W52 + make_tm(2000, 1, 3, 12, 14, 16) // W1 + }; + const std::string iso_week_spec = "%Y-%m-%d: %G %g %V"; + for (auto ctm : tm_list) { + // Calculate tm_yday, tm_wday, etc. + std::time_t t = std::mktime(&ctm); + tm = *std::localtime(&t); + + auto fmt_spec = fmt::format("{{:{}}}", iso_week_spec); + EXPECT_EQ(system_strftime(iso_week_spec, &tm), + fmt::format(fmt::runtime(fmt_spec), tm)); + } + + // Every day from 1970-01-01 + std::time_t time_now = std::time(nullptr); + for (std::time_t t = 6 * 3600; t < time_now; t += 86400) { + tm = *std::localtime(&t); + + auto fmt_spec = fmt::format("{{:{}}}", iso_week_spec); + EXPECT_EQ(system_strftime(iso_week_spec, &tm), + fmt::format(fmt::runtime(fmt_spec), tm)); + } } -TEST(TimeTest, GrowBuffer) { - std::string s = "{:"; +// MSVC: +// minkernel\crts\ucrt\src\appcrt\time\wcsftime.cpp(971) : Assertion failed: +// timeptr->tm_year >= -1900 && timeptr->tm_year <= 8099 +#ifndef _WIN32 +TEST(chrono_test, format_tm_future) { + auto tm = std::tm(); + tm.tm_year = 10445; // 10000+ years + tm.tm_mon = 3; + tm.tm_mday = 25; + tm.tm_hour = 11; + tm.tm_min = 22; + tm.tm_sec = 33; + EXPECT_EQ(fmt::format("The date is {:%Y-%m-%d %H:%M:%S}.", tm), + "The date is 12345-04-25 11:22:33."); + EXPECT_EQ(fmt::format("{:%Y}", tm), "12345"); + EXPECT_EQ(fmt::format("{:%C}", tm), "123"); + EXPECT_EQ(fmt::format("{:%C%y}", tm), fmt::format("{:%Y}", tm)); + EXPECT_EQ(fmt::format("{:%D}", tm), "04/25/45"); + EXPECT_EQ(fmt::format("{:%F}", tm), "12345-04-25"); + EXPECT_EQ(fmt::format("{:%T}", tm), "11:22:33"); +} + +TEST(chrono_test, format_tm_past) { + auto tm = std::tm(); + tm.tm_year = -2001; + tm.tm_mon = 3; + tm.tm_mday = 25; + tm.tm_hour = 11; + tm.tm_min = 22; + tm.tm_sec = 33; + EXPECT_EQ(fmt::format("The date is {:%Y-%m-%d %H:%M:%S}.", tm), + "The date is -101-04-25 11:22:33."); + EXPECT_EQ(fmt::format("{:%Y}", tm), "-101"); + + // macOS %C - "-1" + // Linux %C - "-2" + // fmt %C - "-1" + EXPECT_EQ(fmt::format("{:%C}", tm), "-1"); + EXPECT_EQ(fmt::format("{:%C%y}", tm), fmt::format("{:%Y}", tm)); + + // macOS %D - "04/25/01" (%y) + // Linux %D - "04/25/99" (%y) + // fmt %D - "04/25/01" (%y) + EXPECT_EQ(fmt::format("{:%D}", tm), "04/25/01"); + + EXPECT_EQ(fmt::format("{:%F}", tm), "-101-04-25"); + EXPECT_EQ(fmt::format("{:%T}", tm), "11:22:33"); + + tm.tm_year = -1901; // -1 + EXPECT_EQ(fmt::format("{:%Y}", tm), "-001"); + EXPECT_EQ(fmt::format("{:%C%y}", tm), fmt::format("{:%Y}", tm)); + + tm.tm_year = -1911; // -11 + EXPECT_EQ(fmt::format("{:%Y}", tm), "-011"); + EXPECT_EQ(fmt::format("{:%C%y}", tm), fmt::format("{:%Y}", tm)); +} +#endif + +TEST(chrono_test, grow_buffer) { + auto s = std::string("{:"); for (int i = 0; i < 30; ++i) s += "%c"; s += "}\n"; - std::time_t t = std::time(nullptr); - fmt::format(s, *std::localtime(&t)); + auto t = std::time(nullptr); + (void)fmt::format(fmt::runtime(s), *std::localtime(&t)); } -TEST(TimeTest, FormatToEmptyContainer) { - std::string s; +TEST(chrono_test, format_to_empty_container) { auto time = std::tm(); time.tm_sec = 42; + auto s = std::string(); fmt::format_to(std::back_inserter(s), "{:%S}", time); EXPECT_EQ(s, "42"); } -TEST(TimeTest, EmptyResult) { EXPECT_EQ("", fmt::format("{}", std::tm())); } +TEST(chrono_test, empty_result) { EXPECT_EQ(fmt::format("{}", std::tm()), ""); } -static bool EqualTime(const std::tm& lhs, const std::tm& rhs) { +auto equal(const std::tm& lhs, const std::tm& rhs) -> bool { return lhs.tm_sec == rhs.tm_sec && lhs.tm_min == rhs.tm_min && lhs.tm_hour == rhs.tm_hour && lhs.tm_mday == rhs.tm_mday && lhs.tm_mon == rhs.tm_mon && lhs.tm_year == rhs.tm_year && @@ -83,39 +227,62 @@ static bool EqualTime(const std::tm& lhs, const std::tm& rhs) { lhs.tm_isdst == rhs.tm_isdst; } -TEST(TimeTest, LocalTime) { - std::time_t t = std::time(nullptr); - std::tm tm = *std::localtime(&t); - EXPECT_TRUE(EqualTime(tm, fmt::localtime(t))); +TEST(chrono_test, localtime) { + auto t = std::time(nullptr); + auto tm = *std::localtime(&t); + EXPECT_TRUE(equal(tm, fmt::localtime(t))); } -TEST(TimeTest, GMTime) { - std::time_t t = std::time(nullptr); - std::tm tm = *std::gmtime(&t); - EXPECT_TRUE(EqualTime(tm, fmt::gmtime(t))); +TEST(chrono_test, gmtime) { + auto t = std::time(nullptr); + auto tm = *std::gmtime(&t); + EXPECT_TRUE(equal(tm, fmt::gmtime(t))); } -TEST(TimeTest, TimePoint) { - std::chrono::system_clock::time_point point = std::chrono::system_clock::now(); +template <typename TimePoint> auto strftime_full(TimePoint tp) -> std::string { + auto t = std::chrono::system_clock::to_time_t(tp); + auto tm = *std::localtime(&t); + return system_strftime("%Y-%m-%d %H:%M:%S", &tm); +} - std::time_t t = std::chrono::system_clock::to_time_t(point); - std::tm tm = *std::localtime(&t); - char strftime_output[256]; - std::strftime(strftime_output, sizeof(strftime_output), "It is %Y-%m-%d %H:%M:%S", &tm); +TEST(chrono_test, time_point) { + auto t1 = std::chrono::system_clock::now(); + EXPECT_EQ(strftime_full(t1), fmt::format("{:%Y-%m-%d %H:%M:%S}", t1)); + EXPECT_EQ(strftime_full(t1), fmt::format("{}", t1)); + using time_point = + std::chrono::time_point<std::chrono::system_clock, std::chrono::seconds>; + auto t2 = time_point(std::chrono::seconds(42)); + EXPECT_EQ(strftime_full(t2), fmt::format("{:%Y-%m-%d %H:%M:%S}", t2)); + + std::vector<std::string> spec_list = { + "%%", "%n", "%t", "%Y", "%EY", "%y", "%Oy", "%Ey", "%C", + "%EC", "%G", "%g", "%b", "%h", "%B", "%m", "%Om", "%U", + "%OU", "%W", "%OW", "%V", "%OV", "%j", "%d", "%Od", "%e", + "%Oe", "%a", "%A", "%w", "%Ow", "%u", "%Ou", "%H", "%OH", + "%I", "%OI", "%M", "%OM", "%S", "%OS", "%x", "%Ex", "%X", + "%EX", "%D", "%F", "%R", "%T", "%p", "%z", "%Z"}; + spec_list.push_back("%Y-%m-%d %H:%M:%S"); +#ifndef _WIN32 + // Disabled on Windows because these formats are not consistent among + // platforms. + spec_list.insert(spec_list.end(), {"%c", "%Ec", "%r"}); +#endif - EXPECT_EQ(strftime_output, fmt::format("It is {:%Y-%m-%d %H:%M:%S}", point)); -} + for (const auto& spec : spec_list) { + auto t = std::chrono::system_clock::to_time_t(t1); + auto tm = *std::localtime(&t); + + auto sys_output = system_strftime(spec, &tm); -#define EXPECT_TIME(spec, time, duration) \ - { \ - std::locale loc("ja_JP.utf8"); \ - EXPECT_EQ(format_tm(time, spec, loc), \ - fmt::format(loc, "{:" spec "}", duration)); \ + auto fmt_spec = fmt::format("{{:{}}}", spec); + EXPECT_EQ(sys_output, fmt::format(fmt::runtime(fmt_spec), t1)); + EXPECT_EQ(sys_output, fmt::format(fmt::runtime(fmt_spec), tm)); } +} #ifndef FMT_STATIC_THOUSANDS_SEPARATOR -TEST(ChronoTest, FormatDefault) { +TEST(chrono_test, format_default) { EXPECT_EQ("42s", fmt::format("{}", std::chrono::seconds(42))); EXPECT_EQ("42as", fmt::format("{}", std::chrono::duration<int, std::atto>(42))); @@ -157,49 +324,7 @@ TEST(ChronoTest, FormatDefault) { fmt::format("{}", std::chrono::duration<int, std::ratio<15, 4>>(42))); } -TEST(ChronoTest, FormatWide) { - EXPECT_EQ(L"42s", fmt::format(L"{}", std::chrono::seconds(42))); - EXPECT_EQ(L"42as", - fmt::format(L"{}", std::chrono::duration<int, std::atto>(42))); - EXPECT_EQ(L"42fs", - fmt::format(L"{}", std::chrono::duration<int, std::femto>(42))); - EXPECT_EQ(L"42ps", - fmt::format(L"{}", std::chrono::duration<int, std::pico>(42))); - EXPECT_EQ(L"42ns", fmt::format(L"{}", std::chrono::nanoseconds(42))); - EXPECT_EQ(L"42\u00B5s", fmt::format(L"{}", std::chrono::microseconds(42))); - EXPECT_EQ(L"42ms", fmt::format(L"{}", std::chrono::milliseconds(42))); - EXPECT_EQ(L"42cs", - fmt::format(L"{}", std::chrono::duration<int, std::centi>(42))); - EXPECT_EQ(L"42ds", - fmt::format(L"{}", std::chrono::duration<int, std::deci>(42))); - EXPECT_EQ(L"42s", fmt::format(L"{}", std::chrono::seconds(42))); - EXPECT_EQ(L"42das", - fmt::format(L"{}", std::chrono::duration<int, std::deca>(42))); - EXPECT_EQ(L"42hs", - fmt::format(L"{}", std::chrono::duration<int, std::hecto>(42))); - EXPECT_EQ(L"42ks", - fmt::format(L"{}", std::chrono::duration<int, std::kilo>(42))); - EXPECT_EQ(L"42Ms", - fmt::format(L"{}", std::chrono::duration<int, std::mega>(42))); - EXPECT_EQ(L"42Gs", - fmt::format(L"{}", std::chrono::duration<int, std::giga>(42))); - EXPECT_EQ(L"42Ts", - fmt::format(L"{}", std::chrono::duration<int, std::tera>(42))); - EXPECT_EQ(L"42Ps", - fmt::format(L"{}", std::chrono::duration<int, std::peta>(42))); - EXPECT_EQ(L"42Es", - fmt::format(L"{}", std::chrono::duration<int, std::exa>(42))); - EXPECT_EQ(L"42m", fmt::format(L"{}", std::chrono::minutes(42))); - EXPECT_EQ(L"42h", fmt::format(L"{}", std::chrono::hours(42))); - EXPECT_EQ( - L"42[15]s", - fmt::format(L"{}", std::chrono::duration<int, std::ratio<15, 1>>(42))); - EXPECT_EQ( - L"42[15/4]s", - fmt::format(L"{}", std::chrono::duration<int, std::ratio<15, 4>>(42))); -} - -TEST(ChronoTest, Align) { +TEST(chrono_test, align) { auto s = std::chrono::seconds(42); EXPECT_EQ("42s ", fmt::format("{:5}", s)); EXPECT_EQ("42s ", fmt::format("{:{}}", s, 5)); @@ -215,7 +340,7 @@ TEST(ChronoTest, Align) { fmt::format("{:{}%H:%M:%S}", std::chrono::seconds(12345), 12)); } -TEST(ChronoTest, FormatSpecs) { +TEST(chrono_test, format_specs) { EXPECT_EQ("%", fmt::format("{:%%}", std::chrono::seconds(0))); EXPECT_EQ("\n", fmt::format("{:%n}", std::chrono::seconds(0))); EXPECT_EQ("\t", fmt::format("{:%t}", std::chrono::seconds(0))); @@ -244,43 +369,64 @@ TEST(ChronoTest, FormatSpecs) { EXPECT_EQ("s", fmt::format("{:%q}", std::chrono::seconds(12345))); } -TEST(ChronoTest, InvalidSpecs) { +TEST(chrono_test, invalid_specs) { auto sec = std::chrono::seconds(0); - EXPECT_THROW_MSG(fmt::format("{:%a}", sec), fmt::format_error, "no date"); - EXPECT_THROW_MSG(fmt::format("{:%A}", sec), fmt::format_error, "no date"); - EXPECT_THROW_MSG(fmt::format("{:%c}", sec), fmt::format_error, "no date"); - EXPECT_THROW_MSG(fmt::format("{:%x}", sec), fmt::format_error, "no date"); - EXPECT_THROW_MSG(fmt::format("{:%Ex}", sec), fmt::format_error, "no date"); - EXPECT_THROW_MSG(fmt::format("{:%X}", sec), fmt::format_error, "no date"); - EXPECT_THROW_MSG(fmt::format("{:%EX}", sec), fmt::format_error, "no date"); - EXPECT_THROW_MSG(fmt::format("{:%D}", sec), fmt::format_error, "no date"); - EXPECT_THROW_MSG(fmt::format("{:%F}", sec), fmt::format_error, "no date"); - EXPECT_THROW_MSG(fmt::format("{:%Ec}", sec), fmt::format_error, "no date"); - EXPECT_THROW_MSG(fmt::format("{:%w}", sec), fmt::format_error, "no date"); - EXPECT_THROW_MSG(fmt::format("{:%u}", sec), fmt::format_error, "no date"); - EXPECT_THROW_MSG(fmt::format("{:%b}", sec), fmt::format_error, "no date"); - EXPECT_THROW_MSG(fmt::format("{:%B}", sec), fmt::format_error, "no date"); - EXPECT_THROW_MSG(fmt::format("{:%z}", sec), fmt::format_error, "no date"); - EXPECT_THROW_MSG(fmt::format("{:%Z}", sec), fmt::format_error, "no date"); - EXPECT_THROW_MSG(fmt::format("{:%Eq}", sec), fmt::format_error, + EXPECT_THROW_MSG((void)fmt::format(runtime("{:%a}"), sec), fmt::format_error, + "no date"); + EXPECT_THROW_MSG((void)fmt::format(runtime("{:%A}"), sec), fmt::format_error, + "no date"); + EXPECT_THROW_MSG((void)fmt::format(runtime("{:%c}"), sec), fmt::format_error, + "no date"); + EXPECT_THROW_MSG((void)fmt::format(runtime("{:%x}"), sec), fmt::format_error, + "no date"); + EXPECT_THROW_MSG((void)fmt::format(runtime("{:%Ex}"), sec), fmt::format_error, + "no date"); + EXPECT_THROW_MSG((void)fmt::format(runtime("{:%X}"), sec), fmt::format_error, + "no date"); + EXPECT_THROW_MSG((void)fmt::format(runtime("{:%EX}"), sec), fmt::format_error, + "no date"); + EXPECT_THROW_MSG((void)fmt::format(runtime("{:%D}"), sec), fmt::format_error, + "no date"); + EXPECT_THROW_MSG((void)fmt::format(runtime("{:%F}"), sec), fmt::format_error, + "no date"); + EXPECT_THROW_MSG((void)fmt::format(runtime("{:%Ec}"), sec), fmt::format_error, + "no date"); + EXPECT_THROW_MSG((void)fmt::format(runtime("{:%w}"), sec), fmt::format_error, + "no date"); + EXPECT_THROW_MSG((void)fmt::format(runtime("{:%u}"), sec), fmt::format_error, + "no date"); + EXPECT_THROW_MSG((void)fmt::format(runtime("{:%b}"), sec), fmt::format_error, + "no date"); + EXPECT_THROW_MSG((void)fmt::format(runtime("{:%B}"), sec), fmt::format_error, + "no date"); + EXPECT_THROW_MSG((void)fmt::format(runtime("{:%z}"), sec), fmt::format_error, + "no date"); + EXPECT_THROW_MSG((void)fmt::format(runtime("{:%Z}"), sec), fmt::format_error, + "no date"); + EXPECT_THROW_MSG((void)fmt::format(runtime("{:%Eq}"), sec), fmt::format_error, "invalid format"); - EXPECT_THROW_MSG(fmt::format("{:%Oq}", sec), fmt::format_error, + EXPECT_THROW_MSG((void)fmt::format(runtime("{:%Oq}"), sec), fmt::format_error, "invalid format"); } -TEST(ChronoTest, Locale) { - const char* loc_name = "ja_JP.utf8"; - bool has_locale = false; - std::locale loc; - try { - loc = std::locale(loc_name); - has_locale = true; - } catch (const std::runtime_error&) { - } - if (!has_locale) { - fmt::print("{} locale is missing.\n", loc_name); - return; - } +auto format_tm(const std::tm& time, fmt::string_view spec, + const std::locale& loc) -> std::string { + auto& facet = std::use_facet<std::time_put<char>>(loc); + std::ostringstream os; + os.imbue(loc); + facet.put(os, os, ' ', &time, spec.begin(), spec.end()); + return os.str(); +} + +TEST(chrono_test, locale) { + auto loc = get_locale("ja_JP.utf8"); + if (loc == std::locale::classic()) return; +# define EXPECT_TIME(spec, time, duration) \ + { \ + auto jp_loc = std::locale("ja_JP.utf8"); \ + EXPECT_EQ(format_tm(time, spec, jp_loc), \ + fmt::format(jp_loc, "{:L" spec "}", duration)); \ + } EXPECT_TIME("%OH", make_hour(14), std::chrono::hours(14)); EXPECT_TIME("%OI", make_hour(14), std::chrono::hours(14)); EXPECT_TIME("%OM", make_minute(42), std::chrono::minutes(42)); @@ -294,9 +440,9 @@ TEST(ChronoTest, Locale) { EXPECT_TIME("%p", time, sec); } -typedef std::chrono::duration<double, std::milli> dms; +using dms = std::chrono::duration<double, std::milli>; -TEST(ChronoTest, FormatDefaultFP) { +TEST(chrono_test, format_default_fp) { typedef std::chrono::duration<float> fs; EXPECT_EQ("1.234s", fmt::format("{}", fs(1.234))); typedef std::chrono::duration<float, std::milli> fms; @@ -306,24 +452,37 @@ TEST(ChronoTest, FormatDefaultFP) { EXPECT_EQ("1.234ms", fmt::format("{}", dms(1.234))); } -TEST(ChronoTest, FormatPrecision) { - EXPECT_THROW_MSG(fmt::format("{:.2}", std::chrono::seconds(42)), - fmt::format_error, - "precision not allowed for this argument type"); +TEST(chrono_test, format_precision) { + EXPECT_THROW_MSG( + (void)fmt::format(runtime("{:.2}"), std::chrono::seconds(42)), + fmt::format_error, "precision not allowed for this argument type"); + EXPECT_EQ("1ms", fmt::format("{:.0}", dms(1.234))); EXPECT_EQ("1.2ms", fmt::format("{:.1}", dms(1.234))); EXPECT_EQ("1.23ms", fmt::format("{:.{}}", dms(1.234), 2)); + + EXPECT_EQ("13ms", fmt::format("{:.0}", dms(12.56))); + EXPECT_EQ("12.6ms", fmt::format("{:.1}", dms(12.56))); + EXPECT_EQ("12.56ms", fmt::format("{:.2}", dms(12.56))); } -TEST(ChronoTest, FormatFullSpecs) { +TEST(chrono_test, format_full_specs) { + EXPECT_EQ("1ms ", fmt::format("{:6.0}", dms(1.234))); EXPECT_EQ("1.2ms ", fmt::format("{:6.1}", dms(1.234))); EXPECT_EQ(" 1.23ms", fmt::format("{:>8.{}}", dms(1.234), 2)); EXPECT_EQ(" 1.2ms ", fmt::format("{:^{}.{}}", dms(1.234), 7, 1)); EXPECT_EQ(" 1.23ms ", fmt::format("{0:^{2}.{1}}", dms(1.234), 2, 8)); EXPECT_EQ("=1.234ms=", fmt::format("{:=^{}.{}}", dms(1.234), 9, 3)); EXPECT_EQ("*1.2340ms*", fmt::format("{:*^10.4}", dms(1.234))); + + EXPECT_EQ("13ms ", fmt::format("{:6.0}", dms(12.56))); + EXPECT_EQ(" 13ms", fmt::format("{:>8.{}}", dms(12.56), 0)); + EXPECT_EQ(" 13ms ", fmt::format("{:^{}.{}}", dms(12.56), 6, 0)); + EXPECT_EQ(" 13ms ", fmt::format("{0:^{2}.{1}}", dms(12.56), 0, 8)); + EXPECT_EQ("==13ms===", fmt::format("{:=^{}.{}}", dms(12.56), 9, 0)); + EXPECT_EQ("***13ms***", fmt::format("{:*^10.0}", dms(12.56))); } -TEST(ChronoTest, FormatSimpleQq) { +TEST(chrono_test, format_simple_q) { typedef std::chrono::duration<float> fs; EXPECT_EQ("1.234 s", fmt::format("{:%Q %q}", fs(1.234))); typedef std::chrono::duration<float, std::milli> fms; @@ -333,34 +492,42 @@ TEST(ChronoTest, FormatSimpleQq) { EXPECT_EQ("1.234 ms", fmt::format("{:%Q %q}", dms(1.234))); } -TEST(ChronoTest, FormatPrecisionQq) { - EXPECT_THROW_MSG(fmt::format("{:.2%Q %q}", std::chrono::seconds(42)), - fmt::format_error, - "precision not allowed for this argument type"); +TEST(chrono_test, format_precision_q) { + EXPECT_THROW_MSG( + (void)fmt::format(runtime("{:.2%Q %q}"), std::chrono::seconds(42)), + fmt::format_error, "precision not allowed for this argument type"); EXPECT_EQ("1.2 ms", fmt::format("{:.1%Q %q}", dms(1.234))); EXPECT_EQ("1.23 ms", fmt::format("{:.{}%Q %q}", dms(1.234), 2)); } -TEST(ChronoTest, FormatFullSpecsQq) { +TEST(chrono_test, format_full_specs_q) { + EXPECT_EQ("1 ms ", fmt::format("{:7.0%Q %q}", dms(1.234))); EXPECT_EQ("1.2 ms ", fmt::format("{:7.1%Q %q}", dms(1.234))); EXPECT_EQ(" 1.23 ms", fmt::format("{:>8.{}%Q %q}", dms(1.234), 2)); EXPECT_EQ(" 1.2 ms ", fmt::format("{:^{}.{}%Q %q}", dms(1.234), 8, 1)); EXPECT_EQ(" 1.23 ms ", fmt::format("{0:^{2}.{1}%Q %q}", dms(1.234), 2, 9)); EXPECT_EQ("=1.234 ms=", fmt::format("{:=^{}.{}%Q %q}", dms(1.234), 10, 3)); EXPECT_EQ("*1.2340 ms*", fmt::format("{:*^11.4%Q %q}", dms(1.234))); + + EXPECT_EQ("13 ms ", fmt::format("{:7.0%Q %q}", dms(12.56))); + EXPECT_EQ(" 13 ms", fmt::format("{:>8.{}%Q %q}", dms(12.56), 0)); + EXPECT_EQ(" 13 ms ", fmt::format("{:^{}.{}%Q %q}", dms(12.56), 8, 0)); + EXPECT_EQ(" 13 ms ", fmt::format("{0:^{2}.{1}%Q %q}", dms(12.56), 0, 9)); + EXPECT_EQ("==13 ms==", fmt::format("{:=^{}.{}%Q %q}", dms(12.56), 9, 0)); + EXPECT_EQ("***13 ms***", fmt::format("{:*^11.0%Q %q}", dms(12.56))); } -TEST(ChronoTest, InvalidWidthId) { - EXPECT_THROW(fmt::format("{:{o}", std::chrono::seconds(0)), +TEST(chrono_test, invalid_width_id) { + EXPECT_THROW((void)fmt::format(runtime("{:{o}"), std::chrono::seconds(0)), fmt::format_error); } -TEST(ChronoTest, InvalidColons) { - EXPECT_THROW(fmt::format("{0}=:{0::", std::chrono::seconds(0)), +TEST(chrono_test, invalid_colons) { + EXPECT_THROW((void)fmt::format(runtime("{0}=:{0::"), std::chrono::seconds(0)), fmt::format_error); } -TEST(ChronoTest, NegativeDurations) { +TEST(chrono_test, negative_durations) { EXPECT_EQ("-12345", fmt::format("{:%Q}", std::chrono::seconds(-12345))); EXPECT_EQ("-03:25:45", fmt::format("{:%H:%M:%S}", std::chrono::seconds(-12345))); @@ -375,16 +542,13 @@ TEST(ChronoTest, NegativeDurations) { fmt::format("{:%Q}", std::chrono::duration<int>(min))); } -TEST(ChronoTest, SpecialDurations) { - EXPECT_EQ( - "40.", - fmt::format("{:%S}", std::chrono::duration<double>(1e20)).substr(0, 3)); +TEST(chrono_test, special_durations) { + auto value = fmt::format("{:%S}", std::chrono::duration<double>(1e20)); + EXPECT_EQ(value, "40"); auto nan = std::numeric_limits<double>::quiet_NaN(); EXPECT_EQ( "nan nan nan nan nan:nan nan", fmt::format("{:%I %H %M %S %R %r}", std::chrono::duration<double>(nan))); - fmt::format("{:%S}", - std::chrono::duration<float, std::atto>(1.79400457e+31f)); EXPECT_EQ(fmt::format("{}", std::chrono::duration<float, std::exa>(1)), "1Es"); EXPECT_EQ(fmt::format("{}", std::chrono::duration<float, std::atto>(1)), @@ -395,4 +559,67 @@ TEST(ChronoTest, SpecialDurations) { "03:33:20"); } +TEST(chrono_test, unsigned_duration) { + EXPECT_EQ("42s", fmt::format("{}", std::chrono::duration<unsigned>(42))); +} + +TEST(chrono_test, weekday) { + auto loc = get_locale("ru_RU.UTF-8"); + std::locale::global(loc); + auto mon = fmt::weekday(1); + + auto tm = std::tm(); + tm.tm_wday = static_cast<int>(mon.c_encoding()); + + EXPECT_EQ(fmt::format("{}", mon), "Mon"); + EXPECT_EQ(fmt::format("{:%a}", tm), "Mon"); + + if (loc != std::locale::classic()) { + EXPECT_THAT((std::vector<std::string>{"пн", "Пн", "пнд", "Пнд"}), + Contains(fmt::format(loc, "{:L}", mon))); + EXPECT_THAT((std::vector<std::string>{"пн", "Пн", "пнд", "Пнд"}), + Contains(fmt::format(loc, "{:%a}", tm))); + } +} + +TEST(chrono_test, cpp20_duration_subsecond_support) { + using attoseconds = std::chrono::duration<long long, std::atto>; + // Check that 18 digits of subsecond precision are supported. + EXPECT_EQ(fmt::format("{:%S}", attoseconds{999999999999999999}), + "00.999999999999999999"); + EXPECT_EQ(fmt::format("{:%S}", attoseconds{673231113420148734}), + "00.673231113420148734"); + EXPECT_EQ(fmt::format("{:%S}", attoseconds{-673231113420148734}), + "-00.673231113420148734"); + EXPECT_EQ(fmt::format("{:%S}", std::chrono::nanoseconds{13420148734}), + "13.420148734"); + EXPECT_EQ(fmt::format("{:%S}", std::chrono::nanoseconds{-13420148734}), + "-13.420148734"); + EXPECT_EQ(fmt::format("{:%S}", std::chrono::milliseconds{1234}), "01.234"); + { + // Check that {:%H:%M:%S} is equivalent to {:%T}. + auto dur = std::chrono::milliseconds{3601234}; + auto formatted_dur = fmt::format("{:%T}", dur); + EXPECT_EQ(formatted_dur, "01:00:01.234"); + EXPECT_EQ(fmt::format("{:%H:%M:%S}", dur), formatted_dur); + } + using nanoseconds_dbl = std::chrono::duration<double, std::nano>; + EXPECT_EQ(fmt::format("{:%S}", nanoseconds_dbl{-123456789}), "-00.123456789"); + EXPECT_EQ(fmt::format("{:%S}", nanoseconds_dbl{9123456789}), "09.123456789"); + // Verify that only the seconds part is extracted and printed. + EXPECT_EQ(fmt::format("{:%S}", nanoseconds_dbl{99123456789}), "39.123456789"); + EXPECT_EQ(fmt::format("{:%S}", nanoseconds_dbl{99123000000}), "39.123000000"); + { + // Now the hour is printed, and we also test if negative doubles work. + auto dur = nanoseconds_dbl{-99123456789}; + auto formatted_dur = fmt::format("{:%T}", dur); + EXPECT_EQ(formatted_dur, "-00:01:39.123456789"); + EXPECT_EQ(fmt::format("{:%H:%M:%S}", dur), formatted_dur); + } + // Check that durations with precision greater than std::chrono::seconds have + // fixed precision, and print zeros even if there is no fractional part. + EXPECT_EQ(fmt::format("{:%S}", std::chrono::microseconds{7000000}), + "07.000000"); +} + #endif // FMT_STATIC_THOUSANDS_SEPARATOR diff --git a/contrib/libs/fmt/test/color-test.cc b/contrib/libs/fmt/test/color-test.cc index 3073808541..af8f149426 100644 --- a/contrib/libs/fmt/test/color-test.cc +++ b/contrib/libs/fmt/test/color-test.cc @@ -7,66 +7,29 @@ #include "fmt/color.h" -#include <iterator> -#include <string> -#include <utility> +#include <iterator> // std::back_inserter -#include "gtest-extra.h" +#include "gtest-extra.h" // EXPECT_WRITE -TEST(ColorsTest, ColorsPrint) { - EXPECT_WRITE(stdout, fmt::print(fg(fmt::rgb(255, 20, 30)), "rgb(255,20,30)"), - "\x1b[38;2;255;020;030mrgb(255,20,30)\x1b[0m"); - EXPECT_WRITE(stdout, fmt::print(fg(fmt::color::blue), "blue"), - "\x1b[38;2;000;000;255mblue\x1b[0m"); - EXPECT_WRITE( - stdout, - fmt::print(fg(fmt::color::blue) | bg(fmt::color::red), "two color"), - "\x1b[38;2;000;000;255m\x1b[48;2;255;000;000mtwo color\x1b[0m"); - EXPECT_WRITE(stdout, fmt::print(fmt::emphasis::bold, "bold"), - "\x1b[1mbold\x1b[0m"); - EXPECT_WRITE(stdout, fmt::print(fmt::emphasis::italic, "italic"), - "\x1b[3mitalic\x1b[0m"); - EXPECT_WRITE(stdout, fmt::print(fmt::emphasis::underline, "underline"), - "\x1b[4munderline\x1b[0m"); - EXPECT_WRITE(stdout, - fmt::print(fmt::emphasis::strikethrough, "strikethrough"), - "\x1b[9mstrikethrough\x1b[0m"); - EXPECT_WRITE( - stdout, - fmt::print(fg(fmt::color::blue) | fmt::emphasis::bold, "blue/bold"), - "\x1b[1m\x1b[38;2;000;000;255mblue/bold\x1b[0m"); - EXPECT_WRITE(stderr, fmt::print(stderr, fmt::emphasis::bold, "bold error"), - "\x1b[1mbold error\x1b[0m"); - EXPECT_WRITE(stderr, fmt::print(stderr, fg(fmt::color::blue), "blue log"), - "\x1b[38;2;000;000;255mblue log\x1b[0m"); - EXPECT_WRITE(stdout, fmt::print(fmt::text_style(), "hi"), "hi"); - EXPECT_WRITE(stdout, fmt::print(fg(fmt::terminal_color::red), "tred"), - "\x1b[31mtred\x1b[0m"); - EXPECT_WRITE(stdout, fmt::print(bg(fmt::terminal_color::cyan), "tcyan"), - "\x1b[46mtcyan\x1b[0m"); - EXPECT_WRITE(stdout, - fmt::print(fg(fmt::terminal_color::bright_green), "tbgreen"), - "\x1b[92mtbgreen\x1b[0m"); - EXPECT_WRITE(stdout, - fmt::print(bg(fmt::terminal_color::bright_magenta), "tbmagenta"), - "\x1b[105mtbmagenta\x1b[0m"); -} - -TEST(ColorsTest, Format) { +TEST(color_test, format) { EXPECT_EQ(fmt::format(fg(fmt::rgb(255, 20, 30)), "rgb(255,20,30)"), "\x1b[38;2;255;020;030mrgb(255,20,30)\x1b[0m"); - EXPECT_EQ(fmt::format(fg(fmt::rgb(255, 20, 30)), L"rgb(255,20,30) wide"), - L"\x1b[38;2;255;020;030mrgb(255,20,30) wide\x1b[0m"); EXPECT_EQ(fmt::format(fg(fmt::color::blue), "blue"), "\x1b[38;2;000;000;255mblue\x1b[0m"); EXPECT_EQ( fmt::format(fg(fmt::color::blue) | bg(fmt::color::red), "two color"), "\x1b[38;2;000;000;255m\x1b[48;2;255;000;000mtwo color\x1b[0m"); EXPECT_EQ(fmt::format(fmt::emphasis::bold, "bold"), "\x1b[1mbold\x1b[0m"); + EXPECT_EQ(fmt::format(fmt::emphasis::faint, "faint"), "\x1b[2mfaint\x1b[0m"); EXPECT_EQ(fmt::format(fmt::emphasis::italic, "italic"), "\x1b[3mitalic\x1b[0m"); EXPECT_EQ(fmt::format(fmt::emphasis::underline, "underline"), "\x1b[4munderline\x1b[0m"); + EXPECT_EQ(fmt::format(fmt::emphasis::blink, "blink"), "\x1b[5mblink\x1b[0m"); + EXPECT_EQ(fmt::format(fmt::emphasis::reverse, "reverse"), + "\x1b[7mreverse\x1b[0m"); + EXPECT_EQ(fmt::format(fmt::emphasis::conceal, "conceal"), + "\x1b[8mconceal\x1b[0m"); EXPECT_EQ(fmt::format(fmt::emphasis::strikethrough, "strikethrough"), "\x1b[9mstrikethrough\x1b[0m"); EXPECT_EQ( @@ -89,11 +52,15 @@ TEST(ColorsTest, Format) { "\x1b[31mfoo\x1b[0m"); } -TEST(ColorsTest, FormatToOutAcceptsTextStyle) { - fmt::text_style ts = fg(fmt::rgb(255, 20, 30)); - std::string out; - fmt::format_to(std::back_inserter(out), ts, "rgb(255,20,30){}{}{}", 1, 2, 3); - +TEST(color_test, format_to) { + auto out = std::string(); + fmt::format_to(std::back_inserter(out), fg(fmt::rgb(255, 20, 30)), + "rgb(255,20,30){}{}{}", 1, 2, 3); EXPECT_EQ(fmt::to_string(out), "\x1b[38;2;255;020;030mrgb(255,20,30)123\x1b[0m"); } + +TEST(color_test, print) { + EXPECT_WRITE(stdout, fmt::print(fg(fmt::rgb(255, 20, 30)), "rgb(255,20,30)"), + "\x1b[38;2;255;020;030mrgb(255,20,30)\x1b[0m"); +} diff --git a/contrib/libs/fmt/test/compile-fp-test.cc b/contrib/libs/fmt/test/compile-fp-test.cc new file mode 100644 index 0000000000..afedc26d06 --- /dev/null +++ b/contrib/libs/fmt/test/compile-fp-test.cc @@ -0,0 +1,62 @@ +// Formatting library for C++ - formatting library tests +// +// Copyright (c) 2012 - present, Victor Zverovich +// All rights reserved. +// +// For the license information refer to format.h. + +#include "fmt/compile.h" +#include "gmock/gmock.h" + +#if defined(__cpp_lib_bit_cast) && __cpp_lib_bit_cast >= 201806 && \ + defined(__cpp_constexpr) && __cpp_constexpr >= 201907 && \ + defined(__cpp_constexpr_dynamic_alloc) && \ + __cpp_constexpr_dynamic_alloc >= 201907 && __cplusplus >= 202002L +template <size_t max_string_length, typename Char = char> struct test_string { + template <typename T> constexpr bool operator==(const T& rhs) const noexcept { + return fmt::basic_string_view<Char>(rhs).compare(buffer) == 0; + } + Char buffer[max_string_length]{}; +}; + +template <size_t max_string_length, typename Char = char, typename... Args> +consteval auto test_format(auto format, const Args&... args) { + test_string<max_string_length, Char> string{}; + fmt::format_to(string.buffer, format, args...); + return string; +} + +TEST(compile_time_formatting_test, floating_point) { + EXPECT_EQ("0", test_format<2>(FMT_COMPILE("{}"), 0.0f)); + EXPECT_EQ("392.500000", test_format<11>(FMT_COMPILE("{0:f}"), 392.5f)); + + EXPECT_EQ("0", test_format<2>(FMT_COMPILE("{:}"), 0.0)); + EXPECT_EQ("0.000000", test_format<9>(FMT_COMPILE("{:f}"), 0.0)); + EXPECT_EQ("0", test_format<2>(FMT_COMPILE("{:g}"), 0.0)); + EXPECT_EQ("392.65", test_format<7>(FMT_COMPILE("{:}"), 392.65)); + EXPECT_EQ("392.65", test_format<7>(FMT_COMPILE("{:g}"), 392.65)); + EXPECT_EQ("392.65", test_format<7>(FMT_COMPILE("{:G}"), 392.65)); + EXPECT_EQ("4.9014e+06", test_format<11>(FMT_COMPILE("{:g}"), 4.9014e6)); + EXPECT_EQ("-392.650000", test_format<12>(FMT_COMPILE("{:f}"), -392.65)); + EXPECT_EQ("-392.650000", test_format<12>(FMT_COMPILE("{:F}"), -392.65)); + + EXPECT_EQ("3.926500e+02", test_format<13>(FMT_COMPILE("{0:e}"), 392.65)); + EXPECT_EQ("3.926500E+02", test_format<13>(FMT_COMPILE("{0:E}"), 392.65)); + EXPECT_EQ("+0000392.6", test_format<11>(FMT_COMPILE("{0:+010.4g}"), 392.65)); + EXPECT_EQ("9223372036854775808.000000", + test_format<27>(FMT_COMPILE("{:f}"), 9223372036854775807.0)); + + constexpr double nan = std::numeric_limits<double>::quiet_NaN(); + EXPECT_EQ("nan", test_format<4>(FMT_COMPILE("{}"), nan)); + EXPECT_EQ("+nan", test_format<5>(FMT_COMPILE("{:+}"), nan)); + if (std::signbit(-nan)) + EXPECT_EQ("-nan", test_format<5>(FMT_COMPILE("{}"), -nan)); + else + fmt::print("Warning: compiler doesn't handle negative NaN correctly"); + + constexpr double inf = std::numeric_limits<double>::infinity(); + EXPECT_EQ("inf", test_format<4>(FMT_COMPILE("{}"), inf)); + EXPECT_EQ("+inf", test_format<5>(FMT_COMPILE("{:+}"), inf)); + EXPECT_EQ("-inf", test_format<5>(FMT_COMPILE("{}"), -inf)); +} +#endif diff --git a/contrib/libs/fmt/test/compile-test.cc b/contrib/libs/fmt/test/compile-test.cc index 9bb9bb7d9e..1765961b89 100644 --- a/contrib/libs/fmt/test/compile-test.cc +++ b/contrib/libs/fmt/test/compile-test.cc @@ -5,121 +5,100 @@ // // For the license information refer to format.h. -#include <string> -#include <type_traits> +#include "fmt/compile.h" -// Check that fmt/compile.h compiles with windows.h included before it. -#ifdef _WIN32 -# include <windows.h> -#endif +#include <type_traits> -#include "fmt/compile.h" -#include <gmock/gmock.h> +#include "fmt/chrono.h" +#include "gmock/gmock.h" #include "gtest-extra.h" -#include "util.h" - -// compiletime_prepared_parts_type_provider is useful only with relaxed -// constexpr. -#if FMT_USE_CONSTEXPR -template <unsigned EXPECTED_PARTS_COUNT, typename Format> -void check_prepared_parts_type(Format format) { - typedef fmt::detail::compiled_format_base<decltype(format)> provider; - typedef fmt::detail::format_part<char> - expected_parts_type[EXPECTED_PARTS_COUNT]; - static_assert(std::is_same<typename provider::parts_container, - expected_parts_type>::value, - "CompileTimePreparedPartsTypeProvider test failed"); -} - -TEST(CompileTest, CompileTimePreparedPartsTypeProvider) { - check_prepared_parts_type<1u>(FMT_STRING("text")); - check_prepared_parts_type<1u>(FMT_STRING("{}")); - check_prepared_parts_type<2u>(FMT_STRING("text{}")); - check_prepared_parts_type<2u>(FMT_STRING("{}text")); - check_prepared_parts_type<3u>(FMT_STRING("text{}text")); - check_prepared_parts_type<3u>(FMT_STRING("{:{}.{}} {:{}}")); - - check_prepared_parts_type<3u>(FMT_STRING("{{{}}}")); // '{', 'argument', '}' - check_prepared_parts_type<2u>(FMT_STRING("text{{")); // 'text', '{' - check_prepared_parts_type<3u>(FMT_STRING("text{{ ")); // 'text', '{', ' ' - check_prepared_parts_type<2u>(FMT_STRING("}}text")); // '}', text - check_prepared_parts_type<2u>(FMT_STRING("text}}text")); // 'text}', 'text' - check_prepared_parts_type<4u>( - FMT_STRING("text{{}}text")); // 'text', '{', '}', 'text' -} -#endif -TEST(CompileTest, PassStringLiteralFormat) { - const auto prepared = fmt::detail::compile<int>("test {}"); - EXPECT_EQ("test 42", fmt::format(prepared, 42)); - const auto wprepared = fmt::detail::compile<int>(L"test {}"); - EXPECT_EQ(L"test 42", fmt::format(wprepared, 42)); +TEST(iterator_test, counting_iterator) { + auto it = fmt::detail::counting_iterator(); + auto prev = it++; + EXPECT_EQ(prev.count(), 0); + EXPECT_EQ(it.count(), 1); + EXPECT_EQ((it + 41).count(), 42); } -TEST(CompileTest, FormatToArrayOfChars) { - char buffer[32] = {0}; - const auto prepared = fmt::detail::compile<int>("4{}"); - fmt::format_to(fmt::detail::make_checked(buffer, 32), prepared, 2); - EXPECT_EQ(std::string("42"), buffer); - wchar_t wbuffer[32] = {0}; - const auto wprepared = fmt::detail::compile<int>(L"4{}"); - fmt::format_to(fmt::detail::make_checked(wbuffer, 32), wprepared, 2); - EXPECT_EQ(std::wstring(L"42"), wbuffer); +TEST(iterator_test, truncating_iterator) { + char* p = nullptr; + auto it = fmt::detail::truncating_iterator<char*>(p, 3); + auto prev = it++; + EXPECT_EQ(prev.base(), p); + EXPECT_EQ(it.base(), p + 1); } -TEST(CompileTest, FormatToIterator) { - std::string s(2, ' '); - const auto prepared = fmt::detail::compile<int>("4{}"); - fmt::format_to(s.begin(), prepared, 2); - EXPECT_EQ("42", s); - std::wstring ws(2, L' '); - const auto wprepared = fmt::detail::compile<int>(L"4{}"); - fmt::format_to(ws.begin(), wprepared, 2); - EXPECT_EQ(L"42", ws); +TEST(iterator_test, truncating_iterator_default_construct) { + auto it = fmt::detail::truncating_iterator<char*>(); + EXPECT_EQ(nullptr, it.base()); + EXPECT_EQ(std::size_t{0}, it.count()); } -TEST(CompileTest, FormatToN) { - char buf[5]; - auto f = fmt::detail::compile<int>("{:10}"); - auto result = fmt::format_to_n(buf, 5, f, 42); - EXPECT_EQ(result.size, 10); - EXPECT_EQ(result.out, buf + 5); - EXPECT_EQ(fmt::string_view(buf, 5), " "); +#ifdef __cpp_lib_ranges +TEST(iterator_test, truncating_iterator_is_output_iterator) { + static_assert( + std::output_iterator<fmt::detail::truncating_iterator<char*>, char>); } +#endif -TEST(CompileTest, FormattedSize) { - auto f = fmt::detail::compile<int>("{:10}"); - EXPECT_EQ(fmt::formatted_size(f, 42), 10); +TEST(iterator_test, truncating_back_inserter) { + auto buffer = std::string(); + auto bi = std::back_inserter(buffer); + auto it = fmt::detail::truncating_iterator<decltype(bi)>(bi, 2); + *it++ = '4'; + *it++ = '2'; + *it++ = '1'; + EXPECT_EQ(buffer.size(), 2); + EXPECT_EQ(buffer, "42"); } -TEST(CompileTest, MultipleTypes) { - auto f = fmt::detail::compile<int, int>("{} {}"); - EXPECT_EQ(fmt::format(f, 42, 42), "42 42"); +TEST(compile_test, compile_fallback) { + // FMT_COMPILE should fallback on runtime formatting when `if constexpr` is + // not available. + EXPECT_EQ("42", fmt::format(FMT_COMPILE("{}"), 42)); } -struct test_formattable {}; +struct type_with_get { + template <int> friend void get(type_with_get); +}; FMT_BEGIN_NAMESPACE -template <> struct formatter<test_formattable> : formatter<const char*> { +template <> struct formatter<type_with_get> : formatter<int> { template <typename FormatContext> - auto format(test_formattable, FormatContext& ctx) -> decltype(ctx.out()) { - return formatter<const char*>::format("foo", ctx); + auto format(type_with_get, FormatContext& ctx) -> decltype(ctx.out()) { + return formatter<int>::format(42, ctx); } }; FMT_END_NAMESPACE -TEST(CompileTest, FormatUserDefinedType) { - auto f = fmt::detail::compile<test_formattable>("{}"); - EXPECT_EQ(fmt::format(f, test_formattable()), "foo"); +TEST(compile_test, compile_type_with_get) { + EXPECT_EQ("42", fmt::format(FMT_COMPILE("{}"), type_with_get())); } -TEST(CompileTest, EmptyFormatString) { - auto f = fmt::detail::compile<>(""); - EXPECT_EQ(fmt::format(f), ""); -} +#if defined(__cpp_if_constexpr) && defined(__cpp_return_type_deduction) +struct test_formattable {}; + +FMT_BEGIN_NAMESPACE +template <> struct formatter<test_formattable> : formatter<const char*> { + char word_spec = 'f'; + constexpr auto parse(format_parse_context& ctx) { + auto it = ctx.begin(), end = ctx.end(); + if (it == end || *it == '}') return it; + if (it != end && (*it == 'f' || *it == 'b')) word_spec = *it++; + if (it != end && *it != '}') throw format_error("invalid format"); + return it; + } + template <typename FormatContext> + constexpr auto format(test_formattable, FormatContext& ctx) const + -> decltype(ctx.out()) { + return formatter<const char*>::format(word_spec == 'f' ? "foo" : "bar", + ctx); + } +}; +FMT_END_NAMESPACE -#ifdef __cpp_if_constexpr -TEST(CompileTest, FormatDefault) { +TEST(compile_test, format_default) { EXPECT_EQ("42", fmt::format(FMT_COMPILE("{}"), 42)); EXPECT_EQ("42", fmt::format(FMT_COMPILE("{}"), 42u)); EXPECT_EQ("42", fmt::format(FMT_COMPILE("{}"), 42ll)); @@ -130,22 +109,99 @@ TEST(CompileTest, FormatDefault) { EXPECT_EQ("foo", fmt::format(FMT_COMPILE("{}"), "foo")); EXPECT_EQ("foo", fmt::format(FMT_COMPILE("{}"), std::string("foo"))); EXPECT_EQ("foo", fmt::format(FMT_COMPILE("{}"), test_formattable())); + auto t = std::chrono::system_clock::now(); + EXPECT_EQ(fmt::format("{}", t), fmt::format(FMT_COMPILE("{}"), t)); +# ifdef __cpp_lib_byte + EXPECT_EQ("42", fmt::format(FMT_COMPILE("{}"), std::byte{42})); +# endif } -TEST(CompileTest, FormatWideString) { +TEST(compile_test, format_wide_string) { EXPECT_EQ(L"42", fmt::format(FMT_COMPILE(L"{}"), 42)); } -TEST(CompileTest, FormatSpecs) { +TEST(compile_test, format_specs) { EXPECT_EQ("42", fmt::format(FMT_COMPILE("{:x}"), 0x42)); + EXPECT_EQ("1.2 ms ", + fmt::format(FMT_COMPILE("{:7.1%Q %q}"), + std::chrono::duration<double, std::milli>(1.234))); +} + +TEST(compile_test, dynamic_format_specs) { + EXPECT_EQ("foo ", fmt::format(FMT_COMPILE("{:{}}"), "foo", 5)); + EXPECT_EQ(" 3.14", fmt::format(FMT_COMPILE("{:{}.{}f}"), 3.141592, 6, 2)); + EXPECT_EQ( + "=1.234ms=", + fmt::format(FMT_COMPILE("{:=^{}.{}}"), + std::chrono::duration<double, std::milli>(1.234), 9, 3)); } -TEST(CompileTest, DynamicWidth) { - EXPECT_EQ(" 42foo ", - fmt::format(FMT_COMPILE("{:{}}{:{}}"), 42, 4, "foo", 5)); +TEST(compile_test, manual_ordering) { + EXPECT_EQ("42", fmt::format(FMT_COMPILE("{0}"), 42)); + EXPECT_EQ(" -42", fmt::format(FMT_COMPILE("{0:4}"), -42)); + EXPECT_EQ("41 43", fmt::format(FMT_COMPILE("{0} {1}"), 41, 43)); + EXPECT_EQ("41 43", fmt::format(FMT_COMPILE("{1} {0}"), 43, 41)); + EXPECT_EQ("41 43", fmt::format(FMT_COMPILE("{0} {2}"), 41, 42, 43)); + EXPECT_EQ(" 41 43", fmt::format(FMT_COMPILE("{1:{2}} {0:4}"), 43, 41, 4)); + EXPECT_EQ("42 1.2 ms ", + fmt::format(FMT_COMPILE("{0} {1:7.1%Q %q}"), 42, + std::chrono::duration<double, std::milli>(1.234))); + EXPECT_EQ( + "true 42 42 foo 0x1234 foo", + fmt::format(FMT_COMPILE("{0} {1} {2} {3} {4} {5}"), true, 42, 42.0f, + "foo", reinterpret_cast<void*>(0x1234), test_formattable())); + EXPECT_EQ(L"42", fmt::format(FMT_COMPILE(L"{0}"), 42)); +} + +TEST(compile_test, named) { + auto runtime_named_field_compiled = + fmt::detail::compile<decltype(fmt::arg("arg", 42))>(FMT_COMPILE("{arg}")); + static_assert(std::is_same_v<decltype(runtime_named_field_compiled), + fmt::detail::runtime_named_field<char>>); + + EXPECT_EQ("42", fmt::format(FMT_COMPILE("{}"), fmt::arg("arg", 42))); + EXPECT_EQ("41 43", fmt::format(FMT_COMPILE("{} {}"), fmt::arg("arg", 41), + fmt::arg("arg", 43))); + + EXPECT_EQ("foobar", + fmt::format(FMT_COMPILE("{a0}{a1}"), fmt::arg("a0", "foo"), + fmt::arg("a1", "bar"))); + EXPECT_EQ("foobar", fmt::format(FMT_COMPILE("{}{a1}"), fmt::arg("a0", "foo"), + fmt::arg("a1", "bar"))); + EXPECT_EQ("foofoo", fmt::format(FMT_COMPILE("{a0}{}"), fmt::arg("a0", "foo"), + fmt::arg("a1", "bar"))); + EXPECT_EQ("foobar", fmt::format(FMT_COMPILE("{0}{a1}"), fmt::arg("a0", "foo"), + fmt::arg("a1", "bar"))); + EXPECT_EQ("foobar", fmt::format(FMT_COMPILE("{a0}{1}"), fmt::arg("a0", "foo"), + fmt::arg("a1", "bar"))); + + EXPECT_EQ("foobar", + fmt::format(FMT_COMPILE("{}{a1}"), "foo", fmt::arg("a1", "bar"))); + EXPECT_EQ("foobar", + fmt::format(FMT_COMPILE("{a0}{a1}"), fmt::arg("a1", "bar"), + fmt::arg("a2", "baz"), fmt::arg("a0", "foo"))); + EXPECT_EQ(" bar foo ", + fmt::format(FMT_COMPILE(" {foo} {bar} "), fmt::arg("foo", "bar"), + fmt::arg("bar", "foo"))); + + EXPECT_THROW(fmt::format(FMT_COMPILE("{invalid}"), fmt::arg("valid", 42)), + fmt::format_error); + +# if FMT_USE_NONTYPE_TEMPLATE_PARAMETERS + using namespace fmt::literals; + auto statically_named_field_compiled = + fmt::detail::compile<decltype("arg"_a = 42)>(FMT_COMPILE("{arg}")); + static_assert(std::is_same_v<decltype(statically_named_field_compiled), + fmt::detail::field<char, int, 0>>); + + EXPECT_EQ("41 43", + fmt::format(FMT_COMPILE("{a0} {a1}"), "a0"_a = 41, "a1"_a = 43)); + EXPECT_EQ("41 43", + fmt::format(FMT_COMPILE("{a1} {a0}"), "a0"_a = 43, "a1"_a = 41)); +# endif } -TEST(CompileTest, FormatTo) { +TEST(compile_test, format_to) { char buf[8]; auto end = fmt::format_to(buf, FMT_COMPILE("{}"), 42); *end = '\0'; @@ -155,7 +211,7 @@ TEST(CompileTest, FormatTo) { EXPECT_STREQ("2a", buf); } -TEST(CompileTest, FormatToNWithCompileMacro) { +TEST(compile_test, format_to_n) { constexpr auto buffer_size = 8; char buffer[buffer_size]; auto res = fmt::format_to_n(buffer, buffer_size, FMT_COMPILE("{}"), 42); @@ -166,8 +222,155 @@ TEST(CompileTest, FormatToNWithCompileMacro) { EXPECT_STREQ("2a", buffer); } -TEST(CompileTest, TextAndArg) { +TEST(compile_test, formatted_size) { + EXPECT_EQ(2, fmt::formatted_size(FMT_COMPILE("{0}"), 42)); + EXPECT_EQ(5, fmt::formatted_size(FMT_COMPILE("{0:<4.2f}"), 42.0)); +} + +TEST(compile_test, text_and_arg) { EXPECT_EQ(">>>42<<<", fmt::format(FMT_COMPILE(">>>{}<<<"), 42)); EXPECT_EQ("42!", fmt::format(FMT_COMPILE("{}!"), 42)); } + +TEST(compile_test, unknown_format_fallback) { + EXPECT_EQ(" 42 ", + fmt::format(FMT_COMPILE("{name:^4}"), fmt::arg("name", 42))); + + std::vector<char> v; + fmt::format_to(std::back_inserter(v), FMT_COMPILE("{name:^4}"), + fmt::arg("name", 42)); + EXPECT_EQ(" 42 ", fmt::string_view(v.data(), v.size())); + + char buffer[4]; + auto result = fmt::format_to_n(buffer, 4, FMT_COMPILE("{name:^5}"), + fmt::arg("name", 42)); + EXPECT_EQ(5u, result.size); + EXPECT_EQ(buffer + 4, result.out); + EXPECT_EQ(" 42 ", fmt::string_view(buffer, 4)); +} + +TEST(compile_test, empty) { EXPECT_EQ("", fmt::format(FMT_COMPILE(""))); } + +struct to_stringable { + friend fmt::string_view to_string_view(to_stringable) { return {}; } +}; + +FMT_BEGIN_NAMESPACE +template <> struct formatter<to_stringable> { + auto parse(format_parse_context& ctx) const -> decltype(ctx.begin()) { + return ctx.begin(); + } + + template <typename FormatContext> + auto format(const to_stringable&, FormatContext& ctx) -> decltype(ctx.out()) { + return ctx.out(); + } +}; +FMT_END_NAMESPACE + +TEST(compile_test, to_string_and_formatter) { + fmt::format(FMT_COMPILE("{}"), to_stringable()); +} + +TEST(compile_test, print) { + EXPECT_WRITE(stdout, fmt::print(FMT_COMPILE("Don't {}!"), "panic"), + "Don't panic!"); + EXPECT_WRITE(stderr, fmt::print(stderr, FMT_COMPILE("Don't {}!"), "panic"), + "Don't panic!"); +} +#endif + +#if FMT_USE_NONTYPE_TEMPLATE_PARAMETERS +TEST(compile_test, compile_format_string_literal) { + using namespace fmt::literals; + EXPECT_EQ("", fmt::format(""_cf)); + EXPECT_EQ("42", fmt::format("{}"_cf, 42)); + EXPECT_EQ(L"42", fmt::format(L"{}"_cf, 42)); +} +#endif + +#if __cplusplus >= 202002L || \ + (__cplusplus >= 201709L && FMT_GCC_VERSION >= 1002) +template <size_t max_string_length, typename Char = char> struct test_string { + template <typename T> constexpr bool operator==(const T& rhs) const noexcept { + return fmt::basic_string_view<Char>(rhs).compare(buffer) == 0; + } + Char buffer[max_string_length]{}; +}; + +template <size_t max_string_length, typename Char = char, typename... Args> +consteval auto test_format(auto format, const Args&... args) { + test_string<max_string_length, Char> string{}; + fmt::format_to(string.buffer, format, args...); + return string; +} + +TEST(compile_time_formatting_test, bool) { + EXPECT_EQ("true", test_format<5>(FMT_COMPILE("{}"), true)); + EXPECT_EQ("false", test_format<6>(FMT_COMPILE("{}"), false)); + EXPECT_EQ("true ", test_format<6>(FMT_COMPILE("{:5}"), true)); + EXPECT_EQ("1", test_format<2>(FMT_COMPILE("{:d}"), true)); +} + +TEST(compile_time_formatting_test, integer) { + EXPECT_EQ("42", test_format<3>(FMT_COMPILE("{}"), 42)); + EXPECT_EQ("420", test_format<4>(FMT_COMPILE("{}"), 420)); + EXPECT_EQ("42 42", test_format<6>(FMT_COMPILE("{} {}"), 42, 42)); + EXPECT_EQ("42 42", + test_format<6>(FMT_COMPILE("{} {}"), uint32_t{42}, uint64_t{42})); + + EXPECT_EQ("+42", test_format<4>(FMT_COMPILE("{:+}"), 42)); + EXPECT_EQ("42", test_format<3>(FMT_COMPILE("{:-}"), 42)); + EXPECT_EQ(" 42", test_format<4>(FMT_COMPILE("{: }"), 42)); + + EXPECT_EQ("-0042", test_format<6>(FMT_COMPILE("{:05}"), -42)); + + EXPECT_EQ("101010", test_format<7>(FMT_COMPILE("{:b}"), 42)); + EXPECT_EQ("0b101010", test_format<9>(FMT_COMPILE("{:#b}"), 42)); + EXPECT_EQ("0B101010", test_format<9>(FMT_COMPILE("{:#B}"), 42)); + EXPECT_EQ("042", test_format<4>(FMT_COMPILE("{:#o}"), 042)); + EXPECT_EQ("0x4a", test_format<5>(FMT_COMPILE("{:#x}"), 0x4a)); + EXPECT_EQ("0X4A", test_format<5>(FMT_COMPILE("{:#X}"), 0x4a)); + + EXPECT_EQ(" 42", test_format<6>(FMT_COMPILE("{:5}"), 42)); + EXPECT_EQ(" 42", test_format<6>(FMT_COMPILE("{:5}"), 42ll)); + EXPECT_EQ(" 42", test_format<6>(FMT_COMPILE("{:5}"), 42ull)); + + EXPECT_EQ("42 ", test_format<5>(FMT_COMPILE("{:<4}"), 42)); + EXPECT_EQ(" 42", test_format<5>(FMT_COMPILE("{:>4}"), 42)); + EXPECT_EQ(" 42 ", test_format<5>(FMT_COMPILE("{:^4}"), 42)); + EXPECT_EQ("**-42", test_format<6>(FMT_COMPILE("{:*>5}"), -42)); +} + +TEST(compile_time_formatting_test, char) { + EXPECT_EQ("c", test_format<2>(FMT_COMPILE("{}"), 'c')); + + EXPECT_EQ("c ", test_format<4>(FMT_COMPILE("{:3}"), 'c')); + EXPECT_EQ("99", test_format<3>(FMT_COMPILE("{:d}"), 'c')); +} + +TEST(compile_time_formatting_test, string) { + EXPECT_EQ("42", test_format<3>(FMT_COMPILE("{}"), "42")); + EXPECT_EQ("The answer is 42", + test_format<17>(FMT_COMPILE("{} is {}"), "The answer", "42")); + + EXPECT_EQ("abc**", test_format<6>(FMT_COMPILE("{:*<5}"), "abc")); + EXPECT_EQ("**🤡**", test_format<9>(FMT_COMPILE("{:*^6}"), "🤡")); +} + +TEST(compile_time_formatting_test, combination) { + EXPECT_EQ("420, true, answer", + test_format<18>(FMT_COMPILE("{}, {}, {}"), 420, true, "answer")); + + EXPECT_EQ(" -42", test_format<5>(FMT_COMPILE("{:{}}"), -42, 4)); +} + +TEST(compile_time_formatting_test, custom_type) { + EXPECT_EQ("foo", test_format<4>(FMT_COMPILE("{}"), test_formattable())); + EXPECT_EQ("bar", test_format<4>(FMT_COMPILE("{:b}"), test_formattable())); +} + +TEST(compile_time_formatting_test, multibyte_fill) { + EXPECT_EQ("жж42", test_format<8>(FMT_COMPILE("{:ж>4}"), 42)); +} #endif diff --git a/contrib/libs/fmt/test/core-test.cc b/contrib/libs/fmt/test/core-test.cc index a5fd01fa4d..b2f2097ea1 100644 --- a/contrib/libs/fmt/test/core-test.cc +++ b/contrib/libs/fmt/test/core-test.cc @@ -5,58 +5,128 @@ // // For the license information refer to format.h. -#include <algorithm> -#include <climits> -#include <cstring> -#include <functional> -#include <iterator> -#include <limits> -#include <memory> -#include <string> -#include <type_traits> - -#include <gmock/gmock.h> +// clang-format off #include "test-assert.h" - -// Check if fmt/core.h compiles with windows.h included before it. -#ifdef _WIN32 -# include <windows.h> -#endif +// clang-format on #include "fmt/core.h" -#undef min -#undef max +#include <algorithm> // std::copy_n +#include <climits> // INT_MAX +#include <cstring> // std::strlen +#include <functional> // std::equal_to +#include <iterator> // std::back_insert_iterator +#include <limits> // std::numeric_limits +#include <string> // std::string +#include <type_traits> // std::is_same + +#include "gmock/gmock.h" -using fmt::basic_format_arg; using fmt::string_view; using fmt::detail::buffer; -using fmt::detail::make_arg; -using fmt::detail::value; using testing::_; using testing::Invoke; using testing::Return; -using testing::StrictMock; -struct test_struct {}; +#ifdef FMT_FORMAT_H_ +# error core-test includes format.h +#endif -FMT_BEGIN_NAMESPACE -template <typename Char> struct formatter<test_struct, Char> { - template <typename ParseContext> - auto parse(ParseContext& ctx) -> decltype(ctx.begin()) { - return ctx.begin(); - } +TEST(string_view_test, value_type) { + static_assert(std::is_same<string_view::value_type, char>::value, ""); +} - auto format(test_struct, format_context& ctx) -> decltype(ctx.out()) { - const Char* test = "test"; - return std::copy_n(test, std::strlen(test), ctx.out()); +TEST(string_view_test, ctor) { + EXPECT_STREQ("abc", fmt::string_view("abc").data()); + EXPECT_EQ(3u, fmt::string_view("abc").size()); + + EXPECT_STREQ("defg", fmt::string_view(std::string("defg")).data()); + EXPECT_EQ(4u, fmt::string_view(std::string("defg")).size()); +} + +TEST(string_view_test, length) { + // Test that string_view::size() returns string length, not buffer size. + char str[100] = "some string"; + EXPECT_EQ(std::strlen(str), string_view(str).size()); + EXPECT_LT(std::strlen(str), sizeof(str)); +} + +// Check string_view's comparison operator. +template <template <typename> class Op> void check_op() { + const char* inputs[] = {"foo", "fop", "fo"}; + size_t num_inputs = sizeof(inputs) / sizeof(*inputs); + for (size_t i = 0; i < num_inputs; ++i) { + for (size_t j = 0; j < num_inputs; ++j) { + string_view lhs(inputs[i]), rhs(inputs[j]); + EXPECT_EQ(Op<int>()(lhs.compare(rhs), 0), Op<string_view>()(lhs, rhs)); + } } +} + +TEST(string_view_test, compare) { + EXPECT_EQ(string_view("foo").compare(string_view("foo")), 0); + EXPECT_GT(string_view("fop").compare(string_view("foo")), 0); + EXPECT_LT(string_view("foo").compare(string_view("fop")), 0); + EXPECT_GT(string_view("foo").compare(string_view("fo")), 0); + EXPECT_LT(string_view("fo").compare(string_view("foo")), 0); + check_op<std::equal_to>(); + check_op<std::not_equal_to>(); + check_op<std::less>(); + check_op<std::less_equal>(); + check_op<std::greater>(); + check_op<std::greater_equal>(); +} + +namespace test_ns { +template <typename Char> class test_string { + private: + std::basic_string<Char> s_; + + public: + test_string(const Char* s) : s_(s) {} + const Char* data() const { return s_.data(); } + size_t length() const { return s_.size(); } + operator const Char*() const { return s_.c_str(); } }; -FMT_END_NAMESPACE + +template <typename Char> +fmt::basic_string_view<Char> to_string_view(const test_string<Char>& s) { + return {s.data(), s.length()}; +} +} // namespace test_ns + +TEST(core_test, is_output_iterator) { + EXPECT_TRUE((fmt::detail::is_output_iterator<char*, char>::value)); + EXPECT_FALSE((fmt::detail::is_output_iterator<const char*, char>::value)); + EXPECT_FALSE((fmt::detail::is_output_iterator<std::string, char>::value)); + EXPECT_TRUE( + (fmt::detail::is_output_iterator<std::back_insert_iterator<std::string>, + char>::value)); + EXPECT_TRUE( + (fmt::detail::is_output_iterator<std::string::iterator, char>::value)); + EXPECT_FALSE((fmt::detail::is_output_iterator<std::string::const_iterator, + char>::value)); +} + +TEST(core_test, buffer_appender) { + // back_insert_iterator is not default-constructible before C++20, so + // buffer_appender can only be default-constructible when back_insert_iterator + // is. + static_assert( + std::is_default_constructible< + std::back_insert_iterator<fmt::detail::buffer<char>>>::value == + std::is_default_constructible< + fmt::detail::buffer_appender<char>>::value, + ""); + +#ifdef __cpp_lib_ranges + static_assert(std::output_iterator<fmt::detail::buffer_appender<char>, char>); +#endif +} #if !FMT_GCC_VERSION || FMT_GCC_VERSION >= 470 -TEST(BufferTest, Noncopyable) { +TEST(buffer_test, noncopyable) { EXPECT_FALSE(std::is_copy_constructible<buffer<char>>::value); # if !FMT_MSC_VER // std::is_copy_assignable is broken in MSVC2013. @@ -64,7 +134,7 @@ TEST(BufferTest, Noncopyable) { # endif } -TEST(BufferTest, Nonmoveable) { +TEST(buffer_test, nonmoveable) { EXPECT_FALSE(std::is_move_constructible<buffer<char>>::value); # if !FMT_MSC_VER // std::is_move_assignable is broken in MSVC2013. @@ -73,7 +143,7 @@ TEST(BufferTest, Nonmoveable) { } #endif -TEST(BufferTest, Indestructible) { +TEST(buffer_test, indestructible) { static_assert(!std::is_destructible<fmt::detail::buffer<int>>(), "buffer's destructor is protected"); } @@ -81,17 +151,19 @@ TEST(BufferTest, Indestructible) { template <typename T> struct mock_buffer final : buffer<T> { MOCK_METHOD1(do_grow, size_t(size_t capacity)); - void grow(size_t capacity) { this->set(this->data(), do_grow(capacity)); } + void grow(size_t capacity) override { + this->set(this->data(), do_grow(capacity)); + } - mock_buffer(T* data = nullptr, size_t capacity = 0) { - this->set(data, capacity); + mock_buffer(T* data = nullptr, size_t buf_capacity = 0) { + this->set(data, buf_capacity); ON_CALL(*this, do_grow(_)).WillByDefault(Invoke([](size_t capacity) { return capacity; })); } }; -TEST(BufferTest, Ctor) { +TEST(buffer_test, ctor) { { mock_buffer<int> buffer; EXPECT_EQ(nullptr, buffer.data()); @@ -115,7 +187,7 @@ TEST(BufferTest, Ctor) { } } -TEST(BufferTest, Access) { +TEST(buffer_test, access) { char data[10]; mock_buffer<char> buffer(data, sizeof(data)); buffer[0] = 11; @@ -126,7 +198,7 @@ TEST(BufferTest, Access) { EXPECT_EQ(42, const_buffer[3]); } -TEST(BufferTest, TryResize) { +TEST(buffer_test, try_resize) { char data[123]; mock_buffer<char> buffer(data, sizeof(data)); buffer[10] = 42; @@ -146,7 +218,7 @@ TEST(BufferTest, TryResize) { buffer.try_resize(200); } -TEST(BufferTest, TryResizePartial) { +TEST(buffer_test, try_resize_partial) { char data[10]; mock_buffer<char> buffer(data, sizeof(data)); EXPECT_CALL(buffer, do_grow(20)).WillOnce(Return(15)); @@ -155,7 +227,7 @@ TEST(BufferTest, TryResizePartial) { EXPECT_EQ(buffer.size(), 15); } -TEST(BufferTest, Clear) { +TEST(buffer_test, clear) { mock_buffer<char> buffer; EXPECT_CALL(buffer, do_grow(20)); buffer.try_resize(20); @@ -164,7 +236,7 @@ TEST(BufferTest, Clear) { EXPECT_EQ(20u, buffer.capacity()); } -TEST(BufferTest, Append) { +TEST(buffer_test, append) { char data[15]; mock_buffer<char> buffer(data, 10); auto test = "test"; @@ -179,7 +251,7 @@ TEST(BufferTest, Append) { EXPECT_EQ(12u, buffer.size()); } -TEST(BufferTest, AppendPartial) { +TEST(buffer_test, append_partial) { char data[10]; mock_buffer<char> buffer(data, sizeof(data)); testing::InSequence seq; @@ -193,7 +265,7 @@ TEST(BufferTest, AppendPartial) { buffer.append(test, test + 15); } -TEST(BufferTest, AppendAllocatesEnoughStorage) { +TEST(buffer_test, append_allocates_enough_storage) { char data[19]; mock_buffer<char> buffer(data, 10); auto test = "abcdefgh"; @@ -202,18 +274,14 @@ TEST(BufferTest, AppendAllocatesEnoughStorage) { buffer.append(test, test + 9); } -TEST(ArgTest, FormatArgs) { - auto args = fmt::format_args(); - EXPECT_FALSE(args.get(1)); -} - struct custom_context { using char_type = char; using parse_context_type = fmt::format_parse_context; + bool called = false; + template <typename T> struct formatter_type { - template <typename ParseContext> - auto parse(ParseContext& ctx) -> decltype(ctx.begin()) { + auto parse(fmt::format_parse_context& ctx) -> decltype(ctx.begin()) { return ctx.begin(); } @@ -223,31 +291,39 @@ struct custom_context { } }; - bool called; - fmt::format_parse_context ctx; - - fmt::format_parse_context& parse_context() { return ctx; } void advance_to(const char*) {} }; -TEST(ArgTest, MakeValueWithCustomContext) { +struct test_struct {}; + +FMT_BEGIN_NAMESPACE +template <typename Char> struct formatter<test_struct, Char> { + auto parse(format_parse_context& ctx) -> decltype(ctx.begin()) { + return ctx.begin(); + } + + auto format(test_struct, format_context& ctx) -> decltype(ctx.out()) { + auto test = string_view("test"); + return std::copy_n(test.data(), test.size(), ctx.out()); + } +}; +FMT_END_NAMESPACE + +TEST(arg_test, format_args) { + auto args = fmt::format_args(); + EXPECT_FALSE(args.get(1)); +} + +TEST(arg_test, make_value_with_custom_context) { auto t = test_struct(); fmt::detail::value<custom_context> arg( fmt::detail::arg_mapper<custom_context>().map(t)); - custom_context ctx = {false, fmt::format_parse_context("")}; - arg.custom.format(&t, ctx.parse_context(), ctx); + auto ctx = custom_context(); + auto parse_ctx = fmt::format_parse_context(""); + arg.custom.format(&t, parse_ctx, ctx); EXPECT_TRUE(ctx.called); } -FMT_BEGIN_NAMESPACE -namespace detail { -template <typename Char> -bool operator==(custom_value<Char> lhs, custom_value<Char> rhs) { - return lhs.value == rhs.value; -} -} // namespace detail -FMT_END_NAMESPACE - // Use a unique result type to make sure that there are no undesirable // conversions. struct test_result {}; @@ -288,81 +364,80 @@ VISIT_TYPE(long, long long); VISIT_TYPE(unsigned long, unsigned long long); #endif -#define CHECK_ARG_(Char, expected, value) \ - { \ - testing::StrictMock<mock_visitor<decltype(expected)>> visitor; \ - EXPECT_CALL(visitor, visit(expected)); \ - using iterator = std::back_insert_iterator<buffer<Char>>; \ - fmt::visit_format_arg( \ - visitor, make_arg<fmt::basic_format_context<iterator, Char>>(value)); \ +#define CHECK_ARG(Char, expected, value) \ + { \ + testing::StrictMock<mock_visitor<decltype(expected)>> visitor; \ + EXPECT_CALL(visitor, visit(expected)); \ + using iterator = std::back_insert_iterator<buffer<Char>>; \ + fmt::visit_format_arg( \ + visitor, \ + fmt::detail::make_arg<fmt::basic_format_context<iterator, Char>>( \ + value)); \ } -#define CHECK_ARG(value, typename_) \ - { \ - using value_type = decltype(value); \ - typename_ visit_type<value_type>::type expected = value; \ - CHECK_ARG_(char, expected, value) \ - CHECK_ARG_(wchar_t, expected, value) \ +#define CHECK_ARG_SIMPLE(value) \ + { \ + using value_type = decltype(value); \ + typename visit_type<value_type>::type expected = value; \ + CHECK_ARG(char, expected, value) \ + CHECK_ARG(wchar_t, expected, value) \ } -template <typename T> class NumericArgTest : public testing::Test {}; +template <typename T> class numeric_arg_test : public testing::Test {}; using types = - ::testing::Types<bool, signed char, unsigned char, signed, unsigned short, - int, unsigned, long, unsigned long, long long, - unsigned long long, float, double, long double>; -TYPED_TEST_CASE(NumericArgTest, types); + testing::Types<bool, signed char, unsigned char, short, unsigned short, int, + unsigned, long, unsigned long, long long, unsigned long long, + float, double, long double>; +TYPED_TEST_SUITE(numeric_arg_test, types); -template <typename T> -fmt::enable_if_t<std::is_integral<T>::value, T> test_value() { +template <typename T, fmt::enable_if_t<std::is_integral<T>::value, int> = 0> +T test_value() { return static_cast<T>(42); } -template <typename T> -fmt::enable_if_t<std::is_floating_point<T>::value, T> test_value() { +template <typename T, + fmt::enable_if_t<std::is_floating_point<T>::value, int> = 0> +T test_value() { return static_cast<T>(4.2); } -TYPED_TEST(NumericArgTest, MakeAndVisit) { - CHECK_ARG(test_value<TypeParam>(), typename); - CHECK_ARG(std::numeric_limits<TypeParam>::min(), typename); - CHECK_ARG(std::numeric_limits<TypeParam>::max(), typename); +TYPED_TEST(numeric_arg_test, make_and_visit) { + CHECK_ARG_SIMPLE(test_value<TypeParam>()); + CHECK_ARG_SIMPLE(std::numeric_limits<TypeParam>::min()); + CHECK_ARG_SIMPLE(std::numeric_limits<TypeParam>::max()); } -TEST(ArgTest, CharArg) { - CHECK_ARG_(char, 'a', 'a'); - CHECK_ARG_(wchar_t, L'a', 'a'); - CHECK_ARG_(wchar_t, L'a', L'a'); -} +TEST(arg_test, char_arg) { CHECK_ARG(char, 'a', 'a'); } -TEST(ArgTest, StringArg) { +TEST(arg_test, string_arg) { char str_data[] = "test"; char* str = str_data; const char* cstr = str; - CHECK_ARG_(char, cstr, str); + CHECK_ARG(char, cstr, str); - auto sref = string_view(str); - CHECK_ARG_(char, sref, std::string(str)); + auto sv = fmt::string_view(str); + CHECK_ARG(char, sv, std::string(str)); } -TEST(ArgTest, WStringArg) { +TEST(arg_test, wstring_arg) { wchar_t str_data[] = L"test"; wchar_t* str = str_data; const wchar_t* cstr = str; - fmt::wstring_view sref(str); - CHECK_ARG_(wchar_t, cstr, str); - CHECK_ARG_(wchar_t, cstr, cstr); - CHECK_ARG_(wchar_t, sref, std::wstring(str)); - CHECK_ARG_(wchar_t, sref, fmt::wstring_view(str)); + auto sv = fmt::basic_string_view<wchar_t>(str); + CHECK_ARG(wchar_t, cstr, str); + CHECK_ARG(wchar_t, cstr, cstr); + CHECK_ARG(wchar_t, sv, std::wstring(str)); + CHECK_ARG(wchar_t, sv, fmt::basic_string_view<wchar_t>(str)); } -TEST(ArgTest, PointerArg) { +TEST(arg_test, pointer_arg) { void* p = nullptr; const void* cp = nullptr; - CHECK_ARG_(char, cp, p); - CHECK_ARG_(wchar_t, cp, p); - CHECK_ARG(cp, ); + CHECK_ARG(char, cp, p); + CHECK_ARG(wchar_t, cp, p); + CHECK_ARG_SIMPLE(cp); } struct check_custom { @@ -371,222 +446,237 @@ struct check_custom { struct test_buffer final : fmt::detail::buffer<char> { char data[10]; test_buffer() : fmt::detail::buffer<char>(data, 0, 10) {} - void grow(size_t) {} + void grow(size_t) override {} } buffer; - fmt::format_parse_context parse_ctx(""); - fmt::format_context ctx{fmt::detail::buffer_appender<char>(buffer), - fmt::format_args()}; + auto parse_ctx = fmt::format_parse_context(""); + auto ctx = fmt::format_context(fmt::detail::buffer_appender<char>(buffer), + fmt::format_args()); h.format(parse_ctx, ctx); EXPECT_EQ("test", std::string(buffer.data, buffer.size())); return test_result(); } }; -TEST(ArgTest, CustomArg) { - test_struct test; +TEST(arg_test, custom_arg) { + auto test = test_struct(); using visitor = mock_visitor<fmt::basic_format_arg<fmt::format_context>::handle>; testing::StrictMock<visitor> v; EXPECT_CALL(v, visit(_)).WillOnce(Invoke(check_custom())); - fmt::visit_format_arg(v, make_arg<fmt::format_context>(test)); + fmt::visit_format_arg(v, fmt::detail::make_arg<fmt::format_context>(test)); } -TEST(ArgTest, VisitInvalidArg) { +TEST(arg_test, visit_invalid_arg) { testing::StrictMock<mock_visitor<fmt::monostate>> visitor; EXPECT_CALL(visitor, visit(_)); - fmt::basic_format_arg<fmt::format_context> arg; + auto arg = fmt::basic_format_arg<fmt::format_context>(); fmt::visit_format_arg(visitor, arg); } -TEST(FormatDynArgsTest, Basic) { - fmt::dynamic_format_arg_store<fmt::format_context> store; - store.push_back(42); - store.push_back("abc1"); - store.push_back(1.5f); - EXPECT_EQ("42 and abc1 and 1.5", fmt::vformat("{} and {} and {}", store)); -} - -TEST(FormatDynArgsTest, StringsAndRefs) { - // Unfortunately the tests are compiled with old ABI so strings use COW. - fmt::dynamic_format_arg_store<fmt::format_context> store; - char str[] = "1234567890"; - store.push_back(str); - store.push_back(std::cref(str)); - store.push_back(fmt::string_view{str}); - str[0] = 'X'; +#if FMT_USE_CONSTEXPR - std::string result = fmt::vformat("{} and {} and {}", store); - EXPECT_EQ("1234567890 and X234567890 and X234567890", result); -} +enum class arg_id_result { none, empty, index, name, error }; +struct test_arg_id_handler { + arg_id_result res = arg_id_result::none; + int index = 0; + string_view name; -struct custom_type { - int i = 0; -}; + constexpr void operator()() { res = arg_id_result::empty; } -FMT_BEGIN_NAMESPACE -template <> struct formatter<custom_type> { - auto parse(format_parse_context& ctx) const -> decltype(ctx.begin()) { - return ctx.begin(); + constexpr void operator()(int i) { + res = arg_id_result::index; + index = i; } - template <typename FormatContext> - auto format(const custom_type& p, FormatContext& ctx) -> decltype(ctx.out()) { - return format_to(ctx.out(), "cust={}", p.i); + constexpr void operator()(string_view n) { + res = arg_id_result::name; + name = n; } + + constexpr void on_error(const char*) { res = arg_id_result::error; } }; -FMT_END_NAMESPACE -TEST(FormatDynArgsTest, CustomFormat) { - fmt::dynamic_format_arg_store<fmt::format_context> store; - custom_type c{}; - store.push_back(c); - ++c.i; - store.push_back(c); - ++c.i; - store.push_back(std::cref(c)); - ++c.i; - std::string result = fmt::vformat("{} and {} and {}", store); - EXPECT_EQ("cust=0 and cust=1 and cust=3", result); -} - -TEST(FormatDynArgsTest, NamedInt) { - fmt::dynamic_format_arg_store<fmt::format_context> store; - store.push_back(fmt::arg("a1", 42)); - EXPECT_EQ("42", fmt::vformat("{a1}", store)); -} - -TEST(FormatDynArgsTest, NamedStrings) { - fmt::dynamic_format_arg_store<fmt::format_context> store; - char str[]{"1234567890"}; - store.push_back(fmt::arg("a1", str)); - store.push_back(fmt::arg("a2", std::cref(str))); - str[0] = 'X'; - EXPECT_EQ("1234567890 and X234567890", fmt::vformat("{a1} and {a2}", store)); -} - -TEST(FormatDynArgsTest, NamedArgByRef) { - fmt::dynamic_format_arg_store<fmt::format_context> store; - - // Note: fmt::arg() constructs an object which holds a reference - // to its value. It's not an aggregate, so it doesn't extend the - // reference lifetime. As a result, it's a very bad idea passing temporary - // as a named argument value. Only GCC with optimization level >0 - // complains about this. - // - // A real life usecase is when you have both name and value alive - // guarantee their lifetime and thus don't want them to be copied into - // storages. - int a1_val{42}; - auto a1 = fmt::arg("a1_", a1_val); - store.push_back("abc"); - store.push_back(1.5f); - store.push_back(std::cref(a1)); - - std::string result = fmt::vformat("{a1_} and {} and {} and {}", store); - EXPECT_EQ("42 and abc and 1.5 and 42", result); -} - -TEST(FormatDynArgsTest, NamedCustomFormat) { - fmt::dynamic_format_arg_store<fmt::format_context> store; - custom_type c{}; - store.push_back(fmt::arg("c1", c)); - ++c.i; - store.push_back(fmt::arg("c2", c)); - ++c.i; - store.push_back(fmt::arg("c_ref", std::cref(c))); - ++c.i; - std::string result = fmt::vformat("{c1} and {c2} and {c_ref}", store); - EXPECT_EQ("cust=0 and cust=1 and cust=3", result); -} - -TEST(FormatDynArgsTest, Clear) { - fmt::dynamic_format_arg_store<fmt::format_context> store; - store.push_back(42); - - std::string result = fmt::vformat("{}", store); - EXPECT_EQ("42", result); - - store.push_back(43); - result = fmt::vformat("{} and {}", store); - EXPECT_EQ("42 and 43", result); - - store.clear(); - store.push_back(44); - result = fmt::vformat("{}", store); - EXPECT_EQ("44", result); -} - -TEST(FormatDynArgsTest, Reserve) { - fmt::dynamic_format_arg_store<fmt::format_context> store; - store.reserve(2, 1); - store.push_back(1.5f); - store.push_back(fmt::arg("a1", 42)); - std::string result = fmt::vformat("{a1} and {}", store); - EXPECT_EQ("42 and 1.5", result); -} - -struct copy_throwable { - copy_throwable() {} - copy_throwable(const copy_throwable&) { throw "deal with it"; } +template <size_t N> +constexpr test_arg_id_handler parse_arg_id(const char (&s)[N]) { + test_arg_id_handler h; + fmt::detail::parse_arg_id(s, s + N, h); + return h; +} + +TEST(format_test, constexpr_parse_arg_id) { + static_assert(parse_arg_id(":").res == arg_id_result::empty, ""); + static_assert(parse_arg_id("}").res == arg_id_result::empty, ""); + static_assert(parse_arg_id("42:").res == arg_id_result::index, ""); + static_assert(parse_arg_id("42:").index == 42, ""); + static_assert(parse_arg_id("foo:").res == arg_id_result::name, ""); + static_assert(parse_arg_id("foo:").name.size() == 3, ""); + static_assert(parse_arg_id("!").res == arg_id_result::error, ""); +} + +struct test_format_specs_handler { + enum result { none, hash, zero, loc, error }; + result res = none; + + fmt::align_t alignment = fmt::align::none; + fmt::sign_t sign = fmt::sign::none; + char fill = 0; + int width = 0; + fmt::detail::arg_ref<char> width_ref; + int precision = 0; + fmt::detail::arg_ref<char> precision_ref; + fmt::presentation_type type = fmt::presentation_type::none; + + // Workaround for MSVC2017 bug that results in "expression did not evaluate + // to a constant" with compiler-generated copy ctor. + constexpr test_format_specs_handler() {} + constexpr test_format_specs_handler(const test_format_specs_handler& other) = + default; + + constexpr void on_align(fmt::align_t a) { alignment = a; } + constexpr void on_fill(fmt::string_view f) { fill = f[0]; } + constexpr void on_sign(fmt::sign_t s) { sign = s; } + constexpr void on_hash() { res = hash; } + constexpr void on_zero() { res = zero; } + constexpr void on_localized() { res = loc; } + + constexpr void on_width(int w) { width = w; } + constexpr void on_dynamic_width(fmt::detail::auto_id) {} + constexpr void on_dynamic_width(int index) { width_ref = index; } + constexpr void on_dynamic_width(string_view) {} + + constexpr void on_precision(int p) { precision = p; } + constexpr void on_dynamic_precision(fmt::detail::auto_id) {} + constexpr void on_dynamic_precision(int index) { precision_ref = index; } + constexpr void on_dynamic_precision(string_view) {} + + constexpr void end_precision() {} + constexpr void on_type(fmt::presentation_type t) { type = t; } + constexpr void on_error(const char*) { res = error; } }; -FMT_BEGIN_NAMESPACE -template <> struct formatter<copy_throwable> { - auto parse(format_parse_context& ctx) const -> decltype(ctx.begin()) { - return ctx.begin(); - } - auto format(copy_throwable, format_context& ctx) -> decltype(ctx.out()) { - return ctx.out(); - } +template <size_t N> +constexpr test_format_specs_handler parse_test_specs(const char (&s)[N]) { + auto h = test_format_specs_handler(); + fmt::detail::parse_format_specs(s, s + N - 1, h); + return h; +} + +TEST(core_test, constexpr_parse_format_specs) { + using handler = test_format_specs_handler; + static_assert(parse_test_specs("<").alignment == fmt::align::left, ""); + static_assert(parse_test_specs("*^").fill == '*', ""); + static_assert(parse_test_specs("+").sign == fmt::sign::plus, ""); + static_assert(parse_test_specs("-").sign == fmt::sign::minus, ""); + static_assert(parse_test_specs(" ").sign == fmt::sign::space, ""); + static_assert(parse_test_specs("#").res == handler::hash, ""); + static_assert(parse_test_specs("0").res == handler::zero, ""); + static_assert(parse_test_specs("L").res == handler::loc, ""); + static_assert(parse_test_specs("42").width == 42, ""); + static_assert(parse_test_specs("{42}").width_ref.val.index == 42, ""); + static_assert(parse_test_specs(".42").precision == 42, ""); + static_assert(parse_test_specs(".{42}").precision_ref.val.index == 42, ""); + static_assert(parse_test_specs("d").type == fmt::presentation_type::dec, ""); + static_assert(parse_test_specs("{<").res == handler::error, ""); +} + +struct test_parse_context { + using char_type = char; + + constexpr int next_arg_id() { return 11; } + template <typename Id> FMT_CONSTEXPR void check_arg_id(Id) {} + + constexpr const char* begin() { return nullptr; } + constexpr const char* end() { return nullptr; } + + void on_error(const char*) {} }; -FMT_END_NAMESPACE -TEST(FormatDynArgsTest, ThrowOnCopy) { - fmt::dynamic_format_arg_store<fmt::format_context> store; - store.push_back(std::string("foo")); - try { - store.push_back(copy_throwable()); - } catch (...) { - } - EXPECT_EQ(fmt::vformat("{}", store), "foo"); +template <size_t N> +constexpr fmt::detail::dynamic_format_specs<char> parse_dynamic_specs( + const char (&s)[N]) { + auto specs = fmt::detail::dynamic_format_specs<char>(); + auto ctx = test_parse_context(); + auto h = fmt::detail::dynamic_specs_handler<test_parse_context>(specs, ctx); + parse_format_specs(s, s + N - 1, h); + return specs; +} + +TEST(format_test, constexpr_dynamic_specs_handler) { + static_assert(parse_dynamic_specs("<").align == fmt::align::left, ""); + static_assert(parse_dynamic_specs("*^").fill[0] == '*', ""); + static_assert(parse_dynamic_specs("+").sign == fmt::sign::plus, ""); + static_assert(parse_dynamic_specs("-").sign == fmt::sign::minus, ""); + static_assert(parse_dynamic_specs(" ").sign == fmt::sign::space, ""); + static_assert(parse_dynamic_specs("#").alt, ""); + static_assert(parse_dynamic_specs("0").align == fmt::align::numeric, ""); + static_assert(parse_dynamic_specs("42").width == 42, ""); + static_assert(parse_dynamic_specs("{}").width_ref.val.index == 11, ""); + static_assert(parse_dynamic_specs("{42}").width_ref.val.index == 42, ""); + static_assert(parse_dynamic_specs(".42").precision == 42, ""); + static_assert(parse_dynamic_specs(".{}").precision_ref.val.index == 11, ""); + static_assert(parse_dynamic_specs(".{42}").precision_ref.val.index == 42, ""); + static_assert(parse_dynamic_specs("d").type == fmt::presentation_type::dec, + ""); } -TEST(StringViewTest, ValueType) { - static_assert(std::is_same<string_view::value_type, char>::value, ""); +template <size_t N> +constexpr test_format_specs_handler check_specs(const char (&s)[N]) { + fmt::detail::specs_checker<test_format_specs_handler> checker( + test_format_specs_handler(), fmt::detail::type::double_type); + parse_format_specs(s, s + N - 1, checker); + return checker; } -TEST(StringViewTest, Length) { - // Test that string_view::size() returns string length, not buffer size. - char str[100] = "some string"; - EXPECT_EQ(std::strlen(str), string_view(str).size()); - EXPECT_LT(std::strlen(str), sizeof(str)); +TEST(format_test, constexpr_specs_checker) { + using handler = test_format_specs_handler; + static_assert(check_specs("<").alignment == fmt::align::left, ""); + static_assert(check_specs("*^").fill == '*', ""); + static_assert(check_specs("+").sign == fmt::sign::plus, ""); + static_assert(check_specs("-").sign == fmt::sign::minus, ""); + static_assert(check_specs(" ").sign == fmt::sign::space, ""); + static_assert(check_specs("#").res == handler::hash, ""); + static_assert(check_specs("0").res == handler::zero, ""); + static_assert(check_specs("42").width == 42, ""); + static_assert(check_specs("{42}").width_ref.val.index == 42, ""); + static_assert(check_specs(".42").precision == 42, ""); + static_assert(check_specs(".{42}").precision_ref.val.index == 42, ""); + static_assert(check_specs("d").type == fmt::presentation_type::dec, ""); + static_assert(check_specs("{<").res == handler::error, ""); } -// Check string_view's comparison operator. -template <template <typename> class Op> void check_op() { - const char* inputs[] = {"foo", "fop", "fo"}; - size_t num_inputs = sizeof(inputs) / sizeof(*inputs); - for (size_t i = 0; i < num_inputs; ++i) { - for (size_t j = 0; j < num_inputs; ++j) { - string_view lhs(inputs[i]), rhs(inputs[j]); - EXPECT_EQ(Op<int>()(lhs.compare(rhs), 0), Op<string_view>()(lhs, rhs)); - } +struct test_format_string_handler { + constexpr void on_text(const char*, const char*) {} + + constexpr int on_arg_id() { return 0; } + + template <typename T> constexpr int on_arg_id(T) { return 0; } + + constexpr void on_replacement_field(int, const char*) {} + + constexpr const char* on_format_specs(int, const char* begin, const char*) { + return begin; } + + constexpr void on_error(const char*) { error = true; } + + bool error = false; +}; + +template <size_t N> constexpr bool parse_string(const char (&s)[N]) { + auto h = test_format_string_handler(); + fmt::detail::parse_format_string<true>(fmt::string_view(s, N - 1), h); + return !h.error; } -TEST(StringViewTest, Compare) { - EXPECT_EQ(string_view("foo").compare(string_view("foo")), 0); - EXPECT_GT(string_view("fop").compare(string_view("foo")), 0); - EXPECT_LT(string_view("foo").compare(string_view("fop")), 0); - EXPECT_GT(string_view("foo").compare(string_view("fo")), 0); - EXPECT_LT(string_view("fo").compare(string_view("foo")), 0); - check_op<std::equal_to>(); - check_op<std::not_equal_to>(); - check_op<std::less>(); - check_op<std::less_equal>(); - check_op<std::greater>(); - check_op<std::greater_equal>(); +TEST(format_test, constexpr_parse_format_string) { + static_assert(parse_string("foo"), ""); + static_assert(!parse_string("}"), ""); + static_assert(parse_string("{}"), ""); + static_assert(parse_string("{42}"), ""); + static_assert(parse_string("{foo}"), ""); + static_assert(parse_string("{:}"), ""); } +#endif // FMT_USE_CONSTEXPR struct enabled_formatter {}; struct disabled_formatter {}; @@ -605,7 +695,7 @@ template <> struct formatter<enabled_formatter> { }; FMT_END_NAMESPACE -TEST(CoreTest, HasFormatter) { +TEST(core_test, has_formatter) { using fmt::has_formatter; using context = fmt::format_context; static_assert(has_formatter<enabled_formatter, context>::value, ""); @@ -614,6 +704,90 @@ TEST(CoreTest, HasFormatter) { ""); } +struct const_formattable {}; +struct nonconst_formattable {}; + +FMT_BEGIN_NAMESPACE +template <> struct formatter<const_formattable> { + auto parse(format_parse_context& ctx) -> decltype(ctx.begin()) { + return ctx.begin(); + } + + auto format(const const_formattable&, format_context& ctx) + -> decltype(ctx.out()) { + auto test = string_view("test"); + return std::copy_n(test.data(), test.size(), ctx.out()); + } +}; + +template <> struct formatter<nonconst_formattable> { + auto parse(format_parse_context& ctx) -> decltype(ctx.begin()) { + return ctx.begin(); + } + + auto format(nonconst_formattable&, format_context& ctx) + -> decltype(ctx.out()) { + auto test = string_view("test"); + return std::copy_n(test.data(), test.size(), ctx.out()); + } +}; +FMT_END_NAMESPACE + +struct convertible_to_pointer { + operator const int*() const { return nullptr; } +}; + +enum class test_scoped_enum {}; + +TEST(core_test, is_formattable) { +#if 0 + // This should be enabled once corresponding map overloads are gone. + static_assert(fmt::is_formattable<signed char*>::value, ""); + static_assert(fmt::is_formattable<unsigned char*>::value, ""); + static_assert(fmt::is_formattable<const signed char*>::value, ""); + static_assert(fmt::is_formattable<const unsigned char*>::value, ""); +#endif + static_assert(!fmt::is_formattable<wchar_t>::value, ""); +#ifdef __cpp_char8_t + static_assert(!fmt::is_formattable<char8_t>::value, ""); +#endif + static_assert(!fmt::is_formattable<char16_t>::value, ""); + static_assert(!fmt::is_formattable<char32_t>::value, ""); + static_assert(!fmt::is_formattable<const wchar_t*>::value, ""); + static_assert(!fmt::is_formattable<const wchar_t[3]>::value, ""); + static_assert(!fmt::is_formattable<fmt::basic_string_view<wchar_t>>::value, + ""); + static_assert(fmt::is_formattable<enabled_formatter>::value, ""); + static_assert(!fmt::is_formattable<disabled_formatter>::value, ""); + static_assert(fmt::is_formattable<disabled_formatter_convertible>::value, ""); + + static_assert(fmt::is_formattable<const_formattable&>::value, ""); + static_assert(fmt::is_formattable<const const_formattable&>::value, ""); + + static_assert(fmt::is_formattable<nonconst_formattable&>::value, ""); +#if !FMT_MSC_VER || FMT_MSC_VER >= 1910 + static_assert(!fmt::is_formattable<const nonconst_formattable&>::value, ""); +#endif + + static_assert(!fmt::is_formattable<convertible_to_pointer>::value, ""); + + static_assert(!fmt::is_formattable<void (*)()>::value, ""); + + struct s; + + static_assert(!fmt::is_formattable<int(s::*)>::value, ""); + static_assert(!fmt::is_formattable<int (s::*)()>::value, ""); + static_assert(!fmt::is_formattable<test_scoped_enum>::value, ""); +} + +TEST(core_test, format) { EXPECT_EQ(fmt::format("{}", 42), "42"); } + +TEST(core_test, format_to) { + std::string s; + fmt::format_to(std::back_inserter(s), "{}", 42); + EXPECT_EQ(s, "42"); +} + struct convertible_to_int { operator int() const { return 42; } }; @@ -633,7 +807,7 @@ template <> struct formatter<convertible_to_int> { }; template <> struct formatter<convertible_to_c_string> { - auto parse(format_parse_context& ctx) -> decltype(ctx.begin()) { + FMT_CONSTEXPR auto parse(format_parse_context& ctx) -> decltype(ctx.begin()) { return ctx.begin(); } auto format(convertible_to_c_string, format_context& ctx) @@ -643,90 +817,26 @@ template <> struct formatter<convertible_to_c_string> { }; FMT_END_NAMESPACE -TEST(CoreTest, FormatterOverridesImplicitConversion) { +TEST(core_test, formatter_overrides_implicit_conversion) { EXPECT_EQ(fmt::format("{}", convertible_to_int()), "foo"); EXPECT_EQ(fmt::format("{}", convertible_to_c_string()), "bar"); } -namespace my_ns { -template <typename Char> class my_string { - private: - std::basic_string<Char> s_; - - public: - my_string(const Char* s) : s_(s) {} - const Char* data() const FMT_NOEXCEPT { return s_.data(); } - size_t length() const FMT_NOEXCEPT { return s_.size(); } - operator const Char*() const { return s_.c_str(); } -}; - -template <typename Char> -inline fmt::basic_string_view<Char> to_string_view(const my_string<Char>& s) - FMT_NOEXCEPT { - return {s.data(), s.length()}; -} - -struct non_string {}; -} // namespace my_ns - -template <typename T> class IsStringTest : public testing::Test {}; - -typedef ::testing::Types<char, wchar_t, char16_t, char32_t> StringCharTypes; -TYPED_TEST_CASE(IsStringTest, StringCharTypes); - -namespace { -template <typename Char> -struct derived_from_string_view : fmt::basic_string_view<Char> {}; -} // namespace - -TYPED_TEST(IsStringTest, IsString) { - EXPECT_TRUE(fmt::detail::is_string<TypeParam*>::value); - EXPECT_TRUE(fmt::detail::is_string<const TypeParam*>::value); - EXPECT_TRUE(fmt::detail::is_string<TypeParam[2]>::value); - EXPECT_TRUE(fmt::detail::is_string<const TypeParam[2]>::value); - EXPECT_TRUE(fmt::detail::is_string<std::basic_string<TypeParam>>::value); - EXPECT_TRUE(fmt::detail::is_string<fmt::basic_string_view<TypeParam>>::value); - EXPECT_TRUE( - fmt::detail::is_string<derived_from_string_view<TypeParam>>::value); - using string_view = fmt::detail::std_string_view<TypeParam>; - EXPECT_TRUE(std::is_empty<string_view>::value != - fmt::detail::is_string<string_view>::value); - EXPECT_TRUE(fmt::detail::is_string<my_ns::my_string<TypeParam>>::value); - EXPECT_FALSE(fmt::detail::is_string<my_ns::non_string>::value); -} - -TEST(CoreTest, Format) { - // This should work without including fmt/format.h. -#ifdef FMT_FORMAT_H_ -# error fmt/format.h must not be included in the core test -#endif - EXPECT_EQ(fmt::format("{}", 42), "42"); -} - -TEST(CoreTest, FormatTo) { - // This should work without including fmt/format.h. -#ifdef FMT_FORMAT_H_ -# error fmt/format.h must not be included in the core test -#endif - std::string s; - fmt::format_to(std::back_inserter(s), "{}", 42); - EXPECT_EQ(s, "42"); +// Test that check is not found by ADL. +template <typename T> void check(T); +TEST(core_test, adl_check) { + EXPECT_EQ(fmt::format("{}", test_struct()), "test"); } -TEST(CoreTest, ToStringViewForeignStrings) { - using namespace my_ns; - EXPECT_EQ(to_string_view(my_string<char>("42")), "42"); +TEST(core_test, to_string_view_foreign_strings) { + using namespace test_ns; + EXPECT_EQ(to_string_view(test_string<char>("42")), "42"); fmt::detail::type type = - fmt::detail::mapped_type_constant<my_string<char>, + fmt::detail::mapped_type_constant<test_string<char>, fmt::format_context>::value; EXPECT_EQ(type, fmt::detail::type::string_type); } -TEST(CoreTest, FormatForeignStrings) { - using namespace my_ns; - EXPECT_EQ(fmt::format(my_string<char>("{}"), 42), "42"); -} - struct implicitly_convertible_to_string { operator std::string() const { return "foo"; } }; @@ -735,7 +845,7 @@ struct implicitly_convertible_to_string_view { operator fmt::string_view() const { return "foo"; } }; -TEST(CoreTest, FormatImplicitlyConvertibleToStringView) { +TEST(core_test, format_implicitly_convertible_to_string_view) { EXPECT_EQ("foo", fmt::format("{}", implicitly_convertible_to_string_view())); } @@ -745,7 +855,7 @@ struct explicitly_convertible_to_string_view { explicit operator fmt::string_view() const { return "foo"; } }; -TEST(CoreTest, FormatExplicitlyConvertibleToStringView) { +TEST(core_test, format_explicitly_convertible_to_string_view) { EXPECT_EQ("foo", fmt::format("{}", explicitly_convertible_to_string_view())); } @@ -754,13 +864,21 @@ struct explicitly_convertible_to_std_string_view { explicit operator std::string_view() const { return "foo"; } }; -TEST(CoreTest, FormatExplicitlyConvertibleToStdStringView) { +TEST(core_test, format_explicitly_convertible_to_std_string_view) { EXPECT_EQ("foo", fmt::format("{}", explicitly_convertible_to_std_string_view())); } # endif #endif +struct convertible_to_long_long { + operator long long() const { return 1LL << 32; } +}; + +TEST(format_test, format_convertible_to_long_long) { + EXPECT_EQ("100000000", fmt::format("{:x}", convertible_to_long_long())); +} + struct disabled_rvalue_conversion { operator const char*() const& { return "foo"; } operator const char*() & { return "foo"; } @@ -768,6 +886,38 @@ struct disabled_rvalue_conversion { operator const char*() && = delete; }; -TEST(CoreTest, DisabledRValueConversion) { +TEST(core_test, disabled_rvalue_conversion) { EXPECT_EQ("foo", fmt::format("{}", disabled_rvalue_conversion())); } + +namespace adl_test { +template <typename... T> void make_format_args(const T&...) = delete; + +struct string : std::string {}; +} // namespace adl_test + +// Test that formatting functions compile when make_format_args is found by ADL. +TEST(core_test, adl) { + // Only check compilation and don't run the code to avoid polluting the output + // and since the output is tested elsewhere. + if (fmt::detail::const_check(true)) return; + auto s = adl_test::string(); + char buf[10]; + (void)fmt::format("{}", s); + fmt::format_to(buf, "{}", s); + fmt::format_to_n(buf, 10, "{}", s); + (void)fmt::formatted_size("{}", s); + fmt::print("{}", s); + fmt::print(stdout, "{}", s); +} + +TEST(core_test, has_const_formatter) { + EXPECT_TRUE((fmt::detail::has_const_formatter<const_formattable, + fmt::format_context>())); + EXPECT_FALSE((fmt::detail::has_const_formatter<nonconst_formattable, + fmt::format_context>())); +} + +TEST(core_test, format_nonconst) { + EXPECT_EQ(fmt::format("{}", nonconst_formattable()), "test"); +} diff --git a/contrib/libs/fmt/test/enforce-checks-test.cc b/contrib/libs/fmt/test/enforce-checks-test.cc new file mode 100644 index 0000000000..c77cb142f6 --- /dev/null +++ b/contrib/libs/fmt/test/enforce-checks-test.cc @@ -0,0 +1,63 @@ +// Formatting library for C++ - formatting library tests +// +// Copyright (c) 2012 - present, Victor Zverovich +// All rights reserved. +// +// For the license information refer to format.h. + +#include <iterator> +#include <vector> + +#include "fmt/chrono.h" +#include "fmt/color.h" +#include "fmt/format.h" +#include "fmt/ostream.h" +#include "fmt/ranges.h" +#include "fmt/xchar.h" + +// Exercise the API to verify that everything we expect to can compile. +void test_format_api() { + (void)fmt::format(FMT_STRING("{}"), 42); + (void)fmt::format(FMT_STRING(L"{}"), 42); + (void)fmt::format(FMT_STRING("noop")); + + (void)fmt::to_string(42); + (void)fmt::to_wstring(42); + + std::vector<char> out; + fmt::format_to(std::back_inserter(out), FMT_STRING("{}"), 42); + + char buffer[4]; + fmt::format_to_n(buffer, 3, FMT_STRING("{}"), 12345); + + wchar_t wbuffer[4]; + fmt::format_to_n(wbuffer, 3, FMT_STRING(L"{}"), 12345); +} + +void test_chrono() { + (void)fmt::format(FMT_STRING("{}"), std::chrono::seconds(42)); + (void)fmt::format(FMT_STRING(L"{}"), std::chrono::seconds(42)); +} + +void test_text_style() { + fmt::print(fg(fmt::rgb(255, 20, 30)), FMT_STRING("{}"), "rgb(255,20,30)"); + (void)fmt::format(fg(fmt::rgb(255, 20, 30)), FMT_STRING("{}"), + "rgb(255,20,30)"); + + fmt::text_style ts = fg(fmt::rgb(255, 20, 30)); + std::string out; + fmt::format_to(std::back_inserter(out), ts, + FMT_STRING("rgb(255,20,30){}{}{}"), 1, 2, 3); +} + +void test_range() { + std::vector<char> hello = {'h', 'e', 'l', 'l', 'o'}; + (void)fmt::format(FMT_STRING("{}"), hello); +} + +int main() { + test_format_api(); + test_chrono(); + test_text_style(); + test_range(); +} diff --git a/contrib/libs/fmt/test/format-impl-test.cc b/contrib/libs/fmt/test/format-impl-test.cc index 66b55b5381..a012306f5b 100644 --- a/contrib/libs/fmt/test/format-impl-test.cc +++ b/contrib/libs/fmt/test/format-impl-test.cc @@ -5,24 +5,16 @@ // // For the license information refer to format.h. -#define FMT_NOEXCEPT -#undef FMT_SHARED -#include "test-assert.h" - -// Include format.cc instead of format.h to test implementation. #include <algorithm> #include <cstring> -#include "../src/format.cc" -#include "fmt/printf.h" -#include <gmock/gmock.h> -#include "gtest-extra.h" -#include "util.h" +// clang-format off +#include "test-assert.h" +// clang-format on -#ifdef _WIN32 -# include <windows.h> -# undef max -#endif +#include "fmt/format.h" +#include "gmock/gmock.h" +#include "util.h" using fmt::detail::bigint; using fmt::detail::fp; @@ -31,13 +23,13 @@ using fmt::detail::max_value; static_assert(!std::is_copy_constructible<bigint>::value, ""); static_assert(!std::is_copy_assignable<bigint>::value, ""); -TEST(BigIntTest, Construct) { +TEST(bigint_test, construct) { EXPECT_EQ("", fmt::format("{}", bigint())); EXPECT_EQ("42", fmt::format("{}", bigint(0x42))); EXPECT_EQ("123456789abcedf0", fmt::format("{}", bigint(0x123456789abcedf0))); } -TEST(BigIntTest, Compare) { +TEST(bigint_test, compare) { bigint n1(42); bigint n2(42); EXPECT_EQ(compare(n1, n2), 0); @@ -51,7 +43,7 @@ TEST(BigIntTest, Compare) { EXPECT_GT(compare(n4, n2), 0); } -TEST(BigIntTest, AddCompare) { +TEST(bigint_test, add_compare) { EXPECT_LT( add_compare(bigint(0xffffffff), bigint(0xffffffff), bigint(1) <<= 64), 0); EXPECT_LT(add_compare(bigint(1) <<= 32, bigint(1), bigint(1) <<= 96), 0); @@ -77,7 +69,7 @@ TEST(BigIntTest, AddCompare) { 0); } -TEST(BigIntTest, ShiftLeft) { +TEST(bigint_test, shift_left) { bigint n(0x42); n <<= 0; EXPECT_EQ("42", fmt::format("{}", n)); @@ -87,7 +79,7 @@ TEST(BigIntTest, ShiftLeft) { EXPECT_EQ("108000000", fmt::format("{}", n)); } -TEST(BigIntTest, Multiply) { +TEST(bigint_test, multiply) { bigint n(0x42); EXPECT_THROW(n *= 0, assertion_failure); n *= 1; @@ -104,7 +96,7 @@ TEST(BigIntTest, Multiply) { EXPECT_EQ("fffffffffffffffe0000000000000001", fmt::format("{}", bigmax)); } -TEST(BigIntTest, Accumulator) { +TEST(bigint_test, accumulator) { fmt::detail::accumulator acc; EXPECT_EQ(acc.lower, 0); EXPECT_EQ(acc.upper, 0); @@ -113,7 +105,7 @@ TEST(BigIntTest, Accumulator) { EXPECT_EQ(static_cast<uint32_t>(acc), 34); acc += 56; EXPECT_EQ(acc.lower, 90); - acc += fmt::detail::max_value<uint64_t>(); + acc += max_value<uint64_t>(); EXPECT_EQ(acc.upper, 13); EXPECT_EQ(acc.lower, 89); acc >>= 32; @@ -121,7 +113,7 @@ TEST(BigIntTest, Accumulator) { EXPECT_EQ(acc.lower, 13 * 0x100000000); } -TEST(BigIntTest, Square) { +TEST(bigint_test, square) { bigint n0(0); n0.square(); EXPECT_EQ("0", fmt::format("{}", n0)); @@ -139,18 +131,18 @@ TEST(BigIntTest, Square) { EXPECT_EQ("2540be400", fmt::format("{}", n4)); } -TEST(BigIntTest, DivModAssignZeroDivisor) { +TEST(bigint_test, divmod_assign_zero_divisor) { bigint zero(0); EXPECT_THROW(bigint(0).divmod_assign(zero), assertion_failure); EXPECT_THROW(bigint(42).divmod_assign(zero), assertion_failure); } -TEST(BigIntTest, DivModAssignSelf) { +TEST(bigint_test, divmod_assign_self) { bigint n(100); EXPECT_THROW(n.divmod_assign(n), assertion_failure); } -TEST(BigIntTest, DivModAssignUnaligned) { +TEST(bigint_test, divmod_assign_unaligned) { // (42 << 340) / pow(10, 100): bigint n1(42); n1 <<= 340; @@ -162,7 +154,7 @@ TEST(BigIntTest, DivModAssignUnaligned) { fmt::format("{}", n1)); } -TEST(BigIntTest, DivModAssign) { +TEST(bigint_test, divmod_assign) { // 100 / 10: bigint n1(100); int result = n1.divmod_assign(bigint(10)); @@ -191,18 +183,18 @@ template <> void run_double_tests<true>() { EXPECT_EQ(fp(1.23), fp(0x13ae147ae147aeu, -52)); } -TEST(FPTest, DoubleTests) { +TEST(fp_test, double_tests) { run_double_tests<std::numeric_limits<double>::is_iec559>(); } -TEST(FPTest, Normalize) { +TEST(fp_test, normalize) { const auto v = fp(0xbeef, 42); auto normalized = normalize(v); EXPECT_EQ(0xbeef000000000000, normalized.f); EXPECT_EQ(-6, normalized.e); } -TEST(FPTest, Multiply) { +TEST(fp_test, multiply) { auto v = fp(123ULL << 32, 4) * fp(56ULL << 32, 7); EXPECT_EQ(v.f, 123u * 56u); EXPECT_EQ(v.e, 4 + 7 + 64); @@ -211,7 +203,7 @@ TEST(FPTest, Multiply) { EXPECT_EQ(v.e, 4 + 8 + 64); } -TEST(FPTest, GetCachedPower) { +TEST(fp_test, get_cached_power) { using limits = std::numeric_limits<double>; for (auto exp = limits::min_exponent; exp <= limits::max_exponent; ++exp) { int dec_exp = 0; @@ -248,7 +240,7 @@ TEST(FPTest, GetCachedPower) { } } -TEST(FPTest, DragonboxMaxK) { +TEST(fp_test, dragonbox_max_k) { using fmt::detail::dragonbox::floor_log10_pow2; using float_info = fmt::detail::dragonbox::float_info<float>; EXPECT_EQ(fmt::detail::const_check(float_info::max_k), @@ -261,7 +253,7 @@ TEST(FPTest, DragonboxMaxK) { double_info::significand_bits)); } -TEST(FPTest, GetRoundDirection) { +TEST(fp_test, get_round_direction) { using fmt::detail::get_round_direction; using fmt::detail::round_direction; EXPECT_EQ(round_direction::down, get_round_direction(100, 50, 0)); @@ -285,108 +277,42 @@ TEST(FPTest, GetRoundDirection) { EXPECT_EQ(round_direction::up, get_round_direction(max, max - 1, 1)); } -TEST(FPTest, FixedHandler) { - struct handler : fmt::detail::fixed_handler { +TEST(fp_test, fixed_handler) { + struct handler : fmt::detail::gen_digits_handler { char buffer[10]; - handler(int prec = 0) : fmt::detail::fixed_handler() { + handler(int prec = 0) : fmt::detail::gen_digits_handler() { buf = buffer; precision = prec; } }; - int exp = 0; - handler().on_digit('0', 100, 99, 0, exp, false); - EXPECT_THROW(handler().on_digit('0', 100, 100, 0, exp, false), - assertion_failure); + handler().on_digit('0', 100, 99, 0, false); + EXPECT_THROW(handler().on_digit('0', 100, 100, 0, false), assertion_failure); namespace digits = fmt::detail::digits; - EXPECT_EQ(handler(1).on_digit('0', 100, 10, 10, exp, false), digits::error); + EXPECT_EQ(handler(1).on_digit('0', 100, 10, 10, false), digits::error); // Check that divisor - error doesn't overflow. - EXPECT_EQ(handler(1).on_digit('0', 100, 10, 101, exp, false), digits::error); + EXPECT_EQ(handler(1).on_digit('0', 100, 10, 101, false), digits::error); // Check that 2 * error doesn't overflow. uint64_t max = max_value<uint64_t>(); - EXPECT_EQ(handler(1).on_digit('0', max, 10, max - 1, exp, false), - digits::error); + EXPECT_EQ(handler(1).on_digit('0', max, 10, max - 1, false), digits::error); } -TEST(FPTest, GrisuFormatCompilesWithNonIEEEDouble) { +TEST(fp_test, grisu_format_compiles_with_on_ieee_double) { fmt::memory_buffer buf; format_float(0.42, -1, fmt::detail::float_specs(), buf); } -template <typename T> struct value_extractor { - T operator()(T value) { return value; } - - template <typename U> FMT_NORETURN T operator()(U) { - throw std::runtime_error(fmt::format("invalid type {}", typeid(U).name())); - } - -#if FMT_USE_INT128 - // Apple Clang does not define typeid for __int128_t and __uint128_t. - FMT_NORETURN T operator()(fmt::detail::int128_t) { - throw std::runtime_error("invalid type __int128_t"); - } - - FMT_NORETURN T operator()(fmt::detail::uint128_t) { - throw std::runtime_error("invalid type __uint128_t"); - } -#endif -}; - -TEST(FormatTest, ArgConverter) { - long long value = max_value<long long>(); - auto arg = fmt::detail::make_arg<fmt::format_context>(value); - fmt::visit_format_arg( - fmt::detail::arg_converter<long long, fmt::format_context>(arg, 'd'), - arg); - EXPECT_EQ(value, fmt::visit_format_arg(value_extractor<long long>(), arg)); -} - -TEST(FormatTest, StrError) { - char* message = nullptr; - char buffer[BUFFER_SIZE]; - EXPECT_ASSERT(fmt::detail::safe_strerror(EDOM, message = nullptr, 0), - "invalid buffer"); - EXPECT_ASSERT(fmt::detail::safe_strerror(EDOM, message = buffer, 0), - "invalid buffer"); - buffer[0] = 'x'; -#if defined(_GNU_SOURCE) && !defined(__COVERITY__) - // Use invalid error code to make sure that safe_strerror returns an error - // message in the buffer rather than a pointer to a static string. - int error_code = -1; -#else - int error_code = EDOM; -#endif - - int result = - fmt::detail::safe_strerror(error_code, message = buffer, BUFFER_SIZE); - EXPECT_EQ(result, 0); - size_t message_size = std::strlen(message); - EXPECT_GE(BUFFER_SIZE - 1u, message_size); - EXPECT_EQ(get_system_error(error_code), message); - - // safe_strerror never uses buffer on MinGW. -#if !defined(__MINGW32__) && !defined(__sun) - result = - fmt::detail::safe_strerror(error_code, message = buffer, message_size); - EXPECT_EQ(ERANGE, result); - result = fmt::detail::safe_strerror(error_code, message = buffer, 1); - EXPECT_EQ(buffer, message); // Message should point to buffer. - EXPECT_EQ(ERANGE, result); - EXPECT_STREQ("", message); -#endif -} - -TEST(FormatTest, FormatErrorCode) { +TEST(format_impl_test, format_error_code) { std::string msg = "error 42", sep = ": "; { fmt::memory_buffer buffer; - format_to(buffer, "garbage"); + format_to(fmt::appender(buffer), "garbage"); fmt::detail::format_error_code(buffer, 42, "test"); EXPECT_EQ("test: " + msg, to_string(buffer)); } { fmt::memory_buffer buffer; - std::string prefix(fmt::inline_buffer_size - msg.size() - sep.size() + 1, - 'x'); + auto prefix = + std::string(fmt::inline_buffer_size - msg.size() - sep.size() + 1, 'x'); fmt::detail::format_error_code(buffer, 42, prefix); EXPECT_EQ(msg, to_string(buffer)); } @@ -395,7 +321,8 @@ TEST(FormatTest, FormatErrorCode) { // Test maximum buffer size. msg = fmt::format("error {}", codes[i]); fmt::memory_buffer buffer; - std::string prefix(fmt::inline_buffer_size - msg.size() - sep.size(), 'x'); + auto prefix = + std::string(fmt::inline_buffer_size - msg.size() - sep.size(), 'x'); fmt::detail::format_error_code(buffer, codes[i], prefix); EXPECT_EQ(prefix + sep + msg, to_string(buffer)); size_t size = fmt::inline_buffer_size; @@ -408,9 +335,9 @@ TEST(FormatTest, FormatErrorCode) { } } -TEST(FormatTest, CountCodePoints) { +TEST(format_impl_test, compute_width) { EXPECT_EQ(4, - fmt::detail::count_code_points( + fmt::detail::compute_width( fmt::basic_string_view<fmt::detail::char8_type>( reinterpret_cast<const fmt::detail::char8_type*>("ёжик")))); } @@ -425,12 +352,12 @@ template <typename Int> void test_count_digits() { } } -TEST(UtilTest, CountDigits) { +TEST(format_impl_test, count_digits) { test_count_digits<uint32_t>(); test_count_digits<uint64_t>(); } -TEST(UtilTest, WriteFallbackUIntPtr) { +TEST(format_impl_test, write_fallback_uintptr) { std::string s; fmt::detail::write_ptr<char>( std::back_inserter(s), @@ -439,7 +366,11 @@ TEST(UtilTest, WriteFallbackUIntPtr) { } #ifdef _WIN32 -TEST(UtilTest, WriteConsoleSignature) { +# include <windows.h> +#endif + +#ifdef _WIN32 +TEST(format_impl_test, write_console_signature) { decltype(WriteConsoleW)* p = fmt::detail::WriteConsoleW; (void)p; } diff --git a/contrib/libs/fmt/test/format-test.cc b/contrib/libs/fmt/test/format-test.cc index 6164ad60d6..a8592ef07e 100644 --- a/contrib/libs/fmt/test/format-test.cc +++ b/contrib/libs/fmt/test/format-test.cc @@ -5,111 +5,63 @@ // // For the license information refer to format.h. -#include <stdint.h> - -#include <cctype> -#include <cfloat> -#include <climits> -#include <cmath> -#include <cstring> -#include <list> -#include <memory> -#include <string> - // Check if fmt/format.h compiles with windows.h included before it. #ifdef _WIN32 # include <windows.h> #endif - -// Check if fmt/format.h compiles with the X11 index macro defined. -#define index(x, y) no nice things - +// clang-format off #include "fmt/format.h" +// clang-format on -#undef index +#include <stdint.h> // uint32_t + +#include <climits> // INT_MAX +#include <cmath> // std::signbit +#include <cstring> // std::strlen +#include <iterator> // std::back_inserter +#include <list> // std::list +#include <memory> // std::unique_ptr +#include <type_traits> // std::is_default_constructible -#include <gmock/gmock.h> #include "gtest-extra.h" #include "mock-allocator.h" #include "util.h" -#undef ERROR - using fmt::basic_memory_buffer; -using fmt::format; using fmt::format_error; using fmt::memory_buffer; +using fmt::runtime; using fmt::string_view; -using fmt::wmemory_buffer; -using fmt::wstring_view; using fmt::detail::max_value; using testing::Return; using testing::StrictMock; -namespace { - -#if !FMT_GCC_VERSION || FMT_GCC_VERSION >= 408 -template <typename Char, typename T> bool check_enabled_formatter() { - static_assert(std::is_default_constructible<fmt::formatter<T, Char>>::value, - ""); - return true; -} - -template <typename Char, typename... T> void check_enabled_formatters() { - auto dummy = {check_enabled_formatter<Char, T>()...}; - (void)dummy; -} - -TEST(FormatterTest, TestFormattersEnabled) { - check_enabled_formatters<char, bool, char, signed char, unsigned char, short, - unsigned short, int, unsigned, long, unsigned long, - long long, unsigned long long, float, double, - long double, void*, const void*, char*, const char*, - std::string, std::nullptr_t>(); - check_enabled_formatters<wchar_t, bool, wchar_t, signed char, unsigned char, - short, unsigned short, int, unsigned, long, - unsigned long, long long, unsigned long long, float, - double, long double, void*, const void*, wchar_t*, - const wchar_t*, std::wstring, std::nullptr_t>(); -} -#endif - -// Format value using the standard library. -template <typename Char, typename T> -void std_format(const T& value, std::basic_string<Char>& result) { - std::basic_ostringstream<Char> os; - os << value; - result = os.str(); -} - -#ifdef __MINGW32__ -// Workaround a bug in formatting long double in MinGW. -void std_format(long double value, std::string& result) { - char buffer[100]; - safe_sprintf(buffer, "%Lg", value); - result = buffer; -} -void std_format(long double value, std::wstring& result) { - wchar_t buffer[100]; - swprintf(buffer, L"%Lg", value); - result = buffer; -} -#endif -} // namespace +enum { buffer_size = 256 }; struct uint32_pair { uint32_t u[2]; }; -TEST(UtilTest, BitCast) { +TEST(util_test, bit_cast) { auto s = fmt::detail::bit_cast<uint32_pair>(uint64_t{42}); EXPECT_EQ(fmt::detail::bit_cast<uint64_t>(s), 42ull); - s = fmt::detail::bit_cast<uint32_pair>(uint64_t(~0ull)); + s = fmt::detail::bit_cast<uint32_pair>(~uint64_t{0}); EXPECT_EQ(fmt::detail::bit_cast<uint64_t>(s), ~0ull); } -TEST(UtilTest, Increment) { +// Increment a number in a string. +void increment(char* s) { + for (int i = static_cast<int>(std::strlen(s)) - 1; i >= 0; --i) { + if (s[i] != '9') { + ++s[i]; + break; + } + s[i] = '0'; + } +} + +TEST(util_test, increment) { char s[10] = "123"; increment(s); EXPECT_STREQ("124", s); @@ -123,92 +75,52 @@ TEST(UtilTest, Increment) { EXPECT_STREQ("200", s); } -TEST(UtilTest, ParseNonnegativeInt) { - if (max_value<int>() != static_cast<int>(static_cast<unsigned>(1) << 31)) { - fmt::print("Skipping parse_nonnegative_int test\n"); - return; - } - fmt::string_view s = "10000000000"; +TEST(util_test, parse_nonnegative_int) { + auto s = fmt::string_view("10000000000"); auto begin = s.begin(), end = s.end(); - EXPECT_THROW_MSG( - parse_nonnegative_int(begin, end, fmt::detail::error_handler()), - fmt::format_error, "number is too big"); + EXPECT_EQ(fmt::detail::parse_nonnegative_int(begin, end, -1), -1); s = "2147483649"; begin = s.begin(); end = s.end(); - EXPECT_THROW_MSG( - parse_nonnegative_int(begin, end, fmt::detail::error_handler()), - fmt::format_error, "number is too big"); -} - -TEST(IteratorTest, CountingIterator) { - fmt::detail::counting_iterator it; - auto prev = it++; - EXPECT_EQ(prev.count(), 0); - EXPECT_EQ(it.count(), 1); - EXPECT_EQ((it + 41).count(), 42); -} - -TEST(IteratorTest, TruncatingIterator) { - char* p = nullptr; - fmt::detail::truncating_iterator<char*> it(p, 3); - auto prev = it++; - EXPECT_EQ(prev.base(), p); - EXPECT_EQ(it.base(), p + 1); -} - -TEST(IteratorTest, TruncatingBackInserter) { - std::string buffer; - auto bi = std::back_inserter(buffer); - fmt::detail::truncating_iterator<decltype(bi)> it(bi, 2); - *it++ = '4'; - *it++ = '2'; - *it++ = '1'; - EXPECT_EQ(buffer.size(), 2); - EXPECT_EQ(buffer, "42"); -} - -TEST(IteratorTest, IsOutputIterator) { - EXPECT_TRUE((fmt::detail::is_output_iterator<char*, char>::value)); - EXPECT_FALSE((fmt::detail::is_output_iterator<const char*, char>::value)); - EXPECT_FALSE((fmt::detail::is_output_iterator<std::string, char>::value)); - EXPECT_TRUE( - (fmt::detail::is_output_iterator<std::back_insert_iterator<std::string>, - char>::value)); - EXPECT_TRUE( - (fmt::detail::is_output_iterator<std::string::iterator, char>::value)); - EXPECT_FALSE((fmt::detail::is_output_iterator<std::string::const_iterator, - char>::value)); - EXPECT_FALSE((fmt::detail::is_output_iterator<std::list<char>, char>::value)); - EXPECT_TRUE(( - fmt::detail::is_output_iterator<std::list<char>::iterator, char>::value)); - EXPECT_FALSE((fmt::detail::is_output_iterator<std::list<char>::const_iterator, - char>::value)); - EXPECT_FALSE((fmt::detail::is_output_iterator<uint32_pair, char>::value)); -} - -TEST(MemoryBufferTest, Ctor) { - basic_memory_buffer<char, 123> buffer; - EXPECT_EQ(static_cast<size_t>(0), buffer.size()); - EXPECT_EQ(123u, buffer.capacity()); + EXPECT_EQ(fmt::detail::parse_nonnegative_int(begin, end, -1), -1); } -static void check_forwarding(mock_allocator<int>& alloc, - allocator_ref<mock_allocator<int>>& ref) { - int mem; - // Check if value_type is properly defined. - allocator_ref<mock_allocator<int>>::value_type* ptr = &mem; - // Check forwarding. - EXPECT_CALL(alloc, allocate(42)).WillOnce(testing::Return(ptr)); - ref.allocate(42); - EXPECT_CALL(alloc, deallocate(ptr, 42)); - ref.deallocate(ptr, 42); +TEST(util_test, utf8_to_utf16) { + auto u = fmt::detail::utf8_to_utf16("лошадка"); + EXPECT_EQ(L"\x043B\x043E\x0448\x0430\x0434\x043A\x0430", u.str()); + EXPECT_EQ(7, u.size()); + // U+10437 { DESERET SMALL LETTER YEE } + EXPECT_EQ(L"\xD801\xDC37", fmt::detail::utf8_to_utf16("𐐷").str()); + EXPECT_THROW_MSG(fmt::detail::utf8_to_utf16("\xc3\x28"), std::runtime_error, + "invalid utf8"); + EXPECT_THROW_MSG(fmt::detail::utf8_to_utf16(fmt::string_view("л", 1)), + std::runtime_error, "invalid utf8"); + EXPECT_EQ(L"123456", fmt::detail::utf8_to_utf16("123456").str()); } -TEST(AllocatorTest, allocator_ref) { +TEST(util_test, utf8_to_utf16_empty_string) { + auto s = std::string(); + auto u = fmt::detail::utf8_to_utf16(s.c_str()); + EXPECT_EQ(L"", u.str()); + EXPECT_EQ(s.size(), u.size()); +} + +TEST(util_test, allocator_ref) { + using test_allocator_ref = allocator_ref<mock_allocator<int>>; + auto check_forwarding = [](mock_allocator<int>& alloc, + test_allocator_ref& ref) { + int mem; + // Check if value_type is properly defined. + allocator_ref<mock_allocator<int>>::value_type* ptr = &mem; + // Check forwarding. + EXPECT_CALL(alloc, allocate(42)).WillOnce(Return(ptr)); + ref.allocate(42); + EXPECT_CALL(alloc, deallocate(ptr, 42)); + ref.deallocate(ptr, 42); + }; + StrictMock<mock_allocator<int>> alloc; - typedef allocator_ref<mock_allocator<int>> test_allocator_ref; - test_allocator_ref ref(&alloc); + auto ref = test_allocator_ref(&alloc); // Check if allocator_ref forwards to the underlying allocator. check_forwarding(alloc, ref); test_allocator_ref ref2(ref); @@ -219,24 +131,78 @@ TEST(AllocatorTest, allocator_ref) { check_forwarding(alloc, ref3); } -typedef allocator_ref<std::allocator<char>> TestAllocator; +TEST(util_test, format_system_error) { + fmt::memory_buffer message; + fmt::format_system_error(message, EDOM, "test"); + auto ec = std::error_code(EDOM, std::generic_category()); + EXPECT_EQ(to_string(message), std::system_error(ec, "test").what()); + message = fmt::memory_buffer(); -static void check_move_buffer( - const char* str, basic_memory_buffer<char, 5, TestAllocator>& buffer) { - std::allocator<char>* alloc = buffer.get_allocator().get(); - basic_memory_buffer<char, 5, TestAllocator> buffer2(std::move(buffer)); - // Move shouldn't destroy the inline content of the first buffer. - EXPECT_EQ(str, std::string(&buffer[0], buffer.size())); - EXPECT_EQ(str, std::string(&buffer2[0], buffer2.size())); - EXPECT_EQ(5u, buffer2.capacity()); - // Move should transfer allocator. - EXPECT_EQ(nullptr, buffer.get_allocator().get()); - EXPECT_EQ(alloc, buffer2.get_allocator().get()); + // Check if std::allocator throws on allocating max size_t / 2 chars. + size_t max_size = max_value<size_t>() / 2; + bool throws_on_alloc = false; + try { + auto alloc = std::allocator<char>(); + alloc.deallocate(alloc.allocate(max_size), max_size); + } catch (const std::bad_alloc&) { + throws_on_alloc = true; + } + if (!throws_on_alloc) { + fmt::print("warning: std::allocator allocates {} chars", max_size); + return; + } } -TEST(MemoryBufferTest, MoveCtorInlineBuffer) { - std::allocator<char> alloc; - basic_memory_buffer<char, 5, TestAllocator> buffer((TestAllocator(&alloc))); +TEST(util_test, system_error) { + auto test_error = fmt::system_error(EDOM, "test"); + auto ec = std::error_code(EDOM, std::generic_category()); + EXPECT_STREQ(test_error.what(), std::system_error(ec, "test").what()); + EXPECT_EQ(test_error.code(), ec); + + auto error = std::system_error(std::error_code()); + try { + throw fmt::system_error(EDOM, "test {}", "error"); + } catch (const std::system_error& e) { + error = e; + } + fmt::memory_buffer message; + fmt::format_system_error(message, EDOM, "test error"); + EXPECT_EQ(error.what(), to_string(message)); + EXPECT_EQ(error.code(), std::error_code(EDOM, std::generic_category())); +} + +TEST(util_test, report_system_error) { + fmt::memory_buffer out; + fmt::format_system_error(out, EDOM, "test error"); + out.push_back('\n'); + EXPECT_WRITE(stderr, fmt::report_system_error(EDOM, "test error"), + to_string(out)); +} + +TEST(memory_buffer_test, ctor) { + basic_memory_buffer<char, 123> buffer; + EXPECT_EQ(static_cast<size_t>(0), buffer.size()); + EXPECT_EQ(123u, buffer.capacity()); +} + +using std_allocator = allocator_ref<std::allocator<char>>; + +TEST(memory_buffer_test, move_ctor_inline_buffer) { + auto check_move_buffer = + [](const char* str, basic_memory_buffer<char, 5, std_allocator>& buffer) { + std::allocator<char>* alloc = buffer.get_allocator().get(); + basic_memory_buffer<char, 5, std_allocator> buffer2(std::move(buffer)); + // Move shouldn't destroy the inline content of the first buffer. + EXPECT_EQ(str, std::string(&buffer[0], buffer.size())); + EXPECT_EQ(str, std::string(&buffer2[0], buffer2.size())); + EXPECT_EQ(5u, buffer2.capacity()); + // Move should transfer allocator. + EXPECT_EQ(nullptr, buffer.get_allocator().get()); + EXPECT_EQ(alloc, buffer2.get_allocator().get()); + }; + + auto alloc = std::allocator<char>(); + basic_memory_buffer<char, 5, std_allocator> buffer((std_allocator(&alloc))); const char test[] = "test"; buffer.append(string_view(test, 4)); check_move_buffer("test", buffer); @@ -246,24 +212,24 @@ TEST(MemoryBufferTest, MoveCtorInlineBuffer) { check_move_buffer("testa", buffer); } -TEST(MemoryBufferTest, MoveCtorDynamicBuffer) { - std::allocator<char> alloc; - basic_memory_buffer<char, 4, TestAllocator> buffer((TestAllocator(&alloc))); +TEST(memory_buffer_test, move_ctor_dynamic_buffer) { + auto alloc = std::allocator<char>(); + basic_memory_buffer<char, 4, std_allocator> buffer((std_allocator(&alloc))); const char test[] = "test"; buffer.append(test, test + 4); const char* inline_buffer_ptr = &buffer[0]; // Adding one more character causes the content to move from the inline to // a dynamically allocated buffer. buffer.push_back('a'); - basic_memory_buffer<char, 4, TestAllocator> buffer2(std::move(buffer)); + basic_memory_buffer<char, 4, std_allocator> buffer2(std::move(buffer)); // Move should rip the guts of the first buffer. EXPECT_EQ(inline_buffer_ptr, &buffer[0]); EXPECT_EQ("testa", std::string(&buffer2[0], buffer2.size())); EXPECT_GT(buffer2.capacity(), 4u); } -static void check_move_assign_buffer(const char* str, - basic_memory_buffer<char, 5>& buffer) { +void check_move_assign_buffer(const char* str, + basic_memory_buffer<char, 5>& buffer) { basic_memory_buffer<char, 5> buffer2; buffer2 = std::move(buffer); // Move shouldn't destroy the inline content of the first buffer. @@ -272,7 +238,7 @@ static void check_move_assign_buffer(const char* str, EXPECT_EQ(5u, buffer2.capacity()); } -TEST(MemoryBufferTest, MoveAssignment) { +TEST(memory_buffer_test, move_assignment) { basic_memory_buffer<char, 5> buffer; const char test[] = "test"; buffer.append(test, test + 4); @@ -293,7 +259,7 @@ TEST(MemoryBufferTest, MoveAssignment) { EXPECT_GT(buffer2.capacity(), 5u); } -TEST(MemoryBufferTest, Grow) { +TEST(memory_buffer_test, grow) { typedef allocator_ref<mock_allocator<int>> Allocator; mock_allocator<int> alloc; basic_memory_buffer<int, 10, Allocator> buffer((Allocator(&alloc))); @@ -313,15 +279,15 @@ TEST(MemoryBufferTest, Grow) { EXPECT_CALL(alloc, deallocate(mem, 20)); } -TEST(MemoryBufferTest, Allocator) { - typedef allocator_ref<mock_allocator<char>> TestAllocator; - basic_memory_buffer<char, 10, TestAllocator> buffer; +TEST(memory_buffer_test, allocator) { + using test_allocator = allocator_ref<mock_allocator<char>>; + basic_memory_buffer<char, 10, test_allocator> buffer; EXPECT_EQ(nullptr, buffer.get_allocator().get()); StrictMock<mock_allocator<char>> alloc; char mem; { - basic_memory_buffer<char, 10, TestAllocator> buffer2( - (TestAllocator(&alloc))); + basic_memory_buffer<char, 10, test_allocator> buffer2( + (test_allocator(&alloc))); EXPECT_EQ(&alloc, buffer2.get_allocator().get()); size_t size = 2 * fmt::inline_buffer_size; EXPECT_CALL(alloc, allocate(size)).WillOnce(Return(&mem)); @@ -330,21 +296,22 @@ TEST(MemoryBufferTest, Allocator) { } } -TEST(MemoryBufferTest, ExceptionInDeallocate) { - typedef allocator_ref<mock_allocator<char>> TestAllocator; +TEST(memory_buffer_test, exception_in_deallocate) { + using test_allocator = allocator_ref<mock_allocator<char>>; StrictMock<mock_allocator<char>> alloc; - basic_memory_buffer<char, 10, TestAllocator> buffer((TestAllocator(&alloc))); + basic_memory_buffer<char, 10, test_allocator> buffer( + (test_allocator(&alloc))); size_t size = 2 * fmt::inline_buffer_size; - std::vector<char> mem(size); + auto mem = std::vector<char>(size); { EXPECT_CALL(alloc, allocate(size)).WillOnce(Return(&mem[0])); buffer.resize(size); std::fill(&buffer[0], &buffer[0] + size, 'x'); } - std::vector<char> mem2(2 * size); + auto mem2 = std::vector<char>(2 * size); { EXPECT_CALL(alloc, allocate(2 * size)).WillOnce(Return(&mem2[0])); - std::exception e; + auto e = std::exception(); EXPECT_CALL(alloc, deallocate(&mem[0], size)).WillOnce(testing::Throw(e)); EXPECT_THROW(buffer.reserve(2 * size), std::exception); EXPECT_EQ(&mem2[0], &buffer[0]); @@ -354,595 +321,576 @@ TEST(MemoryBufferTest, ExceptionInDeallocate) { EXPECT_CALL(alloc, deallocate(&mem2[0], 2 * size)); } -TEST(UtilTest, UTF8ToUTF16) { - fmt::detail::utf8_to_utf16 u("лошадка"); - EXPECT_EQ(L"\x043B\x043E\x0448\x0430\x0434\x043A\x0430", u.str()); - EXPECT_EQ(7, u.size()); - // U+10437 { DESERET SMALL LETTER YEE } - EXPECT_EQ(L"\xD801\xDC37", fmt::detail::utf8_to_utf16("𐐷").str()); - EXPECT_THROW_MSG(fmt::detail::utf8_to_utf16("\xc3\x28"), std::runtime_error, - "invalid utf8"); - EXPECT_THROW_MSG(fmt::detail::utf8_to_utf16(fmt::string_view("л", 1)), - std::runtime_error, "invalid utf8"); - EXPECT_EQ(L"123456", fmt::detail::utf8_to_utf16("123456").str()); -} - -TEST(UtilTest, UTF8ToUTF16EmptyString) { - std::string s = ""; - fmt::detail::utf8_to_utf16 u(s.c_str()); - EXPECT_EQ(L"", u.str()); - EXPECT_EQ(s.size(), u.size()); -} - -TEST(UtilTest, FormatSystemError) { - fmt::memory_buffer message; - fmt::format_system_error(message, EDOM, "test"); - EXPECT_EQ(fmt::format("test: {}", get_system_error(EDOM)), - to_string(message)); - message = fmt::memory_buffer(); - - // Check if std::allocator throws on allocating max size_t / 2 chars. - size_t max_size = max_value<size_t>() / 2; - bool throws_on_alloc = false; - try { - std::allocator<char> alloc; - alloc.deallocate(alloc.allocate(max_size), max_size); - } catch (const std::bad_alloc&) { - throws_on_alloc = true; - } - if (!throws_on_alloc) { - fmt::print("warning: std::allocator allocates {} chars", max_size); - return; +template <typename Allocator, size_t MaxSize> +class max_size_allocator : public Allocator { + public: + using typename Allocator::value_type; + size_t max_size() const FMT_NOEXCEPT { return MaxSize; } + value_type* allocate(size_t n) { + if (n > max_size()) { + throw std::length_error("size > max_size"); + } + return std::allocator_traits<Allocator>::allocate( + *static_cast<Allocator*>(this), n); } - fmt::format_system_error(message, EDOM, fmt::string_view(nullptr, max_size)); - EXPECT_EQ(fmt::format("error {}", EDOM), to_string(message)); -} - -TEST(UtilTest, SystemError) { - fmt::system_error e(EDOM, "test"); - EXPECT_EQ(fmt::format("test: {}", get_system_error(EDOM)), e.what()); - EXPECT_EQ(EDOM, e.error_code()); - - fmt::system_error error(0, ""); - try { - throw fmt::system_error(EDOM, "test {}", "error"); - } catch (const fmt::system_error& e) { - error = e; + void deallocate(value_type* p, size_t n) { + std::allocator_traits<Allocator>::deallocate(*static_cast<Allocator*>(this), + p, n); } - fmt::memory_buffer message; - fmt::format_system_error(message, EDOM, "test error"); - EXPECT_EQ(to_string(message), error.what()); - EXPECT_EQ(EDOM, error.error_code()); -} - -TEST(UtilTest, ReportSystemError) { - fmt::memory_buffer out; - fmt::format_system_error(out, EDOM, "test error"); - out.push_back('\n'); - EXPECT_WRITE(stderr, fmt::report_system_error(EDOM, "test error"), - to_string(out)); -} - -TEST(StringViewTest, Ctor) { - EXPECT_STREQ("abc", string_view("abc").data()); - EXPECT_EQ(3u, string_view("abc").size()); - - EXPECT_STREQ("defg", string_view(std::string("defg")).data()); - EXPECT_EQ(4u, string_view(std::string("defg")).size()); -} - -TEST(FormatToTest, FormatWithoutArgs) { - std::string s; - fmt::format_to(std::back_inserter(s), "test"); - EXPECT_EQ("test", s); -} - -TEST(FormatToTest, Format) { - std::string s; - fmt::format_to(std::back_inserter(s), "part{0}", 1); - EXPECT_EQ("part1", s); - fmt::format_to(std::back_inserter(s), "part{0}", 2); - EXPECT_EQ("part1part2", s); -} +}; -TEST(FormatToTest, WideString) { - std::vector<wchar_t> buf; - fmt::format_to(std::back_inserter(buf), L"{}{}", 42, L'\0'); - EXPECT_STREQ(buf.data(), L"42"); +TEST(memory_buffer_test, max_size_allocator) { + // 160 = 128 + 32 + using test_allocator = max_size_allocator<std::allocator<char>, 160>; + basic_memory_buffer<char, 10, test_allocator> buffer; + buffer.resize(128); + // new_capacity = 128 + 128/2 = 192 > 160 + buffer.resize(160); // Shouldn't throw. } -TEST(FormatToTest, FormatToMemoryBuffer) { - fmt::basic_memory_buffer<char, 100> buffer; - fmt::format_to(buffer, "{}", "foo"); - EXPECT_EQ("foo", to_string(buffer)); - fmt::wmemory_buffer wbuffer; - fmt::format_to(wbuffer, L"{}", L"foo"); - EXPECT_EQ(L"foo", to_string(wbuffer)); +TEST(memory_buffer_test, max_size_allocator_overflow) { + using test_allocator = max_size_allocator<std::allocator<char>, 160>; + basic_memory_buffer<char, 10, test_allocator> buffer; + EXPECT_THROW(buffer.resize(161), std::exception); } -TEST(FormatterTest, Escape) { - EXPECT_EQ("{", format("{{")); - EXPECT_EQ("before {", format("before {{")); - EXPECT_EQ("{ after", format("{{ after")); - EXPECT_EQ("before { after", format("before {{ after")); +TEST(format_test, escape) { + EXPECT_EQ("{", fmt::format("{{")); + EXPECT_EQ("before {", fmt::format("before {{")); + EXPECT_EQ("{ after", fmt::format("{{ after")); + EXPECT_EQ("before { after", fmt::format("before {{ after")); - EXPECT_EQ("}", format("}}")); - EXPECT_EQ("before }", format("before }}")); - EXPECT_EQ("} after", format("}} after")); - EXPECT_EQ("before } after", format("before }} after")); + EXPECT_EQ("}", fmt::format("}}")); + EXPECT_EQ("before }", fmt::format("before }}")); + EXPECT_EQ("} after", fmt::format("}} after")); + EXPECT_EQ("before } after", fmt::format("before }} after")); - EXPECT_EQ("{}", format("{{}}")); - EXPECT_EQ("{42}", format("{{{0}}}", 42)); + EXPECT_EQ("{}", fmt::format("{{}}")); + EXPECT_EQ("{42}", fmt::format("{{{0}}}", 42)); } -TEST(FormatterTest, UnmatchedBraces) { - EXPECT_THROW_MSG(format("{"), format_error, "invalid format string"); - EXPECT_THROW_MSG(format("}"), format_error, "unmatched '}' in format string"); - EXPECT_THROW_MSG(format("{0{}"), format_error, "invalid format string"); +TEST(format_test, unmatched_braces) { + EXPECT_THROW_MSG((void)fmt::format(runtime("{")), format_error, + "invalid format string"); + EXPECT_THROW_MSG((void)fmt::format(runtime("}")), format_error, + "unmatched '}' in format string"); + EXPECT_THROW_MSG((void)fmt::format(runtime("{0{}")), format_error, + "invalid format string"); } -TEST(FormatterTest, NoArgs) { EXPECT_EQ("test", format("test")); } +TEST(format_test, no_args) { EXPECT_EQ("test", fmt::format("test")); } -TEST(FormatterTest, ArgsInDifferentPositions) { - EXPECT_EQ("42", format("{0}", 42)); - EXPECT_EQ("before 42", format("before {0}", 42)); - EXPECT_EQ("42 after", format("{0} after", 42)); - EXPECT_EQ("before 42 after", format("before {0} after", 42)); - EXPECT_EQ("answer = 42", format("{0} = {1}", "answer", 42)); - EXPECT_EQ("42 is the answer", format("{1} is the {0}", "answer", 42)); - EXPECT_EQ("abracadabra", format("{0}{1}{0}", "abra", "cad")); +TEST(format_test, args_in_different_positions) { + EXPECT_EQ("42", fmt::format("{0}", 42)); + EXPECT_EQ("before 42", fmt::format("before {0}", 42)); + EXPECT_EQ("42 after", fmt::format("{0} after", 42)); + EXPECT_EQ("before 42 after", fmt::format("before {0} after", 42)); + EXPECT_EQ("answer = 42", fmt::format("{0} = {1}", "answer", 42)); + EXPECT_EQ("42 is the answer", fmt::format("{1} is the {0}", "answer", 42)); + EXPECT_EQ("abracadabra", fmt::format("{0}{1}{0}", "abra", "cad")); } -TEST(FormatterTest, ArgErrors) { - EXPECT_THROW_MSG(format("{"), format_error, "invalid format string"); - EXPECT_THROW_MSG(format("{?}"), format_error, "invalid format string"); - EXPECT_THROW_MSG(format("{0"), format_error, "invalid format string"); - EXPECT_THROW_MSG(format("{0}"), format_error, "argument not found"); - EXPECT_THROW_MSG(format("{00}", 42), format_error, "invalid format string"); +TEST(format_test, arg_errors) { + EXPECT_THROW_MSG((void)fmt::format(runtime("{")), format_error, + "invalid format string"); + EXPECT_THROW_MSG((void)fmt::format(runtime("{?}")), format_error, + "invalid format string"); + EXPECT_THROW_MSG((void)fmt::format(runtime("{0")), format_error, + "invalid format string"); + EXPECT_THROW_MSG((void)fmt::format(runtime("{0}")), format_error, + "argument not found"); + EXPECT_THROW_MSG((void)fmt::format(runtime("{00}"), 42), format_error, + "invalid format string"); - char format_str[BUFFER_SIZE]; + char format_str[buffer_size]; safe_sprintf(format_str, "{%u", INT_MAX); - EXPECT_THROW_MSG(format(format_str), format_error, "invalid format string"); + EXPECT_THROW_MSG((void)fmt::format(runtime(format_str)), format_error, + "invalid format string"); safe_sprintf(format_str, "{%u}", INT_MAX); - EXPECT_THROW_MSG(format(format_str), format_error, "argument not found"); + EXPECT_THROW_MSG((void)fmt::format(runtime(format_str)), format_error, + "argument not found"); safe_sprintf(format_str, "{%u", INT_MAX + 1u); - EXPECT_THROW_MSG(format(format_str), format_error, "number is too big"); + EXPECT_THROW_MSG((void)fmt::format(runtime(format_str)), format_error, + "invalid format string"); safe_sprintf(format_str, "{%u}", INT_MAX + 1u); - EXPECT_THROW_MSG(format(format_str), format_error, "number is too big"); + EXPECT_THROW_MSG((void)fmt::format(runtime(format_str)), format_error, + "argument not found"); } -template <int N> struct TestFormat { - template <typename... Args> - static std::string format(fmt::string_view format_str, const Args&... args) { - return TestFormat<N - 1>::format(format_str, N - 1, args...); +template <int N> struct test_format { + template <typename... T> + static std::string format(fmt::string_view fmt, const T&... args) { + return test_format<N - 1>::format(fmt, N - 1, args...); } }; -template <> struct TestFormat<0> { - template <typename... Args> - static std::string format(fmt::string_view format_str, const Args&... args) { - return fmt::format(format_str, args...); +template <> struct test_format<0> { + template <typename... T> + static std::string format(fmt::string_view fmt, const T&... args) { + return fmt::format(runtime(fmt), args...); } }; -TEST(FormatterTest, ManyArgs) { - EXPECT_EQ("19", TestFormat<20>::format("{19}")); - EXPECT_THROW_MSG(TestFormat<20>::format("{20}"), format_error, +TEST(format_test, many_args) { + EXPECT_EQ("19", test_format<20>::format("{19}")); + EXPECT_THROW_MSG(test_format<20>::format("{20}"), format_error, "argument not found"); - EXPECT_THROW_MSG(TestFormat<21>::format("{21}"), format_error, + EXPECT_THROW_MSG(test_format<21>::format("{21}"), format_error, "argument not found"); - enum { max_packed_args = fmt::detail::max_packed_args }; + using fmt::detail::max_packed_args; std::string format_str = fmt::format("{{{}}}", max_packed_args + 1); - EXPECT_THROW_MSG(TestFormat<max_packed_args>::format(format_str), + EXPECT_THROW_MSG(test_format<max_packed_args>::format(format_str), format_error, "argument not found"); } -TEST(FormatterTest, NamedArg) { - EXPECT_EQ("1/a/A", format("{_1}/{a_}/{A_}", fmt::arg("a_", 'a'), - fmt::arg("A_", "A"), fmt::arg("_1", 1))); - EXPECT_EQ(" -42", format("{0:{width}}", -42, fmt::arg("width", 4))); - EXPECT_EQ("st", format("{0:.{precision}}", "str", fmt::arg("precision", 2))); - EXPECT_EQ("1 2", format("{} {two}", 1, fmt::arg("two", 2))); - EXPECT_EQ("42", format("{c}", fmt::arg("a", 0), fmt::arg("b", 0), - fmt::arg("c", 42), fmt::arg("d", 0), fmt::arg("e", 0), - fmt::arg("f", 0), fmt::arg("g", 0), fmt::arg("h", 0), - fmt::arg("i", 0), fmt::arg("j", 0), fmt::arg("k", 0), - fmt::arg("l", 0), fmt::arg("m", 0), fmt::arg("n", 0), - fmt::arg("o", 0), fmt::arg("p", 0))); - EXPECT_THROW_MSG(format("{a}"), format_error, "argument not found"); - EXPECT_THROW_MSG(format("{a}", 42), format_error, "argument not found"); -} - -TEST(FormatterTest, AutoArgIndex) { - EXPECT_EQ("abc", format("{}{}{}", 'a', 'b', 'c')); - EXPECT_THROW_MSG(format("{0}{}", 'a', 'b'), format_error, +TEST(format_test, named_arg) { + EXPECT_EQ("1/a/A", fmt::format("{_1}/{a_}/{A_}", fmt::arg("a_", 'a'), + fmt::arg("A_", "A"), fmt::arg("_1", 1))); + EXPECT_EQ(" -42", fmt::format("{0:{width}}", -42, fmt::arg("width", 4))); + EXPECT_EQ("st", + fmt::format("{0:.{precision}}", "str", fmt::arg("precision", 2))); + EXPECT_EQ("1 2", fmt::format("{} {two}", 1, fmt::arg("two", 2))); + EXPECT_EQ("42", + fmt::format("{c}", fmt::arg("a", 0), fmt::arg("b", 0), + fmt::arg("c", 42), fmt::arg("d", 0), fmt::arg("e", 0), + fmt::arg("f", 0), fmt::arg("g", 0), fmt::arg("h", 0), + fmt::arg("i", 0), fmt::arg("j", 0), fmt::arg("k", 0), + fmt::arg("l", 0), fmt::arg("m", 0), fmt::arg("n", 0), + fmt::arg("o", 0), fmt::arg("p", 0))); + EXPECT_THROW_MSG((void)fmt::format(runtime("{a}")), format_error, + "argument not found"); + EXPECT_THROW_MSG((void)fmt::format(runtime("{a}"), 42), format_error, + "argument not found"); +} + +TEST(format_test, auto_arg_index) { + EXPECT_EQ("abc", fmt::format("{}{}{}", 'a', 'b', 'c')); + EXPECT_THROW_MSG((void)fmt::format(runtime("{0}{}"), 'a', 'b'), format_error, "cannot switch from manual to automatic argument indexing"); - EXPECT_THROW_MSG(format("{}{0}", 'a', 'b'), format_error, + EXPECT_THROW_MSG((void)fmt::format(runtime("{}{0}"), 'a', 'b'), format_error, "cannot switch from automatic to manual argument indexing"); - EXPECT_EQ("1.2", format("{:.{}}", 1.2345, 2)); - EXPECT_THROW_MSG(format("{0}:.{}", 1.2345, 2), format_error, + EXPECT_EQ("1.2", fmt::format("{:.{}}", 1.2345, 2)); + EXPECT_THROW_MSG((void)fmt::format(runtime("{0}:.{}"), 1.2345, 2), + format_error, "cannot switch from manual to automatic argument indexing"); - EXPECT_THROW_MSG(format("{:.{0}}", 1.2345, 2), format_error, + EXPECT_THROW_MSG((void)fmt::format(runtime("{:.{0}}"), 1.2345, 2), + format_error, "cannot switch from automatic to manual argument indexing"); - EXPECT_THROW_MSG(format("{}"), format_error, "argument not found"); -} - -TEST(FormatterTest, EmptySpecs) { EXPECT_EQ("42", format("{0:}", 42)); } - -TEST(FormatterTest, LeftAlign) { - EXPECT_EQ("42 ", format("{0:<4}", 42)); - EXPECT_EQ("42 ", format("{0:<4o}", 042)); - EXPECT_EQ("42 ", format("{0:<4x}", 0x42)); - EXPECT_EQ("-42 ", format("{0:<5}", -42)); - EXPECT_EQ("42 ", format("{0:<5}", 42u)); - EXPECT_EQ("-42 ", format("{0:<5}", -42l)); - EXPECT_EQ("42 ", format("{0:<5}", 42ul)); - EXPECT_EQ("-42 ", format("{0:<5}", -42ll)); - EXPECT_EQ("42 ", format("{0:<5}", 42ull)); - EXPECT_EQ("-42 ", format("{0:<5}", -42.0)); - EXPECT_EQ("-42 ", format("{0:<5}", -42.0l)); - EXPECT_EQ("c ", format("{0:<5}", 'c')); - EXPECT_EQ("abc ", format("{0:<5}", "abc")); - EXPECT_EQ("0xface ", format("{0:<8}", reinterpret_cast<void*>(0xface))); -} - -TEST(FormatterTest, RightAlign) { - EXPECT_EQ(" 42", format("{0:>4}", 42)); - EXPECT_EQ(" 42", format("{0:>4o}", 042)); - EXPECT_EQ(" 42", format("{0:>4x}", 0x42)); - EXPECT_EQ(" -42", format("{0:>5}", -42)); - EXPECT_EQ(" 42", format("{0:>5}", 42u)); - EXPECT_EQ(" -42", format("{0:>5}", -42l)); - EXPECT_EQ(" 42", format("{0:>5}", 42ul)); - EXPECT_EQ(" -42", format("{0:>5}", -42ll)); - EXPECT_EQ(" 42", format("{0:>5}", 42ull)); - EXPECT_EQ(" -42", format("{0:>5}", -42.0)); - EXPECT_EQ(" -42", format("{0:>5}", -42.0l)); - EXPECT_EQ(" c", format("{0:>5}", 'c')); - EXPECT_EQ(" abc", format("{0:>5}", "abc")); - EXPECT_EQ(" 0xface", format("{0:>8}", reinterpret_cast<void*>(0xface))); -} - -#if FMT_DEPRECATED_NUMERIC_ALIGN -TEST(FormatterTest, NumericAlign) { EXPECT_EQ("0042", format("{0:=4}", 42)); } -#endif + EXPECT_THROW_MSG((void)fmt::format(runtime("{}")), format_error, + "argument not found"); +} -TEST(FormatterTest, CenterAlign) { - EXPECT_EQ(" 42 ", format("{0:^5}", 42)); - EXPECT_EQ(" 42 ", format("{0:^5o}", 042)); - EXPECT_EQ(" 42 ", format("{0:^5x}", 0x42)); - EXPECT_EQ(" -42 ", format("{0:^5}", -42)); - EXPECT_EQ(" 42 ", format("{0:^5}", 42u)); - EXPECT_EQ(" -42 ", format("{0:^5}", -42l)); - EXPECT_EQ(" 42 ", format("{0:^5}", 42ul)); - EXPECT_EQ(" -42 ", format("{0:^5}", -42ll)); - EXPECT_EQ(" 42 ", format("{0:^5}", 42ull)); - EXPECT_EQ(" -42 ", format("{0:^5}", -42.0)); - EXPECT_EQ(" -42 ", format("{0:^5}", -42.0l)); - EXPECT_EQ(" c ", format("{0:^5}", 'c')); - EXPECT_EQ(" abc ", format("{0:^6}", "abc")); - EXPECT_EQ(" 0xface ", format("{0:^8}", reinterpret_cast<void*>(0xface))); -} - -TEST(FormatterTest, Fill) { - EXPECT_THROW_MSG(format("{0:{<5}", 'c'), format_error, +TEST(format_test, empty_specs) { EXPECT_EQ("42", fmt::format("{0:}", 42)); } + +TEST(format_test, left_align) { + EXPECT_EQ("42 ", fmt::format("{0:<4}", 42)); + EXPECT_EQ("42 ", fmt::format("{0:<4o}", 042)); + EXPECT_EQ("42 ", fmt::format("{0:<4x}", 0x42)); + EXPECT_EQ("-42 ", fmt::format("{0:<5}", -42)); + EXPECT_EQ("42 ", fmt::format("{0:<5}", 42u)); + EXPECT_EQ("-42 ", fmt::format("{0:<5}", -42l)); + EXPECT_EQ("42 ", fmt::format("{0:<5}", 42ul)); + EXPECT_EQ("-42 ", fmt::format("{0:<5}", -42ll)); + EXPECT_EQ("42 ", fmt::format("{0:<5}", 42ull)); + EXPECT_EQ("-42 ", fmt::format("{0:<5}", -42.0)); + EXPECT_EQ("-42 ", fmt::format("{0:<5}", -42.0l)); + EXPECT_EQ("c ", fmt::format("{0:<5}", 'c')); + EXPECT_EQ("abc ", fmt::format("{0:<5}", "abc")); + EXPECT_EQ("0xface ", fmt::format("{0:<8}", reinterpret_cast<void*>(0xface))); +} + +TEST(format_test, right_align) { + EXPECT_EQ(" 42", fmt::format("{0:>4}", 42)); + EXPECT_EQ(" 42", fmt::format("{0:>4o}", 042)); + EXPECT_EQ(" 42", fmt::format("{0:>4x}", 0x42)); + EXPECT_EQ(" -42", fmt::format("{0:>5}", -42)); + EXPECT_EQ(" 42", fmt::format("{0:>5}", 42u)); + EXPECT_EQ(" -42", fmt::format("{0:>5}", -42l)); + EXPECT_EQ(" 42", fmt::format("{0:>5}", 42ul)); + EXPECT_EQ(" -42", fmt::format("{0:>5}", -42ll)); + EXPECT_EQ(" 42", fmt::format("{0:>5}", 42ull)); + EXPECT_EQ(" -42", fmt::format("{0:>5}", -42.0)); + EXPECT_EQ(" -42", fmt::format("{0:>5}", -42.0l)); + EXPECT_EQ(" c", fmt::format("{0:>5}", 'c')); + EXPECT_EQ(" abc", fmt::format("{0:>5}", "abc")); + EXPECT_EQ(" 0xface", fmt::format("{0:>8}", reinterpret_cast<void*>(0xface))); +} + +TEST(format_test, center_align) { + EXPECT_EQ(" 42 ", fmt::format("{0:^5}", 42)); + EXPECT_EQ(" 42 ", fmt::format("{0:^5o}", 042)); + EXPECT_EQ(" 42 ", fmt::format("{0:^5x}", 0x42)); + EXPECT_EQ(" -42 ", fmt::format("{0:^5}", -42)); + EXPECT_EQ(" 42 ", fmt::format("{0:^5}", 42u)); + EXPECT_EQ(" -42 ", fmt::format("{0:^5}", -42l)); + EXPECT_EQ(" 42 ", fmt::format("{0:^5}", 42ul)); + EXPECT_EQ(" -42 ", fmt::format("{0:^5}", -42ll)); + EXPECT_EQ(" 42 ", fmt::format("{0:^5}", 42ull)); + EXPECT_EQ(" -42 ", fmt::format("{0:^5}", -42.0)); + EXPECT_EQ(" -42 ", fmt::format("{0:^5}", -42.0l)); + EXPECT_EQ(" c ", fmt::format("{0:^5}", 'c')); + EXPECT_EQ(" abc ", fmt::format("{0:^6}", "abc")); + EXPECT_EQ(" 0xface ", fmt::format("{0:^8}", reinterpret_cast<void*>(0xface))); +} + +TEST(format_test, fill) { + EXPECT_THROW_MSG((void)fmt::format(runtime("{0:{<5}"), 'c'), format_error, "invalid fill character '{'"); - EXPECT_THROW_MSG(format("{0:{<5}}", 'c'), format_error, + EXPECT_THROW_MSG((void)fmt::format(runtime("{0:{<5}}"), 'c'), format_error, "invalid fill character '{'"); - EXPECT_EQ("**42", format("{0:*>4}", 42)); - EXPECT_EQ("**-42", format("{0:*>5}", -42)); - EXPECT_EQ("***42", format("{0:*>5}", 42u)); - EXPECT_EQ("**-42", format("{0:*>5}", -42l)); - EXPECT_EQ("***42", format("{0:*>5}", 42ul)); - EXPECT_EQ("**-42", format("{0:*>5}", -42ll)); - EXPECT_EQ("***42", format("{0:*>5}", 42ull)); - EXPECT_EQ("**-42", format("{0:*>5}", -42.0)); - EXPECT_EQ("**-42", format("{0:*>5}", -42.0l)); - EXPECT_EQ("c****", format("{0:*<5}", 'c')); - EXPECT_EQ("abc**", format("{0:*<5}", "abc")); - EXPECT_EQ("**0xface", format("{0:*>8}", reinterpret_cast<void*>(0xface))); - EXPECT_EQ("foo=", format("{:}=", "foo")); - EXPECT_EQ(std::string("\0\0\0*", 4), format(string_view("{:\0>4}", 6), '*')); - EXPECT_EQ("жж42", format("{0:ж>4}", 42)); - EXPECT_THROW_MSG(format("{:\x80\x80\x80\x80\x80>}", 0), format_error, - "missing '}' in format string"); -} - -TEST(FormatterTest, PlusSign) { - EXPECT_EQ("+42", format("{0:+}", 42)); - EXPECT_EQ("-42", format("{0:+}", -42)); - EXPECT_EQ("+42", format("{0:+}", 42)); - EXPECT_THROW_MSG(format("{0:+}", 42u), format_error, + EXPECT_EQ("**42", fmt::format("{0:*>4}", 42)); + EXPECT_EQ("**-42", fmt::format("{0:*>5}", -42)); + EXPECT_EQ("***42", fmt::format("{0:*>5}", 42u)); + EXPECT_EQ("**-42", fmt::format("{0:*>5}", -42l)); + EXPECT_EQ("***42", fmt::format("{0:*>5}", 42ul)); + EXPECT_EQ("**-42", fmt::format("{0:*>5}", -42ll)); + EXPECT_EQ("***42", fmt::format("{0:*>5}", 42ull)); + EXPECT_EQ("**-42", fmt::format("{0:*>5}", -42.0)); + EXPECT_EQ("**-42", fmt::format("{0:*>5}", -42.0l)); + EXPECT_EQ("c****", fmt::format("{0:*<5}", 'c')); + EXPECT_EQ("abc**", fmt::format("{0:*<5}", "abc")); + EXPECT_EQ("**0xface", + fmt::format("{0:*>8}", reinterpret_cast<void*>(0xface))); + EXPECT_EQ("foo=", fmt::format("{:}=", "foo")); + EXPECT_EQ(std::string("\0\0\0*", 4), + fmt::format(string_view("{:\0>4}", 6), '*')); + EXPECT_EQ("жж42", fmt::format("{0:ж>4}", 42)); + EXPECT_THROW_MSG((void)fmt::format(runtime("{:\x80\x80\x80\x80\x80>}"), 0), + format_error, "invalid type specifier"); +} + +TEST(format_test, plus_sign) { + EXPECT_EQ("+42", fmt::format("{0:+}", 42)); + EXPECT_EQ("-42", fmt::format("{0:+}", -42)); + EXPECT_EQ("+42", fmt::format("{0:+}", 42)); + EXPECT_THROW_MSG((void)fmt::format(runtime("{0:+}"), 42u), format_error, "format specifier requires signed argument"); - EXPECT_EQ("+42", format("{0:+}", 42l)); - EXPECT_THROW_MSG(format("{0:+}", 42ul), format_error, + EXPECT_EQ("+42", fmt::format("{0:+}", 42l)); + EXPECT_THROW_MSG((void)fmt::format(runtime("{0:+}"), 42ul), format_error, "format specifier requires signed argument"); - EXPECT_EQ("+42", format("{0:+}", 42ll)); - EXPECT_THROW_MSG(format("{0:+}", 42ull), format_error, + EXPECT_EQ("+42", fmt::format("{0:+}", 42ll)); + EXPECT_THROW_MSG((void)fmt::format(runtime("{0:+}"), 42ull), format_error, "format specifier requires signed argument"); - EXPECT_EQ("+42", format("{0:+}", 42.0)); - EXPECT_EQ("+42", format("{0:+}", 42.0l)); - EXPECT_THROW_MSG(format("{0:+", 'c'), format_error, + EXPECT_EQ("+42", fmt::format("{0:+}", 42.0)); + EXPECT_EQ("+42", fmt::format("{0:+}", 42.0l)); + EXPECT_THROW_MSG((void)fmt::format(runtime("{0:+"), 'c'), format_error, "missing '}' in format string"); - EXPECT_THROW_MSG(format("{0:+}", 'c'), format_error, + EXPECT_THROW_MSG((void)fmt::format(runtime("{0:+}"), 'c'), format_error, "invalid format specifier for char"); - EXPECT_THROW_MSG(format("{0:+}", "abc"), format_error, - "format specifier requires numeric argument"); - EXPECT_THROW_MSG(format("{0:+}", reinterpret_cast<void*>(0x42)), format_error, + EXPECT_THROW_MSG((void)fmt::format(runtime("{0:+}"), "abc"), format_error, "format specifier requires numeric argument"); + EXPECT_THROW_MSG( + (void)fmt::format(runtime("{0:+}"), reinterpret_cast<void*>(0x42)), + format_error, "format specifier requires numeric argument"); } -TEST(FormatterTest, MinusSign) { - EXPECT_EQ("42", format("{0:-}", 42)); - EXPECT_EQ("-42", format("{0:-}", -42)); - EXPECT_EQ("42", format("{0:-}", 42)); - EXPECT_THROW_MSG(format("{0:-}", 42u), format_error, +TEST(format_test, minus_sign) { + EXPECT_EQ("42", fmt::format("{0:-}", 42)); + EXPECT_EQ("-42", fmt::format("{0:-}", -42)); + EXPECT_EQ("42", fmt::format("{0:-}", 42)); + EXPECT_THROW_MSG((void)fmt::format(runtime("{0:-}"), 42u), format_error, "format specifier requires signed argument"); - EXPECT_EQ("42", format("{0:-}", 42l)); - EXPECT_THROW_MSG(format("{0:-}", 42ul), format_error, + EXPECT_EQ("42", fmt::format("{0:-}", 42l)); + EXPECT_THROW_MSG((void)fmt::format(runtime("{0:-}"), 42ul), format_error, "format specifier requires signed argument"); - EXPECT_EQ("42", format("{0:-}", 42ll)); - EXPECT_THROW_MSG(format("{0:-}", 42ull), format_error, + EXPECT_EQ("42", fmt::format("{0:-}", 42ll)); + EXPECT_THROW_MSG((void)fmt::format(runtime("{0:-}"), 42ull), format_error, "format specifier requires signed argument"); - EXPECT_EQ("42", format("{0:-}", 42.0)); - EXPECT_EQ("42", format("{0:-}", 42.0l)); - EXPECT_THROW_MSG(format("{0:-", 'c'), format_error, + EXPECT_EQ("42", fmt::format("{0:-}", 42.0)); + EXPECT_EQ("42", fmt::format("{0:-}", 42.0l)); + EXPECT_THROW_MSG((void)fmt::format(runtime("{0:-"), 'c'), format_error, "missing '}' in format string"); - EXPECT_THROW_MSG(format("{0:-}", 'c'), format_error, + EXPECT_THROW_MSG((void)fmt::format(runtime("{0:-}"), 'c'), format_error, "invalid format specifier for char"); - EXPECT_THROW_MSG(format("{0:-}", "abc"), format_error, - "format specifier requires numeric argument"); - EXPECT_THROW_MSG(format("{0:-}", reinterpret_cast<void*>(0x42)), format_error, + EXPECT_THROW_MSG((void)fmt::format(runtime("{0:-}"), "abc"), format_error, "format specifier requires numeric argument"); + EXPECT_THROW_MSG( + (void)fmt::format(runtime("{0:-}"), reinterpret_cast<void*>(0x42)), + format_error, "format specifier requires numeric argument"); } -TEST(FormatterTest, SpaceSign) { - EXPECT_EQ(" 42", format("{0: }", 42)); - EXPECT_EQ("-42", format("{0: }", -42)); - EXPECT_EQ(" 42", format("{0: }", 42)); - EXPECT_THROW_MSG(format("{0: }", 42u), format_error, +TEST(format_test, space_sign) { + EXPECT_EQ(" 42", fmt::format("{0: }", 42)); + EXPECT_EQ("-42", fmt::format("{0: }", -42)); + EXPECT_EQ(" 42", fmt::format("{0: }", 42)); + EXPECT_THROW_MSG((void)fmt::format(runtime("{0: }"), 42u), format_error, "format specifier requires signed argument"); - EXPECT_EQ(" 42", format("{0: }", 42l)); - EXPECT_THROW_MSG(format("{0: }", 42ul), format_error, + EXPECT_EQ(" 42", fmt::format("{0: }", 42l)); + EXPECT_THROW_MSG((void)fmt::format(runtime("{0: }"), 42ul), format_error, "format specifier requires signed argument"); - EXPECT_EQ(" 42", format("{0: }", 42ll)); - EXPECT_THROW_MSG(format("{0: }", 42ull), format_error, + EXPECT_EQ(" 42", fmt::format("{0: }", 42ll)); + EXPECT_THROW_MSG((void)fmt::format(runtime("{0: }"), 42ull), format_error, "format specifier requires signed argument"); - EXPECT_EQ(" 42", format("{0: }", 42.0)); - EXPECT_EQ(" 42", format("{0: }", 42.0l)); - EXPECT_THROW_MSG(format("{0: ", 'c'), format_error, + EXPECT_EQ(" 42", fmt::format("{0: }", 42.0)); + EXPECT_EQ(" 42", fmt::format("{0: }", 42.0l)); + EXPECT_THROW_MSG((void)fmt::format(runtime("{0: "), 'c'), format_error, "missing '}' in format string"); - EXPECT_THROW_MSG(format("{0: }", 'c'), format_error, + EXPECT_THROW_MSG((void)fmt::format(runtime("{0: }"), 'c'), format_error, "invalid format specifier for char"); - EXPECT_THROW_MSG(format("{0: }", "abc"), format_error, + EXPECT_THROW_MSG((void)fmt::format(runtime("{0: }"), "abc"), format_error, "format specifier requires numeric argument"); - EXPECT_THROW_MSG(format("{0: }", reinterpret_cast<void*>(0x42)), format_error, - "format specifier requires numeric argument"); -} - -TEST(FormatterTest, SignNotTruncated) { - wchar_t format_str[] = {L'{', L':', - '+' | (1 << fmt::detail::num_bits<char>()), L'}', 0}; - EXPECT_THROW(format(format_str, 42), format_error); -} - -TEST(FormatterTest, HashFlag) { - EXPECT_EQ("42", format("{0:#}", 42)); - EXPECT_EQ("-42", format("{0:#}", -42)); - EXPECT_EQ("0b101010", format("{0:#b}", 42)); - EXPECT_EQ("0B101010", format("{0:#B}", 42)); - EXPECT_EQ("-0b101010", format("{0:#b}", -42)); - EXPECT_EQ("0x42", format("{0:#x}", 0x42)); - EXPECT_EQ("0X42", format("{0:#X}", 0x42)); - EXPECT_EQ("-0x42", format("{0:#x}", -0x42)); - EXPECT_EQ("0", format("{0:#o}", 0)); - EXPECT_EQ("042", format("{0:#o}", 042)); - EXPECT_EQ("-042", format("{0:#o}", -042)); - EXPECT_EQ("42", format("{0:#}", 42u)); - EXPECT_EQ("0x42", format("{0:#x}", 0x42u)); - EXPECT_EQ("042", format("{0:#o}", 042u)); - - EXPECT_EQ("-42", format("{0:#}", -42l)); - EXPECT_EQ("0x42", format("{0:#x}", 0x42l)); - EXPECT_EQ("-0x42", format("{0:#x}", -0x42l)); - EXPECT_EQ("042", format("{0:#o}", 042l)); - EXPECT_EQ("-042", format("{0:#o}", -042l)); - EXPECT_EQ("42", format("{0:#}", 42ul)); - EXPECT_EQ("0x42", format("{0:#x}", 0x42ul)); - EXPECT_EQ("042", format("{0:#o}", 042ul)); - - EXPECT_EQ("-42", format("{0:#}", -42ll)); - EXPECT_EQ("0x42", format("{0:#x}", 0x42ll)); - EXPECT_EQ("-0x42", format("{0:#x}", -0x42ll)); - EXPECT_EQ("042", format("{0:#o}", 042ll)); - EXPECT_EQ("-042", format("{0:#o}", -042ll)); - EXPECT_EQ("42", format("{0:#}", 42ull)); - EXPECT_EQ("0x42", format("{0:#x}", 0x42ull)); - EXPECT_EQ("042", format("{0:#o}", 042ull)); - - EXPECT_EQ("-42.0", format("{0:#}", -42.0)); - EXPECT_EQ("-42.0", format("{0:#}", -42.0l)); - EXPECT_EQ("4.e+01", format("{:#.0e}", 42.0)); - EXPECT_EQ("0.", format("{:#.0f}", 0.01)); - EXPECT_EQ("0.50", format("{:#.2g}", 0.5)); - EXPECT_EQ("0.", format("{:#.0f}", 0.5)); - EXPECT_THROW_MSG(format("{0:#", 'c'), format_error, + EXPECT_THROW_MSG( + (void)fmt::format(runtime("{0: }"), reinterpret_cast<void*>(0x42)), + format_error, "format specifier requires numeric argument"); +} + +TEST(format_test, hash_flag) { + EXPECT_EQ("42", fmt::format("{0:#}", 42)); + EXPECT_EQ("-42", fmt::format("{0:#}", -42)); + EXPECT_EQ("0b101010", fmt::format("{0:#b}", 42)); + EXPECT_EQ("0B101010", fmt::format("{0:#B}", 42)); + EXPECT_EQ("-0b101010", fmt::format("{0:#b}", -42)); + EXPECT_EQ("0x42", fmt::format("{0:#x}", 0x42)); + EXPECT_EQ("0X42", fmt::format("{0:#X}", 0x42)); + EXPECT_EQ("-0x42", fmt::format("{0:#x}", -0x42)); + EXPECT_EQ("0", fmt::format("{0:#o}", 0)); + EXPECT_EQ("042", fmt::format("{0:#o}", 042)); + EXPECT_EQ("-042", fmt::format("{0:#o}", -042)); + EXPECT_EQ("42", fmt::format("{0:#}", 42u)); + EXPECT_EQ("0x42", fmt::format("{0:#x}", 0x42u)); + EXPECT_EQ("042", fmt::format("{0:#o}", 042u)); + + EXPECT_EQ("-42", fmt::format("{0:#}", -42l)); + EXPECT_EQ("0x42", fmt::format("{0:#x}", 0x42l)); + EXPECT_EQ("-0x42", fmt::format("{0:#x}", -0x42l)); + EXPECT_EQ("042", fmt::format("{0:#o}", 042l)); + EXPECT_EQ("-042", fmt::format("{0:#o}", -042l)); + EXPECT_EQ("42", fmt::format("{0:#}", 42ul)); + EXPECT_EQ("0x42", fmt::format("{0:#x}", 0x42ul)); + EXPECT_EQ("042", fmt::format("{0:#o}", 042ul)); + + EXPECT_EQ("-42", fmt::format("{0:#}", -42ll)); + EXPECT_EQ("0x42", fmt::format("{0:#x}", 0x42ll)); + EXPECT_EQ("-0x42", fmt::format("{0:#x}", -0x42ll)); + EXPECT_EQ("042", fmt::format("{0:#o}", 042ll)); + EXPECT_EQ("-042", fmt::format("{0:#o}", -042ll)); + EXPECT_EQ("42", fmt::format("{0:#}", 42ull)); + EXPECT_EQ("0x42", fmt::format("{0:#x}", 0x42ull)); + EXPECT_EQ("042", fmt::format("{0:#o}", 042ull)); + + EXPECT_EQ("-42.0", fmt::format("{0:#}", -42.0)); + EXPECT_EQ("-42.0", fmt::format("{0:#}", -42.0l)); + EXPECT_EQ("4.e+01", fmt::format("{:#.0e}", 42.0)); + EXPECT_EQ("0.", fmt::format("{:#.0f}", 0.01)); + EXPECT_EQ("0.50", fmt::format("{:#.2g}", 0.5)); + EXPECT_EQ("0.", fmt::format("{:#.0f}", 0.5)); + EXPECT_THROW_MSG((void)fmt::format(runtime("{0:#"), 'c'), format_error, "missing '}' in format string"); - EXPECT_THROW_MSG(format("{0:#}", 'c'), format_error, + EXPECT_THROW_MSG((void)fmt::format(runtime("{0:#}"), 'c'), format_error, "invalid format specifier for char"); - EXPECT_THROW_MSG(format("{0:#}", "abc"), format_error, + EXPECT_THROW_MSG((void)fmt::format(runtime("{0:#}"), "abc"), format_error, "format specifier requires numeric argument"); - EXPECT_THROW_MSG(format("{0:#}", reinterpret_cast<void*>(0x42)), format_error, - "format specifier requires numeric argument"); -} - -TEST(FormatterTest, ZeroFlag) { - EXPECT_EQ("42", format("{0:0}", 42)); - EXPECT_EQ("-0042", format("{0:05}", -42)); - EXPECT_EQ("00042", format("{0:05}", 42u)); - EXPECT_EQ("-0042", format("{0:05}", -42l)); - EXPECT_EQ("00042", format("{0:05}", 42ul)); - EXPECT_EQ("-0042", format("{0:05}", -42ll)); - EXPECT_EQ("00042", format("{0:05}", 42ull)); - EXPECT_EQ("-000042", format("{0:07}", -42.0)); - EXPECT_EQ("-000042", format("{0:07}", -42.0l)); - EXPECT_THROW_MSG(format("{0:0", 'c'), format_error, + EXPECT_THROW_MSG( + (void)fmt::format(runtime("{0:#}"), reinterpret_cast<void*>(0x42)), + format_error, "format specifier requires numeric argument"); +} + +TEST(format_test, zero_flag) { + EXPECT_EQ("42", fmt::format("{0:0}", 42)); + EXPECT_EQ("-0042", fmt::format("{0:05}", -42)); + EXPECT_EQ("00042", fmt::format("{0:05}", 42u)); + EXPECT_EQ("-0042", fmt::format("{0:05}", -42l)); + EXPECT_EQ("00042", fmt::format("{0:05}", 42ul)); + EXPECT_EQ("-0042", fmt::format("{0:05}", -42ll)); + EXPECT_EQ("00042", fmt::format("{0:05}", 42ull)); + EXPECT_EQ("-000042", fmt::format("{0:07}", -42.0)); + EXPECT_EQ("-000042", fmt::format("{0:07}", -42.0l)); + EXPECT_THROW_MSG((void)fmt::format(runtime("{0:0"), 'c'), format_error, "missing '}' in format string"); - EXPECT_THROW_MSG(format("{0:05}", 'c'), format_error, + EXPECT_THROW_MSG((void)fmt::format(runtime("{0:05}"), 'c'), format_error, "invalid format specifier for char"); - EXPECT_THROW_MSG(format("{0:05}", "abc"), format_error, + EXPECT_THROW_MSG((void)fmt::format(runtime("{0:05}"), "abc"), format_error, "format specifier requires numeric argument"); - EXPECT_THROW_MSG(format("{0:05}", reinterpret_cast<void*>(0x42)), - format_error, "format specifier requires numeric argument"); + EXPECT_THROW_MSG( + (void)fmt::format(runtime("{0:05}"), reinterpret_cast<void*>(0x42)), + format_error, "format specifier requires numeric argument"); } -TEST(FormatterTest, Width) { - char format_str[BUFFER_SIZE]; +TEST(format_test, width) { + char format_str[buffer_size]; safe_sprintf(format_str, "{0:%u", UINT_MAX); increment(format_str + 3); - EXPECT_THROW_MSG(format(format_str, 0), format_error, "number is too big"); + EXPECT_THROW_MSG((void)fmt::format(runtime(format_str), 0), format_error, + "number is too big"); size_t size = std::strlen(format_str); format_str[size] = '}'; format_str[size + 1] = 0; - EXPECT_THROW_MSG(format(format_str, 0), format_error, "number is too big"); + EXPECT_THROW_MSG((void)fmt::format(runtime(format_str), 0), format_error, + "number is too big"); safe_sprintf(format_str, "{0:%u", INT_MAX + 1u); - EXPECT_THROW_MSG(format(format_str, 0), format_error, "number is too big"); + EXPECT_THROW_MSG((void)fmt::format(runtime(format_str), 0), format_error, + "number is too big"); safe_sprintf(format_str, "{0:%u}", INT_MAX + 1u); - EXPECT_THROW_MSG(format(format_str, 0), format_error, "number is too big"); - EXPECT_EQ(" -42", format("{0:4}", -42)); - EXPECT_EQ(" 42", format("{0:5}", 42u)); - EXPECT_EQ(" -42", format("{0:6}", -42l)); - EXPECT_EQ(" 42", format("{0:7}", 42ul)); - EXPECT_EQ(" -42", format("{0:6}", -42ll)); - EXPECT_EQ(" 42", format("{0:7}", 42ull)); - EXPECT_EQ(" -1.23", format("{0:8}", -1.23)); - EXPECT_EQ(" -1.23", format("{0:9}", -1.23l)); - EXPECT_EQ(" 0xcafe", format("{0:10}", reinterpret_cast<void*>(0xcafe))); - EXPECT_EQ("x ", format("{0:11}", 'x')); - EXPECT_EQ("str ", format("{0:12}", "str")); - EXPECT_EQ(fmt::format("{:*^5}", "🤡"), "**🤡**"); -} - -template <typename T> inline T const_check(T value) { return value; } - -TEST(FormatterTest, RuntimeWidth) { - char format_str[BUFFER_SIZE]; + EXPECT_THROW_MSG((void)fmt::format(runtime(format_str), 0), format_error, + "number is too big"); + EXPECT_EQ(" -42", fmt::format("{0:4}", -42)); + EXPECT_EQ(" 42", fmt::format("{0:5}", 42u)); + EXPECT_EQ(" -42", fmt::format("{0:6}", -42l)); + EXPECT_EQ(" 42", fmt::format("{0:7}", 42ul)); + EXPECT_EQ(" -42", fmt::format("{0:6}", -42ll)); + EXPECT_EQ(" 42", fmt::format("{0:7}", 42ull)); + EXPECT_EQ(" -1.23", fmt::format("{0:8}", -1.23)); + EXPECT_EQ(" -1.23", fmt::format("{0:9}", -1.23l)); + EXPECT_EQ(" 0xcafe", + fmt::format("{0:10}", reinterpret_cast<void*>(0xcafe))); + EXPECT_EQ("x ", fmt::format("{0:11}", 'x')); + EXPECT_EQ("str ", fmt::format("{0:12}", "str")); + EXPECT_EQ(fmt::format("{:*^6}", "🤡"), "**🤡**"); + EXPECT_EQ(fmt::format("{:*^8}", "你好"), "**你好**"); + EXPECT_EQ(fmt::format("{:#6}", 42.0), " 42.0"); + EXPECT_EQ(fmt::format("{:6c}", static_cast<int>('x')), "x "); + EXPECT_EQ(fmt::format("{:>06.0f}", 0.00884311), "000000"); +} + +TEST(format_test, runtime_width) { + char format_str[buffer_size]; safe_sprintf(format_str, "{0:{%u", UINT_MAX); increment(format_str + 4); - EXPECT_THROW_MSG(format(format_str, 0), format_error, "number is too big"); + EXPECT_THROW_MSG((void)fmt::format(runtime(format_str), 0), format_error, + "invalid format string"); size_t size = std::strlen(format_str); format_str[size] = '}'; format_str[size + 1] = 0; - EXPECT_THROW_MSG(format(format_str, 0), format_error, "number is too big"); + EXPECT_THROW_MSG((void)fmt::format(runtime(format_str), 0), format_error, + "argument not found"); format_str[size + 1] = '}'; format_str[size + 2] = 0; - EXPECT_THROW_MSG(format(format_str, 0), format_error, "number is too big"); + EXPECT_THROW_MSG((void)fmt::format(runtime(format_str), 0), format_error, + "argument not found"); - EXPECT_THROW_MSG(format("{0:{", 0), format_error, "invalid format string"); - EXPECT_THROW_MSG(format("{0:{}", 0), format_error, + EXPECT_THROW_MSG((void)fmt::format(runtime("{0:{"), 0), format_error, + "invalid format string"); + EXPECT_THROW_MSG((void)fmt::format(runtime("{0:{}"), 0), format_error, "cannot switch from manual to automatic argument indexing"); - EXPECT_THROW_MSG(format("{0:{?}}", 0), format_error, "invalid format string"); - EXPECT_THROW_MSG(format("{0:{1}}", 0), format_error, "argument not found"); + EXPECT_THROW_MSG((void)fmt::format(runtime("{0:{?}}"), 0), format_error, + "invalid format string"); + EXPECT_THROW_MSG((void)fmt::format(runtime("{0:{1}}"), 0), format_error, + "argument not found"); - EXPECT_THROW_MSG(format("{0:{0:}}", 0), format_error, + EXPECT_THROW_MSG((void)fmt::format(runtime("{0:{0:}}"), 0), format_error, "invalid format string"); - EXPECT_THROW_MSG(format("{0:{1}}", 0, -1), format_error, "negative width"); - EXPECT_THROW_MSG(format("{0:{1}}", 0, (INT_MAX + 1u)), format_error, - "number is too big"); - EXPECT_THROW_MSG(format("{0:{1}}", 0, -1l), format_error, "negative width"); - if (const_check(sizeof(long) > sizeof(int))) { + EXPECT_THROW_MSG((void)fmt::format(runtime("{0:{1}}"), 0, -1), format_error, + "negative width"); + EXPECT_THROW_MSG((void)fmt::format(runtime("{0:{1}}"), 0, (INT_MAX + 1u)), + format_error, "number is too big"); + EXPECT_THROW_MSG((void)fmt::format(runtime("{0:{1}}"), 0, -1l), format_error, + "negative width"); + if (fmt::detail::const_check(sizeof(long) > sizeof(int))) { long value = INT_MAX; - EXPECT_THROW_MSG(format("{0:{1}}", 0, (value + 1)), format_error, - "number is too big"); + EXPECT_THROW_MSG((void)fmt::format(runtime("{0:{1}}"), 0, (value + 1)), + format_error, "number is too big"); } - EXPECT_THROW_MSG(format("{0:{1}}", 0, (INT_MAX + 1ul)), format_error, - "number is too big"); + EXPECT_THROW_MSG((void)fmt::format(runtime("{0:{1}}"), 0, (INT_MAX + 1ul)), + format_error, "number is too big"); - EXPECT_THROW_MSG(format("{0:{1}}", 0, '0'), format_error, + EXPECT_THROW_MSG((void)fmt::format(runtime("{0:{1}}"), 0, '0'), format_error, "width is not integer"); - EXPECT_THROW_MSG(format("{0:{1}}", 0, 0.0), format_error, + EXPECT_THROW_MSG((void)fmt::format(runtime("{0:{1}}"), 0, 0.0), format_error, "width is not integer"); - EXPECT_EQ(" -42", format("{0:{1}}", -42, 4)); - EXPECT_EQ(" 42", format("{0:{1}}", 42u, 5)); - EXPECT_EQ(" -42", format("{0:{1}}", -42l, 6)); - EXPECT_EQ(" 42", format("{0:{1}}", 42ul, 7)); - EXPECT_EQ(" -42", format("{0:{1}}", -42ll, 6)); - EXPECT_EQ(" 42", format("{0:{1}}", 42ull, 7)); - EXPECT_EQ(" -1.23", format("{0:{1}}", -1.23, 8)); - EXPECT_EQ(" -1.23", format("{0:{1}}", -1.23l, 9)); + EXPECT_EQ(" -42", fmt::format("{0:{1}}", -42, 4)); + EXPECT_EQ(" 42", fmt::format("{0:{1}}", 42u, 5)); + EXPECT_EQ(" -42", fmt::format("{0:{1}}", -42l, 6)); + EXPECT_EQ(" 42", fmt::format("{0:{1}}", 42ul, 7)); + EXPECT_EQ(" -42", fmt::format("{0:{1}}", -42ll, 6)); + EXPECT_EQ(" 42", fmt::format("{0:{1}}", 42ull, 7)); + EXPECT_EQ(" -1.23", fmt::format("{0:{1}}", -1.23, 8)); + EXPECT_EQ(" -1.23", fmt::format("{0:{1}}", -1.23l, 9)); EXPECT_EQ(" 0xcafe", - format("{0:{1}}", reinterpret_cast<void*>(0xcafe), 10)); - EXPECT_EQ("x ", format("{0:{1}}", 'x', 11)); - EXPECT_EQ("str ", format("{0:{1}}", "str", 12)); + fmt::format("{0:{1}}", reinterpret_cast<void*>(0xcafe), 10)); + EXPECT_EQ("x ", fmt::format("{0:{1}}", 'x', 11)); + EXPECT_EQ("str ", fmt::format("{0:{1}}", "str", 12)); } -TEST(FormatterTest, Precision) { - char format_str[BUFFER_SIZE]; +TEST(format_test, precision) { + char format_str[buffer_size]; safe_sprintf(format_str, "{0:.%u", UINT_MAX); increment(format_str + 4); - EXPECT_THROW_MSG(format(format_str, 0), format_error, "number is too big"); + EXPECT_THROW_MSG((void)fmt::format(runtime(format_str), 0), format_error, + "number is too big"); size_t size = std::strlen(format_str); format_str[size] = '}'; format_str[size + 1] = 0; - EXPECT_THROW_MSG(format(format_str, 0), format_error, "number is too big"); + EXPECT_THROW_MSG((void)fmt::format(runtime(format_str), 0), format_error, + "number is too big"); safe_sprintf(format_str, "{0:.%u", INT_MAX + 1u); - EXPECT_THROW_MSG(format(format_str, 0), format_error, "number is too big"); + EXPECT_THROW_MSG((void)fmt::format(runtime(format_str), 0), format_error, + "number is too big"); safe_sprintf(format_str, "{0:.%u}", INT_MAX + 1u); - EXPECT_THROW_MSG(format(format_str, 0), format_error, "number is too big"); + EXPECT_THROW_MSG((void)fmt::format(runtime(format_str), 0), format_error, + "number is too big"); - EXPECT_THROW_MSG(format("{0:.", 0), format_error, + EXPECT_THROW_MSG((void)fmt::format(runtime("{0:."), 0), format_error, "missing precision specifier"); - EXPECT_THROW_MSG(format("{0:.}", 0), format_error, + EXPECT_THROW_MSG((void)fmt::format(runtime("{0:.}"), 0), format_error, "missing precision specifier"); - EXPECT_THROW_MSG(format("{0:.2", 0), format_error, + EXPECT_THROW_MSG((void)fmt::format(runtime("{0:.2"), 0), format_error, "precision not allowed for this argument type"); - EXPECT_THROW_MSG(format("{0:.2}", 42), format_error, + EXPECT_THROW_MSG((void)fmt::format(runtime("{0:.2}"), 42), format_error, "precision not allowed for this argument type"); - EXPECT_THROW_MSG(format("{0:.2f}", 42), format_error, + EXPECT_THROW_MSG((void)fmt::format(runtime("{0:.2f}"), 42), format_error, "precision not allowed for this argument type"); - EXPECT_THROW_MSG(format("{0:.2}", 42u), format_error, + EXPECT_THROW_MSG((void)fmt::format(runtime("{0:.2}"), 42u), format_error, "precision not allowed for this argument type"); - EXPECT_THROW_MSG(format("{0:.2f}", 42u), format_error, + EXPECT_THROW_MSG((void)fmt::format(runtime("{0:.2f}"), 42u), format_error, "precision not allowed for this argument type"); - EXPECT_THROW_MSG(format("{0:.2}", 42l), format_error, + EXPECT_THROW_MSG((void)fmt::format(runtime("{0:.2}"), 42l), format_error, "precision not allowed for this argument type"); - EXPECT_THROW_MSG(format("{0:.2f}", 42l), format_error, + EXPECT_THROW_MSG((void)fmt::format(runtime("{0:.2f}"), 42l), format_error, "precision not allowed for this argument type"); - EXPECT_THROW_MSG(format("{0:.2}", 42ul), format_error, + EXPECT_THROW_MSG((void)fmt::format(runtime("{0:.2}"), 42ul), format_error, "precision not allowed for this argument type"); - EXPECT_THROW_MSG(format("{0:.2f}", 42ul), format_error, + EXPECT_THROW_MSG((void)fmt::format(runtime("{0:.2f}"), 42ul), format_error, "precision not allowed for this argument type"); - EXPECT_THROW_MSG(format("{0:.2}", 42ll), format_error, + EXPECT_THROW_MSG((void)fmt::format(runtime("{0:.2}"), 42ll), format_error, "precision not allowed for this argument type"); - EXPECT_THROW_MSG(format("{0:.2f}", 42ll), format_error, + EXPECT_THROW_MSG((void)fmt::format(runtime("{0:.2f}"), 42ll), format_error, "precision not allowed for this argument type"); - EXPECT_THROW_MSG(format("{0:.2}", 42ull), format_error, + EXPECT_THROW_MSG((void)fmt::format(runtime("{0:.2}"), 42ull), format_error, "precision not allowed for this argument type"); - EXPECT_THROW_MSG(format("{0:.2f}", 42ull), format_error, + EXPECT_THROW_MSG((void)fmt::format(runtime("{0:.2f}"), 42ull), format_error, "precision not allowed for this argument type"); - EXPECT_THROW_MSG(format("{0:3.0}", 'x'), format_error, + EXPECT_THROW_MSG((void)fmt::format(runtime("{0:3.0}"), 'x'), format_error, "precision not allowed for this argument type"); - EXPECT_EQ("1.2", format("{0:.2}", 1.2345)); - EXPECT_EQ("1.2", format("{0:.2}", 1.2345l)); - EXPECT_EQ("1.2e+56", format("{:.2}", 1.234e56)); - EXPECT_EQ("1e+00", format("{:.0e}", 1.0L)); - EXPECT_EQ(" 0.0e+00", format("{:9.1e}", 0.0)); + EXPECT_EQ("1.2", fmt::format("{0:.2}", 1.2345)); + EXPECT_EQ("1.2", fmt::format("{0:.2}", 1.2345l)); + EXPECT_EQ("1.2e+56", fmt::format("{:.2}", 1.234e56)); + EXPECT_EQ("1.1", fmt::format("{0:.3}", 1.1)); + EXPECT_EQ("1e+00", fmt::format("{:.0e}", 1.0L)); + EXPECT_EQ(" 0.0e+00", fmt::format("{:9.1e}", 0.0)); EXPECT_EQ( + fmt::format("{:.494}", 4.9406564584124654E-324), "4.9406564584124654417656879286822137236505980261432476442558568250067550" "727020875186529983636163599237979656469544571773092665671035593979639877" "479601078187812630071319031140452784581716784898210368871863605699873072" "305000638740915356498438731247339727316961514003171538539807412623856559" "117102665855668676818703956031062493194527159149245532930545654440112748" "012970999954193198940908041656332452475714786901472678015935523861155013" - "480352649347201937902681071074917033322268447533357208324319361e-324", - format("{:.494}", 4.9406564584124654E-324)); + "480352649347201937902681071074917033322268447533357208324319361e-324"); EXPECT_EQ( + fmt::format("{:.1074f}", 1.1125369292536e-308), + "0.0000000000000000000000000000000000000000000000000000000000000000000000" + "000000000000000000000000000000000000000000000000000000000000000000000000" + "000000000000000000000000000000000000000000000000000000000000000000000000" + "000000000000000000000000000000000000000000000000000000000000000000000000" + "000000000000000000000111253692925360019747947051741965785554081512200979" + "355021686109411883779182127659725163430929750364498219730822952552570601" + "152163505899912777129583674906301179059298598412303893909188340988729019" + "014361467448914817838555156840459458527907308695109202499990850735085304" + "478476991912072201449236975063640913461919914396877093174125167509869762" + "482369631100360266123742648159508919592746619553246586039571522788247697" + "156360766271842991667238355464496455107749716934387136380536472531224398" + "559833794807213172371254492216255558078524900147957309382830827524104234" + "530961756787819847850302379672357738807808384667004752163416921762619527" + "462847642037420991432005657440259928195996762610375541867198059294212446" + "81962777939941034720757232455434770912461317493580281734466552734375"); + + std::string outputs[] = { "-0X1.41FE3FFE71C9E000000000000000000000000000000000000000000000000000000" "000000000000000000000000000000000000000000000000000000000000000000000000" "000000000000000000000000000000000000000000000000000000000000000000000000" @@ -955,155 +903,193 @@ TEST(FormatterTest, Precision) { "000000000000000000000000000000000000000000000000000000000000000000000000" "000000000000000000000000000000000000000000000000000000000000000000000000" "000000000000000000000000000000000000000000000000000P+127", - format("{:.838A}", -2.14001164E+38)); - EXPECT_EQ("123.", format("{:#.0f}", 123.0)); - EXPECT_EQ("1.23", format("{:.02f}", 1.234)); - EXPECT_EQ("0.001", format("{:.1g}", 0.001)); - EXPECT_EQ("1019666400", format("{}", 1019666432.0f)); - EXPECT_EQ("1e+01", format("{:.0e}", 9.5)); + "-0XA.0FF1FFF38E4F0000000000000000000000000000000000000000000000000000000" + "000000000000000000000000000000000000000000000000000000000000000000000000" + "000000000000000000000000000000000000000000000000000000000000000000000000" + "000000000000000000000000000000000000000000000000000000000000000000000000" + "000000000000000000000000000000000000000000000000000000000000000000000000" + "000000000000000000000000000000000000000000000000000000000000000000000000" + "000000000000000000000000000000000000000000000000000000000000000000000000" + "000000000000000000000000000000000000000000000000000000000000000000000000" + "000000000000000000000000000000000000000000000000000000000000000000000000" + "000000000000000000000000000000000000000000000000000000000000000000000000" + "000000000000000000000000000000000000000000000000000000000000000000000000" + "000000000000000000000000000000000000000000000000000P+124"}; + EXPECT_THAT(outputs, + testing::Contains(fmt::format("{:.838A}", -2.14001164E+38))); + + EXPECT_EQ("123.", fmt::format("{:#.0f}", 123.0)); + EXPECT_EQ("1.23", fmt::format("{:.02f}", 1.234)); + EXPECT_EQ("0.001", fmt::format("{:.1g}", 0.001)); + EXPECT_EQ("1019666400", fmt::format("{}", 1019666432.0f)); + EXPECT_EQ("1e+01", fmt::format("{:.0e}", 9.5)); EXPECT_EQ("1.0e-34", fmt::format("{:.1e}", 1e-34)); - EXPECT_THROW_MSG(format("{0:.2}", reinterpret_cast<void*>(0xcafe)), - format_error, - "precision not allowed for this argument type"); - EXPECT_THROW_MSG(format("{0:.2f}", reinterpret_cast<void*>(0xcafe)), - format_error, - "precision not allowed for this argument type"); - EXPECT_THROW_MSG(format("{:.{}e}", 42.0, fmt::detail::max_value<int>()), + EXPECT_THROW_MSG( + (void)fmt::format(runtime("{0:.2}"), reinterpret_cast<void*>(0xcafe)), + format_error, "precision not allowed for this argument type"); + EXPECT_THROW_MSG( + (void)fmt::format(runtime("{0:.2f}"), reinterpret_cast<void*>(0xcafe)), + format_error, "precision not allowed for this argument type"); + EXPECT_THROW_MSG((void)fmt::format(runtime("{:.{}e}"), 42.0, + fmt::detail::max_value<int>()), format_error, "number is too big"); + EXPECT_THROW_MSG( + (void)fmt::format("{:.2147483646f}", -2.2121295195081227E+304), + format_error, "number is too big"); - EXPECT_EQ("st", format("{0:.2}", "str")); + EXPECT_EQ("st", fmt::format("{0:.2}", "str")); } -TEST(FormatterTest, RuntimePrecision) { - char format_str[BUFFER_SIZE]; +TEST(format_test, runtime_precision) { + char format_str[buffer_size]; safe_sprintf(format_str, "{0:.{%u", UINT_MAX); increment(format_str + 5); - EXPECT_THROW_MSG(format(format_str, 0), format_error, "number is too big"); + EXPECT_THROW_MSG((void)fmt::format(runtime(format_str), 0), format_error, + "invalid format string"); size_t size = std::strlen(format_str); format_str[size] = '}'; format_str[size + 1] = 0; - EXPECT_THROW_MSG(format(format_str, 0), format_error, "number is too big"); + EXPECT_THROW_MSG((void)fmt::format(runtime(format_str), 0), format_error, + "argument not found"); format_str[size + 1] = '}'; format_str[size + 2] = 0; - EXPECT_THROW_MSG(format(format_str, 0), format_error, "number is too big"); + EXPECT_THROW_MSG((void)fmt::format(runtime(format_str), 0), format_error, + "argument not found"); - EXPECT_THROW_MSG(format("{0:.{", 0), format_error, "invalid format string"); - EXPECT_THROW_MSG(format("{0:.{}", 0), format_error, + EXPECT_THROW_MSG((void)fmt::format(runtime("{0:.{"), 0), format_error, + "invalid format string"); + EXPECT_THROW_MSG((void)fmt::format(runtime("{0:.{}"), 0), format_error, "cannot switch from manual to automatic argument indexing"); - EXPECT_THROW_MSG(format("{0:.{?}}", 0), format_error, + EXPECT_THROW_MSG((void)fmt::format(runtime("{0:.{?}}"), 0), format_error, "invalid format string"); - EXPECT_THROW_MSG(format("{0:.{1}", 0, 0), format_error, + EXPECT_THROW_MSG((void)fmt::format(runtime("{0:.{1}"), 0, 0), format_error, "precision not allowed for this argument type"); - EXPECT_THROW_MSG(format("{0:.{1}}", 0), format_error, "argument not found"); + EXPECT_THROW_MSG((void)fmt::format(runtime("{0:.{1}}"), 0), format_error, + "argument not found"); - EXPECT_THROW_MSG(format("{0:.{0:}}", 0), format_error, + EXPECT_THROW_MSG((void)fmt::format(runtime("{0:.{0:}}"), 0), format_error, "invalid format string"); - EXPECT_THROW_MSG(format("{0:.{1}}", 0, -1), format_error, + EXPECT_THROW_MSG((void)fmt::format(runtime("{0:.{1}}"), 0, -1), format_error, "negative precision"); - EXPECT_THROW_MSG(format("{0:.{1}}", 0, (INT_MAX + 1u)), format_error, - "number is too big"); - EXPECT_THROW_MSG(format("{0:.{1}}", 0, -1l), format_error, + EXPECT_THROW_MSG((void)fmt::format(runtime("{0:.{1}}"), 0, (INT_MAX + 1u)), + format_error, "number is too big"); + EXPECT_THROW_MSG((void)fmt::format(runtime("{0:.{1}}"), 0, -1l), format_error, "negative precision"); - if (const_check(sizeof(long) > sizeof(int))) { + if (fmt::detail::const_check(sizeof(long) > sizeof(int))) { long value = INT_MAX; - EXPECT_THROW_MSG(format("{0:.{1}}", 0, (value + 1)), format_error, - "number is too big"); + EXPECT_THROW_MSG((void)fmt::format(runtime("{0:.{1}}"), 0, (value + 1)), + format_error, "number is too big"); } - EXPECT_THROW_MSG(format("{0:.{1}}", 0, (INT_MAX + 1ul)), format_error, - "number is too big"); + EXPECT_THROW_MSG((void)fmt::format(runtime("{0:.{1}}"), 0, (INT_MAX + 1ul)), + format_error, "number is too big"); - EXPECT_THROW_MSG(format("{0:.{1}}", 0, '0'), format_error, + EXPECT_THROW_MSG((void)fmt::format(runtime("{0:.{1}}"), 0, '0'), format_error, "precision is not integer"); - EXPECT_THROW_MSG(format("{0:.{1}}", 0, 0.0), format_error, + EXPECT_THROW_MSG((void)fmt::format(runtime("{0:.{1}}"), 0, 0.0), format_error, "precision is not integer"); - EXPECT_THROW_MSG(format("{0:.{1}}", 42, 2), format_error, + EXPECT_THROW_MSG((void)fmt::format(runtime("{0:.{1}}"), 42, 2), format_error, "precision not allowed for this argument type"); - EXPECT_THROW_MSG(format("{0:.{1}f}", 42, 2), format_error, + EXPECT_THROW_MSG((void)fmt::format(runtime("{0:.{1}f}"), 42, 2), format_error, "precision not allowed for this argument type"); - EXPECT_THROW_MSG(format("{0:.{1}}", 42u, 2), format_error, + EXPECT_THROW_MSG((void)fmt::format(runtime("{0:.{1}}"), 42u, 2), format_error, "precision not allowed for this argument type"); - EXPECT_THROW_MSG(format("{0:.{1}f}", 42u, 2), format_error, + EXPECT_THROW_MSG((void)fmt::format(runtime("{0:.{1}f}"), 42u, 2), + format_error, "precision not allowed for this argument type"); - EXPECT_THROW_MSG(format("{0:.{1}}", 42l, 2), format_error, + EXPECT_THROW_MSG((void)fmt::format(runtime("{0:.{1}}"), 42l, 2), format_error, "precision not allowed for this argument type"); - EXPECT_THROW_MSG(format("{0:.{1}f}", 42l, 2), format_error, + EXPECT_THROW_MSG((void)fmt::format(runtime("{0:.{1}f}"), 42l, 2), + format_error, "precision not allowed for this argument type"); - EXPECT_THROW_MSG(format("{0:.{1}}", 42ul, 2), format_error, + EXPECT_THROW_MSG((void)fmt::format(runtime("{0:.{1}}"), 42ul, 2), + format_error, "precision not allowed for this argument type"); - EXPECT_THROW_MSG(format("{0:.{1}f}", 42ul, 2), format_error, + EXPECT_THROW_MSG((void)fmt::format(runtime("{0:.{1}f}"), 42ul, 2), + format_error, "precision not allowed for this argument type"); - EXPECT_THROW_MSG(format("{0:.{1}}", 42ll, 2), format_error, + EXPECT_THROW_MSG((void)fmt::format(runtime("{0:.{1}}"), 42ll, 2), + format_error, "precision not allowed for this argument type"); - EXPECT_THROW_MSG(format("{0:.{1}f}", 42ll, 2), format_error, + EXPECT_THROW_MSG((void)fmt::format(runtime("{0:.{1}f}"), 42ll, 2), + format_error, "precision not allowed for this argument type"); - EXPECT_THROW_MSG(format("{0:.{1}}", 42ull, 2), format_error, + EXPECT_THROW_MSG((void)fmt::format(runtime("{0:.{1}}"), 42ull, 2), + format_error, "precision not allowed for this argument type"); - EXPECT_THROW_MSG(format("{0:.{1}f}", 42ull, 2), format_error, + EXPECT_THROW_MSG((void)fmt::format(runtime("{0:.{1}f}"), 42ull, 2), + format_error, "precision not allowed for this argument type"); - EXPECT_THROW_MSG(format("{0:3.{1}}", 'x', 0), format_error, + EXPECT_THROW_MSG((void)fmt::format(runtime("{0:3.{1}}"), 'x', 0), + format_error, "precision not allowed for this argument type"); - EXPECT_EQ("1.2", format("{0:.{1}}", 1.2345, 2)); - EXPECT_EQ("1.2", format("{1:.{0}}", 2, 1.2345l)); + EXPECT_EQ("1.2", fmt::format("{0:.{1}}", 1.2345, 2)); + EXPECT_EQ("1.2", fmt::format("{1:.{0}}", 2, 1.2345l)); - EXPECT_THROW_MSG(format("{0:.{1}}", reinterpret_cast<void*>(0xcafe), 2), + EXPECT_THROW_MSG((void)fmt::format(runtime("{0:.{1}}"), + reinterpret_cast<void*>(0xcafe), 2), format_error, "precision not allowed for this argument type"); - EXPECT_THROW_MSG(format("{0:.{1}f}", reinterpret_cast<void*>(0xcafe), 2), + EXPECT_THROW_MSG((void)fmt::format(runtime("{0:.{1}f}"), + reinterpret_cast<void*>(0xcafe), 2), format_error, "precision not allowed for this argument type"); - EXPECT_EQ("st", format("{0:.{1}}", "str", 2)); + EXPECT_EQ("st", fmt::format("{0:.{1}}", "str", 2)); +} + +TEST(format_test, format_bool) { + EXPECT_EQ("true", fmt::format("{}", true)); + EXPECT_EQ("false", fmt::format("{}", false)); + EXPECT_EQ("1", fmt::format("{:d}", true)); + EXPECT_EQ("true ", fmt::format("{:5}", true)); + EXPECT_EQ("true", fmt::format("{:s}", true)); + EXPECT_EQ("false", fmt::format("{:s}", false)); + EXPECT_EQ("false ", fmt::format("{:6s}", false)); +} + +TEST(format_test, format_short) { + short s = 42; + EXPECT_EQ("42", fmt::format("{0:d}", s)); + unsigned short us = 42; + EXPECT_EQ("42", fmt::format("{0:d}", us)); } template <typename T> void check_unknown_types(const T& value, const char* types, const char*) { - char format_str[BUFFER_SIZE]; - const char* special = ".0123456789}"; + char format_str[buffer_size]; + const char* special = ".0123456789L}"; for (int i = CHAR_MIN; i <= CHAR_MAX; ++i) { char c = static_cast<char>(i); if (std::strchr(types, c) || std::strchr(special, c) || !c) continue; safe_sprintf(format_str, "{0:10%c}", c); const char* message = "invalid type specifier"; - EXPECT_THROW_MSG(format(format_str, value), format_error, message) + EXPECT_THROW_MSG((void)fmt::format(runtime(format_str), value), + format_error, message) << format_str << " " << message; } } -TEST(BoolTest, FormatBool) { - EXPECT_EQ("true", format("{}", true)); - EXPECT_EQ("false", format("{}", false)); - EXPECT_EQ("1", format("{:d}", true)); - EXPECT_EQ("true ", format("{:5}", true)); - EXPECT_EQ(L"true", format(L"{}", true)); -} - -TEST(FormatterTest, FormatShort) { - short s = 42; - EXPECT_EQ("42", format("{0:d}", s)); - unsigned short us = 42; - EXPECT_EQ("42", format("{0:d}", us)); -} - -TEST(FormatterTest, FormatInt) { - EXPECT_THROW_MSG(format("{0:v", 42), format_error, - "missing '}' in format string"); +TEST(format_test, format_int) { + EXPECT_THROW_MSG((void)fmt::format(runtime("{0:v"), 42), format_error, + "invalid type specifier"); check_unknown_types(42, "bBdoxXnLc", "integer"); - EXPECT_EQ("x", format("{:c}", static_cast<int>('x'))); -} - -TEST(FormatterTest, FormatBin) { - EXPECT_EQ("0", format("{0:b}", 0)); - EXPECT_EQ("101010", format("{0:b}", 42)); - EXPECT_EQ("101010", format("{0:b}", 42u)); - EXPECT_EQ("-101010", format("{0:b}", -42)); - EXPECT_EQ("11000000111001", format("{0:b}", 12345)); - EXPECT_EQ("10010001101000101011001111000", format("{0:b}", 0x12345678)); - EXPECT_EQ("10010000101010111100110111101111", format("{0:b}", 0x90ABCDEF)); + EXPECT_EQ("x", fmt::format("{:c}", static_cast<int>('x'))); +} + +TEST(format_test, format_bin) { + EXPECT_EQ("0", fmt::format("{0:b}", 0)); + EXPECT_EQ("101010", fmt::format("{0:b}", 42)); + EXPECT_EQ("101010", fmt::format("{0:b}", 42u)); + EXPECT_EQ("-101010", fmt::format("{0:b}", -42)); + EXPECT_EQ("11000000111001", fmt::format("{0:b}", 12345)); + EXPECT_EQ("10010001101000101011001111000", fmt::format("{0:b}", 0x12345678)); + EXPECT_EQ("10010000101010111100110111101111", + fmt::format("{0:b}", 0x90ABCDEF)); EXPECT_EQ("11111111111111111111111111111111", - format("{0:b}", max_value<uint32_t>())); + fmt::format("{0:b}", max_value<uint32_t>())); } #if FMT_USE_INT128 @@ -1114,177 +1100,174 @@ constexpr auto int128_min = -int128_max - 1; constexpr auto uint128_max = ~static_cast<__uint128_t>(0); #endif -TEST(FormatterTest, FormatDec) { - EXPECT_EQ("0", format("{0}", 0)); - EXPECT_EQ("42", format("{0}", 42)); - EXPECT_EQ("42", format("{0:d}", 42)); - EXPECT_EQ("42", format("{0}", 42u)); - EXPECT_EQ("-42", format("{0}", -42)); - EXPECT_EQ("12345", format("{0}", 12345)); - EXPECT_EQ("67890", format("{0}", 67890)); +TEST(format_test, format_dec) { + EXPECT_EQ("0", fmt::format("{0}", 0)); + EXPECT_EQ("42", fmt::format("{0}", 42)); + EXPECT_EQ("42", fmt::format("{0:d}", 42)); + EXPECT_EQ("42", fmt::format("{0}", 42u)); + EXPECT_EQ("-42", fmt::format("{0}", -42)); + EXPECT_EQ("12345", fmt::format("{0}", 12345)); + EXPECT_EQ("67890", fmt::format("{0}", 67890)); #if FMT_USE_INT128 - EXPECT_EQ("0", format("{0}", static_cast<__int128_t>(0))); - EXPECT_EQ("0", format("{0}", static_cast<__uint128_t>(0))); + EXPECT_EQ("0", fmt::format("{0}", static_cast<__int128_t>(0))); + EXPECT_EQ("0", fmt::format("{0}", static_cast<__uint128_t>(0))); EXPECT_EQ("9223372036854775808", - format("{0}", static_cast<__int128_t>(INT64_MAX) + 1)); + fmt::format("{0}", static_cast<__int128_t>(INT64_MAX) + 1)); EXPECT_EQ("-9223372036854775809", - format("{0}", static_cast<__int128_t>(INT64_MIN) - 1)); + fmt::format("{0}", static_cast<__int128_t>(INT64_MIN) - 1)); EXPECT_EQ("18446744073709551616", - format("{0}", static_cast<__int128_t>(UINT64_MAX) + 1)); + fmt::format("{0}", static_cast<__int128_t>(UINT64_MAX) + 1)); EXPECT_EQ("170141183460469231731687303715884105727", - format("{0}", int128_max)); + fmt::format("{0}", int128_max)); EXPECT_EQ("-170141183460469231731687303715884105728", - format("{0}", int128_min)); + fmt::format("{0}", int128_min)); EXPECT_EQ("340282366920938463463374607431768211455", - format("{0}", uint128_max)); + fmt::format("{0}", uint128_max)); #endif - char buffer[BUFFER_SIZE]; + char buffer[buffer_size]; safe_sprintf(buffer, "%d", INT_MIN); - EXPECT_EQ(buffer, format("{0}", INT_MIN)); + EXPECT_EQ(buffer, fmt::format("{0}", INT_MIN)); safe_sprintf(buffer, "%d", INT_MAX); - EXPECT_EQ(buffer, format("{0}", INT_MAX)); + EXPECT_EQ(buffer, fmt::format("{0}", INT_MAX)); safe_sprintf(buffer, "%u", UINT_MAX); - EXPECT_EQ(buffer, format("{0}", UINT_MAX)); + EXPECT_EQ(buffer, fmt::format("{0}", UINT_MAX)); safe_sprintf(buffer, "%ld", 0 - static_cast<unsigned long>(LONG_MIN)); - EXPECT_EQ(buffer, format("{0}", LONG_MIN)); + EXPECT_EQ(buffer, fmt::format("{0}", LONG_MIN)); safe_sprintf(buffer, "%ld", LONG_MAX); - EXPECT_EQ(buffer, format("{0}", LONG_MAX)); + EXPECT_EQ(buffer, fmt::format("{0}", LONG_MAX)); safe_sprintf(buffer, "%lu", ULONG_MAX); - EXPECT_EQ(buffer, format("{0}", ULONG_MAX)); -} - -TEST(FormatterTest, FormatHex) { - EXPECT_EQ("0", format("{0:x}", 0)); - EXPECT_EQ("42", format("{0:x}", 0x42)); - EXPECT_EQ("42", format("{0:x}", 0x42u)); - EXPECT_EQ("-42", format("{0:x}", -0x42)); - EXPECT_EQ("12345678", format("{0:x}", 0x12345678)); - EXPECT_EQ("90abcdef", format("{0:x}", 0x90abcdef)); - EXPECT_EQ("12345678", format("{0:X}", 0x12345678)); - EXPECT_EQ("90ABCDEF", format("{0:X}", 0x90ABCDEF)); + EXPECT_EQ(buffer, fmt::format("{0}", ULONG_MAX)); +} + +TEST(format_test, format_hex) { + EXPECT_EQ("0", fmt::format("{0:x}", 0)); + EXPECT_EQ("42", fmt::format("{0:x}", 0x42)); + EXPECT_EQ("42", fmt::format("{0:x}", 0x42u)); + EXPECT_EQ("-42", fmt::format("{0:x}", -0x42)); + EXPECT_EQ("12345678", fmt::format("{0:x}", 0x12345678)); + EXPECT_EQ("90abcdef", fmt::format("{0:x}", 0x90abcdef)); + EXPECT_EQ("12345678", fmt::format("{0:X}", 0x12345678)); + EXPECT_EQ("90ABCDEF", fmt::format("{0:X}", 0x90ABCDEF)); #if FMT_USE_INT128 - EXPECT_EQ("0", format("{0:x}", static_cast<__int128_t>(0))); - EXPECT_EQ("0", format("{0:x}", static_cast<__uint128_t>(0))); + EXPECT_EQ("0", fmt::format("{0:x}", static_cast<__int128_t>(0))); + EXPECT_EQ("0", fmt::format("{0:x}", static_cast<__uint128_t>(0))); EXPECT_EQ("8000000000000000", - format("{0:x}", static_cast<__int128_t>(INT64_MAX) + 1)); + fmt::format("{0:x}", static_cast<__int128_t>(INT64_MAX) + 1)); EXPECT_EQ("-8000000000000001", - format("{0:x}", static_cast<__int128_t>(INT64_MIN) - 1)); + fmt::format("{0:x}", static_cast<__int128_t>(INT64_MIN) - 1)); EXPECT_EQ("10000000000000000", - format("{0:x}", static_cast<__int128_t>(UINT64_MAX) + 1)); - EXPECT_EQ("7fffffffffffffffffffffffffffffff", format("{0:x}", int128_max)); - EXPECT_EQ("-80000000000000000000000000000000", format("{0:x}", int128_min)); - EXPECT_EQ("ffffffffffffffffffffffffffffffff", format("{0:x}", uint128_max)); + fmt::format("{0:x}", static_cast<__int128_t>(UINT64_MAX) + 1)); + EXPECT_EQ("7fffffffffffffffffffffffffffffff", + fmt::format("{0:x}", int128_max)); + EXPECT_EQ("-80000000000000000000000000000000", + fmt::format("{0:x}", int128_min)); + EXPECT_EQ("ffffffffffffffffffffffffffffffff", + fmt::format("{0:x}", uint128_max)); #endif - char buffer[BUFFER_SIZE]; + char buffer[buffer_size]; safe_sprintf(buffer, "-%x", 0 - static_cast<unsigned>(INT_MIN)); - EXPECT_EQ(buffer, format("{0:x}", INT_MIN)); + EXPECT_EQ(buffer, fmt::format("{0:x}", INT_MIN)); safe_sprintf(buffer, "%x", INT_MAX); - EXPECT_EQ(buffer, format("{0:x}", INT_MAX)); + EXPECT_EQ(buffer, fmt::format("{0:x}", INT_MAX)); safe_sprintf(buffer, "%x", UINT_MAX); - EXPECT_EQ(buffer, format("{0:x}", UINT_MAX)); + EXPECT_EQ(buffer, fmt::format("{0:x}", UINT_MAX)); safe_sprintf(buffer, "-%lx", 0 - static_cast<unsigned long>(LONG_MIN)); - EXPECT_EQ(buffer, format("{0:x}", LONG_MIN)); + EXPECT_EQ(buffer, fmt::format("{0:x}", LONG_MIN)); safe_sprintf(buffer, "%lx", LONG_MAX); - EXPECT_EQ(buffer, format("{0:x}", LONG_MAX)); + EXPECT_EQ(buffer, fmt::format("{0:x}", LONG_MAX)); safe_sprintf(buffer, "%lx", ULONG_MAX); - EXPECT_EQ(buffer, format("{0:x}", ULONG_MAX)); + EXPECT_EQ(buffer, fmt::format("{0:x}", ULONG_MAX)); } -TEST(FormatterTest, FormatOct) { - EXPECT_EQ("0", format("{0:o}", 0)); - EXPECT_EQ("42", format("{0:o}", 042)); - EXPECT_EQ("42", format("{0:o}", 042u)); - EXPECT_EQ("-42", format("{0:o}", -042)); - EXPECT_EQ("12345670", format("{0:o}", 012345670)); +TEST(format_test, format_oct) { + EXPECT_EQ("0", fmt::format("{0:o}", 0)); + EXPECT_EQ("42", fmt::format("{0:o}", 042)); + EXPECT_EQ("42", fmt::format("{0:o}", 042u)); + EXPECT_EQ("-42", fmt::format("{0:o}", -042)); + EXPECT_EQ("12345670", fmt::format("{0:o}", 012345670)); #if FMT_USE_INT128 - EXPECT_EQ("0", format("{0:o}", static_cast<__int128_t>(0))); - EXPECT_EQ("0", format("{0:o}", static_cast<__uint128_t>(0))); + EXPECT_EQ("0", fmt::format("{0:o}", static_cast<__int128_t>(0))); + EXPECT_EQ("0", fmt::format("{0:o}", static_cast<__uint128_t>(0))); EXPECT_EQ("1000000000000000000000", - format("{0:o}", static_cast<__int128_t>(INT64_MAX) + 1)); + fmt::format("{0:o}", static_cast<__int128_t>(INT64_MAX) + 1)); EXPECT_EQ("-1000000000000000000001", - format("{0:o}", static_cast<__int128_t>(INT64_MIN) - 1)); + fmt::format("{0:o}", static_cast<__int128_t>(INT64_MIN) - 1)); EXPECT_EQ("2000000000000000000000", - format("{0:o}", static_cast<__int128_t>(UINT64_MAX) + 1)); + fmt::format("{0:o}", static_cast<__int128_t>(UINT64_MAX) + 1)); EXPECT_EQ("1777777777777777777777777777777777777777777", - format("{0:o}", int128_max)); + fmt::format("{0:o}", int128_max)); EXPECT_EQ("-2000000000000000000000000000000000000000000", - format("{0:o}", int128_min)); + fmt::format("{0:o}", int128_min)); EXPECT_EQ("3777777777777777777777777777777777777777777", - format("{0:o}", uint128_max)); + fmt::format("{0:o}", uint128_max)); #endif - char buffer[BUFFER_SIZE]; + char buffer[buffer_size]; safe_sprintf(buffer, "-%o", 0 - static_cast<unsigned>(INT_MIN)); - EXPECT_EQ(buffer, format("{0:o}", INT_MIN)); + EXPECT_EQ(buffer, fmt::format("{0:o}", INT_MIN)); safe_sprintf(buffer, "%o", INT_MAX); - EXPECT_EQ(buffer, format("{0:o}", INT_MAX)); + EXPECT_EQ(buffer, fmt::format("{0:o}", INT_MAX)); safe_sprintf(buffer, "%o", UINT_MAX); - EXPECT_EQ(buffer, format("{0:o}", UINT_MAX)); + EXPECT_EQ(buffer, fmt::format("{0:o}", UINT_MAX)); safe_sprintf(buffer, "-%lo", 0 - static_cast<unsigned long>(LONG_MIN)); - EXPECT_EQ(buffer, format("{0:o}", LONG_MIN)); + EXPECT_EQ(buffer, fmt::format("{0:o}", LONG_MIN)); safe_sprintf(buffer, "%lo", LONG_MAX); - EXPECT_EQ(buffer, format("{0:o}", LONG_MAX)); + EXPECT_EQ(buffer, fmt::format("{0:o}", LONG_MAX)); safe_sprintf(buffer, "%lo", ULONG_MAX); - EXPECT_EQ(buffer, format("{0:o}", ULONG_MAX)); -} - -TEST(FormatterTest, FormatIntLocale) { - EXPECT_EQ("1234", format("{:L}", 1234)); + EXPECT_EQ(buffer, fmt::format("{0:o}", ULONG_MAX)); } -struct ConvertibleToLongLong { - operator long long() const { return 1LL << 32; } -}; - -TEST(FormatterTest, FormatConvertibleToLongLong) { - EXPECT_EQ("100000000", format("{:x}", ConvertibleToLongLong())); +TEST(format_test, format_int_locale) { + EXPECT_EQ("1234", fmt::format("{:L}", 1234)); } -TEST(FormatterTest, FormatFloat) { - EXPECT_EQ("0", format("{}", 0.0f)); - EXPECT_EQ("392.500000", format("{0:f}", 392.5f)); +TEST(format_test, format_float) { + EXPECT_EQ("0", fmt::format("{}", 0.0f)); + EXPECT_EQ("392.500000", fmt::format("{0:f}", 392.5f)); } -TEST(FormatterTest, FormatDouble) { - EXPECT_EQ("0", format("{}", 0.0)); +TEST(format_test, format_double) { + EXPECT_EQ("0", fmt::format("{}", 0.0)); check_unknown_types(1.2, "eEfFgGaAnL%", "double"); - EXPECT_EQ("0", format("{:}", 0.0)); - EXPECT_EQ("0.000000", format("{:f}", 0.0)); - EXPECT_EQ("0", format("{:g}", 0.0)); - EXPECT_EQ("392.65", format("{:}", 392.65)); - EXPECT_EQ("392.65", format("{:g}", 392.65)); - EXPECT_EQ("392.65", format("{:G}", 392.65)); - EXPECT_EQ("4.9014e+06", format("{:g}", 4.9014e6)); - EXPECT_EQ("392.650000", format("{:f}", 392.65)); - EXPECT_EQ("392.650000", format("{:F}", 392.65)); - EXPECT_EQ("42", format("{:L}", 42.0)); - char buffer[BUFFER_SIZE]; + EXPECT_EQ("0", fmt::format("{:}", 0.0)); + EXPECT_EQ("0.000000", fmt::format("{:f}", 0.0)); + EXPECT_EQ("0", fmt::format("{:g}", 0.0)); + EXPECT_EQ("392.65", fmt::format("{:}", 392.65)); + EXPECT_EQ("392.65", fmt::format("{:g}", 392.65)); + EXPECT_EQ("392.65", fmt::format("{:G}", 392.65)); + EXPECT_EQ("4.9014e+06", fmt::format("{:g}", 4.9014e6)); + EXPECT_EQ("392.650000", fmt::format("{:f}", 392.65)); + EXPECT_EQ("392.650000", fmt::format("{:F}", 392.65)); + EXPECT_EQ("42", fmt::format("{:L}", 42.0)); + EXPECT_EQ(" 0x1.0cccccccccccdp+2", fmt::format("{:24a}", 4.2)); + EXPECT_EQ("0x1.0cccccccccccdp+2 ", fmt::format("{:<24a}", 4.2)); + char buffer[buffer_size]; safe_sprintf(buffer, "%e", 392.65); - EXPECT_EQ(buffer, format("{0:e}", 392.65)); + EXPECT_EQ(buffer, fmt::format("{0:e}", 392.65)); safe_sprintf(buffer, "%E", 392.65); - EXPECT_EQ(buffer, format("{0:E}", 392.65)); - EXPECT_EQ("+0000392.6", format("{0:+010.4g}", 392.65)); + EXPECT_EQ(buffer, fmt::format("{0:E}", 392.65)); + EXPECT_EQ("+0000392.6", fmt::format("{0:+010.4g}", 392.65)); safe_sprintf(buffer, "%a", -42.0); - EXPECT_EQ(buffer, format("{:a}", -42.0)); + EXPECT_EQ(buffer, fmt::format("{:a}", -42.0)); safe_sprintf(buffer, "%A", -42.0); - EXPECT_EQ(buffer, format("{:A}", -42.0)); + EXPECT_EQ(buffer, fmt::format("{:A}", -42.0)); EXPECT_EQ("9223372036854775808.000000", - format("{:f}", 9223372036854775807.0)); -} - -TEST(FormatterTest, PrecisionRounding) { - EXPECT_EQ("0", format("{:.0f}", 0.0)); - EXPECT_EQ("0", format("{:.0f}", 0.01)); - EXPECT_EQ("0", format("{:.0f}", 0.1)); - EXPECT_EQ("0.000", format("{:.3f}", 0.00049)); - EXPECT_EQ("0.001", format("{:.3f}", 0.0005)); - EXPECT_EQ("0.001", format("{:.3f}", 0.00149)); - EXPECT_EQ("0.002", format("{:.3f}", 0.0015)); - EXPECT_EQ("1.000", format("{:.3f}", 0.9999)); - EXPECT_EQ("0.00123", format("{:.3}", 0.00123)); - EXPECT_EQ("0.1", format("{:.16g}", 0.1)); + fmt::format("{:f}", 9223372036854775807.0)); +} + +TEST(format_test, precision_rounding) { + EXPECT_EQ("0", fmt::format("{:.0f}", 0.0)); + EXPECT_EQ("0", fmt::format("{:.0f}", 0.01)); + EXPECT_EQ("0", fmt::format("{:.0f}", 0.1)); + EXPECT_EQ("0.000", fmt::format("{:.3f}", 0.00049)); + EXPECT_EQ("0.001", fmt::format("{:.3f}", 0.0005)); + EXPECT_EQ("0.001", fmt::format("{:.3f}", 0.00149)); + EXPECT_EQ("0.002", fmt::format("{:.3f}", 0.0015)); + EXPECT_EQ("1.000", fmt::format("{:.3f}", 0.9999)); + EXPECT_EQ("0.00123", fmt::format("{:.3}", 0.00123)); + EXPECT_EQ("0.1", fmt::format("{:.16g}", 0.1)); EXPECT_EQ("1", fmt::format("{:.0}", 1.0)); EXPECT_EQ("225.51575035152063720", fmt::format("{:.17f}", 225.51575035152064)); @@ -1294,10 +1277,10 @@ TEST(FormatterTest, PrecisionRounding) { EXPECT_EQ("0.0000", fmt::format("{:.4f}", 7.2809479766055470e-15)); // Trigger a rounding error in Grisu by a specially chosen number. - EXPECT_EQ("3788512123356.985352", format("{:f}", 3788512123356.985352)); + EXPECT_EQ("3788512123356.985352", fmt::format("{:f}", 3788512123356.985352)); } -TEST(FormatterTest, PrettifyFloat) { +TEST(format_test, prettify_float) { EXPECT_EQ("0.0001", fmt::format("{}", 1e-4)); EXPECT_EQ("1e-05", fmt::format("{}", 1e-5)); EXPECT_EQ("1000000000000000", fmt::format("{}", 1e15)); @@ -1313,127 +1296,128 @@ TEST(FormatterTest, PrettifyFloat) { EXPECT_EQ("1.3563156e-19", fmt::format("{}", 1.35631564e-19f)); } -TEST(FormatterTest, FormatNaN) { +TEST(format_test, format_nan) { double nan = std::numeric_limits<double>::quiet_NaN(); - EXPECT_EQ("nan", format("{}", nan)); - EXPECT_EQ("+nan", format("{:+}", nan)); - if (std::signbit(-nan)) - EXPECT_EQ("-nan", format("{}", -nan)); - else + EXPECT_EQ("nan", fmt::format("{}", nan)); + EXPECT_EQ("+nan", fmt::format("{:+}", nan)); + EXPECT_EQ(" +nan", fmt::format("{:+06}", nan)); + EXPECT_EQ("+nan ", fmt::format("{:<+06}", nan)); + EXPECT_EQ(" +nan ", fmt::format("{:^+06}", nan)); + EXPECT_EQ(" +nan", fmt::format("{:>+06}", nan)); + if (std::signbit(-nan)) { + EXPECT_EQ("-nan", fmt::format("{}", -nan)); + EXPECT_EQ(" -nan", fmt::format("{:+06}", -nan)); + } else { fmt::print("Warning: compiler doesn't handle negative NaN correctly"); - EXPECT_EQ(" nan", format("{: }", nan)); - EXPECT_EQ("NAN", format("{:F}", nan)); - EXPECT_EQ("nan ", format("{:<7}", nan)); - EXPECT_EQ(" nan ", format("{:^7}", nan)); - EXPECT_EQ(" nan", format("{:>7}", nan)); + } + EXPECT_EQ(" nan", fmt::format("{: }", nan)); + EXPECT_EQ("NAN", fmt::format("{:F}", nan)); + EXPECT_EQ("nan ", fmt::format("{:<7}", nan)); + EXPECT_EQ(" nan ", fmt::format("{:^7}", nan)); + EXPECT_EQ(" nan", fmt::format("{:>7}", nan)); } -TEST(FormatterTest, FormatInfinity) { +TEST(format_test, format_infinity) { double inf = std::numeric_limits<double>::infinity(); - EXPECT_EQ("inf", format("{}", inf)); - EXPECT_EQ("+inf", format("{:+}", inf)); - EXPECT_EQ("-inf", format("{}", -inf)); - EXPECT_EQ(" inf", format("{: }", inf)); - EXPECT_EQ("INF", format("{:F}", inf)); - EXPECT_EQ("inf ", format("{:<7}", inf)); - EXPECT_EQ(" inf ", format("{:^7}", inf)); - EXPECT_EQ(" inf", format("{:>7}", inf)); -} - -TEST(FormatterTest, FormatLongDouble) { - EXPECT_EQ("0", format("{0:}", 0.0l)); - EXPECT_EQ("0.000000", format("{0:f}", 0.0l)); - EXPECT_EQ("392.65", format("{0:}", 392.65l)); - EXPECT_EQ("392.65", format("{0:g}", 392.65l)); - EXPECT_EQ("392.65", format("{0:G}", 392.65l)); - EXPECT_EQ("392.650000", format("{0:f}", 392.65l)); - EXPECT_EQ("392.650000", format("{0:F}", 392.65l)); - char buffer[BUFFER_SIZE]; + EXPECT_EQ("inf", fmt::format("{}", inf)); + EXPECT_EQ("+inf", fmt::format("{:+}", inf)); + EXPECT_EQ("-inf", fmt::format("{}", -inf)); + EXPECT_EQ(" +inf", fmt::format("{:+06}", inf)); + EXPECT_EQ(" -inf", fmt::format("{:+06}", -inf)); + EXPECT_EQ("+inf ", fmt::format("{:<+06}", inf)); + EXPECT_EQ(" +inf ", fmt::format("{:^+06}", inf)); + EXPECT_EQ(" +inf", fmt::format("{:>+06}", inf)); + EXPECT_EQ(" inf", fmt::format("{: }", inf)); + EXPECT_EQ("INF", fmt::format("{:F}", inf)); + EXPECT_EQ("inf ", fmt::format("{:<7}", inf)); + EXPECT_EQ(" inf ", fmt::format("{:^7}", inf)); + EXPECT_EQ(" inf", fmt::format("{:>7}", inf)); +} + +TEST(format_test, format_long_double) { + EXPECT_EQ("0", fmt::format("{0:}", 0.0l)); + EXPECT_EQ("0.000000", fmt::format("{0:f}", 0.0l)); + EXPECT_EQ("392.65", fmt::format("{0:}", 392.65l)); + EXPECT_EQ("392.65", fmt::format("{0:g}", 392.65l)); + EXPECT_EQ("392.65", fmt::format("{0:G}", 392.65l)); + EXPECT_EQ("392.650000", fmt::format("{0:f}", 392.65l)); + EXPECT_EQ("392.650000", fmt::format("{0:F}", 392.65l)); + char buffer[buffer_size]; safe_sprintf(buffer, "%Le", 392.65l); - EXPECT_EQ(buffer, format("{0:e}", 392.65l)); - EXPECT_EQ("+0000392.6", format("{0:+010.4g}", 392.64l)); + EXPECT_EQ(buffer, fmt::format("{0:e}", 392.65l)); + EXPECT_EQ("+0000392.6", fmt::format("{0:+010.4g}", 392.64l)); safe_sprintf(buffer, "%La", 3.31l); - EXPECT_EQ(buffer, format("{:a}", 3.31l)); + EXPECT_EQ(buffer, fmt::format("{:a}", 3.31l)); } -TEST(FormatterTest, FormatChar) { - const char types[] = "cbBdoxXL"; +TEST(format_test, format_char) { + const char types[] = "cbBdoxX"; check_unknown_types('a', types, "char"); - EXPECT_EQ("a", format("{0}", 'a')); - EXPECT_EQ("z", format("{0:c}", 'z')); - EXPECT_EQ(L"a", format(L"{0}", 'a')); + EXPECT_EQ("a", fmt::format("{0}", 'a')); + EXPECT_EQ("z", fmt::format("{0:c}", 'z')); int n = 'x'; for (const char* type = types + 1; *type; ++type) { std::string format_str = fmt::format("{{:{}}}", *type); - EXPECT_EQ(fmt::format(format_str, n), fmt::format(format_str, 'x')); + EXPECT_EQ(fmt::format(runtime(format_str), n), + fmt::format(runtime(format_str), 'x')) + << format_str; } EXPECT_EQ(fmt::format("{:02X}", n), fmt::format("{:02X}", 'x')); } -TEST(FormatterTest, FormatVolatileChar) { +TEST(format_test, format_volatile_char) { volatile char c = 'x'; - EXPECT_EQ("x", format("{}", c)); -} - -TEST(FormatterTest, FormatUnsignedChar) { - EXPECT_EQ("42", format("{}", static_cast<unsigned char>(42))); - EXPECT_EQ("42", format("{}", static_cast<uint8_t>(42))); + EXPECT_EQ("x", fmt::format("{}", c)); } -TEST(FormatterTest, FormatWChar) { - EXPECT_EQ(L"a", format(L"{0}", L'a')); - // This shouldn't compile: - // format("{}", L'a'); +TEST(format_test, format_unsigned_char) { + EXPECT_EQ("42", fmt::format("{}", static_cast<unsigned char>(42))); + EXPECT_EQ("42", fmt::format("{}", static_cast<uint8_t>(42))); } -TEST(FormatterTest, FormatCString) { +TEST(format_test, format_cstring) { check_unknown_types("test", "sp", "string"); - EXPECT_EQ("test", format("{0}", "test")); - EXPECT_EQ("test", format("{0:s}", "test")); + EXPECT_EQ("test", fmt::format("{0}", "test")); + EXPECT_EQ("test", fmt::format("{0:s}", "test")); char nonconst[] = "nonconst"; - EXPECT_EQ("nonconst", format("{0}", nonconst)); - EXPECT_THROW_MSG(format("{0}", static_cast<const char*>(nullptr)), - format_error, "string pointer is null"); -} - -TEST(FormatterTest, FormatSCharString) { - signed char str[] = "test"; - EXPECT_EQ("test", format("{0:s}", str)); - const signed char* const_str = str; - EXPECT_EQ("test", format("{0:s}", const_str)); + EXPECT_EQ("nonconst", fmt::format("{0}", nonconst)); + EXPECT_THROW_MSG( + (void)fmt::format(runtime("{0}"), static_cast<const char*>(nullptr)), + format_error, "string pointer is null"); } -TEST(FormatterTest, FormatUCharString) { - unsigned char str[] = "test"; - EXPECT_EQ("test", format("{0:s}", str)); - const unsigned char* const_str = str; - EXPECT_EQ("test", format("{0:s}", const_str)); - unsigned char* ptr = str; - EXPECT_EQ("test", format("{0:s}", ptr)); -} +void function_pointer_test(int, double, std::string) {} -TEST(FormatterTest, FormatPointer) { +TEST(format_test, format_pointer) { check_unknown_types(reinterpret_cast<void*>(0x1234), "p", "pointer"); - EXPECT_EQ("0x0", format("{0}", static_cast<void*>(nullptr))); - EXPECT_EQ("0x1234", format("{0}", reinterpret_cast<void*>(0x1234))); - EXPECT_EQ("0x1234", format("{0:p}", reinterpret_cast<void*>(0x1234))); + EXPECT_EQ("0x0", fmt::format("{0}", static_cast<void*>(nullptr))); + EXPECT_EQ("0x1234", fmt::format("{0}", reinterpret_cast<void*>(0x1234))); + EXPECT_EQ("0x1234", fmt::format("{0:p}", reinterpret_cast<void*>(0x1234))); EXPECT_EQ("0x" + std::string(sizeof(void*) * CHAR_BIT / 4, 'f'), - format("{0}", reinterpret_cast<void*>(~uintptr_t()))); - EXPECT_EQ("0x1234", format("{}", fmt::ptr(reinterpret_cast<int*>(0x1234)))); + fmt::format("{0}", reinterpret_cast<void*>(~uintptr_t()))); + EXPECT_EQ("0x1234", + fmt::format("{}", fmt::ptr(reinterpret_cast<int*>(0x1234)))); std::unique_ptr<int> up(new int(1)); - EXPECT_EQ(format("{}", fmt::ptr(up.get())), format("{}", fmt::ptr(up))); + EXPECT_EQ(fmt::format("{}", fmt::ptr(up.get())), + fmt::format("{}", fmt::ptr(up))); std::shared_ptr<int> sp(new int(1)); - EXPECT_EQ(format("{}", fmt::ptr(sp.get())), format("{}", fmt::ptr(sp))); - EXPECT_EQ("0x0", format("{}", nullptr)); + EXPECT_EQ(fmt::format("{}", fmt::ptr(sp.get())), + fmt::format("{}", fmt::ptr(sp))); + EXPECT_EQ(fmt::format("{}", fmt::detail::bit_cast<const void*>( + &function_pointer_test)), + fmt::format("{}", fmt::ptr(function_pointer_test))); + EXPECT_EQ("0x0", fmt::format("{}", nullptr)); } -TEST(FormatterTest, FormatString) { - EXPECT_EQ("test", format("{0}", std::string("test"))); +TEST(format_test, format_string) { + EXPECT_EQ("test", fmt::format("{0}", std::string("test"))); + EXPECT_THROW((void)fmt::format(fmt::runtime("{:x}"), std::string("test")), + fmt::format_error); } -TEST(FormatterTest, FormatStringView) { - EXPECT_EQ("test", format("{}", string_view("test"))); - EXPECT_EQ("", format("{}", string_view())); +TEST(format_test, format_string_view) { + EXPECT_EQ("test", fmt::format("{}", string_view("test"))); + EXPECT_EQ("", fmt::format("{}", string_view())); } #ifdef FMT_USE_STRING_VIEW @@ -1447,68 +1431,55 @@ template <> struct formatter<string_viewable> : formatter<std::string_view> { }; FMT_END_NAMESPACE -TEST(FormatterTest, FormatStdStringView) { - EXPECT_EQ("test", format("{}", std::string_view("test"))); - EXPECT_EQ("foo", format("{}", string_viewable())); +TEST(format_test, format_std_string_view) { + EXPECT_EQ("test", fmt::format("{}", std::string_view("test"))); + EXPECT_EQ("foo", fmt::format("{}", string_viewable())); } struct explicitly_convertible_to_std_string_view { explicit operator std::string_view() const { return "foo"; } }; -namespace fmt { template <> -struct formatter<explicitly_convertible_to_std_string_view> +struct fmt::formatter<explicitly_convertible_to_std_string_view> : formatter<std::string_view> { - auto format(const explicitly_convertible_to_std_string_view& v, - format_context& ctx) -> decltype(ctx.out()) { + auto format(explicitly_convertible_to_std_string_view v, format_context& ctx) + -> decltype(ctx.out()) { return format_to(ctx.out(), "'{}'", std::string_view(v)); } }; -} // namespace fmt -TEST(FormatterTest, FormatExplicitlyConvertibleToStdStringView) { +TEST(format_test, format_explicitly_convertible_to_std_string_view) { EXPECT_EQ("'foo'", fmt::format("{}", explicitly_convertible_to_std_string_view())); } #endif -// std::is_constructible is broken in MSVC until version 2015. -#if !FMT_MSC_VER || FMT_MSC_VER >= 1900 -struct explicitly_convertible_to_wstring_view { - explicit operator fmt::wstring_view() const { return L"foo"; } +struct converible_to_anything { + template <typename T> operator T() const { return T(); } }; -TEST(FormatTest, FormatExplicitlyConvertibleToWStringView) { - EXPECT_EQ(L"foo", - fmt::format(L"{}", explicitly_convertible_to_wstring_view())); -} -#endif - -namespace fake_qt { -class QString { - public: - QString(const wchar_t* s) : s_(std::make_shared<std::wstring>(s)) {} - const wchar_t* utf16() const FMT_NOEXCEPT { return s_->data(); } - int size() const FMT_NOEXCEPT { return static_cast<int>(s_->size()); } +FMT_BEGIN_NAMESPACE +template <> struct formatter<converible_to_anything> { + FMT_CONSTEXPR auto parse(format_parse_context& ctx) -> decltype(ctx.begin()) { + return ctx.begin(); + } - private: - std::shared_ptr<std::wstring> s_; + auto format(converible_to_anything, format_context& ctx) + -> decltype(ctx.out()) { + return format_to(ctx.out(), "foo"); + } }; +FMT_END_NAMESPACE -fmt::basic_string_view<wchar_t> to_string_view(const QString& s) FMT_NOEXCEPT { - return {s.utf16(), static_cast<size_t>(s.size())}; +TEST(format_test, format_convertible_to_anything) { + EXPECT_EQ("foo", fmt::format("{}", converible_to_anything())); } -} // namespace fake_qt -TEST(FormatTest, FormatForeignStrings) { - using fake_qt::QString; - EXPECT_EQ(fmt::format(QString(L"{}"), 42), L"42"); - EXPECT_EQ(fmt::format(QString(L"{}"), QString(L"42")), L"42"); -} +class Answer {}; FMT_BEGIN_NAMESPACE -template <> struct formatter<Date> { +template <> struct formatter<date> { template <typename ParseContext> FMT_CONSTEXPR auto parse(ParseContext& ctx) -> decltype(ctx.begin()) { auto it = ctx.begin(); @@ -1516,22 +1487,12 @@ template <> struct formatter<Date> { return it; } - auto format(const Date& d, format_context& ctx) -> decltype(ctx.out()) { + auto format(const date& d, format_context& ctx) -> decltype(ctx.out()) { format_to(ctx.out(), "{}-{}-{}", d.year(), d.month(), d.day()); return ctx.out(); } }; -FMT_END_NAMESPACE - -TEST(FormatterTest, FormatCustom) { - Date date(2012, 12, 9); - EXPECT_THROW_MSG(fmt::format("{:s}", date), format_error, - "unknown format specifier"); -} -class Answer {}; - -FMT_BEGIN_NAMESPACE template <> struct formatter<Answer> : formatter<int> { template <typename FormatContext> auto format(Answer, FormatContext& ctx) -> decltype(ctx.out()) { @@ -1540,12 +1501,14 @@ template <> struct formatter<Answer> : formatter<int> { }; FMT_END_NAMESPACE -TEST(FormatterTest, CustomFormat) { - EXPECT_EQ("42", format("{0}", Answer())); - EXPECT_EQ("0042", format("{:04}", Answer())); +TEST(format_test, format_custom) { + EXPECT_THROW_MSG((void)fmt::format(runtime("{:s}"), date(2012, 12, 9)), + format_error, "unknown format specifier"); + EXPECT_EQ("42", fmt::format("{0}", Answer())); + EXPECT_EQ("0042", fmt::format("{:04}", Answer())); } -TEST(FormatterTest, CustomFormatTo) { +TEST(format_test, format_to_custom) { char buf[10] = {}; auto end = &*fmt::format_to(fmt::detail::make_checked(buf, 10), "{}", Answer()); @@ -1553,29 +1516,20 @@ TEST(FormatterTest, CustomFormatTo) { EXPECT_STREQ(buf, "42"); } -TEST(FormatterTest, WideFormatString) { - EXPECT_EQ(L"42", format(L"{}", 42)); - EXPECT_EQ(L"4.2", format(L"{}", 4.2)); - EXPECT_EQ(L"abc", format(L"{}", L"abc")); - EXPECT_EQ(L"z", format(L"{}", L'z')); - EXPECT_THROW(fmt::format(L"{:*\x343E}", 42), fmt::format_error); -} - -TEST(FormatterTest, FormatStringFromSpeedTest) { +TEST(format_test, format_string_from_speed_test) { EXPECT_EQ("1.2340000000:0042:+3.13:str:0x3e8:X:%", - format("{0:0.10f}:{1:04}:{2:+g}:{3}:{4}:{5}:%", 1.234, 42, 3.13, - "str", reinterpret_cast<void*>(1000), 'X')); + fmt::format("{0:0.10f}:{1:04}:{2:+g}:{3}:{4}:{5}:%", 1.234, 42, + 3.13, "str", reinterpret_cast<void*>(1000), 'X')); } -TEST(FormatterTest, FormatExamples) { - std::string message = format("The answer is {}", 42); +TEST(format_test, format_examples) { + std::string message = fmt::format("The answer is {}", 42); EXPECT_EQ("The answer is 42", message); - EXPECT_EQ("42", format("{}", 42)); - EXPECT_EQ("42", format(std::string("{}"), 42)); + EXPECT_EQ("42", fmt::format("{}", 42)); memory_buffer out; - format_to(out, "The answer is {}.", 42); + format_to(std::back_inserter(out), "The answer is {}.", 42); EXPECT_EQ("The answer is 42.", to_string(out)); const char* filename = "nonexistent"; @@ -1591,143 +1545,123 @@ TEST(FormatterTest, FormatExamples) { fclose(f); }, error_code, "Cannot open file 'nonexistent'"); -} -TEST(FormatterTest, Examples) { EXPECT_EQ("First, thou shalt count to three", - format("First, thou shalt count to {0}", "three")); - EXPECT_EQ("Bring me a shrubbery", format("Bring me a {}", "shrubbery")); - EXPECT_EQ("From 1 to 3", format("From {} to {}", 1, 3)); + fmt::format("First, thou shalt count to {0}", "three")); + EXPECT_EQ("Bring me a shrubbery", fmt::format("Bring me a {}", "shrubbery")); + EXPECT_EQ("From 1 to 3", fmt::format("From {} to {}", 1, 3)); - char buffer[BUFFER_SIZE]; + char buffer[buffer_size]; safe_sprintf(buffer, "%03.2f", -1.2); - EXPECT_EQ(buffer, format("{:03.2f}", -1.2)); + EXPECT_EQ(buffer, fmt::format("{:03.2f}", -1.2)); - EXPECT_EQ("a, b, c", format("{0}, {1}, {2}", 'a', 'b', 'c')); - EXPECT_EQ("a, b, c", format("{}, {}, {}", 'a', 'b', 'c')); - EXPECT_EQ("c, b, a", format("{2}, {1}, {0}", 'a', 'b', 'c')); - EXPECT_EQ("abracadabra", format("{0}{1}{0}", "abra", "cad")); + EXPECT_EQ("a, b, c", fmt::format("{0}, {1}, {2}", 'a', 'b', 'c')); + EXPECT_EQ("a, b, c", fmt::format("{}, {}, {}", 'a', 'b', 'c')); + EXPECT_EQ("c, b, a", fmt::format("{2}, {1}, {0}", 'a', 'b', 'c')); + EXPECT_EQ("abracadabra", fmt::format("{0}{1}{0}", "abra", "cad")); - EXPECT_EQ("left aligned ", format("{:<30}", "left aligned")); + EXPECT_EQ("left aligned ", + fmt::format("{:<30}", "left aligned")); EXPECT_EQ(" right aligned", - format("{:>30}", "right aligned")); - EXPECT_EQ(" centered ", format("{:^30}", "centered")); - EXPECT_EQ("***********centered***********", format("{:*^30}", "centered")); + fmt::format("{:>30}", "right aligned")); + EXPECT_EQ(" centered ", + fmt::format("{:^30}", "centered")); + EXPECT_EQ("***********centered***********", + fmt::format("{:*^30}", "centered")); - EXPECT_EQ("+3.140000; -3.140000", format("{:+f}; {:+f}", 3.14, -3.14)); - EXPECT_EQ(" 3.140000; -3.140000", format("{: f}; {: f}", 3.14, -3.14)); - EXPECT_EQ("3.140000; -3.140000", format("{:-f}; {:-f}", 3.14, -3.14)); + EXPECT_EQ("+3.140000; -3.140000", fmt::format("{:+f}; {:+f}", 3.14, -3.14)); + EXPECT_EQ(" 3.140000; -3.140000", fmt::format("{: f}; {: f}", 3.14, -3.14)); + EXPECT_EQ("3.140000; -3.140000", fmt::format("{:-f}; {:-f}", 3.14, -3.14)); EXPECT_EQ("int: 42; hex: 2a; oct: 52", - format("int: {0:d}; hex: {0:x}; oct: {0:o}", 42)); + fmt::format("int: {0:d}; hex: {0:x}; oct: {0:o}", 42)); EXPECT_EQ("int: 42; hex: 0x2a; oct: 052", - format("int: {0:d}; hex: {0:#x}; oct: {0:#o}", 42)); - - EXPECT_EQ("The answer is 42", format("The answer is {}", 42)); - EXPECT_THROW_MSG(format("The answer is {:d}", "forty-two"), format_error, - "invalid type specifier"); + fmt::format("int: {0:d}; hex: {0:#x}; oct: {0:#o}", 42)); - EXPECT_EQ(L"Cyrillic letter \x42e", format(L"Cyrillic letter {}", L'\x42e')); + EXPECT_EQ("The answer is 42", fmt::format("The answer is {}", 42)); + EXPECT_THROW_MSG( + (void)fmt::format(runtime("The answer is {:d}"), "forty-two"), + format_error, "invalid type specifier"); EXPECT_WRITE( stdout, fmt::print("{}", std::numeric_limits<double>::infinity()), "inf"); } -TEST(FormatIntTest, Data) { - fmt::format_int format_int(42); - EXPECT_EQ("42", std::string(format_int.data(), format_int.size())); -} - -TEST(FormatIntTest, FormatInt) { - EXPECT_EQ("42", fmt::format_int(42).str()); - EXPECT_EQ(2u, fmt::format_int(42).size()); - EXPECT_EQ("-42", fmt::format_int(-42).str()); - EXPECT_EQ(3u, fmt::format_int(-42).size()); - EXPECT_EQ("42", fmt::format_int(42ul).str()); - EXPECT_EQ("-42", fmt::format_int(-42l).str()); - EXPECT_EQ("42", fmt::format_int(42ull).str()); - EXPECT_EQ("-42", fmt::format_int(-42ll).str()); - std::ostringstream os; - os << max_value<int64_t>(); - EXPECT_EQ(os.str(), fmt::format_int(max_value<int64_t>()).str()); -} - -TEST(FormatTest, Print) { -#if FMT_USE_FCNTL +TEST(format_test, print) { EXPECT_WRITE(stdout, fmt::print("Don't {}!", "panic"), "Don't panic!"); EXPECT_WRITE(stderr, fmt::print(stderr, "Don't {}!", "panic"), "Don't panic!"); -#endif - // Check that the wide print overload compiles. - if (fmt::detail::const_check(false)) fmt::print(L"test"); } -TEST(FormatTest, Variadic) { - EXPECT_EQ("abc1", format("{}c{}", "ab", 1)); - EXPECT_EQ(L"abc1", format(L"{}c{}", L"ab", 1)); +TEST(format_test, variadic) { + EXPECT_EQ("abc1", fmt::format("{}c{}", "ab", 1)); } -TEST(FormatTest, Dynamic) { - typedef fmt::format_context ctx; - std::vector<fmt::basic_format_arg<ctx>> args; +TEST(format_test, dynamic) { + using ctx = fmt::format_context; + auto args = std::vector<fmt::basic_format_arg<ctx>>(); args.emplace_back(fmt::detail::make_arg<ctx>(42)); args.emplace_back(fmt::detail::make_arg<ctx>("abc1")); args.emplace_back(fmt::detail::make_arg<ctx>(1.5f)); std::string result = fmt::vformat( "{} and {} and {}", - fmt::basic_format_args<ctx>(args.data(), static_cast<int>(args.size()))); + fmt::format_args(args.data(), static_cast<int>(args.size()))); EXPECT_EQ("42 and abc1 and 1.5", result); } -TEST(FormatTest, Bytes) { +TEST(format_test, bytes) { auto s = fmt::format("{:10}", fmt::bytes("ёжик")); EXPECT_EQ("ёжик ", s); EXPECT_EQ(10, s.size()); } -TEST(FormatTest, JoinArg) { +TEST(format_test, group_digits_view) { + EXPECT_EQ(fmt::format("{}", fmt::group_digits(10000000)), "10,000,000"); + EXPECT_EQ(fmt::format("{:8}", fmt::group_digits(1000)), " 1,000"); +} + +enum test_enum { foo, bar }; + +TEST(format_test, join) { using fmt::join; int v1[3] = {1, 2, 3}; - std::vector<float> v2; + auto v2 = std::vector<float>(); v2.push_back(1.2f); v2.push_back(3.4f); void* v3[2] = {&v1[0], &v1[1]}; - EXPECT_EQ("(1, 2, 3)", format("({})", join(v1, v1 + 3, ", "))); - EXPECT_EQ("(1)", format("({})", join(v1, v1 + 1, ", "))); - EXPECT_EQ("()", format("({})", join(v1, v1, ", "))); - EXPECT_EQ("(001, 002, 003)", format("({:03})", join(v1, v1 + 3, ", "))); + EXPECT_EQ("(1, 2, 3)", fmt::format("({})", join(v1, v1 + 3, ", "))); + EXPECT_EQ("(1)", fmt::format("({})", join(v1, v1 + 1, ", "))); + EXPECT_EQ("()", fmt::format("({})", join(v1, v1, ", "))); + EXPECT_EQ("(001, 002, 003)", fmt::format("({:03})", join(v1, v1 + 3, ", "))); EXPECT_EQ("(+01.20, +03.40)", - format("({:+06.2f})", join(v2.begin(), v2.end(), ", "))); + fmt::format("({:+06.2f})", join(v2.begin(), v2.end(), ", "))); - EXPECT_EQ(L"(1, 2, 3)", format(L"({})", join(v1, v1 + 3, L", "))); - EXPECT_EQ("1, 2, 3", format("{0:{1}}", join(v1, v1 + 3, ", "), 1)); + EXPECT_EQ("1, 2, 3", fmt::format("{0:{1}}", join(v1, v1 + 3, ", "), 1)); - EXPECT_EQ(format("{}, {}", v3[0], v3[1]), - format("{}", join(v3, v3 + 2, ", "))); + EXPECT_EQ(fmt::format("{}, {}", v3[0], v3[1]), + fmt::format("{}", join(v3, v3 + 2, ", "))); -#if !FMT_GCC_VERSION || FMT_GCC_VERSION >= 405 - EXPECT_EQ("(1, 2, 3)", format("({})", join(v1, ", "))); - EXPECT_EQ("(+01.20, +03.40)", format("({:+06.2f})", join(v2, ", "))); -#endif -} + EXPECT_EQ("(1, 2, 3)", fmt::format("({})", join(v1, ", "))); + EXPECT_EQ("(+01.20, +03.40)", fmt::format("({:+06.2f})", join(v2, ", "))); -template <typename T> std::string str(const T& value) { - return fmt::format("{}", value); + auto v4 = std::vector<test_enum>{foo, bar, foo}; + EXPECT_EQ("0 1 0", fmt::format("{}", join(v4, " "))); } -TEST(StrTest, Convert) { - EXPECT_EQ("42", str(42)); - std::string s = str(Date(2012, 12, 9)); - EXPECT_EQ("2012-12-9", s); +#ifdef __cpp_lib_byte +TEST(format_test, join_bytes) { + auto v = std::vector<std::byte>{std::byte(1), std::byte(2), std::byte(3)}; + EXPECT_EQ("1, 2, 3", fmt::format("{}", fmt::join(v, ", "))); } +#endif std::string vformat_message(int id, const char* format, fmt::format_args args) { - fmt::memory_buffer buffer; - format_to(buffer, "[{}] ", id); - vformat_to(buffer, format, args); + auto buffer = fmt::memory_buffer(); + format_to(fmt::appender(buffer), "[{}] ", id); + vformat_to(fmt::appender(buffer), format, args); return to_string(buffer); } @@ -1737,7 +1671,7 @@ std::string format_message(int id, const char* format, const Args&... args) { return vformat_message(id, format, va); } -TEST(FormatTest, FormatMessageExample) { +TEST(format_test, format_message_example) { EXPECT_EQ("[42] something happened", format_message(42, "{} happened", "something")); } @@ -1749,7 +1683,7 @@ void print_error(const char* file, int line, const char* format, fmt::print(format, args...); } -TEST(FormatTest, UnpackedArgs) { +TEST(format_test, unpacked_args) { EXPECT_EQ("0123456789abcdefg", fmt::format("{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}", 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 'a', 'b', 'c', 'd', 'e', 'f', 'g')); @@ -1760,11 +1694,29 @@ fmt::string_view to_string_view(string_like) { return "foo"; } constexpr char with_null[3] = {'{', '}', '\0'}; constexpr char no_null[2] = {'{', '}'}; +static FMT_CONSTEXPR_DECL const char static_with_null[3] = {'{', '}', '\0'}; +static FMT_CONSTEXPR_DECL const char static_no_null[2] = {'{', '}'}; -TEST(FormatTest, CompileTimeString) { +TEST(format_test, compile_time_string) { + EXPECT_EQ("foo", fmt::format(FMT_STRING("foo"))); EXPECT_EQ("42", fmt::format(FMT_STRING("{}"), 42)); - EXPECT_EQ(L"42", fmt::format(FMT_STRING(L"{}"), 42)); EXPECT_EQ("foo", fmt::format(FMT_STRING("{}"), string_like())); + +#if FMT_USE_NONTYPE_TEMPLATE_PARAMETERS + using namespace fmt::literals; + EXPECT_EQ("foobar", fmt::format(FMT_STRING("{foo}{bar}"), "bar"_a = "bar", + "foo"_a = "foo")); + EXPECT_EQ("", fmt::format(FMT_STRING(""))); + EXPECT_EQ("", fmt::format(FMT_STRING(""), "arg"_a = 42)); +#endif + + (void)static_with_null; + (void)static_no_null; +#ifndef _MSC_VER + EXPECT_EQ("42", fmt::format(FMT_STRING(static_with_null), 42)); + EXPECT_EQ("42", fmt::format(FMT_STRING(static_no_null), 42)); +#endif + (void)with_null; (void)no_null; #if __cplusplus >= 201703L @@ -1773,13 +1725,12 @@ TEST(FormatTest, CompileTimeString) { #endif #if defined(FMT_USE_STRING_VIEW) && __cplusplus >= 201703L EXPECT_EQ("42", fmt::format(FMT_STRING(std::string_view("{}")), 42)); - EXPECT_EQ(L"42", fmt::format(FMT_STRING(std::wstring_view(L"{}")), 42)); #endif } -TEST(FormatTest, CustomFormatCompileTimeString) { +TEST(format_test, custom_format_compile_time_string) { EXPECT_EQ("42", fmt::format(FMT_STRING("{}"), Answer())); - Answer answer; + auto answer = Answer(); EXPECT_EQ("42", fmt::format(FMT_STRING("{}"), answer)); char buf[10] = {}; fmt::format_to(buf, FMT_STRING("{}"), answer); @@ -1794,100 +1745,98 @@ TEST(FormatTest, CustomFormatCompileTimeString) { using namespace fmt::literals; -TEST(LiteralsTest, Format) { - auto udl_format = "{}c{}"_format("ab", 1); - EXPECT_EQ(format("{}c{}", "ab", 1), udl_format); - auto udl_format_w = L"{}c{}"_format(L"ab", 1); - EXPECT_EQ(format(L"{}c{}", L"ab", 1), udl_format_w); -} - -TEST(LiteralsTest, NamedArg) { - auto udl_a = format("{first}{second}{first}{third}", "first"_a = "abra", - "second"_a = "cad", "third"_a = 99); - EXPECT_EQ(format("{first}{second}{first}{third}", fmt::arg("first", "abra"), - fmt::arg("second", "cad"), fmt::arg("third", 99)), - udl_a); - auto udl_a_w = format(L"{first}{second}{first}{third}", L"first"_a = L"abra", - L"second"_a = L"cad", L"third"_a = 99); - EXPECT_EQ( - format(L"{first}{second}{first}{third}", fmt::arg(L"first", L"abra"), - fmt::arg(L"second", L"cad"), fmt::arg(L"third", 99)), - udl_a_w); -} +# if FMT_GCC_VERSION +# define FMT_CHECK_DEPRECATED_UDL_FORMAT 1 +# elif FMT_CLANG_VERSION && defined(__has_warning) +# if __has_warning("-Wdeprecated-declarations") +# define FMT_CHECK_DEPRECATED_UDL_FORMAT 1 +# endif +# endif +# ifndef FMT_CHECK_DEPRECATED_UDL_FORMAT +# define FMT_CHECK_DEPRECATED_UDL_FORMAT 0 +# endif -TEST(FormatTest, UdlTemplate) { - EXPECT_EQ("foo", "foo"_format()); - EXPECT_EQ(" 42", "{0:10}"_format(42)); +# if FMT_CHECK_DEPRECATED_UDL_FORMAT +# pragma GCC diagnostic push +# pragma GCC diagnostic ignored "-Wdeprecated-declarations" + +TEST(format_test, format_udl) { + EXPECT_EQ("{}c{}"_format("ab", 1), fmt::format("{}c{}", "ab", 1)); + EXPECT_EQ("foo"_format(), "foo"); + EXPECT_EQ("{0:10}"_format(42), " 42"); + EXPECT_EQ("{}"_format(date(2015, 10, 21)), "2015-10-21"); } -TEST(FormatTest, UdlPassUserDefinedObjectAsLvalue) { - Date date(2015, 10, 21); - EXPECT_EQ("2015-10-21", "{}"_format(date)); +# pragma GCC diagnostic pop +# endif + +TEST(format_test, named_arg_udl) { + auto udl_a = fmt::format("{first}{second}{first}{third}", "first"_a = "abra", + "second"_a = "cad", "third"_a = 99); + EXPECT_EQ( + fmt::format("{first}{second}{first}{third}", fmt::arg("first", "abra"), + fmt::arg("second", "cad"), fmt::arg("third", 99)), + udl_a); } #endif // FMT_USE_USER_DEFINED_LITERALS -enum TestEnum { A }; +TEST(format_test, enum) { EXPECT_EQ("0", fmt::format("{}", foo)); } -TEST(FormatTest, Enum) { EXPECT_EQ("0", fmt::format("{}", A)); } - -TEST(FormatTest, FormatterNotSpecialized) { - static_assert( - !fmt::has_formatter<fmt::formatter<TestEnum>, fmt::format_context>::value, - ""); +TEST(format_test, formatter_not_specialized) { + static_assert(!fmt::has_formatter<fmt::formatter<test_enum>, + fmt::format_context>::value, + ""); } #if FMT_HAS_FEATURE(cxx_strong_enums) enum big_enum : unsigned long long { big_enum_value = 5000000000ULL }; -TEST(FormatTest, StrongEnum) { +TEST(format_test, strong_enum) { EXPECT_EQ("5000000000", fmt::format("{}", big_enum_value)); } #endif -TEST(FormatTest, NonNullTerminatedFormatString) { - EXPECT_EQ("42", format(string_view("{}foo", 2), 42)); +TEST(format_test, non_null_terminated_format_string) { + EXPECT_EQ("42", fmt::format(string_view("{}foo", 2), 42)); } struct variant { - enum { INT, STRING } type; - explicit variant(int) : type(INT) {} - explicit variant(const char*) : type(STRING) {} + enum { int_type, string_type } type; + explicit variant(int) : type(int_type) {} + explicit variant(const char*) : type(string_type) {} }; FMT_BEGIN_NAMESPACE template <> struct formatter<variant> : dynamic_formatter<> { auto format(variant value, format_context& ctx) -> decltype(ctx.out()) { - if (value.type == variant::INT) return dynamic_formatter<>::format(42, ctx); + if (value.type == variant::int_type) + return dynamic_formatter<>::format(42, ctx); return dynamic_formatter<>::format("foo", ctx); } }; FMT_END_NAMESPACE -TEST(FormatTest, DynamicFormatter) { +TEST(format_test, dynamic_formatter) { auto num = variant(42); auto str = variant("foo"); - EXPECT_EQ("42", format("{:d}", num)); - EXPECT_EQ("foo", format("{:s}", str)); - EXPECT_EQ(" 42 foo ", format("{:{}} {:{}}", num, 3, str, 4)); - EXPECT_THROW_MSG(format("{0:{}}", num), format_error, + EXPECT_EQ("42", fmt::format("{:d}", num)); + EXPECT_EQ("foo", fmt::format("{:s}", str)); + EXPECT_EQ(" 42 foo ", fmt::format("{:{}} {:{}}", num, 3, str, 4)); + EXPECT_THROW_MSG((void)fmt::format(runtime("{0:{}}"), num), format_error, "cannot switch from manual to automatic argument indexing"); - EXPECT_THROW_MSG(format("{:{0}}", num), format_error, + EXPECT_THROW_MSG((void)fmt::format(runtime("{:{0}}"), num), format_error, "cannot switch from automatic to manual argument indexing"); -#if FMT_DEPRECATED_NUMERIC_ALIGN - EXPECT_THROW_MSG(format("{:=}", str), format_error, - "format specifier requires numeric argument"); -#endif - EXPECT_THROW_MSG(format("{:+}", str), format_error, + EXPECT_THROW_MSG((void)fmt::format(runtime("{:+}"), str), format_error, "format specifier requires numeric argument"); - EXPECT_THROW_MSG(format("{:-}", str), format_error, + EXPECT_THROW_MSG((void)fmt::format(runtime("{:-}"), str), format_error, "format specifier requires numeric argument"); - EXPECT_THROW_MSG(format("{: }", str), format_error, + EXPECT_THROW_MSG((void)fmt::format(runtime("{: }"), str), format_error, "format specifier requires numeric argument"); - EXPECT_THROW_MSG(format("{:#}", str), format_error, + EXPECT_THROW_MSG((void)fmt::format(runtime("{:#}"), str), format_error, "format specifier requires numeric argument"); - EXPECT_THROW_MSG(format("{:0}", str), format_error, + EXPECT_THROW_MSG((void)fmt::format(runtime("{:0}"), str), format_error, "format specifier requires numeric argument"); - EXPECT_THROW_MSG(format("{:.2}", num), format_error, + EXPECT_THROW_MSG((void)fmt::format(runtime("{:.2}"), num), format_error, "precision not allowed for this argument type"); } @@ -1911,15 +1860,23 @@ struct formatter<adl_test::fmt::detail::foo> : formatter<std::string> { }; FMT_END_NAMESPACE -TEST(FormatTest, ToString) { - EXPECT_EQ("42", fmt::to_string(42)); - EXPECT_EQ("0x1234", fmt::to_string(reinterpret_cast<void*>(0x1234))); - EXPECT_EQ("foo", fmt::to_string(adl_test::fmt::detail::foo())); -} +struct convertible_to_int { + operator int() const { return value; } + + int value = 42; +}; + +TEST(format_test, to_string) { + EXPECT_EQ(fmt::to_string(42), "42"); + EXPECT_EQ(fmt::to_string(reinterpret_cast<void*>(0x1234)), "0x1234"); + EXPECT_EQ(fmt::to_string(adl_test::fmt::detail::foo()), "foo"); + EXPECT_EQ(fmt::to_string(convertible_to_int()), "42"); -TEST(FormatTest, ToWString) { EXPECT_EQ(L"42", fmt::to_wstring(42)); } + enum foo : unsigned char { zero }; + EXPECT_EQ(fmt::to_string(zero), "0"); +} -TEST(FormatTest, OutputIterators) { +TEST(format_test, output_iterators) { std::list<char> out; fmt::format_to(std::back_inserter(out), "{}", 42); EXPECT_EQ("42", std::string(out.begin(), out.end())); @@ -1928,17 +1885,48 @@ TEST(FormatTest, OutputIterators) { EXPECT_EQ("42", s.str()); } -TEST(FormatTest, FormattedSize) { +TEST(format_test, formatted_size) { EXPECT_EQ(2u, fmt::formatted_size("{}", 42)); } -TEST(FormatTest, FormatTo) { +TEST(format_test, format_to_no_args) { + std::string s; + fmt::format_to(std::back_inserter(s), "test"); + EXPECT_EQ("test", s); +} + +TEST(format_test, format_to) { + std::string s; + fmt::format_to(std::back_inserter(s), "part{0}", 1); + EXPECT_EQ("part1", s); + fmt::format_to(std::back_inserter(s), "part{0}", 2); + EXPECT_EQ("part1part2", s); +} + +TEST(format_test, format_to_memory_buffer) { + auto buf = fmt::basic_memory_buffer<char, 100>(); + fmt::format_to(fmt::appender(buf), "{}", "foo"); + EXPECT_EQ("foo", to_string(buf)); +} + +TEST(format_test, format_to_vector) { std::vector<char> v; fmt::format_to(std::back_inserter(v), "{}", "foo"); EXPECT_EQ(string_view(v.data(), v.size()), "foo"); } -TEST(FormatTest, FormatToN) { +struct nongrowing_container { + using value_type = char; + void push_back(char) { throw std::runtime_error("can't take it any more"); } +}; + +TEST(format_test, format_to_propagates_exceptions) { + auto c = nongrowing_container(); + EXPECT_THROW(fmt::format_to(std::back_inserter(c), "{}", 42), + std::runtime_error); +} + +TEST(format_test, format_to_n) { char buffer[4]; buffer[3] = 'x'; auto result = fmt::format_to_n(buffer, 3, "{}", 12345); @@ -1974,26 +1962,6 @@ TEST(FormatTest, FormatToN) { EXPECT_EQ("***x", fmt::string_view(buffer, 4)); } -TEST(FormatTest, WideFormatToN) { - wchar_t buffer[4]; - buffer[3] = L'x'; - auto result = fmt::format_to_n(buffer, 3, L"{}", 12345); - EXPECT_EQ(5u, result.size); - EXPECT_EQ(buffer + 3, result.out); - EXPECT_EQ(L"123x", fmt::wstring_view(buffer, 4)); - buffer[0] = L'x'; - buffer[1] = L'x'; - buffer[2] = L'x'; - result = fmt::format_to_n(buffer, 3, L"{}", L'A'); - EXPECT_EQ(1u, result.size); - EXPECT_EQ(buffer + 1, result.out); - EXPECT_EQ(L"Axxx", fmt::wstring_view(buffer, 4)); - result = fmt::format_to_n(buffer, 3, L"{}{} ", L'B', L'C'); - EXPECT_EQ(3u, result.size); - EXPECT_EQ(buffer + 3, result.out); - EXPECT_EQ(L"BC x", fmt::wstring_view(buffer, 4)); -} - struct test_output_iterator { char* data; @@ -2015,269 +1983,13 @@ struct test_output_iterator { char& operator*() { return *data; } }; -TEST(FormatTest, FormatToNOutputIterator) { +TEST(format_test, format_to_n_output_iterator) { char buf[10] = {}; fmt::format_to_n(test_output_iterator{buf}, 10, "{}", 42); EXPECT_STREQ(buf, "42"); } #if FMT_USE_CONSTEXPR -struct test_arg_id_handler { - enum result { NONE, EMPTY, INDEX, NAME, ERROR }; - result res = NONE; - int index = 0; - string_view name; - - FMT_CONSTEXPR void operator()() { res = EMPTY; } - - FMT_CONSTEXPR void operator()(int i) { - res = INDEX; - index = i; - } - - FMT_CONSTEXPR void operator()(string_view n) { - res = NAME; - name = n; - } - - FMT_CONSTEXPR void on_error(const char*) { res = ERROR; } -}; - -template <size_t N> -FMT_CONSTEXPR test_arg_id_handler parse_arg_id(const char (&s)[N]) { - test_arg_id_handler h; - fmt::detail::parse_arg_id(s, s + N, h); - return h; -} - -TEST(FormatTest, ConstexprParseArgID) { - static_assert(parse_arg_id(":").res == test_arg_id_handler::EMPTY, ""); - static_assert(parse_arg_id("}").res == test_arg_id_handler::EMPTY, ""); - static_assert(parse_arg_id("42:").res == test_arg_id_handler::INDEX, ""); - static_assert(parse_arg_id("42:").index == 42, ""); - static_assert(parse_arg_id("foo:").res == test_arg_id_handler::NAME, ""); - static_assert(parse_arg_id("foo:").name.size() == 3, ""); - static_assert(parse_arg_id("!").res == test_arg_id_handler::ERROR, ""); -} - -struct test_format_specs_handler { - enum Result { NONE, PLUS, MINUS, SPACE, HASH, ZERO, ERROR }; - Result res = NONE; - - fmt::align_t align = fmt::align::none; - char fill = 0; - int width = 0; - fmt::detail::arg_ref<char> width_ref; - int precision = 0; - fmt::detail::arg_ref<char> precision_ref; - char type = 0; - - // Workaround for MSVC2017 bug that results in "expression did not evaluate - // to a constant" with compiler-generated copy ctor. - FMT_CONSTEXPR test_format_specs_handler() {} - FMT_CONSTEXPR test_format_specs_handler( - const test_format_specs_handler& other) - : res(other.res), - align(other.align), - fill(other.fill), - width(other.width), - width_ref(other.width_ref), - precision(other.precision), - precision_ref(other.precision_ref), - type(other.type) {} - - FMT_CONSTEXPR void on_align(fmt::align_t a) { align = a; } - FMT_CONSTEXPR void on_fill(fmt::string_view f) { fill = f[0]; } - FMT_CONSTEXPR void on_plus() { res = PLUS; } - FMT_CONSTEXPR void on_minus() { res = MINUS; } - FMT_CONSTEXPR void on_space() { res = SPACE; } - FMT_CONSTEXPR void on_hash() { res = HASH; } - FMT_CONSTEXPR void on_zero() { res = ZERO; } - - FMT_CONSTEXPR void on_width(int w) { width = w; } - FMT_CONSTEXPR void on_dynamic_width(fmt::detail::auto_id) {} - FMT_CONSTEXPR void on_dynamic_width(int index) { width_ref = index; } - FMT_CONSTEXPR void on_dynamic_width(string_view) {} - - FMT_CONSTEXPR void on_precision(int p) { precision = p; } - FMT_CONSTEXPR void on_dynamic_precision(fmt::detail::auto_id) {} - FMT_CONSTEXPR void on_dynamic_precision(int index) { precision_ref = index; } - FMT_CONSTEXPR void on_dynamic_precision(string_view) {} - - FMT_CONSTEXPR void end_precision() {} - FMT_CONSTEXPR void on_type(char t) { type = t; } - FMT_CONSTEXPR void on_error(const char*) { res = ERROR; } -}; - -template <size_t N> -FMT_CONSTEXPR test_format_specs_handler parse_test_specs(const char (&s)[N]) { - test_format_specs_handler h; - fmt::detail::parse_format_specs(s, s + N, h); - return h; -} - -TEST(FormatTest, ConstexprParseFormatSpecs) { - typedef test_format_specs_handler handler; - static_assert(parse_test_specs("<").align == fmt::align::left, ""); - static_assert(parse_test_specs("*^").fill == '*', ""); - static_assert(parse_test_specs("+").res == handler::PLUS, ""); - static_assert(parse_test_specs("-").res == handler::MINUS, ""); - static_assert(parse_test_specs(" ").res == handler::SPACE, ""); - static_assert(parse_test_specs("#").res == handler::HASH, ""); - static_assert(parse_test_specs("0").res == handler::ZERO, ""); - static_assert(parse_test_specs("42").width == 42, ""); - static_assert(parse_test_specs("{42}").width_ref.val.index == 42, ""); - static_assert(parse_test_specs(".42").precision == 42, ""); - static_assert(parse_test_specs(".{42}").precision_ref.val.index == 42, ""); - static_assert(parse_test_specs("d").type == 'd', ""); - static_assert(parse_test_specs("{<").res == handler::ERROR, ""); -} - -struct test_parse_context { - typedef char char_type; - - FMT_CONSTEXPR int next_arg_id() { return 11; } - template <typename Id> FMT_CONSTEXPR void check_arg_id(Id) {} - - FMT_CONSTEXPR const char* begin() { return nullptr; } - FMT_CONSTEXPR const char* end() { return nullptr; } - - void on_error(const char*) {} -}; - -struct test_context { - using char_type = char; - using format_arg = fmt::basic_format_arg<test_context>; - using parse_context_type = fmt::format_parse_context; - - template <typename T> struct formatter_type { - typedef fmt::formatter<T, char_type> type; - }; - - template <typename Id> - FMT_CONSTEXPR fmt::basic_format_arg<test_context> arg(Id id) { - return fmt::detail::make_arg<test_context>(id); - } - - void on_error(const char*) {} - - FMT_CONSTEXPR test_context error_handler() { return *this; } -}; - -template <size_t N> -FMT_CONSTEXPR fmt::format_specs parse_specs(const char (&s)[N]) { - auto specs = fmt::format_specs(); - auto parse_ctx = test_parse_context(); - auto ctx = test_context(); - fmt::detail::specs_handler<test_parse_context, test_context> h( - specs, parse_ctx, ctx); - parse_format_specs(s, s + N, h); - return specs; -} - -TEST(FormatTest, ConstexprSpecsHandler) { - static_assert(parse_specs("<").align == fmt::align::left, ""); - static_assert(parse_specs("*^").fill[0] == '*', ""); - static_assert(parse_specs("+").sign == fmt::sign::plus, ""); - static_assert(parse_specs("-").sign == fmt::sign::minus, ""); - static_assert(parse_specs(" ").sign == fmt::sign::space, ""); - static_assert(parse_specs("#").alt, ""); - static_assert(parse_specs("0").align == fmt::align::numeric, ""); - static_assert(parse_specs("42").width == 42, ""); - static_assert(parse_specs("{}").width == 11, ""); - static_assert(parse_specs("{22}").width == 22, ""); - static_assert(parse_specs(".42").precision == 42, ""); - static_assert(parse_specs(".{}").precision == 11, ""); - static_assert(parse_specs(".{22}").precision == 22, ""); - static_assert(parse_specs("d").type == 'd', ""); -} - -template <size_t N> -FMT_CONSTEXPR fmt::detail::dynamic_format_specs<char> parse_dynamic_specs( - const char (&s)[N]) { - fmt::detail::dynamic_format_specs<char> specs; - test_parse_context ctx{}; - fmt::detail::dynamic_specs_handler<test_parse_context> h(specs, ctx); - parse_format_specs(s, s + N, h); - return specs; -} - -TEST(FormatTest, ConstexprDynamicSpecsHandler) { - static_assert(parse_dynamic_specs("<").align == fmt::align::left, ""); - static_assert(parse_dynamic_specs("*^").fill[0] == '*', ""); - static_assert(parse_dynamic_specs("+").sign == fmt::sign::plus, ""); - static_assert(parse_dynamic_specs("-").sign == fmt::sign::minus, ""); - static_assert(parse_dynamic_specs(" ").sign == fmt::sign::space, ""); - static_assert(parse_dynamic_specs("#").alt, ""); - static_assert(parse_dynamic_specs("0").align == fmt::align::numeric, ""); - static_assert(parse_dynamic_specs("42").width == 42, ""); - static_assert(parse_dynamic_specs("{}").width_ref.val.index == 11, ""); - static_assert(parse_dynamic_specs("{42}").width_ref.val.index == 42, ""); - static_assert(parse_dynamic_specs(".42").precision == 42, ""); - static_assert(parse_dynamic_specs(".{}").precision_ref.val.index == 11, ""); - static_assert(parse_dynamic_specs(".{42}").precision_ref.val.index == 42, ""); - static_assert(parse_dynamic_specs("d").type == 'd', ""); -} - -template <size_t N> -FMT_CONSTEXPR test_format_specs_handler check_specs(const char (&s)[N]) { - fmt::detail::specs_checker<test_format_specs_handler> checker( - test_format_specs_handler(), fmt::detail::type::double_type); - parse_format_specs(s, s + N, checker); - return checker; -} - -TEST(FormatTest, ConstexprSpecsChecker) { - typedef test_format_specs_handler handler; - static_assert(check_specs("<").align == fmt::align::left, ""); - static_assert(check_specs("*^").fill == '*', ""); - static_assert(check_specs("+").res == handler::PLUS, ""); - static_assert(check_specs("-").res == handler::MINUS, ""); - static_assert(check_specs(" ").res == handler::SPACE, ""); - static_assert(check_specs("#").res == handler::HASH, ""); - static_assert(check_specs("0").res == handler::ZERO, ""); - static_assert(check_specs("42").width == 42, ""); - static_assert(check_specs("{42}").width_ref.val.index == 42, ""); - static_assert(check_specs(".42").precision == 42, ""); - static_assert(check_specs(".{42}").precision_ref.val.index == 42, ""); - static_assert(check_specs("d").type == 'd', ""); - static_assert(check_specs("{<").res == handler::ERROR, ""); -} - -struct test_format_string_handler { - FMT_CONSTEXPR void on_text(const char*, const char*) {} - - FMT_CONSTEXPR int on_arg_id() { return 0; } - - template <typename T> FMT_CONSTEXPR int on_arg_id(T) { return 0; } - - FMT_CONSTEXPR void on_replacement_field(int, const char*) {} - - FMT_CONSTEXPR const char* on_format_specs(int, const char* begin, - const char*) { - return begin; - } - - FMT_CONSTEXPR void on_error(const char*) { error = true; } - - bool error = false; -}; - -template <size_t N> FMT_CONSTEXPR bool parse_string(const char (&s)[N]) { - test_format_string_handler h; - fmt::detail::parse_format_string<true>(fmt::string_view(s, N - 1), h); - return !h.error; -} - -TEST(FormatTest, ConstexprParseFormatString) { - static_assert(parse_string("foo"), ""); - static_assert(!parse_string("}"), ""); - static_assert(parse_string("{}"), ""); - static_assert(parse_string("{42}"), ""); - static_assert(parse_string("{foo}"), ""); - static_assert(parse_string("{:}"), ""); -} - struct test_error_handler { const char*& error; @@ -2309,9 +2021,10 @@ FMT_CONSTEXPR bool equal(const char* s1, const char* s2) { template <typename... Args> FMT_CONSTEXPR bool test_error(const char* fmt, const char* expected_error) { const char* actual_error = nullptr; - string_view s(fmt, len(fmt)); - fmt::detail::format_string_checker<char, test_error_handler, Args...> checker( - s, test_error_handler(actual_error)); + auto s = string_view(fmt, len(fmt)); + auto checker = + fmt::detail::format_string_checker<char, test_error_handler, Args...>( + s, test_error_handler(actual_error)); fmt::detail::parse_format_string<true>(s, checker); return equal(actual_error, expected_error); } @@ -2321,21 +2034,16 @@ FMT_CONSTEXPR bool test_error(const char* fmt, const char* expected_error) { # define EXPECT_ERROR(fmt, error, ...) \ static_assert(test_error<__VA_ARGS__>(fmt, error), "") -TEST(FormatTest, FormatStringErrors) { +TEST(format_test, format_string_errors) { EXPECT_ERROR_NOARGS("foo", nullptr); EXPECT_ERROR_NOARGS("}", "unmatched '}' in format string"); - EXPECT_ERROR("{0:s", "unknown format specifier", Date); + EXPECT_ERROR("{0:s", "unknown format specifier", date); # if !FMT_MSC_VER || FMT_MSC_VER >= 1916 // This causes an detail compiler error in MSVC2017. EXPECT_ERROR("{:{<}", "invalid fill character '{'", int); EXPECT_ERROR("{:10000000000}", "number is too big", int); EXPECT_ERROR("{:.10000000000}", "number is too big", int); EXPECT_ERROR_NOARGS("{:x}", "argument not found"); -# if FMT_DEPRECATED_NUMERIC_ALIGN - EXPECT_ERROR("{0:=5", "unknown format specifier", int); - EXPECT_ERROR("{:=}", "format specifier requires numeric argument", - const char*); -# endif EXPECT_ERROR("{:+}", "format specifier requires numeric argument", const char*); EXPECT_ERROR("{:-}", "format specifier requires numeric argument", @@ -2353,7 +2061,6 @@ TEST(FormatTest, FormatStringErrors) { EXPECT_ERROR("{:.{}}", "argument not found", double); EXPECT_ERROR("{:.2}", "precision not allowed for this argument type", int); EXPECT_ERROR("{:s}", "invalid type specifier", int); - EXPECT_ERROR("{:s}", "invalid type specifier", bool); EXPECT_ERROR("{:s}", "invalid type specifier", char); EXPECT_ERROR("{:+}", "invalid format specifier for char", char); EXPECT_ERROR("{:s}", "invalid type specifier", double); @@ -2363,9 +2070,16 @@ TEST(FormatTest, FormatStringErrors) { # else fmt::print("warning: constexpr is broken in this version of MSVC\n"); # endif - EXPECT_ERROR("{foo", "compile-time checks don't support named arguments", +# if FMT_USE_NONTYPE_TEMPLATE_PARAMETERS + EXPECT_ERROR("{foo}", "named argument is not found", decltype("bar"_a = 42)); + EXPECT_ERROR("{foo}", "named argument is not found", + decltype(fmt::arg("foo", 42))); +# else + EXPECT_ERROR("{foo}", + "compile-time checks for named arguments require C++20 support", int); - EXPECT_ERROR_NOARGS("{10000000000}", "number is too big"); +# endif + EXPECT_ERROR_NOARGS("{10000000000}", "argument not found"); EXPECT_ERROR_NOARGS("{0x}", "invalid format string"); EXPECT_ERROR_NOARGS("{-}", "invalid format string"); EXPECT_ERROR("{:{0x}}", "invalid format string", int); @@ -2383,99 +2097,37 @@ TEST(FormatTest, FormatStringErrors) { int); } -TEST(FormatTest, VFormatTo) { - typedef fmt::format_context context; +TEST(format_test, vformat_to) { + using context = fmt::format_context; fmt::basic_format_arg<context> arg = fmt::detail::make_arg<context>(42); - fmt::basic_format_args<context> args(&arg, 1); - std::string s; + auto args = fmt::basic_format_args<context>(&arg, 1); + auto s = std::string(); fmt::vformat_to(std::back_inserter(s), "{}", args); EXPECT_EQ("42", s); s.clear(); fmt::vformat_to(std::back_inserter(s), FMT_STRING("{}"), args); EXPECT_EQ("42", s); - - typedef fmt::wformat_context wcontext; - fmt::basic_format_arg<wcontext> warg = fmt::detail::make_arg<wcontext>(42); - fmt::basic_format_args<wcontext> wargs(&warg, 1); - std::wstring w; - fmt::vformat_to(std::back_inserter(w), L"{}", wargs); - EXPECT_EQ(L"42", w); - w.clear(); - fmt::vformat_to(std::back_inserter(w), FMT_STRING(L"{}"), wargs); - EXPECT_EQ(L"42", w); -} - -template <typename T> static std::string FmtToString(const T& t) { - return fmt::format(FMT_STRING("{}"), t); -} - -TEST(FormatTest, FmtStringInTemplate) { - EXPECT_EQ(FmtToString(1), "1"); - EXPECT_EQ(FmtToString(0), "0"); } #endif // FMT_USE_CONSTEXPR -TEST(FormatTest, CharTraitsIsNotAmbiguous) { +TEST(format_test, char_traits_is_not_ambiguous) { // Test that we don't inject detail names into the std namespace. using namespace std; - char_traits<char>::char_type c; + auto c = char_traits<char>::char_type(); (void)c; #if __cplusplus >= 201103L - std::string s; + auto s = std::string(); auto lval = begin(s); (void)lval; #endif } -#if __cplusplus > 201103L -struct custom_char { - int value; - custom_char() = default; - - template <typename T> - constexpr custom_char(T val) : value(static_cast<int>(val)) {} - - operator int() const { return value; } -}; - -int to_ascii(custom_char c) { return c; } - -FMT_BEGIN_NAMESPACE -template <> struct is_char<custom_char> : std::true_type {}; -FMT_END_NAMESPACE - -TEST(FormatTest, FormatCustomChar) { - const custom_char format[] = {'{', '}', 0}; - auto result = fmt::format(format, custom_char('x')); - EXPECT_EQ(result.size(), 1); - EXPECT_EQ(result[0], custom_char('x')); -} -#endif - -// Convert a char8_t string to std::string. Otherwise GTest will insist on -// inserting `char8_t` NTBS into a `char` stream which is disabled by P1423. -template <typename S> std::string from_u8str(const S& str) { - return std::string(str.begin(), str.end()); -} - -TEST(FormatTest, FormatUTF8Precision) { - using str_type = std::basic_string<fmt::detail::char8_type>; - str_type format(reinterpret_cast<const fmt::detail::char8_type*>(u8"{:.4}")); - str_type str(reinterpret_cast<const fmt::detail::char8_type*>( - u8"caf\u00e9s")); // cafés - auto result = fmt::format(format, str); - EXPECT_EQ(fmt::detail::count_code_points(result), 4); - EXPECT_EQ(result.size(), 5); - EXPECT_EQ(from_u8str(result), from_u8str(str.substr(0, 5))); -} - struct check_back_appender {}; FMT_BEGIN_NAMESPACE template <> struct formatter<check_back_appender> { - template <typename ParseContext> - auto parse(ParseContext& ctx) -> decltype(ctx.begin()) { + auto parse(format_parse_context& ctx) -> decltype(ctx.begin()) { return ctx.begin(); } @@ -2490,6 +2142,49 @@ template <> struct formatter<check_back_appender> { }; FMT_END_NAMESPACE -TEST(FormatTest, BackInsertSlicing) { +TEST(format_test, back_insert_slicing) { EXPECT_EQ(fmt::format("{}", check_back_appender{}), "y"); } + +template <typename Char, typename T> bool check_enabled_formatter() { + static_assert(std::is_default_constructible<fmt::formatter<T, Char>>::value, + ""); + return true; +} + +template <typename Char, typename... T> void check_enabled_formatters() { + auto dummy = {check_enabled_formatter<Char, T>()...}; + (void)dummy; +} + +TEST(format_test, test_formatters_enabled) { + check_enabled_formatters<char, bool, char, signed char, unsigned char, short, + unsigned short, int, unsigned, long, unsigned long, + long long, unsigned long long, float, double, + long double, void*, const void*, char*, const char*, + std::string, std::nullptr_t>(); + check_enabled_formatters<wchar_t, bool, wchar_t, signed char, unsigned char, + short, unsigned short, int, unsigned, long, + unsigned long, long long, unsigned long long, float, + double, long double, void*, const void*, wchar_t*, + const wchar_t*, std::wstring, std::nullptr_t>(); +} + +TEST(format_int_test, data) { + fmt::format_int format_int(42); + EXPECT_EQ("42", std::string(format_int.data(), format_int.size())); +} + +TEST(format_int_test, format_int) { + EXPECT_EQ("42", fmt::format_int(42).str()); + EXPECT_EQ(2u, fmt::format_int(42).size()); + EXPECT_EQ("-42", fmt::format_int(-42).str()); + EXPECT_EQ(3u, fmt::format_int(-42).size()); + EXPECT_EQ("42", fmt::format_int(42ul).str()); + EXPECT_EQ("-42", fmt::format_int(-42l).str()); + EXPECT_EQ("42", fmt::format_int(42ull).str()); + EXPECT_EQ("-42", fmt::format_int(-42ll).str()); + std::ostringstream os; + os << max_value<int64_t>(); + EXPECT_EQ(os.str(), fmt::format_int(max_value<int64_t>()).str()); +} diff --git a/contrib/libs/fmt/test/gtest-extra-test.cc b/contrib/libs/fmt/test/gtest-extra-test.cc index ea728607e8..0d86206c93 100644 --- a/contrib/libs/fmt/test/gtest-extra-test.cc +++ b/contrib/libs/fmt/test/gtest-extra-test.cc @@ -9,31 +9,18 @@ #include <gtest/gtest-spi.h> -#include <algorithm> #include <cstring> #include <memory> #include <stdexcept> -#if defined(_WIN32) && !defined(__MINGW32__) -# include <crtdbg.h> // for _CrtSetReportMode -#endif // _WIN32 - +#include "fmt/os.h" #include "util.h" -namespace { - -// This is used to suppress coverity warnings about untrusted values. -std::string sanitize(const std::string& s) { - std::string result; - for (std::string::const_iterator i = s.begin(), end = s.end(); i != end; ++i) - result.push_back(static_cast<char>(*i & 0xff)); - return result; -} - // Tests that assertion macros evaluate their arguments exactly once. -class SingleEvaluationTest : public ::testing::Test { +namespace { +class single_evaluation_test : public ::testing::Test { protected: - SingleEvaluationTest() { + single_evaluation_test() { p_ = s_; a_ = 0; b_ = 0; @@ -45,11 +32,12 @@ class SingleEvaluationTest : public ::testing::Test { static int a_; static int b_; }; +} // namespace -const char* const SingleEvaluationTest::s_ = "01234"; -const char* SingleEvaluationTest::p_; -int SingleEvaluationTest::a_; -int SingleEvaluationTest::b_; +const char* const single_evaluation_test::s_ = "01234"; +const char* single_evaluation_test::p_; +int single_evaluation_test::a_; +int single_evaluation_test::b_; void do_nothing() {} @@ -61,7 +49,7 @@ FMT_NORETURN void throw_system_error() { // Tests that when EXPECT_THROW_MSG fails, it evaluates its message argument // exactly once. -TEST_F(SingleEvaluationTest, FailedEXPECT_THROW_MSG) { +TEST_F(single_evaluation_test, failed_expect_throw_msg) { EXPECT_NONFATAL_FAILURE( EXPECT_THROW_MSG(throw_exception(), std::exception, p_++), "01234"); EXPECT_EQ(s_ + 1, p_); @@ -69,14 +57,14 @@ TEST_F(SingleEvaluationTest, FailedEXPECT_THROW_MSG) { // Tests that when EXPECT_SYSTEM_ERROR fails, it evaluates its message argument // exactly once. -TEST_F(SingleEvaluationTest, FailedEXPECT_SYSTEM_ERROR) { +TEST_F(single_evaluation_test, failed_expect_system_error) { EXPECT_NONFATAL_FAILURE(EXPECT_SYSTEM_ERROR(throw_system_error(), EDOM, p_++), "01234"); EXPECT_EQ(s_ + 1, p_); } // Tests that assertion arguments are evaluated exactly once. -TEST_F(SingleEvaluationTest, ExceptionTests) { +TEST_F(single_evaluation_test, exception_tests) { // successful EXPECT_THROW_MSG EXPECT_THROW_MSG( { // NOLINT @@ -116,7 +104,7 @@ TEST_F(SingleEvaluationTest, ExceptionTests) { EXPECT_EQ(4, b_); } -TEST_F(SingleEvaluationTest, SystemErrorTests) { +TEST_F(single_evaluation_test, system_error_tests) { // successful EXPECT_SYSTEM_ERROR EXPECT_SYSTEM_ERROR( { // NOLINT @@ -159,14 +147,14 @@ TEST_F(SingleEvaluationTest, SystemErrorTests) { #if FMT_USE_FCNTL // Tests that when EXPECT_WRITE fails, it evaluates its message argument // exactly once. -TEST_F(SingleEvaluationTest, FailedEXPECT_WRITE) { +TEST_F(single_evaluation_test, failed_expect_write) { EXPECT_NONFATAL_FAILURE(EXPECT_WRITE(stdout, std::printf("test"), p_++), "01234"); EXPECT_EQ(s_ + 1, p_); } // Tests that assertion arguments are evaluated exactly once. -TEST_F(SingleEvaluationTest, WriteTests) { +TEST_F(single_evaluation_test, write_tests) { // successful EXPECT_WRITE EXPECT_WRITE( stdout, @@ -192,7 +180,7 @@ TEST_F(SingleEvaluationTest, WriteTests) { } // Tests EXPECT_WRITE. -TEST(ExpectTest, EXPECT_WRITE) { +TEST(gtest_extra_test, expect_write) { EXPECT_WRITE(stdout, do_nothing(), ""); EXPECT_WRITE(stdout, std::printf("test"), "test"); EXPECT_WRITE(stderr, std::fprintf(stderr, "test"), "test"); @@ -201,7 +189,7 @@ TEST(ExpectTest, EXPECT_WRITE) { " Actual: that"); } -TEST(StreamingAssertionsTest, EXPECT_WRITE) { +TEST(gtest_extra_test, expect_write_streaming) { EXPECT_WRITE(stdout, std::printf("test"), "test") << "unexpected failure"; EXPECT_NONFATAL_FAILURE(EXPECT_WRITE(stdout, std::printf("test"), "other") << "expected failure", @@ -211,7 +199,7 @@ TEST(StreamingAssertionsTest, EXPECT_WRITE) { // Tests that the compiler will not complain about unreachable code in the // EXPECT_THROW_MSG macro. -TEST(ExpectThrowTest, DoesNotGenerateUnreachableCodeWarning) { +TEST(gtest_extra_test, expect_throw_no_unreachable_code_warning) { int n = 0; using std::runtime_error; EXPECT_THROW_MSG(throw runtime_error(""), runtime_error, ""); @@ -223,7 +211,7 @@ TEST(ExpectThrowTest, DoesNotGenerateUnreachableCodeWarning) { // Tests that the compiler will not complain about unreachable code in the // EXPECT_SYSTEM_ERROR macro. -TEST(ExpectSystemErrorTest, DoesNotGenerateUnreachableCodeWarning) { +TEST(gtest_extra_test, expect_system_error_no_unreachable_code_warning) { int n = 0; EXPECT_SYSTEM_ERROR(throw fmt::system_error(EDOM, "test"), EDOM, "test"); EXPECT_NONFATAL_FAILURE(EXPECT_SYSTEM_ERROR(n++, EDOM, ""), ""); @@ -233,7 +221,7 @@ TEST(ExpectSystemErrorTest, DoesNotGenerateUnreachableCodeWarning) { ""); } -TEST(AssertionSyntaxTest, ExceptionAssertionBehavesLikeSingleStatement) { +TEST(gtest_extra_test, expect_throw_behaves_like_single_statement) { if (::testing::internal::AlwaysFalse()) EXPECT_THROW_MSG(do_nothing(), std::exception, ""); @@ -243,7 +231,7 @@ TEST(AssertionSyntaxTest, ExceptionAssertionBehavesLikeSingleStatement) { do_nothing(); } -TEST(AssertionSyntaxTest, SystemErrorAssertionBehavesLikeSingleStatement) { +TEST(gtest_extra_test, expect_system_error_behaves_like_single_statement) { if (::testing::internal::AlwaysFalse()) EXPECT_SYSTEM_ERROR(do_nothing(), EDOM, ""); @@ -253,7 +241,7 @@ TEST(AssertionSyntaxTest, SystemErrorAssertionBehavesLikeSingleStatement) { do_nothing(); } -TEST(AssertionSyntaxTest, WriteAssertionBehavesLikeSingleStatement) { +TEST(gtest_extra_test, expect_write_behaves_like_single_statement) { if (::testing::internal::AlwaysFalse()) EXPECT_WRITE(stdout, std::printf("x"), "x"); @@ -264,7 +252,7 @@ TEST(AssertionSyntaxTest, WriteAssertionBehavesLikeSingleStatement) { } // Tests EXPECT_THROW_MSG. -TEST(ExpectTest, EXPECT_THROW_MSG) { +TEST(gtest_extra_test, expect_throw_msg) { EXPECT_THROW_MSG(throw_exception(), std::exception, "test"); EXPECT_NONFATAL_FAILURE( EXPECT_THROW_MSG(throw_exception(), std::logic_error, "test"), @@ -282,15 +270,15 @@ TEST(ExpectTest, EXPECT_THROW_MSG) { } // Tests EXPECT_SYSTEM_ERROR. -TEST(ExpectTest, EXPECT_SYSTEM_ERROR) { +TEST(gtest_extra_test, expect_system_error) { EXPECT_SYSTEM_ERROR(throw_system_error(), EDOM, "test"); EXPECT_NONFATAL_FAILURE( EXPECT_SYSTEM_ERROR(throw_exception(), EDOM, "test"), "Expected: throw_exception() throws an exception of " - "type fmt::system_error.\n Actual: it throws a different type."); + "type std::system_error.\n Actual: it throws a different type."); EXPECT_NONFATAL_FAILURE( EXPECT_SYSTEM_ERROR(do_nothing(), EDOM, "test"), - "Expected: do_nothing() throws an exception of type fmt::system_error.\n" + "Expected: do_nothing() throws an exception of type std::system_error.\n" " Actual: it throws nothing."); EXPECT_NONFATAL_FAILURE( EXPECT_SYSTEM_ERROR(throw_system_error(), EDOM, "other"), @@ -298,11 +286,11 @@ TEST(ExpectTest, EXPECT_SYSTEM_ERROR) { "throw_system_error() throws an exception with a different message.\n" "Expected: {}\n" " Actual: {}", - format_system_error(EDOM, "other"), - format_system_error(EDOM, "test"))); + system_error_message(EDOM, "other"), + system_error_message(EDOM, "test"))); } -TEST(StreamingAssertionsTest, EXPECT_THROW_MSG) { +TEST(gtest_extra_test, expect_throw_msg_streaming) { EXPECT_THROW_MSG(throw_exception(), std::exception, "test") << "unexpected failure"; EXPECT_NONFATAL_FAILURE( @@ -311,7 +299,7 @@ TEST(StreamingAssertionsTest, EXPECT_THROW_MSG) { "expected failure"); } -TEST(StreamingAssertionsTest, EXPECT_SYSTEM_ERROR) { +TEST(gtest_extra_test, expect_system_error_streaming) { EXPECT_SYSTEM_ERROR(throw_system_error(), EDOM, "test") << "unexpected failure"; EXPECT_NONFATAL_FAILURE( @@ -320,31 +308,19 @@ TEST(StreamingAssertionsTest, EXPECT_SYSTEM_ERROR) { "expected failure"); } -TEST(UtilTest, FormatSystemError) { - fmt::memory_buffer out; - fmt::format_system_error(out, EDOM, "test message"); - EXPECT_EQ(to_string(out), format_system_error(EDOM, "test message")); -} - #if FMT_USE_FCNTL using fmt::buffered_file; -using fmt::error_code; using fmt::file; -TEST(ErrorCodeTest, Ctor) { - EXPECT_EQ(error_code().get(), 0); - EXPECT_EQ(error_code(42).get(), 42); -} - -TEST(OutputRedirectTest, ScopedRedirect) { +TEST(output_redirect_test, scoped_redirect) { file read_end, write_end; file::pipe(read_end, write_end); { buffered_file file(write_end.fdopen("w")); std::fprintf(file.get(), "[[["); { - OutputRedirect redir(file.get()); + output_redirect redir(file.get()); std::fprintf(file.get(), "censored"); } std::fprintf(file.get(), "]]]"); @@ -352,8 +328,8 @@ TEST(OutputRedirectTest, ScopedRedirect) { EXPECT_READ(read_end, "[[[]]]"); } -// Test that OutputRedirect handles errors in flush correctly. -TEST(OutputRedirectTest, FlushErrorInCtor) { +// Test that output_redirect handles errors in flush correctly. +TEST(output_redirect_test, flush_error_in_ctor) { file read_end, write_end; file::pipe(read_end, write_end); int write_fd = write_end.descriptor(); @@ -362,47 +338,47 @@ TEST(OutputRedirectTest, FlushErrorInCtor) { // Put a character in a file buffer. EXPECT_EQ('x', fputc('x', f.get())); FMT_POSIX(close(write_fd)); - std::unique_ptr<OutputRedirect> redir{nullptr}; - EXPECT_SYSTEM_ERROR_NOASSERT(redir.reset(new OutputRedirect(f.get())), EBADF, + std::unique_ptr<output_redirect> redir{nullptr}; + EXPECT_SYSTEM_ERROR_NOASSERT(redir.reset(new output_redirect(f.get())), EBADF, "cannot flush stream"); redir.reset(nullptr); write_copy.dup2(write_fd); // "undo" close or dtor will fail } -TEST(OutputRedirectTest, DupErrorInCtor) { +TEST(output_redirect_test, dup_error_in_ctor) { buffered_file f = open_buffered_file(); int fd = (f.fileno)(); file copy = file::dup(fd); FMT_POSIX(close(fd)); - std::unique_ptr<OutputRedirect> redir{nullptr}; + std::unique_ptr<output_redirect> redir{nullptr}; EXPECT_SYSTEM_ERROR_NOASSERT( - redir.reset(new OutputRedirect(f.get())), EBADF, + redir.reset(new output_redirect(f.get())), EBADF, fmt::format("cannot duplicate file descriptor {}", fd)); copy.dup2(fd); // "undo" close or dtor will fail } -TEST(OutputRedirectTest, RestoreAndRead) { +TEST(output_redirect_test, restore_and_read) { file read_end, write_end; file::pipe(read_end, write_end); buffered_file file(write_end.fdopen("w")); std::fprintf(file.get(), "[[["); - OutputRedirect redir(file.get()); + output_redirect redir(file.get()); std::fprintf(file.get(), "censored"); - EXPECT_EQ("censored", sanitize(redir.restore_and_read())); - EXPECT_EQ("", sanitize(redir.restore_and_read())); + EXPECT_EQ("censored", redir.restore_and_read()); + EXPECT_EQ("", redir.restore_and_read()); std::fprintf(file.get(), "]]]"); file = buffered_file(); EXPECT_READ(read_end, "[[[]]]"); } // Test that OutputRedirect handles errors in flush correctly. -TEST(OutputRedirectTest, FlushErrorInRestoreAndRead) { +TEST(output_redirect_test, flush_error_in_restore_and_read) { file read_end, write_end; file::pipe(read_end, write_end); int write_fd = write_end.descriptor(); file write_copy = write_end.dup(write_fd); buffered_file f = write_end.fdopen("w"); - OutputRedirect redir(f.get()); + output_redirect redir(f.get()); // Put a character in a file buffer. EXPECT_EQ('x', fputc('x', f.get())); FMT_POSIX(close(write_fd)); @@ -411,13 +387,13 @@ TEST(OutputRedirectTest, FlushErrorInRestoreAndRead) { write_copy.dup2(write_fd); // "undo" close or dtor will fail } -TEST(OutputRedirectTest, ErrorInDtor) { +TEST(output_redirect_test, error_in_dtor) { file read_end, write_end; file::pipe(read_end, write_end); int write_fd = write_end.descriptor(); file write_copy = write_end.dup(write_fd); buffered_file f = write_end.fdopen("w"); - std::unique_ptr<OutputRedirect> redir(new OutputRedirect(f.get())); + std::unique_ptr<output_redirect> redir(new output_redirect(f.get())); // Put a character in a file buffer. EXPECT_EQ('x', fputc('x', f.get())); EXPECT_WRITE( @@ -430,10 +406,8 @@ TEST(OutputRedirectTest, ErrorInDtor) { FMT_POSIX(close(write_fd)); SUPPRESS_ASSERT(redir.reset(nullptr)); }, - format_system_error(EBADF, "cannot flush stream")); + system_error_message(EBADF, "cannot flush stream")); write_copy.dup2(write_fd); // "undo" close or dtor of buffered_file will fail } -#endif // FMT_USE_FILE_DESCRIPTORS - -} // namespace +#endif // FMT_USE_FCNTL diff --git a/contrib/libs/fmt/test/gtest-extra.cc b/contrib/libs/fmt/test/gtest-extra.cc index 58628a8a98..1d48a1736d 100644 --- a/contrib/libs/fmt/test/gtest-extra.cc +++ b/contrib/libs/fmt/test/gtest-extra.cc @@ -11,24 +11,7 @@ using fmt::file; -void OutputRedirect::flush() { -# if EOF != -1 -# error "FMT_RETRY assumes return value of -1 indicating failure" -# endif - int result = 0; - FMT_RETRY(result, fflush(file_)); - if (result != 0) throw fmt::system_error(errno, "cannot flush stream"); -} - -void OutputRedirect::restore() { - if (original_.descriptor() == -1) return; // Already restored. - flush(); - // Restore the original file. - original_.dup2(FMT_POSIX(fileno(file_))); - original_.close(); -} - -OutputRedirect::OutputRedirect(FILE* f) : file_(f) { +output_redirect::output_redirect(FILE* f) : file_(f) { flush(); int fd = FMT_POSIX(fileno(f)); // Create a file object referring to the original file. @@ -40,7 +23,7 @@ OutputRedirect::OutputRedirect(FILE* f) : file_(f) { write_end.dup2(fd); } -OutputRedirect::~OutputRedirect() FMT_NOEXCEPT { +output_redirect::~output_redirect() FMT_NOEXCEPT { try { restore(); } catch (const std::exception& e) { @@ -48,7 +31,23 @@ OutputRedirect::~OutputRedirect() FMT_NOEXCEPT { } } -std::string OutputRedirect::restore_and_read() { +void output_redirect::flush() { + int result = 0; + do { + result = fflush(file_); + } while (result == EOF && errno == EINTR); + if (result != 0) throw fmt::system_error(errno, "cannot flush stream"); +} + +void output_redirect::restore() { + if (original_.descriptor() == -1) return; // Already restored. + flush(); + // Restore the original file. + original_.dup2(FMT_POSIX(fileno(file_))); + original_.close(); +} + +std::string output_redirect::restore_and_read() { // Restore output. restore(); @@ -79,9 +78,3 @@ std::string read(file& f, size_t count) { } #endif // FMT_USE_FCNTL - -std::string format_system_error(int error_code, fmt::string_view message) { - fmt::memory_buffer out; - format_system_error(out, error_code, message); - return to_string(out); -} diff --git a/contrib/libs/fmt/test/gtest-extra.h b/contrib/libs/fmt/test/gtest-extra.h index 010bde066b..f779731748 100644 --- a/contrib/libs/fmt/test/gtest-extra.h +++ b/contrib/libs/fmt/test/gtest-extra.h @@ -8,10 +8,17 @@ #ifndef FMT_GTEST_EXTRA_H_ #define FMT_GTEST_EXTRA_H_ +#include <stdlib.h> // _invalid_parameter_handler + #include <string> -#include "fmt/os.h" -#include <gmock/gmock.h> +#ifdef FMT_MODULE_TEST +import fmt; +#else +# include "fmt/os.h" +#endif // FMG_MODULE_TEST + +#include "gmock/gmock.h" #define FMT_TEST_THROW_(statement, expected_exception, expected_message, fail) \ GTEST_AMBIGUOUS_ELSE_BLOCKER_ \ @@ -51,31 +58,35 @@ FMT_TEST_THROW_(statement, expected_exception, expected_message, \ GTEST_NONFATAL_FAILURE_) -std::string format_system_error(int error_code, fmt::string_view message); +inline std::string system_error_message(int error_code, + const std::string& message) { + auto ec = std::error_code(error_code, std::generic_category()); + return std::system_error(ec, message).what(); +} #define EXPECT_SYSTEM_ERROR(statement, error_code, message) \ - EXPECT_THROW_MSG(statement, fmt::system_error, \ - format_system_error(error_code, message)) + EXPECT_THROW_MSG(statement, std::system_error, \ + system_error_message(error_code, message)) #if FMT_USE_FCNTL // Captures file output by redirecting it to a pipe. // The output it can handle is limited by the pipe capacity. -class OutputRedirect { +class output_redirect { private: FILE* file_; fmt::file original_; // Original file passed to redirector. fmt::file read_end_; // Read end of the pipe where the output is redirected. - OutputRedirect(const OutputRedirect&) = delete; - OutputRedirect& operator= (const OutputRedirect&) = delete; - void flush(); void restore(); public: - explicit OutputRedirect(FILE* file); - ~OutputRedirect() FMT_NOEXCEPT; + explicit output_redirect(FILE* file); + ~output_redirect() FMT_NOEXCEPT; + + output_redirect(const output_redirect&) = delete; + void operator=(const output_redirect&) = delete; // Restores the original file, reads output from the pipe into a string // and returns it. @@ -86,7 +97,7 @@ class OutputRedirect { GTEST_AMBIGUOUS_ELSE_BLOCKER_ \ if (::testing::AssertionResult gtest_ar = ::testing::AssertionSuccess()) { \ std::string gtest_expected_output = expected_output; \ - OutputRedirect gtest_redir(file); \ + output_redirect gtest_redir(file); \ GTEST_SUPPRESS_UNREACHABLE_CODE_WARNING_BELOW_(statement); \ std::string gtest_output = gtest_redir.restore_and_read(); \ if (gtest_output != gtest_expected_output) { \ @@ -108,7 +119,7 @@ class OutputRedirect { // Suppresses Windows assertions on invalid file descriptors, making // POSIX functions return proper error codes instead of crashing on Windows. -class SuppressAssert { +class suppress_assert { private: _invalid_parameter_handler original_handler_; int original_report_mode_; @@ -117,19 +128,20 @@ class SuppressAssert { const wchar_t*, unsigned, uintptr_t) {} public: - SuppressAssert() + suppress_assert() : original_handler_( _set_invalid_parameter_handler(handle_invalid_parameter)), original_report_mode_(_CrtSetReportMode(_CRT_ASSERT, 0)) {} - ~SuppressAssert() { + ~suppress_assert() { _set_invalid_parameter_handler(original_handler_); _CrtSetReportMode(_CRT_ASSERT, original_report_mode_); + (void)original_report_mode_; } }; # define SUPPRESS_ASSERT(statement) \ { \ - SuppressAssert sa; \ + suppress_assert sa; \ statement; \ } # else @@ -143,7 +155,7 @@ class SuppressAssert { std::string read(fmt::file& f, size_t count); # define EXPECT_READ(file, expected_content) \ - EXPECT_EQ(expected_content, \ + EXPECT_EQ(expected_content, \ read(file, fmt::string_view(expected_content).size())) #else @@ -156,9 +168,4 @@ std::string read(fmt::file& f, size_t count); } while (false) #endif // FMT_USE_FCNTL -template <typename Mock> struct ScopedMock : testing::StrictMock<Mock> { - ScopedMock() { Mock::instance = this; } - ~ScopedMock() { Mock::instance = nullptr; } -}; - #endif // FMT_GTEST_EXTRA_H_ diff --git a/contrib/libs/fmt/test/header-only-test.cc b/contrib/libs/fmt/test/header-only-test.cc index 674dab993d..570f09a563 100644 --- a/contrib/libs/fmt/test/header-only-test.cc +++ b/contrib/libs/fmt/test/header-only-test.cc @@ -1,3 +1,11 @@ // Header-only configuration test #include "fmt/core.h" +#include "fmt/ostream.h" +#include "gtest/gtest.h" + +#ifndef FMT_HEADER_ONLY +# error "Not in the header-only mode." +#endif + +TEST(header_only_test, format) { EXPECT_EQ(fmt::format("foo"), "foo"); } diff --git a/contrib/libs/fmt/test/header-only-test2.cc b/contrib/libs/fmt/test/header-only-test2.cc deleted file mode 100644 index ea90b604e4..0000000000 --- a/contrib/libs/fmt/test/header-only-test2.cc +++ /dev/null @@ -1,3 +0,0 @@ -// Additional translation unit for the header-only configuration test - -#include "fmt/core.h" diff --git a/contrib/libs/fmt/test/locale-test.cc b/contrib/libs/fmt/test/locale-test.cc deleted file mode 100644 index 7d776b4290..0000000000 --- a/contrib/libs/fmt/test/locale-test.cc +++ /dev/null @@ -1,160 +0,0 @@ -// Formatting library for C++ - locale tests -// -// Copyright (c) 2012 - present, Victor Zverovich -// All rights reserved. -// -// For the license information refer to format.h. - -#include "fmt/locale.h" - -#include <complex> - -#include <gmock/gmock.h> - -using fmt::detail::max_value; - -#ifndef FMT_STATIC_THOUSANDS_SEPARATOR -template <typename Char> struct numpunct : std::numpunct<Char> { - protected: - Char do_decimal_point() const FMT_OVERRIDE { return '?'; } - std::string do_grouping() const FMT_OVERRIDE { return "\03"; } - Char do_thousands_sep() const FMT_OVERRIDE { return '~'; } -}; - -template <typename Char> struct no_grouping : std::numpunct<Char> { - protected: - Char do_decimal_point() const FMT_OVERRIDE { return '.'; } - std::string do_grouping() const FMT_OVERRIDE { return ""; } - Char do_thousands_sep() const FMT_OVERRIDE { return ','; } -}; - -template <typename Char> struct special_grouping : std::numpunct<Char> { - protected: - Char do_decimal_point() const FMT_OVERRIDE { return '.'; } - std::string do_grouping() const FMT_OVERRIDE { return "\03\02"; } - Char do_thousands_sep() const FMT_OVERRIDE { return ','; } -}; - -template <typename Char> struct small_grouping : std::numpunct<Char> { - protected: - Char do_decimal_point() const FMT_OVERRIDE { return '.'; } - std::string do_grouping() const FMT_OVERRIDE { return "\01"; } - Char do_thousands_sep() const FMT_OVERRIDE { return ','; } -}; - -TEST(LocaleTest, DoubleDecimalPoint) { - std::locale loc(std::locale(), new numpunct<char>()); - EXPECT_EQ("1?23", fmt::format(loc, "{:L}", 1.23)); -} - -TEST(LocaleTest, Format) { - std::locale loc(std::locale(), new numpunct<char>()); - EXPECT_EQ("1234567", fmt::format(std::locale(), "{:L}", 1234567)); - EXPECT_EQ("1~234~567", fmt::format(loc, "{:L}", 1234567)); - EXPECT_EQ("-1~234~567", fmt::format(loc, "{:L}", -1234567)); - EXPECT_EQ("-256", fmt::format(loc, "{:L}", -256)); - fmt::format_arg_store<fmt::format_context, int> as{1234567}; - EXPECT_EQ("1~234~567", fmt::vformat(loc, "{:L}", fmt::format_args(as))); - std::string s; - fmt::format_to(std::back_inserter(s), loc, "{:L}", 1234567); - EXPECT_EQ("1~234~567", s); - - std::locale no_grouping_loc(std::locale(), new no_grouping<char>()); - EXPECT_EQ("1234567", fmt::format(no_grouping_loc, "{:L}", 1234567)); - - std::locale special_grouping_loc(std::locale(), new special_grouping<char>()); - EXPECT_EQ("1,23,45,678", fmt::format(special_grouping_loc, "{:L}", 12345678)); - EXPECT_EQ("12,345", fmt::format(special_grouping_loc, "{:L}", 12345)); - - std::locale small_grouping_loc(std::locale(), new small_grouping<char>()); - EXPECT_EQ("4,2,9,4,9,6,7,2,9,5", - fmt::format(small_grouping_loc, "{:L}", max_value<uint32_t>())); -} - -TEST(LocaleTest, FormatDetaultAlign) { - std::locale special_grouping_loc(std::locale(), new special_grouping<char>()); - EXPECT_EQ(" 12,345", fmt::format(special_grouping_loc, "{:8L}", 12345)); -} - -TEST(LocaleTest, WFormat) { - std::locale loc(std::locale(), new numpunct<wchar_t>()); - EXPECT_EQ(L"1234567", fmt::format(std::locale(), L"{:L}", 1234567)); - EXPECT_EQ(L"1~234~567", fmt::format(loc, L"{:L}", 1234567)); - fmt::format_arg_store<fmt::wformat_context, int> as{1234567}; - EXPECT_EQ(L"1~234~567", fmt::vformat(loc, L"{:L}", fmt::wformat_args(as))); - EXPECT_EQ(L"1234567", fmt::format(std::locale("C"), L"{:L}", 1234567)); - - std::locale no_grouping_loc(std::locale(), new no_grouping<wchar_t>()); - EXPECT_EQ(L"1234567", fmt::format(no_grouping_loc, L"{:L}", 1234567)); - - std::locale special_grouping_loc(std::locale(), - new special_grouping<wchar_t>()); - EXPECT_EQ(L"1,23,45,678", - fmt::format(special_grouping_loc, L"{:L}", 12345678)); - - std::locale small_grouping_loc(std::locale(), new small_grouping<wchar_t>()); - EXPECT_EQ(L"4,2,9,4,9,6,7,2,9,5", - fmt::format(small_grouping_loc, L"{:L}", max_value<uint32_t>())); -} - -TEST(LocaleTest, DoubleFormatter) { - auto loc = std::locale(std::locale(), new special_grouping<char>()); - auto f = fmt::formatter<int>(); - auto parse_ctx = fmt::format_parse_context("L"); - f.parse(parse_ctx); - char buf[10] = {}; - fmt::basic_format_context<char*, char> format_ctx( - buf, {}, fmt::detail::locale_ref(loc)); - *f.format(12345, format_ctx) = 0; - EXPECT_STREQ("12,345", buf); -} - -FMT_BEGIN_NAMESPACE -template <class charT> struct formatter<std::complex<double>, charT> { - private: - detail::dynamic_format_specs<char> specs_; - - public: - typename basic_format_parse_context<charT>::iterator parse( - basic_format_parse_context<charT>& ctx) { - using handler_type = - detail::dynamic_specs_handler<basic_format_parse_context<charT>>; - detail::specs_checker<handler_type> handler(handler_type(specs_, ctx), - detail::type::string_type); - auto it = parse_format_specs(ctx.begin(), ctx.end(), handler); - detail::parse_float_type_spec(specs_, ctx.error_handler()); - return it; - } - - template <class FormatContext> - typename FormatContext::iterator format(const std::complex<double>& c, - FormatContext& ctx) { - detail::handle_dynamic_spec<detail::precision_checker>( - specs_.precision, specs_.precision_ref, ctx); - auto format_specs = std::string(); - if (specs_.precision > 0) - format_specs = fmt::format(".{}", specs_.precision); - if (specs_.type) - format_specs += specs_.type; - auto real = fmt::format(ctx.locale().template get<std::locale>(), - "{:" + format_specs + "}", c.real()); - auto imag = fmt::format(ctx.locale().template get<std::locale>(), - "{:" + format_specs + "}", c.imag()); - auto fill_align_width = std::string(); - if (specs_.width > 0) - fill_align_width = fmt::format(">{}", specs_.width); - return format_to( - ctx.out(), "{:" + fill_align_width + "}", - fmt::format(c.real() != 0 ? "({0}+{1}i)" : "{1}i", real, imag)); - } -}; -FMT_END_NAMESPACE - -TEST(FormatTest, Complex) { - std::string s = fmt::format("{}", std::complex<double>(1, 2)); - EXPECT_EQ(s, "(1+2i)"); - EXPECT_EQ(fmt::format("{:.2f}", std::complex<double>(1, 2)), "(1.00+2.00i)"); - EXPECT_EQ(fmt::format("{:8}", std::complex<double>(1, 2)), " (1+2i)"); -} - -#endif // FMT_STATIC_THOUSANDS_SEPARATOR diff --git a/contrib/libs/fmt/test/mock-allocator.h b/contrib/libs/fmt/test/mock-allocator.h index dfc13feee7..6a67e08f4f 100644 --- a/contrib/libs/fmt/test/mock-allocator.h +++ b/contrib/libs/fmt/test/mock-allocator.h @@ -8,14 +8,18 @@ #ifndef FMT_MOCK_ALLOCATOR_H_ #define FMT_MOCK_ALLOCATOR_H_ -#include "fmt/format.h" -#include <gmock/gmock.h> +#include <assert.h> // assert +#include <stddef.h> // size_t + +#include <memory> // std::allocator_traits + +#include "gmock/gmock.h" template <typename T> class mock_allocator { public: mock_allocator() {} mock_allocator(const mock_allocator&) {} - typedef T value_type; + using value_type = T; MOCK_METHOD1_T(allocate, T*(size_t n)); MOCK_METHOD2_T(deallocate, void(T* p, size_t n)); }; @@ -30,7 +34,7 @@ template <typename Allocator> class allocator_ref { } public: - typedef typename Allocator::value_type value_type; + using value_type = typename Allocator::value_type; explicit allocator_ref(Allocator* alloc = nullptr) : alloc_(alloc) {} diff --git a/contrib/libs/fmt/test/os-test.cc b/contrib/libs/fmt/test/os-test.cc index 359b5ff8ce..5b5ef76ed6 100644 --- a/contrib/libs/fmt/test/os-test.cc +++ b/contrib/libs/fmt/test/os-test.cc @@ -19,20 +19,21 @@ #endif using fmt::buffered_file; -using fmt::error_code; +using testing::HasSubstr; +using wstring_view = fmt::basic_string_view<wchar_t>; #ifdef _WIN32 # include <windows.h> -TEST(UtilTest, UTF16ToUTF8) { - std::string s = "ёжик"; +TEST(util_test, utf16_to_utf8) { + auto s = std::string("ёжик"); fmt::detail::utf16_to_utf8 u(L"\x0451\x0436\x0438\x043A"); EXPECT_EQ(s, u.str()); EXPECT_EQ(s.size(), u.size()); } -TEST(UtilTest, UTF16ToUTF8EmptyString) { +TEST(util_test, utf16_to_utf8_empty_string) { std::string s = ""; fmt::detail::utf16_to_utf8 u(L""); EXPECT_EQ(s, u.str()); @@ -40,70 +41,78 @@ TEST(UtilTest, UTF16ToUTF8EmptyString) { } template <typename Converter, typename Char> -void check_utf_conversion_error( - const char* message, - fmt::basic_string_view<Char> str = fmt::basic_string_view<Char>(0, 1)) { +void check_utf_conversion_error(const char* message, + fmt::basic_string_view<Char> str = + fmt::basic_string_view<Char>(nullptr, 1)) { fmt::memory_buffer out; fmt::detail::format_windows_error(out, ERROR_INVALID_PARAMETER, message); - fmt::system_error error(0, ""); + auto error = std::system_error(std::error_code()); try { (Converter)(str); - } catch (const fmt::system_error& e) { + } catch (const std::system_error& e) { error = e; } - EXPECT_EQ(ERROR_INVALID_PARAMETER, error.error_code()); - EXPECT_EQ(fmt::to_string(out), error.what()); + EXPECT_EQ(ERROR_INVALID_PARAMETER, error.code().value()); + EXPECT_THAT(error.what(), HasSubstr(fmt::to_string(out))); } -TEST(UtilTest, UTF16ToUTF8Error) { +TEST(util_test, utf16_to_utf8_error) { check_utf_conversion_error<fmt::detail::utf16_to_utf8, wchar_t>( "cannot convert string from UTF-16 to UTF-8"); } -TEST(UtilTest, UTF16ToUTF8Convert) { +TEST(util_test, utf16_to_utf8_convert) { fmt::detail::utf16_to_utf8 u; - EXPECT_EQ(ERROR_INVALID_PARAMETER, u.convert(fmt::wstring_view(0, 1))); + EXPECT_EQ(ERROR_INVALID_PARAMETER, u.convert(wstring_view(nullptr, 1))); EXPECT_EQ(ERROR_INVALID_PARAMETER, - u.convert(fmt::wstring_view(L"foo", INT_MAX + 1u))); -} - -TEST(UtilTest, FormatWindowsError) { - LPWSTR message = 0; - FormatMessageW(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | - FORMAT_MESSAGE_IGNORE_INSERTS, - 0, ERROR_FILE_EXISTS, - MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), - reinterpret_cast<LPWSTR>(&message), 0, 0); - fmt::detail::utf16_to_utf8 utf8_message(message); + u.convert(wstring_view(L"foo", INT_MAX + 1u))); +} + +TEST(os_test, format_std_error_code) { + EXPECT_EQ("generic:42", + fmt::format(FMT_STRING("{0}"), + std::error_code(42, std::generic_category()))); + EXPECT_EQ("system:42", + fmt::format(FMT_STRING("{0}"), + std::error_code(42, fmt::system_category()))); + EXPECT_EQ("system:-42", + fmt::format(FMT_STRING("{0}"), + std::error_code(-42, fmt::system_category()))); +} + +TEST(os_test, format_windows_error) { + LPWSTR message = nullptr; + auto result = FormatMessageW( + FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | + FORMAT_MESSAGE_IGNORE_INSERTS, + nullptr, ERROR_FILE_EXISTS, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), + reinterpret_cast<LPWSTR>(&message), 0, nullptr); + fmt::detail::utf16_to_utf8 utf8_message(wstring_view(message, result - 2)); LocalFree(message); fmt::memory_buffer actual_message; fmt::detail::format_windows_error(actual_message, ERROR_FILE_EXISTS, "test"); EXPECT_EQ(fmt::format("test: {}", utf8_message.str()), fmt::to_string(actual_message)); actual_message.resize(0); - auto max_size = fmt::detail::max_value<size_t>() / 2; - fmt::detail::format_windows_error(actual_message, ERROR_FILE_EXISTS, - fmt::string_view(nullptr, max_size)); - EXPECT_EQ(fmt::format("error {}", ERROR_FILE_EXISTS), - fmt::to_string(actual_message)); } -TEST(UtilTest, FormatLongWindowsError) { - LPWSTR message = 0; +TEST(os_test, format_long_windows_error) { + LPWSTR message = nullptr; // this error code is not available on all Windows platforms and // Windows SDKs, so do not fail the test if the error string cannot // be retrieved. - const int provisioning_not_allowed = - 0x80284013L /*TBS_E_PROVISIONING_NOT_ALLOWED*/; - if (FormatMessageW(FORMAT_MESSAGE_ALLOCATE_BUFFER | - FORMAT_MESSAGE_FROM_SYSTEM | - FORMAT_MESSAGE_IGNORE_INSERTS, - 0, static_cast<DWORD>(provisioning_not_allowed), - MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), - reinterpret_cast<LPWSTR>(&message), 0, 0) == 0) { + int provisioning_not_allowed = 0x80284013L; // TBS_E_PROVISIONING_NOT_ALLOWED + auto result = FormatMessageW( + FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | + FORMAT_MESSAGE_IGNORE_INSERTS, + nullptr, static_cast<DWORD>(provisioning_not_allowed), + MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), + reinterpret_cast<LPWSTR>(&message), 0, nullptr); + if (result == 0) { + LocalFree(message); return; } - fmt::detail::utf16_to_utf8 utf8_message(message); + fmt::detail::utf16_to_utf8 utf8_message(wstring_view(message, result - 2)); LocalFree(message); fmt::memory_buffer actual_message; fmt::detail::format_windows_error(actual_message, provisioning_not_allowed, @@ -112,20 +121,20 @@ TEST(UtilTest, FormatLongWindowsError) { fmt::to_string(actual_message)); } -TEST(UtilTest, WindowsError) { - fmt::system_error error(0, ""); +TEST(os_test, windows_error) { + auto error = std::system_error(std::error_code()); try { throw fmt::windows_error(ERROR_FILE_EXISTS, "test {}", "error"); - } catch (const fmt::system_error& e) { + } catch (const std::system_error& e) { error = e; } fmt::memory_buffer message; fmt::detail::format_windows_error(message, ERROR_FILE_EXISTS, "test error"); - EXPECT_EQ(to_string(message), error.what()); - EXPECT_EQ(ERROR_FILE_EXISTS, error.error_code()); + EXPECT_THAT(error.what(), HasSubstr(to_string(message))); + EXPECT_EQ(ERROR_FILE_EXISTS, error.code().value()); } -TEST(UtilTest, ReportWindowsError) { +TEST(os_test, report_windows_error) { fmt::memory_buffer out; fmt::detail::format_windows_error(out, ERROR_FILE_EXISTS, "test error"); out.push_back('\n'); @@ -140,30 +149,24 @@ TEST(UtilTest, ReportWindowsError) { using fmt::file; -// Checks if the file is open by reading one character from it. -static bool isopen(int fd) { - char buffer; - return FMT_POSIX(read(fd, &buffer, 1)) == 1; -} - -static bool isclosed(int fd) { +bool isclosed(int fd) { char buffer; - std::streamsize result = 0; + auto result = std::streamsize(); SUPPRESS_ASSERT(result = FMT_POSIX(read(fd, &buffer, 1))); return result == -1 && errno == EBADF; } // Opens a file for reading. -static file open_file() { +file open_file() { file read_end, write_end; file::pipe(read_end, write_end); - write_end.write(FILE_CONTENT, std::strlen(FILE_CONTENT)); + write_end.write(file_content, std::strlen(file_content)); write_end.close(); return read_end; } // Attempts to write a string to a file. -static void write(file& f, fmt::string_view s) { +void write(file& f, fmt::string_view s) { size_t num_chars_left = s.size(); const char* ptr = s.data(); do { @@ -175,12 +178,12 @@ static void write(file& f, fmt::string_view s) { } while (num_chars_left != 0); } -TEST(BufferedFileTest, DefaultCtor) { - buffered_file f; +TEST(buffered_file_test, default_ctor) { + auto f = buffered_file(); EXPECT_TRUE(f.get() == nullptr); } -TEST(BufferedFileTest, MoveCtor) { +TEST(buffered_file_test, move_ctor) { buffered_file bf = open_buffered_file(); FILE* fp = bf.get(); EXPECT_TRUE(fp != nullptr); @@ -189,7 +192,7 @@ TEST(BufferedFileTest, MoveCtor) { EXPECT_TRUE(bf.get() == nullptr); } -TEST(BufferedFileTest, MoveAssignment) { +TEST(buffered_file_test, move_assignment) { buffered_file bf = open_buffered_file(); FILE* fp = bf.get(); EXPECT_TRUE(fp != nullptr); @@ -199,7 +202,7 @@ TEST(BufferedFileTest, MoveAssignment) { EXPECT_TRUE(bf.get() == nullptr); } -TEST(BufferedFileTest, MoveAssignmentClosesFile) { +TEST(buffered_file_test, move_assignment_closes_file) { buffered_file bf = open_buffered_file(); buffered_file bf2 = open_buffered_file(); int old_fd = bf2.fileno(); @@ -207,27 +210,27 @@ TEST(BufferedFileTest, MoveAssignmentClosesFile) { EXPECT_TRUE(isclosed(old_fd)); } -TEST(BufferedFileTest, MoveFromTemporaryInCtor) { +TEST(buffered_file_test, move_from_temporary_in_ctor) { FILE* fp = nullptr; - buffered_file f(open_buffered_file(&fp)); + buffered_file f = open_buffered_file(&fp); EXPECT_EQ(fp, f.get()); } -TEST(BufferedFileTest, MoveFromTemporaryInAssignment) { +TEST(buffered_file_test, move_from_temporary_in_assignment) { FILE* fp = nullptr; - buffered_file f; + auto f = buffered_file(); f = open_buffered_file(&fp); EXPECT_EQ(fp, f.get()); } -TEST(BufferedFileTest, MoveFromTemporaryInAssignmentClosesFile) { +TEST(buffered_file_test, move_from_temporary_in_assignment_closes_file) { buffered_file f = open_buffered_file(); int old_fd = f.fileno(); f = open_buffered_file(); EXPECT_TRUE(isclosed(old_fd)); } -TEST(BufferedFileTest, CloseFileInDtor) { +TEST(buffered_file_test, close_file_in_dtor) { int fd = 0; { buffered_file f = open_buffered_file(); @@ -236,8 +239,9 @@ TEST(BufferedFileTest, CloseFileInDtor) { EXPECT_TRUE(isclosed(fd)); } -TEST(BufferedFileTest, CloseErrorInDtor) { - std::unique_ptr<buffered_file> f(new buffered_file(open_buffered_file())); +TEST(buffered_file_test, close_error_in_dtor) { + auto f = + std::unique_ptr<buffered_file>(new buffered_file(open_buffered_file())); EXPECT_WRITE( stderr, { @@ -248,10 +252,10 @@ TEST(BufferedFileTest, CloseErrorInDtor) { FMT_POSIX(close(f->fileno())); SUPPRESS_ASSERT(f.reset(nullptr)); }, - format_system_error(EBADF, "cannot close file") + "\n"); + system_error_message(EBADF, "cannot close file") + "\n"); } -TEST(BufferedFileTest, Close) { +TEST(buffered_file_test, close) { buffered_file f = open_buffered_file(); int fd = f.fileno(); f.close(); @@ -259,49 +263,49 @@ TEST(BufferedFileTest, Close) { EXPECT_TRUE(isclosed(fd)); } -TEST(BufferedFileTest, CloseError) { +TEST(buffered_file_test, close_error) { buffered_file f = open_buffered_file(); FMT_POSIX(close(f.fileno())); EXPECT_SYSTEM_ERROR_NOASSERT(f.close(), EBADF, "cannot close file"); EXPECT_TRUE(f.get() == nullptr); } -TEST(BufferedFileTest, Fileno) { - buffered_file f; -# ifndef __COVERITY__ - // fileno on a null FILE pointer either crashes or returns an error. - // Disable Coverity because this is intentional. - EXPECT_DEATH_IF_SUPPORTED( - { - try { - f.fileno(); - } catch (const fmt::system_error&) { - std::exit(1); - } - }, - ""); -# endif - f = open_buffered_file(); +TEST(buffered_file_test, fileno) { + auto f = open_buffered_file(); EXPECT_TRUE(f.fileno() != -1); file copy = file::dup(f.fileno()); - EXPECT_READ(copy, FILE_CONTENT); + EXPECT_READ(copy, file_content); } -TEST(OStreamTest, Move) { +TEST(ostream_test, move) { fmt::ostream out = fmt::output_file("test-file"); fmt::ostream moved(std::move(out)); moved.print("hello"); } -TEST(OStreamTest, Print) { +TEST(ostream_test, move_while_holding_data) { + { + fmt::ostream out = fmt::output_file("test-file"); + out.print("Hello, "); + fmt::ostream moved(std::move(out)); + moved.print("world!\n"); + } + { + file in("test-file", file::RDONLY); + EXPECT_READ(in, "Hello, world!\n"); + } +} + +TEST(ostream_test, print) { fmt::ostream out = fmt::output_file("test-file"); - out.print("The answer is {}.\n", 42); + out.print("The answer is {}.\n", + fmt::join(std::initializer_list<int>{42}, ", ")); out.close(); file in("test-file", file::RDONLY); EXPECT_READ(in, "The answer is 42.\n"); } -TEST(OStreamTest, BufferBoundary) { +TEST(ostream_test, buffer_boundary) { auto str = std::string(4096, 'x'); fmt::ostream out = fmt::output_file("test-file"); out.print("{}", str); @@ -311,33 +315,57 @@ TEST(OStreamTest, BufferBoundary) { EXPECT_READ(in, str + str); } -TEST(OStreamTest, BufferSize) { - fmt::ostream out = fmt::output_file("test-file", fmt::buffer_size=1); +TEST(ostream_test, buffer_size) { + fmt::ostream out = fmt::output_file("test-file", fmt::buffer_size = 1); out.print("{}", "foo"); out.close(); file in("test-file", file::RDONLY); EXPECT_READ(in, "foo"); } -TEST(FileTest, DefaultCtor) { +TEST(ostream_test, truncate) { + { + fmt::ostream out = fmt::output_file("test-file"); + out.print("0123456789"); + } + { + fmt::ostream out = fmt::output_file("test-file"); + out.print("foo"); + } + file in("test-file", file::RDONLY); + EXPECT_EQ("foo", read(in, 4)); +} + +TEST(ostream_test, flush) { + auto out = fmt::output_file("test-file"); + out.print("x"); + out.flush(); + auto in = fmt::file("test-file", file::RDONLY); + EXPECT_READ(in, "x"); +} + +TEST(file_test, default_ctor) { file f; EXPECT_EQ(-1, f.descriptor()); } -TEST(FileTest, OpenBufferedFileInCtor) { +TEST(file_test, open_buffered_file_in_ctor) { FILE* fp = safe_fopen("test-file", "w"); - std::fputs(FILE_CONTENT, fp); + std::fputs(file_content, fp); std::fclose(fp); file f("test-file", file::RDONLY); - ASSERT_TRUE(isopen(f.descriptor())); + // Check if the file is open by reading one character from it. + char buffer; + bool isopen = FMT_POSIX(read(f.descriptor(), &buffer, 1)) == 1; + ASSERT_TRUE(isopen); } -TEST(FileTest, OpenBufferedFileError) { +TEST(file_test, open_buffered_file_error) { EXPECT_SYSTEM_ERROR(file("nonexistent", file::RDONLY), ENOENT, "cannot open file nonexistent"); } -TEST(FileTest, MoveCtor) { +TEST(file_test, move_ctor) { file f = open_file(); int fd = f.descriptor(); EXPECT_NE(-1, fd); @@ -346,7 +374,7 @@ TEST(FileTest, MoveCtor) { EXPECT_EQ(-1, f.descriptor()); } -TEST(FileTest, MoveAssignment) { +TEST(file_test, move_assignment) { file f = open_file(); int fd = f.descriptor(); EXPECT_NE(-1, fd); @@ -356,7 +384,7 @@ TEST(FileTest, MoveAssignment) { EXPECT_EQ(-1, f.descriptor()); } -TEST(FileTest, MoveAssignmentClosesFile) { +TEST(file_test, move_assignment_closes_file) { file f = open_file(); file f2 = open_file(); int old_fd = f2.descriptor(); @@ -364,34 +392,34 @@ TEST(FileTest, MoveAssignmentClosesFile) { EXPECT_TRUE(isclosed(old_fd)); } -static file OpenBufferedFile(int& fd) { +file open_buffered_file(int& fd) { file f = open_file(); fd = f.descriptor(); return f; } -TEST(FileTest, MoveFromTemporaryInCtor) { +TEST(file_test, move_from_temporary_in_ctor) { int fd = 0xdead; - file f(OpenBufferedFile(fd)); + file f(open_buffered_file(fd)); EXPECT_EQ(fd, f.descriptor()); } -TEST(FileTest, MoveFromTemporaryInAssignment) { +TEST(file_test, move_from_temporary_in_assignment) { int fd = 0xdead; file f; - f = OpenBufferedFile(fd); + f = open_buffered_file(fd); EXPECT_EQ(fd, f.descriptor()); } -TEST(FileTest, MoveFromTemporaryInAssignmentClosesFile) { +TEST(file_test, move_from_temporary_in_assignment_closes_file) { int fd = 0xdead; file f = open_file(); int old_fd = f.descriptor(); - f = OpenBufferedFile(fd); + f = open_buffered_file(fd); EXPECT_TRUE(isclosed(old_fd)); } -TEST(FileTest, CloseFileInDtor) { +TEST(file_test, close_file_in_dtor) { int fd = 0; { file f = open_file(); @@ -400,7 +428,7 @@ TEST(FileTest, CloseFileInDtor) { EXPECT_TRUE(isclosed(fd)); } -TEST(FileTest, CloseErrorInDtor) { +TEST(file_test, close_error_in_dtor) { std::unique_ptr<file> f(new file(open_file())); EXPECT_WRITE( stderr, @@ -412,10 +440,10 @@ TEST(FileTest, CloseErrorInDtor) { FMT_POSIX(close(f->descriptor())); SUPPRESS_ASSERT(f.reset(nullptr)); }, - format_system_error(EBADF, "cannot close file") + "\n"); + system_error_message(EBADF, "cannot close file") + "\n"); } -TEST(FileTest, Close) { +TEST(file_test, close) { file f = open_file(); int fd = f.descriptor(); f.close(); @@ -423,19 +451,19 @@ TEST(FileTest, Close) { EXPECT_TRUE(isclosed(fd)); } -TEST(FileTest, CloseError) { +TEST(file_test, close_error) { file f = open_file(); FMT_POSIX(close(f.descriptor())); EXPECT_SYSTEM_ERROR_NOASSERT(f.close(), EBADF, "cannot close file"); EXPECT_EQ(-1, f.descriptor()); } -TEST(FileTest, Read) { +TEST(file_test, read) { file f = open_file(); - EXPECT_READ(f, FILE_CONTENT); + EXPECT_READ(f, file_content); } -TEST(FileTest, ReadError) { +TEST(file_test, read_error) { file f("test-file", file::WRONLY); char buf; // We intentionally read from a file opened in the write-only mode to @@ -443,7 +471,7 @@ TEST(FileTest, ReadError) { EXPECT_SYSTEM_ERROR(f.read(&buf, 1), EBADF, "cannot read from file"); } -TEST(FileTest, Write) { +TEST(file_test, write) { file read_end, write_end; file::pipe(read_end, write_end); write(write_end, "test"); @@ -451,61 +479,61 @@ TEST(FileTest, Write) { EXPECT_READ(read_end, "test"); } -TEST(FileTest, WriteError) { +TEST(file_test, write_error) { file f("test-file", file::RDONLY); // We intentionally write to a file opened in the read-only mode to // cause error. EXPECT_SYSTEM_ERROR(f.write(" ", 1), EBADF, "cannot write to file"); } -TEST(FileTest, Dup) { +TEST(file_test, dup) { file f = open_file(); file copy = file::dup(f.descriptor()); EXPECT_NE(f.descriptor(), copy.descriptor()); - EXPECT_EQ(FILE_CONTENT, read(copy, std::strlen(FILE_CONTENT))); + EXPECT_EQ(file_content, read(copy, std::strlen(file_content))); } # ifndef __COVERITY__ -TEST(FileTest, DupError) { +TEST(file_test, dup_error) { int value = -1; EXPECT_SYSTEM_ERROR_NOASSERT(file::dup(value), EBADF, "cannot duplicate file descriptor -1"); } # endif -TEST(FileTest, Dup2) { +TEST(file_test, dup2) { file f = open_file(); file copy = open_file(); f.dup2(copy.descriptor()); EXPECT_NE(f.descriptor(), copy.descriptor()); - EXPECT_READ(copy, FILE_CONTENT); + EXPECT_READ(copy, file_content); } -TEST(FileTest, Dup2Error) { +TEST(file_test, dup2_error) { file f = open_file(); EXPECT_SYSTEM_ERROR_NOASSERT( f.dup2(-1), EBADF, fmt::format("cannot duplicate file descriptor {} to -1", f.descriptor())); } -TEST(FileTest, Dup2NoExcept) { +TEST(file_test, dup2_noexcept) { file f = open_file(); file copy = open_file(); - error_code ec; + std::error_code ec; f.dup2(copy.descriptor(), ec); - EXPECT_EQ(ec.get(), 0); + EXPECT_EQ(ec.value(), 0); EXPECT_NE(f.descriptor(), copy.descriptor()); - EXPECT_READ(copy, FILE_CONTENT); + EXPECT_READ(copy, file_content); } -TEST(FileTest, Dup2NoExceptError) { +TEST(file_test, dup2_noexcept_error) { file f = open_file(); - error_code ec; + std::error_code ec; SUPPRESS_ASSERT(f.dup2(-1, ec)); - EXPECT_EQ(EBADF, ec.get()); + EXPECT_EQ(EBADF, ec.value()); } -TEST(FileTest, Pipe) { +TEST(file_test, pipe) { file read_end, write_end; file::pipe(read_end, write_end); EXPECT_NE(-1, read_end.descriptor()); @@ -514,19 +542,10 @@ TEST(FileTest, Pipe) { EXPECT_READ(read_end, "test"); } -TEST(FileTest, Fdopen) { +TEST(file_test, fdopen) { file read_end, write_end; file::pipe(read_end, write_end); int read_fd = read_end.descriptor(); EXPECT_EQ(read_fd, FMT_POSIX(fileno(read_end.fdopen("r").get()))); } - -# ifdef FMT_LOCALE -TEST(LocaleTest, Strtod) { - fmt::locale loc; - const char *start = "4.2", *ptr = start; - EXPECT_EQ(4.2, loc.strtod(ptr)); - EXPECT_EQ(start + 3, ptr); -} -# endif #endif // FMT_USE_FCNTL diff --git a/contrib/libs/fmt/test/ostream-test.cc b/contrib/libs/fmt/test/ostream-test.cc index 4cef5a78c4..f81039e5bb 100644 --- a/contrib/libs/fmt/test/ostream-test.cc +++ b/contrib/libs/fmt/test/ostream-test.cc @@ -7,14 +7,15 @@ #include "fmt/format.h" +using fmt::runtime; + struct test {}; // Test that there is no issues with specializations when fmt/ostream.h is // included after fmt/format.h. namespace fmt { template <> struct formatter<test> : formatter<int> { - template <typename FormatContext> - typename FormatContext::iterator format(const test&, FormatContext& ctx) { + auto format(const test&, format_context& ctx) -> decltype(ctx.out()) { return formatter<int>::format(42, ctx); } }; @@ -22,21 +23,19 @@ template <> struct formatter<test> : formatter<int> { #include <sstream> +#include "fmt/compile.h" #include "fmt/ostream.h" #include "fmt/ranges.h" -#include <gmock/gmock.h> +#include "gmock/gmock.h" #include "gtest-extra.h" #include "util.h" -using fmt::format; -using fmt::format_error; - -static std::ostream& operator<<(std::ostream& os, const Date& d) { +std::ostream& operator<<(std::ostream& os, const date& d) { os << d.year() << '-' << d.month() << '-' << d.day(); return os; } -static std::wostream& operator<<(std::wostream& os, const Date& d) { +std::wostream& operator<<(std::wostream& os, const date& d) { os << d.year() << L'-' << d.month() << L'-' << d.day(); return os; } @@ -44,99 +43,63 @@ static std::wostream& operator<<(std::wostream& os, const Date& d) { // Make sure that overloaded comma operators do no harm to is_streamable. struct type_with_comma_op {}; template <typename T> void operator,(type_with_comma_op, const T&); -template <typename T> type_with_comma_op operator<<(T&, const Date&); +template <typename T> type_with_comma_op operator<<(T&, const date&); enum streamable_enum {}; -static std::ostream& operator<<(std::ostream& os, streamable_enum) { - return os << "streamable_enum"; -} -static std::wostream& operator<<(std::wostream& os, streamable_enum) { - return os << L"streamable_enum"; +std::ostream& operator<<(std::ostream& os, streamable_enum) { + return os << "streamable_enum"; } enum unstreamable_enum {}; -TEST(OStreamTest, Enum) { +TEST(ostream_test, enum) { EXPECT_EQ("streamable_enum", fmt::format("{}", streamable_enum())); EXPECT_EQ("0", fmt::format("{}", unstreamable_enum())); - EXPECT_EQ(L"streamable_enum", fmt::format(L"{}", streamable_enum())); - EXPECT_EQ(L"0", fmt::format(L"{}", unstreamable_enum())); -} - -struct test_arg_formatter - : fmt::detail::arg_formatter<fmt::format_context::iterator, char> { - fmt::format_parse_context parse_ctx; - test_arg_formatter(fmt::format_context& ctx, fmt::format_specs& s) - : fmt::detail::arg_formatter<fmt::format_context::iterator, char>( - ctx, &parse_ctx, &s), - parse_ctx("") {} -}; - -TEST(OStreamTest, CustomArg) { - fmt::memory_buffer buffer; - fmt::format_context ctx(fmt::detail::buffer_appender<char>{buffer}, - fmt::format_args()); - fmt::format_specs spec; - test_arg_formatter af(ctx, spec); - fmt::visit_format_arg( - af, fmt::detail::make_arg<fmt::format_context>(streamable_enum())); - EXPECT_EQ("streamable_enum", std::string(buffer.data(), buffer.size())); } -TEST(OStreamTest, Format) { - EXPECT_EQ("a string", format("{0}", TestString("a string"))); - std::string s = format("The date is {0}", Date(2012, 12, 9)); - EXPECT_EQ("The date is 2012-12-9", s); - Date date(2012, 12, 9); - EXPECT_EQ(L"The date is 2012-12-9", - format(L"The date is {0}", Date(2012, 12, 9))); +TEST(ostream_test, format) { + EXPECT_EQ("a string", fmt::format("{0}", test_string("a string"))); + EXPECT_EQ("The date is 2012-12-9", + fmt::format("The date is {0}", date(2012, 12, 9))); } -TEST(OStreamTest, FormatSpecs) { - EXPECT_EQ("def ", format("{0:<5}", TestString("def"))); - EXPECT_EQ(" def", format("{0:>5}", TestString("def"))); -#if FMT_DEPRECATED_NUMERIC_ALIGN - EXPECT_THROW_MSG(format("{0:=5}", TestString("def")), format_error, - "format specifier requires numeric argument"); -#endif - EXPECT_EQ(" def ", format("{0:^5}", TestString("def"))); - EXPECT_EQ("def**", format("{0:*<5}", TestString("def"))); - EXPECT_THROW_MSG(format("{0:+}", TestString()), format_error, - "format specifier requires numeric argument"); - EXPECT_THROW_MSG(format("{0:-}", TestString()), format_error, - "format specifier requires numeric argument"); - EXPECT_THROW_MSG(format("{0: }", TestString()), format_error, - "format specifier requires numeric argument"); - EXPECT_THROW_MSG(format("{0:#}", TestString()), format_error, - "format specifier requires numeric argument"); - EXPECT_THROW_MSG(format("{0:05}", TestString()), format_error, - "format specifier requires numeric argument"); - EXPECT_EQ("test ", format("{0:13}", TestString("test"))); - EXPECT_EQ("test ", format("{0:{1}}", TestString("test"), 13)); - EXPECT_EQ("te", format("{0:.2}", TestString("test"))); - EXPECT_EQ("te", format("{0:.{1}}", TestString("test"), 2)); +TEST(ostream_test, format_specs) { + using fmt::format_error; + EXPECT_EQ("def ", fmt::format("{0:<5}", test_string("def"))); + EXPECT_EQ(" def", fmt::format("{0:>5}", test_string("def"))); + EXPECT_EQ(" def ", fmt::format("{0:^5}", test_string("def"))); + EXPECT_EQ("def**", fmt::format("{0:*<5}", test_string("def"))); + EXPECT_THROW_MSG((void)fmt::format(runtime("{0:+}"), test_string()), + format_error, "format specifier requires numeric argument"); + EXPECT_THROW_MSG((void)fmt::format(runtime("{0:-}"), test_string()), + format_error, "format specifier requires numeric argument"); + EXPECT_THROW_MSG((void)fmt::format(runtime("{0: }"), test_string()), + format_error, "format specifier requires numeric argument"); + EXPECT_THROW_MSG((void)fmt::format(runtime("{0:#}"), test_string()), + format_error, "format specifier requires numeric argument"); + EXPECT_THROW_MSG((void)fmt::format(runtime("{0:05}"), test_string()), + format_error, "format specifier requires numeric argument"); + EXPECT_EQ("test ", fmt::format("{0:13}", test_string("test"))); + EXPECT_EQ("test ", fmt::format("{0:{1}}", test_string("test"), 13)); + EXPECT_EQ("te", fmt::format("{0:.2}", test_string("test"))); + EXPECT_EQ("te", fmt::format("{0:.{1}}", test_string("test"), 2)); } -struct EmptyTest {}; -static std::ostream& operator<<(std::ostream& os, EmptyTest) { - return os << ""; -} +struct empty_test {}; +std::ostream& operator<<(std::ostream& os, empty_test) { return os << ""; } -TEST(OStreamTest, EmptyCustomOutput) { - EXPECT_EQ("", fmt::format("{}", EmptyTest())); +TEST(ostream_test, empty_custom_output) { + EXPECT_EQ("", fmt::format("{}", empty_test())); } -TEST(OStreamTest, Print) { +TEST(ostream_test, print) { std::ostringstream os; fmt::print(os, "Don't {}!", "panic"); EXPECT_EQ("Don't panic!", os.str()); - std::wostringstream wos; - fmt::print(wos, L"Don't {}!", L"panic"); - EXPECT_EQ(L"Don't panic!", wos.str()); } -TEST(OStreamTest, WriteToOStream) { +TEST(ostream_test, write_to_ostream) { std::ostringstream os; fmt::memory_buffer buffer; const char* foo = "foo"; @@ -145,32 +108,33 @@ TEST(OStreamTest, WriteToOStream) { EXPECT_EQ("foo", os.str()); } -TEST(OStreamTest, WriteToOStreamMaxSize) { - size_t max_size = fmt::detail::max_value<size_t>(); - std::streamsize max_streamsize = fmt::detail::max_value<std::streamsize>(); +TEST(ostream_test, write_to_ostream_max_size) { + auto max_size = fmt::detail::max_value<size_t>(); + auto max_streamsize = fmt::detail::max_value<std::streamsize>(); if (max_size <= fmt::detail::to_unsigned(max_streamsize)) return; struct test_buffer final : fmt::detail::buffer<char> { explicit test_buffer(size_t size) - : fmt::detail::buffer<char>(nullptr, size, size) {} - void grow(size_t) {} + : fmt::detail::buffer<char>(nullptr, size, size) {} + void grow(size_t) override {} } buffer(max_size); struct mock_streambuf : std::streambuf { MOCK_METHOD2(xsputn, std::streamsize(const void* s, std::streamsize n)); - std::streamsize xsputn(const char* s, std::streamsize n) { + std::streamsize xsputn(const char* s, std::streamsize n) override { const void* v = s; return xsputn(v, n); } } streambuf; struct test_ostream : std::ostream { - explicit test_ostream(mock_streambuf& buffer) : std::ostream(&buffer) {} + explicit test_ostream(mock_streambuf& output_buffer) + : std::ostream(&output_buffer) {} } os(streambuf); testing::InSequence sequence; const char* data = nullptr; - typedef std::make_unsigned<std::streamsize>::type ustreamsize; + using ustreamsize = std::make_unsigned<std::streamsize>::type; ustreamsize size = max_size; do { auto n = std::min(size, fmt::detail::to_unsigned(max_streamsize)); @@ -182,68 +146,62 @@ TEST(OStreamTest, WriteToOStreamMaxSize) { fmt::detail::write_buffer(os, buffer); } -TEST(OStreamTest, Join) { +TEST(ostream_test, join) { int v[3] = {1, 2, 3}; EXPECT_EQ("1, 2, 3", fmt::format("{}", fmt::join(v, v + 3, ", "))); } +TEST(ostream_test, join_fallback_formatter) { + auto strs = std::vector<test_string>{test_string("foo"), test_string("bar")}; + EXPECT_EQ("foo, bar", fmt::format("{}", fmt::join(strs, ", "))); +} + #if FMT_USE_CONSTEXPR -TEST(OStreamTest, ConstexprString) { +TEST(ostream_test, constexpr_string) { EXPECT_EQ("42", format(FMT_STRING("{}"), std::string("42"))); - EXPECT_EQ("a string", format(FMT_STRING("{0}"), TestString("a string"))); + EXPECT_EQ("a string", format(FMT_STRING("{0}"), test_string("a string"))); } #endif namespace fmt_test { -struct ABC {}; +struct abc {}; -template <typename Output> Output& operator<<(Output& out, ABC) { - out << "ABC"; - return out; +template <typename Output> Output& operator<<(Output& out, abc) { + return out << "abc"; } } // namespace fmt_test -template <typename T> struct TestTemplate {}; +template <typename T> struct test_template {}; template <typename T> -std::ostream& operator<<(std::ostream& os, TestTemplate<T>) { +std::ostream& operator<<(std::ostream& os, test_template<T>) { return os << 1; } namespace fmt { -template <typename T> struct formatter<TestTemplate<T>> : formatter<int> { - template <typename FormatContext> - typename FormatContext::iterator format(TestTemplate<T>, FormatContext& ctx) { +template <typename T> struct formatter<test_template<T>> : formatter<int> { + auto format(test_template<T>, format_context& ctx) -> decltype(ctx.out()) { return formatter<int>::format(2, ctx); } }; } // namespace fmt -#if !FMT_GCC_VERSION || FMT_GCC_VERSION >= 407 -TEST(OStreamTest, Template) { - EXPECT_EQ("2", fmt::format("{}", TestTemplate<int>())); +TEST(ostream_test, template) { + EXPECT_EQ("2", fmt::format("{}", test_template<int>())); } -TEST(FormatTest, FormatToN) { +TEST(ostream_test, format_to_n) { char buffer[4]; buffer[3] = 'x'; - auto result = fmt::format_to_n(buffer, 3, "{}", fmt_test::ABC()); + auto result = fmt::format_to_n(buffer, 3, "{}", fmt_test::abc()); EXPECT_EQ(3u, result.size); EXPECT_EQ(buffer + 3, result.out); - EXPECT_EQ("ABCx", fmt::string_view(buffer, 4)); - result = fmt::format_to_n(buffer, 3, "x{}y", fmt_test::ABC()); + EXPECT_EQ("abcx", fmt::string_view(buffer, 4)); + result = fmt::format_to_n(buffer, 3, "x{}y", fmt_test::abc()); EXPECT_EQ(5u, result.size); EXPECT_EQ(buffer + 3, result.out); - EXPECT_EQ("xABx", fmt::string_view(buffer, 4)); -} -#endif - -#if FMT_USE_USER_DEFINED_LITERALS -TEST(FormatTest, UDL) { - using namespace fmt::literals; - EXPECT_EQ("{}"_format("test"), "test"); + EXPECT_EQ("xabx", fmt::string_view(buffer, 4)); } -#endif template <typename T> struct convertible { T value; @@ -251,9 +209,8 @@ template <typename T> struct convertible { operator T() const { return value; } }; -TEST(OStreamTest, DisableBuiltinOStreamOperators) { +TEST(ostream_test, disable_builtin_ostream_operators) { EXPECT_EQ("42", fmt::format("{:d}", convertible<unsigned short>(42))); - EXPECT_EQ(L"42", fmt::format(L"{:d}", convertible<unsigned short>(42))); EXPECT_EQ("foo", fmt::format("{}", convertible<const char*>("foo"))); } @@ -271,7 +228,7 @@ std::ostream& operator<<(std::ostream& os, return os << "bar"; } -TEST(OStreamTest, FormatExplicitlyConvertibleToStringLike) { +TEST(ostream_test, format_explicitly_convertible_to_string_like) { EXPECT_EQ("bar", fmt::format("{}", explicitly_convertible_to_string_like())); } @@ -287,7 +244,7 @@ std::ostream& operator<<(std::ostream& os, return os << "bar"; } -TEST(OStreamTest, FormatExplicitlyConvertibleToStdStringView) { +TEST(ostream_test, format_explicitly_convertible_to_std_string_view) { EXPECT_EQ("bar", fmt::format("{}", explicitly_convertible_to_string_like())); } #endif // FMT_USE_STRING_VIEW @@ -300,8 +257,9 @@ std::ostream& operator<<(std::ostream& os, streamable_and_convertible_to_bool) { return os << "foo"; } -TEST(OStreamTest, FormatConvertibleToBool) { - EXPECT_EQ("foo", fmt::format("{}", streamable_and_convertible_to_bool())); +TEST(ostream_test, format_convertible_to_bool) { + // operator<< is intentionally not used because of potential ODR violations. + EXPECT_EQ(fmt::format("{}", streamable_and_convertible_to_bool()), "true"); } struct copyfmt_test {}; @@ -312,19 +270,32 @@ std::ostream& operator<<(std::ostream& os, copyfmt_test) { return os << "foo"; } -TEST(OStreamTest, CopyFmt) { +TEST(ostream_test, copyfmt) { EXPECT_EQ("foo", fmt::format("{}", copyfmt_test())); } -TEST(OStreamTest, CompileTimeString) { - EXPECT_EQ("42", fmt::format(FMT_STRING("{}"), 42)); +TEST(ostream_test, to_string) { + EXPECT_EQ("abc", fmt::to_string(fmt_test::abc())); } -TEST(OStreamTest, ToString) { - EXPECT_EQ("ABC", fmt::to_string(fmt_test::ABC())); +TEST(ostream_test, range) { + auto strs = std::vector<test_string>{test_string("foo"), test_string("bar")}; + EXPECT_EQ("[foo, bar]", fmt::format("{}", strs)); } -TEST(OStreamTest, Range) { - auto strs = std::vector<TestString>{TestString("foo"), TestString("bar")}; - EXPECT_EQ("{foo, bar}", format("{}", strs)); -}
\ No newline at end of file +struct abstract { + virtual ~abstract() = default; + virtual void f() = 0; + friend std::ostream& operator<<(std::ostream& os, const abstract&) { + return os; + } +}; + +void format_abstract_compiles(const abstract& a) { + fmt::format(FMT_COMPILE("{}"), a); +} + +TEST(ostream_test, is_formattable) { + EXPECT_TRUE(fmt::is_formattable<std::string>()); + EXPECT_TRUE(fmt::is_formattable<fmt::detail::std_string_view<char>>()); +} diff --git a/contrib/libs/fmt/test/posix-mock-test.cc b/contrib/libs/fmt/test/posix-mock-test.cc index 0ea1b9c6d5..3a20b269a4 100644 --- a/contrib/libs/fmt/test/posix-mock-test.cc +++ b/contrib/libs/fmt/test/posix-mock-test.cc @@ -23,20 +23,23 @@ #ifdef _WIN32 # include <io.h> # undef max -# undef ERROR #endif -#include <gmock/gmock.h> +#include "gmock/gmock.h" #include "gtest-extra.h" #include "util.h" using fmt::buffered_file; -using fmt::error_code; using testing::_; using testing::Return; using testing::StrEq; +template <typename Mock> struct scoped_mock : testing::StrictMock<Mock> { + scoped_mock() { Mock::instance = this; } + ~scoped_mock() { Mock::instance = nullptr; } +}; + namespace { int open_count; int close_count; @@ -53,7 +56,7 @@ size_t read_nbyte; size_t write_nbyte; bool sysconf_error; -enum { NONE, MAX_SIZE, ERROR } fstat_sim; +enum { none, max_size, error } fstat_sim; } // namespace #define EMULATE_EINTR(func, error_result) \ @@ -91,7 +94,7 @@ static off_t max_file_size() { return std::numeric_limits<off_t>::max(); } int test::fstat(int fd, struct stat* buf) { int result = ::fstat(fd, buf); - if (fstat_sim == MAX_SIZE) buf->st_size = max_file_size(); + if (fstat_sim == max_size) buf->st_size = max_file_size(); return result; } @@ -100,11 +103,11 @@ int test::fstat(int fd, struct stat* buf) { static LONGLONG max_file_size() { return std::numeric_limits<LONGLONG>::max(); } DWORD test::GetFileSize(HANDLE hFile, LPDWORD lpFileSizeHigh) { - if (fstat_sim == ERROR) { + if (fstat_sim == error) { SetLastError(ERROR_ACCESS_DENIED); return INVALID_FILE_SIZE; } - if (fstat_sim == MAX_SIZE) { + if (fstat_sim == max_size) { DWORD max = std::numeric_limits<DWORD>::max(); *lpFileSizeHigh = max >> 1; return max; @@ -194,15 +197,15 @@ int(test::fileno)(FILE* stream) { # define EXPECT_EQ_POSIX(expected, actual) #endif -static void write_file(fmt::cstring_view filename, fmt::string_view content) { +#if FMT_USE_FCNTL +void write_file(fmt::cstring_view filename, fmt::string_view content) { fmt::buffered_file f(filename, "w"); f.print("{}", content); } -#if FMT_USE_FCNTL using fmt::file; -TEST(UtilTest, GetPageSize) { +TEST(os_test, getpagesize) { # ifdef _WIN32 SYSTEM_INFO si = {}; GetSystemInfo(&si); @@ -216,7 +219,7 @@ TEST(UtilTest, GetPageSize) { # endif } -TEST(FileTest, OpenRetry) { +TEST(file_test, open_retry) { write_file("temp", "there must be something here"); std::unique_ptr<file> f{nullptr}; EXPECT_RETRY(f.reset(new file("temp", file::RDONLY)), open, @@ -227,7 +230,7 @@ TEST(FileTest, OpenRetry) { # endif } -TEST(FileTest, CloseNoRetryInDtor) { +TEST(file_test, close_no_retry_in_dtor) { file read_end, write_end; file::pipe(read_end, write_end); std::unique_ptr<file> f(new file(std::move(read_end))); @@ -240,11 +243,11 @@ TEST(FileTest, CloseNoRetryInDtor) { saved_close_count = close_count; close_count = 0; }, - format_system_error(EINTR, "cannot close file") + "\n"); + system_error_message(EINTR, "cannot close file") + "\n"); EXPECT_EQ(2, saved_close_count); } -TEST(FileTest, CloseNoRetry) { +TEST(file_test, close_no_retry) { file read_end, write_end; file::pipe(read_end, write_end); close_count = 1; @@ -253,35 +256,39 @@ TEST(FileTest, CloseNoRetry) { close_count = 0; } -TEST(FileTest, Size) { +TEST(file_test, size) { std::string content = "top secret, destroy before reading"; write_file("temp", content); file f("temp", file::RDONLY); EXPECT_GE(f.size(), 0); EXPECT_EQ(content.size(), static_cast<unsigned long long>(f.size())); # ifdef _WIN32 - fmt::memory_buffer message; - fmt::detail::format_windows_error(message, ERROR_ACCESS_DENIED, - "cannot get file size"); - fstat_sim = ERROR; - EXPECT_THROW_MSG(f.size(), fmt::windows_error, fmt::to_string(message)); - fstat_sim = NONE; + auto error_code = std::error_code(); + fstat_sim = error; + try { + f.size(); + } catch (const std::system_error& e) { + error_code = e.code(); + } + fstat_sim = none; + EXPECT_EQ(error_code, + std::error_code(ERROR_ACCESS_DENIED, fmt::system_category())); # else f.close(); EXPECT_SYSTEM_ERROR(f.size(), EBADF, "cannot get file attributes"); # endif } -TEST(FileTest, MaxSize) { +TEST(file_test, max_size) { write_file("temp", ""); file f("temp", file::RDONLY); - fstat_sim = MAX_SIZE; + fstat_sim = max_size; EXPECT_GE(f.size(), 0); EXPECT_EQ(max_file_size(), f.size()); - fstat_sim = NONE; + fstat_sim = none; } -TEST(FileTest, ReadRetry) { +TEST(file_test, read_retry) { file read_end, write_end; file::pipe(read_end, write_end); enum { SIZE = 4 }; @@ -294,7 +301,7 @@ TEST(FileTest, ReadRetry) { EXPECT_EQ_POSIX(static_cast<std::streamsize>(SIZE), count); } -TEST(FileTest, WriteRetry) { +TEST(file_test, write_retry) { file read_end, write_end; file::pipe(read_end, write_end); enum { SIZE = 4 }; @@ -312,7 +319,7 @@ TEST(FileTest, WriteRetry) { } # ifdef _WIN32 -TEST(FileTest, ConvertReadCount) { +TEST(file_test, convert_read_count) { file read_end, write_end; file::pipe(read_end, write_end); char c; @@ -320,12 +327,12 @@ TEST(FileTest, ConvertReadCount) { if (sizeof(unsigned) != sizeof(size_t)) ++size; read_count = 1; read_nbyte = 0; - EXPECT_THROW(read_end.read(&c, size), fmt::system_error); + EXPECT_THROW(read_end.read(&c, size), std::system_error); read_count = 0; EXPECT_EQ(UINT_MAX, read_nbyte); } -TEST(FileTest, ConvertWriteCount) { +TEST(file_test, convert_write_count) { file read_end, write_end; file::pipe(read_end, write_end); char c; @@ -333,13 +340,13 @@ TEST(FileTest, ConvertWriteCount) { if (sizeof(unsigned) != sizeof(size_t)) ++size; write_count = 1; write_nbyte = 0; - EXPECT_THROW(write_end.write(&c, size), fmt::system_error); + EXPECT_THROW(write_end.write(&c, size), std::system_error); write_count = 0; EXPECT_EQ(UINT_MAX, write_nbyte); } # endif -TEST(FileTest, DupNoRetry) { +TEST(file_test, dup_no_retry) { int stdout_fd = FMT_POSIX(fileno(stdout)); dup_count = 1; EXPECT_SYSTEM_ERROR( @@ -348,7 +355,7 @@ TEST(FileTest, DupNoRetry) { dup_count = 0; } -TEST(FileTest, Dup2Retry) { +TEST(file_test, dup2_retry) { int stdout_fd = FMT_POSIX(fileno(stdout)); file f1 = file::dup(stdout_fd), f2 = file::dup(stdout_fd); EXPECT_RETRY(f1.dup2(f2.descriptor()), dup2, @@ -356,21 +363,21 @@ TEST(FileTest, Dup2Retry) { f1.descriptor(), f2.descriptor())); } -TEST(FileTest, Dup2NoExceptRetry) { +TEST(file_test, dup2_no_except_retry) { int stdout_fd = FMT_POSIX(fileno(stdout)); file f1 = file::dup(stdout_fd), f2 = file::dup(stdout_fd); - error_code ec; + std::error_code ec; dup2_count = 1; f1.dup2(f2.descriptor(), ec); # ifndef _WIN32 EXPECT_EQ(4, dup2_count); # else - EXPECT_EQ(EINTR, ec.get()); + EXPECT_EQ(EINTR, ec.value()); # endif dup2_count = 0; } -TEST(FileTest, PipeNoRetry) { +TEST(file_test, pipe_no_retry) { file read_end, write_end; pipe_count = 1; EXPECT_SYSTEM_ERROR(file::pipe(read_end, write_end), EINTR, @@ -378,7 +385,7 @@ TEST(FileTest, PipeNoRetry) { pipe_count = 0; } -TEST(FileTest, FdopenNoRetry) { +TEST(file_test, fdopen_no_retry) { file read_end, write_end; file::pipe(read_end, write_end); fdopen_count = 1; @@ -387,7 +394,7 @@ TEST(FileTest, FdopenNoRetry) { fdopen_count = 0; } -TEST(BufferedFileTest, OpenRetry) { +TEST(buffered_file_test, open_retry) { write_file("temp", "there must be something here"); std::unique_ptr<buffered_file> f{nullptr}; EXPECT_RETRY(f.reset(new buffered_file("temp", "r")), fopen, @@ -399,7 +406,7 @@ TEST(BufferedFileTest, OpenRetry) { # endif } -TEST(BufferedFileTest, CloseNoRetryInDtor) { +TEST(buffered_file_test, close_no_retry_in_dtor) { file read_end, write_end; file::pipe(read_end, write_end); std::unique_ptr<buffered_file> f(new buffered_file(read_end.fdopen("r"))); @@ -412,11 +419,11 @@ TEST(BufferedFileTest, CloseNoRetryInDtor) { saved_fclose_count = fclose_count; fclose_count = 0; }, - format_system_error(EINTR, "cannot close file") + "\n"); + system_error_message(EINTR, "cannot close file") + "\n"); EXPECT_EQ(2, saved_fclose_count); } -TEST(BufferedFileTest, CloseNoRetry) { +TEST(buffered_file_test, close_no_retry) { file read_end, write_end; file::pipe(read_end, write_end); buffered_file f = read_end.fdopen("r"); @@ -426,7 +433,7 @@ TEST(BufferedFileTest, CloseNoRetry) { fclose_count = 0; } -TEST(BufferedFileTest, FilenoNoRetry) { +TEST(buffered_file_test, fileno_no_retry) { file read_end, write_end; file::pipe(read_end, write_end); buffered_file f = read_end.fdopen("r"); @@ -441,9 +448,9 @@ struct test_mock { static test_mock* instance; } * test_mock::instance; -TEST(ScopedMock, Scope) { +TEST(scoped_mock, scope) { { - ScopedMock<test_mock> mock; + scoped_mock<test_mock> mock; EXPECT_EQ(&mock, test_mock::instance); test_mock& copy = mock; static_cast<void>(copy); @@ -453,16 +460,13 @@ TEST(ScopedMock, Scope) { #if defined(FMT_LOCALE) && !defined(_LIBCPP_VERSION) -typedef fmt::locale::type locale_type; +using locale_type = fmt::locale::type; struct locale_mock { static locale_mock* instance; MOCK_METHOD3(newlocale, locale_type(int category_mask, const char* locale, locale_type base)); MOCK_METHOD1(freelocale, void(locale_type locale)); - - MOCK_METHOD3(strtod_l, - double(const char* nptr, char** endptr, locale_type locale)); } * locale_mock::instance; # ifdef _MSC_VER @@ -480,17 +484,14 @@ _locale_t _create_locale(int category, const char* locale) { void _free_locale(_locale_t locale) { locale_mock::instance->freelocale(locale); } - -double _strtod_l(const char* nptr, char** endptr, _locale_t locale) { - return locale_mock::instance->strtod_l(nptr, endptr, locale); -} # ifdef __clang__ # pragma clang diagnostic pop # endif # pragma warning(pop) # endif -# if defined(__THROW) && FMT_GCC_VERSION > 0 && FMT_GCC_VERSION <= 408 +# if defined(__THROW) && \ + ((FMT_GCC_VERSION > 0 && FMT_GCC_VERSION <= 408) || defined(__e2k__)) # define FMT_LOCALE_THROW __THROW # else # define FMT_LOCALE_THROW @@ -508,11 +509,6 @@ FreeLocaleResult freelocale(locale_type locale) FMT_LOCALE_THROW { return FreeLocaleResult(); } -double strtod_l(const char* nptr, char** endptr, - locale_type locale) FMT_LOCALE_THROW { - return locale_mock::instance->strtod_l(nptr, endptr, locale); -} - # undef FMT_LOCALE_THROW # if !defined(_WIN32) || defined(_LIBCPP_VERSION) @@ -520,20 +516,20 @@ locale_t test::newlocale(int category_mask, const char* locale, locale_t base) { return locale_mock::instance->newlocale(category_mask, locale, base); } -TEST(LocaleTest, LocaleMock) { - ScopedMock<locale_mock> mock; - locale_type locale = reinterpret_cast<locale_type>(11); +TEST(locale_test, locale_mock) { + scoped_mock<locale_mock> mock; + auto locale = reinterpret_cast<locale_type>(11); EXPECT_CALL(mock, newlocale(222, StrEq("foo"), locale)); FMT_SYSTEM(newlocale(222, "foo", locale)); } # endif -TEST(LocaleTest, Locale) { +TEST(locale_test, locale) { # ifndef LC_NUMERIC_MASK enum { LC_NUMERIC_MASK = LC_NUMERIC }; # endif - ScopedMock<locale_mock> mock; - locale_type impl = reinterpret_cast<locale_type>(42); + scoped_mock<locale_mock> mock; + auto impl = reinterpret_cast<locale_type>(42); EXPECT_CALL(mock, newlocale(LC_NUMERIC_MASK, StrEq("C"), nullptr)) .WillOnce(Return(impl)); EXPECT_CALL(mock, freelocale(impl)); @@ -541,18 +537,4 @@ TEST(LocaleTest, Locale) { EXPECT_EQ(impl, loc.get()); } -TEST(LocaleTest, Strtod) { - ScopedMock<locale_mock> mock; - EXPECT_CALL(mock, newlocale(_, _, _)) - .WillOnce(Return(reinterpret_cast<locale_type>(42))); - EXPECT_CALL(mock, freelocale(_)); - fmt::locale loc; - const char* str = "4.2"; - char end = 'x'; - EXPECT_CALL(mock, strtod_l(str, _, loc.get())) - .WillOnce(testing::DoAll(testing::SetArgPointee<1>(&end), Return(777))); - EXPECT_EQ(777, loc.strtod(str)); - EXPECT_EQ(&end, str); -} - #endif // FMT_LOCALE diff --git a/contrib/libs/fmt/test/printf-test.cc b/contrib/libs/fmt/test/printf-test.cc index ccd72dcd75..0bb9ccdaf6 100644 --- a/contrib/libs/fmt/test/printf-test.cc +++ b/contrib/libs/fmt/test/printf-test.cc @@ -11,7 +11,8 @@ #include <climits> #include <cstring> -#include "fmt/core.h" +#include "fmt/ostream.h" +#include "fmt/xchar.h" #include "gtest-extra.h" #include "util.h" @@ -19,7 +20,7 @@ using fmt::format; using fmt::format_error; using fmt::detail::max_value; -const unsigned BIG_NUM = INT_MAX + 1u; +const unsigned big_num = INT_MAX + 1u; // Makes format string argument positional. static std::string make_positional(fmt::string_view format) { @@ -28,7 +29,7 @@ static std::string make_positional(fmt::string_view format) { return s; } -static std::wstring make_positional(fmt::wstring_view format) { +static std::wstring make_positional(fmt::basic_string_view<wchar_t> format) { std::wstring s(format.data(), format.size()); s.replace(s.find(L'%'), 1, L"%1$"); return s; @@ -41,7 +42,8 @@ std::string test_sprintf(fmt::string_view format, const Args&... args) { return fmt::sprintf(format, args...); } template <typename... Args> -std::wstring test_sprintf(fmt::wstring_view format, const Args&... args) { +std::wstring test_sprintf(fmt::basic_string_view<wchar_t> format, + const Args&... args) { return fmt::sprintf(format, args...); } @@ -50,12 +52,12 @@ std::wstring test_sprintf(fmt::wstring_view format, const Args&... args) { << "format: " << format; \ EXPECT_EQ(expected_output, fmt::sprintf(make_positional(format), arg)) -TEST(PrintfTest, NoArgs) { +TEST(printf_test, no_args) { EXPECT_EQ("test", test_sprintf("test")); EXPECT_EQ(L"test", fmt::sprintf(L"test")); } -TEST(PrintfTest, Escape) { +TEST(printf_test, escape) { EXPECT_EQ("%", test_sprintf("%%")); EXPECT_EQ("before %", test_sprintf("before %%")); EXPECT_EQ("% after", test_sprintf("%% after")); @@ -68,7 +70,7 @@ TEST(PrintfTest, Escape) { EXPECT_EQ(L"%s", fmt::sprintf(L"%%s")); } -TEST(PrintfTest, PositionalArgs) { +TEST(printf_test, positional_args) { EXPECT_EQ("42", test_sprintf("%1$d", 42)); EXPECT_EQ("before 42", test_sprintf("before %1$d", 42)); EXPECT_EQ("42 after", test_sprintf("%1$d after", 42)); @@ -78,40 +80,40 @@ TEST(PrintfTest, PositionalArgs) { EXPECT_EQ("abracadabra", test_sprintf("%1$s%2$s%1$s", "abra", "cad")); } -TEST(PrintfTest, AutomaticArgIndexing) { +TEST(printf_test, automatic_arg_indexing) { EXPECT_EQ("abc", test_sprintf("%c%c%c", 'a', 'b', 'c')); } -TEST(PrintfTest, NumberIsTooBigInArgIndex) { - EXPECT_THROW_MSG(test_sprintf(format("%{}$", BIG_NUM)), format_error, - "number is too big"); - EXPECT_THROW_MSG(test_sprintf(format("%{}$d", BIG_NUM)), format_error, - "number is too big"); +TEST(printf_test, number_is_too_big_in_arg_index) { + EXPECT_THROW_MSG(test_sprintf(format("%{}$", big_num)), format_error, + "argument not found"); + EXPECT_THROW_MSG(test_sprintf(format("%{}$d", big_num)), format_error, + "argument not found"); } -TEST(PrintfTest, SwitchArgIndexing) { +TEST(printf_test, switch_arg_indexing) { EXPECT_THROW_MSG(test_sprintf("%1$d%", 1, 2), format_error, "cannot switch from manual to automatic argument indexing"); - EXPECT_THROW_MSG(test_sprintf(format("%1$d%{}d", BIG_NUM), 1, 2), + EXPECT_THROW_MSG(test_sprintf(format("%1$d%{}d", big_num), 1, 2), format_error, "number is too big"); EXPECT_THROW_MSG(test_sprintf("%1$d%d", 1, 2), format_error, "cannot switch from manual to automatic argument indexing"); EXPECT_THROW_MSG(test_sprintf("%d%1$", 1, 2), format_error, "cannot switch from automatic to manual argument indexing"); - EXPECT_THROW_MSG(test_sprintf(format("%d%{}$d", BIG_NUM), 1, 2), format_error, - "number is too big"); + EXPECT_THROW_MSG(test_sprintf(format("%d%{}$d", big_num), 1, 2), format_error, + "cannot switch from automatic to manual argument indexing"); EXPECT_THROW_MSG(test_sprintf("%d%1$d", 1, 2), format_error, "cannot switch from automatic to manual argument indexing"); // Indexing errors override width errors. - EXPECT_THROW_MSG(test_sprintf(format("%d%1${}d", BIG_NUM), 1, 2), + EXPECT_THROW_MSG(test_sprintf(format("%d%1${}d", big_num), 1, 2), format_error, "number is too big"); - EXPECT_THROW_MSG(test_sprintf(format("%1$d%{}d", BIG_NUM), 1, 2), + EXPECT_THROW_MSG(test_sprintf(format("%1$d%{}d", big_num), 1, 2), format_error, "number is too big"); } -TEST(PrintfTest, InvalidArgIndex) { +TEST(printf_test, invalid_arg_index) { EXPECT_THROW_MSG(test_sprintf("%0$d", 42), format_error, "argument not found"); EXPECT_THROW_MSG(test_sprintf("%2$d", 42), format_error, @@ -120,16 +122,16 @@ TEST(PrintfTest, InvalidArgIndex) { "argument not found"); EXPECT_THROW_MSG(test_sprintf("%2$", 42), format_error, "argument not found"); - EXPECT_THROW_MSG(test_sprintf(format("%{}$d", BIG_NUM), 42), format_error, - "number is too big"); + EXPECT_THROW_MSG(test_sprintf(format("%{}$d", big_num), 42), format_error, + "argument not found"); } -TEST(PrintfTest, DefaultAlignRight) { +TEST(printf_test, default_align_right) { EXPECT_PRINTF(" 42", "%5d", 42); EXPECT_PRINTF(" abc", "%5s", "abc"); } -TEST(PrintfTest, ZeroFlag) { +TEST(printf_test, zero_flag) { EXPECT_PRINTF("00042", "%05d", 42); EXPECT_PRINTF("-0042", "%05d", -42); @@ -146,7 +148,7 @@ TEST(PrintfTest, ZeroFlag) { EXPECT_PRINTF(" x", "%05c", 'x'); } -TEST(PrintfTest, PlusFlag) { +TEST(printf_test, plus_flag) { EXPECT_PRINTF("+42", "%+d", 42); EXPECT_PRINTF("-42", "%+d", -42); EXPECT_PRINTF("+0042", "%+05d", 42); @@ -168,7 +170,7 @@ TEST(PrintfTest, PlusFlag) { EXPECT_PRINTF("x", "% +c", 'x'); } -TEST(PrintfTest, MinusFlag) { +TEST(printf_test, minus_flag) { EXPECT_PRINTF("abc ", "%-5s", "abc"); EXPECT_PRINTF("abc ", "%0--5s", "abc"); @@ -188,7 +190,7 @@ TEST(PrintfTest, MinusFlag) { EXPECT_PRINTF(" 42", "%- d", 42); } -TEST(PrintfTest, SpaceFlag) { +TEST(printf_test, space_flag) { EXPECT_PRINTF(" 42", "% d", 42); EXPECT_PRINTF("-42", "% d", -42); EXPECT_PRINTF(" 0042", "% 05d", 42); @@ -198,7 +200,7 @@ TEST(PrintfTest, SpaceFlag) { EXPECT_PRINTF("x", "% c", 'x'); } -TEST(PrintfTest, HashFlag) { +TEST(printf_test, hash_flag) { EXPECT_PRINTF("042", "%#o", 042); EXPECT_PRINTF(fmt::format("0{:o}", static_cast<unsigned>(-042)), "%#o", -042); EXPECT_PRINTF("0", "%#o", 0); @@ -215,7 +217,7 @@ TEST(PrintfTest, HashFlag) { EXPECT_PRINTF("-42.000000", "%#f", -42.0); EXPECT_PRINTF("-42.000000", "%#F", -42.0); - char buffer[BUFFER_SIZE]; + char buffer[256]; safe_sprintf(buffer, "%#e", -42.0); EXPECT_PRINTF(buffer, "%#e", -42.0); safe_sprintf(buffer, "%#E", -42.0); @@ -233,30 +235,30 @@ TEST(PrintfTest, HashFlag) { EXPECT_PRINTF("x", "%#c", 'x'); } -TEST(PrintfTest, Width) { +TEST(printf_test, width) { EXPECT_PRINTF(" abc", "%5s", "abc"); // Width cannot be specified twice. EXPECT_THROW_MSG(test_sprintf("%5-5d", 42), format_error, "invalid type specifier"); - EXPECT_THROW_MSG(test_sprintf(format("%{}d", BIG_NUM), 42), format_error, + EXPECT_THROW_MSG(test_sprintf(format("%{}d", big_num), 42), format_error, "number is too big"); - EXPECT_THROW_MSG(test_sprintf(format("%1${}d", BIG_NUM), 42), format_error, + EXPECT_THROW_MSG(test_sprintf(format("%1${}d", big_num), 42), format_error, "number is too big"); } -TEST(PrintfTest, DynamicWidth) { +TEST(printf_test, dynamic_width) { EXPECT_EQ(" 42", test_sprintf("%*d", 5, 42)); EXPECT_EQ("42 ", test_sprintf("%*d", -5, 42)); EXPECT_THROW_MSG(test_sprintf("%*d", 5.0, 42), format_error, "width is not integer"); EXPECT_THROW_MSG(test_sprintf("%*d"), format_error, "argument not found"); - EXPECT_THROW_MSG(test_sprintf("%*d", BIG_NUM, 42), format_error, + EXPECT_THROW_MSG(test_sprintf("%*d", big_num, 42), format_error, "number is too big"); } -TEST(PrintfTest, IntPrecision) { +TEST(printf_test, int_precision) { EXPECT_PRINTF("00042", "%.5d", 42); EXPECT_PRINTF("-00042", "%.5d", -42); EXPECT_PRINTF("00042", "%.5x", 0x42); @@ -277,8 +279,8 @@ TEST(PrintfTest, IntPrecision) { EXPECT_PRINTF("00042 ", "%-#10.5o", 042); } -TEST(PrintfTest, FloatPrecision) { - char buffer[BUFFER_SIZE]; +TEST(printf_test, float_precision) { + char buffer[256]; safe_sprintf(buffer, "%.3e", 1234.5678); EXPECT_PRINTF(buffer, "%.3e", 1234.5678); EXPECT_PRINTF("1234.568", "%.3f", 1234.5678); @@ -287,22 +289,22 @@ TEST(PrintfTest, FloatPrecision) { EXPECT_PRINTF(buffer, "%.3a", 1234.5678); } -TEST(PrintfTest, StringPrecision) { +TEST(printf_test, string_precision) { char test[] = {'H', 'e', 'l', 'l', 'o'}; EXPECT_EQ(fmt::sprintf("%.4s", test), "Hell"); } -TEST(PrintfTest, IgnorePrecisionForNonNumericArg) { +TEST(printf_test, ignore_precision_for_non_numeric_arg) { EXPECT_PRINTF("abc", "%.5s", "abc"); } -TEST(PrintfTest, DynamicPrecision) { +TEST(printf_test, dynamic_precision) { EXPECT_EQ("00042", test_sprintf("%.*d", 5, 42)); EXPECT_EQ("42", test_sprintf("%.*d", -5, 42)); EXPECT_THROW_MSG(test_sprintf("%.*d", 5.0, 42), format_error, "precision is not integer"); EXPECT_THROW_MSG(test_sprintf("%.*d"), format_error, "argument not found"); - EXPECT_THROW_MSG(test_sprintf("%.*d", BIG_NUM, 42), format_error, + EXPECT_THROW_MSG(test_sprintf("%.*d", big_num, 42), format_error, "number is too big"); if (sizeof(long long) != sizeof(int)) { long long prec = static_cast<long long>(INT_MIN) - 1; @@ -325,7 +327,7 @@ SPECIALIZE_MAKE_SIGNED(unsigned long long, long long); // Test length format specifier ``length_spec``. template <typename T, typename U> -void TestLength(const char* length_spec, U value) { +void test_length(const char* length_spec, U value) { long long signed_value = 0; unsigned long long unsigned_value = 0; // Apply integer promotion to the argument. @@ -364,54 +366,54 @@ void TestLength(const char* length_spec, U value) { EXPECT_PRINTF(os.str(), fmt::format("%{}X", length_spec), value); } -template <typename T> void TestLength(const char* length_spec) { +template <typename T> void test_length(const char* length_spec) { T min = std::numeric_limits<T>::min(), max = max_value<T>(); - TestLength<T>(length_spec, 42); - TestLength<T>(length_spec, -42); - TestLength<T>(length_spec, min); - TestLength<T>(length_spec, max); + test_length<T>(length_spec, 42); + test_length<T>(length_spec, -42); + test_length<T>(length_spec, min); + test_length<T>(length_spec, max); long long long_long_min = std::numeric_limits<long long>::min(); if (static_cast<long long>(min) > long_long_min) - TestLength<T>(length_spec, static_cast<long long>(min) - 1); + test_length<T>(length_spec, static_cast<long long>(min) - 1); unsigned long long long_long_max = max_value<long long>(); if (static_cast<unsigned long long>(max) < long_long_max) - TestLength<T>(length_spec, static_cast<long long>(max) + 1); - TestLength<T>(length_spec, std::numeric_limits<short>::min()); - TestLength<T>(length_spec, max_value<unsigned short>()); - TestLength<T>(length_spec, std::numeric_limits<int>::min()); - TestLength<T>(length_spec, max_value<int>()); - TestLength<T>(length_spec, std::numeric_limits<unsigned>::min()); - TestLength<T>(length_spec, max_value<unsigned>()); - TestLength<T>(length_spec, std::numeric_limits<long long>::min()); - TestLength<T>(length_spec, max_value<long long>()); - TestLength<T>(length_spec, std::numeric_limits<unsigned long long>::min()); - TestLength<T>(length_spec, max_value<unsigned long long>()); -} - -TEST(PrintfTest, Length) { - TestLength<char>("hh"); - TestLength<signed char>("hh"); - TestLength<unsigned char>("hh"); - TestLength<short>("h"); - TestLength<unsigned short>("h"); - TestLength<long>("l"); - TestLength<unsigned long>("l"); - TestLength<long long>("ll"); - TestLength<unsigned long long>("ll"); - TestLength<intmax_t>("j"); - TestLength<size_t>("z"); - TestLength<std::ptrdiff_t>("t"); + test_length<T>(length_spec, static_cast<long long>(max) + 1); + test_length<T>(length_spec, std::numeric_limits<short>::min()); + test_length<T>(length_spec, max_value<unsigned short>()); + test_length<T>(length_spec, std::numeric_limits<int>::min()); + test_length<T>(length_spec, max_value<int>()); + test_length<T>(length_spec, std::numeric_limits<unsigned>::min()); + test_length<T>(length_spec, max_value<unsigned>()); + test_length<T>(length_spec, std::numeric_limits<long long>::min()); + test_length<T>(length_spec, max_value<long long>()); + test_length<T>(length_spec, std::numeric_limits<unsigned long long>::min()); + test_length<T>(length_spec, max_value<unsigned long long>()); +} + +TEST(printf_test, length) { + test_length<char>("hh"); + test_length<signed char>("hh"); + test_length<unsigned char>("hh"); + test_length<short>("h"); + test_length<unsigned short>("h"); + test_length<long>("l"); + test_length<unsigned long>("l"); + test_length<long long>("ll"); + test_length<unsigned long long>("ll"); + test_length<intmax_t>("j"); + test_length<size_t>("z"); + test_length<std::ptrdiff_t>("t"); long double max = max_value<long double>(); EXPECT_PRINTF(fmt::format("{:.6}", max), "%g", max); EXPECT_PRINTF(fmt::format("{:.6}", max), "%Lg", max); } -TEST(PrintfTest, Bool) { +TEST(printf_test, bool) { EXPECT_PRINTF("1", "%d", true); EXPECT_PRINTF("true", "%s", true); } -TEST(PrintfTest, Int) { +TEST(printf_test, int) { EXPECT_PRINTF("-42", "%d", -42); EXPECT_PRINTF("-42", "%i", -42); unsigned u = 0 - 42u; @@ -421,20 +423,20 @@ TEST(PrintfTest, Int) { EXPECT_PRINTF(fmt::format("{:X}", u), "%X", -42); } -TEST(PrintfTest, long_long) { +TEST(printf_test, long_long) { // fmt::printf allows passing long long arguments to %d without length // specifiers. long long max = max_value<long long>(); EXPECT_PRINTF(fmt::format("{}", max), "%d", max); } -TEST(PrintfTest, Float) { +TEST(printf_test, float) { EXPECT_PRINTF("392.650000", "%f", 392.65); EXPECT_PRINTF("392.65", "%.2f", 392.65); EXPECT_PRINTF("392.6", "%.1f", 392.65); EXPECT_PRINTF("393", "%.f", 392.65); EXPECT_PRINTF("392.650000", "%F", 392.65); - char buffer[BUFFER_SIZE]; + char buffer[256]; safe_sprintf(buffer, "%e", 392.65); EXPECT_PRINTF(buffer, "%e", 392.65); safe_sprintf(buffer, "%E", 392.65); @@ -450,7 +452,7 @@ TEST(PrintfTest, Float) { EXPECT_EQ(buffer, format("{:A}", -392.65)); } -TEST(PrintfTest, Inf) { +TEST(printf_test, inf) { double inf = std::numeric_limits<double>::infinity(); for (const char* type = "fega"; *type; ++type) { EXPECT_PRINTF("inf", fmt::format("%{}", *type), inf); @@ -459,7 +461,7 @@ TEST(PrintfTest, Inf) { } } -TEST(PrintfTest, Char) { +TEST(printf_test, char) { EXPECT_PRINTF("x", "%c", 'x'); int max = max_value<int>(); EXPECT_PRINTF(fmt::format("{}", static_cast<char>(max)), "%c", max); @@ -468,7 +470,7 @@ TEST(PrintfTest, Char) { EXPECT_PRINTF(fmt::format(L"{}", static_cast<wchar_t>(max)), L"%c", max); } -TEST(PrintfTest, String) { +TEST(printf_test, string) { EXPECT_PRINTF("abc", "%s", "abc"); const char* null_str = nullptr; EXPECT_PRINTF("(null)", "%s", null_str); @@ -479,13 +481,7 @@ TEST(PrintfTest, String) { EXPECT_PRINTF(L" (null)", L"%10s", null_wstr); } -TEST(PrintfTest, UCharString) { - unsigned char str[] = "test"; - unsigned char* pstr = str; - EXPECT_EQ("test", fmt::sprintf("%s", pstr)); -} - -TEST(PrintfTest, Pointer) { +TEST(printf_test, pointer) { int n; void* p = &n; EXPECT_PRINTF(fmt::format("{}", p), "%p", p); @@ -508,20 +504,16 @@ TEST(PrintfTest, Pointer) { EXPECT_PRINTF(L"(nil)", L"%p", null_wstr); } -TEST(PrintfTest, Location) { - // TODO: test %n -} - enum test_enum { answer = 42 }; -TEST(PrintfTest, Enum) { +TEST(printf_test, enum) { EXPECT_PRINTF("42", "%d", answer); volatile test_enum volatile_enum = answer; EXPECT_PRINTF("42", "%d", volatile_enum); } #if FMT_USE_FCNTL -TEST(PrintfTest, Examples) { +TEST(printf_test, examples) { const char* weekday = "Thursday"; const char* month = "August"; int day = 21; @@ -529,7 +521,7 @@ TEST(PrintfTest, Examples) { "Thursday, 21 August"); } -TEST(PrintfTest, PrintfError) { +TEST(printf_test, printf_error) { fmt::file read_end, write_end; fmt::file::pipe(read_end, write_end); int result = fmt::fprintf(read_end.fdopen("r").get(), "test"); @@ -537,26 +529,20 @@ TEST(PrintfTest, PrintfError) { } #endif -TEST(PrintfTest, WideString) { EXPECT_EQ(L"abc", fmt::sprintf(L"%s", L"abc")); } - -TEST(PrintfTest, PrintfCustom) { - EXPECT_EQ("abc", test_sprintf("%s", TestString("abc"))); +TEST(printf_test, wide_string) { + EXPECT_EQ(L"abc", fmt::sprintf(L"%s", L"abc")); } -TEST(PrintfTest, OStream) { - std::ostringstream os; - int ret = fmt::fprintf(os, "Don't %s!", "panic"); - EXPECT_EQ("Don't panic!", os.str()); - EXPECT_EQ(12, ret); +TEST(printf_test, printf_custom) { + EXPECT_EQ("abc", test_sprintf("%s", test_string("abc"))); } -TEST(PrintfTest, VPrintf) { +TEST(printf_test, vprintf) { fmt::format_arg_store<fmt::printf_context, int> as{42}; fmt::basic_format_args<fmt::printf_context> args(as); EXPECT_EQ(fmt::vsprintf("%d", args), "42"); EXPECT_WRITE(stdout, fmt::vprintf("%d", args), "42"); EXPECT_WRITE(stdout, fmt::vfprintf(stdout, "%d", args), "42"); - EXPECT_WRITE(stdout, fmt::vfprintf(std::cout, "%d", args), "42"); } template <typename... Args> @@ -564,15 +550,15 @@ void check_format_string_regression(fmt::string_view s, const Args&... args) { fmt::sprintf(s, args...); } -TEST(PrintfTest, CheckFormatStringRegression) { +TEST(printf_test, check_format_string_regression) { check_format_string_regression("%c%s", 'x', ""); } -TEST(PrintfTest, FixedLargeExponent) { +TEST(printf_test, fixed_large_exponent) { EXPECT_EQ("1000000000000000000000", fmt::sprintf("%.*f", -13, 1e21)); } -TEST(PrintfTest, VSPrintfMakeArgsExample) { +TEST(printf_test, vsprintf_make_args_example) { fmt::format_arg_store<fmt::printf_context, int, const char*> as{42, "something"}; fmt::basic_format_args<fmt::printf_context> args(as); @@ -581,15 +567,12 @@ TEST(PrintfTest, VSPrintfMakeArgsExample) { fmt::basic_format_args<fmt::printf_context> args2(as2); EXPECT_EQ("[42] something happened", fmt::vsprintf("[%d] %s happened", args2)); - // The older gcc versions can't cast the return value. -#if !defined(__GNUC__) || (__GNUC__ > 4) EXPECT_EQ("[42] something happened", fmt::vsprintf("[%d] %s happened", {fmt::make_printf_args(42, "something")})); -#endif } -TEST(PrintfTest, VSPrintfMakeWArgsExample) { +TEST(printf_test, vsprintf_make_wargs_example) { fmt::format_arg_store<fmt::wprintf_context, int, const wchar_t*> as{ 42, L"something"}; fmt::basic_format_args<fmt::wprintf_context> args(as); @@ -599,30 +582,7 @@ TEST(PrintfTest, VSPrintfMakeWArgsExample) { fmt::basic_format_args<fmt::wprintf_context> args2(as2); EXPECT_EQ(L"[42] something happened", fmt::vsprintf(L"[%d] %s happened", args2)); - // the older gcc versions can't cast the return value -#if !defined(__GNUC__) || (__GNUC__ > 4) EXPECT_EQ(L"[42] something happened", fmt::vsprintf(L"[%d] %s happened", {fmt::make_wprintf_args(42, L"something")})); -#endif -} - -TEST(PrintfTest, PrintfDetermineOutputSize) { - using backit = std::back_insert_iterator<std::vector<char>>; - using truncated_printf_context = - fmt::basic_printf_context<fmt::detail::truncating_iterator<backit>, char>; - - auto v = std::vector<char>{}; - auto it = std::back_inserter(v); - - const auto format_string = "%s"; - const auto format_arg = "Hello"; - const auto expected_size = fmt::sprintf(format_string, format_arg).size(); - - EXPECT_EQ((truncated_printf_context( - fmt::detail::truncating_iterator<backit>(it, 0), format_string, - fmt::make_format_args<truncated_printf_context>(format_arg)) - .format() - .count()), - expected_size); } diff --git a/contrib/libs/fmt/test/ranges-odr-test.cc b/contrib/libs/fmt/test/ranges-odr-test.cc new file mode 100644 index 0000000000..031354d3c2 --- /dev/null +++ b/contrib/libs/fmt/test/ranges-odr-test.cc @@ -0,0 +1,17 @@ +// Formatting library for C++ - the core API +// +// Copyright (c) 2012 - present, Victor Zverovich +// All rights reserved. +// +// For the license information refer to format.h. + +#include <vector> + +#include "fmt/ranges.h" +#include "gtest/gtest.h" + +// call fmt::format from another translation unit to test ODR +TEST(ranges_odr_test, format_vector) { + auto v = std::vector<int>{1, 2, 3, 5, 7, 11}; + EXPECT_EQ(fmt::format("{}", v), "[1, 2, 3, 5, 7, 11]"); +} diff --git a/contrib/libs/fmt/test/ranges-test.cc b/contrib/libs/fmt/test/ranges-test.cc index 394f7b81be..63cb8c8bca 100644 --- a/contrib/libs/fmt/test/ranges-test.cc +++ b/contrib/libs/fmt/test/ranges-test.cc @@ -11,106 +11,109 @@ #include "fmt/ranges.h" -#include <gtest/gtest.h> +#include <map> +#include <string> +#include <vector> -// Check if 'if constexpr' is supported. -#if (__cplusplus > 201402L) || \ - (defined(_MSVC_LANG) && _MSVC_LANG > 201402L && _MSC_VER >= 1910) +#include "gtest/gtest.h" -# include <array> -# include <map> -# include <string> -# include <vector> +#if !FMT_GCC_VERSION || FMT_GCC_VERSION >= 601 +# define FMT_RANGES_TEST_ENABLE_C_STYLE_ARRAY +#endif -TEST(RangesTest, FormatVector) { - std::vector<int32_t> iv{1, 2, 3, 5, 7, 11}; - auto ivf = fmt::format("{}", iv); - EXPECT_EQ("{1, 2, 3, 5, 7, 11}", ivf); -} +#if !FMT_MSC_VER || FMT_MSC_VER > 1910 +# define FMT_RANGES_TEST_ENABLE_JOIN +# define FMT_RANGES_TEST_ENABLE_FORMAT_STRUCT +#endif -TEST(RangesTest, FormatVector2) { - std::vector<std::vector<int32_t>> ivv{{1, 2}, {3, 5}, {7, 11}}; - auto ivf = fmt::format("{}", ivv); - EXPECT_EQ("{{1, 2}, {3, 5}, {7, 11}}", ivf); +#ifdef FMT_RANGES_TEST_ENABLE_C_STYLE_ARRAY +TEST(ranges_test, format_array) { + int arr[] = {1, 2, 3, 5, 7, 11}; + EXPECT_EQ(fmt::format("{}", arr), "[1, 2, 3, 5, 7, 11]"); } -TEST(RangesTest, FormatMap) { - std::map<std::string, int32_t> simap{{"one", 1}, {"two", 2}}; - EXPECT_EQ("{(\"one\", 1), (\"two\", 2)}", fmt::format("{}", simap)); +TEST(ranges_test, format_2d_array) { + int arr[][2] = {{1, 2}, {3, 5}, {7, 11}}; + EXPECT_EQ(fmt::format("{}", arr), "[[1, 2], [3, 5], [7, 11]]"); } -TEST(RangesTest, FormatPair) { - std::pair<int64_t, float> pa1{42, 1.5f}; - EXPECT_EQ("(42, 1.5)", fmt::format("{}", pa1)); +TEST(ranges_test, format_array_of_literals) { + const char* arr[] = {"1234", "abcd"}; + EXPECT_EQ(fmt::format("{}", arr), "[\"1234\", \"abcd\"]"); } +#endif // FMT_RANGES_TEST_ENABLE_C_STYLE_ARRAY -TEST(RangesTest, FormatTuple) { - std::tuple<int64_t, float, std::string, char> t{42, 1.5f, "this is tuple", - 'i'}; - EXPECT_EQ("(42, 1.5, \"this is tuple\", 'i')", fmt::format("{}", t)); - EXPECT_EQ("()", fmt::format("{}", std::tuple<>())); +TEST(ranges_test, format_vector) { + auto v = std::vector<int>{1, 2, 3, 5, 7, 11}; + EXPECT_EQ(fmt::format("{}", v), "[1, 2, 3, 5, 7, 11]"); } -TEST(RangesTest, JoinTuple) { - // Value tuple args - std::tuple<char, int, float> t1 = std::make_tuple('a', 1, 2.0f); - EXPECT_EQ("(a, 1, 2)", fmt::format("({})", fmt::join(t1, ", "))); +TEST(ranges_test, format_vector2) { + auto v = std::vector<std::vector<int>>{{1, 2}, {3, 5}, {7, 11}}; + EXPECT_EQ(fmt::format("{}", v), "[[1, 2], [3, 5], [7, 11]]"); +} - // Testing lvalue tuple args - int x = 4; - std::tuple<char, int&> t2{'b', x}; - EXPECT_EQ("b + 4", fmt::format("{}", fmt::join(t2, " + "))); +TEST(ranges_test, format_map) { + auto m = std::map<std::string, int>{{"one", 1}, {"two", 2}}; + EXPECT_EQ(fmt::format("{}", m), "{\"one\": 1, \"two\": 2}"); +} - // Empty tuple - std::tuple<> t3; - EXPECT_EQ("", fmt::format("{}", fmt::join(t3, "|"))); +TEST(ranges_test, format_set) { + EXPECT_EQ(fmt::format("{}", std::set<std::string>{"one", "two"}), + "{\"one\", \"two\"}"); +} - // Single element tuple - std::tuple<float> t4{4.0f}; - EXPECT_EQ("4", fmt::format("{}", fmt::join(t4, "/"))); +TEST(ranges_test, format_pair) { + auto p = std::pair<int, float>(42, 1.5f); + EXPECT_EQ(fmt::format("{}", p), "(42, 1.5)"); } -TEST(RangesTest, JoinInitializerList) { - EXPECT_EQ("1, 2, 3", fmt::format("{}", fmt::join({1, 2, 3}, ", "))); - EXPECT_EQ("fmt rocks !", - fmt::format("{}", fmt::join({"fmt", "rocks", "!"}, " "))); +TEST(ranges_test, format_tuple) { + auto t = + std::tuple<int, float, std::string, char>(42, 1.5f, "this is tuple", 'i'); + EXPECT_EQ(fmt::format("{}", t), "(42, 1.5, \"this is tuple\", 'i')"); + EXPECT_EQ(fmt::format("{}", std::tuple<>()), "()"); } -struct my_struct { - int32_t i; - std::string str; // can throw - template <size_t N> decltype(auto) get() const noexcept { - if constexpr (N == 0) - return i; - else if constexpr (N == 1) - return fmt::string_view{str}; +#ifdef FMT_RANGES_TEST_ENABLE_FORMAT_STRUCT +struct tuple_like { + int i; + std::string str; + + template <size_t N> fmt::enable_if_t<N == 0, int> get() const noexcept { + return i; + } + template <size_t N> + fmt::enable_if_t<N == 1, fmt::string_view> get() const noexcept { + return str; } }; -template <size_t N> decltype(auto) get(const my_struct& s) noexcept { - return s.get<N>(); +template <size_t N> +auto get(const tuple_like& t) noexcept -> decltype(t.get<N>()) { + return t.get<N>(); } namespace std { +template <> +struct tuple_size<tuple_like> : std::integral_constant<size_t, 2> {}; -template <> struct tuple_size<my_struct> : std::integral_constant<size_t, 2> {}; - -template <size_t N> struct tuple_element<N, my_struct> { - using type = decltype(std::declval<my_struct>().get<N>()); +template <size_t N> struct tuple_element<N, tuple_like> { + using type = decltype(std::declval<tuple_like>().get<N>()); }; - } // namespace std -TEST(RangesTest, FormatStruct) { - my_struct mst{13, "my struct"}; - EXPECT_EQ("(13, \"my struct\")", fmt::format("{}", mst)); +TEST(ranges_test, format_struct) { + auto t = tuple_like{42, "foo"}; + EXPECT_EQ(fmt::format("{}", t), "(42, \"foo\")"); } +#endif // FMT_RANGES_TEST_ENABLE_FORMAT_STRUCT -TEST(RangesTest, FormatTo) { +TEST(ranges_test, format_to) { char buf[10]; - auto end = fmt::format_to(buf, "{}", std::vector{1, 2, 3}); + auto end = fmt::format_to(buf, "{}", std::vector<int>{1, 2, 3}); *end = '\0'; - EXPECT_STREQ(buf, "{1, 2, 3}"); + EXPECT_STREQ(buf, "[1, 2, 3]"); } struct path_like { @@ -120,13 +123,10 @@ struct path_like { operator std::string() const; }; -TEST(RangesTest, PathLike) { +TEST(ranges_test, path_like) { EXPECT_FALSE((fmt::is_range<path_like, char>::value)); } -#endif // (__cplusplus > 201402L) || (defined(_MSVC_LANG) && _MSVC_LANG > - // 201402L && _MSC_VER >= 1910) - #ifdef FMT_USE_STRING_VIEW struct string_like { const char* begin(); @@ -135,32 +135,15 @@ struct string_like { explicit operator std::string_view() const { return "foo"; } }; -TEST(RangesTest, FormatStringLike) { - EXPECT_EQ("foo", fmt::format("{}", string_like())); +TEST(ranges_test, format_string_like) { + EXPECT_EQ(fmt::format("{}", string_like()), "foo"); } #endif // FMT_USE_STRING_VIEW -struct zstring_sentinel {}; - -bool operator==(const char* p, zstring_sentinel) { return *p == '\0'; } -bool operator!=(const char* p, zstring_sentinel) { return *p != '\0'; } - -struct zstring { - const char* p; - const char* begin() const { return p; } - zstring_sentinel end() const { return {}; } -}; - -TEST(RangesTest, JoinSentinel) { - zstring hello{"hello"}; - EXPECT_EQ("{'h', 'e', 'l', 'l', 'o'}", fmt::format("{}", hello)); - EXPECT_EQ("h_e_l_l_o", fmt::format("{}", fmt::join(hello, "_"))); -} - // A range that provides non-const only begin()/end() to test fmt::join handles -// that +// that. // -// Some ranges (eg those produced by range-v3's views::filter()) can cache +// Some ranges (e.g. those produced by range-v3's views::filter()) can cache // information during iteration so they only provide non-const begin()/end(). template <typename T> class non_const_only_range { private: @@ -171,33 +154,210 @@ template <typename T> class non_const_only_range { template <typename... Args> explicit non_const_only_range(Args&&... args) - : vec(::std::forward<Args>(args)...) {} + : vec(std::forward<Args>(args)...) {} const_iterator begin() { return vec.begin(); } const_iterator end() { return vec.end(); } }; -TEST(RangesTest, JoinRange) { +template <typename T> class noncopyable_range { + private: + std::vector<T> vec; + + public: + using const_iterator = typename ::std::vector<T>::const_iterator; + + template <typename... Args> + explicit noncopyable_range(Args&&... args) + : vec(std::forward<Args>(args)...) {} + + noncopyable_range(noncopyable_range const&) = delete; + noncopyable_range(noncopyable_range&) = delete; + + const_iterator begin() const { return vec.begin(); } + const_iterator end() const { return vec.end(); } +}; + +TEST(ranges_test, range) { + noncopyable_range<int> w(3u, 0); + EXPECT_EQ(fmt::format("{}", w), "[0, 0, 0]"); + EXPECT_EQ(fmt::format("{}", noncopyable_range<int>(3u, 0)), "[0, 0, 0]"); + non_const_only_range<int> x(3u, 0); - EXPECT_EQ("0,0,0", fmt::format("{}", fmt::join(x, ","))); - EXPECT_EQ( - "0,0,0", - fmt::format("{}", fmt::join(non_const_only_range<int>(3u, 0), ","))); + EXPECT_EQ(fmt::format("{}", x), "[0, 0, 0]"); + EXPECT_EQ(fmt::format("{}", non_const_only_range<int>(3u, 0)), "[0, 0, 0]"); + + auto y = std::vector<int>(3u, 0); + EXPECT_EQ(fmt::format("{}", y), "[0, 0, 0]"); + EXPECT_EQ(fmt::format("{}", std::vector<int>(3u, 0)), "[0, 0, 0]"); + + const auto z = std::vector<int>(3u, 0); + EXPECT_EQ(fmt::format("{}", z), "[0, 0, 0]"); +} - std::vector<int> y(3u, 0); - EXPECT_EQ("0,0,0", fmt::format("{}", fmt::join(y, ","))); - EXPECT_EQ("0,0,0", - fmt::format("{}", fmt::join(std::vector<int>(3u, 0), ","))); +enum test_enum { foo }; - const std::vector<int> z(3u, 0); - EXPECT_EQ("0,0,0", fmt::format("{}", fmt::join(z, ","))); +TEST(ranges_test, enum_range) { + auto v = std::vector<test_enum>{test_enum::foo}; + EXPECT_EQ(fmt::format("{}", v), "[0]"); } -#if !FMT_MSC_VER || FMT_MSC_VER >= 1927 +#if !FMT_MSC_VER struct unformattable {}; -TEST(RangesTest, UnformattableRange) { +TEST(ranges_test, unformattable_range) { EXPECT_FALSE((fmt::has_formatter<std::vector<unformattable>, fmt::format_context>::value)); } #endif + +#ifdef FMT_RANGES_TEST_ENABLE_JOIN +TEST(ranges_test, join_tuple) { + // Value tuple args. + auto t1 = std::tuple<char, int, float>('a', 1, 2.0f); + EXPECT_EQ(fmt::format("({})", fmt::join(t1, ", ")), "(a, 1, 2)"); + + // Testing lvalue tuple args. + int x = 4; + auto t2 = std::tuple<char, int&>('b', x); + EXPECT_EQ(fmt::format("{}", fmt::join(t2, " + ")), "b + 4"); + + // Empty tuple. + auto t3 = std::tuple<>(); + EXPECT_EQ(fmt::format("{}", fmt::join(t3, "|")), ""); + + // Single element tuple. + auto t4 = std::tuple<float>(4.0f); + EXPECT_EQ(fmt::format("{}", fmt::join(t4, "/")), "4"); + +# if FMT_TUPLE_JOIN_SPECIFIERS + // Specs applied to each element. + auto t5 = std::tuple<int, int, long>(-3, 100, 1); + EXPECT_EQ(fmt::format("{:+03}", fmt::join(t5, ", ")), "-03, +100, +01"); + + auto t6 = std::tuple<float, double, long double>(3, 3.14, 3.1415); + EXPECT_EQ(fmt::format("{:5.5f}", fmt::join(t6, ", ")), + "3.00000, 3.14000, 3.14150"); + + // Testing lvalue tuple args. + int y = -1; + auto t7 = std::tuple<int, int&, const int&>(3, y, y); + EXPECT_EQ(fmt::format("{:03}", fmt::join(t7, ", ")), "003, -01, -01"); +# endif +} + +TEST(ranges_test, join_initializer_list) { + EXPECT_EQ(fmt::format("{}", fmt::join({1, 2, 3}, ", ")), "1, 2, 3"); + EXPECT_EQ(fmt::format("{}", fmt::join({"fmt", "rocks", "!"}, " ")), + "fmt rocks !"); +} + +struct zstring_sentinel {}; + +bool operator==(const char* p, zstring_sentinel) { return *p == '\0'; } +bool operator!=(const char* p, zstring_sentinel) { return *p != '\0'; } + +struct zstring { + const char* p; + const char* begin() const { return p; } + zstring_sentinel end() const { return {}; } +}; + +# ifdef __cpp_lib_ranges +struct cpp20_only_range { + struct iterator { + int val = 0; + + using value_type = int; + using difference_type = std::ptrdiff_t; + using iterator_concept = std::input_iterator_tag; + + iterator() = default; + iterator(int i) : val(i) {} + int operator*() const { return val; } + iterator& operator++() { + ++val; + return *this; + } + void operator++(int) { ++*this; } + bool operator==(const iterator& rhs) const { return val == rhs.val; } + }; + + int lo; + int hi; + + iterator begin() const { return iterator(lo); } + iterator end() const { return iterator(hi); } +}; + +static_assert(std::input_iterator<cpp20_only_range::iterator>); +# endif + +TEST(ranges_test, join_sentinel) { + auto hello = zstring{"hello"}; + EXPECT_EQ(fmt::format("{}", hello), "['h', 'e', 'l', 'l', 'o']"); + EXPECT_EQ(fmt::format("{}", fmt::join(hello, "_")), "h_e_l_l_o"); +} + +TEST(ranges_test, join_range) { + noncopyable_range<int> w(3u, 0); + EXPECT_EQ(fmt::format("{}", fmt::join(w, ",")), "0,0,0"); + EXPECT_EQ(fmt::format("{}", fmt::join(noncopyable_range<int>(3u, 0), ",")), + "0,0,0"); + + non_const_only_range<int> x(3u, 0); + EXPECT_EQ(fmt::format("{}", fmt::join(x, ",")), "0,0,0"); + EXPECT_EQ(fmt::format("{}", fmt::join(non_const_only_range<int>(3u, 0), ",")), + "0,0,0"); + + auto y = std::vector<int>(3u, 0); + EXPECT_EQ(fmt::format("{}", fmt::join(y, ",")), "0,0,0"); + EXPECT_EQ(fmt::format("{}", fmt::join(std::vector<int>(3u, 0), ",")), + "0,0,0"); + + const auto z = std::vector<int>(3u, 0); + EXPECT_EQ(fmt::format("{}", fmt::join(z, ",")), "0,0,0"); + +# ifdef __cpp_lib_ranges + EXPECT_EQ(fmt::format("{}", cpp20_only_range{.lo = 0, .hi = 5}), + "[0, 1, 2, 3, 4]"); + EXPECT_EQ( + fmt::format("{}", fmt::join(cpp20_only_range{.lo = 0, .hi = 5}, ",")), + "0,1,2,3,4"); +# endif +} +#endif // FMT_RANGES_TEST_ENABLE_JOIN + +TEST(ranges_test, is_printable) { + using fmt::detail::is_printable; + EXPECT_TRUE(is_printable(0x0323)); + EXPECT_FALSE(is_printable(0x0378)); + EXPECT_FALSE(is_printable(0x110000)); +} + +TEST(ranges_test, escape_string) { + using vec = std::vector<std::string>; + EXPECT_EQ(fmt::format("{}", vec{"\n\r\t\"\\"}), "[\"\\n\\r\\t\\\"\\\\\"]"); + EXPECT_EQ(fmt::format("{}", vec{"\x07"}), "[\"\\x07\"]"); + EXPECT_EQ(fmt::format("{}", vec{"\x7f"}), "[\"\\x7f\"]"); + EXPECT_EQ(fmt::format("{}", vec{"n\xcc\x83"}), "[\"n\xcc\x83\"]"); + + if (fmt::detail::is_utf8()) { + EXPECT_EQ(fmt::format("{}", vec{"\xcd\xb8"}), "[\"\\u0378\"]"); + // Unassigned Unicode code points. + EXPECT_EQ(fmt::format("{}", vec{"\xf0\xaa\x9b\x9e"}), "[\"\\U0002a6de\"]"); + EXPECT_EQ(fmt::format("{}", vec{"\xf4\x8f\xbf\xc0"}), + "[\"\\xf4\\x8f\\xbf\\xc0\"]"); + } +} + +#ifdef FMT_USE_STRING_VIEW +struct convertible_to_string_view { + operator std::string_view() const { return "foo"; } +}; + +TEST(ranges_test, escape_convertible_to_string_view) { + EXPECT_EQ(fmt::format("{}", std::vector<convertible_to_string_view>(1)), + "[\"foo\"]"); +} +#endif // FMT_USE_STRING_VIEW diff --git a/contrib/libs/fmt/test/scan-test.cc b/contrib/libs/fmt/test/scan-test.cc index 90c0edef9b..7e327ea3f5 100644 --- a/contrib/libs/fmt/test/scan-test.cc +++ b/contrib/libs/fmt/test/scan-test.cc @@ -11,25 +11,25 @@ #include <climits> -#include <gmock/gmock.h> +#include "gmock/gmock.h" #include "gtest-extra.h" -TEST(ScanTest, ReadText) { - fmt::string_view s = "foo"; +TEST(scan_test, read_text) { + auto s = fmt::string_view("foo"); auto end = fmt::scan(s, "foo"); EXPECT_EQ(end, s.end()); EXPECT_THROW_MSG(fmt::scan("fob", "foo"), fmt::format_error, "invalid input"); } -TEST(ScanTest, ReadInt) { - int n = 0; +TEST(scan_test, read_int) { + auto n = int(); fmt::scan("42", "{}", n); EXPECT_EQ(n, 42); fmt::scan("-42", "{}", n); EXPECT_EQ(n, -42); } -TEST(ScanTest, ReadLongLong) { +TEST(scan_test, read_longlong) { long long n = 0; fmt::scan("42", "{}", n); EXPECT_EQ(n, 42); @@ -37,15 +37,15 @@ TEST(ScanTest, ReadLongLong) { EXPECT_EQ(n, -42); } -TEST(ScanTest, ReadUInt) { - unsigned n = 0; +TEST(scan_test, read_uint) { + auto n = unsigned(); fmt::scan("42", "{}", n); EXPECT_EQ(n, 42); EXPECT_THROW_MSG(fmt::scan("-42", "{}", n), fmt::format_error, "invalid input"); } -TEST(ScanTest, ReadULongLong) { +TEST(scan_test, read_ulonglong) { unsigned long long n = 0; fmt::scan("42", "{}", n); EXPECT_EQ(n, 42); @@ -53,14 +53,14 @@ TEST(ScanTest, ReadULongLong) { "invalid input"); } -TEST(ScanTest, ReadString) { - std::string s; +TEST(scan_test, read_string) { + auto s = std::string(); fmt::scan("foo", "{}", s); EXPECT_EQ(s, "foo"); } -TEST(ScanTest, ReadStringView) { - fmt::string_view s; +TEST(scan_test, read_string_view) { + auto s = fmt::string_view(); fmt::scan("foo", "{}", s); EXPECT_EQ(s, "foo"); } @@ -90,8 +90,8 @@ template <> struct scanner<tm> { }; } // namespace fmt -TEST(ScanTest, ReadCustom) { - const char* input = "Date: 1985-10-25"; +TEST(scan_test, read_custom) { + auto input = "Date: 1985-10-25"; auto t = tm(); fmt::scan(input, "Date: {0:%Y-%m-%d}", t); EXPECT_EQ(t.tm_year, 85); @@ -100,16 +100,16 @@ TEST(ScanTest, ReadCustom) { } #endif -TEST(ScanTest, InvalidFormat) { +TEST(scan_test, invalid_format) { EXPECT_THROW_MSG(fmt::scan("", "{}"), fmt::format_error, "argument index out of range"); EXPECT_THROW_MSG(fmt::scan("", "{"), fmt::format_error, "invalid format string"); } -TEST(ScanTest, Example) { - std::string key; - int value; +TEST(scan_test, example) { + auto key = std::string(); + auto value = int(); fmt::scan("answer = 42", "{} = {}", key, value); EXPECT_EQ(key, "answer"); EXPECT_EQ(value, 42); diff --git a/contrib/libs/fmt/test/scan.h b/contrib/libs/fmt/test/scan.h index de82067a49..41748ae895 100644 --- a/contrib/libs/fmt/test/scan.h +++ b/contrib/libs/fmt/test/scan.h @@ -169,13 +169,16 @@ struct scan_handler : error_handler { scan_ctx_.advance_to(it + size); } - int on_arg_id() { return on_arg_id(next_arg_id_++); } - int on_arg_id(int id) { + FMT_CONSTEXPR int on_arg_id() { return on_arg_id(next_arg_id_++); } + FMT_CONSTEXPR int on_arg_id(int id) { if (id >= args_.size) on_error("argument index out of range"); arg_ = args_.data[id]; return id; } - int on_arg_id(string_view) { return on_error("invalid format"), 0; } + FMT_CONSTEXPR int on_arg_id(string_view id) { + if (id.data()) on_error("invalid format"); + return 0; + } void on_replacement_field(int, const char*) { auto it = scan_ctx_.begin(), end = scan_ctx_.end(); diff --git a/contrib/libs/fmt/test/test-assert.h b/contrib/libs/fmt/test/test-assert.h index f9df580539..ab7b2bf732 100644 --- a/contrib/libs/fmt/test/test-assert.h +++ b/contrib/libs/fmt/test/test-assert.h @@ -10,7 +10,11 @@ #include <stdexcept> -#include <gtest/gtest.h> +void throw_assertion_failure(const char* message); +#define FMT_ASSERT(condition, message) \ + if (!(condition)) throw_assertion_failure(message); + +#include "gtest/gtest.h" class assertion_failure : public std::logic_error { public: @@ -22,8 +26,11 @@ class assertion_failure : public std::logic_error { void assertion_failure::avoid_weak_vtable() {} -#define FMT_ASSERT(condition, message) \ - if (!(condition)) throw assertion_failure(message); +// We use a separate function (rather than throw directly from FMT_ASSERT) to +// avoid GCC's -Wterminate warning when FMT_ASSERT is used in a destructor. +inline void throw_assertion_failure(const char* message) { + throw assertion_failure(message); +} // Expects an assertion failure. #define EXPECT_ASSERT(stmt, message) \ diff --git a/contrib/libs/fmt/test/unicode-test.cc b/contrib/libs/fmt/test/unicode-test.cc new file mode 100644 index 0000000000..63c828dd8f --- /dev/null +++ b/contrib/libs/fmt/test/unicode-test.cc @@ -0,0 +1,48 @@ +// Formatting library for C++ - Unicode tests +// +// Copyright (c) 2012 - present, Victor Zverovich +// All rights reserved. +// +// For the license information refer to format.h. + +#include <iomanip> +#include <locale> +#include <vector> + +#include "fmt/chrono.h" +#include "gmock/gmock.h" +#include "util.h" // get_locale + +using testing::Contains; + +TEST(unicode_test, is_utf8) { EXPECT_TRUE(fmt::detail::is_utf8()); } + +TEST(unicode_test, legacy_locale) { + auto loc = get_locale("ru_RU.CP1251", "Russian_Russia.1251"); + if (loc == std::locale::classic()) return; + + auto s = std::string(); + try { + s = fmt::format(loc, "День недели: {:L}", fmt::weekday(1)); + } catch (const fmt::format_error& e) { + // Formatting can fail due to an unsupported encoding. + fmt::print("Format error: {}\n", e.what()); + return; + } + +#if !FMT_GCC_VERSION || FMT_GCC_VERSION >= 500 + auto&& os = std::ostringstream(); + os.imbue(loc); + auto tm = std::tm(); + tm.tm_wday = 1; + os << std::put_time(&tm, "%a"); + auto wd = os.str(); + if (wd == "??") { + EXPECT_EQ(s, "День недели: ??"); + fmt::print("std::locale gives ?? as a weekday.\n"); + return; + } +#endif + EXPECT_THAT((std::vector<std::string>{"День недели: пн", "День недели: Пн"}), + Contains(s)); +} diff --git a/contrib/libs/fmt/test/util.cc b/contrib/libs/fmt/test/util.cc index d08dcbdcbf..f4cb74ca0a 100644 --- a/contrib/libs/fmt/test/util.cc +++ b/contrib/libs/fmt/test/util.cc @@ -9,42 +9,38 @@ #include <cstring> -void increment(char* s) { - for (int i = static_cast<int>(std::strlen(s)) - 1; i >= 0; --i) { - if (s[i] != '9') { - ++s[i]; - break; - } - s[i] = '0'; - } -} - -std::string get_system_error(int error_code) { -#if defined(__MINGW32__) || !defined(_WIN32) - return strerror(error_code); -#else - enum { BUFFER_SIZE = 200 }; - char buffer[BUFFER_SIZE]; - if (strerror_s(buffer, BUFFER_SIZE, error_code)) - throw std::exception("strerror_s failed"); - return buffer; -#endif -} - -const char* const FILE_CONTENT = "Don't panic!"; +const char* const file_content = "Don't panic!"; fmt::buffered_file open_buffered_file(FILE** fp) { #if FMT_USE_FCNTL fmt::file read_end, write_end; fmt::file::pipe(read_end, write_end); - write_end.write(FILE_CONTENT, std::strlen(FILE_CONTENT)); + write_end.write(file_content, std::strlen(file_content)); write_end.close(); fmt::buffered_file f = read_end.fdopen("r"); if (fp) *fp = f.get(); #else fmt::buffered_file f("test-file", "w"); - fputs(FILE_CONTENT, f.get()); + fputs(file_content, f.get()); if (fp) *fp = f.get(); #endif return f; } + +std::locale do_get_locale(const char* name) { + try { + return std::locale(name); + } catch (const std::runtime_error&) { + } + return std::locale::classic(); +} + +std::locale get_locale(const char* name, const char* alt_name) { + auto loc = do_get_locale(name); + if (loc == std::locale::classic() && alt_name) { + loc = do_get_locale(alt_name); + } + if (loc == std::locale::classic()) + fmt::print(stderr, "{} locale is missing.\n", name); + return loc; +} diff --git a/contrib/libs/fmt/test/util.h b/contrib/libs/fmt/test/util.h index 24a5f4e34b..2e58ad950c 100644 --- a/contrib/libs/fmt/test/util.h +++ b/contrib/libs/fmt/test/util.h @@ -7,11 +7,14 @@ #include <cstdarg> #include <cstdio> +#include <locale> #include <string> -#include "fmt/os.h" - -enum { BUFFER_SIZE = 256 }; +#ifdef FMT_MODULE_TEST +import fmt; +#else +# include "fmt/os.h" +#endif // FMT_MODULE_TEST #ifdef _MSC_VER # define FMT_VSNPRINTF vsprintf_s @@ -27,12 +30,7 @@ void safe_sprintf(char (&buffer)[SIZE], const char* format, ...) { va_end(args); } -// Increment a number in a string. -void increment(char* s); - -std::string get_system_error(int error_code); - -extern const char* const FILE_CONTENT; +extern const char* const file_content; // Opens a buffered file for reading. fmt::buffered_file open_buffered_file(FILE** fp = nullptr); @@ -40,7 +38,7 @@ fmt::buffered_file open_buffered_file(FILE** fp = nullptr); inline FILE* safe_fopen(const char* filename, const char* mode) { #if defined(_WIN32) && !defined(__MINGW32__) // Fix MSVC warning about "unsafe" fopen. - FILE* f = 0; + FILE* f = nullptr; errno = fopen_s(&f, filename, mode); return f; #else @@ -48,37 +46,40 @@ inline FILE* safe_fopen(const char* filename, const char* mode) { #endif } -template <typename Char> class BasicTestString { +template <typename Char> class basic_test_string { private: std::basic_string<Char> value_; - static const Char EMPTY[]; + static const Char empty[]; public: - explicit BasicTestString(const Char* value = EMPTY) : value_(value) {} + explicit basic_test_string(const Char* value = empty) : value_(value) {} const std::basic_string<Char>& value() const { return value_; } }; -template <typename Char> const Char BasicTestString<Char>::EMPTY[] = {0}; +template <typename Char> const Char basic_test_string<Char>::empty[] = {0}; -typedef BasicTestString<char> TestString; -typedef BasicTestString<wchar_t> TestWString; +typedef basic_test_string<char> test_string; +typedef basic_test_string<wchar_t> test_wstring; template <typename Char> std::basic_ostream<Char>& operator<<(std::basic_ostream<Char>& os, - const BasicTestString<Char>& s) { + const basic_test_string<Char>& s) { os << s.value(); return os; } -class Date { +class date { int year_, month_, day_; public: - Date(int year, int month, int day) : year_(year), month_(month), day_(day) {} + date(int year, int month, int day) : year_(year), month_(month), day_(day) {} int year() const { return year_; } int month() const { return month_; } int day() const { return day_; } }; + +// Returns a locale with the given name if available or classic locale othewise. +std::locale get_locale(const char* name, const char* alt_name = nullptr); diff --git a/contrib/libs/fmt/test/xchar-test.cc b/contrib/libs/fmt/test/xchar-test.cc new file mode 100644 index 0000000000..346cd21262 --- /dev/null +++ b/contrib/libs/fmt/test/xchar-test.cc @@ -0,0 +1,502 @@ +// Formatting library for C++ - formatting library tests +// +// Copyright (c) 2012 - present, Victor Zverovich +// All rights reserved. +// +// For the license information refer to format.h. + +#include "fmt/xchar.h" + +#include <complex> +#include <cwchar> +#include <vector> + +#include "fmt/chrono.h" +#include "fmt/color.h" +#include "fmt/ostream.h" +#include "fmt/ranges.h" +#include "gtest-extra.h" // Contains +#include "util.h" // get_locale + +using fmt::detail::max_value; +using testing::Contains; + +namespace test_ns { +template <typename Char> class test_string { + private: + std::basic_string<Char> s_; + + public: + test_string(const Char* s) : s_(s) {} + const Char* data() const { return s_.data(); } + size_t length() const { return s_.size(); } + operator const Char*() const { return s_.c_str(); } +}; + +template <typename Char> +fmt::basic_string_view<Char> to_string_view(const test_string<Char>& s) { + return {s.data(), s.length()}; +} + +struct non_string {}; +} // namespace test_ns + +template <typename T> class is_string_test : public testing::Test {}; + +using string_char_types = testing::Types<char, wchar_t, char16_t, char32_t>; +TYPED_TEST_SUITE(is_string_test, string_char_types); + +template <typename Char> +struct derived_from_string_view : fmt::basic_string_view<Char> {}; + +TYPED_TEST(is_string_test, is_string) { + EXPECT_TRUE(fmt::detail::is_string<TypeParam*>::value); + EXPECT_TRUE(fmt::detail::is_string<const TypeParam*>::value); + EXPECT_TRUE(fmt::detail::is_string<TypeParam[2]>::value); + EXPECT_TRUE(fmt::detail::is_string<const TypeParam[2]>::value); + EXPECT_TRUE(fmt::detail::is_string<std::basic_string<TypeParam>>::value); + EXPECT_TRUE(fmt::detail::is_string<fmt::basic_string_view<TypeParam>>::value); + EXPECT_TRUE( + fmt::detail::is_string<derived_from_string_view<TypeParam>>::value); + using fmt_string_view = fmt::detail::std_string_view<TypeParam>; + EXPECT_TRUE(std::is_empty<fmt_string_view>::value != + fmt::detail::is_string<fmt_string_view>::value); + EXPECT_TRUE(fmt::detail::is_string<test_ns::test_string<TypeParam>>::value); + EXPECT_FALSE(fmt::detail::is_string<test_ns::non_string>::value); +} + +// std::is_constructible is broken in MSVC until version 2015. +#if !FMT_MSC_VER || FMT_MSC_VER >= 1900 +struct explicitly_convertible_to_wstring_view { + explicit operator fmt::wstring_view() const { return L"foo"; } +}; + +TEST(xchar_test, format_explicitly_convertible_to_wstring_view) { + EXPECT_EQ(L"foo", + fmt::format(L"{}", explicitly_convertible_to_wstring_view())); +} +#endif + +TEST(xchar_test, format) { + EXPECT_EQ(L"42", fmt::format(L"{}", 42)); + EXPECT_EQ(L"4.2", fmt::format(L"{}", 4.2)); + EXPECT_EQ(L"abc", fmt::format(L"{}", L"abc")); + EXPECT_EQ(L"z", fmt::format(L"{}", L'z')); + EXPECT_THROW(fmt::format(L"{:*\x343E}", 42), fmt::format_error); + EXPECT_EQ(L"true", fmt::format(L"{}", true)); + EXPECT_EQ(L"a", fmt::format(L"{0}", 'a')); + EXPECT_EQ(L"a", fmt::format(L"{0}", L'a')); + EXPECT_EQ(L"Cyrillic letter \x42e", + fmt::format(L"Cyrillic letter {}", L'\x42e')); + EXPECT_EQ(L"abc1", fmt::format(L"{}c{}", L"ab", 1)); +} + +TEST(xchar_test, is_formattable) { + static_assert(!fmt::is_formattable<const wchar_t*>::value, ""); +} + +TEST(xchar_test, compile_time_string) { +#if defined(FMT_USE_STRING_VIEW) && __cplusplus >= 201703L + EXPECT_EQ(L"42", fmt::format(FMT_STRING(std::wstring_view(L"{}")), 42)); +#endif +} + +#if __cplusplus > 201103L +struct custom_char { + int value; + custom_char() = default; + + template <typename T> + constexpr custom_char(T val) : value(static_cast<int>(val)) {} + + operator int() const { return value; } +}; + +int to_ascii(custom_char c) { return c; } + +FMT_BEGIN_NAMESPACE +template <> struct is_char<custom_char> : std::true_type {}; +FMT_END_NAMESPACE + +TEST(xchar_test, format_custom_char) { + const custom_char format[] = {'{', '}', 0}; + auto result = fmt::format(format, custom_char('x')); + EXPECT_EQ(result.size(), 1); + EXPECT_EQ(result[0], custom_char('x')); +} +#endif + +// Convert a char8_t string to std::string. Otherwise GTest will insist on +// inserting `char8_t` NTBS into a `char` stream which is disabled by P1423. +template <typename S> std::string from_u8str(const S& str) { + return std::string(str.begin(), str.end()); +} + +TEST(xchar_test, format_utf8_precision) { + using str_type = std::basic_string<fmt::detail::char8_type>; + auto format = + str_type(reinterpret_cast<const fmt::detail::char8_type*>(u8"{:.4}")); + auto str = str_type(reinterpret_cast<const fmt::detail::char8_type*>( + u8"caf\u00e9s")); // cafés + auto result = fmt::format(format, str); + EXPECT_EQ(fmt::detail::compute_width(result), 4); + EXPECT_EQ(result.size(), 5); + EXPECT_EQ(from_u8str(result), from_u8str(str.substr(0, 5))); +} + +TEST(xchar_test, format_to) { + auto buf = std::vector<wchar_t>(); + fmt::format_to(std::back_inserter(buf), L"{}{}", 42, L'\0'); + EXPECT_STREQ(buf.data(), L"42"); +} + +TEST(xchar_test, vformat_to) { + using wcontext = fmt::wformat_context; + fmt::basic_format_arg<wcontext> warg = fmt::detail::make_arg<wcontext>(42); + auto wargs = fmt::basic_format_args<wcontext>(&warg, 1); + auto w = std::wstring(); + fmt::vformat_to(std::back_inserter(w), L"{}", wargs); + EXPECT_EQ(L"42", w); + w.clear(); + fmt::vformat_to(std::back_inserter(w), FMT_STRING(L"{}"), wargs); + EXPECT_EQ(L"42", w); +} + +TEST(format_test, wide_format_to_n) { + wchar_t buffer[4]; + buffer[3] = L'x'; + auto result = fmt::format_to_n(buffer, 3, L"{}", 12345); + EXPECT_EQ(5u, result.size); + EXPECT_EQ(buffer + 3, result.out); + EXPECT_EQ(L"123x", fmt::wstring_view(buffer, 4)); + buffer[0] = L'x'; + buffer[1] = L'x'; + buffer[2] = L'x'; + result = fmt::format_to_n(buffer, 3, L"{}", L'A'); + EXPECT_EQ(1u, result.size); + EXPECT_EQ(buffer + 1, result.out); + EXPECT_EQ(L"Axxx", fmt::wstring_view(buffer, 4)); + result = fmt::format_to_n(buffer, 3, L"{}{} ", L'B', L'C'); + EXPECT_EQ(3u, result.size); + EXPECT_EQ(buffer + 3, result.out); + EXPECT_EQ(L"BC x", fmt::wstring_view(buffer, 4)); +} + +#if FMT_USE_USER_DEFINED_LITERALS +TEST(xchar_test, format_udl) { + using namespace fmt::literals; + EXPECT_EQ(L"{}c{}"_format(L"ab", 1), fmt::format(L"{}c{}", L"ab", 1)); +} + +TEST(xchar_test, named_arg_udl) { + using namespace fmt::literals; + auto udl_a = + fmt::format(L"{first}{second}{first}{third}", L"first"_a = L"abra", + L"second"_a = L"cad", L"third"_a = 99); + EXPECT_EQ( + fmt::format(L"{first}{second}{first}{third}", fmt::arg(L"first", L"abra"), + fmt::arg(L"second", L"cad"), fmt::arg(L"third", 99)), + udl_a); +} +#endif // FMT_USE_USER_DEFINED_LITERALS + +TEST(xchar_test, print) { + // Check that the wide print overload compiles. + if (fmt::detail::const_check(false)) fmt::print(L"test"); +} + +TEST(xchar_test, join) { + int v[3] = {1, 2, 3}; + EXPECT_EQ(fmt::format(L"({})", fmt::join(v, v + 3, L", ")), L"(1, 2, 3)"); + auto t = std::tuple<wchar_t, int, float>('a', 1, 2.0f); + EXPECT_EQ(fmt::format(L"({})", fmt::join(t, L", ")), L"(a, 1, 2)"); +} + +enum streamable_enum {}; + +std::wostream& operator<<(std::wostream& os, streamable_enum) { + return os << L"streamable_enum"; +} + +enum unstreamable_enum {}; + +TEST(xchar_test, enum) { + EXPECT_EQ(L"streamable_enum", fmt::format(L"{}", streamable_enum())); + EXPECT_EQ(L"0", fmt::format(L"{}", unstreamable_enum())); +} + +TEST(xchar_test, sign_not_truncated) { + wchar_t format_str[] = { + L'{', L':', + '+' | static_cast<wchar_t>(1 << fmt::detail::num_bits<char>()), L'}', 0}; + EXPECT_THROW(fmt::format(format_str, 42), fmt::format_error); +} + +namespace fake_qt { +class QString { + public: + QString(const wchar_t* s) : s_(s) {} + const wchar_t* utf16() const FMT_NOEXCEPT { return s_.data(); } + int size() const FMT_NOEXCEPT { return static_cast<int>(s_.size()); } + + private: + std::wstring s_; +}; + +fmt::basic_string_view<wchar_t> to_string_view(const QString& s) FMT_NOEXCEPT { + return {s.utf16(), static_cast<size_t>(s.size())}; +} +} // namespace fake_qt + +TEST(format_test, format_foreign_strings) { + using fake_qt::QString; + EXPECT_EQ(fmt::format(QString(L"{}"), 42), L"42"); + EXPECT_EQ(fmt::format(QString(L"{}"), QString(L"42")), L"42"); +} + +TEST(xchar_test, chrono) { + auto tm = std::tm(); + tm.tm_year = 116; + tm.tm_mon = 3; + tm.tm_mday = 25; + tm.tm_hour = 11; + tm.tm_min = 22; + tm.tm_sec = 33; + EXPECT_EQ(fmt::format("The date is {:%Y-%m-%d %H:%M:%S}.", tm), + "The date is 2016-04-25 11:22:33."); + EXPECT_EQ(L"42s", fmt::format(L"{}", std::chrono::seconds(42))); + EXPECT_EQ(fmt::format(L"{:%F}", tm), L"2016-04-25"); + EXPECT_EQ(fmt::format(L"{:%T}", tm), L"11:22:33"); +} + +std::wstring system_wcsftime(const std::wstring& format, const std::tm* timeptr, + std::locale* locptr = nullptr) { + auto loc = locptr ? *locptr : std::locale::classic(); + auto& facet = std::use_facet<std::time_put<wchar_t>>(loc); + std::wostringstream os; + os.imbue(loc); + facet.put(os, os, L' ', timeptr, format.c_str(), + format.c_str() + format.size()); +#ifdef _WIN32 + // Workaround a bug in older versions of Universal CRT. + auto str = os.str(); + if (str == L"-0000") str = L"+0000"; + return str; +#else + return os.str(); +#endif +} + +TEST(chrono_test, time_point) { + auto t1 = std::chrono::system_clock::now(); + + std::vector<std::wstring> spec_list = { + L"%%", L"%n", L"%t", L"%Y", L"%EY", L"%y", L"%Oy", L"%Ey", L"%C", + L"%EC", L"%G", L"%g", L"%b", L"%h", L"%B", L"%m", L"%Om", L"%U", + L"%OU", L"%W", L"%OW", L"%V", L"%OV", L"%j", L"%d", L"%Od", L"%e", + L"%Oe", L"%a", L"%A", L"%w", L"%Ow", L"%u", L"%Ou", L"%H", L"%OH", + L"%I", L"%OI", L"%M", L"%OM", L"%S", L"%OS", L"%x", L"%Ex", L"%X", + L"%EX", L"%D", L"%F", L"%R", L"%T", L"%p", L"%z", L"%Z"}; + spec_list.push_back(L"%Y-%m-%d %H:%M:%S"); +#ifndef _WIN32 + // Disabled on Windows, because these formats is not consistent among + // platforms. + spec_list.insert(spec_list.end(), {L"%c", L"%Ec", L"%r"}); +#endif + + for (const auto& spec : spec_list) { + auto t = std::chrono::system_clock::to_time_t(t1); + auto tm = *std::localtime(&t); + + auto sys_output = system_wcsftime(spec, &tm); + + auto fmt_spec = fmt::format(L"{{:{}}}", spec); + EXPECT_EQ(sys_output, fmt::format(fmt_spec, t1)); + EXPECT_EQ(sys_output, fmt::format(fmt_spec, tm)); + } +} + +TEST(xchar_test, color) { + EXPECT_EQ(fmt::format(fg(fmt::rgb(255, 20, 30)), L"rgb(255,20,30) wide"), + L"\x1b[38;2;255;020;030mrgb(255,20,30) wide\x1b[0m"); +} + +TEST(xchar_test, ostream) { + std::wostringstream wos; + fmt::print(wos, L"Don't {}!", L"panic"); + EXPECT_EQ(L"Don't panic!", wos.str()); +} + +TEST(xchar_test, to_wstring) { EXPECT_EQ(L"42", fmt::to_wstring(42)); } + +#ifndef FMT_STATIC_THOUSANDS_SEPARATOR +template <typename Char> struct numpunct : std::numpunct<Char> { + protected: + Char do_decimal_point() const override { return '?'; } + std::string do_grouping() const override { return "\03"; } + Char do_thousands_sep() const override { return '~'; } +}; + +template <typename Char> struct no_grouping : std::numpunct<Char> { + protected: + Char do_decimal_point() const override { return '.'; } + std::string do_grouping() const override { return ""; } + Char do_thousands_sep() const override { return ','; } +}; + +template <typename Char> struct special_grouping : std::numpunct<Char> { + protected: + Char do_decimal_point() const override { return '.'; } + std::string do_grouping() const override { return "\03\02"; } + Char do_thousands_sep() const override { return ','; } +}; + +template <typename Char> struct small_grouping : std::numpunct<Char> { + protected: + Char do_decimal_point() const override { return '.'; } + std::string do_grouping() const override { return "\01"; } + Char do_thousands_sep() const override { return ','; } +}; + +TEST(locale_test, localized_double) { + auto loc = std::locale(std::locale(), new numpunct<char>()); + EXPECT_EQ("1?23", fmt::format(loc, "{:L}", 1.23)); + EXPECT_EQ("1?230000", fmt::format(loc, "{:Lf}", 1.23)); + EXPECT_EQ("1~234?5", fmt::format(loc, "{:L}", 1234.5)); + EXPECT_EQ("12~000", fmt::format(loc, "{:L}", 12000.0)); +} + +TEST(locale_test, format) { + auto loc = std::locale(std::locale(), new numpunct<char>()); + EXPECT_EQ("1234567", fmt::format(std::locale(), "{:L}", 1234567)); + EXPECT_EQ("1~234~567", fmt::format(loc, "{:L}", 1234567)); + EXPECT_EQ("-1~234~567", fmt::format(loc, "{:L}", -1234567)); + EXPECT_EQ("-256", fmt::format(loc, "{:L}", -256)); + fmt::format_arg_store<fmt::format_context, int> as{1234567}; + EXPECT_EQ("1~234~567", fmt::vformat(loc, "{:L}", fmt::format_args(as))); + auto s = std::string(); + fmt::format_to(std::back_inserter(s), loc, "{:L}", 1234567); + EXPECT_EQ("1~234~567", s); + + auto no_grouping_loc = std::locale(std::locale(), new no_grouping<char>()); + EXPECT_EQ("1234567", fmt::format(no_grouping_loc, "{:L}", 1234567)); + + auto special_grouping_loc = + std::locale(std::locale(), new special_grouping<char>()); + EXPECT_EQ("1,23,45,678", fmt::format(special_grouping_loc, "{:L}", 12345678)); + EXPECT_EQ("12,345", fmt::format(special_grouping_loc, "{:L}", 12345)); + + auto small_grouping_loc = + std::locale(std::locale(), new small_grouping<char>()); + EXPECT_EQ("4,2,9,4,9,6,7,2,9,5", + fmt::format(small_grouping_loc, "{:L}", max_value<uint32_t>())); +} + +TEST(locale_test, format_detault_align) { + auto loc = std::locale({}, new special_grouping<char>()); + EXPECT_EQ(" 12,345", fmt::format(loc, "{:8L}", 12345)); +} + +TEST(locale_test, format_plus) { + auto loc = std::locale({}, new special_grouping<char>()); + EXPECT_EQ("+100", fmt::format(loc, "{:+L}", 100)); +} + +TEST(locale_test, wformat) { + auto loc = std::locale(std::locale(), new numpunct<wchar_t>()); + EXPECT_EQ(L"1234567", fmt::format(std::locale(), L"{:L}", 1234567)); + EXPECT_EQ(L"1~234~567", fmt::format(loc, L"{:L}", 1234567)); + using wcontext = fmt::buffer_context<wchar_t>; + fmt::format_arg_store<wcontext, int> as{1234567}; + EXPECT_EQ(L"1~234~567", + fmt::vformat(loc, L"{:L}", fmt::basic_format_args<wcontext>(as))); + EXPECT_EQ(L"1234567", fmt::format(std::locale("C"), L"{:L}", 1234567)); + + auto no_grouping_loc = std::locale(std::locale(), new no_grouping<wchar_t>()); + EXPECT_EQ(L"1234567", fmt::format(no_grouping_loc, L"{:L}", 1234567)); + + auto special_grouping_loc = + std::locale(std::locale(), new special_grouping<wchar_t>()); + EXPECT_EQ(L"1,23,45,678", + fmt::format(special_grouping_loc, L"{:L}", 12345678)); + + auto small_grouping_loc = + std::locale(std::locale(), new small_grouping<wchar_t>()); + EXPECT_EQ(L"4,2,9,4,9,6,7,2,9,5", + fmt::format(small_grouping_loc, L"{:L}", max_value<uint32_t>())); +} + +TEST(locale_test, double_formatter) { + auto loc = std::locale(std::locale(), new special_grouping<char>()); + auto f = fmt::formatter<int>(); + auto parse_ctx = fmt::format_parse_context("L"); + f.parse(parse_ctx); + char buf[10] = {}; + fmt::basic_format_context<char*, char> format_ctx( + buf, {}, fmt::detail::locale_ref(loc)); + *f.format(12345, format_ctx) = 0; + EXPECT_STREQ("12,345", buf); +} + +FMT_BEGIN_NAMESPACE +template <class charT> struct formatter<std::complex<double>, charT> { + private: + detail::dynamic_format_specs<char> specs_; + + public: + FMT_CONSTEXPR typename basic_format_parse_context<charT>::iterator parse( + basic_format_parse_context<charT>& ctx) { + using handler_type = + detail::dynamic_specs_handler<basic_format_parse_context<charT>>; + detail::specs_checker<handler_type> handler(handler_type(specs_, ctx), + detail::type::string_type); + auto it = parse_format_specs(ctx.begin(), ctx.end(), handler); + detail::parse_float_type_spec(specs_, ctx.error_handler()); + return it; + } + + template <class FormatContext> + typename FormatContext::iterator format(const std::complex<double>& c, + FormatContext& ctx) { + detail::handle_dynamic_spec<detail::precision_checker>( + specs_.precision, specs_.precision_ref, ctx); + auto specs = std::string(); + if (specs_.precision > 0) specs = fmt::format(".{}", specs_.precision); + if (specs_.type == presentation_type::fixed_lower) specs += 'f'; + auto real = fmt::format(ctx.locale().template get<std::locale>(), + fmt::runtime("{:" + specs + "}"), c.real()); + auto imag = fmt::format(ctx.locale().template get<std::locale>(), + fmt::runtime("{:" + specs + "}"), c.imag()); + auto fill_align_width = std::string(); + if (specs_.width > 0) fill_align_width = fmt::format(">{}", specs_.width); + return format_to(ctx.out(), runtime("{:" + fill_align_width + "}"), + c.real() != 0 ? fmt::format("({}+{}i)", real, imag) + : fmt::format("{}i", imag)); + } +}; +FMT_END_NAMESPACE + +TEST(locale_test, complex) { + std::string s = fmt::format("{}", std::complex<double>(1, 2)); + EXPECT_EQ(s, "(1+2i)"); + EXPECT_EQ(fmt::format("{:.2f}", std::complex<double>(1, 2)), "(1.00+2.00i)"); + EXPECT_EQ(fmt::format("{:8}", std::complex<double>(1, 2)), " (1+2i)"); +} + +TEST(locale_test, chrono_weekday) { + auto loc = get_locale("ru_RU.UTF-8", "Russian_Russia.1251"); + auto loc_old = std::locale::global(loc); + auto mon = fmt::weekday(1); + EXPECT_EQ(fmt::format(L"{}", mon), L"Mon"); + if (loc != std::locale::classic()) { + // {L"\x43F\x43D", L"\x41F\x43D", L"\x43F\x43D\x434", L"\x41F\x43D\x434"} + // {L"пн", L"Пн", L"пнд", L"Пнд"} + EXPECT_THAT( + (std::vector<std::wstring>{L"\x43F\x43D", L"\x41F\x43D", + L"\x43F\x43D\x434", L"\x41F\x43D\x434"}), + Contains(fmt::format(loc, L"{:L}", mon))); + } + std::locale::global(loc_old); +} + +#endif // FMT_STATIC_THOUSANDS_SEPARATOR |