More tests

This commit is contained in:
Victor Zverovich
2017-11-12 19:14:35 -08:00
parent dfdb1adea5
commit f2b52bba05
2 changed files with 30 additions and 12 deletions

View File

@@ -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;

View File

@@ -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);
} }