More tests

This commit is contained in:
Victor Zverovich 2017-11-19 06:35:23 -08:00
parent 093e2a4780
commit 5a32e64b05
5 changed files with 44 additions and 43 deletions

View File

@ -407,7 +407,7 @@ class basic_string_view {
constexpr iterator begin() const { return data_; }
constexpr iterator end() const { return data_ + size_; }
void remove_prefix(size_t n) {
constexpr void remove_prefix(size_t n) {
data_ += n;
size_ -= n;
}
@ -460,7 +460,7 @@ namespace internal {
// Casts nonnegative integer to unsigned.
template <typename Int>
inline typename std::make_unsigned<Int>::type to_unsigned(Int value) {
constexpr typename std::make_unsigned<Int>::type to_unsigned(Int value) {
FMT_ASSERT(value >= 0, "negative value");
return static_cast<typename std::make_unsigned<Int>::type>(value);
}
@ -1956,9 +1956,9 @@ class parse_context : public ErrorHandler {
int next_arg_index_;
protected:
bool check_no_auto_index(const char *&error) {
constexpr bool check_no_auto_index() {
if (next_arg_index_ > 0) {
error = "cannot switch from automatic to manual argument indexing";
on_error("cannot switch from automatic to manual argument indexing");
return false;
}
next_arg_index_ = -1;
@ -1981,26 +1981,25 @@ class parse_context : public ErrorHandler {
constexpr iterator end() const { return format_str_.end(); }
// Advances the begin iterator to ``it``.
void advance_to(iterator it) {
constexpr void advance_to(iterator it) {
format_str_.remove_prefix(it - begin());
}
// Returns the next argument index.
unsigned next_arg_index(const char *&error) {
constexpr unsigned next_arg_index() {
if (next_arg_index_ >= 0)
return internal::to_unsigned(next_arg_index_++);
error = "cannot switch from manual to automatic argument indexing";
on_error("cannot switch from manual to automatic argument indexing");
return 0;
}
void check_arg_id(unsigned) {
const char *error = 0;
if (!check_no_auto_index(error))
FMT_THROW(format_error(error));
}
constexpr void check_arg_id(unsigned) { check_no_auto_index(); }
void check_arg_id(basic_string_view<Char>) {}
constexpr void on_error(const char *message) {
ErrorHandler::on_error(message);
}
constexpr ErrorHandler error_handler() const { return *this; }
};
@ -2029,7 +2028,7 @@ class context_base : public parse_context<Char>{
// Checks if manual indexing is used and returns the argument with
// specified index.
format_arg get_arg(unsigned arg_index, const char *&error) {
return this->check_no_auto_index(error) ?
return this->check_no_auto_index() ?
this->do_get_arg(arg_index, error) : format_arg();
}
@ -2365,11 +2364,7 @@ class dynamic_specs_handler :
}
constexpr arg_ref_type make_arg_ref(auto_id) {
const char *error = 0;
auto index = context_.next_arg_index(error);
if (error)
FMT_THROW(format_error(error));
return arg_ref_type(index);
return arg_ref_type(context_.next_arg_index());
}
dynamic_format_specs<char_type> &specs_;
@ -2607,19 +2602,21 @@ constexpr const typename ParseContext::char_type *
}
template <typename Char, typename ErrorHandler, typename... Args>
class format_string_checker : public ErrorHandler {
class format_string_checker {
public:
explicit constexpr format_string_checker(ErrorHandler eh, const Char *end)
: ErrorHandler(eh), end_(end) {}
explicit constexpr format_string_checker(
basic_string_view<Char> format_str, ErrorHandler eh)
: context_(format_str, eh) {}
constexpr void on_text(const Char *, const Char *) {}
constexpr void on_arg_id() {
++arg_index_;
arg_index_ = context_.next_arg_index();
check_arg_index();
}
constexpr void on_arg_id(unsigned index) {
arg_index_ = index;
context_.check_arg_id(index);
check_arg_index();
}
constexpr void on_arg_id(basic_string_view<Char>) {}
@ -2627,8 +2624,13 @@ class format_string_checker : public ErrorHandler {
constexpr void on_replacement_field(const Char *) {}
constexpr const Char *on_format_specs(const Char *s) {
parse_context_type ctx(basic_string_view<Char>(s, end_ - s), *this);
return arg_index_ < NUM_ARGS ? parse_funcs_[arg_index_](ctx) : s;
context_.advance_to(s);
return to_unsigned(arg_index_) < NUM_ARGS ?
parse_funcs_[arg_index_](context_) : s;
}
constexpr void on_error(const char *message) {
context_.on_error(message);
}
private:
@ -2636,16 +2638,15 @@ class format_string_checker : public ErrorHandler {
constexpr static size_t NUM_ARGS = sizeof...(Args);
constexpr void check_arg_index() {
unsigned unsigned_index = arg_index_;
if (arg_index_ < 0 || unsigned_index >= NUM_ARGS)
this->on_error("argument index out of range");
if (internal::to_unsigned(arg_index_) >= NUM_ARGS)
context_.on_error("argument index out of range");
}
// Format specifier parsing function.
using parse_func = const Char *(*)(parse_context_type &);
const Char *end_;
int arg_index_ = -1;
parse_context_type context_;
parse_func parse_funcs_[NUM_ARGS > 0 ? NUM_ARGS : 1] = {
&parse_format_specs<Args, parse_context_type>...
};
@ -2654,7 +2655,7 @@ class format_string_checker : public ErrorHandler {
template <typename Char, typename ErrorHandler, typename... Args>
constexpr bool check_format_string(
basic_string_view<Char> s, ErrorHandler eh = ErrorHandler()) {
format_string_checker<Char, ErrorHandler, Args...> checker(eh, s.end());
format_string_checker<Char, ErrorHandler, Args...> checker(s, eh);
parse_format_string(s.begin(), checker);
return true;
}
@ -2751,7 +2752,7 @@ class basic_context :
format_arg next_arg() {
const char *error = 0;
format_arg arg = this->do_get_arg(this->next_arg_index(error), error);
format_arg arg = this->do_get_arg(this->next_arg_index(), error);
if (error)
FMT_THROW(format_error(error));
return arg;
@ -3861,15 +3862,12 @@ struct dynamic_formatter {
template <typename Char>
inline typename basic_context<Char>::format_arg
basic_context<Char>::get_arg(basic_string_view<Char> name) {
const char *error = 0;
if (this->check_no_auto_index(error)) {
if (this->check_no_auto_index()) {
map_.init(this->args());
if (const format_arg *arg = map_.find(name))
return *arg;
error = "argument not found";
this->on_error("argument not found");
}
if (error)
FMT_THROW(format_error(error));
return format_arg();
}
@ -3881,8 +3879,8 @@ void vformat_to(basic_buffer<Char> &buffer, basic_string_view<Char> format_str,
struct handler : internal::error_handler {
handler(basic_buffer<Char> &b, basic_string_view<Char> str,
basic_args<Context> args)
: buffer(b), context(str, args) {}
basic_args<Context> format_args)
: buffer(b), context(str, format_args) {}
void on_text(iterator begin, iterator end) {
buffer.append(pointer_from(begin), pointer_from(end));

View File

@ -370,7 +370,7 @@ typename printf_context<Char, AF>::format_arg printf_context<Char, AF>::get_arg(
const char *error = 0;
format_arg arg;
if (arg_index == std::numeric_limits<unsigned>::max()) {
arg_index = this->next_arg_index(error);
arg_index = this->next_arg_index();
if (!error)
arg = this->do_get_arg(arg_index, error);
} else {

View File

@ -32,7 +32,7 @@ struct formatter<std::tm> {
return pointer_from(end);
}
void format(buffer &buf, const std::tm &tm, context &ctx) {
void format(buffer &buf, const std::tm &tm, context &) {
std::size_t start = buf.size();
for (;;) {
std::size_t size = buf.capacity() - start;

View File

@ -1702,7 +1702,7 @@ struct test_context {
template <typename Id>
constexpr void check_arg_id(Id) {}
constexpr unsigned next_arg_index(const char *&) { return 33; }
constexpr unsigned next_arg_index() { return 33; }
void on_error(const char *) {}
@ -1903,4 +1903,7 @@ TEST(FormatTest, FormatStringErrors) {
EXPECT_ERROR("{:.x}", "missing precision specifier", int);
EXPECT_ERROR("{}", "argument index out of range");
EXPECT_ERROR("{1}", "argument index out of range", int);
EXPECT_ERROR("{1}{}",
"cannot switch from manual to automatic argument indexing",
int, int);
}

View File

@ -87,14 +87,14 @@ TEST(PrintfTest, NumberIsTooBigInArgIndex) {
TEST(PrintfTest, SwitchArgIndexing) {
EXPECT_THROW_MSG(fmt::sprintf("%1$d%", 1, 2),
format_error, "invalid format string");
format_error, "cannot switch from manual to automatic argument indexing");
EXPECT_THROW_MSG(fmt::sprintf(format("%1$d%{}d", BIG_NUM), 1, 2),
format_error, "number is too big");
EXPECT_THROW_MSG(fmt::sprintf("%1$d%d", 1, 2),
format_error, "cannot switch from manual to automatic argument indexing");
EXPECT_THROW_MSG(fmt::sprintf("%d%1$", 1, 2),
format_error, "invalid format string");
format_error, "cannot switch from automatic to manual argument indexing");
EXPECT_THROW_MSG(fmt::sprintf(format("%d%{}$d", BIG_NUM), 1, 2),
format_error, "number is too big");
EXPECT_THROW_MSG(fmt::sprintf("%d%1$d", 1, 2),