add support for manual indexing and named fields, add tests

This commit is contained in:
Alexey Ochapov
2021-02-07 23:43:52 +03:00
committed by Victor Zverovich
parent 7e72673d87
commit 95e1aa2dc5
2 changed files with 245 additions and 16 deletions

View File

@ -139,13 +139,136 @@ TEST(CompileTest, FormatWideString) {
EXPECT_EQ(L"42", fmt::format(FMT_COMPILE(L"{}"), 42));
}
struct test_custom_formattable {};
FMT_BEGIN_NAMESPACE
template <> struct formatter<test_custom_formattable> {
enum class output_type { two, four } type{output_type::two};
FMT_CONSTEXPR auto parse(format_parse_context& ctx) -> decltype(ctx.begin()) {
auto it = ctx.begin(), end = ctx.end();
while (it != end && *it != '}') {
++it;
}
auto spec = string_view(ctx.begin(), static_cast<size_t>(it - ctx.begin()));
auto tag = string_view("custom");
if (spec.size() == tag.size()) {
bool is_same = true;
for (size_t index = 0; index < spec.size(); ++index) {
if (spec[index] != tag[index]) {
is_same = false;
break;
}
}
type = is_same ? output_type::four : output_type::two;
} else {
type = output_type::two;
}
return it;
}
template <typename FormatContext>
auto format(const test_custom_formattable&, FormatContext& ctx) const
-> decltype(ctx.out()) {
return format_to(ctx.out(), type == output_type::two ? "{:>2}" : "{:>4}",
42);
}
};
FMT_END_NAMESPACE
TEST(CompileTest, FormatSpecs) {
EXPECT_EQ("42", fmt::format(FMT_COMPILE("{:x}"), 0x42));
EXPECT_EQ("42", fmt::format(FMT_COMPILE("{}"), test_custom_formattable()));
EXPECT_EQ(" 42",
fmt::format(FMT_COMPILE("{:custom}"), test_custom_formattable()));
}
TEST(CompileTest, DynamicWidth) {
struct test_dynamic_formattable {};
FMT_BEGIN_NAMESPACE
template <> struct formatter<test_dynamic_formattable> {
size_t amount = 0;
detail::arg_ref<char> width_refs[3];
FMT_CONSTEXPR auto parse(format_parse_context& ctx) -> decltype(ctx.begin()) {
amount = static_cast<size_t>(*ctx.begin() - '0');
if (amount >= 1) {
width_refs[0] = detail::arg_ref<char>(ctx.next_arg_id());
}
if (amount >= 2) {
width_refs[1] = detail::arg_ref<char>(ctx.next_arg_id());
}
if (amount >= 3) {
width_refs[2] = detail::arg_ref<char>(ctx.next_arg_id());
}
return ctx.begin() + 1;
}
template <typename FormatContext>
auto format(const test_dynamic_formattable&, FormatContext& ctx) const
-> decltype(ctx.out()) {
int widths[3]{};
for (size_t i = 0; i < amount; ++i) {
detail::handle_dynamic_spec<detail::width_checker>(widths[i],
width_refs[i], ctx);
}
if (amount == 1) {
return format_to(ctx.out(), "{:{}}", 41, widths[0]);
} else if (amount == 2) {
return format_to(ctx.out(), "{:{}}{:{}}", 41, widths[0], 42, widths[1]);
} else if (amount == 3) {
return format_to(ctx.out(), "{:{}}{:{}}{:{}}", 41, widths[0], 42,
widths[1], 43, widths[2]);
} else {
throw format_error("formatting error");
}
}
};
FMT_END_NAMESPACE
TEST(CompileTest, DynamicFormatSpecs) {
EXPECT_EQ(" 42foo ",
fmt::format(FMT_COMPILE("{:{}}{:{}}"), 42, 4, "foo", 5));
EXPECT_EQ(" 41",
fmt::format(FMT_COMPILE("{:1}"), test_dynamic_formattable(), 4));
EXPECT_EQ(" 41 42",
fmt::format(FMT_COMPILE("{:2}"), test_dynamic_formattable(), 3, 5));
EXPECT_EQ(" 41 42 43", fmt::format(FMT_COMPILE("{:3}"),
test_dynamic_formattable(), 5, 3, 4));
}
TEST(CompileTest, ManualOrdering) {
EXPECT_EQ("42", fmt::format(FMT_COMPILE("{0}"), 42));
EXPECT_EQ(" -42", fmt::format(FMT_COMPILE("{0:4}"), -42));
EXPECT_EQ("41 43", fmt::format(FMT_COMPILE("{0} {1}"), 41, 43));
EXPECT_EQ("41 43", fmt::format(FMT_COMPILE("{1} {0}"), 43, 41));
EXPECT_EQ("41 43", fmt::format(FMT_COMPILE("{0} {2}"), 41, 42, 43));
EXPECT_EQ(" 41 43", fmt::format(FMT_COMPILE("{1:{2}} {0:4}"), 43, 41, 4));
EXPECT_EQ("42 42",
fmt::format(FMT_COMPILE("{1} {0:custom}"),
test_custom_formattable(), test_custom_formattable()));
EXPECT_EQ(
"true 42 42 foo 0x1234 foo",
fmt::format(FMT_COMPILE("{0} {1} {2} {3} {4} {5}"), true, 42, 42.0f,
"foo", reinterpret_cast<void*>(0x1234), test_formattable()));
EXPECT_EQ(L"42", fmt::format(FMT_COMPILE(L"{0}"), 42));
}
TEST(CompileTest, Named) {
EXPECT_EQ("41 43", fmt::format(FMT_COMPILE("{name1} {name2}"),
fmt::arg("name1", 41), fmt::arg("name2", 43)));
EXPECT_EQ("41 43",
fmt::format(FMT_COMPILE("{} {name2}"), 41, fmt::arg("name2", 43)));
EXPECT_EQ("41 43",
fmt::format(FMT_COMPILE("{name1} {}"), fmt::arg("name1", 41), 43));
EXPECT_EQ("41 43",
fmt::format(FMT_COMPILE("{name1} {name2}"), fmt::arg("name1", 41),
fmt::arg("name2", 43), fmt::arg("name3", 42)));
EXPECT_EQ("41 43", fmt::format(FMT_COMPILE("{name2} {name1}"),
fmt::arg("name1", 43), fmt::arg("name2", 41)));
EXPECT_THROW(fmt::format(FMT_COMPILE("{invalid}"), fmt::arg("valid", 42)),
fmt::format_error);
}
TEST(CompileTest, FormatTo) {
@ -174,9 +297,7 @@ TEST(CompileTest, TextAndArg) {
EXPECT_EQ("42!", fmt::format(FMT_COMPILE("{}!"), 42));
}
TEST(CompileTest, Empty) {
EXPECT_EQ("", fmt::format(FMT_COMPILE("")));
}
TEST(CompileTest, Empty) { EXPECT_EQ("", fmt::format(FMT_COMPILE(""))); }
#endif
#if FMT_USE_NONTYPE_TEMPLATE_PARAMETERS