aboutsummaryrefslogtreecommitdiffstats
path: root/contrib/libs/fmt/test
diff options
context:
space:
mode:
authorDevtools Arcadia <arcadia-devtools@yandex-team.ru>2022-02-07 18:08:42 +0300
committerDevtools Arcadia <arcadia-devtools@mous.vla.yp-c.yandex.net>2022-02-07 18:08:42 +0300
commit1110808a9d39d4b808aef724c861a2e1a38d2a69 (patch)
treee26c9fed0de5d9873cce7e00bc214573dc2195b7 /contrib/libs/fmt/test
downloadydb-1110808a9d39d4b808aef724c861a2e1a38d2a69.tar.gz
intermediate changes
ref:cde9a383711a11544ce7e107a78147fb96cc4029
Diffstat (limited to 'contrib/libs/fmt/test')
-rw-r--r--contrib/libs/fmt/test/assert-test.cc32
-rw-r--r--contrib/libs/fmt/test/assert-test/ya.make37
-rw-r--r--contrib/libs/fmt/test/chrono-test.cc398
-rw-r--r--contrib/libs/fmt/test/chrono-test/ya.make37
-rw-r--r--contrib/libs/fmt/test/color-test.cc99
-rw-r--r--contrib/libs/fmt/test/color-test/ya.make37
-rw-r--r--contrib/libs/fmt/test/compile-test.cc173
-rw-r--r--contrib/libs/fmt/test/compile-test/ya.make37
-rw-r--r--contrib/libs/fmt/test/core-test.cc773
-rw-r--r--contrib/libs/fmt/test/core-test/ya.make37
-rw-r--r--contrib/libs/fmt/test/format-impl-test.cc446
-rw-r--r--contrib/libs/fmt/test/format-impl-test/ya.make37
-rw-r--r--contrib/libs/fmt/test/format-test.cc2495
-rw-r--r--contrib/libs/fmt/test/format-test/ya.make39
-rw-r--r--contrib/libs/fmt/test/gtest-extra-test.cc439
-rw-r--r--contrib/libs/fmt/test/gtest-extra-test/ya.make37
-rw-r--r--contrib/libs/fmt/test/gtest-extra.cc87
-rw-r--r--contrib/libs/fmt/test/gtest-extra.h163
-rw-r--r--contrib/libs/fmt/test/header-only-test.cc3
-rw-r--r--contrib/libs/fmt/test/header-only-test/ya.make37
-rw-r--r--contrib/libs/fmt/test/header-only-test2.cc3
-rw-r--r--contrib/libs/fmt/test/locale-test.cc160
-rw-r--r--contrib/libs/fmt/test/locale-test/ya.make37
-rw-r--r--contrib/libs/fmt/test/mock-allocator.h60
-rw-r--r--contrib/libs/fmt/test/os-test.cc532
-rw-r--r--contrib/libs/fmt/test/os-test/ya.make37
-rw-r--r--contrib/libs/fmt/test/ostream-test.cc330
-rw-r--r--contrib/libs/fmt/test/ostream-test/ya.make37
-rw-r--r--contrib/libs/fmt/test/posix-mock-test.cc558
-rw-r--r--contrib/libs/fmt/test/posix-mock-test/ya.make38
-rw-r--r--contrib/libs/fmt/test/posix-mock.h78
-rw-r--r--contrib/libs/fmt/test/printf-test.cc628
-rw-r--r--contrib/libs/fmt/test/printf-test/ya.make37
-rw-r--r--contrib/libs/fmt/test/ranges-test.cc203
-rw-r--r--contrib/libs/fmt/test/ranges-test/ya.make37
-rw-r--r--contrib/libs/fmt/test/scan-test.cc116
-rw-r--r--contrib/libs/fmt/test/scan-test/ya.make37
-rw-r--r--contrib/libs/fmt/test/scan.h238
-rw-r--r--contrib/libs/fmt/test/test-assert.h32
-rw-r--r--contrib/libs/fmt/test/util.cc50
-rw-r--r--contrib/libs/fmt/test/util.h84
-rw-r--r--contrib/libs/fmt/test/ya.make55
42 files changed, 8830 insertions, 0 deletions
diff --git a/contrib/libs/fmt/test/assert-test.cc b/contrib/libs/fmt/test/assert-test.cc
new file mode 100644
index 0000000000..73f622e56b
--- /dev/null
+++ b/contrib/libs/fmt/test/assert-test.cc
@@ -0,0 +1,32 @@
+// Formatting library for C++ - FMT_ASSERT test
+//
+// It is a separate test to minimize the number of EXPECT_DEBUG_DEATH checks
+// which are slow on some platforms. In other tests FMT_ASSERT is made to throw
+// an exception which is much faster and easier to check.
+//
+// Copyright (c) 2012 - present, Victor Zverovich
+// All rights reserved.
+//
+// For the license information refer to format.h.
+
+#include "fmt/core.h"
+#include <gtest/gtest.h>
+
+TEST(AssertTest, Fail) {
+#if GTEST_HAS_DEATH_TEST
+ EXPECT_DEBUG_DEATH(FMT_ASSERT(false, "don't panic!"), "don't panic!");
+#else
+ fmt::print("warning: death tests are not supported\n");
+#endif
+}
+
+bool test_condition = false;
+
+TEST(AssertTest, DanglingElse) {
+ bool executed_else = false;
+ if (test_condition)
+ FMT_ASSERT(true, "");
+ else
+ executed_else = true;
+ EXPECT_TRUE(executed_else);
+}
diff --git a/contrib/libs/fmt/test/assert-test/ya.make b/contrib/libs/fmt/test/assert-test/ya.make
new file mode 100644
index 0000000000..22d19ae00a
--- /dev/null
+++ b/contrib/libs/fmt/test/assert-test/ya.make
@@ -0,0 +1,37 @@
+# Generated by devtools/yamaker.
+
+GTEST()
+
+WITHOUT_LICENSE_TEXTS()
+
+OWNER(
+ orivej
+ g:cpp-contrib
+)
+
+LICENSE(MIT)
+
+PEERDIR(
+ contrib/libs/fmt
+ contrib/libs/fmt/test
+)
+
+NO_COMPILER_WARNINGS()
+
+NO_UTIL()
+
+CFLAGS(
+ -DFMT_LOCALE
+ -DFMT_SHARED
+ -DGTEST_HAS_STD_WSTRING=1
+ -DGTEST_LANG_CXX11=0
+ -D_SILENCE_TR1_NAMESPACE_DEPRECATION_WARNING=1
+)
+
+SRCDIR(contrib/libs/fmt/test)
+
+SRCS(
+ assert-test.cc
+)
+
+END()
diff --git a/contrib/libs/fmt/test/chrono-test.cc b/contrib/libs/fmt/test/chrono-test.cc
new file mode 100644
index 0000000000..fa383c1446
--- /dev/null
+++ b/contrib/libs/fmt/test/chrono-test.cc
@@ -0,0 +1,398 @@
+// Formatting library for C++ - time formatting tests
+//
+// Copyright (c) 2012 - present, Victor Zverovich
+// All rights reserved.
+//
+// For the license information refer to format.h.
+
+#ifdef WIN32
+# define _CRT_SECURE_NO_WARNINGS
+#endif
+
+#include "fmt/chrono.h"
+
+#include <iomanip>
+
+#include "gtest-extra.h"
+
+std::tm make_tm() {
+ auto time = std::tm();
+ time.tm_mday = 1;
+ return time;
+}
+
+std::tm make_hour(int h) {
+ auto time = make_tm();
+ time.tm_hour = h;
+ return time;
+}
+
+std::tm make_minute(int m) {
+ auto time = make_tm();
+ time.tm_min = m;
+ return time;
+}
+
+std::tm make_second(int s) {
+ 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) {
+ 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));
+ return os.str();
+}
+
+TEST(TimeTest, Format) {
+ std::tm 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));
+}
+
+TEST(TimeTest, GrowBuffer) {
+ std::string s = "{:";
+ for (int i = 0; i < 30; ++i) s += "%c";
+ s += "}\n";
+ std::time_t t = std::time(nullptr);
+ fmt::format(s, *std::localtime(&t));
+}
+
+TEST(TimeTest, FormatToEmptyContainer) {
+ std::string s;
+ auto time = std::tm();
+ time.tm_sec = 42;
+ fmt::format_to(std::back_inserter(s), "{:%S}", time);
+ EXPECT_EQ(s, "42");
+}
+
+TEST(TimeTest, EmptyResult) { EXPECT_EQ("", fmt::format("{}", std::tm())); }
+
+static bool EqualTime(const std::tm& lhs, const std::tm& rhs) {
+ 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 &&
+ lhs.tm_wday == rhs.tm_wday && lhs.tm_yday == rhs.tm_yday &&
+ 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(TimeTest, GMTime) {
+ std::time_t t = std::time(nullptr);
+ std::tm tm = *std::gmtime(&t);
+ EXPECT_TRUE(EqualTime(tm, fmt::gmtime(t)));
+}
+
+TEST(TimeTest, TimePoint) {
+ std::chrono::system_clock::time_point point = std::chrono::system_clock::now();
+
+ 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);
+
+ EXPECT_EQ(strftime_output, fmt::format("It is {:%Y-%m-%d %H:%M:%S}", point));
+}
+
+#define EXPECT_TIME(spec, time, duration) \
+ { \
+ std::locale loc("ja_JP.utf8"); \
+ EXPECT_EQ(format_tm(time, spec, loc), \
+ fmt::format(loc, "{:" spec "}", duration)); \
+ }
+
+#ifndef FMT_STATIC_THOUSANDS_SEPARATOR
+
+TEST(ChronoTest, FormatDefault) {
+ EXPECT_EQ("42s", fmt::format("{}", std::chrono::seconds(42)));
+ EXPECT_EQ("42as",
+ fmt::format("{}", std::chrono::duration<int, std::atto>(42)));
+ EXPECT_EQ("42fs",
+ fmt::format("{}", std::chrono::duration<int, std::femto>(42)));
+ EXPECT_EQ("42ps",
+ fmt::format("{}", std::chrono::duration<int, std::pico>(42)));
+ EXPECT_EQ("42ns", fmt::format("{}", std::chrono::nanoseconds(42)));
+ EXPECT_EQ("42µs", fmt::format("{}", std::chrono::microseconds(42)));
+ EXPECT_EQ("42ms", fmt::format("{}", std::chrono::milliseconds(42)));
+ EXPECT_EQ("42cs",
+ fmt::format("{}", std::chrono::duration<int, std::centi>(42)));
+ EXPECT_EQ("42ds",
+ fmt::format("{}", std::chrono::duration<int, std::deci>(42)));
+ EXPECT_EQ("42s", fmt::format("{}", std::chrono::seconds(42)));
+ EXPECT_EQ("42das",
+ fmt::format("{}", std::chrono::duration<int, std::deca>(42)));
+ EXPECT_EQ("42hs",
+ fmt::format("{}", std::chrono::duration<int, std::hecto>(42)));
+ EXPECT_EQ("42ks",
+ fmt::format("{}", std::chrono::duration<int, std::kilo>(42)));
+ EXPECT_EQ("42Ms",
+ fmt::format("{}", std::chrono::duration<int, std::mega>(42)));
+ EXPECT_EQ("42Gs",
+ fmt::format("{}", std::chrono::duration<int, std::giga>(42)));
+ EXPECT_EQ("42Ts",
+ fmt::format("{}", std::chrono::duration<int, std::tera>(42)));
+ EXPECT_EQ("42Ps",
+ fmt::format("{}", std::chrono::duration<int, std::peta>(42)));
+ EXPECT_EQ("42Es",
+ fmt::format("{}", std::chrono::duration<int, std::exa>(42)));
+ EXPECT_EQ("42m", fmt::format("{}", std::chrono::minutes(42)));
+ EXPECT_EQ("42h", fmt::format("{}", std::chrono::hours(42)));
+ EXPECT_EQ(
+ "42[15]s",
+ fmt::format("{}", std::chrono::duration<int, std::ratio<15, 1>>(42)));
+ EXPECT_EQ(
+ "42[15/4]s",
+ 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) {
+ auto s = std::chrono::seconds(42);
+ EXPECT_EQ("42s ", fmt::format("{:5}", s));
+ EXPECT_EQ("42s ", fmt::format("{:{}}", s, 5));
+ EXPECT_EQ(" 42s", fmt::format("{:>5}", s));
+ EXPECT_EQ("**42s**", fmt::format("{:*^7}", s));
+ EXPECT_EQ("03:25:45 ",
+ fmt::format("{:12%H:%M:%S}", std::chrono::seconds(12345)));
+ EXPECT_EQ(" 03:25:45",
+ fmt::format("{:>12%H:%M:%S}", std::chrono::seconds(12345)));
+ EXPECT_EQ("~~03:25:45~~",
+ fmt::format("{:~^12%H:%M:%S}", std::chrono::seconds(12345)));
+ EXPECT_EQ("03:25:45 ",
+ fmt::format("{:{}%H:%M:%S}", std::chrono::seconds(12345), 12));
+}
+
+TEST(ChronoTest, FormatSpecs) {
+ 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)));
+ EXPECT_EQ("00", fmt::format("{:%S}", std::chrono::seconds(0)));
+ EXPECT_EQ("00", fmt::format("{:%S}", std::chrono::seconds(60)));
+ EXPECT_EQ("42", fmt::format("{:%S}", std::chrono::seconds(42)));
+ EXPECT_EQ("01.234", fmt::format("{:%S}", std::chrono::milliseconds(1234)));
+ EXPECT_EQ("00", fmt::format("{:%M}", std::chrono::minutes(0)));
+ EXPECT_EQ("00", fmt::format("{:%M}", std::chrono::minutes(60)));
+ EXPECT_EQ("42", fmt::format("{:%M}", std::chrono::minutes(42)));
+ EXPECT_EQ("01", fmt::format("{:%M}", std::chrono::seconds(61)));
+ EXPECT_EQ("00", fmt::format("{:%H}", std::chrono::hours(0)));
+ EXPECT_EQ("00", fmt::format("{:%H}", std::chrono::hours(24)));
+ EXPECT_EQ("14", fmt::format("{:%H}", std::chrono::hours(14)));
+ EXPECT_EQ("01", fmt::format("{:%H}", std::chrono::minutes(61)));
+ EXPECT_EQ("12", fmt::format("{:%I}", std::chrono::hours(0)));
+ EXPECT_EQ("12", fmt::format("{:%I}", std::chrono::hours(12)));
+ EXPECT_EQ("12", fmt::format("{:%I}", std::chrono::hours(24)));
+ EXPECT_EQ("04", fmt::format("{:%I}", std::chrono::hours(4)));
+ EXPECT_EQ("02", fmt::format("{:%I}", std::chrono::hours(14)));
+ EXPECT_EQ("03:25:45",
+ fmt::format("{:%H:%M:%S}", std::chrono::seconds(12345)));
+ EXPECT_EQ("03:25", fmt::format("{:%R}", std::chrono::seconds(12345)));
+ EXPECT_EQ("03:25:45", fmt::format("{:%T}", std::chrono::seconds(12345)));
+ EXPECT_EQ("12345", fmt::format("{:%Q}", std::chrono::seconds(12345)));
+ EXPECT_EQ("s", fmt::format("{:%q}", std::chrono::seconds(12345)));
+}
+
+TEST(ChronoTest, InvalidSpecs) {
+ 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,
+ "invalid format");
+ EXPECT_THROW_MSG(fmt::format("{:%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;
+ }
+ 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));
+ EXPECT_TIME("%OS", make_second(42), std::chrono::seconds(42));
+ auto time = make_tm();
+ time.tm_hour = 3;
+ time.tm_min = 25;
+ time.tm_sec = 45;
+ auto sec = std::chrono::seconds(12345);
+ EXPECT_TIME("%r", time, sec);
+ EXPECT_TIME("%p", time, sec);
+}
+
+typedef std::chrono::duration<double, std::milli> dms;
+
+TEST(ChronoTest, FormatDefaultFP) {
+ typedef std::chrono::duration<float> fs;
+ EXPECT_EQ("1.234s", fmt::format("{}", fs(1.234)));
+ typedef std::chrono::duration<float, std::milli> fms;
+ EXPECT_EQ("1.234ms", fmt::format("{}", fms(1.234)));
+ typedef std::chrono::duration<double> ds;
+ EXPECT_EQ("1.234s", fmt::format("{}", ds(1.234)));
+ 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");
+ EXPECT_EQ("1.2ms", fmt::format("{:.1}", dms(1.234)));
+ EXPECT_EQ("1.23ms", fmt::format("{:.{}}", dms(1.234), 2));
+}
+
+TEST(ChronoTest, FormatFullSpecs) {
+ 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)));
+}
+
+TEST(ChronoTest, FormatSimpleQq) {
+ 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;
+ EXPECT_EQ("1.234 ms", fmt::format("{:%Q %q}", fms(1.234)));
+ typedef std::chrono::duration<double> ds;
+ EXPECT_EQ("1.234 s", fmt::format("{:%Q %q}", ds(1.234)));
+ 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");
+ 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) {
+ 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)));
+}
+
+TEST(ChronoTest, InvalidWidthId) {
+ EXPECT_THROW(fmt::format("{:{o}", std::chrono::seconds(0)),
+ fmt::format_error);
+}
+
+TEST(ChronoTest, InvalidColons) {
+ EXPECT_THROW(fmt::format("{0}=:{0::", std::chrono::seconds(0)),
+ fmt::format_error);
+}
+
+TEST(ChronoTest, NegativeDurations) {
+ EXPECT_EQ("-12345", fmt::format("{:%Q}", std::chrono::seconds(-12345)));
+ EXPECT_EQ("-03:25:45",
+ fmt::format("{:%H:%M:%S}", std::chrono::seconds(-12345)));
+ EXPECT_EQ("-00:01",
+ fmt::format("{:%M:%S}", std::chrono::duration<double>(-1)));
+ EXPECT_EQ("s", fmt::format("{:%q}", std::chrono::seconds(-12345)));
+ EXPECT_EQ("-00.127",
+ fmt::format("{:%S}",
+ std::chrono::duration<signed char, std::milli>{-127}));
+ auto min = std::numeric_limits<int>::min();
+ EXPECT_EQ(fmt::format("{}", min),
+ 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));
+ 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)),
+ "1as");
+ EXPECT_EQ(fmt::format("{:%R}", std::chrono::duration<char, std::mega>{2}),
+ "03:33");
+ EXPECT_EQ(fmt::format("{:%T}", std::chrono::duration<char, std::mega>{2}),
+ "03:33:20");
+}
+
+#endif // FMT_STATIC_THOUSANDS_SEPARATOR
diff --git a/contrib/libs/fmt/test/chrono-test/ya.make b/contrib/libs/fmt/test/chrono-test/ya.make
new file mode 100644
index 0000000000..7982d65069
--- /dev/null
+++ b/contrib/libs/fmt/test/chrono-test/ya.make
@@ -0,0 +1,37 @@
+# Generated by devtools/yamaker.
+
+GTEST()
+
+WITHOUT_LICENSE_TEXTS()
+
+OWNER(
+ orivej
+ g:cpp-contrib
+)
+
+LICENSE(MIT)
+
+PEERDIR(
+ contrib/libs/fmt
+ contrib/libs/fmt/test
+)
+
+NO_COMPILER_WARNINGS()
+
+NO_UTIL()
+
+CFLAGS(
+ -DFMT_LOCALE
+ -DFMT_SHARED
+ -DGTEST_HAS_STD_WSTRING=1
+ -DGTEST_LANG_CXX11=0
+ -D_SILENCE_TR1_NAMESPACE_DEPRECATION_WARNING=1
+)
+
+SRCDIR(contrib/libs/fmt/test)
+
+SRCS(
+ chrono-test.cc
+)
+
+END()
diff --git a/contrib/libs/fmt/test/color-test.cc b/contrib/libs/fmt/test/color-test.cc
new file mode 100644
index 0000000000..3073808541
--- /dev/null
+++ b/contrib/libs/fmt/test/color-test.cc
@@ -0,0 +1,99 @@
+// Formatting library for C++ - color tests
+//
+// Copyright (c) 2012 - present, Victor Zverovich
+// All rights reserved.
+//
+// For the license information refer to format.h.
+
+#include "fmt/color.h"
+
+#include <iterator>
+#include <string>
+#include <utility>
+
+#include "gtest-extra.h"
+
+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) {
+ 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::italic, "italic"),
+ "\x1b[3mitalic\x1b[0m");
+ EXPECT_EQ(fmt::format(fmt::emphasis::underline, "underline"),
+ "\x1b[4munderline\x1b[0m");
+ EXPECT_EQ(fmt::format(fmt::emphasis::strikethrough, "strikethrough"),
+ "\x1b[9mstrikethrough\x1b[0m");
+ EXPECT_EQ(
+ fmt::format(fg(fmt::color::blue) | fmt::emphasis::bold, "blue/bold"),
+ "\x1b[1m\x1b[38;2;000;000;255mblue/bold\x1b[0m");
+ EXPECT_EQ(fmt::format(fmt::emphasis::bold, "bold error"),
+ "\x1b[1mbold error\x1b[0m");
+ EXPECT_EQ(fmt::format(fg(fmt::color::blue), "blue log"),
+ "\x1b[38;2;000;000;255mblue log\x1b[0m");
+ EXPECT_EQ(fmt::format(fmt::text_style(), "hi"), "hi");
+ EXPECT_EQ(fmt::format(fg(fmt::terminal_color::red), "tred"),
+ "\x1b[31mtred\x1b[0m");
+ EXPECT_EQ(fmt::format(bg(fmt::terminal_color::cyan), "tcyan"),
+ "\x1b[46mtcyan\x1b[0m");
+ EXPECT_EQ(fmt::format(fg(fmt::terminal_color::bright_green), "tbgreen"),
+ "\x1b[92mtbgreen\x1b[0m");
+ EXPECT_EQ(fmt::format(bg(fmt::terminal_color::bright_magenta), "tbmagenta"),
+ "\x1b[105mtbmagenta\x1b[0m");
+ EXPECT_EQ(fmt::format(fg(fmt::terminal_color::red), "{}", "foo"),
+ "\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);
+
+ EXPECT_EQ(fmt::to_string(out),
+ "\x1b[38;2;255;020;030mrgb(255,20,30)123\x1b[0m");
+}
diff --git a/contrib/libs/fmt/test/color-test/ya.make b/contrib/libs/fmt/test/color-test/ya.make
new file mode 100644
index 0000000000..22e6654b0f
--- /dev/null
+++ b/contrib/libs/fmt/test/color-test/ya.make
@@ -0,0 +1,37 @@
+# Generated by devtools/yamaker.
+
+GTEST()
+
+WITHOUT_LICENSE_TEXTS()
+
+OWNER(
+ orivej
+ g:cpp-contrib
+)
+
+LICENSE(MIT)
+
+PEERDIR(
+ contrib/libs/fmt
+ contrib/libs/fmt/test
+)
+
+NO_COMPILER_WARNINGS()
+
+NO_UTIL()
+
+CFLAGS(
+ -DFMT_LOCALE
+ -DFMT_SHARED
+ -DGTEST_HAS_STD_WSTRING=1
+ -DGTEST_LANG_CXX11=0
+ -D_SILENCE_TR1_NAMESPACE_DEPRECATION_WARNING=1
+)
+
+SRCDIR(contrib/libs/fmt/test)
+
+SRCS(
+ color-test.cc
+)
+
+END()
diff --git a/contrib/libs/fmt/test/compile-test.cc b/contrib/libs/fmt/test/compile-test.cc
new file mode 100644
index 0000000000..9bb9bb7d9e
--- /dev/null
+++ b/contrib/libs/fmt/test/compile-test.cc
@@ -0,0 +1,173 @@
+// 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 <string>
+#include <type_traits>
+
+// Check that fmt/compile.h compiles with windows.h included before it.
+#ifdef _WIN32
+# include <windows.h>
+#endif
+
+#include "fmt/compile.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(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(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(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), " ");
+}
+
+TEST(CompileTest, FormattedSize) {
+ auto f = fmt::detail::compile<int>("{:10}");
+ EXPECT_EQ(fmt::formatted_size(f, 42), 10);
+}
+
+TEST(CompileTest, MultipleTypes) {
+ auto f = fmt::detail::compile<int, int>("{} {}");
+ EXPECT_EQ(fmt::format(f, 42, 42), "42 42");
+}
+
+struct test_formattable {};
+
+FMT_BEGIN_NAMESPACE
+template <> struct formatter<test_formattable> : formatter<const char*> {
+ template <typename FormatContext>
+ auto format(test_formattable, FormatContext& ctx) -> decltype(ctx.out()) {
+ return formatter<const char*>::format("foo", ctx);
+ }
+};
+FMT_END_NAMESPACE
+
+TEST(CompileTest, FormatUserDefinedType) {
+ auto f = fmt::detail::compile<test_formattable>("{}");
+ EXPECT_EQ(fmt::format(f, test_formattable()), "foo");
+}
+
+TEST(CompileTest, EmptyFormatString) {
+ auto f = fmt::detail::compile<>("");
+ EXPECT_EQ(fmt::format(f), "");
+}
+
+#ifdef __cpp_if_constexpr
+TEST(CompileTest, FormatDefault) {
+ EXPECT_EQ("42", fmt::format(FMT_COMPILE("{}"), 42));
+ EXPECT_EQ("42", fmt::format(FMT_COMPILE("{}"), 42u));
+ EXPECT_EQ("42", fmt::format(FMT_COMPILE("{}"), 42ll));
+ EXPECT_EQ("42", fmt::format(FMT_COMPILE("{}"), 42ull));
+ EXPECT_EQ("true", fmt::format(FMT_COMPILE("{}"), true));
+ EXPECT_EQ("x", fmt::format(FMT_COMPILE("{}"), 'x'));
+ EXPECT_EQ("4.2", fmt::format(FMT_COMPILE("{}"), 4.2));
+ 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()));
+}
+
+TEST(CompileTest, FormatWideString) {
+ EXPECT_EQ(L"42", fmt::format(FMT_COMPILE(L"{}"), 42));
+}
+
+TEST(CompileTest, FormatSpecs) {
+ EXPECT_EQ("42", fmt::format(FMT_COMPILE("{:x}"), 0x42));
+}
+
+TEST(CompileTest, DynamicWidth) {
+ EXPECT_EQ(" 42foo ",
+ fmt::format(FMT_COMPILE("{:{}}{:{}}"), 42, 4, "foo", 5));
+}
+
+TEST(CompileTest, FormatTo) {
+ char buf[8];
+ auto end = fmt::format_to(buf, FMT_COMPILE("{}"), 42);
+ *end = '\0';
+ EXPECT_STREQ("42", buf);
+ end = fmt::format_to(buf, FMT_COMPILE("{:x}"), 42);
+ *end = '\0';
+ EXPECT_STREQ("2a", buf);
+}
+
+TEST(CompileTest, FormatToNWithCompileMacro) {
+ constexpr auto buffer_size = 8;
+ char buffer[buffer_size];
+ auto res = fmt::format_to_n(buffer, buffer_size, FMT_COMPILE("{}"), 42);
+ *res.out = '\0';
+ EXPECT_STREQ("42", buffer);
+ res = fmt::format_to_n(buffer, buffer_size, FMT_COMPILE("{:x}"), 42);
+ *res.out = '\0';
+ EXPECT_STREQ("2a", buffer);
+}
+
+TEST(CompileTest, TextAndArg) {
+ EXPECT_EQ(">>>42<<<", fmt::format(FMT_COMPILE(">>>{}<<<"), 42));
+ EXPECT_EQ("42!", fmt::format(FMT_COMPILE("{}!"), 42));
+}
+#endif
diff --git a/contrib/libs/fmt/test/compile-test/ya.make b/contrib/libs/fmt/test/compile-test/ya.make
new file mode 100644
index 0000000000..0173e7e70f
--- /dev/null
+++ b/contrib/libs/fmt/test/compile-test/ya.make
@@ -0,0 +1,37 @@
+# Generated by devtools/yamaker.
+
+GTEST()
+
+WITHOUT_LICENSE_TEXTS()
+
+OWNER(
+ orivej
+ g:cpp-contrib
+)
+
+LICENSE(MIT)
+
+PEERDIR(
+ contrib/libs/fmt
+ contrib/libs/fmt/test
+)
+
+NO_COMPILER_WARNINGS()
+
+NO_UTIL()
+
+CFLAGS(
+ -DFMT_LOCALE
+ -DFMT_SHARED
+ -DGTEST_HAS_STD_WSTRING=1
+ -DGTEST_LANG_CXX11=0
+ -D_SILENCE_TR1_NAMESPACE_DEPRECATION_WARNING=1
+)
+
+SRCDIR(contrib/libs/fmt/test)
+
+SRCS(
+ compile-test.cc
+)
+
+END()
diff --git a/contrib/libs/fmt/test/core-test.cc b/contrib/libs/fmt/test/core-test.cc
new file mode 100644
index 0000000000..a5fd01fa4d
--- /dev/null
+++ b/contrib/libs/fmt/test/core-test.cc
@@ -0,0 +1,773 @@
+// Formatting library for C++ - core tests
+//
+// Copyright (c) 2012 - present, Victor Zverovich
+// All rights reserved.
+//
+// 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>
+#include "test-assert.h"
+
+// Check if fmt/core.h compiles with windows.h included before it.
+#ifdef _WIN32
+# include <windows.h>
+#endif
+
+#include "fmt/core.h"
+
+#undef min
+#undef max
+
+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 {};
+
+FMT_BEGIN_NAMESPACE
+template <typename Char> struct formatter<test_struct, Char> {
+ template <typename ParseContext>
+ auto parse(ParseContext& ctx) -> decltype(ctx.begin()) {
+ return ctx.begin();
+ }
+
+ auto format(test_struct, format_context& ctx) -> decltype(ctx.out()) {
+ const Char* test = "test";
+ return std::copy_n(test, std::strlen(test), ctx.out());
+ }
+};
+FMT_END_NAMESPACE
+
+#if !FMT_GCC_VERSION || FMT_GCC_VERSION >= 470
+TEST(BufferTest, Noncopyable) {
+ EXPECT_FALSE(std::is_copy_constructible<buffer<char>>::value);
+# if !FMT_MSC_VER
+ // std::is_copy_assignable is broken in MSVC2013.
+ EXPECT_FALSE(std::is_copy_assignable<buffer<char>>::value);
+# endif
+}
+
+TEST(BufferTest, Nonmoveable) {
+ EXPECT_FALSE(std::is_move_constructible<buffer<char>>::value);
+# if !FMT_MSC_VER
+ // std::is_move_assignable is broken in MSVC2013.
+ EXPECT_FALSE(std::is_move_assignable<buffer<char>>::value);
+# endif
+}
+#endif
+
+TEST(BufferTest, Indestructible) {
+ static_assert(!std::is_destructible<fmt::detail::buffer<int>>(),
+ "buffer's destructor is protected");
+}
+
+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)); }
+
+ mock_buffer(T* data = nullptr, size_t capacity = 0) {
+ this->set(data, capacity);
+ ON_CALL(*this, do_grow(_)).WillByDefault(Invoke([](size_t capacity) {
+ return capacity;
+ }));
+ }
+};
+
+TEST(BufferTest, Ctor) {
+ {
+ mock_buffer<int> buffer;
+ EXPECT_EQ(nullptr, buffer.data());
+ EXPECT_EQ(static_cast<size_t>(0), buffer.size());
+ EXPECT_EQ(static_cast<size_t>(0), buffer.capacity());
+ }
+ {
+ int dummy;
+ mock_buffer<int> buffer(&dummy);
+ EXPECT_EQ(&dummy, &buffer[0]);
+ EXPECT_EQ(static_cast<size_t>(0), buffer.size());
+ EXPECT_EQ(static_cast<size_t>(0), buffer.capacity());
+ }
+ {
+ int dummy;
+ size_t capacity = std::numeric_limits<size_t>::max();
+ mock_buffer<int> buffer(&dummy, capacity);
+ EXPECT_EQ(&dummy, &buffer[0]);
+ EXPECT_EQ(static_cast<size_t>(0), buffer.size());
+ EXPECT_EQ(capacity, buffer.capacity());
+ }
+}
+
+TEST(BufferTest, Access) {
+ char data[10];
+ mock_buffer<char> buffer(data, sizeof(data));
+ buffer[0] = 11;
+ EXPECT_EQ(11, buffer[0]);
+ buffer[3] = 42;
+ EXPECT_EQ(42, *(&buffer[0] + 3));
+ const fmt::detail::buffer<char>& const_buffer = buffer;
+ EXPECT_EQ(42, const_buffer[3]);
+}
+
+TEST(BufferTest, TryResize) {
+ char data[123];
+ mock_buffer<char> buffer(data, sizeof(data));
+ buffer[10] = 42;
+ EXPECT_EQ(42, buffer[10]);
+ buffer.try_resize(20);
+ EXPECT_EQ(20u, buffer.size());
+ EXPECT_EQ(123u, buffer.capacity());
+ EXPECT_EQ(42, buffer[10]);
+ buffer.try_resize(5);
+ EXPECT_EQ(5u, buffer.size());
+ EXPECT_EQ(123u, buffer.capacity());
+ EXPECT_EQ(42, buffer[10]);
+ // Check if try_resize calls grow.
+ EXPECT_CALL(buffer, do_grow(124));
+ buffer.try_resize(124);
+ EXPECT_CALL(buffer, do_grow(200));
+ buffer.try_resize(200);
+}
+
+TEST(BufferTest, TryResizePartial) {
+ char data[10];
+ mock_buffer<char> buffer(data, sizeof(data));
+ EXPECT_CALL(buffer, do_grow(20)).WillOnce(Return(15));
+ buffer.try_resize(20);
+ EXPECT_EQ(buffer.capacity(), 15);
+ EXPECT_EQ(buffer.size(), 15);
+}
+
+TEST(BufferTest, Clear) {
+ mock_buffer<char> buffer;
+ EXPECT_CALL(buffer, do_grow(20));
+ buffer.try_resize(20);
+ buffer.try_resize(0);
+ EXPECT_EQ(static_cast<size_t>(0), buffer.size());
+ EXPECT_EQ(20u, buffer.capacity());
+}
+
+TEST(BufferTest, Append) {
+ char data[15];
+ mock_buffer<char> buffer(data, 10);
+ auto test = "test";
+ buffer.append(test, test + 5);
+ EXPECT_STREQ(test, &buffer[0]);
+ EXPECT_EQ(5u, buffer.size());
+ buffer.try_resize(10);
+ EXPECT_CALL(buffer, do_grow(12));
+ buffer.append(test, test + 2);
+ EXPECT_EQ('t', buffer[10]);
+ EXPECT_EQ('e', buffer[11]);
+ EXPECT_EQ(12u, buffer.size());
+}
+
+TEST(BufferTest, AppendPartial) {
+ char data[10];
+ mock_buffer<char> buffer(data, sizeof(data));
+ testing::InSequence seq;
+ EXPECT_CALL(buffer, do_grow(15)).WillOnce(Return(10));
+ EXPECT_CALL(buffer, do_grow(15)).WillOnce(Invoke([&buffer](size_t) {
+ EXPECT_EQ(fmt::string_view(buffer.data(), buffer.size()), "0123456789");
+ buffer.clear();
+ return 10;
+ }));
+ auto test = "0123456789abcde";
+ buffer.append(test, test + 15);
+}
+
+TEST(BufferTest, AppendAllocatesEnoughStorage) {
+ char data[19];
+ mock_buffer<char> buffer(data, 10);
+ auto test = "abcdefgh";
+ buffer.try_resize(10);
+ EXPECT_CALL(buffer, do_grow(19));
+ 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;
+
+ template <typename T> struct formatter_type {
+ template <typename ParseContext>
+ auto parse(ParseContext& ctx) -> decltype(ctx.begin()) {
+ return ctx.begin();
+ }
+
+ const char* format(const T&, custom_context& ctx) {
+ ctx.called = true;
+ return nullptr;
+ }
+ };
+
+ bool called;
+ fmt::format_parse_context ctx;
+
+ fmt::format_parse_context& parse_context() { return ctx; }
+ void advance_to(const char*) {}
+};
+
+TEST(ArgTest, MakeValueWithCustomContext) {
+ 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);
+ 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 {};
+
+template <typename T> struct mock_visitor {
+ template <typename U> struct result { using type = test_result; };
+
+ mock_visitor() {
+ ON_CALL(*this, visit(_)).WillByDefault(Return(test_result()));
+ }
+
+ MOCK_METHOD1_T(visit, test_result(T value));
+ MOCK_METHOD0_T(unexpected, void());
+
+ test_result operator()(T value) { return visit(value); }
+
+ template <typename U> test_result operator()(U) {
+ unexpected();
+ return test_result();
+ }
+};
+
+template <typename T> struct visit_type { using type = T; };
+
+#define VISIT_TYPE(type_, visit_type_) \
+ template <> struct visit_type<type_> { using type = visit_type_; }
+
+VISIT_TYPE(signed char, int);
+VISIT_TYPE(unsigned char, unsigned);
+VISIT_TYPE(short, int);
+VISIT_TYPE(unsigned short, unsigned);
+
+#if LONG_MAX == INT_MAX
+VISIT_TYPE(long, int);
+VISIT_TYPE(unsigned long, unsigned);
+#else
+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(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) \
+ }
+
+template <typename T> class NumericArgTest : 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);
+
+template <typename T>
+fmt::enable_if_t<std::is_integral<T>::value, T> test_value() {
+ return static_cast<T>(42);
+}
+
+template <typename T>
+fmt::enable_if_t<std::is_floating_point<T>::value, 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);
+}
+
+TEST(ArgTest, CharArg) {
+ CHECK_ARG_(char, 'a', 'a');
+ CHECK_ARG_(wchar_t, L'a', 'a');
+ CHECK_ARG_(wchar_t, L'a', L'a');
+}
+
+TEST(ArgTest, StringArg) {
+ char str_data[] = "test";
+ char* str = str_data;
+ const char* cstr = str;
+ CHECK_ARG_(char, cstr, str);
+
+ auto sref = string_view(str);
+ CHECK_ARG_(char, sref, std::string(str));
+}
+
+TEST(ArgTest, WStringArg) {
+ 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));
+}
+
+TEST(ArgTest, PointerArg) {
+ void* p = nullptr;
+ const void* cp = nullptr;
+ CHECK_ARG_(char, cp, p);
+ CHECK_ARG_(wchar_t, cp, p);
+ CHECK_ARG(cp, );
+}
+
+struct check_custom {
+ test_result operator()(
+ fmt::basic_format_arg<fmt::format_context>::handle h) const {
+ struct test_buffer final : fmt::detail::buffer<char> {
+ char data[10];
+ test_buffer() : fmt::detail::buffer<char>(data, 0, 10) {}
+ void grow(size_t) {}
+ } buffer;
+ fmt::format_parse_context parse_ctx("");
+ fmt::format_context ctx{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;
+ 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));
+}
+
+TEST(ArgTest, VisitInvalidArg) {
+ testing::StrictMock<mock_visitor<fmt::monostate>> visitor;
+ EXPECT_CALL(visitor, visit(_));
+ fmt::basic_format_arg<fmt::format_context> arg;
+ 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';
+
+ std::string 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(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"; }
+};
+
+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(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");
+}
+
+TEST(StringViewTest, ValueType) {
+ static_assert(std::is_same<string_view::value_type, char>::value, "");
+}
+
+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));
+}
+
+// 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(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>();
+}
+
+struct enabled_formatter {};
+struct disabled_formatter {};
+struct disabled_formatter_convertible {
+ operator int() const { return 42; }
+};
+
+FMT_BEGIN_NAMESPACE
+template <> struct formatter<enabled_formatter> {
+ auto parse(format_parse_context& ctx) -> decltype(ctx.begin()) {
+ return ctx.begin();
+ }
+ auto format(enabled_formatter, format_context& ctx) -> decltype(ctx.out()) {
+ return ctx.out();
+ }
+};
+FMT_END_NAMESPACE
+
+TEST(CoreTest, HasFormatter) {
+ using fmt::has_formatter;
+ using context = fmt::format_context;
+ static_assert(has_formatter<enabled_formatter, context>::value, "");
+ static_assert(!has_formatter<disabled_formatter, context>::value, "");
+ static_assert(!has_formatter<disabled_formatter_convertible, context>::value,
+ "");
+}
+
+struct convertible_to_int {
+ operator int() const { return 42; }
+};
+
+struct convertible_to_c_string {
+ operator const char*() const { return "foo"; }
+};
+
+FMT_BEGIN_NAMESPACE
+template <> struct formatter<convertible_to_int> {
+ auto parse(format_parse_context& ctx) -> decltype(ctx.begin()) {
+ return ctx.begin();
+ }
+ auto format(convertible_to_int, format_context& ctx) -> decltype(ctx.out()) {
+ return std::copy_n("foo", 3, ctx.out());
+ }
+};
+
+template <> struct formatter<convertible_to_c_string> {
+ auto parse(format_parse_context& ctx) -> decltype(ctx.begin()) {
+ return ctx.begin();
+ }
+ auto format(convertible_to_c_string, format_context& ctx)
+ -> decltype(ctx.out()) {
+ return std::copy_n("bar", 3, ctx.out());
+ }
+};
+FMT_END_NAMESPACE
+
+TEST(CoreTest, FormatterOverridesImplicitConversion) {
+ 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(CoreTest, ToStringViewForeignStrings) {
+ using namespace my_ns;
+ EXPECT_EQ(to_string_view(my_string<char>("42")), "42");
+ fmt::detail::type type =
+ fmt::detail::mapped_type_constant<my_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"; }
+};
+
+struct implicitly_convertible_to_string_view {
+ operator fmt::string_view() const { return "foo"; }
+};
+
+TEST(CoreTest, FormatImplicitlyConvertibleToStringView) {
+ EXPECT_EQ("foo", fmt::format("{}", implicitly_convertible_to_string_view()));
+}
+
+// std::is_constructible is broken in MSVC until version 2015.
+#if !FMT_MSC_VER || FMT_MSC_VER >= 1900
+struct explicitly_convertible_to_string_view {
+ explicit operator fmt::string_view() const { return "foo"; }
+};
+
+TEST(CoreTest, FormatExplicitlyConvertibleToStringView) {
+ EXPECT_EQ("foo", fmt::format("{}", explicitly_convertible_to_string_view()));
+}
+
+# ifdef FMT_USE_STRING_VIEW
+struct explicitly_convertible_to_std_string_view {
+ explicit operator std::string_view() const { return "foo"; }
+};
+
+TEST(CoreTest, FormatExplicitlyConvertibleToStdStringView) {
+ EXPECT_EQ("foo",
+ fmt::format("{}", explicitly_convertible_to_std_string_view()));
+}
+# endif
+#endif
+
+struct disabled_rvalue_conversion {
+ operator const char*() const& { return "foo"; }
+ operator const char*() & { return "foo"; }
+ operator const char*() const&& = delete;
+ operator const char*() && = delete;
+};
+
+TEST(CoreTest, DisabledRValueConversion) {
+ EXPECT_EQ("foo", fmt::format("{}", disabled_rvalue_conversion()));
+}
diff --git a/contrib/libs/fmt/test/core-test/ya.make b/contrib/libs/fmt/test/core-test/ya.make
new file mode 100644
index 0000000000..8c320f4810
--- /dev/null
+++ b/contrib/libs/fmt/test/core-test/ya.make
@@ -0,0 +1,37 @@
+# Generated by devtools/yamaker.
+
+GTEST()
+
+WITHOUT_LICENSE_TEXTS()
+
+OWNER(
+ orivej
+ g:cpp-contrib
+)
+
+LICENSE(MIT)
+
+PEERDIR(
+ contrib/libs/fmt
+ contrib/libs/fmt/test
+)
+
+NO_COMPILER_WARNINGS()
+
+NO_UTIL()
+
+CFLAGS(
+ -DFMT_LOCALE
+ -DFMT_SHARED
+ -DGTEST_HAS_STD_WSTRING=1
+ -DGTEST_LANG_CXX11=0
+ -D_SILENCE_TR1_NAMESPACE_DEPRECATION_WARNING=1
+)
+
+SRCDIR(contrib/libs/fmt/test)
+
+SRCS(
+ core-test.cc
+)
+
+END()
diff --git a/contrib/libs/fmt/test/format-impl-test.cc b/contrib/libs/fmt/test/format-impl-test.cc
new file mode 100644
index 0000000000..66b55b5381
--- /dev/null
+++ b/contrib/libs/fmt/test/format-impl-test.cc
@@ -0,0 +1,446 @@
+// Formatting library for C++ - formatting library implementation tests
+//
+// Copyright (c) 2012 - present, Victor Zverovich
+// All rights reserved.
+//
+// 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"
+
+#ifdef _WIN32
+# include <windows.h>
+# undef max
+#endif
+
+using fmt::detail::bigint;
+using fmt::detail::fp;
+using fmt::detail::max_value;
+
+static_assert(!std::is_copy_constructible<bigint>::value, "");
+static_assert(!std::is_copy_assignable<bigint>::value, "");
+
+TEST(BigIntTest, Construct) {
+ EXPECT_EQ("", fmt::format("{}", bigint()));
+ EXPECT_EQ("42", fmt::format("{}", bigint(0x42)));
+ EXPECT_EQ("123456789abcedf0", fmt::format("{}", bigint(0x123456789abcedf0)));
+}
+
+TEST(BigIntTest, Compare) {
+ bigint n1(42);
+ bigint n2(42);
+ EXPECT_EQ(compare(n1, n2), 0);
+ n2 <<= 32;
+ EXPECT_LT(compare(n1, n2), 0);
+ bigint n3(43);
+ EXPECT_LT(compare(n1, n3), 0);
+ EXPECT_GT(compare(n3, n1), 0);
+ bigint n4(42 * 0x100000001);
+ EXPECT_LT(compare(n2, n4), 0);
+ EXPECT_GT(compare(n4, n2), 0);
+}
+
+TEST(BigIntTest, AddCompare) {
+ 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);
+ EXPECT_GT(add_compare(bigint(1) <<= 32, bigint(0), bigint(0xffffffff)), 0);
+ EXPECT_GT(add_compare(bigint(0), bigint(1) <<= 32, bigint(0xffffffff)), 0);
+ EXPECT_GT(add_compare(bigint(42), bigint(1), bigint(42)), 0);
+ EXPECT_GT(add_compare(bigint(0xffffffff), bigint(1), bigint(0xffffffff)), 0);
+ EXPECT_LT(add_compare(bigint(10), bigint(10), bigint(22)), 0);
+ EXPECT_LT(add_compare(bigint(0x100000010), bigint(0x100000010),
+ bigint(0x300000010)),
+ 0);
+ EXPECT_GT(add_compare(bigint(0x1ffffffff), bigint(0x100000002),
+ bigint(0x300000000)),
+ 0);
+ EXPECT_EQ(add_compare(bigint(0x1ffffffff), bigint(0x100000002),
+ bigint(0x300000001)),
+ 0);
+ EXPECT_LT(add_compare(bigint(0x1ffffffff), bigint(0x100000002),
+ bigint(0x300000002)),
+ 0);
+ EXPECT_LT(add_compare(bigint(0x1ffffffff), bigint(0x100000002),
+ bigint(0x300000003)),
+ 0);
+}
+
+TEST(BigIntTest, ShiftLeft) {
+ bigint n(0x42);
+ n <<= 0;
+ EXPECT_EQ("42", fmt::format("{}", n));
+ n <<= 1;
+ EXPECT_EQ("84", fmt::format("{}", n));
+ n <<= 25;
+ EXPECT_EQ("108000000", fmt::format("{}", n));
+}
+
+TEST(BigIntTest, Multiply) {
+ bigint n(0x42);
+ EXPECT_THROW(n *= 0, assertion_failure);
+ n *= 1;
+ EXPECT_EQ("42", fmt::format("{}", n));
+ n *= 2;
+ EXPECT_EQ("84", fmt::format("{}", n));
+ n *= 0x12345678;
+ EXPECT_EQ("962fc95e0", fmt::format("{}", n));
+ bigint bigmax(max_value<uint32_t>());
+ bigmax *= max_value<uint32_t>();
+ EXPECT_EQ("fffffffe00000001", fmt::format("{}", bigmax));
+ bigmax.assign(max_value<uint64_t>());
+ bigmax *= max_value<uint64_t>();
+ EXPECT_EQ("fffffffffffffffe0000000000000001", fmt::format("{}", bigmax));
+}
+
+TEST(BigIntTest, Accumulator) {
+ fmt::detail::accumulator acc;
+ EXPECT_EQ(acc.lower, 0);
+ EXPECT_EQ(acc.upper, 0);
+ acc.upper = 12;
+ acc.lower = 34;
+ EXPECT_EQ(static_cast<uint32_t>(acc), 34);
+ acc += 56;
+ EXPECT_EQ(acc.lower, 90);
+ acc += fmt::detail::max_value<uint64_t>();
+ EXPECT_EQ(acc.upper, 13);
+ EXPECT_EQ(acc.lower, 89);
+ acc >>= 32;
+ EXPECT_EQ(acc.upper, 0);
+ EXPECT_EQ(acc.lower, 13 * 0x100000000);
+}
+
+TEST(BigIntTest, Square) {
+ bigint n0(0);
+ n0.square();
+ EXPECT_EQ("0", fmt::format("{}", n0));
+ bigint n1(0x100);
+ n1.square();
+ EXPECT_EQ("10000", fmt::format("{}", n1));
+ bigint n2(0xfffffffff);
+ n2.square();
+ EXPECT_EQ("ffffffffe000000001", fmt::format("{}", n2));
+ bigint n3(max_value<uint64_t>());
+ n3.square();
+ EXPECT_EQ("fffffffffffffffe0000000000000001", fmt::format("{}", n3));
+ bigint n4;
+ n4.assign_pow10(10);
+ EXPECT_EQ("2540be400", fmt::format("{}", n4));
+}
+
+TEST(BigIntTest, DivModAssignZeroDivisor) {
+ bigint zero(0);
+ EXPECT_THROW(bigint(0).divmod_assign(zero), assertion_failure);
+ EXPECT_THROW(bigint(42).divmod_assign(zero), assertion_failure);
+}
+
+TEST(BigIntTest, DivModAssignSelf) {
+ bigint n(100);
+ EXPECT_THROW(n.divmod_assign(n), assertion_failure);
+}
+
+TEST(BigIntTest, DivModAssignUnaligned) {
+ // (42 << 340) / pow(10, 100):
+ bigint n1(42);
+ n1 <<= 340;
+ bigint n2;
+ n2.assign_pow10(100);
+ int result = n1.divmod_assign(n2);
+ EXPECT_EQ(result, 9406);
+ EXPECT_EQ("10f8353019583bfc29ffc8f564e1b9f9d819dbb4cf783e4507eca1539220p96",
+ fmt::format("{}", n1));
+}
+
+TEST(BigIntTest, DivModAssign) {
+ // 100 / 10:
+ bigint n1(100);
+ int result = n1.divmod_assign(bigint(10));
+ EXPECT_EQ(result, 10);
+ EXPECT_EQ("0", fmt::format("{}", n1));
+ // pow(10, 100) / (42 << 320):
+ n1.assign_pow10(100);
+ result = n1.divmod_assign(bigint(42) <<= 320);
+ EXPECT_EQ(result, 111);
+ EXPECT_EQ("13ad2594c37ceb0b2784c4ce0bf38ace408e211a7caab24308a82e8f10p96",
+ fmt::format("{}", n1));
+ // 42 / 100:
+ bigint n2(42);
+ n1.assign_pow10(2);
+ result = n2.divmod_assign(n1);
+ EXPECT_EQ(result, 0);
+ EXPECT_EQ("2a", fmt::format("{}", n2));
+}
+
+template <bool is_iec559> void run_double_tests() {
+ fmt::print("warning: double is not IEC559, skipping FP tests\n");
+}
+
+template <> void run_double_tests<true>() {
+ // Construct from double.
+ EXPECT_EQ(fp(1.23), fp(0x13ae147ae147aeu, -52));
+}
+
+TEST(FPTest, DoubleTests) {
+ run_double_tests<std::numeric_limits<double>::is_iec559>();
+}
+
+TEST(FPTest, Normalize) {
+ const auto v = fp(0xbeef, 42);
+ auto normalized = normalize(v);
+ EXPECT_EQ(0xbeef000000000000, normalized.f);
+ EXPECT_EQ(-6, normalized.e);
+}
+
+TEST(FPTest, Multiply) {
+ auto v = fp(123ULL << 32, 4) * fp(56ULL << 32, 7);
+ EXPECT_EQ(v.f, 123u * 56u);
+ EXPECT_EQ(v.e, 4 + 7 + 64);
+ v = fp(123ULL << 32, 4) * fp(567ULL << 31, 8);
+ EXPECT_EQ(v.f, (123 * 567 + 1u) / 2);
+ EXPECT_EQ(v.e, 4 + 8 + 64);
+}
+
+TEST(FPTest, GetCachedPower) {
+ using limits = std::numeric_limits<double>;
+ for (auto exp = limits::min_exponent; exp <= limits::max_exponent; ++exp) {
+ int dec_exp = 0;
+ auto fp = fmt::detail::get_cached_power(exp, dec_exp);
+ bigint exact, cache(fp.f);
+ if (dec_exp >= 0) {
+ exact.assign_pow10(dec_exp);
+ if (fp.e <= 0)
+ exact <<= -fp.e;
+ else
+ cache <<= fp.e;
+ exact.align(cache);
+ cache.align(exact);
+ auto exact_str = fmt::format("{}", exact);
+ auto cache_str = fmt::format("{}", cache);
+ EXPECT_EQ(exact_str.size(), cache_str.size());
+ EXPECT_EQ(exact_str.substr(0, 15), cache_str.substr(0, 15));
+ int diff = cache_str[15] - exact_str[15];
+ if (diff == 1)
+ EXPECT_GT(exact_str[16], '8');
+ else
+ EXPECT_EQ(diff, 0);
+ } else {
+ cache.assign_pow10(-dec_exp);
+ cache *= fp.f + 1; // Inexact check.
+ exact.assign(1);
+ exact <<= -fp.e;
+ exact.align(cache);
+ auto exact_str = fmt::format("{}", exact);
+ auto cache_str = fmt::format("{}", cache);
+ EXPECT_EQ(exact_str.size(), cache_str.size());
+ EXPECT_EQ(exact_str.substr(0, 16), cache_str.substr(0, 16));
+ }
+ }
+}
+
+TEST(FPTest, DragonboxMaxK) {
+ 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),
+ float_info::kappa - floor_log10_pow2(float_info::min_exponent -
+ float_info::significand_bits));
+ using double_info = fmt::detail::dragonbox::float_info<double>;
+ EXPECT_EQ(
+ fmt::detail::const_check(double_info::max_k),
+ double_info::kappa - floor_log10_pow2(double_info::min_exponent -
+ double_info::significand_bits));
+}
+
+TEST(FPTest, GetRoundDirection) {
+ using fmt::detail::get_round_direction;
+ using fmt::detail::round_direction;
+ EXPECT_EQ(round_direction::down, get_round_direction(100, 50, 0));
+ EXPECT_EQ(round_direction::up, get_round_direction(100, 51, 0));
+ EXPECT_EQ(round_direction::down, get_round_direction(100, 40, 10));
+ EXPECT_EQ(round_direction::up, get_round_direction(100, 60, 10));
+ for (size_t i = 41; i < 60; ++i)
+ EXPECT_EQ(round_direction::unknown, get_round_direction(100, i, 10));
+ uint64_t max = max_value<uint64_t>();
+ EXPECT_THROW(get_round_direction(100, 100, 0), assertion_failure);
+ EXPECT_THROW(get_round_direction(100, 0, 100), assertion_failure);
+ EXPECT_THROW(get_round_direction(100, 0, 50), assertion_failure);
+ // Check that remainder + error doesn't overflow.
+ EXPECT_EQ(round_direction::up, get_round_direction(max, max - 1, 2));
+ // Check that 2 * (remainder + error) doesn't overflow.
+ EXPECT_EQ(round_direction::unknown,
+ get_round_direction(max, max / 2 + 1, max / 2));
+ // Check that remainder - error doesn't overflow.
+ EXPECT_EQ(round_direction::unknown, get_round_direction(100, 40, 41));
+ // Check that 2 * (remainder - error) doesn't overflow.
+ EXPECT_EQ(round_direction::up, get_round_direction(max, max - 1, 1));
+}
+
+TEST(FPTest, FixedHandler) {
+ struct handler : fmt::detail::fixed_handler {
+ char buffer[10];
+ handler(int prec = 0) : fmt::detail::fixed_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);
+ namespace digits = fmt::detail::digits;
+ EXPECT_EQ(handler(1).on_digit('0', 100, 10, 10, exp, false), digits::error);
+ // Check that divisor - error doesn't overflow.
+ EXPECT_EQ(handler(1).on_digit('0', 100, 10, 101, exp, 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);
+}
+
+TEST(FPTest, GrisuFormatCompilesWithNonIEEEDouble) {
+ 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) {
+ std::string msg = "error 42", sep = ": ";
+ {
+ fmt::memory_buffer buffer;
+ format_to(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');
+ fmt::detail::format_error_code(buffer, 42, prefix);
+ EXPECT_EQ(msg, to_string(buffer));
+ }
+ int codes[] = {42, -1};
+ for (size_t i = 0, n = sizeof(codes) / sizeof(*codes); i < n; ++i) {
+ // 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');
+ fmt::detail::format_error_code(buffer, codes[i], prefix);
+ EXPECT_EQ(prefix + sep + msg, to_string(buffer));
+ size_t size = fmt::inline_buffer_size;
+ EXPECT_EQ(size, buffer.size());
+ buffer.resize(0);
+ // Test with a message that doesn't fit into the buffer.
+ prefix += 'x';
+ fmt::detail::format_error_code(buffer, codes[i], prefix);
+ EXPECT_EQ(msg, to_string(buffer));
+ }
+}
+
+TEST(FormatTest, CountCodePoints) {
+ EXPECT_EQ(4,
+ fmt::detail::count_code_points(
+ fmt::basic_string_view<fmt::detail::char8_type>(
+ reinterpret_cast<const fmt::detail::char8_type*>("ёжик"))));
+}
+
+// Tests fmt::detail::count_digits for integer type Int.
+template <typename Int> void test_count_digits() {
+ for (Int i = 0; i < 10; ++i) EXPECT_EQ(1u, fmt::detail::count_digits(i));
+ for (Int i = 1, n = 1, end = max_value<Int>() / 10; n <= end; ++i) {
+ n *= 10;
+ EXPECT_EQ(i, fmt::detail::count_digits(n - 1));
+ EXPECT_EQ(i + 1, fmt::detail::count_digits(n));
+ }
+}
+
+TEST(UtilTest, CountDigits) {
+ test_count_digits<uint32_t>();
+ test_count_digits<uint64_t>();
+}
+
+TEST(UtilTest, WriteFallbackUIntPtr) {
+ std::string s;
+ fmt::detail::write_ptr<char>(
+ std::back_inserter(s),
+ fmt::detail::fallback_uintptr(reinterpret_cast<void*>(0xface)), nullptr);
+ EXPECT_EQ(s, "0xface");
+}
+
+#ifdef _WIN32
+TEST(UtilTest, WriteConsoleSignature) {
+ decltype(WriteConsoleW)* p = fmt::detail::WriteConsoleW;
+ (void)p;
+}
+#endif
diff --git a/contrib/libs/fmt/test/format-impl-test/ya.make b/contrib/libs/fmt/test/format-impl-test/ya.make
new file mode 100644
index 0000000000..f8612f4120
--- /dev/null
+++ b/contrib/libs/fmt/test/format-impl-test/ya.make
@@ -0,0 +1,37 @@
+# Generated by devtools/yamaker.
+
+GTEST()
+
+WITHOUT_LICENSE_TEXTS()
+
+OWNER(
+ orivej
+ g:cpp-contrib
+)
+
+LICENSE(MIT)
+
+PEERDIR(
+ contrib/libs/fmt
+ contrib/libs/fmt/test
+)
+
+NO_COMPILER_WARNINGS()
+
+NO_UTIL()
+
+CFLAGS(
+ -DFMT_LOCALE
+ -DFMT_SHARED
+ -DGTEST_HAS_STD_WSTRING=1
+ -DGTEST_LANG_CXX11=0
+ -D_SILENCE_TR1_NAMESPACE_DEPRECATION_WARNING=1
+)
+
+SRCDIR(contrib/libs/fmt/test)
+
+SRCS(
+ format-impl-test.cc
+)
+
+END()
diff --git a/contrib/libs/fmt/test/format-test.cc b/contrib/libs/fmt/test/format-test.cc
new file mode 100644
index 0000000000..6164ad60d6
--- /dev/null
+++ b/contrib/libs/fmt/test/format-test.cc
@@ -0,0 +1,2495 @@
+// 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 <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
+
+#include "fmt/format.h"
+
+#undef index
+
+#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::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
+
+struct uint32_pair {
+ uint32_t u[2];
+};
+
+TEST(UtilTest, BitCast) {
+ 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));
+ EXPECT_EQ(fmt::detail::bit_cast<uint64_t>(s), ~0ull);
+}
+
+TEST(UtilTest, Increment) {
+ char s[10] = "123";
+ increment(s);
+ EXPECT_STREQ("124", s);
+ s[2] = '8';
+ increment(s);
+ EXPECT_STREQ("129", s);
+ increment(s);
+ EXPECT_STREQ("130", s);
+ s[1] = s[2] = '9';
+ increment(s);
+ 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";
+ 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");
+ 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());
+}
+
+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(AllocatorTest, allocator_ref) {
+ StrictMock<mock_allocator<int>> alloc;
+ typedef allocator_ref<mock_allocator<int>> test_allocator_ref;
+ test_allocator_ref ref(&alloc);
+ // Check if allocator_ref forwards to the underlying allocator.
+ check_forwarding(alloc, ref);
+ test_allocator_ref ref2(ref);
+ check_forwarding(alloc, ref2);
+ test_allocator_ref ref3;
+ EXPECT_EQ(nullptr, ref3.get());
+ ref3 = ref;
+ check_forwarding(alloc, ref3);
+}
+
+typedef allocator_ref<std::allocator<char>> TestAllocator;
+
+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());
+}
+
+TEST(MemoryBufferTest, MoveCtorInlineBuffer) {
+ std::allocator<char> alloc;
+ basic_memory_buffer<char, 5, TestAllocator> buffer((TestAllocator(&alloc)));
+ const char test[] = "test";
+ buffer.append(string_view(test, 4));
+ check_move_buffer("test", buffer);
+ // Adding one more character fills the inline buffer, but doesn't cause
+ // dynamic allocation.
+ buffer.push_back('a');
+ check_move_buffer("testa", buffer);
+}
+
+TEST(MemoryBufferTest, MoveCtorDynamicBuffer) {
+ std::allocator<char> alloc;
+ basic_memory_buffer<char, 4, TestAllocator> buffer((TestAllocator(&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));
+ // 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) {
+ basic_memory_buffer<char, 5> buffer2;
+ 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());
+}
+
+TEST(MemoryBufferTest, MoveAssignment) {
+ basic_memory_buffer<char, 5> buffer;
+ const char test[] = "test";
+ buffer.append(test, test + 4);
+ check_move_assign_buffer("test", buffer);
+ // Adding one more character fills the inline buffer, but doesn't cause
+ // dynamic allocation.
+ buffer.push_back('a');
+ check_move_assign_buffer("testa", buffer);
+ 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('b');
+ basic_memory_buffer<char, 5> buffer2;
+ buffer2 = std::move(buffer);
+ // Move should rip the guts of the first buffer.
+ EXPECT_EQ(inline_buffer_ptr, &buffer[0]);
+ EXPECT_EQ("testab", std::string(&buffer2[0], buffer2.size()));
+ EXPECT_GT(buffer2.capacity(), 5u);
+}
+
+TEST(MemoryBufferTest, Grow) {
+ typedef allocator_ref<mock_allocator<int>> Allocator;
+ mock_allocator<int> alloc;
+ basic_memory_buffer<int, 10, Allocator> buffer((Allocator(&alloc)));
+ buffer.resize(7);
+ using fmt::detail::to_unsigned;
+ for (int i = 0; i < 7; ++i) buffer[to_unsigned(i)] = i * i;
+ EXPECT_EQ(10u, buffer.capacity());
+ int mem[20];
+ mem[7] = 0xdead;
+ EXPECT_CALL(alloc, allocate(20)).WillOnce(Return(mem));
+ buffer.try_reserve(20);
+ EXPECT_EQ(20u, buffer.capacity());
+ // Check if size elements have been copied
+ for (int i = 0; i < 7; ++i) EXPECT_EQ(i * i, buffer[to_unsigned(i)]);
+ // and no more than that.
+ EXPECT_EQ(0xdead, buffer[7]);
+ EXPECT_CALL(alloc, deallocate(mem, 20));
+}
+
+TEST(MemoryBufferTest, Allocator) {
+ typedef allocator_ref<mock_allocator<char>> TestAllocator;
+ basic_memory_buffer<char, 10, TestAllocator> buffer;
+ EXPECT_EQ(nullptr, buffer.get_allocator().get());
+ StrictMock<mock_allocator<char>> alloc;
+ char mem;
+ {
+ basic_memory_buffer<char, 10, TestAllocator> buffer2(
+ (TestAllocator(&alloc)));
+ EXPECT_EQ(&alloc, buffer2.get_allocator().get());
+ size_t size = 2 * fmt::inline_buffer_size;
+ EXPECT_CALL(alloc, allocate(size)).WillOnce(Return(&mem));
+ buffer2.reserve(size);
+ EXPECT_CALL(alloc, deallocate(&mem, size));
+ }
+}
+
+TEST(MemoryBufferTest, ExceptionInDeallocate) {
+ typedef allocator_ref<mock_allocator<char>> TestAllocator;
+ StrictMock<mock_allocator<char>> alloc;
+ basic_memory_buffer<char, 10, TestAllocator> buffer((TestAllocator(&alloc)));
+ size_t size = 2 * fmt::inline_buffer_size;
+ std::vector<char> mem(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);
+ {
+ EXPECT_CALL(alloc, allocate(2 * size)).WillOnce(Return(&mem2[0]));
+ std::exception e;
+ 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]);
+ // Check that the data has been copied.
+ for (size_t i = 0; i < size; ++i) EXPECT_EQ('x', buffer[i]);
+ }
+ 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;
+ }
+ 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;
+ }
+ 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(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(FormatterTest, Escape) {
+ EXPECT_EQ("{", format("{{"));
+ EXPECT_EQ("before {", format("before {{"));
+ EXPECT_EQ("{ after", format("{{ after"));
+ EXPECT_EQ("before { after", 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("{}", format("{{}}"));
+ EXPECT_EQ("{42}", 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(FormatterTest, NoArgs) { EXPECT_EQ("test", 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(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");
+
+ char format_str[BUFFER_SIZE];
+ safe_sprintf(format_str, "{%u", INT_MAX);
+ EXPECT_THROW_MSG(format(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");
+
+ safe_sprintf(format_str, "{%u", INT_MAX + 1u);
+ EXPECT_THROW_MSG(format(format_str), format_error, "number is too big");
+ safe_sprintf(format_str, "{%u}", INT_MAX + 1u);
+ EXPECT_THROW_MSG(format(format_str), format_error, "number is too big");
+}
+
+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 <> struct TestFormat<0> {
+ template <typename... Args>
+ static std::string format(fmt::string_view format_str, const Args&... args) {
+ return fmt::format(format_str, args...);
+ }
+};
+
+TEST(FormatterTest, ManyArgs) {
+ EXPECT_EQ("19", TestFormat<20>::format("{19}"));
+ EXPECT_THROW_MSG(TestFormat<20>::format("{20}"), format_error,
+ "argument not found");
+ EXPECT_THROW_MSG(TestFormat<21>::format("{21}"), format_error,
+ "argument not found");
+ enum { max_packed_args = 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),
+ 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,
+ "cannot switch from manual to automatic argument indexing");
+ EXPECT_THROW_MSG(format("{}{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,
+ "cannot switch from manual to automatic argument indexing");
+ EXPECT_THROW_MSG(format("{:.{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
+
+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,
+ "invalid fill character '{'");
+ EXPECT_THROW_MSG(format("{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,
+ "format specifier requires signed argument");
+ EXPECT_EQ("+42", format("{0:+}", 42l));
+ EXPECT_THROW_MSG(format("{0:+}", 42ul), format_error,
+ "format specifier requires signed argument");
+ EXPECT_EQ("+42", format("{0:+}", 42ll));
+ EXPECT_THROW_MSG(format("{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,
+ "missing '}' in format string");
+ EXPECT_THROW_MSG(format("{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,
+ "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,
+ "format specifier requires signed argument");
+ EXPECT_EQ("42", format("{0:-}", 42l));
+ EXPECT_THROW_MSG(format("{0:-}", 42ul), format_error,
+ "format specifier requires signed argument");
+ EXPECT_EQ("42", format("{0:-}", 42ll));
+ EXPECT_THROW_MSG(format("{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,
+ "missing '}' in format string");
+ EXPECT_THROW_MSG(format("{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,
+ "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,
+ "format specifier requires signed argument");
+ EXPECT_EQ(" 42", format("{0: }", 42l));
+ EXPECT_THROW_MSG(format("{0: }", 42ul), format_error,
+ "format specifier requires signed argument");
+ EXPECT_EQ(" 42", format("{0: }", 42ll));
+ EXPECT_THROW_MSG(format("{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,
+ "missing '}' in format string");
+ EXPECT_THROW_MSG(format("{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,
+ "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,
+ "missing '}' in format string");
+ EXPECT_THROW_MSG(format("{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,
+ "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,
+ "missing '}' in format string");
+ EXPECT_THROW_MSG(format("{0:05}", 'c'), format_error,
+ "invalid format specifier for char");
+ EXPECT_THROW_MSG(format("{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");
+}
+
+TEST(FormatterTest, 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");
+ 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");
+
+ safe_sprintf(format_str, "{0:%u", INT_MAX + 1u);
+ EXPECT_THROW_MSG(format(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];
+ 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");
+ 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");
+ 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(format("{0:{", 0), format_error, "invalid format string");
+ EXPECT_THROW_MSG(format("{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(format("{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))) {
+ long value = INT_MAX;
+ EXPECT_THROW_MSG(format("{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(format("{0:{1}}", 0, '0'), format_error,
+ "width is not integer");
+ EXPECT_THROW_MSG(format("{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(" 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));
+}
+
+TEST(FormatterTest, 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");
+ 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");
+
+ safe_sprintf(format_str, "{0:.%u", INT_MAX + 1u);
+ EXPECT_THROW_MSG(format(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(format("{0:.", 0), format_error,
+ "missing precision specifier");
+ EXPECT_THROW_MSG(format("{0:.}", 0), format_error,
+ "missing precision specifier");
+
+ EXPECT_THROW_MSG(format("{0:.2", 0), format_error,
+ "precision not allowed for this argument type");
+ EXPECT_THROW_MSG(format("{0:.2}", 42), format_error,
+ "precision not allowed for this argument type");
+ EXPECT_THROW_MSG(format("{0:.2f}", 42), format_error,
+ "precision not allowed for this argument type");
+ EXPECT_THROW_MSG(format("{0:.2}", 42u), format_error,
+ "precision not allowed for this argument type");
+ EXPECT_THROW_MSG(format("{0:.2f}", 42u), format_error,
+ "precision not allowed for this argument type");
+ EXPECT_THROW_MSG(format("{0:.2}", 42l), format_error,
+ "precision not allowed for this argument type");
+ EXPECT_THROW_MSG(format("{0:.2f}", 42l), format_error,
+ "precision not allowed for this argument type");
+ EXPECT_THROW_MSG(format("{0:.2}", 42ul), format_error,
+ "precision not allowed for this argument type");
+ EXPECT_THROW_MSG(format("{0:.2f}", 42ul), format_error,
+ "precision not allowed for this argument type");
+ EXPECT_THROW_MSG(format("{0:.2}", 42ll), format_error,
+ "precision not allowed for this argument type");
+ EXPECT_THROW_MSG(format("{0:.2f}", 42ll), format_error,
+ "precision not allowed for this argument type");
+ EXPECT_THROW_MSG(format("{0:.2}", 42ull), format_error,
+ "precision not allowed for this argument type");
+ EXPECT_THROW_MSG(format("{0:.2f}", 42ull), format_error,
+ "precision not allowed for this argument type");
+ EXPECT_THROW_MSG(format("{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(
+ "4.9406564584124654417656879286822137236505980261432476442558568250067550"
+ "727020875186529983636163599237979656469544571773092665671035593979639877"
+ "479601078187812630071319031140452784581716784898210368871863605699873072"
+ "305000638740915356498438731247339727316961514003171538539807412623856559"
+ "117102665855668676818703956031062493194527159149245532930545654440112748"
+ "012970999954193198940908041656332452475714786901472678015935523861155013"
+ "480352649347201937902681071074917033322268447533357208324319361e-324",
+ format("{:.494}", 4.9406564584124654E-324));
+ EXPECT_EQ(
+ "-0X1.41FE3FFE71C9E000000000000000000000000000000000000000000000000000000"
+ "000000000000000000000000000000000000000000000000000000000000000000000000"
+ "000000000000000000000000000000000000000000000000000000000000000000000000"
+ "000000000000000000000000000000000000000000000000000000000000000000000000"
+ "000000000000000000000000000000000000000000000000000000000000000000000000"
+ "000000000000000000000000000000000000000000000000000000000000000000000000"
+ "000000000000000000000000000000000000000000000000000000000000000000000000"
+ "000000000000000000000000000000000000000000000000000000000000000000000000"
+ "000000000000000000000000000000000000000000000000000000000000000000000000"
+ "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));
+ 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>()),
+ format_error, "number is too big");
+
+ EXPECT_EQ("st", format("{0:.2}", "str"));
+}
+
+TEST(FormatterTest, RuntimePrecision) {
+ 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");
+ 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");
+ 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(format("{0:.{", 0), format_error, "invalid format string");
+ EXPECT_THROW_MSG(format("{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, 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(format("{0:.{0:}}", 0), format_error,
+ "invalid format string");
+
+ EXPECT_THROW_MSG(format("{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,
+ "negative precision");
+ if (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(format("{0:.{1}}", 0, (INT_MAX + 1ul)), format_error,
+ "number is too big");
+
+ EXPECT_THROW_MSG(format("{0:.{1}}", 0, '0'), format_error,
+ "precision is not integer");
+ EXPECT_THROW_MSG(format("{0:.{1}}", 0, 0.0), format_error,
+ "precision is not integer");
+
+ EXPECT_THROW_MSG(format("{0:.{1}}", 42, 2), format_error,
+ "precision not allowed for this argument type");
+ EXPECT_THROW_MSG(format("{0:.{1}f}", 42, 2), format_error,
+ "precision not allowed for this argument type");
+ EXPECT_THROW_MSG(format("{0:.{1}}", 42u, 2), format_error,
+ "precision not allowed for this argument type");
+ EXPECT_THROW_MSG(format("{0:.{1}f}", 42u, 2), format_error,
+ "precision not allowed for this argument type");
+ EXPECT_THROW_MSG(format("{0:.{1}}", 42l, 2), format_error,
+ "precision not allowed for this argument type");
+ EXPECT_THROW_MSG(format("{0:.{1}f}", 42l, 2), format_error,
+ "precision not allowed for this argument type");
+ EXPECT_THROW_MSG(format("{0:.{1}}", 42ul, 2), format_error,
+ "precision not allowed for this argument type");
+ EXPECT_THROW_MSG(format("{0:.{1}f}", 42ul, 2), format_error,
+ "precision not allowed for this argument type");
+ EXPECT_THROW_MSG(format("{0:.{1}}", 42ll, 2), format_error,
+ "precision not allowed for this argument type");
+ EXPECT_THROW_MSG(format("{0:.{1}f}", 42ll, 2), format_error,
+ "precision not allowed for this argument type");
+ EXPECT_THROW_MSG(format("{0:.{1}}", 42ull, 2), format_error,
+ "precision not allowed for this argument type");
+ EXPECT_THROW_MSG(format("{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,
+ "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_THROW_MSG(format("{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),
+ format_error,
+ "precision not allowed for this argument type");
+
+ EXPECT_EQ("st", format("{0:.{1}}", "str", 2));
+}
+
+template <typename T>
+void check_unknown_types(const T& value, const char* types, const char*) {
+ char format_str[BUFFER_SIZE];
+ const char* special = ".0123456789}";
+ 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)
+ << 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");
+ 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("11111111111111111111111111111111",
+ format("{0:b}", max_value<uint32_t>()));
+}
+
+#if FMT_USE_INT128
+constexpr auto int128_max = static_cast<__int128_t>(
+ (static_cast<__uint128_t>(1) << ((__SIZEOF_INT128__ * CHAR_BIT) - 1)) - 1);
+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));
+#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("9223372036854775808",
+ format("{0}", static_cast<__int128_t>(INT64_MAX) + 1));
+ EXPECT_EQ("-9223372036854775809",
+ format("{0}", static_cast<__int128_t>(INT64_MIN) - 1));
+ EXPECT_EQ("18446744073709551616",
+ format("{0}", static_cast<__int128_t>(UINT64_MAX) + 1));
+ EXPECT_EQ("170141183460469231731687303715884105727",
+ format("{0}", int128_max));
+ EXPECT_EQ("-170141183460469231731687303715884105728",
+ format("{0}", int128_min));
+ EXPECT_EQ("340282366920938463463374607431768211455",
+ format("{0}", uint128_max));
+#endif
+
+ char buffer[BUFFER_SIZE];
+ safe_sprintf(buffer, "%d", INT_MIN);
+ EXPECT_EQ(buffer, format("{0}", INT_MIN));
+ safe_sprintf(buffer, "%d", INT_MAX);
+ EXPECT_EQ(buffer, format("{0}", INT_MAX));
+ safe_sprintf(buffer, "%u", UINT_MAX);
+ EXPECT_EQ(buffer, format("{0}", UINT_MAX));
+ safe_sprintf(buffer, "%ld", 0 - static_cast<unsigned long>(LONG_MIN));
+ EXPECT_EQ(buffer, format("{0}", LONG_MIN));
+ safe_sprintf(buffer, "%ld", LONG_MAX);
+ EXPECT_EQ(buffer, 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));
+#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("8000000000000000",
+ format("{0:x}", static_cast<__int128_t>(INT64_MAX) + 1));
+ EXPECT_EQ("-8000000000000001",
+ 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));
+#endif
+
+ char buffer[BUFFER_SIZE];
+ safe_sprintf(buffer, "-%x", 0 - static_cast<unsigned>(INT_MIN));
+ EXPECT_EQ(buffer, format("{0:x}", INT_MIN));
+ safe_sprintf(buffer, "%x", INT_MAX);
+ EXPECT_EQ(buffer, format("{0:x}", INT_MAX));
+ safe_sprintf(buffer, "%x", UINT_MAX);
+ EXPECT_EQ(buffer, format("{0:x}", UINT_MAX));
+ safe_sprintf(buffer, "-%lx", 0 - static_cast<unsigned long>(LONG_MIN));
+ EXPECT_EQ(buffer, format("{0:x}", LONG_MIN));
+ safe_sprintf(buffer, "%lx", LONG_MAX);
+ EXPECT_EQ(buffer, format("{0:x}", LONG_MAX));
+ safe_sprintf(buffer, "%lx", ULONG_MAX);
+ EXPECT_EQ(buffer, 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));
+#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("1000000000000000000000",
+ format("{0:o}", static_cast<__int128_t>(INT64_MAX) + 1));
+ EXPECT_EQ("-1000000000000000000001",
+ format("{0:o}", static_cast<__int128_t>(INT64_MIN) - 1));
+ EXPECT_EQ("2000000000000000000000",
+ format("{0:o}", static_cast<__int128_t>(UINT64_MAX) + 1));
+ EXPECT_EQ("1777777777777777777777777777777777777777777",
+ format("{0:o}", int128_max));
+ EXPECT_EQ("-2000000000000000000000000000000000000000000",
+ format("{0:o}", int128_min));
+ EXPECT_EQ("3777777777777777777777777777777777777777777",
+ format("{0:o}", uint128_max));
+#endif
+
+ char buffer[BUFFER_SIZE];
+ safe_sprintf(buffer, "-%o", 0 - static_cast<unsigned>(INT_MIN));
+ EXPECT_EQ(buffer, format("{0:o}", INT_MIN));
+ safe_sprintf(buffer, "%o", INT_MAX);
+ EXPECT_EQ(buffer, format("{0:o}", INT_MAX));
+ safe_sprintf(buffer, "%o", UINT_MAX);
+ EXPECT_EQ(buffer, format("{0:o}", UINT_MAX));
+ safe_sprintf(buffer, "-%lo", 0 - static_cast<unsigned long>(LONG_MIN));
+ EXPECT_EQ(buffer, format("{0:o}", LONG_MIN));
+ safe_sprintf(buffer, "%lo", LONG_MAX);
+ EXPECT_EQ(buffer, 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));
+}
+
+struct ConvertibleToLongLong {
+ operator long long() const { return 1LL << 32; }
+};
+
+TEST(FormatterTest, FormatConvertibleToLongLong) {
+ EXPECT_EQ("100000000", format("{:x}", ConvertibleToLongLong()));
+}
+
+TEST(FormatterTest, FormatFloat) {
+ EXPECT_EQ("0", format("{}", 0.0f));
+ EXPECT_EQ("392.500000", format("{0:f}", 392.5f));
+}
+
+TEST(FormatterTest, FormatDouble) {
+ EXPECT_EQ("0", 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];
+ safe_sprintf(buffer, "%e", 392.65);
+ EXPECT_EQ(buffer, 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));
+ safe_sprintf(buffer, "%a", -42.0);
+ EXPECT_EQ(buffer, format("{:a}", -42.0));
+ safe_sprintf(buffer, "%A", -42.0);
+ EXPECT_EQ(buffer, 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));
+ EXPECT_EQ("1", fmt::format("{:.0}", 1.0));
+ EXPECT_EQ("225.51575035152063720",
+ fmt::format("{:.17f}", 225.51575035152064));
+ EXPECT_EQ("-761519619559038.2", fmt::format("{:.1f}", -761519619559038.2));
+ EXPECT_EQ("1.9156918820264798e-56",
+ fmt::format("{}", 1.9156918820264798e-56));
+ 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));
+}
+
+TEST(FormatterTest, PrettifyFloat) {
+ EXPECT_EQ("0.0001", fmt::format("{}", 1e-4));
+ EXPECT_EQ("1e-05", fmt::format("{}", 1e-5));
+ EXPECT_EQ("1000000000000000", fmt::format("{}", 1e15));
+ EXPECT_EQ("1e+16", fmt::format("{}", 1e16));
+ EXPECT_EQ("9.999e-05", fmt::format("{}", 9.999e-5));
+ EXPECT_EQ("10000000000", fmt::format("{}", 1e10));
+ EXPECT_EQ("100000000000", fmt::format("{}", 1e11));
+ EXPECT_EQ("12340000000", fmt::format("{}", 1234e7));
+ EXPECT_EQ("12.34", fmt::format("{}", 1234e-2));
+ EXPECT_EQ("0.001234", fmt::format("{}", 1234e-6));
+ EXPECT_EQ("0.1", fmt::format("{}", 0.1f));
+ EXPECT_EQ("0.10000000149011612", fmt::format("{}", double(0.1f)));
+ EXPECT_EQ("1.3563156e-19", fmt::format("{}", 1.35631564e-19f));
+}
+
+TEST(FormatterTest, FormatNaN) {
+ 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
+ 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));
+}
+
+TEST(FormatterTest, FormatInfinity) {
+ 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];
+ safe_sprintf(buffer, "%Le", 392.65l);
+ EXPECT_EQ(buffer, format("{0:e}", 392.65l));
+ EXPECT_EQ("+0000392.6", format("{0:+010.4g}", 392.64l));
+ safe_sprintf(buffer, "%La", 3.31l);
+ EXPECT_EQ(buffer, format("{:a}", 3.31l));
+}
+
+TEST(FormatterTest, FormatChar) {
+ const char types[] = "cbBdoxXL";
+ 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'));
+ 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("{:02X}", n), fmt::format("{:02X}", 'x'));
+}
+
+TEST(FormatterTest, FormatVolatileChar) {
+ 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)));
+}
+
+TEST(FormatterTest, FormatWChar) {
+ EXPECT_EQ(L"a", format(L"{0}", L'a'));
+ // This shouldn't compile:
+ // format("{}", L'a');
+}
+
+TEST(FormatterTest, FormatCString) {
+ check_unknown_types("test", "sp", "string");
+ EXPECT_EQ("test", format("{0}", "test"));
+ EXPECT_EQ("test", 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));
+}
+
+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));
+}
+
+TEST(FormatterTest, FormatPointer) {
+ 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("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))));
+ std::unique_ptr<int> up(new int(1));
+ EXPECT_EQ(format("{}", fmt::ptr(up.get())), 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));
+}
+
+TEST(FormatterTest, FormatString) {
+ EXPECT_EQ("test", format("{0}", std::string("test")));
+}
+
+TEST(FormatterTest, FormatStringView) {
+ EXPECT_EQ("test", format("{}", string_view("test")));
+ EXPECT_EQ("", format("{}", string_view()));
+}
+
+#ifdef FMT_USE_STRING_VIEW
+struct string_viewable {};
+
+FMT_BEGIN_NAMESPACE
+template <> struct formatter<string_viewable> : formatter<std::string_view> {
+ auto format(string_viewable, format_context& ctx) -> decltype(ctx.out()) {
+ return formatter<std::string_view>::format("foo", ctx);
+ }
+};
+FMT_END_NAMESPACE
+
+TEST(FormatterTest, FormatStdStringView) {
+ EXPECT_EQ("test", format("{}", std::string_view("test")));
+ EXPECT_EQ("foo", 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>
+ : formatter<std::string_view> {
+ auto format(const 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) {
+ 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"; }
+};
+
+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()); }
+
+ private:
+ std::shared_ptr<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(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");
+}
+
+FMT_BEGIN_NAMESPACE
+template <> struct formatter<Date> {
+ template <typename ParseContext>
+ FMT_CONSTEXPR auto parse(ParseContext& ctx) -> decltype(ctx.begin()) {
+ auto it = ctx.begin();
+ if (it != ctx.end() && *it == 'd') ++it;
+ return it;
+ }
+
+ 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()) {
+ return formatter<int>::format(42, ctx);
+ }
+};
+FMT_END_NAMESPACE
+
+TEST(FormatterTest, CustomFormat) {
+ EXPECT_EQ("42", format("{0}", Answer()));
+ EXPECT_EQ("0042", format("{:04}", Answer()));
+}
+
+TEST(FormatterTest, CustomFormatTo) {
+ char buf[10] = {};
+ auto end =
+ &*fmt::format_to(fmt::detail::make_checked(buf, 10), "{}", Answer());
+ EXPECT_EQ(end, buf + 2);
+ 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) {
+ 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'));
+}
+
+TEST(FormatterTest, FormatExamples) {
+ std::string message = format("The answer is {}", 42);
+ EXPECT_EQ("The answer is 42", message);
+
+ EXPECT_EQ("42", format("{}", 42));
+ EXPECT_EQ("42", format(std::string("{}"), 42));
+
+ memory_buffer out;
+ format_to(out, "The answer is {}.", 42);
+ EXPECT_EQ("The answer is 42.", to_string(out));
+
+ const char* filename = "nonexistent";
+ FILE* ftest = safe_fopen(filename, "r");
+ if (ftest) fclose(ftest);
+ int error_code = errno;
+ EXPECT_TRUE(ftest == nullptr);
+ EXPECT_SYSTEM_ERROR(
+ {
+ FILE* f = safe_fopen(filename, "r");
+ if (!f)
+ throw fmt::system_error(errno, "Cannot open file '{}'", filename);
+ 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));
+
+ char buffer[BUFFER_SIZE];
+ safe_sprintf(buffer, "%03.2f", -1.2);
+ EXPECT_EQ(buffer, 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("left aligned ", format("{:<30}", "left aligned"));
+ EXPECT_EQ(" right aligned",
+ format("{:>30}", "right aligned"));
+ EXPECT_EQ(" centered ", format("{:^30}", "centered"));
+ EXPECT_EQ("***********centered***********", 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("int: 42; hex: 2a; oct: 52",
+ 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");
+
+ EXPECT_EQ(L"Cyrillic letter \x42e", format(L"Cyrillic letter {}", L'\x42e'));
+
+ 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
+ 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(FormatTest, Dynamic) {
+ typedef fmt::format_context ctx;
+ std::vector<fmt::basic_format_arg<ctx>> args;
+ 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())));
+
+ EXPECT_EQ("42 and abc1 and 1.5", result);
+}
+
+TEST(FormatTest, Bytes) {
+ auto s = fmt::format("{:10}", fmt::bytes("ёжик"));
+ EXPECT_EQ("ёжик ", s);
+ EXPECT_EQ(10, s.size());
+}
+
+TEST(FormatTest, JoinArg) {
+ using fmt::join;
+ int v1[3] = {1, 2, 3};
+ std::vector<float> v2;
+ 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("(+01.20, +03.40)",
+ 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(format("{}, {}", v3[0], v3[1]),
+ 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
+}
+
+template <typename T> std::string str(const T& value) {
+ return fmt::format("{}", value);
+}
+
+TEST(StrTest, Convert) {
+ EXPECT_EQ("42", str(42));
+ std::string s = str(Date(2012, 12, 9));
+ EXPECT_EQ("2012-12-9", s);
+}
+
+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);
+ return to_string(buffer);
+}
+
+template <typename... Args>
+std::string format_message(int id, const char* format, const Args&... args) {
+ auto va = fmt::make_format_args(args...);
+ return vformat_message(id, format, va);
+}
+
+TEST(FormatTest, FormatMessageExample) {
+ EXPECT_EQ("[42] something happened",
+ format_message(42, "{} happened", "something"));
+}
+
+template <typename... Args>
+void print_error(const char* file, int line, const char* format,
+ const Args&... args) {
+ fmt::print("{}: {}: ", file, line);
+ fmt::print(format, args...);
+}
+
+TEST(FormatTest, UnpackedArgs) {
+ EXPECT_EQ("0123456789abcdefg",
+ fmt::format("{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}", 0, 1, 2, 3, 4, 5,
+ 6, 7, 8, 9, 'a', 'b', 'c', 'd', 'e', 'f', 'g'));
+}
+
+struct string_like {};
+fmt::string_view to_string_view(string_like) { return "foo"; }
+
+constexpr char with_null[3] = {'{', '}', '\0'};
+constexpr char no_null[2] = {'{', '}'};
+
+TEST(FormatTest, CompileTimeString) {
+ 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()));
+ (void)with_null;
+ (void)no_null;
+#if __cplusplus >= 201703L
+ EXPECT_EQ("42", fmt::format(FMT_STRING(with_null), 42));
+ EXPECT_EQ("42", fmt::format(FMT_STRING(no_null), 42));
+#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) {
+ EXPECT_EQ("42", fmt::format(FMT_STRING("{}"), Answer()));
+ Answer answer;
+ EXPECT_EQ("42", fmt::format(FMT_STRING("{}"), answer));
+ char buf[10] = {};
+ fmt::format_to(buf, FMT_STRING("{}"), answer);
+ const Answer const_answer = Answer();
+ EXPECT_EQ("42", fmt::format(FMT_STRING("{}"), const_answer));
+}
+
+#if FMT_USE_USER_DEFINED_LITERALS
+// Passing user-defined literals directly to EXPECT_EQ causes problems
+// with macro argument stringification (#) on some versions of GCC.
+// Workaround: Assing the UDL result to a variable before the macro.
+
+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);
+}
+
+TEST(FormatTest, UdlTemplate) {
+ EXPECT_EQ("foo", "foo"_format());
+ EXPECT_EQ(" 42", "{0:10}"_format(42));
+}
+
+TEST(FormatTest, UdlPassUserDefinedObjectAsLvalue) {
+ Date date(2015, 10, 21);
+ EXPECT_EQ("2015-10-21", "{}"_format(date));
+}
+#endif // FMT_USE_USER_DEFINED_LITERALS
+
+enum TestEnum { A };
+
+TEST(FormatTest, Enum) { EXPECT_EQ("0", fmt::format("{}", A)); }
+
+TEST(FormatTest, FormatterNotSpecialized) {
+ static_assert(
+ !fmt::has_formatter<fmt::formatter<TestEnum>, fmt::format_context>::value,
+ "");
+}
+
+#if FMT_HAS_FEATURE(cxx_strong_enums)
+enum big_enum : unsigned long long { big_enum_value = 5000000000ULL };
+
+TEST(FormatTest, StrongEnum) {
+ EXPECT_EQ("5000000000", fmt::format("{}", big_enum_value));
+}
+#endif
+
+TEST(FormatTest, NonNullTerminatedFormatString) {
+ EXPECT_EQ("42", format(string_view("{}foo", 2), 42));
+}
+
+struct variant {
+ enum { INT, STRING } type;
+ explicit variant(int) : type(INT) {}
+ explicit variant(const char*) : type(STRING) {}
+};
+
+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);
+ return dynamic_formatter<>::format("foo", ctx);
+ }
+};
+FMT_END_NAMESPACE
+
+TEST(FormatTest, DynamicFormatter) {
+ 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,
+ "cannot switch from manual to automatic argument indexing");
+ EXPECT_THROW_MSG(format("{:{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,
+ "format specifier requires numeric argument");
+ EXPECT_THROW_MSG(format("{:-}", str), format_error,
+ "format specifier requires numeric argument");
+ EXPECT_THROW_MSG(format("{: }", str), format_error,
+ "format specifier requires numeric argument");
+ EXPECT_THROW_MSG(format("{:#}", str), format_error,
+ "format specifier requires numeric argument");
+ EXPECT_THROW_MSG(format("{:0}", str), format_error,
+ "format specifier requires numeric argument");
+ EXPECT_THROW_MSG(format("{:.2}", num), format_error,
+ "precision not allowed for this argument type");
+}
+
+namespace adl_test {
+namespace fmt {
+namespace detail {
+struct foo {};
+template <typename, typename OutputIt> void write(OutputIt, foo) = delete;
+} // namespace detail
+} // namespace fmt
+} // namespace adl_test
+
+FMT_BEGIN_NAMESPACE
+template <>
+struct formatter<adl_test::fmt::detail::foo> : formatter<std::string> {
+ template <typename FormatContext>
+ auto format(adl_test::fmt::detail::foo, FormatContext& ctx)
+ -> decltype(ctx.out()) {
+ return formatter<std::string>::format("foo", ctx);
+ }
+};
+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()));
+}
+
+TEST(FormatTest, ToWString) { EXPECT_EQ(L"42", fmt::to_wstring(42)); }
+
+TEST(FormatTest, OutputIterators) {
+ std::list<char> out;
+ fmt::format_to(std::back_inserter(out), "{}", 42);
+ EXPECT_EQ("42", std::string(out.begin(), out.end()));
+ std::stringstream s;
+ fmt::format_to(std::ostream_iterator<char>(s), "{}", 42);
+ EXPECT_EQ("42", s.str());
+}
+
+TEST(FormatTest, FormattedSize) {
+ EXPECT_EQ(2u, fmt::formatted_size("{}", 42));
+}
+
+TEST(FormatTest, FormatTo) {
+ std::vector<char> v;
+ fmt::format_to(std::back_inserter(v), "{}", "foo");
+ EXPECT_EQ(string_view(v.data(), v.size()), "foo");
+}
+
+TEST(FormatTest, FormatToN) {
+ char buffer[4];
+ buffer[3] = 'x';
+ auto result = fmt::format_to_n(buffer, 3, "{}", 12345);
+ EXPECT_EQ(5u, result.size);
+ EXPECT_EQ(buffer + 3, result.out);
+ EXPECT_EQ("123x", fmt::string_view(buffer, 4));
+
+ result = fmt::format_to_n(buffer, 3, "{:s}", "foobar");
+ EXPECT_EQ(6u, result.size);
+ EXPECT_EQ(buffer + 3, result.out);
+ EXPECT_EQ("foox", fmt::string_view(buffer, 4));
+
+ buffer[0] = 'x';
+ buffer[1] = 'x';
+ buffer[2] = 'x';
+ result = fmt::format_to_n(buffer, 3, "{}", 'A');
+ EXPECT_EQ(1u, result.size);
+ EXPECT_EQ(buffer + 1, result.out);
+ EXPECT_EQ("Axxx", fmt::string_view(buffer, 4));
+
+ result = fmt::format_to_n(buffer, 3, "{}{} ", 'B', 'C');
+ EXPECT_EQ(3u, result.size);
+ EXPECT_EQ(buffer + 3, result.out);
+ EXPECT_EQ("BC x", fmt::string_view(buffer, 4));
+
+ result = fmt::format_to_n(buffer, 4, "{}", "ABCDE");
+ EXPECT_EQ(5u, result.size);
+ EXPECT_EQ("ABCD", fmt::string_view(buffer, 4));
+
+ buffer[3] = 'x';
+ result = fmt::format_to_n(buffer, 3, "{}", std::string(1000, '*'));
+ EXPECT_EQ(1000u, result.size);
+ 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;
+
+ using iterator_category = std::output_iterator_tag;
+ using value_type = void;
+ using difference_type = void;
+ using pointer = void;
+ using reference = void;
+
+ test_output_iterator& operator++() {
+ ++data;
+ return *this;
+ }
+ test_output_iterator operator++(int) {
+ auto tmp = *this;
+ ++data;
+ return tmp;
+ }
+ char& operator*() { return *data; }
+};
+
+TEST(FormatTest, FormatToNOutputIterator) {
+ 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;
+
+ FMT_CONSTEXPR test_error_handler(const char*& err) : error(err) {}
+
+ FMT_CONSTEXPR test_error_handler(const test_error_handler& other)
+ : error(other.error) {}
+
+ FMT_CONSTEXPR void on_error(const char* message) {
+ if (!error) error = message;
+ }
+};
+
+FMT_CONSTEXPR size_t len(const char* s) {
+ size_t len = 0;
+ while (*s++) ++len;
+ return len;
+}
+
+FMT_CONSTEXPR bool equal(const char* s1, const char* s2) {
+ if (!s1 || !s2) return s1 == s2;
+ while (*s1 && *s1 == *s2) {
+ ++s1;
+ ++s2;
+ }
+ return *s1 == *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));
+ fmt::detail::parse_format_string<true>(s, checker);
+ return equal(actual_error, expected_error);
+}
+
+# define EXPECT_ERROR_NOARGS(fmt, error) \
+ static_assert(test_error(fmt, error), "")
+# define EXPECT_ERROR(fmt, error, ...) \
+ static_assert(test_error<__VA_ARGS__>(fmt, error), "")
+
+TEST(FormatTest, FormatStringErrors) {
+ EXPECT_ERROR_NOARGS("foo", nullptr);
+ EXPECT_ERROR_NOARGS("}", "unmatched '}' in format string");
+ 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",
+ const char*);
+ EXPECT_ERROR("{:#}", "format specifier requires numeric argument",
+ const char*);
+ EXPECT_ERROR("{: }", "format specifier requires numeric argument",
+ const char*);
+ EXPECT_ERROR("{:0}", "format specifier requires numeric argument",
+ const char*);
+ EXPECT_ERROR("{:+}", "format specifier requires signed argument", unsigned);
+ EXPECT_ERROR("{:-}", "format specifier requires signed argument", unsigned);
+ EXPECT_ERROR("{: }", "format specifier requires signed argument", unsigned);
+ EXPECT_ERROR("{:{}}", "argument not found", int);
+ 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);
+ EXPECT_ERROR("{:d}", "invalid type specifier", const char*);
+ EXPECT_ERROR("{:d}", "invalid type specifier", std::string);
+ EXPECT_ERROR("{:s}", "invalid type specifier", void*);
+# 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",
+ int);
+ EXPECT_ERROR_NOARGS("{10000000000}", "number is too big");
+ EXPECT_ERROR_NOARGS("{0x}", "invalid format string");
+ EXPECT_ERROR_NOARGS("{-}", "invalid format string");
+ EXPECT_ERROR("{:{0x}}", "invalid format string", int);
+ EXPECT_ERROR("{:{-}}", "invalid format string", int);
+ EXPECT_ERROR("{:.{0x}}", "invalid format string", int);
+ EXPECT_ERROR("{:.{-}}", "invalid format string", int);
+ EXPECT_ERROR("{:.x}", "missing precision specifier", int);
+ EXPECT_ERROR_NOARGS("{}", "argument not found");
+ EXPECT_ERROR("{1}", "argument not found", int);
+ EXPECT_ERROR("{1}{}",
+ "cannot switch from manual to automatic argument indexing", int,
+ int);
+ EXPECT_ERROR("{}{1}",
+ "cannot switch from automatic to manual argument indexing", int,
+ int);
+}
+
+TEST(FormatTest, VFormatTo) {
+ typedef fmt::format_context context;
+ fmt::basic_format_arg<context> arg = fmt::detail::make_arg<context>(42);
+ fmt::basic_format_args<context> args(&arg, 1);
+ std::string s;
+ 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 that we don't inject detail names into the std namespace.
+ using namespace std;
+ char_traits<char>::char_type c;
+ (void)c;
+#if __cplusplus >= 201103L
+ std::string s;
+ 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()) {
+ return ctx.begin();
+ }
+
+ template <typename Context>
+ auto format(check_back_appender, Context& ctx) -> decltype(ctx.out()) {
+ auto out = ctx.out();
+ static_assert(std::is_same<decltype(++out), decltype(out)&>::value,
+ "needs to satisfy weakly_incrementable");
+ *out = 'y';
+ return ++out;
+ }
+};
+FMT_END_NAMESPACE
+
+TEST(FormatTest, BackInsertSlicing) {
+ EXPECT_EQ(fmt::format("{}", check_back_appender{}), "y");
+}
diff --git a/contrib/libs/fmt/test/format-test/ya.make b/contrib/libs/fmt/test/format-test/ya.make
new file mode 100644
index 0000000000..bc3d7c85c8
--- /dev/null
+++ b/contrib/libs/fmt/test/format-test/ya.make
@@ -0,0 +1,39 @@
+# Generated by devtools/yamaker.
+
+GTEST()
+
+WITHOUT_LICENSE_TEXTS()
+
+OWNER(
+ orivej
+ g:cpp-contrib
+)
+
+LICENSE(MIT)
+
+ALLOCATOR(J)
+
+PEERDIR(
+ contrib/libs/fmt
+ contrib/libs/fmt/test
+)
+
+NO_COMPILER_WARNINGS()
+
+NO_UTIL()
+
+CFLAGS(
+ -DFMT_LOCALE
+ -DFMT_SHARED
+ -DGTEST_HAS_STD_WSTRING=1
+ -DGTEST_LANG_CXX11=0
+ -D_SILENCE_TR1_NAMESPACE_DEPRECATION_WARNING=1
+)
+
+SRCDIR(contrib/libs/fmt/test)
+
+SRCS(
+ format-test.cc
+)
+
+END()
diff --git a/contrib/libs/fmt/test/gtest-extra-test.cc b/contrib/libs/fmt/test/gtest-extra-test.cc
new file mode 100644
index 0000000000..ea728607e8
--- /dev/null
+++ b/contrib/libs/fmt/test/gtest-extra-test.cc
@@ -0,0 +1,439 @@
+// Formatting library for C++ - tests of custom Google Test assertions
+//
+// Copyright (c) 2012 - present, Victor Zverovich
+// All rights reserved.
+//
+// For the license information refer to format.h.
+
+#include "gtest-extra.h"
+
+#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 "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 {
+ protected:
+ SingleEvaluationTest() {
+ p_ = s_;
+ a_ = 0;
+ b_ = 0;
+ }
+
+ static const char* const s_;
+ static const char* p_;
+
+ static int a_;
+ static int b_;
+};
+
+const char* const SingleEvaluationTest::s_ = "01234";
+const char* SingleEvaluationTest::p_;
+int SingleEvaluationTest::a_;
+int SingleEvaluationTest::b_;
+
+void do_nothing() {}
+
+FMT_NORETURN void throw_exception() { throw std::runtime_error("test"); }
+
+FMT_NORETURN void throw_system_error() {
+ throw fmt::system_error(EDOM, "test");
+}
+
+// Tests that when EXPECT_THROW_MSG fails, it evaluates its message argument
+// exactly once.
+TEST_F(SingleEvaluationTest, FailedEXPECT_THROW_MSG) {
+ EXPECT_NONFATAL_FAILURE(
+ EXPECT_THROW_MSG(throw_exception(), std::exception, p_++), "01234");
+ EXPECT_EQ(s_ + 1, p_);
+}
+
+// Tests that when EXPECT_SYSTEM_ERROR fails, it evaluates its message argument
+// exactly once.
+TEST_F(SingleEvaluationTest, FailedEXPECT_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) {
+ // successful EXPECT_THROW_MSG
+ EXPECT_THROW_MSG(
+ { // NOLINT
+ a_++;
+ throw_exception();
+ },
+ std::exception, (b_++, "test"));
+ EXPECT_EQ(1, a_);
+ EXPECT_EQ(1, b_);
+
+ // failed EXPECT_THROW_MSG, throws different type
+ EXPECT_NONFATAL_FAILURE(EXPECT_THROW_MSG(
+ { // NOLINT
+ a_++;
+ throw_exception();
+ },
+ std::logic_error, (b_++, "test")),
+ "throws a different type");
+ EXPECT_EQ(2, a_);
+ EXPECT_EQ(2, b_);
+
+ // failed EXPECT_THROW_MSG, throws an exception with different message
+ EXPECT_NONFATAL_FAILURE(EXPECT_THROW_MSG(
+ { // NOLINT
+ a_++;
+ throw_exception();
+ },
+ std::exception, (b_++, "other")),
+ "throws an exception with a different message");
+ EXPECT_EQ(3, a_);
+ EXPECT_EQ(3, b_);
+
+ // failed EXPECT_THROW_MSG, throws nothing
+ EXPECT_NONFATAL_FAILURE(
+ EXPECT_THROW_MSG(a_++, std::exception, (b_++, "test")), "throws nothing");
+ EXPECT_EQ(4, a_);
+ EXPECT_EQ(4, b_);
+}
+
+TEST_F(SingleEvaluationTest, SystemErrorTests) {
+ // successful EXPECT_SYSTEM_ERROR
+ EXPECT_SYSTEM_ERROR(
+ { // NOLINT
+ a_++;
+ throw_system_error();
+ },
+ EDOM, (b_++, "test"));
+ EXPECT_EQ(1, a_);
+ EXPECT_EQ(1, b_);
+
+ // failed EXPECT_SYSTEM_ERROR, throws different type
+ EXPECT_NONFATAL_FAILURE(EXPECT_SYSTEM_ERROR(
+ { // NOLINT
+ a_++;
+ throw_exception();
+ },
+ EDOM, (b_++, "test")),
+ "throws a different type");
+ EXPECT_EQ(2, a_);
+ EXPECT_EQ(2, b_);
+
+ // failed EXPECT_SYSTEM_ERROR, throws an exception with different message
+ EXPECT_NONFATAL_FAILURE(EXPECT_SYSTEM_ERROR(
+ { // NOLINT
+ a_++;
+ throw_system_error();
+ },
+ EDOM, (b_++, "other")),
+ "throws an exception with a different message");
+ EXPECT_EQ(3, a_);
+ EXPECT_EQ(3, b_);
+
+ // failed EXPECT_SYSTEM_ERROR, throws nothing
+ EXPECT_NONFATAL_FAILURE(EXPECT_SYSTEM_ERROR(a_++, EDOM, (b_++, "test")),
+ "throws nothing");
+ EXPECT_EQ(4, a_);
+ EXPECT_EQ(4, b_);
+}
+
+#if FMT_USE_FCNTL
+// Tests that when EXPECT_WRITE fails, it evaluates its message argument
+// exactly once.
+TEST_F(SingleEvaluationTest, FailedEXPECT_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) {
+ // successful EXPECT_WRITE
+ EXPECT_WRITE(
+ stdout,
+ { // NOLINT
+ a_++;
+ std::printf("test");
+ },
+ (b_++, "test"));
+ EXPECT_EQ(1, a_);
+ EXPECT_EQ(1, b_);
+
+ // failed EXPECT_WRITE
+ EXPECT_NONFATAL_FAILURE(EXPECT_WRITE(
+ stdout,
+ { // NOLINT
+ a_++;
+ std::printf("test");
+ },
+ (b_++, "other")),
+ "Actual: test");
+ EXPECT_EQ(2, a_);
+ EXPECT_EQ(2, b_);
+}
+
+// Tests EXPECT_WRITE.
+TEST(ExpectTest, EXPECT_WRITE) {
+ EXPECT_WRITE(stdout, do_nothing(), "");
+ EXPECT_WRITE(stdout, std::printf("test"), "test");
+ EXPECT_WRITE(stderr, std::fprintf(stderr, "test"), "test");
+ EXPECT_NONFATAL_FAILURE(EXPECT_WRITE(stdout, std::printf("that"), "this"),
+ "Expected: this\n"
+ " Actual: that");
+}
+
+TEST(StreamingAssertionsTest, EXPECT_WRITE) {
+ EXPECT_WRITE(stdout, std::printf("test"), "test") << "unexpected failure";
+ EXPECT_NONFATAL_FAILURE(EXPECT_WRITE(stdout, std::printf("test"), "other")
+ << "expected failure",
+ "expected failure");
+}
+#endif // FMT_USE_FCNTL
+
+// Tests that the compiler will not complain about unreachable code in the
+// EXPECT_THROW_MSG macro.
+TEST(ExpectThrowTest, DoesNotGenerateUnreachableCodeWarning) {
+ int n = 0;
+ using std::runtime_error;
+ EXPECT_THROW_MSG(throw runtime_error(""), runtime_error, "");
+ EXPECT_NONFATAL_FAILURE(EXPECT_THROW_MSG(n++, runtime_error, ""), "");
+ EXPECT_NONFATAL_FAILURE(EXPECT_THROW_MSG(throw 1, runtime_error, ""), "");
+ EXPECT_NONFATAL_FAILURE(
+ EXPECT_THROW_MSG(throw runtime_error("a"), runtime_error, "b"), "");
+}
+
+// Tests that the compiler will not complain about unreachable code in the
+// EXPECT_SYSTEM_ERROR macro.
+TEST(ExpectSystemErrorTest, DoesNotGenerateUnreachableCodeWarning) {
+ int n = 0;
+ EXPECT_SYSTEM_ERROR(throw fmt::system_error(EDOM, "test"), EDOM, "test");
+ EXPECT_NONFATAL_FAILURE(EXPECT_SYSTEM_ERROR(n++, EDOM, ""), "");
+ EXPECT_NONFATAL_FAILURE(EXPECT_SYSTEM_ERROR(throw 1, EDOM, ""), "");
+ EXPECT_NONFATAL_FAILURE(
+ EXPECT_SYSTEM_ERROR(throw fmt::system_error(EDOM, "aaa"), EDOM, "bbb"),
+ "");
+}
+
+TEST(AssertionSyntaxTest, ExceptionAssertionBehavesLikeSingleStatement) {
+ if (::testing::internal::AlwaysFalse())
+ EXPECT_THROW_MSG(do_nothing(), std::exception, "");
+
+ if (::testing::internal::AlwaysTrue())
+ EXPECT_THROW_MSG(throw_exception(), std::exception, "test");
+ else
+ do_nothing();
+}
+
+TEST(AssertionSyntaxTest, SystemErrorAssertionBehavesLikeSingleStatement) {
+ if (::testing::internal::AlwaysFalse())
+ EXPECT_SYSTEM_ERROR(do_nothing(), EDOM, "");
+
+ if (::testing::internal::AlwaysTrue())
+ EXPECT_SYSTEM_ERROR(throw_system_error(), EDOM, "test");
+ else
+ do_nothing();
+}
+
+TEST(AssertionSyntaxTest, WriteAssertionBehavesLikeSingleStatement) {
+ if (::testing::internal::AlwaysFalse())
+ EXPECT_WRITE(stdout, std::printf("x"), "x");
+
+ if (::testing::internal::AlwaysTrue())
+ EXPECT_WRITE(stdout, std::printf("x"), "x");
+ else
+ do_nothing();
+}
+
+// Tests EXPECT_THROW_MSG.
+TEST(ExpectTest, EXPECT_THROW_MSG) {
+ EXPECT_THROW_MSG(throw_exception(), std::exception, "test");
+ EXPECT_NONFATAL_FAILURE(
+ EXPECT_THROW_MSG(throw_exception(), std::logic_error, "test"),
+ "Expected: throw_exception() throws an exception of "
+ "type std::logic_error.\n Actual: it throws a different type.");
+ EXPECT_NONFATAL_FAILURE(
+ EXPECT_THROW_MSG(do_nothing(), std::exception, "test"),
+ "Expected: do_nothing() throws an exception of type std::exception.\n"
+ " Actual: it throws nothing.");
+ EXPECT_NONFATAL_FAILURE(
+ EXPECT_THROW_MSG(throw_exception(), std::exception, "other"),
+ "throw_exception() throws an exception with a different message.\n"
+ "Expected: other\n"
+ " Actual: test");
+}
+
+// Tests EXPECT_SYSTEM_ERROR.
+TEST(ExpectTest, 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.");
+ EXPECT_NONFATAL_FAILURE(
+ EXPECT_SYSTEM_ERROR(do_nothing(), EDOM, "test"),
+ "Expected: do_nothing() throws an exception of type fmt::system_error.\n"
+ " Actual: it throws nothing.");
+ EXPECT_NONFATAL_FAILURE(
+ EXPECT_SYSTEM_ERROR(throw_system_error(), EDOM, "other"),
+ fmt::format(
+ "throw_system_error() throws an exception with a different message.\n"
+ "Expected: {}\n"
+ " Actual: {}",
+ format_system_error(EDOM, "other"),
+ format_system_error(EDOM, "test")));
+}
+
+TEST(StreamingAssertionsTest, EXPECT_THROW_MSG) {
+ EXPECT_THROW_MSG(throw_exception(), std::exception, "test")
+ << "unexpected failure";
+ EXPECT_NONFATAL_FAILURE(
+ EXPECT_THROW_MSG(throw_exception(), std::exception, "other")
+ << "expected failure",
+ "expected failure");
+}
+
+TEST(StreamingAssertionsTest, EXPECT_SYSTEM_ERROR) {
+ EXPECT_SYSTEM_ERROR(throw_system_error(), EDOM, "test")
+ << "unexpected failure";
+ EXPECT_NONFATAL_FAILURE(
+ EXPECT_SYSTEM_ERROR(throw_system_error(), EDOM, "other")
+ << "expected failure",
+ "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) {
+ 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());
+ std::fprintf(file.get(), "censored");
+ }
+ std::fprintf(file.get(), "]]]");
+ }
+ EXPECT_READ(read_end, "[[[]]]");
+}
+
+// Test that OutputRedirect handles errors in flush correctly.
+TEST(OutputRedirectTest, FlushErrorInCtor) {
+ 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");
+ // 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,
+ "cannot flush stream");
+ redir.reset(nullptr);
+ write_copy.dup2(write_fd); // "undo" close or dtor will fail
+}
+
+TEST(OutputRedirectTest, DupErrorInCtor) {
+ 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};
+ EXPECT_SYSTEM_ERROR_NOASSERT(
+ redir.reset(new OutputRedirect(f.get())), EBADF,
+ fmt::format("cannot duplicate file descriptor {}", fd));
+ copy.dup2(fd); // "undo" close or dtor will fail
+}
+
+TEST(OutputRedirectTest, RestoreAndRead) {
+ 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());
+ std::fprintf(file.get(), "censored");
+ EXPECT_EQ("censored", sanitize(redir.restore_and_read()));
+ EXPECT_EQ("", sanitize(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) {
+ 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());
+ // Put a character in a file buffer.
+ EXPECT_EQ('x', fputc('x', f.get()));
+ FMT_POSIX(close(write_fd));
+ EXPECT_SYSTEM_ERROR_NOASSERT(redir.restore_and_read(), EBADF,
+ "cannot flush stream");
+ write_copy.dup2(write_fd); // "undo" close or dtor will fail
+}
+
+TEST(OutputRedirectTest, ErrorInDtor) {
+ 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()));
+ // Put a character in a file buffer.
+ EXPECT_EQ('x', fputc('x', f.get()));
+ EXPECT_WRITE(
+ stderr,
+ {
+ // The close function must be called inside EXPECT_WRITE,
+ // otherwise the system may recycle closed file descriptor when
+ // redirecting the output in EXPECT_STDERR and the second close
+ // will break output redirection.
+ FMT_POSIX(close(write_fd));
+ SUPPRESS_ASSERT(redir.reset(nullptr));
+ },
+ format_system_error(EBADF, "cannot flush stream"));
+ write_copy.dup2(write_fd); // "undo" close or dtor of buffered_file will fail
+}
+
+#endif // FMT_USE_FILE_DESCRIPTORS
+
+} // namespace
diff --git a/contrib/libs/fmt/test/gtest-extra-test/ya.make b/contrib/libs/fmt/test/gtest-extra-test/ya.make
new file mode 100644
index 0000000000..b8d6cf8316
--- /dev/null
+++ b/contrib/libs/fmt/test/gtest-extra-test/ya.make
@@ -0,0 +1,37 @@
+# Generated by devtools/yamaker.
+
+GTEST()
+
+WITHOUT_LICENSE_TEXTS()
+
+OWNER(
+ orivej
+ g:cpp-contrib
+)
+
+LICENSE(MIT)
+
+PEERDIR(
+ contrib/libs/fmt
+ contrib/libs/fmt/test
+)
+
+NO_COMPILER_WARNINGS()
+
+NO_UTIL()
+
+CFLAGS(
+ -DFMT_LOCALE
+ -DFMT_SHARED
+ -DGTEST_HAS_STD_WSTRING=1
+ -DGTEST_LANG_CXX11=0
+ -D_SILENCE_TR1_NAMESPACE_DEPRECATION_WARNING=1
+)
+
+SRCDIR(contrib/libs/fmt/test)
+
+SRCS(
+ gtest-extra-test.cc
+)
+
+END()
diff --git a/contrib/libs/fmt/test/gtest-extra.cc b/contrib/libs/fmt/test/gtest-extra.cc
new file mode 100644
index 0000000000..58628a8a98
--- /dev/null
+++ b/contrib/libs/fmt/test/gtest-extra.cc
@@ -0,0 +1,87 @@
+// Formatting library for C++ - custom Google Test assertions
+//
+// Copyright (c) 2012 - present, Victor Zverovich
+// All rights reserved.
+//
+// For the license information refer to format.h.
+
+#include "gtest-extra.h"
+
+#if FMT_USE_FCNTL
+
+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) {
+ flush();
+ int fd = FMT_POSIX(fileno(f));
+ // Create a file object referring to the original file.
+ original_ = file::dup(fd);
+ // Create a pipe.
+ file write_end;
+ file::pipe(read_end_, write_end);
+ // Connect the passed FILE object to the write end of the pipe.
+ write_end.dup2(fd);
+}
+
+OutputRedirect::~OutputRedirect() FMT_NOEXCEPT {
+ try {
+ restore();
+ } catch (const std::exception& e) {
+ std::fputs(e.what(), stderr);
+ }
+}
+
+std::string OutputRedirect::restore_and_read() {
+ // Restore output.
+ restore();
+
+ // Read everything from the pipe.
+ std::string content;
+ if (read_end_.descriptor() == -1) return content; // Already read.
+ enum { BUFFER_SIZE = 4096 };
+ char buffer[BUFFER_SIZE];
+ size_t count = 0;
+ do {
+ count = read_end_.read(buffer, BUFFER_SIZE);
+ content.append(buffer, count);
+ } while (count != 0);
+ read_end_.close();
+ return content;
+}
+
+std::string read(file& f, size_t count) {
+ std::string buffer(count, '\0');
+ size_t n = 0, offset = 0;
+ do {
+ n = f.read(&buffer[offset], count - offset);
+ // We can't read more than size_t bytes since count has type size_t.
+ offset += n;
+ } while (offset < count && n != 0);
+ buffer.resize(offset);
+ return buffer;
+}
+
+#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
new file mode 100644
index 0000000000..36be158bbb
--- /dev/null
+++ b/contrib/libs/fmt/test/gtest-extra.h
@@ -0,0 +1,163 @@
+// Formatting library for C++ - custom Google Test assertions
+//
+// Copyright (c) 2012 - present, Victor Zverovich
+// All rights reserved.
+//
+// For the license information refer to format.h.
+
+#ifndef FMT_GTEST_EXTRA_H_
+#define FMT_GTEST_EXTRA_H_
+
+#include <string>
+
+#include "fmt/os.h"
+#include <gmock/gmock.h>
+
+#define FMT_TEST_THROW_(statement, expected_exception, expected_message, fail) \
+ GTEST_AMBIGUOUS_ELSE_BLOCKER_ \
+ if (::testing::AssertionResult gtest_ar = ::testing::AssertionSuccess()) { \
+ std::string gtest_expected_message = expected_message; \
+ bool gtest_caught_expected = false; \
+ try { \
+ GTEST_SUPPRESS_UNREACHABLE_CODE_WARNING_BELOW_(statement); \
+ } catch (expected_exception const& e) { \
+ if (gtest_expected_message != e.what()) { \
+ gtest_ar << #statement \
+ " throws an exception with a different message.\n" \
+ << "Expected: " << gtest_expected_message << "\n" \
+ << " Actual: " << e.what(); \
+ goto GTEST_CONCAT_TOKEN_(gtest_label_testthrow_, __LINE__); \
+ } \
+ gtest_caught_expected = true; \
+ } catch (...) { \
+ gtest_ar << "Expected: " #statement \
+ " throws an exception of type " #expected_exception \
+ ".\n Actual: it throws a different type."; \
+ goto GTEST_CONCAT_TOKEN_(gtest_label_testthrow_, __LINE__); \
+ } \
+ if (!gtest_caught_expected) { \
+ gtest_ar << "Expected: " #statement \
+ " throws an exception of type " #expected_exception \
+ ".\n Actual: it throws nothing."; \
+ goto GTEST_CONCAT_TOKEN_(gtest_label_testthrow_, __LINE__); \
+ } \
+ } else \
+ GTEST_CONCAT_TOKEN_(gtest_label_testthrow_, __LINE__) \
+ : fail(gtest_ar.failure_message())
+
+// Tests that the statement throws the expected exception and the exception's
+// what() method returns expected message.
+#define EXPECT_THROW_MSG(statement, expected_exception, expected_message) \
+ FMT_TEST_THROW_(statement, expected_exception, expected_message, \
+ GTEST_NONFATAL_FAILURE_)
+
+std::string format_system_error(int error_code, fmt::string_view message);
+
+#define EXPECT_SYSTEM_ERROR(statement, error_code, message) \
+ EXPECT_THROW_MSG(statement, fmt::system_error, \
+ format_system_error(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 {
+ 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.
+
+ GTEST_DISALLOW_COPY_AND_ASSIGN_(OutputRedirect);
+
+ void flush();
+ void restore();
+
+ public:
+ explicit OutputRedirect(FILE* file);
+ ~OutputRedirect() FMT_NOEXCEPT;
+
+ // Restores the original file, reads output from the pipe into a string
+ // and returns it.
+ std::string restore_and_read();
+};
+
+# define FMT_TEST_WRITE_(statement, expected_output, file, fail) \
+ GTEST_AMBIGUOUS_ELSE_BLOCKER_ \
+ if (::testing::AssertionResult gtest_ar = ::testing::AssertionSuccess()) { \
+ std::string gtest_expected_output = expected_output; \
+ OutputRedirect 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) { \
+ gtest_ar << #statement " produces different output.\n" \
+ << "Expected: " << gtest_expected_output << "\n" \
+ << " Actual: " << gtest_output; \
+ goto GTEST_CONCAT_TOKEN_(gtest_label_testthrow_, __LINE__); \
+ } \
+ } else \
+ GTEST_CONCAT_TOKEN_(gtest_label_testthrow_, __LINE__) \
+ : fail(gtest_ar.failure_message())
+
+// Tests that the statement writes the expected output to file.
+# define EXPECT_WRITE(file, statement, expected_output) \
+ FMT_TEST_WRITE_(statement, expected_output, file, GTEST_NONFATAL_FAILURE_)
+
+# ifdef _MSC_VER
+#include <crtdbg.h>
+
+// Suppresses Windows assertions on invalid file descriptors, making
+// POSIX functions return proper error codes instead of crashing on Windows.
+class SuppressAssert {
+ private:
+ _invalid_parameter_handler original_handler_;
+ int original_report_mode_;
+
+ static void handle_invalid_parameter(const wchar_t*, const wchar_t*,
+ const wchar_t*, unsigned, uintptr_t) {}
+
+ public:
+ SuppressAssert()
+ : original_handler_(
+ _set_invalid_parameter_handler(handle_invalid_parameter)),
+ original_report_mode_(_CrtSetReportMode(_CRT_ASSERT, 0)) {}
+ ~SuppressAssert() {
+ _set_invalid_parameter_handler(original_handler_);
+ _CrtSetReportMode(_CRT_ASSERT, original_report_mode_);
+ }
+};
+
+# define SUPPRESS_ASSERT(statement) \
+ { \
+ SuppressAssert sa; \
+ statement; \
+ }
+# else
+# define SUPPRESS_ASSERT(statement) statement
+# endif // _MSC_VER
+
+# define EXPECT_SYSTEM_ERROR_NOASSERT(statement, error_code, message) \
+ EXPECT_SYSTEM_ERROR(SUPPRESS_ASSERT(statement), error_code, message)
+
+// Attempts to read count characters from a file.
+std::string read(fmt::file& f, size_t count);
+
+# define EXPECT_READ(file, expected_content) \
+ EXPECT_EQ(expected_content, \
+ read(file, fmt::string_view(expected_content).size()))
+
+#else
+# define EXPECT_WRITE(file, statement, expected_output) \
+ do { \
+ (void)(file); \
+ (void)(statement); \
+ (void)(expected_output); \
+ SUCCEED(); \
+ } 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
new file mode 100644
index 0000000000..674dab993d
--- /dev/null
+++ b/contrib/libs/fmt/test/header-only-test.cc
@@ -0,0 +1,3 @@
+// Header-only configuration test
+
+#include "fmt/core.h"
diff --git a/contrib/libs/fmt/test/header-only-test/ya.make b/contrib/libs/fmt/test/header-only-test/ya.make
new file mode 100644
index 0000000000..cfbc290203
--- /dev/null
+++ b/contrib/libs/fmt/test/header-only-test/ya.make
@@ -0,0 +1,37 @@
+# Generated by devtools/yamaker.
+
+GTEST()
+
+WITHOUT_LICENSE_TEXTS()
+
+OWNER(
+ orivej
+ g:cpp-contrib
+)
+
+LICENSE(MIT)
+
+PEERDIR(
+ contrib/libs/fmt
+ contrib/libs/fmt/test
+)
+
+NO_COMPILER_WARNINGS()
+
+NO_UTIL()
+
+CFLAGS(
+ -DFMT_HEADER_ONLY=1
+ -DGTEST_HAS_STD_WSTRING=1
+ -DGTEST_LANG_CXX11=0
+ -D_SILENCE_TR1_NAMESPACE_DEPRECATION_WARNING=1
+)
+
+SRCDIR(contrib/libs/fmt/test)
+
+SRCS(
+ header-only-test.cc
+ header-only-test2.cc
+)
+
+END()
diff --git a/contrib/libs/fmt/test/header-only-test2.cc b/contrib/libs/fmt/test/header-only-test2.cc
new file mode 100644
index 0000000000..ea90b604e4
--- /dev/null
+++ b/contrib/libs/fmt/test/header-only-test2.cc
@@ -0,0 +1,3 @@
+// 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
new file mode 100644
index 0000000000..7d776b4290
--- /dev/null
+++ b/contrib/libs/fmt/test/locale-test.cc
@@ -0,0 +1,160 @@
+// 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/locale-test/ya.make b/contrib/libs/fmt/test/locale-test/ya.make
new file mode 100644
index 0000000000..06a53a939c
--- /dev/null
+++ b/contrib/libs/fmt/test/locale-test/ya.make
@@ -0,0 +1,37 @@
+# Generated by devtools/yamaker.
+
+GTEST()
+
+WITHOUT_LICENSE_TEXTS()
+
+OWNER(
+ orivej
+ g:cpp-contrib
+)
+
+LICENSE(MIT)
+
+PEERDIR(
+ contrib/libs/fmt
+ contrib/libs/fmt/test
+)
+
+NO_COMPILER_WARNINGS()
+
+NO_UTIL()
+
+CFLAGS(
+ -DFMT_LOCALE
+ -DFMT_SHARED
+ -DGTEST_HAS_STD_WSTRING=1
+ -DGTEST_LANG_CXX11=0
+ -D_SILENCE_TR1_NAMESPACE_DEPRECATION_WARNING=1
+)
+
+SRCDIR(contrib/libs/fmt/test)
+
+SRCS(
+ locale-test.cc
+)
+
+END()
diff --git a/contrib/libs/fmt/test/mock-allocator.h b/contrib/libs/fmt/test/mock-allocator.h
new file mode 100644
index 0000000000..dfc13feee7
--- /dev/null
+++ b/contrib/libs/fmt/test/mock-allocator.h
@@ -0,0 +1,60 @@
+// Formatting library for C++ - mock allocator
+//
+// Copyright (c) 2012 - present, Victor Zverovich
+// All rights reserved.
+//
+// For the license information refer to format.h.
+
+#ifndef FMT_MOCK_ALLOCATOR_H_
+#define FMT_MOCK_ALLOCATOR_H_
+
+#include "fmt/format.h"
+#include <gmock/gmock.h>
+
+template <typename T> class mock_allocator {
+ public:
+ mock_allocator() {}
+ mock_allocator(const mock_allocator&) {}
+ typedef T value_type;
+ MOCK_METHOD1_T(allocate, T*(size_t n));
+ MOCK_METHOD2_T(deallocate, void(T* p, size_t n));
+};
+
+template <typename Allocator> class allocator_ref {
+ private:
+ Allocator* alloc_;
+
+ void move(allocator_ref& other) {
+ alloc_ = other.alloc_;
+ other.alloc_ = nullptr;
+ }
+
+ public:
+ typedef typename Allocator::value_type value_type;
+
+ explicit allocator_ref(Allocator* alloc = nullptr) : alloc_(alloc) {}
+
+ allocator_ref(const allocator_ref& other) : alloc_(other.alloc_) {}
+ allocator_ref(allocator_ref&& other) { move(other); }
+
+ allocator_ref& operator=(allocator_ref&& other) {
+ assert(this != &other);
+ move(other);
+ return *this;
+ }
+
+ allocator_ref& operator=(const allocator_ref& other) {
+ alloc_ = other.alloc_;
+ return *this;
+ }
+
+ public:
+ Allocator* get() const { return alloc_; }
+
+ value_type* allocate(size_t n) {
+ return std::allocator_traits<Allocator>::allocate(*alloc_, n);
+ }
+ void deallocate(value_type* p, size_t n) { alloc_->deallocate(p, n); }
+};
+
+#endif // FMT_MOCK_ALLOCATOR_H_
diff --git a/contrib/libs/fmt/test/os-test.cc b/contrib/libs/fmt/test/os-test.cc
new file mode 100644
index 0000000000..359b5ff8ce
--- /dev/null
+++ b/contrib/libs/fmt/test/os-test.cc
@@ -0,0 +1,532 @@
+// Formatting library for C++ - tests of the OS-specific functionality
+//
+// Copyright (c) 2012 - present, Victor Zverovich
+// All rights reserved.
+//
+// For the license information refer to format.h.
+
+#include "fmt/os.h"
+
+#include <cstdlib> // std::exit
+#include <cstring>
+#include <memory>
+
+#include "gtest-extra.h"
+#include "util.h"
+
+#ifdef fileno
+# undef fileno
+#endif
+
+using fmt::buffered_file;
+using fmt::error_code;
+
+#ifdef _WIN32
+
+# include <windows.h>
+
+TEST(UtilTest, UTF16ToUTF8) {
+ std::string s = "ёжик";
+ 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) {
+ std::string s = "";
+ fmt::detail::utf16_to_utf8 u(L"");
+ EXPECT_EQ(s, u.str());
+ EXPECT_EQ(s.size(), u.size());
+}
+
+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)) {
+ fmt::memory_buffer out;
+ fmt::detail::format_windows_error(out, ERROR_INVALID_PARAMETER, message);
+ fmt::system_error error(0, "");
+ try {
+ (Converter)(str);
+ } catch (const fmt::system_error& e) {
+ error = e;
+ }
+ EXPECT_EQ(ERROR_INVALID_PARAMETER, error.error_code());
+ EXPECT_EQ(fmt::to_string(out), error.what());
+}
+
+TEST(UtilTest, UTF16ToUTF8Error) {
+ check_utf_conversion_error<fmt::detail::utf16_to_utf8, wchar_t>(
+ "cannot convert string from UTF-16 to UTF-8");
+}
+
+TEST(UtilTest, UTF16ToUTF8Convert) {
+ 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(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);
+ 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;
+ // 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) {
+ return;
+ }
+ fmt::detail::utf16_to_utf8 utf8_message(message);
+ LocalFree(message);
+ fmt::memory_buffer actual_message;
+ fmt::detail::format_windows_error(actual_message, provisioning_not_allowed,
+ "test");
+ EXPECT_EQ(fmt::format("test: {}", utf8_message.str()),
+ fmt::to_string(actual_message));
+}
+
+TEST(UtilTest, WindowsError) {
+ fmt::system_error error(0, "");
+ try {
+ throw fmt::windows_error(ERROR_FILE_EXISTS, "test {}", "error");
+ } catch (const fmt::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());
+}
+
+TEST(UtilTest, ReportWindowsError) {
+ fmt::memory_buffer out;
+ fmt::detail::format_windows_error(out, ERROR_FILE_EXISTS, "test error");
+ out.push_back('\n');
+ EXPECT_WRITE(stderr,
+ fmt::report_windows_error(ERROR_FILE_EXISTS, "test error"),
+ fmt::to_string(out));
+}
+
+#endif // _WIN32
+
+#if FMT_USE_FCNTL
+
+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) {
+ char buffer;
+ std::streamsize result = 0;
+ SUPPRESS_ASSERT(result = FMT_POSIX(read(fd, &buffer, 1)));
+ return result == -1 && errno == EBADF;
+}
+
+// Opens a file for reading.
+static 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.close();
+ return read_end;
+}
+
+// Attempts to write a string to a file.
+static void write(file& f, fmt::string_view s) {
+ size_t num_chars_left = s.size();
+ const char* ptr = s.data();
+ do {
+ size_t count = f.write(ptr, num_chars_left);
+ ptr += count;
+ // We can't write more than size_t bytes since num_chars_left
+ // has type size_t.
+ num_chars_left -= count;
+ } while (num_chars_left != 0);
+}
+
+TEST(BufferedFileTest, DefaultCtor) {
+ buffered_file f;
+ EXPECT_TRUE(f.get() == nullptr);
+}
+
+TEST(BufferedFileTest, MoveCtor) {
+ buffered_file bf = open_buffered_file();
+ FILE* fp = bf.get();
+ EXPECT_TRUE(fp != nullptr);
+ buffered_file bf2(std::move(bf));
+ EXPECT_EQ(fp, bf2.get());
+ EXPECT_TRUE(bf.get() == nullptr);
+}
+
+TEST(BufferedFileTest, MoveAssignment) {
+ buffered_file bf = open_buffered_file();
+ FILE* fp = bf.get();
+ EXPECT_TRUE(fp != nullptr);
+ buffered_file bf2;
+ bf2 = std::move(bf);
+ EXPECT_EQ(fp, bf2.get());
+ EXPECT_TRUE(bf.get() == nullptr);
+}
+
+TEST(BufferedFileTest, MoveAssignmentClosesFile) {
+ buffered_file bf = open_buffered_file();
+ buffered_file bf2 = open_buffered_file();
+ int old_fd = bf2.fileno();
+ bf2 = std::move(bf);
+ EXPECT_TRUE(isclosed(old_fd));
+}
+
+TEST(BufferedFileTest, MoveFromTemporaryInCtor) {
+ FILE* fp = nullptr;
+ buffered_file f(open_buffered_file(&fp));
+ EXPECT_EQ(fp, f.get());
+}
+
+TEST(BufferedFileTest, MoveFromTemporaryInAssignment) {
+ FILE* fp = nullptr;
+ buffered_file f;
+ f = open_buffered_file(&fp);
+ EXPECT_EQ(fp, f.get());
+}
+
+TEST(BufferedFileTest, MoveFromTemporaryInAssignmentClosesFile) {
+ buffered_file f = open_buffered_file();
+ int old_fd = f.fileno();
+ f = open_buffered_file();
+ EXPECT_TRUE(isclosed(old_fd));
+}
+
+TEST(BufferedFileTest, CloseFileInDtor) {
+ int fd = 0;
+ {
+ buffered_file f = open_buffered_file();
+ fd = f.fileno();
+ }
+ EXPECT_TRUE(isclosed(fd));
+}
+
+TEST(BufferedFileTest, CloseErrorInDtor) {
+ std::unique_ptr<buffered_file> f(new buffered_file(open_buffered_file()));
+ EXPECT_WRITE(
+ stderr,
+ {
+ // The close function must be called inside EXPECT_WRITE,
+ // otherwise the system may recycle closed file descriptor when
+ // redirecting the output in EXPECT_STDERR and the second close
+ // will break output redirection.
+ FMT_POSIX(close(f->fileno()));
+ SUPPRESS_ASSERT(f.reset(nullptr));
+ },
+ format_system_error(EBADF, "cannot close file") + "\n");
+}
+
+TEST(BufferedFileTest, Close) {
+ buffered_file f = open_buffered_file();
+ int fd = f.fileno();
+ f.close();
+ EXPECT_TRUE(f.get() == nullptr);
+ EXPECT_TRUE(isclosed(fd));
+}
+
+TEST(BufferedFileTest, CloseError) {
+ 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();
+ EXPECT_TRUE(f.fileno() != -1);
+ file copy = file::dup(f.fileno());
+ EXPECT_READ(copy, FILE_CONTENT);
+}
+
+TEST(OStreamTest, Move) {
+ fmt::ostream out = fmt::output_file("test-file");
+ fmt::ostream moved(std::move(out));
+ moved.print("hello");
+}
+
+TEST(OStreamTest, Print) {
+ fmt::ostream out = fmt::output_file("test-file");
+ out.print("The answer is {}.\n", 42);
+ out.close();
+ file in("test-file", file::RDONLY);
+ EXPECT_READ(in, "The answer is 42.\n");
+}
+
+TEST(OStreamTest, BufferBoundary) {
+ auto str = std::string(4096, 'x');
+ fmt::ostream out = fmt::output_file("test-file");
+ out.print("{}", str);
+ out.print("{}", str);
+ out.close();
+ file in("test-file", file::RDONLY);
+ EXPECT_READ(in, str + str);
+}
+
+TEST(OStreamTest, BufferSize) {
+ 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) {
+ file f;
+ EXPECT_EQ(-1, f.descriptor());
+}
+
+TEST(FileTest, OpenBufferedFileInCtor) {
+ FILE* fp = safe_fopen("test-file", "w");
+ std::fputs(FILE_CONTENT, fp);
+ std::fclose(fp);
+ file f("test-file", file::RDONLY);
+ ASSERT_TRUE(isopen(f.descriptor()));
+}
+
+TEST(FileTest, OpenBufferedFileError) {
+ EXPECT_SYSTEM_ERROR(file("nonexistent", file::RDONLY), ENOENT,
+ "cannot open file nonexistent");
+}
+
+TEST(FileTest, MoveCtor) {
+ file f = open_file();
+ int fd = f.descriptor();
+ EXPECT_NE(-1, fd);
+ file f2(std::move(f));
+ EXPECT_EQ(fd, f2.descriptor());
+ EXPECT_EQ(-1, f.descriptor());
+}
+
+TEST(FileTest, MoveAssignment) {
+ file f = open_file();
+ int fd = f.descriptor();
+ EXPECT_NE(-1, fd);
+ file f2;
+ f2 = std::move(f);
+ EXPECT_EQ(fd, f2.descriptor());
+ EXPECT_EQ(-1, f.descriptor());
+}
+
+TEST(FileTest, MoveAssignmentClosesFile) {
+ file f = open_file();
+ file f2 = open_file();
+ int old_fd = f2.descriptor();
+ f2 = std::move(f);
+ EXPECT_TRUE(isclosed(old_fd));
+}
+
+static file OpenBufferedFile(int& fd) {
+ file f = open_file();
+ fd = f.descriptor();
+ return f;
+}
+
+TEST(FileTest, MoveFromTemporaryInCtor) {
+ int fd = 0xdead;
+ file f(OpenBufferedFile(fd));
+ EXPECT_EQ(fd, f.descriptor());
+}
+
+TEST(FileTest, MoveFromTemporaryInAssignment) {
+ int fd = 0xdead;
+ file f;
+ f = OpenBufferedFile(fd);
+ EXPECT_EQ(fd, f.descriptor());
+}
+
+TEST(FileTest, MoveFromTemporaryInAssignmentClosesFile) {
+ int fd = 0xdead;
+ file f = open_file();
+ int old_fd = f.descriptor();
+ f = OpenBufferedFile(fd);
+ EXPECT_TRUE(isclosed(old_fd));
+}
+
+TEST(FileTest, CloseFileInDtor) {
+ int fd = 0;
+ {
+ file f = open_file();
+ fd = f.descriptor();
+ }
+ EXPECT_TRUE(isclosed(fd));
+}
+
+TEST(FileTest, CloseErrorInDtor) {
+ std::unique_ptr<file> f(new file(open_file()));
+ EXPECT_WRITE(
+ stderr,
+ {
+ // The close function must be called inside EXPECT_WRITE,
+ // otherwise the system may recycle closed file descriptor when
+ // redirecting the output in EXPECT_STDERR and the second close
+ // will break output redirection.
+ FMT_POSIX(close(f->descriptor()));
+ SUPPRESS_ASSERT(f.reset(nullptr));
+ },
+ format_system_error(EBADF, "cannot close file") + "\n");
+}
+
+TEST(FileTest, Close) {
+ file f = open_file();
+ int fd = f.descriptor();
+ f.close();
+ EXPECT_EQ(-1, f.descriptor());
+ EXPECT_TRUE(isclosed(fd));
+}
+
+TEST(FileTest, CloseError) {
+ 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) {
+ file f = open_file();
+ EXPECT_READ(f, FILE_CONTENT);
+}
+
+TEST(FileTest, ReadError) {
+ file f("test-file", file::WRONLY);
+ char buf;
+ // We intentionally read from a file opened in the write-only mode to
+ // cause error.
+ EXPECT_SYSTEM_ERROR(f.read(&buf, 1), EBADF, "cannot read from file");
+}
+
+TEST(FileTest, Write) {
+ file read_end, write_end;
+ file::pipe(read_end, write_end);
+ write(write_end, "test");
+ write_end.close();
+ EXPECT_READ(read_end, "test");
+}
+
+TEST(FileTest, WriteError) {
+ 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) {
+ 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)));
+}
+
+# ifndef __COVERITY__
+TEST(FileTest, DupError) {
+ int value = -1;
+ EXPECT_SYSTEM_ERROR_NOASSERT(file::dup(value), EBADF,
+ "cannot duplicate file descriptor -1");
+}
+# endif
+
+TEST(FileTest, Dup2) {
+ file f = open_file();
+ file copy = open_file();
+ f.dup2(copy.descriptor());
+ EXPECT_NE(f.descriptor(), copy.descriptor());
+ EXPECT_READ(copy, FILE_CONTENT);
+}
+
+TEST(FileTest, Dup2Error) {
+ 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) {
+ file f = open_file();
+ file copy = open_file();
+ error_code ec;
+ f.dup2(copy.descriptor(), ec);
+ EXPECT_EQ(ec.get(), 0);
+ EXPECT_NE(f.descriptor(), copy.descriptor());
+ EXPECT_READ(copy, FILE_CONTENT);
+}
+
+TEST(FileTest, Dup2NoExceptError) {
+ file f = open_file();
+ error_code ec;
+ SUPPRESS_ASSERT(f.dup2(-1, ec));
+ EXPECT_EQ(EBADF, ec.get());
+}
+
+TEST(FileTest, Pipe) {
+ file read_end, write_end;
+ file::pipe(read_end, write_end);
+ EXPECT_NE(-1, read_end.descriptor());
+ EXPECT_NE(-1, write_end.descriptor());
+ write(write_end, "test");
+ EXPECT_READ(read_end, "test");
+}
+
+TEST(FileTest, 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/os-test/ya.make b/contrib/libs/fmt/test/os-test/ya.make
new file mode 100644
index 0000000000..34228bb26b
--- /dev/null
+++ b/contrib/libs/fmt/test/os-test/ya.make
@@ -0,0 +1,37 @@
+# Generated by devtools/yamaker.
+
+GTEST()
+
+WITHOUT_LICENSE_TEXTS()
+
+OWNER(
+ orivej
+ g:cpp-contrib
+)
+
+LICENSE(MIT)
+
+PEERDIR(
+ contrib/libs/fmt
+ contrib/libs/fmt/test
+)
+
+NO_COMPILER_WARNINGS()
+
+NO_UTIL()
+
+CFLAGS(
+ -DFMT_LOCALE
+ -DFMT_SHARED
+ -DGTEST_HAS_STD_WSTRING=1
+ -DGTEST_LANG_CXX11=0
+ -D_SILENCE_TR1_NAMESPACE_DEPRECATION_WARNING=1
+)
+
+SRCDIR(contrib/libs/fmt/test)
+
+SRCS(
+ os-test.cc
+)
+
+END()
diff --git a/contrib/libs/fmt/test/ostream-test.cc b/contrib/libs/fmt/test/ostream-test.cc
new file mode 100644
index 0000000000..4cef5a78c4
--- /dev/null
+++ b/contrib/libs/fmt/test/ostream-test.cc
@@ -0,0 +1,330 @@
+// Formatting library for C++ - std::ostream support tests
+//
+// Copyright (c) 2012 - present, Victor Zverovich
+// All rights reserved.
+//
+// For the license information refer to format.h.
+
+#include "fmt/format.h"
+
+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) {
+ return formatter<int>::format(42, ctx);
+ }
+};
+} // namespace fmt
+
+#include <sstream>
+
+#include "fmt/ostream.h"
+#include "fmt/ranges.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) {
+ os << d.year() << '-' << d.month() << '-' << d.day();
+ return os;
+}
+
+static std::wostream& operator<<(std::wostream& os, const Date& d) {
+ os << d.year() << L'-' << d.month() << L'-' << d.day();
+ return os;
+}
+
+// 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&);
+
+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";
+}
+
+enum unstreamable_enum {};
+
+TEST(OStreamTest, 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(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));
+}
+
+struct EmptyTest {};
+static std::ostream& operator<<(std::ostream& os, EmptyTest) {
+ return os << "";
+}
+
+TEST(OStreamTest, EmptyCustomOutput) {
+ EXPECT_EQ("", fmt::format("{}", EmptyTest()));
+}
+
+TEST(OStreamTest, 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) {
+ std::ostringstream os;
+ fmt::memory_buffer buffer;
+ const char* foo = "foo";
+ buffer.append(foo, foo + std::strlen(foo));
+ fmt::detail::write_buffer(os, buffer);
+ 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>();
+ 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) {}
+ } 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) {
+ const void* v = s;
+ return xsputn(v, n);
+ }
+ } streambuf;
+
+ struct test_ostream : std::ostream {
+ explicit test_ostream(mock_streambuf& buffer) : std::ostream(&buffer) {}
+ } os(streambuf);
+
+ testing::InSequence sequence;
+ const char* data = nullptr;
+ typedef std::make_unsigned<std::streamsize>::type ustreamsize;
+ ustreamsize size = max_size;
+ do {
+ auto n = std::min(size, fmt::detail::to_unsigned(max_streamsize));
+ EXPECT_CALL(streambuf, xsputn(data, static_cast<std::streamsize>(n)))
+ .WillOnce(testing::Return(max_streamsize));
+ data += n;
+ size -= n;
+ } while (size != 0);
+ fmt::detail::write_buffer(os, buffer);
+}
+
+TEST(OStreamTest, Join) {
+ int v[3] = {1, 2, 3};
+ EXPECT_EQ("1, 2, 3", fmt::format("{}", fmt::join(v, v + 3, ", ")));
+}
+
+#if FMT_USE_CONSTEXPR
+TEST(OStreamTest, ConstexprString) {
+ EXPECT_EQ("42", format(FMT_STRING("{}"), std::string("42")));
+ EXPECT_EQ("a string", format(FMT_STRING("{0}"), TestString("a string")));
+}
+#endif
+
+namespace fmt_test {
+struct ABC {};
+
+template <typename Output> Output& operator<<(Output& out, ABC) {
+ out << "ABC";
+ return out;
+}
+} // namespace fmt_test
+
+template <typename T> struct TestTemplate {};
+
+template <typename T>
+std::ostream& operator<<(std::ostream& os, TestTemplate<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) {
+ 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(FormatTest, FormatToN) {
+ char buffer[4];
+ buffer[3] = 'x';
+ 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(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");
+}
+#endif
+
+template <typename T> struct convertible {
+ T value;
+ explicit convertible(const T& val) : value(val) {}
+ operator T() const { return value; }
+};
+
+TEST(OStreamTest, DisableBuiltinOStreamOperators) {
+ 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")));
+}
+
+struct explicitly_convertible_to_string_like {
+ template <typename String,
+ typename = typename std::enable_if<std::is_constructible<
+ String, const char*, size_t>::value>::type>
+ explicit operator String() const {
+ return String("foo", 3u);
+ }
+};
+
+std::ostream& operator<<(std::ostream& os,
+ explicitly_convertible_to_string_like) {
+ return os << "bar";
+}
+
+TEST(OStreamTest, FormatExplicitlyConvertibleToStringLike) {
+ EXPECT_EQ("bar", fmt::format("{}", explicitly_convertible_to_string_like()));
+}
+
+#ifdef FMT_USE_STRING_VIEW
+struct explicitly_convertible_to_std_string_view {
+ explicit operator fmt::detail::std_string_view<char>() const {
+ return {"foo", 3u};
+ }
+};
+
+std::ostream& operator<<(std::ostream& os,
+ explicitly_convertible_to_std_string_view) {
+ return os << "bar";
+}
+
+TEST(OStreamTest, FormatExplicitlyConvertibleToStdStringView) {
+ EXPECT_EQ("bar", fmt::format("{}", explicitly_convertible_to_string_like()));
+}
+#endif // FMT_USE_STRING_VIEW
+
+struct streamable_and_convertible_to_bool {
+ operator bool() const { return true; }
+};
+
+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()));
+}
+
+struct copyfmt_test {};
+
+std::ostream& operator<<(std::ostream& os, copyfmt_test) {
+ std::ios ios(nullptr);
+ ios.copyfmt(os);
+ return os << "foo";
+}
+
+TEST(OStreamTest, CopyFmt) {
+ EXPECT_EQ("foo", fmt::format("{}", copyfmt_test()));
+}
+
+TEST(OStreamTest, CompileTimeString) {
+ EXPECT_EQ("42", fmt::format(FMT_STRING("{}"), 42));
+}
+
+TEST(OStreamTest, ToString) {
+ EXPECT_EQ("ABC", fmt::to_string(fmt_test::ABC()));
+}
+
+TEST(OStreamTest, Range) {
+ auto strs = std::vector<TestString>{TestString("foo"), TestString("bar")};
+ EXPECT_EQ("{foo, bar}", format("{}", strs));
+} \ No newline at end of file
diff --git a/contrib/libs/fmt/test/ostream-test/ya.make b/contrib/libs/fmt/test/ostream-test/ya.make
new file mode 100644
index 0000000000..10921b40d1
--- /dev/null
+++ b/contrib/libs/fmt/test/ostream-test/ya.make
@@ -0,0 +1,37 @@
+# Generated by devtools/yamaker.
+
+GTEST()
+
+WITHOUT_LICENSE_TEXTS()
+
+OWNER(
+ orivej
+ g:cpp-contrib
+)
+
+LICENSE(MIT)
+
+PEERDIR(
+ contrib/libs/fmt
+ contrib/libs/fmt/test
+)
+
+NO_COMPILER_WARNINGS()
+
+NO_UTIL()
+
+CFLAGS(
+ -DFMT_LOCALE
+ -DFMT_SHARED
+ -DGTEST_HAS_STD_WSTRING=1
+ -DGTEST_LANG_CXX11=0
+ -D_SILENCE_TR1_NAMESPACE_DEPRECATION_WARNING=1
+)
+
+SRCDIR(contrib/libs/fmt/test)
+
+SRCS(
+ ostream-test.cc
+)
+
+END()
diff --git a/contrib/libs/fmt/test/posix-mock-test.cc b/contrib/libs/fmt/test/posix-mock-test.cc
new file mode 100644
index 0000000000..0ea1b9c6d5
--- /dev/null
+++ b/contrib/libs/fmt/test/posix-mock-test.cc
@@ -0,0 +1,558 @@
+// Tests of the C++ interface to POSIX functions that require mocks
+//
+// Copyright (c) 2012 - present, Victor Zverovich
+// All rights reserved.
+//
+// For the license information refer to format.h.
+
+// Disable bogus MSVC warnings.
+#ifndef _CRT_SECURE_NO_WARNINGS
+# define _CRT_SECURE_NO_WARNINGS
+#endif
+
+#include "posix-mock.h"
+
+#include <errno.h>
+#include <fcntl.h>
+
+#include <climits>
+#include <memory>
+
+#include "../src/os.cc"
+
+#ifdef _WIN32
+# include <io.h>
+# undef max
+# undef ERROR
+#endif
+
+#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;
+
+namespace {
+int open_count;
+int close_count;
+int dup_count;
+int dup2_count;
+int fdopen_count;
+int read_count;
+int write_count;
+int pipe_count;
+int fopen_count;
+int fclose_count;
+int fileno_count;
+size_t read_nbyte;
+size_t write_nbyte;
+bool sysconf_error;
+
+enum { NONE, MAX_SIZE, ERROR } fstat_sim;
+} // namespace
+
+#define EMULATE_EINTR(func, error_result) \
+ if (func##_count != 0) { \
+ if (func##_count++ != 3) { \
+ errno = EINTR; \
+ return error_result; \
+ } \
+ }
+
+#ifndef _MSC_VER
+int test::open(const char* path, int oflag, int mode) {
+ EMULATE_EINTR(open, -1);
+ return ::open(path, oflag, mode);
+}
+#else
+errno_t test::sopen_s(int* pfh, const char* filename, int oflag, int shflag,
+ int pmode) {
+ EMULATE_EINTR(open, EINTR);
+ return _sopen_s(pfh, filename, oflag, shflag, pmode);
+}
+#endif
+
+#ifndef _WIN32
+
+long test::sysconf(int name) {
+ long result = ::sysconf(name);
+ if (!sysconf_error) return result;
+ // Simulate an error.
+ errno = EINVAL;
+ return -1;
+}
+
+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();
+ return result;
+}
+
+#else
+
+static LONGLONG max_file_size() { return std::numeric_limits<LONGLONG>::max(); }
+
+DWORD test::GetFileSize(HANDLE hFile, LPDWORD lpFileSizeHigh) {
+ if (fstat_sim == ERROR) {
+ SetLastError(ERROR_ACCESS_DENIED);
+ return INVALID_FILE_SIZE;
+ }
+ if (fstat_sim == MAX_SIZE) {
+ DWORD max = std::numeric_limits<DWORD>::max();
+ *lpFileSizeHigh = max >> 1;
+ return max;
+ }
+ return ::GetFileSize(hFile, lpFileSizeHigh);
+}
+
+#endif
+
+int test::close(int fildes) {
+ // Close the file first because close shouldn't be retried.
+ int result = ::FMT_POSIX(close(fildes));
+ EMULATE_EINTR(close, -1);
+ return result;
+}
+
+int test::dup(int fildes) {
+ EMULATE_EINTR(dup, -1);
+ return ::FMT_POSIX(dup(fildes));
+}
+
+int test::dup2(int fildes, int fildes2) {
+ EMULATE_EINTR(dup2, -1);
+ return ::FMT_POSIX(dup2(fildes, fildes2));
+}
+
+FILE* test::fdopen(int fildes, const char* mode) {
+ EMULATE_EINTR(fdopen, nullptr);
+ return ::FMT_POSIX(fdopen(fildes, mode));
+}
+
+test::ssize_t test::read(int fildes, void* buf, test::size_t nbyte) {
+ read_nbyte = nbyte;
+ EMULATE_EINTR(read, -1);
+ return ::FMT_POSIX(read(fildes, buf, nbyte));
+}
+
+test::ssize_t test::write(int fildes, const void* buf, test::size_t nbyte) {
+ write_nbyte = nbyte;
+ EMULATE_EINTR(write, -1);
+ return ::FMT_POSIX(write(fildes, buf, nbyte));
+}
+
+#ifndef _WIN32
+int test::pipe(int fildes[2]) {
+ EMULATE_EINTR(pipe, -1);
+ return ::pipe(fildes);
+}
+#else
+int test::pipe(int* pfds, unsigned psize, int textmode) {
+ EMULATE_EINTR(pipe, -1);
+ return _pipe(pfds, psize, textmode);
+}
+#endif
+
+FILE* test::fopen(const char* filename, const char* mode) {
+ EMULATE_EINTR(fopen, nullptr);
+ return ::fopen(filename, mode);
+}
+
+int test::fclose(FILE* stream) {
+ EMULATE_EINTR(fclose, EOF);
+ return ::fclose(stream);
+}
+
+int(test::fileno)(FILE* stream) {
+ EMULATE_EINTR(fileno, -1);
+#ifdef fileno
+ return FMT_POSIX(fileno(stream));
+#else
+ return ::FMT_POSIX(fileno(stream));
+#endif
+}
+
+#ifndef _WIN32
+# define EXPECT_RETRY(statement, func, message) \
+ func##_count = 1; \
+ statement; \
+ EXPECT_EQ(4, func##_count); \
+ func##_count = 0;
+# define EXPECT_EQ_POSIX(expected, actual) EXPECT_EQ(expected, actual)
+#else
+# define EXPECT_RETRY(statement, func, message) \
+ func##_count = 1; \
+ EXPECT_SYSTEM_ERROR(statement, EINTR, message); \
+ func##_count = 0;
+# define EXPECT_EQ_POSIX(expected, actual)
+#endif
+
+static 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) {
+# ifdef _WIN32
+ SYSTEM_INFO si = {};
+ GetSystemInfo(&si);
+ EXPECT_EQ(si.dwPageSize, fmt::getpagesize());
+# else
+ EXPECT_EQ(sysconf(_SC_PAGESIZE), fmt::getpagesize());
+ sysconf_error = true;
+ EXPECT_SYSTEM_ERROR(fmt::getpagesize(), EINVAL,
+ "cannot get memory page size");
+ sysconf_error = false;
+# endif
+}
+
+TEST(FileTest, OpenRetry) {
+ write_file("temp", "there must be something here");
+ std::unique_ptr<file> f{nullptr};
+ EXPECT_RETRY(f.reset(new file("temp", file::RDONLY)), open,
+ "cannot open file temp");
+# ifndef _WIN32
+ char c = 0;
+ f->read(&c, 1);
+# endif
+}
+
+TEST(FileTest, CloseNoRetryInDtor) {
+ file read_end, write_end;
+ file::pipe(read_end, write_end);
+ std::unique_ptr<file> f(new file(std::move(read_end)));
+ int saved_close_count = 0;
+ EXPECT_WRITE(
+ stderr,
+ {
+ close_count = 1;
+ f.reset(nullptr);
+ saved_close_count = close_count;
+ close_count = 0;
+ },
+ format_system_error(EINTR, "cannot close file") + "\n");
+ EXPECT_EQ(2, saved_close_count);
+}
+
+TEST(FileTest, CloseNoRetry) {
+ file read_end, write_end;
+ file::pipe(read_end, write_end);
+ close_count = 1;
+ EXPECT_SYSTEM_ERROR(read_end.close(), EINTR, "cannot close file");
+ EXPECT_EQ(2, close_count);
+ close_count = 0;
+}
+
+TEST(FileTest, 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;
+# else
+ f.close();
+ EXPECT_SYSTEM_ERROR(f.size(), EBADF, "cannot get file attributes");
+# endif
+}
+
+TEST(FileTest, MaxSize) {
+ write_file("temp", "");
+ file f("temp", file::RDONLY);
+ fstat_sim = MAX_SIZE;
+ EXPECT_GE(f.size(), 0);
+ EXPECT_EQ(max_file_size(), f.size());
+ fstat_sim = NONE;
+}
+
+TEST(FileTest, ReadRetry) {
+ file read_end, write_end;
+ file::pipe(read_end, write_end);
+ enum { SIZE = 4 };
+ write_end.write("test", SIZE);
+ write_end.close();
+ char buffer[SIZE];
+ size_t count = 0;
+ EXPECT_RETRY(count = read_end.read(buffer, SIZE), read,
+ "cannot read from file");
+ EXPECT_EQ_POSIX(static_cast<std::streamsize>(SIZE), count);
+}
+
+TEST(FileTest, WriteRetry) {
+ file read_end, write_end;
+ file::pipe(read_end, write_end);
+ enum { SIZE = 4 };
+ size_t count = 0;
+ EXPECT_RETRY(count = write_end.write("test", SIZE), write,
+ "cannot write to file");
+ write_end.close();
+# ifndef _WIN32
+ EXPECT_EQ(static_cast<std::streamsize>(SIZE), count);
+ char buffer[SIZE + 1];
+ read_end.read(buffer, SIZE);
+ buffer[SIZE] = '\0';
+ EXPECT_STREQ("test", buffer);
+# endif
+}
+
+# ifdef _WIN32
+TEST(FileTest, ConvertReadCount) {
+ file read_end, write_end;
+ file::pipe(read_end, write_end);
+ char c;
+ size_t size = UINT_MAX;
+ if (sizeof(unsigned) != sizeof(size_t)) ++size;
+ read_count = 1;
+ read_nbyte = 0;
+ EXPECT_THROW(read_end.read(&c, size), fmt::system_error);
+ read_count = 0;
+ EXPECT_EQ(UINT_MAX, read_nbyte);
+}
+
+TEST(FileTest, ConvertWriteCount) {
+ file read_end, write_end;
+ file::pipe(read_end, write_end);
+ char c;
+ size_t size = UINT_MAX;
+ if (sizeof(unsigned) != sizeof(size_t)) ++size;
+ write_count = 1;
+ write_nbyte = 0;
+ EXPECT_THROW(write_end.write(&c, size), fmt::system_error);
+ write_count = 0;
+ EXPECT_EQ(UINT_MAX, write_nbyte);
+}
+# endif
+
+TEST(FileTest, DupNoRetry) {
+ int stdout_fd = FMT_POSIX(fileno(stdout));
+ dup_count = 1;
+ EXPECT_SYSTEM_ERROR(
+ file::dup(stdout_fd), EINTR,
+ fmt::format("cannot duplicate file descriptor {}", stdout_fd));
+ dup_count = 0;
+}
+
+TEST(FileTest, Dup2Retry) {
+ 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,
+ fmt::format("cannot duplicate file descriptor {} to {}",
+ f1.descriptor(), f2.descriptor()));
+}
+
+TEST(FileTest, Dup2NoExceptRetry) {
+ int stdout_fd = FMT_POSIX(fileno(stdout));
+ file f1 = file::dup(stdout_fd), f2 = file::dup(stdout_fd);
+ error_code ec;
+ dup2_count = 1;
+ f1.dup2(f2.descriptor(), ec);
+# ifndef _WIN32
+ EXPECT_EQ(4, dup2_count);
+# else
+ EXPECT_EQ(EINTR, ec.get());
+# endif
+ dup2_count = 0;
+}
+
+TEST(FileTest, PipeNoRetry) {
+ file read_end, write_end;
+ pipe_count = 1;
+ EXPECT_SYSTEM_ERROR(file::pipe(read_end, write_end), EINTR,
+ "cannot create pipe");
+ pipe_count = 0;
+}
+
+TEST(FileTest, FdopenNoRetry) {
+ file read_end, write_end;
+ file::pipe(read_end, write_end);
+ fdopen_count = 1;
+ EXPECT_SYSTEM_ERROR(read_end.fdopen("r"), EINTR,
+ "cannot associate stream with file descriptor");
+ fdopen_count = 0;
+}
+
+TEST(BufferedFileTest, OpenRetry) {
+ 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,
+ "cannot open file temp");
+# ifndef _WIN32
+ char c = 0;
+ if (fread(&c, 1, 1, f->get()) < 1)
+ throw fmt::system_error(errno, "fread failed");
+# endif
+}
+
+TEST(BufferedFileTest, CloseNoRetryInDtor) {
+ file read_end, write_end;
+ file::pipe(read_end, write_end);
+ std::unique_ptr<buffered_file> f(new buffered_file(read_end.fdopen("r")));
+ int saved_fclose_count = 0;
+ EXPECT_WRITE(
+ stderr,
+ {
+ fclose_count = 1;
+ f.reset(nullptr);
+ saved_fclose_count = fclose_count;
+ fclose_count = 0;
+ },
+ format_system_error(EINTR, "cannot close file") + "\n");
+ EXPECT_EQ(2, saved_fclose_count);
+}
+
+TEST(BufferedFileTest, CloseNoRetry) {
+ file read_end, write_end;
+ file::pipe(read_end, write_end);
+ buffered_file f = read_end.fdopen("r");
+ fclose_count = 1;
+ EXPECT_SYSTEM_ERROR(f.close(), EINTR, "cannot close file");
+ EXPECT_EQ(2, fclose_count);
+ fclose_count = 0;
+}
+
+TEST(BufferedFileTest, FilenoNoRetry) {
+ file read_end, write_end;
+ file::pipe(read_end, write_end);
+ buffered_file f = read_end.fdopen("r");
+ fileno_count = 1;
+ EXPECT_SYSTEM_ERROR((f.fileno)(), EINTR, "cannot get file descriptor");
+ EXPECT_EQ(2, fileno_count);
+ fileno_count = 0;
+}
+#endif // FMT_USE_FCNTL
+
+struct test_mock {
+ static test_mock* instance;
+} * test_mock::instance;
+
+TEST(ScopedMock, Scope) {
+ {
+ ScopedMock<test_mock> mock;
+ EXPECT_EQ(&mock, test_mock::instance);
+ test_mock& copy = mock;
+ static_cast<void>(copy);
+ }
+ EXPECT_EQ(nullptr, test_mock::instance);
+}
+
+#if defined(FMT_LOCALE) && !defined(_LIBCPP_VERSION)
+
+typedef fmt::locale::type 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
+# pragma warning(push)
+# pragma warning(disable : 4273)
+# ifdef __clang__
+# pragma clang diagnostic push
+# pragma clang diagnostic ignored "-Winconsistent-dllimport"
+# endif
+
+_locale_t _create_locale(int category, const char* locale) {
+ return locale_mock::instance->newlocale(category, locale, 0);
+}
+
+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
+# define FMT_LOCALE_THROW __THROW
+# else
+# define FMT_LOCALE_THROW
+# endif
+
+# if defined(__APPLE__) || \
+ (defined(__FreeBSD__) && __FreeBSD_version < 1200002)
+typedef int FreeLocaleResult;
+# else
+typedef void FreeLocaleResult;
+# endif
+
+FreeLocaleResult freelocale(locale_type locale) FMT_LOCALE_THROW {
+ locale_mock::instance->freelocale(locale);
+ 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)
+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);
+ EXPECT_CALL(mock, newlocale(222, StrEq("foo"), locale));
+ FMT_SYSTEM(newlocale(222, "foo", locale));
+}
+# endif
+
+TEST(LocaleTest, Locale) {
+# ifndef LC_NUMERIC_MASK
+ enum { LC_NUMERIC_MASK = LC_NUMERIC };
+# endif
+ ScopedMock<locale_mock> mock;
+ locale_type impl = reinterpret_cast<locale_type>(42);
+ EXPECT_CALL(mock, newlocale(LC_NUMERIC_MASK, StrEq("C"), nullptr))
+ .WillOnce(Return(impl));
+ EXPECT_CALL(mock, freelocale(impl));
+ fmt::locale loc;
+ 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/posix-mock-test/ya.make b/contrib/libs/fmt/test/posix-mock-test/ya.make
new file mode 100644
index 0000000000..d1a55e5200
--- /dev/null
+++ b/contrib/libs/fmt/test/posix-mock-test/ya.make
@@ -0,0 +1,38 @@
+# Generated by devtools/yamaker.
+
+GTEST()
+
+WITHOUT_LICENSE_TEXTS()
+
+OWNER(
+ orivej
+ g:cpp-contrib
+)
+
+LICENSE(MIT)
+
+ADDINCL(
+ contrib/libs/fmt/include
+)
+
+NO_COMPILER_WARNINGS()
+
+NO_UTIL()
+
+CFLAGS(
+ -DFMT_LOCALE
+ -DGTEST_HAS_STD_WSTRING=1
+ -DGTEST_LANG_CXX11=0
+ -D_SILENCE_TR1_NAMESPACE_DEPRECATION_WARNING=1
+)
+
+SRCDIR(contrib/libs/fmt)
+
+SRCS(
+ src/format.cc
+ test/gtest-extra.cc
+ test/posix-mock-test.cc
+ test/util.cc
+)
+
+END()
diff --git a/contrib/libs/fmt/test/posix-mock.h b/contrib/libs/fmt/test/posix-mock.h
new file mode 100644
index 0000000000..1f204263c6
--- /dev/null
+++ b/contrib/libs/fmt/test/posix-mock.h
@@ -0,0 +1,78 @@
+// Formatting library for C++ - mocks of POSIX functions
+//
+// Copyright (c) 2012 - present, Victor Zverovich
+// All rights reserved.
+//
+// For the license information refer to format.h.
+
+#ifndef FMT_POSIX_TEST_H
+#define FMT_POSIX_TEST_H
+
+#include <errno.h>
+#include <locale.h>
+#include <stdio.h>
+#ifdef __APPLE__
+# include <xlocale.h>
+#endif
+
+#ifdef _WIN32
+# include <windows.h>
+# include <locale> // for libc++ locale_win32.h
+#else
+# include <sys/param.h> // for FreeBSD version
+# include <sys/types.h> // for ssize_t
+#endif
+
+#ifndef _MSC_VER
+struct stat;
+#endif
+
+namespace test {
+
+#ifndef _MSC_VER
+// Size type for read and write.
+typedef size_t size_t;
+typedef ssize_t ssize_t;
+int open(const char* path, int oflag, int mode);
+int fstat(int fd, struct stat* buf);
+#else
+typedef unsigned size_t;
+typedef int ssize_t;
+errno_t sopen_s(int* pfh, const char* filename, int oflag, int shflag,
+ int pmode);
+#endif
+
+#ifndef _WIN32
+long sysconf(int name);
+#else
+DWORD GetFileSize(HANDLE hFile, LPDWORD lpFileSizeHigh);
+#endif
+
+int close(int fildes);
+
+int dup(int fildes);
+int dup2(int fildes, int fildes2);
+
+FILE* fdopen(int fildes, const char* mode);
+
+ssize_t read(int fildes, void* buf, size_t nbyte);
+ssize_t write(int fildes, const void* buf, size_t nbyte);
+
+#ifndef _WIN32
+int pipe(int fildes[2]);
+#else
+int pipe(int* pfds, unsigned psize, int textmode);
+#endif
+
+FILE* fopen(const char* filename, const char* mode);
+int fclose(FILE* stream);
+int(fileno)(FILE* stream);
+
+#if defined(FMT_LOCALE) && (!defined(_WIN32) || defined(_LIBCPP_VERSION))
+locale_t newlocale(int category_mask, const char* locale, locale_t base);
+#endif
+} // namespace test
+
+#define FMT_SYSTEM(call) test::call
+
+#endif // FMT_POSIX_TEST_H
diff --git a/contrib/libs/fmt/test/printf-test.cc b/contrib/libs/fmt/test/printf-test.cc
new file mode 100644
index 0000000000..ccd72dcd75
--- /dev/null
+++ b/contrib/libs/fmt/test/printf-test.cc
@@ -0,0 +1,628 @@
+// Formatting library for C++ - printf tests
+//
+// Copyright (c) 2012 - present, Victor Zverovich
+// All rights reserved.
+//
+// For the license information refer to format.h.
+
+#include "fmt/printf.h"
+
+#include <cctype>
+#include <climits>
+#include <cstring>
+
+#include "fmt/core.h"
+#include "gtest-extra.h"
+#include "util.h"
+
+using fmt::format;
+using fmt::format_error;
+using fmt::detail::max_value;
+
+const unsigned BIG_NUM = INT_MAX + 1u;
+
+// Makes format string argument positional.
+static std::string make_positional(fmt::string_view format) {
+ std::string s(format.data(), format.size());
+ s.replace(s.find('%'), 1, "%1$");
+ return s;
+}
+
+static std::wstring make_positional(fmt::wstring_view format) {
+ std::wstring s(format.data(), format.size());
+ s.replace(s.find(L'%'), 1, L"%1$");
+ return s;
+}
+
+// A wrapper around fmt::sprintf to workaround bogus warnings about invalid
+// format strings in MSVC.
+template <typename... Args>
+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) {
+ return fmt::sprintf(format, args...);
+}
+
+#define EXPECT_PRINTF(expected_output, format, arg) \
+ EXPECT_EQ(expected_output, test_sprintf(format, arg)) \
+ << "format: " << format; \
+ EXPECT_EQ(expected_output, fmt::sprintf(make_positional(format), arg))
+
+TEST(PrintfTest, NoArgs) {
+ EXPECT_EQ("test", test_sprintf("test"));
+ EXPECT_EQ(L"test", fmt::sprintf(L"test"));
+}
+
+TEST(PrintfTest, Escape) {
+ EXPECT_EQ("%", test_sprintf("%%"));
+ EXPECT_EQ("before %", test_sprintf("before %%"));
+ EXPECT_EQ("% after", test_sprintf("%% after"));
+ EXPECT_EQ("before % after", test_sprintf("before %% after"));
+ EXPECT_EQ("%s", test_sprintf("%%s"));
+ EXPECT_EQ(L"%", fmt::sprintf(L"%%"));
+ EXPECT_EQ(L"before %", fmt::sprintf(L"before %%"));
+ EXPECT_EQ(L"% after", fmt::sprintf(L"%% after"));
+ EXPECT_EQ(L"before % after", fmt::sprintf(L"before %% after"));
+ EXPECT_EQ(L"%s", fmt::sprintf(L"%%s"));
+}
+
+TEST(PrintfTest, PositionalArgs) {
+ 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));
+ EXPECT_EQ("before 42 after", test_sprintf("before %1$d after", 42));
+ EXPECT_EQ("answer = 42", test_sprintf("%1$s = %2$d", "answer", 42));
+ EXPECT_EQ("42 is the answer", test_sprintf("%2$d is the %1$s", "answer", 42));
+ EXPECT_EQ("abracadabra", test_sprintf("%1$s%2$s%1$s", "abra", "cad"));
+}
+
+TEST(PrintfTest, AutomaticArgIndexing) {
+ 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(PrintfTest, SwitchArgIndexing) {
+ 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),
+ 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("%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),
+ format_error, "number is too big");
+ EXPECT_THROW_MSG(test_sprintf(format("%1$d%{}d", BIG_NUM), 1, 2),
+ format_error, "number is too big");
+}
+
+TEST(PrintfTest, InvalidArgIndex) {
+ EXPECT_THROW_MSG(test_sprintf("%0$d", 42), format_error,
+ "argument not found");
+ EXPECT_THROW_MSG(test_sprintf("%2$d", 42), format_error,
+ "argument not found");
+ EXPECT_THROW_MSG(test_sprintf(format("%{}$d", INT_MAX), 42), format_error,
+ "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");
+}
+
+TEST(PrintfTest, DefaultAlignRight) {
+ EXPECT_PRINTF(" 42", "%5d", 42);
+ EXPECT_PRINTF(" abc", "%5s", "abc");
+}
+
+TEST(PrintfTest, ZeroFlag) {
+ EXPECT_PRINTF("00042", "%05d", 42);
+ EXPECT_PRINTF("-0042", "%05d", -42);
+
+ EXPECT_PRINTF("00042", "%05d", 42);
+ EXPECT_PRINTF("-0042", "%05d", -42);
+ EXPECT_PRINTF("-004.2", "%06g", -4.2);
+
+ EXPECT_PRINTF("+00042", "%00+6d", 42);
+
+ EXPECT_PRINTF(" 42", "%05.d", 42);
+ EXPECT_PRINTF(" 0042", "%05.4d", 42);
+
+ // '0' flag is ignored for non-numeric types.
+ EXPECT_PRINTF(" x", "%05c", 'x');
+}
+
+TEST(PrintfTest, PlusFlag) {
+ EXPECT_PRINTF("+42", "%+d", 42);
+ EXPECT_PRINTF("-42", "%+d", -42);
+ EXPECT_PRINTF("+0042", "%+05d", 42);
+ EXPECT_PRINTF("+0042", "%0++5d", 42);
+
+ // '+' flag is ignored for non-numeric types.
+ EXPECT_PRINTF("x", "%+c", 'x');
+
+ // '+' flag wins over space flag
+ EXPECT_PRINTF("+42", "%+ d", 42);
+ EXPECT_PRINTF("-42", "%+ d", -42);
+ EXPECT_PRINTF("+42", "% +d", 42);
+ EXPECT_PRINTF("-42", "% +d", -42);
+ EXPECT_PRINTF("+0042", "% +05d", 42);
+ EXPECT_PRINTF("+0042", "%0+ 5d", 42);
+
+ // '+' flag and space flag are both ignored for non-numeric types.
+ EXPECT_PRINTF("x", "%+ c", 'x');
+ EXPECT_PRINTF("x", "% +c", 'x');
+}
+
+TEST(PrintfTest, MinusFlag) {
+ EXPECT_PRINTF("abc ", "%-5s", "abc");
+ EXPECT_PRINTF("abc ", "%0--5s", "abc");
+
+ EXPECT_PRINTF("7 ", "%-5d", 7);
+ EXPECT_PRINTF("97 ", "%-5hhi", 'a');
+ EXPECT_PRINTF("a ", "%-5c", 'a');
+
+ // '0' flag is ignored if '-' flag is given
+ EXPECT_PRINTF("7 ", "%-05d", 7);
+ EXPECT_PRINTF("7 ", "%0-5d", 7);
+ EXPECT_PRINTF("a ", "%-05c", 'a');
+ EXPECT_PRINTF("a ", "%0-5c", 'a');
+ EXPECT_PRINTF("97 ", "%-05hhi", 'a');
+ EXPECT_PRINTF("97 ", "%0-5hhi", 'a');
+
+ // '-' and space flag don't interfere
+ EXPECT_PRINTF(" 42", "%- d", 42);
+}
+
+TEST(PrintfTest, SpaceFlag) {
+ EXPECT_PRINTF(" 42", "% d", 42);
+ EXPECT_PRINTF("-42", "% d", -42);
+ EXPECT_PRINTF(" 0042", "% 05d", 42);
+ EXPECT_PRINTF(" 0042", "%0 5d", 42);
+
+ // ' ' flag is ignored for non-numeric types.
+ EXPECT_PRINTF("x", "% c", 'x');
+}
+
+TEST(PrintfTest, HashFlag) {
+ EXPECT_PRINTF("042", "%#o", 042);
+ EXPECT_PRINTF(fmt::format("0{:o}", static_cast<unsigned>(-042)), "%#o", -042);
+ EXPECT_PRINTF("0", "%#o", 0);
+
+ EXPECT_PRINTF("0x42", "%#x", 0x42);
+ EXPECT_PRINTF("0X42", "%#X", 0x42);
+ EXPECT_PRINTF(fmt::format("0x{:x}", static_cast<unsigned>(-0x42)), "%#x",
+ -0x42);
+ EXPECT_PRINTF("0", "%#x", 0);
+
+ EXPECT_PRINTF("0x0042", "%#06x", 0x42);
+ EXPECT_PRINTF("0x0042", "%0##6x", 0x42);
+
+ EXPECT_PRINTF("-42.000000", "%#f", -42.0);
+ EXPECT_PRINTF("-42.000000", "%#F", -42.0);
+
+ char buffer[BUFFER_SIZE];
+ safe_sprintf(buffer, "%#e", -42.0);
+ EXPECT_PRINTF(buffer, "%#e", -42.0);
+ safe_sprintf(buffer, "%#E", -42.0);
+ EXPECT_PRINTF(buffer, "%#E", -42.0);
+
+ EXPECT_PRINTF("-42.0000", "%#g", -42.0);
+ EXPECT_PRINTF("-42.0000", "%#G", -42.0);
+
+ safe_sprintf(buffer, "%#a", 16.0);
+ EXPECT_PRINTF(buffer, "%#a", 16.0);
+ safe_sprintf(buffer, "%#A", 16.0);
+ EXPECT_PRINTF(buffer, "%#A", 16.0);
+
+ // '#' flag is ignored for non-numeric types.
+ EXPECT_PRINTF("x", "%#c", 'x');
+}
+
+TEST(PrintfTest, 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,
+ "number is too big");
+ EXPECT_THROW_MSG(test_sprintf(format("%1${}d", BIG_NUM), 42), format_error,
+ "number is too big");
+}
+
+TEST(PrintfTest, DynamicWidth) {
+ 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,
+ "number is too big");
+}
+
+TEST(PrintfTest, IntPrecision) {
+ EXPECT_PRINTF("00042", "%.5d", 42);
+ EXPECT_PRINTF("-00042", "%.5d", -42);
+ EXPECT_PRINTF("00042", "%.5x", 0x42);
+ EXPECT_PRINTF("0x00042", "%#.5x", 0x42);
+ EXPECT_PRINTF("00042", "%.5o", 042);
+ EXPECT_PRINTF("00042", "%#.5o", 042);
+
+ EXPECT_PRINTF(" 00042", "%7.5d", 42);
+ EXPECT_PRINTF(" 00042", "%7.5x", 0x42);
+ EXPECT_PRINTF(" 0x00042", "%#10.5x", 0x42);
+ EXPECT_PRINTF(" 00042", "%7.5o", 042);
+ EXPECT_PRINTF(" 00042", "%#10.5o", 042);
+
+ EXPECT_PRINTF("00042 ", "%-7.5d", 42);
+ EXPECT_PRINTF("00042 ", "%-7.5x", 0x42);
+ EXPECT_PRINTF("0x00042 ", "%-#10.5x", 0x42);
+ EXPECT_PRINTF("00042 ", "%-7.5o", 042);
+ EXPECT_PRINTF("00042 ", "%-#10.5o", 042);
+}
+
+TEST(PrintfTest, FloatPrecision) {
+ char buffer[BUFFER_SIZE];
+ safe_sprintf(buffer, "%.3e", 1234.5678);
+ EXPECT_PRINTF(buffer, "%.3e", 1234.5678);
+ EXPECT_PRINTF("1234.568", "%.3f", 1234.5678);
+ EXPECT_PRINTF("1.23e+03", "%.3g", 1234.5678);
+ safe_sprintf(buffer, "%.3a", 1234.5678);
+ EXPECT_PRINTF(buffer, "%.3a", 1234.5678);
+}
+
+TEST(PrintfTest, StringPrecision) {
+ char test[] = {'H', 'e', 'l', 'l', 'o'};
+ EXPECT_EQ(fmt::sprintf("%.4s", test), "Hell");
+}
+
+TEST(PrintfTest, IgnorePrecisionForNonNumericArg) {
+ EXPECT_PRINTF("abc", "%.5s", "abc");
+}
+
+TEST(PrintfTest, DynamicPrecision) {
+ 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,
+ "number is too big");
+ if (sizeof(long long) != sizeof(int)) {
+ long long prec = static_cast<long long>(INT_MIN) - 1;
+ EXPECT_THROW_MSG(test_sprintf("%.*d", prec, 42), format_error,
+ "number is too big");
+ }
+}
+
+template <typename T> struct make_signed { typedef T type; };
+
+#define SPECIALIZE_MAKE_SIGNED(T, S) \
+ template <> struct make_signed<T> { typedef S type; }
+
+SPECIALIZE_MAKE_SIGNED(char, signed char);
+SPECIALIZE_MAKE_SIGNED(unsigned char, signed char);
+SPECIALIZE_MAKE_SIGNED(unsigned short, short);
+SPECIALIZE_MAKE_SIGNED(unsigned, int);
+SPECIALIZE_MAKE_SIGNED(unsigned long, long);
+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) {
+ long long signed_value = 0;
+ unsigned long long unsigned_value = 0;
+ // Apply integer promotion to the argument.
+ unsigned long long max = max_value<U>();
+ using fmt::detail::const_check;
+ if (const_check(max <= static_cast<unsigned>(max_value<int>()))) {
+ signed_value = static_cast<int>(value);
+ unsigned_value = static_cast<unsigned long long>(value);
+ } else if (const_check(max <= max_value<unsigned>())) {
+ signed_value = static_cast<unsigned>(value);
+ unsigned_value = static_cast<unsigned long long>(value);
+ }
+ if (sizeof(U) <= sizeof(int) && sizeof(int) < sizeof(T)) {
+ signed_value = static_cast<long long>(value);
+ unsigned_value = static_cast<unsigned long long>(
+ static_cast<typename std::make_unsigned<unsigned>::type>(value));
+ } else {
+ signed_value = static_cast<typename make_signed<T>::type>(value);
+ unsigned_value = static_cast<typename std::make_unsigned<T>::type>(value);
+ }
+ std::ostringstream os;
+ os << signed_value;
+ EXPECT_PRINTF(os.str(), fmt::format("%{}d", length_spec), value);
+ EXPECT_PRINTF(os.str(), fmt::format("%{}i", length_spec), value);
+ os.str("");
+ os << unsigned_value;
+ EXPECT_PRINTF(os.str(), fmt::format("%{}u", length_spec), value);
+ os.str("");
+ os << std::oct << unsigned_value;
+ EXPECT_PRINTF(os.str(), fmt::format("%{}o", length_spec), value);
+ os.str("");
+ os << std::hex << unsigned_value;
+ EXPECT_PRINTF(os.str(), fmt::format("%{}x", length_spec), value);
+ os.str("");
+ os << std::hex << std::uppercase << unsigned_value;
+ EXPECT_PRINTF(os.str(), fmt::format("%{}X", length_spec), value);
+}
+
+template <typename T> void TestLength(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);
+ 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);
+ 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");
+ 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) {
+ EXPECT_PRINTF("1", "%d", true);
+ EXPECT_PRINTF("true", "%s", true);
+}
+
+TEST(PrintfTest, Int) {
+ EXPECT_PRINTF("-42", "%d", -42);
+ EXPECT_PRINTF("-42", "%i", -42);
+ unsigned u = 0 - 42u;
+ EXPECT_PRINTF(fmt::format("{}", u), "%u", -42);
+ EXPECT_PRINTF(fmt::format("{:o}", u), "%o", -42);
+ EXPECT_PRINTF(fmt::format("{:x}", u), "%x", -42);
+ EXPECT_PRINTF(fmt::format("{:X}", u), "%X", -42);
+}
+
+TEST(PrintfTest, 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) {
+ 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];
+ safe_sprintf(buffer, "%e", 392.65);
+ EXPECT_PRINTF(buffer, "%e", 392.65);
+ safe_sprintf(buffer, "%E", 392.65);
+ EXPECT_PRINTF(buffer, "%E", 392.65);
+ EXPECT_PRINTF("392.65", "%g", 392.65);
+ EXPECT_PRINTF("392.65", "%G", 392.65);
+ EXPECT_PRINTF("392", "%g", 392.0);
+ EXPECT_PRINTF("392", "%G", 392.0);
+ EXPECT_PRINTF("4.56e-07", "%g", 0.000000456);
+ safe_sprintf(buffer, "%a", -392.65);
+ EXPECT_EQ(buffer, format("{:a}", -392.65));
+ safe_sprintf(buffer, "%A", -392.65);
+ EXPECT_EQ(buffer, format("{:A}", -392.65));
+}
+
+TEST(PrintfTest, Inf) {
+ double inf = std::numeric_limits<double>::infinity();
+ for (const char* type = "fega"; *type; ++type) {
+ EXPECT_PRINTF("inf", fmt::format("%{}", *type), inf);
+ char upper = static_cast<char>(std::toupper(*type));
+ EXPECT_PRINTF("INF", fmt::format("%{}", upper), inf);
+ }
+}
+
+TEST(PrintfTest, Char) {
+ EXPECT_PRINTF("x", "%c", 'x');
+ int max = max_value<int>();
+ EXPECT_PRINTF(fmt::format("{}", static_cast<char>(max)), "%c", max);
+ // EXPECT_PRINTF("x", "%lc", L'x');
+ EXPECT_PRINTF(L"x", L"%c", L'x');
+ EXPECT_PRINTF(fmt::format(L"{}", static_cast<wchar_t>(max)), L"%c", max);
+}
+
+TEST(PrintfTest, String) {
+ EXPECT_PRINTF("abc", "%s", "abc");
+ const char* null_str = nullptr;
+ EXPECT_PRINTF("(null)", "%s", null_str);
+ EXPECT_PRINTF(" (null)", "%10s", null_str);
+ EXPECT_PRINTF(L"abc", L"%s", L"abc");
+ const wchar_t* null_wstr = nullptr;
+ EXPECT_PRINTF(L"(null)", L"%s", null_wstr);
+ 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) {
+ int n;
+ void* p = &n;
+ EXPECT_PRINTF(fmt::format("{}", p), "%p", p);
+ p = nullptr;
+ EXPECT_PRINTF("(nil)", "%p", p);
+ EXPECT_PRINTF(" (nil)", "%10p", p);
+ const char* s = "test";
+ EXPECT_PRINTF(fmt::format("{:p}", s), "%p", s);
+ const char* null_str = nullptr;
+ EXPECT_PRINTF("(nil)", "%p", null_str);
+
+ p = &n;
+ EXPECT_PRINTF(fmt::format(L"{}", p), L"%p", p);
+ p = nullptr;
+ EXPECT_PRINTF(L"(nil)", L"%p", p);
+ EXPECT_PRINTF(L" (nil)", L"%10p", p);
+ const wchar_t* w = L"test";
+ EXPECT_PRINTF(fmt::format(L"{:p}", w), L"%p", w);
+ const wchar_t* null_wstr = nullptr;
+ EXPECT_PRINTF(L"(nil)", L"%p", null_wstr);
+}
+
+TEST(PrintfTest, Location) {
+ // TODO: test %n
+}
+
+enum test_enum { answer = 42 };
+
+TEST(PrintfTest, 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) {
+ const char* weekday = "Thursday";
+ const char* month = "August";
+ int day = 21;
+ EXPECT_WRITE(stdout, fmt::printf("%1$s, %3$d %2$s", weekday, month, day),
+ "Thursday, 21 August");
+}
+
+TEST(PrintfTest, PrintfError) {
+ fmt::file read_end, write_end;
+ fmt::file::pipe(read_end, write_end);
+ int result = fmt::fprintf(read_end.fdopen("r").get(), "test");
+ EXPECT_LT(result, 0);
+}
+#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(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(PrintfTest, 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>
+void check_format_string_regression(fmt::string_view s, const Args&... args) {
+ fmt::sprintf(s, args...);
+}
+
+TEST(PrintfTest, CheckFormatStringRegression) {
+ check_format_string_regression("%c%s", 'x', "");
+}
+
+TEST(PrintfTest, FixedLargeExponent) {
+ EXPECT_EQ("1000000000000000000000", fmt::sprintf("%.*f", -13, 1e21));
+}
+
+TEST(PrintfTest, VSPrintfMakeArgsExample) {
+ fmt::format_arg_store<fmt::printf_context, int, const char*> as{42,
+ "something"};
+ fmt::basic_format_args<fmt::printf_context> args(as);
+ EXPECT_EQ("[42] something happened", fmt::vsprintf("[%d] %s happened", args));
+ auto as2 = fmt::make_printf_args(42, "something");
+ 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) {
+ fmt::format_arg_store<fmt::wprintf_context, int, const wchar_t*> as{
+ 42, L"something"};
+ fmt::basic_format_args<fmt::wprintf_context> args(as);
+ EXPECT_EQ(L"[42] something happened",
+ fmt::vsprintf(L"[%d] %s happened", args));
+ auto as2 = fmt::make_wprintf_args(42, L"something");
+ 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/printf-test/ya.make b/contrib/libs/fmt/test/printf-test/ya.make
new file mode 100644
index 0000000000..ec264a6c81
--- /dev/null
+++ b/contrib/libs/fmt/test/printf-test/ya.make
@@ -0,0 +1,37 @@
+# Generated by devtools/yamaker.
+
+GTEST()
+
+WITHOUT_LICENSE_TEXTS()
+
+OWNER(
+ orivej
+ g:cpp-contrib
+)
+
+LICENSE(MIT)
+
+PEERDIR(
+ contrib/libs/fmt
+ contrib/libs/fmt/test
+)
+
+NO_COMPILER_WARNINGS()
+
+NO_UTIL()
+
+CFLAGS(
+ -DFMT_LOCALE
+ -DFMT_SHARED
+ -DGTEST_HAS_STD_WSTRING=1
+ -DGTEST_LANG_CXX11=0
+ -D_SILENCE_TR1_NAMESPACE_DEPRECATION_WARNING=1
+)
+
+SRCDIR(contrib/libs/fmt/test)
+
+SRCS(
+ printf-test.cc
+)
+
+END()
diff --git a/contrib/libs/fmt/test/ranges-test.cc b/contrib/libs/fmt/test/ranges-test.cc
new file mode 100644
index 0000000000..394f7b81be
--- /dev/null
+++ b/contrib/libs/fmt/test/ranges-test.cc
@@ -0,0 +1,203 @@
+// Formatting library for C++ - the core API
+//
+// Copyright (c) 2012 - present, Victor Zverovich
+// All rights reserved.
+//
+// For the license information refer to format.h.
+//
+// Copyright (c) 2018 - present, Remotion (Igor Schulz)
+// All Rights Reserved
+// {fmt} support for ranges, containers and types tuple interface.
+
+#include "fmt/ranges.h"
+
+#include <gtest/gtest.h>
+
+// Check if 'if constexpr' is supported.
+#if (__cplusplus > 201402L) || \
+ (defined(_MSVC_LANG) && _MSVC_LANG > 201402L && _MSC_VER >= 1910)
+
+# include <array>
+# include <map>
+# include <string>
+# include <vector>
+
+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);
+}
+
+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);
+}
+
+TEST(RangesTest, FormatMap) {
+ std::map<std::string, int32_t> simap{{"one", 1}, {"two", 2}};
+ EXPECT_EQ("{(\"one\", 1), (\"two\", 2)}", fmt::format("{}", simap));
+}
+
+TEST(RangesTest, FormatPair) {
+ std::pair<int64_t, float> pa1{42, 1.5f};
+ EXPECT_EQ("(42, 1.5)", fmt::format("{}", pa1));
+}
+
+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(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, ", ")));
+
+ // Testing lvalue tuple args
+ int x = 4;
+ std::tuple<char, int&> t2{'b', x};
+ EXPECT_EQ("b + 4", fmt::format("{}", fmt::join(t2, " + ")));
+
+ // Empty tuple
+ std::tuple<> t3;
+ EXPECT_EQ("", fmt::format("{}", fmt::join(t3, "|")));
+
+ // Single element tuple
+ std::tuple<float> t4{4.0f};
+ EXPECT_EQ("4", fmt::format("{}", fmt::join(t4, "/")));
+}
+
+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", "!"}, " ")));
+}
+
+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};
+ }
+};
+
+template <size_t N> decltype(auto) get(const my_struct& s) noexcept {
+ return s.get<N>();
+}
+
+namespace std {
+
+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>());
+};
+
+} // namespace std
+
+TEST(RangesTest, FormatStruct) {
+ my_struct mst{13, "my struct"};
+ EXPECT_EQ("(13, \"my struct\")", fmt::format("{}", mst));
+}
+
+TEST(RangesTest, FormatTo) {
+ char buf[10];
+ auto end = fmt::format_to(buf, "{}", std::vector{1, 2, 3});
+ *end = '\0';
+ EXPECT_STREQ(buf, "{1, 2, 3}");
+}
+
+struct path_like {
+ const path_like* begin() const;
+ const path_like* end() const;
+
+ operator std::string() const;
+};
+
+TEST(RangesTest, PathLike) {
+ 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();
+ const char* end();
+ explicit operator fmt::string_view() const { return "foo"; }
+ explicit operator std::string_view() const { return "foo"; }
+};
+
+TEST(RangesTest, FormatStringLike) {
+ EXPECT_EQ("foo", fmt::format("{}", string_like()));
+}
+#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
+//
+// Some ranges (eg 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:
+ std::vector<T> vec;
+
+ public:
+ using const_iterator = typename ::std::vector<T>::const_iterator;
+
+ template <typename... Args>
+ explicit non_const_only_range(Args&&... args)
+ : vec(::std::forward<Args>(args)...) {}
+
+ const_iterator begin() { return vec.begin(); }
+ const_iterator end() { return vec.end(); }
+};
+
+TEST(RangesTest, JoinRange) {
+ 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), ",")));
+
+ 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), ",")));
+
+ const std::vector<int> z(3u, 0);
+ EXPECT_EQ("0,0,0", fmt::format("{}", fmt::join(z, ",")));
+}
+
+#if !FMT_MSC_VER || FMT_MSC_VER >= 1927
+struct unformattable {};
+
+TEST(RangesTest, UnformattableRange) {
+ EXPECT_FALSE((fmt::has_formatter<std::vector<unformattable>,
+ fmt::format_context>::value));
+}
+#endif
diff --git a/contrib/libs/fmt/test/ranges-test/ya.make b/contrib/libs/fmt/test/ranges-test/ya.make
new file mode 100644
index 0000000000..6856e12893
--- /dev/null
+++ b/contrib/libs/fmt/test/ranges-test/ya.make
@@ -0,0 +1,37 @@
+# Generated by devtools/yamaker.
+
+GTEST()
+
+WITHOUT_LICENSE_TEXTS()
+
+OWNER(
+ orivej
+ g:cpp-contrib
+)
+
+LICENSE(MIT)
+
+PEERDIR(
+ contrib/libs/fmt
+ contrib/libs/fmt/test
+)
+
+NO_COMPILER_WARNINGS()
+
+NO_UTIL()
+
+CFLAGS(
+ -DFMT_LOCALE
+ -DFMT_SHARED
+ -DGTEST_HAS_STD_WSTRING=1
+ -DGTEST_LANG_CXX11=0
+ -D_SILENCE_TR1_NAMESPACE_DEPRECATION_WARNING=1
+)
+
+SRCDIR(contrib/libs/fmt/test)
+
+SRCS(
+ ranges-test.cc
+)
+
+END()
diff --git a/contrib/libs/fmt/test/scan-test.cc b/contrib/libs/fmt/test/scan-test.cc
new file mode 100644
index 0000000000..90c0edef9b
--- /dev/null
+++ b/contrib/libs/fmt/test/scan-test.cc
@@ -0,0 +1,116 @@
+// Formatting library for C++ - scanning API test
+//
+// Copyright (c) 2019 - present, Victor Zverovich
+// All rights reserved.
+//
+// For the license information refer to format.h.
+
+#include "scan.h"
+
+#include <time.h>
+
+#include <climits>
+
+#include <gmock/gmock.h>
+#include "gtest-extra.h"
+
+TEST(ScanTest, ReadText) {
+ fmt::string_view s = "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;
+ fmt::scan("42", "{}", n);
+ EXPECT_EQ(n, 42);
+ fmt::scan("-42", "{}", n);
+ EXPECT_EQ(n, -42);
+}
+
+TEST(ScanTest, ReadLongLong) {
+ long long n = 0;
+ fmt::scan("42", "{}", n);
+ EXPECT_EQ(n, 42);
+ fmt::scan("-42", "{}", n);
+ EXPECT_EQ(n, -42);
+}
+
+TEST(ScanTest, ReadUInt) {
+ unsigned n = 0;
+ fmt::scan("42", "{}", n);
+ EXPECT_EQ(n, 42);
+ EXPECT_THROW_MSG(fmt::scan("-42", "{}", n), fmt::format_error,
+ "invalid input");
+}
+
+TEST(ScanTest, ReadULongLong) {
+ unsigned long long n = 0;
+ fmt::scan("42", "{}", n);
+ EXPECT_EQ(n, 42);
+ EXPECT_THROW_MSG(fmt::scan("-42", "{}", n), fmt::format_error,
+ "invalid input");
+}
+
+TEST(ScanTest, ReadString) {
+ std::string s;
+ fmt::scan("foo", "{}", s);
+ EXPECT_EQ(s, "foo");
+}
+
+TEST(ScanTest, ReadStringView) {
+ fmt::string_view s;
+ fmt::scan("foo", "{}", s);
+ EXPECT_EQ(s, "foo");
+}
+
+#ifndef _WIN32
+namespace fmt {
+template <> struct scanner<tm> {
+ std::string format;
+
+ scan_parse_context::iterator parse(scan_parse_context& ctx) {
+ auto it = ctx.begin();
+ if (it != ctx.end() && *it == ':') ++it;
+ auto end = it;
+ while (end != ctx.end() && *end != '}') ++end;
+ format.reserve(detail::to_unsigned(end - it + 1));
+ format.append(it, end);
+ format.push_back('\0');
+ return end;
+ }
+
+ template <class ScanContext>
+ typename ScanContext::iterator scan(tm& t, ScanContext& ctx) {
+ auto result = strptime(ctx.begin(), format.c_str(), &t);
+ if (!result) throw format_error("failed to parse time");
+ return result;
+ }
+};
+} // namespace fmt
+
+TEST(ScanTest, ReadCustom) {
+ const char* input = "Date: 1985-10-25";
+ auto t = tm();
+ fmt::scan(input, "Date: {0:%Y-%m-%d}", t);
+ EXPECT_EQ(t.tm_year, 85);
+ EXPECT_EQ(t.tm_mon, 9);
+ EXPECT_EQ(t.tm_mday, 25);
+}
+#endif
+
+TEST(ScanTest, InvalidFormat) {
+ 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;
+ fmt::scan("answer = 42", "{} = {}", key, value);
+ EXPECT_EQ(key, "answer");
+ EXPECT_EQ(value, 42);
+}
diff --git a/contrib/libs/fmt/test/scan-test/ya.make b/contrib/libs/fmt/test/scan-test/ya.make
new file mode 100644
index 0000000000..2a3a49bd9a
--- /dev/null
+++ b/contrib/libs/fmt/test/scan-test/ya.make
@@ -0,0 +1,37 @@
+# Generated by devtools/yamaker.
+
+GTEST()
+
+WITHOUT_LICENSE_TEXTS()
+
+OWNER(
+ orivej
+ g:cpp-contrib
+)
+
+LICENSE(MIT)
+
+PEERDIR(
+ contrib/libs/fmt
+ contrib/libs/fmt/test
+)
+
+NO_COMPILER_WARNINGS()
+
+NO_UTIL()
+
+CFLAGS(
+ -DFMT_LOCALE
+ -DFMT_SHARED
+ -DGTEST_HAS_STD_WSTRING=1
+ -DGTEST_LANG_CXX11=0
+ -D_SILENCE_TR1_NAMESPACE_DEPRECATION_WARNING=1
+)
+
+SRCDIR(contrib/libs/fmt/test)
+
+SRCS(
+ scan-test.cc
+)
+
+END()
diff --git a/contrib/libs/fmt/test/scan.h b/contrib/libs/fmt/test/scan.h
new file mode 100644
index 0000000000..de82067a49
--- /dev/null
+++ b/contrib/libs/fmt/test/scan.h
@@ -0,0 +1,238 @@
+// Formatting library for C++ - scanning API proof of concept
+//
+// Copyright (c) 2019 - present, Victor Zverovich
+// All rights reserved.
+//
+// For the license information refer to format.h.
+
+#include <array>
+#include <cassert>
+#include <climits>
+
+#include "fmt/format.h"
+
+FMT_BEGIN_NAMESPACE
+template <typename T, typename Char = char> struct scanner {
+ // A deleted default constructor indicates a disabled scanner.
+ scanner() = delete;
+};
+
+class scan_parse_context {
+ private:
+ string_view format_;
+
+ public:
+ using iterator = string_view::iterator;
+
+ explicit FMT_CONSTEXPR scan_parse_context(string_view format)
+ : format_(format) {}
+
+ FMT_CONSTEXPR iterator begin() const { return format_.begin(); }
+ FMT_CONSTEXPR iterator end() const { return format_.end(); }
+
+ void advance_to(iterator it) {
+ format_.remove_prefix(detail::to_unsigned(it - begin()));
+ }
+};
+
+struct scan_context {
+ private:
+ string_view input_;
+
+ public:
+ using iterator = const char*;
+
+ explicit scan_context(string_view input) : input_(input) {}
+
+ iterator begin() const { return input_.data(); }
+ iterator end() const { return begin() + input_.size(); }
+
+ void advance_to(iterator it) {
+ input_.remove_prefix(detail::to_unsigned(it - begin()));
+ }
+};
+
+namespace detail {
+enum class scan_type {
+ none_type,
+ int_type,
+ uint_type,
+ long_long_type,
+ ulong_long_type,
+ string_type,
+ string_view_type,
+ custom_type
+};
+
+struct custom_scan_arg {
+ void* value;
+ void (*scan)(void* arg, scan_parse_context& parse_ctx, scan_context& ctx);
+};
+
+class scan_arg {
+ public:
+ scan_type type;
+ union {
+ int* int_value;
+ unsigned* uint_value;
+ long long* long_long_value;
+ unsigned long long* ulong_long_value;
+ std::string* string;
+ fmt::string_view* string_view;
+ custom_scan_arg custom;
+ // TODO: more types
+ };
+
+ scan_arg() : type(scan_type::none_type) {}
+ scan_arg(int& value) : type(scan_type::int_type), int_value(&value) {}
+ scan_arg(unsigned& value) : type(scan_type::uint_type), uint_value(&value) {}
+ scan_arg(long long& value)
+ : type(scan_type::long_long_type), long_long_value(&value) {}
+ scan_arg(unsigned long long& value)
+ : type(scan_type::ulong_long_type), ulong_long_value(&value) {}
+ scan_arg(std::string& value) : type(scan_type::string_type), string(&value) {}
+ scan_arg(fmt::string_view& value)
+ : type(scan_type::string_view_type), string_view(&value) {}
+ template <typename T> scan_arg(T& value) : type(scan_type::custom_type) {
+ custom.value = &value;
+ custom.scan = scan_custom_arg<T>;
+ }
+
+ private:
+ template <typename T>
+ static void scan_custom_arg(void* arg, scan_parse_context& parse_ctx,
+ scan_context& ctx) {
+ scanner<T> s;
+ parse_ctx.advance_to(s.parse(parse_ctx));
+ ctx.advance_to(s.scan(*static_cast<T*>(arg), ctx));
+ }
+};
+} // namespace detail
+
+struct scan_args {
+ int size;
+ const detail::scan_arg* data;
+
+ template <size_t N>
+ scan_args(const std::array<detail::scan_arg, N>& store)
+ : size(N), data(store.data()) {
+ static_assert(N < INT_MAX, "too many arguments");
+ }
+};
+
+namespace detail {
+
+struct scan_handler : error_handler {
+ private:
+ scan_parse_context parse_ctx_;
+ scan_context scan_ctx_;
+ scan_args args_;
+ int next_arg_id_;
+ scan_arg arg_;
+
+ template <typename T = unsigned> T read_uint() {
+ T value = 0;
+ auto it = scan_ctx_.begin(), end = scan_ctx_.end();
+ while (it != end) {
+ char c = *it++;
+ if (c < '0' || c > '9') on_error("invalid input");
+ // TODO: check overflow
+ value = value * 10 + static_cast<unsigned>(c - '0');
+ }
+ scan_ctx_.advance_to(it);
+ return value;
+ }
+
+ template <typename T = int> T read_int() {
+ auto it = scan_ctx_.begin(), end = scan_ctx_.end();
+ bool negative = it != end && *it == '-';
+ if (negative) ++it;
+ scan_ctx_.advance_to(it);
+ const auto value = read_uint<typename std::make_unsigned<T>::type>();
+ if (negative) return -static_cast<T>(value);
+ return static_cast<T>(value);
+ }
+
+ public:
+ scan_handler(string_view format, string_view input, scan_args args)
+ : parse_ctx_(format), scan_ctx_(input), args_(args), next_arg_id_(0) {}
+
+ const char* pos() const { return scan_ctx_.begin(); }
+
+ void on_text(const char* begin, const char* end) {
+ auto size = to_unsigned(end - begin);
+ auto it = scan_ctx_.begin();
+ if (it + size > scan_ctx_.end() ||
+ !std::equal(begin, end, make_checked(it, size))) {
+ on_error("invalid input");
+ }
+ scan_ctx_.advance_to(it + size);
+ }
+
+ int on_arg_id() { return on_arg_id(next_arg_id_++); }
+ 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; }
+
+ void on_replacement_field(int, const char*) {
+ auto it = scan_ctx_.begin(), end = scan_ctx_.end();
+ switch (arg_.type) {
+ case scan_type::int_type:
+ *arg_.int_value = read_int();
+ break;
+ case scan_type::uint_type:
+ *arg_.uint_value = read_uint();
+ break;
+ case scan_type::long_long_type:
+ *arg_.long_long_value = read_int<long long>();
+ break;
+ case scan_type::ulong_long_type:
+ *arg_.ulong_long_value = read_uint<unsigned long long>();
+ break;
+ case scan_type::string_type:
+ while (it != end && *it != ' ') arg_.string->push_back(*it++);
+ scan_ctx_.advance_to(it);
+ break;
+ case scan_type::string_view_type: {
+ auto s = it;
+ while (it != end && *it != ' ') ++it;
+ *arg_.string_view = fmt::string_view(s, to_unsigned(it - s));
+ scan_ctx_.advance_to(it);
+ break;
+ }
+ case scan_type::none_type:
+ case scan_type::custom_type:
+ assert(false);
+ }
+ }
+
+ const char* on_format_specs(int, const char* begin, const char*) {
+ if (arg_.type != scan_type::custom_type) return begin;
+ parse_ctx_.advance_to(begin);
+ arg_.custom.scan(arg_.custom.value, parse_ctx_, scan_ctx_);
+ return parse_ctx_.begin();
+ }
+};
+} // namespace detail
+
+template <typename... Args>
+std::array<detail::scan_arg, sizeof...(Args)> make_scan_args(Args&... args) {
+ return {{args...}};
+}
+
+string_view::iterator vscan(string_view input, string_view format_str,
+ scan_args args) {
+ detail::scan_handler h(format_str, input, args);
+ detail::parse_format_string<false>(format_str, h);
+ return input.begin() + (h.pos() - &*input.begin());
+}
+
+template <typename... Args>
+string_view::iterator scan(string_view input, string_view format_str,
+ Args&... args) {
+ return vscan(input, format_str, make_scan_args(args...));
+}
+FMT_END_NAMESPACE
diff --git a/contrib/libs/fmt/test/test-assert.h b/contrib/libs/fmt/test/test-assert.h
new file mode 100644
index 0000000000..f9df580539
--- /dev/null
+++ b/contrib/libs/fmt/test/test-assert.h
@@ -0,0 +1,32 @@
+// Formatting library for C++ - test version of FMT_ASSERT
+//
+// Copyright (c) 2012 - present, Victor Zverovich
+// All rights reserved.
+//
+// For the license information refer to format.h.
+
+#ifndef FMT_TEST_ASSERT_H_
+#define FMT_TEST_ASSERT_H_
+
+#include <stdexcept>
+
+#include <gtest/gtest.h>
+
+class assertion_failure : public std::logic_error {
+ public:
+ explicit assertion_failure(const char* message) : std::logic_error(message) {}
+
+ private:
+ virtual void avoid_weak_vtable();
+};
+
+void assertion_failure::avoid_weak_vtable() {}
+
+#define FMT_ASSERT(condition, message) \
+ if (!(condition)) throw assertion_failure(message);
+
+// Expects an assertion failure.
+#define EXPECT_ASSERT(stmt, message) \
+ FMT_TEST_THROW_(stmt, assertion_failure, message, GTEST_NONFATAL_FAILURE_)
+
+#endif // FMT_TEST_ASSERT_H_
diff --git a/contrib/libs/fmt/test/util.cc b/contrib/libs/fmt/test/util.cc
new file mode 100644
index 0000000000..d08dcbdcbf
--- /dev/null
+++ b/contrib/libs/fmt/test/util.cc
@@ -0,0 +1,50 @@
+// Formatting library for C++ - test utilities
+//
+// Copyright (c) 2012 - present, Victor Zverovich
+// All rights reserved.
+//
+// For the license information refer to format.h.
+
+#include "util.h"
+
+#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!";
+
+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.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());
+ if (fp) *fp = f.get();
+#endif
+ return f;
+}
diff --git a/contrib/libs/fmt/test/util.h b/contrib/libs/fmt/test/util.h
new file mode 100644
index 0000000000..24a5f4e34b
--- /dev/null
+++ b/contrib/libs/fmt/test/util.h
@@ -0,0 +1,84 @@
+// Formatting library for C++ - test utilities
+//
+// Copyright (c) 2012 - present, Victor Zverovich
+// All rights reserved.
+//
+// For the license information refer to format.h.
+
+#include <cstdarg>
+#include <cstdio>
+#include <string>
+
+#include "fmt/os.h"
+
+enum { BUFFER_SIZE = 256 };
+
+#ifdef _MSC_VER
+# define FMT_VSNPRINTF vsprintf_s
+#else
+# define FMT_VSNPRINTF vsnprintf
+#endif
+
+template <size_t SIZE>
+void safe_sprintf(char (&buffer)[SIZE], const char* format, ...) {
+ std::va_list args;
+ va_start(args, format);
+ FMT_VSNPRINTF(buffer, SIZE, format, args);
+ 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;
+
+// Opens a buffered file for reading.
+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;
+ errno = fopen_s(&f, filename, mode);
+ return f;
+#else
+ return std::fopen(filename, mode);
+#endif
+}
+
+template <typename Char> class BasicTestString {
+ private:
+ std::basic_string<Char> value_;
+
+ static const Char EMPTY[];
+
+ public:
+ explicit BasicTestString(const Char* value = EMPTY) : value_(value) {}
+
+ const std::basic_string<Char>& value() const { return value_; }
+};
+
+template <typename Char> const Char BasicTestString<Char>::EMPTY[] = {0};
+
+typedef BasicTestString<char> TestString;
+typedef BasicTestString<wchar_t> TestWString;
+
+template <typename Char>
+std::basic_ostream<Char>& operator<<(std::basic_ostream<Char>& os,
+ const BasicTestString<Char>& s) {
+ os << s.value();
+ return os;
+}
+
+class Date {
+ int year_, month_, day_;
+
+ public:
+ 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_; }
+};
diff --git a/contrib/libs/fmt/test/ya.make b/contrib/libs/fmt/test/ya.make
new file mode 100644
index 0000000000..8db82d6c1e
--- /dev/null
+++ b/contrib/libs/fmt/test/ya.make
@@ -0,0 +1,55 @@
+# Generated by devtools/yamaker.
+
+LIBRARY()
+
+WITHOUT_LICENSE_TEXTS()
+
+OWNER(
+ orivej
+ g:cpp-contrib
+)
+
+LICENSE(MIT)
+
+PEERDIR(
+ contrib/libs/fmt
+ contrib/restricted/googletest/googlemock
+)
+
+NO_COMPILER_WARNINGS()
+
+NO_UTIL()
+
+CFLAGS(
+ -DFMT_LOCALE
+ -DFMT_SHARED
+ -DGTEST_HAS_STD_WSTRING=1
+ -DGTEST_LANG_CXX11=0
+ -D_SILENCE_TR1_NAMESPACE_DEPRECATION_WARNING=1
+)
+
+SRCS(
+ gtest-extra.cc
+ util.cc
+)
+
+END()
+
+RECURSE(
+ assert-test
+ chrono-test
+ color-test
+ compile-test
+ core-test
+ format-impl-test
+ format-test
+ gtest-extra-test
+ header-only-test
+ locale-test
+ os-test
+ ostream-test
+ posix-mock-test
+ printf-test
+ ranges-test
+ scan-test
+)