1 // Formatting library for C++ - scanning API test
3 // Copyright (c) 2019 - present, Victor Zverovich
4 // All rights reserved.
6 // For the license information refer to format.h.
16 #include "gmock/gmock.h"
17 #include "gtest-extra.h"
19 TEST(scan_test
, read_text
) {
20 fmt::string_view s
= "foo";
21 auto end
= fmt::scan_to(s
, "foo");
22 EXPECT_EQ(end
, s
.end());
23 EXPECT_THROW_MSG(fmt::scan
<int>("fob", "foo"), fmt::format_error
,
27 TEST(scan_test
, read_int
) {
28 EXPECT_EQ(fmt::scan
<int>("42", "{}")->value(), 42);
29 EXPECT_EQ(fmt::scan
<int>("-42", "{}")->value(), -42);
30 EXPECT_EQ(fmt::scan
<int>("42", "{:}")->value(), 42);
31 EXPECT_THROW_MSG(fmt::scan
<int>(std::to_string(INT_MAX
+ 1u), "{}"),
32 fmt::format_error
, "number is too big");
35 TEST(scan_test
, read_long_long
) {
36 EXPECT_EQ(fmt::scan
<long long>("42", "{}")->value(), 42);
37 EXPECT_EQ(fmt::scan
<long long>("-42", "{}")->value(), -42);
40 TEST(scan_test
, read_uint
) {
41 EXPECT_EQ(fmt::scan
<unsigned>("42", "{}")->value(), 42);
42 EXPECT_THROW_MSG(fmt::scan
<unsigned>("-42", "{}"), fmt::format_error
,
46 TEST(scan_test
, read_ulong_long
) {
47 EXPECT_EQ(fmt::scan
<unsigned long long>("42", "{}")->value(), 42);
48 EXPECT_THROW_MSG(fmt::scan
<unsigned long long>("-42", "{}")->value(),
49 fmt::format_error
, "invalid input");
52 TEST(scan_test
, read_hex
) {
53 EXPECT_EQ(fmt::scan
<unsigned>("2a", "{:x}")->value(), 42);
54 auto num_digits
= std::numeric_limits
<unsigned>::digits
/ 4;
56 fmt::scan
<unsigned>(fmt::format("1{:0{}}", 0, num_digits
), "{:x}")
58 fmt::format_error
, "number is too big");
61 TEST(scan_test
, read_string
) {
62 EXPECT_EQ(fmt::scan
<std::string
>("foo", "{}")->value(), "foo");
65 TEST(scan_test
, read_string_view
) {
66 EXPECT_EQ(fmt::scan
<fmt::string_view
>("foo", "{}")->value(), "foo");
69 TEST(scan_test
, separator
) {
71 fmt::scan_to("10 20", "{} {}", n1
, n2
);
81 template <> struct scanner
<num
> {
84 auto parse(scan_parse_context
& ctx
) -> scan_parse_context::iterator
{
85 auto it
= ctx
.begin(), end
= ctx
.end();
86 if (it
!= end
&& *it
== 'x') {
90 if (it
!= end
&& *it
!= '}') report_error("invalid format");
94 template <class ScanContext
>
95 auto scan(num
& n
, ScanContext
& ctx
) const -> typename
ScanContext::iterator
{
96 return hex
? scan_to(ctx
, "{:x}", n
.value
) : scan_to(ctx
, "{}", n
.value
);
101 TEST(scan_test
, read_custom
) {
102 EXPECT_EQ(fmt::scan
<num
>("42", "{}")->value().value
, 42);
103 EXPECT_EQ(fmt::scan
<num
>("2a", "{:x}")->value().value
, 42);
106 TEST(scan_test
, invalid_format
) {
107 EXPECT_THROW_MSG(fmt::scan_to("", "{}"), fmt::format_error
,
108 "argument index out of range");
109 EXPECT_THROW_MSG(fmt::scan_to("", "{"), fmt::format_error
,
110 "invalid format string");
115 using fmt::scan_error
;
118 TEST(scan_test
, example
) {
119 // Example from https://wg21.link/p1729r3.
120 if (auto result
= std::scan
<std::string
, int>("answer = 42", "{} = {}")) {
121 auto range
= result
->range();
122 EXPECT_EQ(range
.begin(), range
.end());
123 EXPECT_EQ(result
->begin(), result
->end());
124 #ifdef __cpp_structured_bindings
125 const auto& [key
, value
] = result
->values();
126 EXPECT_EQ(key
, "answer");
127 EXPECT_EQ(value
, 42);
130 std::scan_error error
= result
.error();
136 TEST(scan_test
, end_of_input
) { fmt::scan
<int>("", "{}"); }
139 TEST(scan_test
, file
) {
140 auto pipe
= fmt::pipe();
142 fmt::string_view input
= "10 20";
143 pipe
.write_end
.write(input
.data(), input
.size());
144 pipe
.write_end
.close();
147 fmt::buffered_file f
= pipe
.read_end
.fdopen("r");
148 fmt::scan_to(f
.get(), "{} {}", n1
, n2
);
153 TEST(scan_test
, lock
) {
154 auto pipe
= fmt::pipe();
156 std::thread
producer([&]() {
157 fmt::string_view input
= "42 ";
158 for (int i
= 0; i
< 1000; ++i
)
159 pipe
.write_end
.write(input
.data(), input
.size());
160 pipe
.write_end
.close();
163 std::atomic
<int> count(0);
164 fmt::buffered_file f
= pipe
.read_end
.fdopen("r");
167 while (fmt::scan_to(f
.get(), "{}", value
)) {
169 pipe
.read_end
.close();
170 EXPECT_EQ(value
, 42);
176 std::thread
consumer1(fun
);
177 std::thread
consumer2(fun
);
182 EXPECT_EQ(count
, 1000);
184 #endif // FMT_USE_FCNTL