1*5c90c05cSAndroid Build Coastguard Worker // Formatting library for C++ - scanning API test
2*5c90c05cSAndroid Build Coastguard Worker //
3*5c90c05cSAndroid Build Coastguard Worker // Copyright (c) 2019 - present, Victor Zverovich
4*5c90c05cSAndroid Build Coastguard Worker // All rights reserved.
5*5c90c05cSAndroid Build Coastguard Worker //
6*5c90c05cSAndroid Build Coastguard Worker // For the license information refer to format.h.
7*5c90c05cSAndroid Build Coastguard Worker
8*5c90c05cSAndroid Build Coastguard Worker #include "scan.h"
9*5c90c05cSAndroid Build Coastguard Worker
10*5c90c05cSAndroid Build Coastguard Worker #include <time.h>
11*5c90c05cSAndroid Build Coastguard Worker
12*5c90c05cSAndroid Build Coastguard Worker #include <climits>
13*5c90c05cSAndroid Build Coastguard Worker #include <thread>
14*5c90c05cSAndroid Build Coastguard Worker
15*5c90c05cSAndroid Build Coastguard Worker #include "fmt/os.h"
16*5c90c05cSAndroid Build Coastguard Worker #include "gmock/gmock.h"
17*5c90c05cSAndroid Build Coastguard Worker #include "gtest-extra.h"
18*5c90c05cSAndroid Build Coastguard Worker
TEST(scan_test,read_text)19*5c90c05cSAndroid Build Coastguard Worker TEST(scan_test, read_text) {
20*5c90c05cSAndroid Build Coastguard Worker fmt::string_view s = "foo";
21*5c90c05cSAndroid Build Coastguard Worker auto end = fmt::scan_to(s, "foo");
22*5c90c05cSAndroid Build Coastguard Worker EXPECT_EQ(end, s.end());
23*5c90c05cSAndroid Build Coastguard Worker EXPECT_THROW_MSG(fmt::scan<int>("fob", "foo"), fmt::format_error,
24*5c90c05cSAndroid Build Coastguard Worker "invalid input");
25*5c90c05cSAndroid Build Coastguard Worker }
26*5c90c05cSAndroid Build Coastguard Worker
TEST(scan_test,read_int)27*5c90c05cSAndroid Build Coastguard Worker TEST(scan_test, read_int) {
28*5c90c05cSAndroid Build Coastguard Worker EXPECT_EQ(fmt::scan<int>("42", "{}")->value(), 42);
29*5c90c05cSAndroid Build Coastguard Worker EXPECT_EQ(fmt::scan<int>("-42", "{}")->value(), -42);
30*5c90c05cSAndroid Build Coastguard Worker EXPECT_EQ(fmt::scan<int>("42", "{:}")->value(), 42);
31*5c90c05cSAndroid Build Coastguard Worker EXPECT_THROW_MSG(fmt::scan<int>(std::to_string(INT_MAX + 1u), "{}"),
32*5c90c05cSAndroid Build Coastguard Worker fmt::format_error, "number is too big");
33*5c90c05cSAndroid Build Coastguard Worker }
34*5c90c05cSAndroid Build Coastguard Worker
TEST(scan_test,read_long_long)35*5c90c05cSAndroid Build Coastguard Worker TEST(scan_test, read_long_long) {
36*5c90c05cSAndroid Build Coastguard Worker EXPECT_EQ(fmt::scan<long long>("42", "{}")->value(), 42);
37*5c90c05cSAndroid Build Coastguard Worker EXPECT_EQ(fmt::scan<long long>("-42", "{}")->value(), -42);
38*5c90c05cSAndroid Build Coastguard Worker }
39*5c90c05cSAndroid Build Coastguard Worker
TEST(scan_test,read_uint)40*5c90c05cSAndroid Build Coastguard Worker TEST(scan_test, read_uint) {
41*5c90c05cSAndroid Build Coastguard Worker EXPECT_EQ(fmt::scan<unsigned>("42", "{}")->value(), 42);
42*5c90c05cSAndroid Build Coastguard Worker EXPECT_THROW_MSG(fmt::scan<unsigned>("-42", "{}"), fmt::format_error,
43*5c90c05cSAndroid Build Coastguard Worker "invalid input");
44*5c90c05cSAndroid Build Coastguard Worker }
45*5c90c05cSAndroid Build Coastguard Worker
TEST(scan_test,read_ulong_long)46*5c90c05cSAndroid Build Coastguard Worker TEST(scan_test, read_ulong_long) {
47*5c90c05cSAndroid Build Coastguard Worker EXPECT_EQ(fmt::scan<unsigned long long>("42", "{}")->value(), 42);
48*5c90c05cSAndroid Build Coastguard Worker EXPECT_THROW_MSG(fmt::scan<unsigned long long>("-42", "{}")->value(),
49*5c90c05cSAndroid Build Coastguard Worker fmt::format_error, "invalid input");
50*5c90c05cSAndroid Build Coastguard Worker }
51*5c90c05cSAndroid Build Coastguard Worker
TEST(scan_test,read_hex)52*5c90c05cSAndroid Build Coastguard Worker TEST(scan_test, read_hex) {
53*5c90c05cSAndroid Build Coastguard Worker EXPECT_EQ(fmt::scan<unsigned>("2a", "{:x}")->value(), 42);
54*5c90c05cSAndroid Build Coastguard Worker auto num_digits = std::numeric_limits<unsigned>::digits / 4;
55*5c90c05cSAndroid Build Coastguard Worker EXPECT_THROW_MSG(
56*5c90c05cSAndroid Build Coastguard Worker fmt::scan<unsigned>(fmt::format("1{:0{}}", 0, num_digits), "{:x}")
57*5c90c05cSAndroid Build Coastguard Worker ->value(),
58*5c90c05cSAndroid Build Coastguard Worker fmt::format_error, "number is too big");
59*5c90c05cSAndroid Build Coastguard Worker }
60*5c90c05cSAndroid Build Coastguard Worker
TEST(scan_test,read_string)61*5c90c05cSAndroid Build Coastguard Worker TEST(scan_test, read_string) {
62*5c90c05cSAndroid Build Coastguard Worker EXPECT_EQ(fmt::scan<std::string>("foo", "{}")->value(), "foo");
63*5c90c05cSAndroid Build Coastguard Worker }
64*5c90c05cSAndroid Build Coastguard Worker
TEST(scan_test,read_string_view)65*5c90c05cSAndroid Build Coastguard Worker TEST(scan_test, read_string_view) {
66*5c90c05cSAndroid Build Coastguard Worker EXPECT_EQ(fmt::scan<fmt::string_view>("foo", "{}")->value(), "foo");
67*5c90c05cSAndroid Build Coastguard Worker }
68*5c90c05cSAndroid Build Coastguard Worker
TEST(scan_test,separator)69*5c90c05cSAndroid Build Coastguard Worker TEST(scan_test, separator) {
70*5c90c05cSAndroid Build Coastguard Worker int n1 = 0, n2 = 0;
71*5c90c05cSAndroid Build Coastguard Worker fmt::scan_to("10 20", "{} {}", n1, n2);
72*5c90c05cSAndroid Build Coastguard Worker EXPECT_EQ(n1, 10);
73*5c90c05cSAndroid Build Coastguard Worker EXPECT_EQ(n2, 20);
74*5c90c05cSAndroid Build Coastguard Worker }
75*5c90c05cSAndroid Build Coastguard Worker
76*5c90c05cSAndroid Build Coastguard Worker struct num {
77*5c90c05cSAndroid Build Coastguard Worker int value;
78*5c90c05cSAndroid Build Coastguard Worker };
79*5c90c05cSAndroid Build Coastguard Worker
80*5c90c05cSAndroid Build Coastguard Worker namespace fmt {
81*5c90c05cSAndroid Build Coastguard Worker template <> struct scanner<num> {
82*5c90c05cSAndroid Build Coastguard Worker bool hex = false;
83*5c90c05cSAndroid Build Coastguard Worker
parsefmt::scanner84*5c90c05cSAndroid Build Coastguard Worker auto parse(scan_parse_context& ctx) -> scan_parse_context::iterator {
85*5c90c05cSAndroid Build Coastguard Worker auto it = ctx.begin(), end = ctx.end();
86*5c90c05cSAndroid Build Coastguard Worker if (it != end && *it == 'x') {
87*5c90c05cSAndroid Build Coastguard Worker hex = true;
88*5c90c05cSAndroid Build Coastguard Worker ++it;
89*5c90c05cSAndroid Build Coastguard Worker }
90*5c90c05cSAndroid Build Coastguard Worker if (it != end && *it != '}') report_error("invalid format");
91*5c90c05cSAndroid Build Coastguard Worker return it;
92*5c90c05cSAndroid Build Coastguard Worker }
93*5c90c05cSAndroid Build Coastguard Worker
94*5c90c05cSAndroid Build Coastguard Worker template <class ScanContext>
scanfmt::scanner95*5c90c05cSAndroid Build Coastguard Worker auto scan(num& n, ScanContext& ctx) const -> typename ScanContext::iterator {
96*5c90c05cSAndroid Build Coastguard Worker return hex ? scan_to(ctx, "{:x}", n.value) : scan_to(ctx, "{}", n.value);
97*5c90c05cSAndroid Build Coastguard Worker }
98*5c90c05cSAndroid Build Coastguard Worker };
99*5c90c05cSAndroid Build Coastguard Worker } // namespace fmt
100*5c90c05cSAndroid Build Coastguard Worker
TEST(scan_test,read_custom)101*5c90c05cSAndroid Build Coastguard Worker TEST(scan_test, read_custom) {
102*5c90c05cSAndroid Build Coastguard Worker EXPECT_EQ(fmt::scan<num>("42", "{}")->value().value, 42);
103*5c90c05cSAndroid Build Coastguard Worker EXPECT_EQ(fmt::scan<num>("2a", "{:x}")->value().value, 42);
104*5c90c05cSAndroid Build Coastguard Worker }
105*5c90c05cSAndroid Build Coastguard Worker
TEST(scan_test,invalid_format)106*5c90c05cSAndroid Build Coastguard Worker TEST(scan_test, invalid_format) {
107*5c90c05cSAndroid Build Coastguard Worker EXPECT_THROW_MSG(fmt::scan_to("", "{}"), fmt::format_error,
108*5c90c05cSAndroid Build Coastguard Worker "argument index out of range");
109*5c90c05cSAndroid Build Coastguard Worker EXPECT_THROW_MSG(fmt::scan_to("", "{"), fmt::format_error,
110*5c90c05cSAndroid Build Coastguard Worker "invalid format string");
111*5c90c05cSAndroid Build Coastguard Worker }
112*5c90c05cSAndroid Build Coastguard Worker
113*5c90c05cSAndroid Build Coastguard Worker namespace std {
114*5c90c05cSAndroid Build Coastguard Worker using fmt::scan;
115*5c90c05cSAndroid Build Coastguard Worker using fmt::scan_error;
116*5c90c05cSAndroid Build Coastguard Worker } // namespace std
117*5c90c05cSAndroid Build Coastguard Worker
TEST(scan_test,example)118*5c90c05cSAndroid Build Coastguard Worker TEST(scan_test, example) {
119*5c90c05cSAndroid Build Coastguard Worker // Example from https://wg21.link/p1729r3.
120*5c90c05cSAndroid Build Coastguard Worker if (auto result = std::scan<std::string, int>("answer = 42", "{} = {}")) {
121*5c90c05cSAndroid Build Coastguard Worker auto range = result->range();
122*5c90c05cSAndroid Build Coastguard Worker EXPECT_EQ(range.begin(), range.end());
123*5c90c05cSAndroid Build Coastguard Worker EXPECT_EQ(result->begin(), result->end());
124*5c90c05cSAndroid Build Coastguard Worker #ifdef __cpp_structured_bindings
125*5c90c05cSAndroid Build Coastguard Worker const auto& [key, value] = result->values();
126*5c90c05cSAndroid Build Coastguard Worker EXPECT_EQ(key, "answer");
127*5c90c05cSAndroid Build Coastguard Worker EXPECT_EQ(value, 42);
128*5c90c05cSAndroid Build Coastguard Worker #endif
129*5c90c05cSAndroid Build Coastguard Worker } else {
130*5c90c05cSAndroid Build Coastguard Worker std::scan_error error = result.error();
131*5c90c05cSAndroid Build Coastguard Worker (void)error;
132*5c90c05cSAndroid Build Coastguard Worker FAIL();
133*5c90c05cSAndroid Build Coastguard Worker }
134*5c90c05cSAndroid Build Coastguard Worker }
135*5c90c05cSAndroid Build Coastguard Worker
TEST(scan_test,end_of_input)136*5c90c05cSAndroid Build Coastguard Worker TEST(scan_test, end_of_input) { fmt::scan<int>("", "{}"); }
137*5c90c05cSAndroid Build Coastguard Worker
138*5c90c05cSAndroid Build Coastguard Worker #if FMT_USE_FCNTL
TEST(scan_test,file)139*5c90c05cSAndroid Build Coastguard Worker TEST(scan_test, file) {
140*5c90c05cSAndroid Build Coastguard Worker auto pipe = fmt::pipe();
141*5c90c05cSAndroid Build Coastguard Worker
142*5c90c05cSAndroid Build Coastguard Worker fmt::string_view input = "10 20";
143*5c90c05cSAndroid Build Coastguard Worker pipe.write_end.write(input.data(), input.size());
144*5c90c05cSAndroid Build Coastguard Worker pipe.write_end.close();
145*5c90c05cSAndroid Build Coastguard Worker
146*5c90c05cSAndroid Build Coastguard Worker int n1 = 0, n2 = 0;
147*5c90c05cSAndroid Build Coastguard Worker fmt::buffered_file f = pipe.read_end.fdopen("r");
148*5c90c05cSAndroid Build Coastguard Worker fmt::scan_to(f.get(), "{} {}", n1, n2);
149*5c90c05cSAndroid Build Coastguard Worker EXPECT_EQ(n1, 10);
150*5c90c05cSAndroid Build Coastguard Worker EXPECT_EQ(n2, 20);
151*5c90c05cSAndroid Build Coastguard Worker }
152*5c90c05cSAndroid Build Coastguard Worker
TEST(scan_test,lock)153*5c90c05cSAndroid Build Coastguard Worker TEST(scan_test, lock) {
154*5c90c05cSAndroid Build Coastguard Worker auto pipe = fmt::pipe();
155*5c90c05cSAndroid Build Coastguard Worker
156*5c90c05cSAndroid Build Coastguard Worker std::thread producer([&]() {
157*5c90c05cSAndroid Build Coastguard Worker fmt::string_view input = "42 ";
158*5c90c05cSAndroid Build Coastguard Worker for (int i = 0; i < 1000; ++i)
159*5c90c05cSAndroid Build Coastguard Worker pipe.write_end.write(input.data(), input.size());
160*5c90c05cSAndroid Build Coastguard Worker pipe.write_end.close();
161*5c90c05cSAndroid Build Coastguard Worker });
162*5c90c05cSAndroid Build Coastguard Worker
163*5c90c05cSAndroid Build Coastguard Worker std::atomic<int> count(0);
164*5c90c05cSAndroid Build Coastguard Worker fmt::buffered_file f = pipe.read_end.fdopen("r");
165*5c90c05cSAndroid Build Coastguard Worker auto fun = [&]() {
166*5c90c05cSAndroid Build Coastguard Worker int value = 0;
167*5c90c05cSAndroid Build Coastguard Worker while (fmt::scan_to(f.get(), "{}", value)) {
168*5c90c05cSAndroid Build Coastguard Worker if (value != 42) {
169*5c90c05cSAndroid Build Coastguard Worker pipe.read_end.close();
170*5c90c05cSAndroid Build Coastguard Worker EXPECT_EQ(value, 42);
171*5c90c05cSAndroid Build Coastguard Worker break;
172*5c90c05cSAndroid Build Coastguard Worker }
173*5c90c05cSAndroid Build Coastguard Worker ++count;
174*5c90c05cSAndroid Build Coastguard Worker }
175*5c90c05cSAndroid Build Coastguard Worker };
176*5c90c05cSAndroid Build Coastguard Worker std::thread consumer1(fun);
177*5c90c05cSAndroid Build Coastguard Worker std::thread consumer2(fun);
178*5c90c05cSAndroid Build Coastguard Worker
179*5c90c05cSAndroid Build Coastguard Worker producer.join();
180*5c90c05cSAndroid Build Coastguard Worker consumer1.join();
181*5c90c05cSAndroid Build Coastguard Worker consumer2.join();
182*5c90c05cSAndroid Build Coastguard Worker EXPECT_EQ(count, 1000);
183*5c90c05cSAndroid Build Coastguard Worker }
184*5c90c05cSAndroid Build Coastguard Worker #endif // FMT_USE_FCNTL
185