From 605d2600f8ca631ce06caa6a3ff16a49d695ad7c Mon Sep 17 00:00:00 2001 From: Victor Zverovich Date: Fri, 29 Aug 2014 07:45:55 -0700 Subject: [PATCH] Improve error reporting. --- format.cc | 48 ++++++++++++++++++++++----------------------- format.h | 14 +++++++++++-- test/format-test.cc | 37 +++++++++++++++++----------------- test/printf-test.cc | 10 +++++----- 4 files changed, 59 insertions(+), 50 deletions(-) diff --git a/format.cc b/format.cc index bf355910..97fe136d 100644 --- a/format.cc +++ b/format.cc @@ -760,28 +760,28 @@ inline const Arg &fmt::BasicFormatter::parse_arg_index(const Char *&s) { return *arg; } -const Arg *fmt::internal::FormatterBase::next_arg(const char *&error) { - if (next_arg_index_ < 0) { - error = "cannot switch from manual to automatic argument indexing"; - return 0; - } - unsigned arg_index = next_arg_index_++; +const Arg *fmt::internal::FormatterBase::do_get_arg( + unsigned arg_index, const char *&error) { if (arg_index < args_.size()) return &args_[arg_index]; - error = "argument index is out of range in format"; + error = "argument index out of range"; return 0; } -const Arg *fmt::internal::FormatterBase::get_arg( +inline const Arg *fmt::internal::FormatterBase::next_arg(const char *&error) { + if (next_arg_index_ >= 0) + return do_get_arg(next_arg_index_++, error); + error = "cannot switch from manual to automatic argument indexing"; + return 0; +} + +inline const Arg *fmt::internal::FormatterBase::get_arg( unsigned arg_index, const char *&error) { - if (next_arg_index_ > 0) { - error = "cannot switch from automatic to manual argument indexing"; - return 0; + if (next_arg_index_ <= 0) { + next_arg_index_ = -1; + return do_get_arg(arg_index, error); } - next_arg_index_ = -1; - if (arg_index < args_.size()) - return &args_[arg_index]; - error = "argument index is out of range in format"; + error = "cannot switch from automatic to manual argument indexing"; return 0; } @@ -862,8 +862,7 @@ void fmt::internal::PrintfFormatter::format( BasicWriter &writer, BasicStringRef format, const ArgList &args) { const Char *start = format.c_str(); - args_ = args; - next_arg_index_ = 0; + set_args(args); const Char *s = start; while (*s) { Char c = *s++; @@ -1118,12 +1117,12 @@ const Char *fmt::BasicFormatter::format( ++s; const Arg &precision_arg = parse_arg_index(s); if (*s++ != '}') - throw FormatError("unmatched '{' in format"); + throw FormatError("invalid format string"); ULongLong value = 0; switch (precision_arg.type) { case Arg::INT: if (precision_arg.int_value < 0) - throw FormatError("negative precision in format"); + throw FormatError("negative precision"); value = precision_arg.int_value; break; case Arg::UINT: @@ -1131,7 +1130,7 @@ const Char *fmt::BasicFormatter::format( break; case Arg::LONG_LONG: if (precision_arg.long_long_value < 0) - throw FormatError("negative precision in format"); + throw FormatError("negative precision"); value = precision_arg.long_long_value; break; case Arg::ULONG_LONG: @@ -1144,7 +1143,7 @@ const Char *fmt::BasicFormatter::format( throw FormatError("number is too big"); spec.precision_ = static_cast(value); } else { - throw FormatError("missing precision in format"); + throw FormatError("missing precision specifier"); } if (arg.type != Arg::DOUBLE && arg.type != Arg::LONG_DOUBLE) { throw FormatError( @@ -1158,7 +1157,7 @@ const Char *fmt::BasicFormatter::format( } if (*s++ != '}') - throw FormatError("unmatched '{' in format"); + throw FormatError("missing '}' in format string"); start_ = s; // Format argument. @@ -1170,8 +1169,7 @@ template void fmt::BasicFormatter::format( BasicStringRef format_str, const ArgList &args) { const Char *s = start_ = format_str.c_str(); - args_ = args; - next_arg_index_ = 0; + set_args(args); while (*s) { Char c = *s++; if (c != '{' && c != '}') continue; @@ -1181,7 +1179,7 @@ void fmt::BasicFormatter::format( continue; } if (c == '}') - throw FormatError("unmatched '}' in format"); + throw FormatError("unmatched '}' in format string"); write(writer_, start_, s - 1); Arg arg = parse_arg_index(s); s = format(s, arg); diff --git a/format.h b/format.h index ed681fb6..0f106973 100644 --- a/format.h +++ b/format.h @@ -842,14 +842,24 @@ struct FormatSpec; namespace internal { class FormatterBase { -protected: + private: ArgList args_; int next_arg_index_; + // Returns the argument with specified index. + const Arg *do_get_arg(unsigned arg_index, const char *&error); + + protected: + void set_args(const ArgList &args) { + args_ = args; + next_arg_index_ = 0; + } + // Returns the next argument. const Arg *next_arg(const char *&error); - // Returns the argument with specified index. + // Checks if manual indexing is used and returns the argument with + // specified index. const Arg *get_arg(unsigned arg_index, const char *&error); template diff --git a/test/format-test.cc b/test/format-test.cc index c434efdb..5be74ab3 100644 --- a/test/format-test.cc +++ b/test/format-test.cc @@ -586,7 +586,7 @@ TEST(FormatterTest, Escape) { TEST(FormatterTest, UnmatchedBraces) { EXPECT_THROW_MSG(format("{"), FormatError, "invalid format string"); - EXPECT_THROW_MSG(format("}"), FormatError, "unmatched '}' in format"); + EXPECT_THROW_MSG(format("}"), FormatError, "unmatched '}' in format string"); EXPECT_THROW_MSG(format("{0{}"), FormatError, "invalid format string"); } @@ -608,15 +608,14 @@ TEST(FormatterTest, ArgErrors) { EXPECT_THROW_MSG(format("{"), FormatError, "invalid format string"); EXPECT_THROW_MSG(format("{x}"), FormatError, "invalid format string"); EXPECT_THROW_MSG(format("{0"), FormatError, "invalid format string"); - EXPECT_THROW_MSG(format("{0}"), FormatError, - "argument index is out of range in format"); + EXPECT_THROW_MSG(format("{0}"), FormatError, "argument index out of range"); char format_str[BUFFER_SIZE]; safe_sprintf(format_str, "{%u", INT_MAX); EXPECT_THROW_MSG(format(format_str), FormatError, "invalid format string"); safe_sprintf(format_str, "{%u}", INT_MAX); EXPECT_THROW_MSG(format(format_str), FormatError, - "argument index is out of range in format"); + "argument index out of range"); safe_sprintf(format_str, "{%u", INT_MAX + 1u); EXPECT_THROW_MSG(format(format_str), FormatError, "number is too big"); @@ -635,8 +634,7 @@ TEST(FormatterTest, AutoArgIndex) { FormatError, "cannot switch from manual to automatic argument indexing"); EXPECT_THROW_MSG(format("{:.{0}}", 1.2345, 2), FormatError, "cannot switch from automatic to manual argument indexing"); - EXPECT_THROW_MSG(format("{}"), FormatError, - "argument index is out of range in format"); + EXPECT_THROW_MSG(format("{}"), FormatError, "argument index out of range"); } TEST(FormatterTest, EmptySpecs) { @@ -695,7 +693,7 @@ TEST(FormatterTest, NumericAlign) { EXPECT_EQ("- 42", format("{0:=5}", -42.0)); EXPECT_EQ("- 42", format("{0:=5}", -42.0l)); EXPECT_THROW_MSG(format("{0:=5", 'c'), - FormatError, "unmatched '{' in format"); + FormatError, "missing '}' in format string"); EXPECT_THROW_MSG(format("{0:=5}", 'c'), FormatError, "invalid format specifier for char"); EXPECT_THROW_MSG(format("{0:=5}", "abc"), @@ -759,7 +757,7 @@ TEST(FormatterTest, PlusSign) { EXPECT_EQ("+42", format("{0:+}", 42.0)); EXPECT_EQ("+42", format("{0:+}", 42.0l)); EXPECT_THROW_MSG(format("{0:+", 'c'), - FormatError, "unmatched '{' in format"); + FormatError, "missing '}' in format string"); EXPECT_THROW_MSG(format("{0:+}", 'c'), FormatError, "invalid format specifier for char"); EXPECT_THROW_MSG(format("{0:+}", "abc"), @@ -785,7 +783,7 @@ TEST(FormatterTest, MinusSign) { EXPECT_EQ("42", format("{0:-}", 42.0)); EXPECT_EQ("42", format("{0:-}", 42.0l)); EXPECT_THROW_MSG(format("{0:-", 'c'), - FormatError, "unmatched '{' in format"); + FormatError, "missing '}' in format string"); EXPECT_THROW_MSG(format("{0:-}", 'c'), FormatError, "invalid format specifier for char"); EXPECT_THROW_MSG(format("{0:-}", "abc"), @@ -811,7 +809,7 @@ TEST(FormatterTest, SpaceSign) { EXPECT_EQ(" 42", format("{0: }", 42.0)); EXPECT_EQ(" 42", format("{0: }", 42.0l)); EXPECT_THROW_MSG(format("{0: ", 'c'), - FormatError, "unmatched '{' in format"); + FormatError, "missing '}' in format string"); EXPECT_THROW_MSG(format("{0: }", 'c'), FormatError, "invalid format specifier for char"); EXPECT_THROW_MSG(format("{0: }", "abc"), @@ -858,7 +856,7 @@ TEST(FormatterTest, HashFlag) { EXPECT_EQ("-42.0000", format("{0:#}", -42.0)); EXPECT_EQ("-42.0000", format("{0:#}", -42.0l)); EXPECT_THROW_MSG(format("{0:#", 'c'), - FormatError, "unmatched '{' in format"); + FormatError, "missing '}' in format string"); EXPECT_THROW_MSG(format("{0:#}", 'c'), FormatError, "invalid format specifier for char"); EXPECT_THROW_MSG(format("{0:#}", "abc"), @@ -880,7 +878,7 @@ TEST(FormatterTest, ZeroFlag) { EXPECT_EQ("-0042", format("{0:05}", -42.0)); EXPECT_EQ("-0042", format("{0:05}", -42.0l)); EXPECT_THROW_MSG(format("{0:0", 'c'), - FormatError, "unmatched '{' in format"); + FormatError, "missing '}' in format string"); EXPECT_THROW_MSG(format("{0:05}", 'c'), FormatError, "invalid format specifier for char"); EXPECT_THROW_MSG(format("{0:05}", "abc"), @@ -935,9 +933,9 @@ TEST(FormatterTest, Precision) { EXPECT_THROW_MSG(format(format_str, 0), FormatError, "number is too big"); EXPECT_THROW_MSG(format("{0:.", 0), - FormatError, "missing precision in format"); + FormatError, "missing precision specifier"); EXPECT_THROW_MSG(format("{0:.}", 0), - FormatError, "missing precision in format"); + FormatError, "missing precision specifier"); EXPECT_THROW_MSG(format("{0:.2", 0), FormatError, "precision specifier requires floating-point argument"); @@ -1011,14 +1009,17 @@ TEST(FormatterTest, RuntimePrecision) { EXPECT_THROW_MSG(format("{0:.{1}", 0, 0), FormatError, "precision specifier requires floating-point argument"); EXPECT_THROW_MSG(format("{0:.{1}}", 0), - FormatError, "argument index is out of range in format"); + FormatError, "argument index out of range"); + + EXPECT_THROW_MSG(format("{0:.{0:}}", 0), + FormatError, "invalid format string"); EXPECT_THROW_MSG(format("{0:.{1}}", 0, -1), - FormatError, "negative precision in format"); + FormatError, "negative precision"); EXPECT_THROW_MSG(format("{0:.{1}}", 0, (INT_MAX + 1u)), FormatError, "number is too big"); EXPECT_THROW_MSG(format("{0:.{1}}", 0, -1l), - FormatError, "negative precision in format"); + FormatError, "negative precision"); if (sizeof(long) > sizeof(int)) { long value = INT_MAX; EXPECT_THROW_MSG(format("{0:.{1}}", 0, (value + 1)), @@ -1111,7 +1112,7 @@ TEST(FormatterTest, FormatShort) { TEST(FormatterTest, FormatInt) { EXPECT_THROW_MSG(format("{0:v", 42), - FormatError, "unmatched '{' in format"); + FormatError, "missing '}' in format string"); check_unknown_types(42, "bBdoxX", "integer"); } diff --git a/test/printf-test.cc b/test/printf-test.cc index 8c86ede8..8e65e00a 100644 --- a/test/printf-test.cc +++ b/test/printf-test.cc @@ -108,11 +108,11 @@ TEST(PrintfTest, SwitchArgIndexing) { TEST(PrintfTest, InvalidArgIndex) { EXPECT_THROW_MSG(fmt::sprintf("%0$d", 42), FormatError, - "argument index is out of range in format"); + "argument index out of range"); EXPECT_THROW_MSG(fmt::sprintf("%2$d", 42), FormatError, - "argument index is out of range in format"); + "argument index out of range"); EXPECT_THROW_MSG(fmt::sprintf(format("%{}$d", INT_MAX), 42), - FormatError, "argument index is out of range in format"); + FormatError, "argument index out of range"); EXPECT_THROW_MSG(fmt::sprintf("%2$", 42), FormatError, "invalid format string"); @@ -218,7 +218,7 @@ TEST(PrintfTest, DynamicWidth) { EXPECT_THROW_MSG(fmt::sprintf("%*d", 5.0, 42), FormatError, "width is not integer"); EXPECT_THROW_MSG(fmt::sprintf("%*d"), FormatError, - "argument index is out of range in format"); + "argument index out of range"); EXPECT_THROW_MSG(fmt::sprintf("%*d", BIG_NUM, 42), FormatError, "number is too big"); } @@ -265,7 +265,7 @@ TEST(PrintfTest, DynamicPrecision) { EXPECT_THROW_MSG(fmt::sprintf("%.*d", 5.0, 42), FormatError, "precision is not integer"); EXPECT_THROW_MSG(fmt::sprintf("%.*d"), FormatError, - "argument index is out of range in format"); + "argument index out of range"); EXPECT_THROW_MSG(fmt::sprintf("%.*d", BIG_NUM, 42), FormatError, "number is too big"); if (sizeof(fmt::LongLong) != sizeof(int)) {