diff --git a/test/scan-test.cc b/test/scan-test.cc index 29387a06..e3efba7b 100644 --- a/test/scan-test.cc +++ b/test/scan-test.cc @@ -10,27 +10,18 @@ #include "fmt/format.h" #include "gmock.h" +#include "gtest-extra.h" -namespace fmt { +FMT_BEGIN_NAMESPACE +namespace internal { struct scan_arg { - int& value; + int* value; // TODO: more types }; -struct scan_args { - int size; - const scan_arg* data; - - template - scan_args(const std::array& store) - : size(N), data(store.data()) { - static_assert(N < INT_MAX, "too many arguments"); - } -}; - template -void parse_scan_format(string_view format_str, Handler& handler) { +void parse_scan_format(string_view format_str, Handler&& handler) { const char* p = format_str.data(); const char* end = p + format_str.size(); while (p != end) { @@ -40,48 +31,70 @@ void parse_scan_format(string_view format_str, Handler& handler) { handler.on_arg(); } } +} // namespace internal + +struct scan_args { + int size; + const internal::scan_arg* data; + + template + scan_args(const std::array& store) + : size(N), data(store.data()) { + static_assert(N < INT_MAX, "too many arguments"); + } +}; + +namespace internal { +struct scan_handler { + const char* begin; + const char* end; + scan_args args; + int next_arg_id; + + scan_handler(string_view input, scan_args args) + : begin(input.data()), + end(begin + input.size()), + args(args), + next_arg_id(0) {} + + void on_arg() { + int value = 0; + while (begin != end) { + char c = *begin++; + if (c < '0' || c > '9') throw format_error("invalid input"); + value = value * 10 + (c - '0'); + } + if (next_arg_id >= args.size) + throw format_error("argument index out of range"); + *args.data[0].value = value; + } +}; +} // namespace internal void vscan(string_view input, string_view format_str, scan_args args) { - struct handler { - const char* begin; - const char* end; - scan_args args; - int next_arg_id; - - handler(string_view input, scan_args args) - : begin(input.data()), - end(begin + input.size()), - args(args), - next_arg_id(0) {} - - void on_arg() { - int value = 0; - while (begin != end) { - char c = *begin++; - if (c < '0' || c > '9') throw format_error("invalid input"); - value = value * 10 + (c - '0'); - } - if (next_arg_id >= args.size) - throw format_error("argument index out of range"); - args.data[0].value = value; - } - } h(input, args); - parse_scan_format(format_str, h); + internal::parse_scan_format(format_str, internal::scan_handler(input, args)); } template -std::array make_scan_args(Args&... args) { - return {args...}; +std::array make_scan_args(Args&... args) { + return std::array{&args...}; } template void scan(string_view input, string_view format_str, Args&... args) { vscan(input, format_str, make_scan_args(args...)); } -} // namespace fmt +FMT_END_NAMESPACE TEST(ScanTest, ReadInt) { int n = 0; fmt::scan("42", "{}", n); EXPECT_EQ(n, 42); } + +TEST(ScanTest, InvalidFormat) { + EXPECT_THROW_MSG(fmt::scan("", "{}"), fmt::format_error, + "argument index out of range"); + EXPECT_THROW_MSG(fmt::scan("", "{"), fmt::format_error, + "invalid format string"); +}