prepare tests, fix incorrect handling of named args with simple {} replacement fields

This commit is contained in:
Alexey Ochapov 2021-02-16 07:04:52 +03:00 committed by Victor Zverovich
parent b31bc2dc9f
commit 78c67157c1
2 changed files with 45 additions and 16 deletions

View File

@ -454,10 +454,15 @@ template <typename Char, typename T, int N> struct field {
template <typename OutputIt, typename... Args>
constexpr OutputIt format(OutputIt out, const Args&... args) const {
if constexpr (is_named_arg<typename std::remove_cv<T>::type>::value) {
decltype(T::value) arg = get<N>(args...).value;
return write<Char>(out, arg);
} else {
// This ensures that the argument type is convertile to `const T&`.
const T& arg = get<N>(args...);
return write<Char>(out, arg);
}
}
};
template <typename Char, typename T, int N>
@ -775,8 +780,15 @@ FMT_INLINE std::basic_string<typename S::char_type> format(const S&,
#ifdef __cpp_if_constexpr
if constexpr (std::is_same<typename S::char_type, char>::value) {
constexpr basic_string_view<typename S::char_type> str = S();
if constexpr (str.size() == 2 && str[0] == '{' && str[1] == '}')
return fmt::to_string(detail::first(args...));
if constexpr (str.size() == 2 && str[0] == '{' && str[1] == '}') {
auto first = detail::first(args...);
if constexpr (detail::is_named_arg<typename std::remove_cv<
decltype(first)>::type>::value) {
return fmt::to_string(first.value);
} else {
return fmt::to_string(first);
}
}
}
#endif
constexpr auto compiled = detail::compile<Args...>(S());

View File

@ -255,17 +255,34 @@ TEST(CompileTest, ManualOrdering) {
}
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_EQ("42", fmt::format(FMT_COMPILE("{}"), fmt::arg("arg", 42)));
EXPECT_EQ("41 43", fmt::format(FMT_COMPILE("{} {}"), fmt::arg("arg", 41),
fmt::arg("arg", 43)));
EXPECT_EQ("foobar",
fmt::format(FMT_COMPILE("{a0}{a1}"), fmt::arg("a0", "foo"),
fmt::arg("a1", "bar")));
EXPECT_EQ("foobar",
fmt::format(/*FMT_COMPILE(*/ "{}{a1}" /*)*/, fmt::arg("a0", "foo"),
fmt::arg("a1", "bar")));
EXPECT_EQ("foofoo",
fmt::format(/*FMT_COMPILE(*/ "{a0}{}" /*)*/, fmt::arg("a0", "foo"),
fmt::arg("a1", "bar")));
EXPECT_EQ("foobar",
fmt::format(/*FMT_COMPILE(*/ "{a0}{1}" /*)*/, fmt::arg("a0", "foo"),
fmt::arg("a1", "bar")));
EXPECT_EQ("foobar",
fmt::format(/*FMT_COMPILE(*/ "{0}{a1}" /*)*/, fmt::arg("a0", "foo"),
fmt::arg("a1", "bar")));
EXPECT_EQ("foobar",
fmt::format(FMT_COMPILE("{}{a1}"), "foo", fmt::arg("a1", "bar")));
EXPECT_EQ("foobar",
fmt::format(FMT_COMPILE("{a0}{a1}"), fmt::arg("a1", "bar"),
fmt::arg("a2", "baz"), fmt::arg("a0", "foo")));
EXPECT_EQ(" bar foo ",
fmt::format(FMT_COMPILE(" {foo} {bar} "), fmt::arg("foo", "bar"),
fmt::arg("bar", "foo")));
EXPECT_THROW(fmt::format(FMT_COMPILE("{invalid}"), fmt::arg("valid", 42)),
fmt::format_error);