forked from fmtlib/fmt
More tests
This commit is contained in:
@@ -1708,6 +1708,9 @@ typedef basic_format_specs<char> format_specs;
|
|||||||
namespace internal {
|
namespace internal {
|
||||||
|
|
||||||
struct error_handler {
|
struct error_handler {
|
||||||
|
constexpr error_handler() {}
|
||||||
|
constexpr error_handler(const error_handler &) {}
|
||||||
|
|
||||||
// This function is intentionally not constexpr to give a compile-time error.
|
// This function is intentionally not constexpr to give a compile-time error.
|
||||||
void on_error(const char *message) {
|
void on_error(const char *message) {
|
||||||
FMT_THROW(format_error(message));
|
FMT_THROW(format_error(message));
|
||||||
@@ -1944,8 +1947,8 @@ class arg_formatter_base {
|
|||||||
|
|
||||||
// Parsing context representing a format string range being parsed and an
|
// Parsing context representing a format string range being parsed and an
|
||||||
// argument counter for automatic indexing.
|
// argument counter for automatic indexing.
|
||||||
template <typename Char>
|
template <typename Char, typename ErrorHandler = error_handler>
|
||||||
class parse_context {
|
class parse_context : public ErrorHandler {
|
||||||
private:
|
private:
|
||||||
basic_string_view<Char> format_str_;
|
basic_string_view<Char> format_str_;
|
||||||
int next_arg_index_;
|
int next_arg_index_;
|
||||||
@@ -1964,8 +1967,9 @@ class parse_context {
|
|||||||
using char_type = Char;
|
using char_type = Char;
|
||||||
using iterator = const Char*;
|
using iterator = const Char*;
|
||||||
|
|
||||||
explicit constexpr parse_context(basic_string_view<Char> format_str)
|
explicit constexpr parse_context(
|
||||||
: format_str_(format_str), next_arg_index_(0) {}
|
basic_string_view<Char> format_str, ErrorHandler eh = ErrorHandler())
|
||||||
|
: ErrorHandler(eh), format_str_(format_str), next_arg_index_(0) {}
|
||||||
|
|
||||||
// Returns an iterator to the beginning of the format string range being
|
// Returns an iterator to the beginning of the format string range being
|
||||||
// parsed.
|
// parsed.
|
||||||
@@ -2140,7 +2144,7 @@ class precision_checker {
|
|||||||
|
|
||||||
// A format specifier handler that sets fields in basic_format_specs.
|
// A format specifier handler that sets fields in basic_format_specs.
|
||||||
template <typename Char>
|
template <typename Char>
|
||||||
class specs_setter : public error_handler {
|
class specs_setter {
|
||||||
public:
|
public:
|
||||||
explicit constexpr specs_setter(basic_format_specs<Char> &specs):
|
explicit constexpr specs_setter(basic_format_specs<Char> &specs):
|
||||||
specs_(specs) {}
|
specs_(specs) {}
|
||||||
@@ -2278,6 +2282,10 @@ class specs_handler: public specs_setter<typename Context::char_type> {
|
|||||||
this->specs_.precision_, get_arg(arg_id));
|
this->specs_.precision_, get_arg(arg_id));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void on_error(const char *message) {
|
||||||
|
context_.on_error(message);
|
||||||
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
constexpr basic_arg<Context> get_arg(auto_id) {
|
constexpr basic_arg<Context> get_arg(auto_id) {
|
||||||
return context_.next_arg();
|
return context_.next_arg();
|
||||||
@@ -2349,6 +2357,10 @@ class dynamic_specs_handler :
|
|||||||
specs_.precision_ref = make_arg_ref(arg_id);
|
specs_.precision_ref = make_arg_ref(arg_id);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
constexpr void on_error(const char *message) {
|
||||||
|
context_.on_error(message);
|
||||||
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
using arg_ref_type = arg_ref<char_type>;
|
using arg_ref_type = arg_ref<char_type>;
|
||||||
|
|
||||||
@@ -2593,9 +2605,10 @@ constexpr void parse_format_string(Iterator it, Handler &&handler) {
|
|||||||
handler.on_text(start, it);
|
handler.on_text(start, it);
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename Char, typename T>
|
template <typename T, typename ParseContext>
|
||||||
constexpr const Char *parse_format_specs(parse_context<Char> &ctx) {
|
constexpr const typename ParseContext::char_type *
|
||||||
formatter<T, Char> f;
|
parse_format_specs(ParseContext &ctx) {
|
||||||
|
formatter<T, typename ParseContext::char_type> f;
|
||||||
return f.parse(ctx);
|
return f.parse(ctx);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2620,11 +2633,12 @@ class format_string_checker : public ErrorHandler {
|
|||||||
constexpr void on_replacement_field(const Char *) {}
|
constexpr void on_replacement_field(const Char *) {}
|
||||||
|
|
||||||
constexpr const Char *on_format_specs(const Char *s) {
|
constexpr const Char *on_format_specs(const Char *s) {
|
||||||
parse_context<Char> ctx(basic_string_view<Char>(s, end_ - s));
|
parse_context_type ctx(basic_string_view<Char>(s, end_ - s), *this);
|
||||||
return parse_funcs_[arg_index_](ctx);
|
return parse_funcs_[arg_index_](ctx);
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
using parse_context_type = parse_context<Char, ErrorHandler>;
|
||||||
constexpr static size_t NUM_ARGS = sizeof...(Args);
|
constexpr static size_t NUM_ARGS = sizeof...(Args);
|
||||||
|
|
||||||
constexpr void check_arg_index() {
|
constexpr void check_arg_index() {
|
||||||
@@ -2633,12 +2647,12 @@ class format_string_checker : public ErrorHandler {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Format specifier parsing function.
|
// Format specifier parsing function.
|
||||||
using parse_func = const Char *(*)(parse_context<Char> &);
|
using parse_func = const Char *(*)(parse_context_type &);
|
||||||
|
|
||||||
const Char *end_;
|
const Char *end_;
|
||||||
int arg_index_ = -1;
|
int arg_index_ = -1;
|
||||||
parse_func parse_funcs_[NUM_ARGS > 0 ? NUM_ARGS : 1] = {
|
parse_func parse_funcs_[NUM_ARGS > 0 ? NUM_ARGS : 1] = {
|
||||||
&parse_format_specs<Char, Args>...
|
&parse_format_specs<Args, parse_context_type>...
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -3184,7 +3198,7 @@ void basic_writer<Char>::write_int(T value, const Spec& spec) {
|
|||||||
char prefix[4] = "";
|
char prefix[4] = "";
|
||||||
|
|
||||||
spec_handler(basic_writer<Char> &w, T value, const Spec& s)
|
spec_handler(basic_writer<Char> &w, T value, const Spec& s)
|
||||||
: writer(w), abs_value(static_cast<UnsignedType>(value)), spec(s) {
|
: writer(w), spec(s), abs_value(static_cast<UnsignedType>(value)) {
|
||||||
if (internal::is_negative(value)) {
|
if (internal::is_negative(value)) {
|
||||||
prefix[0] = '-';
|
prefix[0] = '-';
|
||||||
++prefix_size;
|
++prefix_size;
|
||||||
|
@@ -1703,6 +1703,8 @@ struct test_context {
|
|||||||
constexpr void check_arg_id(Id) {}
|
constexpr void check_arg_id(Id) {}
|
||||||
|
|
||||||
constexpr unsigned next_arg_index(const char *&) { return 33; }
|
constexpr unsigned next_arg_index(const char *&) { return 33; }
|
||||||
|
|
||||||
|
void on_error(const char *) {}
|
||||||
};
|
};
|
||||||
|
|
||||||
constexpr fmt::format_specs parse_specs(const char *s) {
|
constexpr fmt::format_specs parse_specs(const char *s) {
|
||||||
@@ -1867,9 +1869,11 @@ TEST(FormatTest, FormatStringErrors) {
|
|||||||
#ifndef _MSC_VER
|
#ifndef _MSC_VER
|
||||||
// This causes an internal compiler error in MSVC2017.
|
// This causes an internal compiler error in MSVC2017.
|
||||||
EXPECT_ERROR("{0:=5", "unknown format specifier", char);
|
EXPECT_ERROR("{0:=5", "unknown format specifier", char);
|
||||||
|
EXPECT_ERROR("{:{<}", "invalid fill character '{'", int);
|
||||||
#endif
|
#endif
|
||||||
EXPECT_ERROR("{foo", "missing '}' in format string", int);
|
EXPECT_ERROR("{foo", "missing '}' in format string", int);
|
||||||
EXPECT_ERROR("{10000000000}", "number is too big");
|
EXPECT_ERROR("{10000000000}", "number is too big");
|
||||||
EXPECT_ERROR("{0x}", "invalid format string");
|
EXPECT_ERROR("{0x}", "invalid format string");
|
||||||
EXPECT_ERROR("{-}", "invalid format string");
|
EXPECT_ERROR("{-}", "invalid format string");
|
||||||
|
EXPECT_ERROR("{1}", "argument index out of range", int);
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user