1*890232f2SAndroid Build Coastguard Worker /*
2*890232f2SAndroid Build Coastguard Worker * Copyright 2014 Google Inc. All rights reserved.
3*890232f2SAndroid Build Coastguard Worker *
4*890232f2SAndroid Build Coastguard Worker * Licensed under the Apache License, Version 2.0 (the "License");
5*890232f2SAndroid Build Coastguard Worker * you may not use this file except in compliance with the License.
6*890232f2SAndroid Build Coastguard Worker * You may obtain a copy of the License at
7*890232f2SAndroid Build Coastguard Worker *
8*890232f2SAndroid Build Coastguard Worker * http://www.apache.org/licenses/LICENSE-2.0
9*890232f2SAndroid Build Coastguard Worker *
10*890232f2SAndroid Build Coastguard Worker * Unless required by applicable law or agreed to in writing, software
11*890232f2SAndroid Build Coastguard Worker * distributed under the License is distributed on an "AS IS" BASIS,
12*890232f2SAndroid Build Coastguard Worker * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13*890232f2SAndroid Build Coastguard Worker * See the License for the specific language governing permissions and
14*890232f2SAndroid Build Coastguard Worker * limitations under the License.
15*890232f2SAndroid Build Coastguard Worker */
16*890232f2SAndroid Build Coastguard Worker
17*890232f2SAndroid Build Coastguard Worker #include <assert.h>
18*890232f2SAndroid Build Coastguard Worker #include <stddef.h>
19*890232f2SAndroid Build Coastguard Worker #include <stdint.h>
20*890232f2SAndroid Build Coastguard Worker
21*890232f2SAndroid Build Coastguard Worker #include <algorithm>
22*890232f2SAndroid Build Coastguard Worker #include <clocale>
23*890232f2SAndroid Build Coastguard Worker #include <memory>
24*890232f2SAndroid Build Coastguard Worker #include <regex>
25*890232f2SAndroid Build Coastguard Worker #include <string>
26*890232f2SAndroid Build Coastguard Worker
27*890232f2SAndroid Build Coastguard Worker #include "flatbuffers/idl.h"
28*890232f2SAndroid Build Coastguard Worker #include "test_init.h"
29*890232f2SAndroid Build Coastguard Worker
30*890232f2SAndroid Build Coastguard Worker static constexpr size_t kMinInputLength = 1;
31*890232f2SAndroid Build Coastguard Worker static constexpr size_t kMaxInputLength = 3000;
32*890232f2SAndroid Build Coastguard Worker
33*890232f2SAndroid Build Coastguard Worker static constexpr uint8_t flags_scalar_type = 0x0F; // type of scalar value
34*890232f2SAndroid Build Coastguard Worker static constexpr uint8_t flags_quotes_kind = 0x10; // quote " or '
35*890232f2SAndroid Build Coastguard Worker // reserved for future: json {named} or [unnamed]
36*890232f2SAndroid Build Coastguard Worker // static constexpr uint8_t flags_json_bracer = 0x20;
37*890232f2SAndroid Build Coastguard Worker
38*890232f2SAndroid Build Coastguard Worker // Find all 'subj' sub-strings and replace first character of sub-string.
39*890232f2SAndroid Build Coastguard Worker // BreakSequence("testest","tes", 'X') -> "XesXest".
40*890232f2SAndroid Build Coastguard Worker // BreakSequence("xxx","xx", 'Y') -> "YYx".
BreakSequence(std::string & s,const char * subj,char repl)41*890232f2SAndroid Build Coastguard Worker static void BreakSequence(std::string &s, const char *subj, char repl) {
42*890232f2SAndroid Build Coastguard Worker size_t pos = 0;
43*890232f2SAndroid Build Coastguard Worker while (pos = s.find(subj, pos), pos != std::string::npos) {
44*890232f2SAndroid Build Coastguard Worker s.at(pos) = repl;
45*890232f2SAndroid Build Coastguard Worker pos++;
46*890232f2SAndroid Build Coastguard Worker }
47*890232f2SAndroid Build Coastguard Worker }
48*890232f2SAndroid Build Coastguard Worker
49*890232f2SAndroid Build Coastguard Worker // Remove all leading and trailing symbols matched with pattern set.
50*890232f2SAndroid Build Coastguard Worker // StripString("xy{xy}y", "xy") -> "{xy}"
StripString(const std::string & s,const char * pattern,size_t * pos=nullptr)51*890232f2SAndroid Build Coastguard Worker static std::string StripString(const std::string &s, const char *pattern,
52*890232f2SAndroid Build Coastguard Worker size_t *pos = nullptr) {
53*890232f2SAndroid Build Coastguard Worker if (pos) *pos = 0;
54*890232f2SAndroid Build Coastguard Worker // leading
55*890232f2SAndroid Build Coastguard Worker auto first = s.find_first_not_of(pattern);
56*890232f2SAndroid Build Coastguard Worker if (std::string::npos == first) return "";
57*890232f2SAndroid Build Coastguard Worker if (pos) *pos = first;
58*890232f2SAndroid Build Coastguard Worker // trailing
59*890232f2SAndroid Build Coastguard Worker auto last = s.find_last_not_of(pattern);
60*890232f2SAndroid Build Coastguard Worker assert(last < s.length());
61*890232f2SAndroid Build Coastguard Worker assert(first <= last);
62*890232f2SAndroid Build Coastguard Worker return s.substr(first, last - first + 1);
63*890232f2SAndroid Build Coastguard Worker }
64*890232f2SAndroid Build Coastguard Worker
65*890232f2SAndroid Build Coastguard Worker class RegexMatcher {
66*890232f2SAndroid Build Coastguard Worker protected:
67*890232f2SAndroid Build Coastguard Worker virtual bool MatchNumber(const std::string &input) const = 0;
68*890232f2SAndroid Build Coastguard Worker
69*890232f2SAndroid Build Coastguard Worker public:
70*890232f2SAndroid Build Coastguard Worker virtual ~RegexMatcher() = default;
71*890232f2SAndroid Build Coastguard Worker
72*890232f2SAndroid Build Coastguard Worker struct MatchResult {
73*890232f2SAndroid Build Coastguard Worker size_t pos{ 0 };
74*890232f2SAndroid Build Coastguard Worker size_t len{ 0 };
75*890232f2SAndroid Build Coastguard Worker bool res{ false };
76*890232f2SAndroid Build Coastguard Worker bool quoted{ false };
77*890232f2SAndroid Build Coastguard Worker };
78*890232f2SAndroid Build Coastguard Worker
Match(const std::string & input) const79*890232f2SAndroid Build Coastguard Worker MatchResult Match(const std::string &input) const {
80*890232f2SAndroid Build Coastguard Worker MatchResult r;
81*890232f2SAndroid Build Coastguard Worker // strip leading and trailing "spaces" accepted by flatbuffer
82*890232f2SAndroid Build Coastguard Worker auto test = StripString(input, "\t\r\n ", &r.pos);
83*890232f2SAndroid Build Coastguard Worker r.len = test.size();
84*890232f2SAndroid Build Coastguard Worker // check quotes
85*890232f2SAndroid Build Coastguard Worker if (test.size() >= 2) {
86*890232f2SAndroid Build Coastguard Worker auto fch = test.front();
87*890232f2SAndroid Build Coastguard Worker auto lch = test.back();
88*890232f2SAndroid Build Coastguard Worker r.quoted = (fch == lch) && (fch == '\'' || fch == '\"');
89*890232f2SAndroid Build Coastguard Worker if (r.quoted) {
90*890232f2SAndroid Build Coastguard Worker // remove quotes for regex test
91*890232f2SAndroid Build Coastguard Worker test = test.substr(1, test.size() - 2);
92*890232f2SAndroid Build Coastguard Worker }
93*890232f2SAndroid Build Coastguard Worker }
94*890232f2SAndroid Build Coastguard Worker // Fast check:
95*890232f2SAndroid Build Coastguard Worker if (test.empty()) return r;
96*890232f2SAndroid Build Coastguard Worker // A string with a valid scalar shouldn't have non-ascii or non-printable
97*890232f2SAndroid Build Coastguard Worker // symbols.
98*890232f2SAndroid Build Coastguard Worker for (auto c : test) {
99*890232f2SAndroid Build Coastguard Worker if ((c < ' ') || (c > '~')) return r;
100*890232f2SAndroid Build Coastguard Worker }
101*890232f2SAndroid Build Coastguard Worker // Check with regex
102*890232f2SAndroid Build Coastguard Worker r.res = MatchNumber(test);
103*890232f2SAndroid Build Coastguard Worker return r;
104*890232f2SAndroid Build Coastguard Worker }
105*890232f2SAndroid Build Coastguard Worker
MatchRegexList(const std::string & input,const std::vector<std::regex> & re_list) const106*890232f2SAndroid Build Coastguard Worker bool MatchRegexList(const std::string &input,
107*890232f2SAndroid Build Coastguard Worker const std::vector<std::regex> &re_list) const {
108*890232f2SAndroid Build Coastguard Worker auto str = StripString(input, " ");
109*890232f2SAndroid Build Coastguard Worker if (str.empty()) return false;
110*890232f2SAndroid Build Coastguard Worker for (auto &re : re_list) {
111*890232f2SAndroid Build Coastguard Worker std::smatch match;
112*890232f2SAndroid Build Coastguard Worker if (std::regex_match(str, match, re)) return true;
113*890232f2SAndroid Build Coastguard Worker }
114*890232f2SAndroid Build Coastguard Worker return false;
115*890232f2SAndroid Build Coastguard Worker }
116*890232f2SAndroid Build Coastguard Worker };
117*890232f2SAndroid Build Coastguard Worker
118*890232f2SAndroid Build Coastguard Worker class IntegerRegex : public RegexMatcher {
119*890232f2SAndroid Build Coastguard Worker protected:
MatchNumber(const std::string & input) const120*890232f2SAndroid Build Coastguard Worker bool MatchNumber(const std::string &input) const override {
121*890232f2SAndroid Build Coastguard Worker static const std::vector<std::regex> re_list = {
122*890232f2SAndroid Build Coastguard Worker std::regex{ R"(^[-+]?[0-9]+$)", std::regex_constants::optimize },
123*890232f2SAndroid Build Coastguard Worker
124*890232f2SAndroid Build Coastguard Worker std::regex{ R"(^[-+]?0[xX][0-9a-fA-F]+$)",
125*890232f2SAndroid Build Coastguard Worker std::regex_constants::optimize }
126*890232f2SAndroid Build Coastguard Worker };
127*890232f2SAndroid Build Coastguard Worker return MatchRegexList(input, re_list);
128*890232f2SAndroid Build Coastguard Worker }
129*890232f2SAndroid Build Coastguard Worker
130*890232f2SAndroid Build Coastguard Worker public:
131*890232f2SAndroid Build Coastguard Worker IntegerRegex() = default;
132*890232f2SAndroid Build Coastguard Worker virtual ~IntegerRegex() = default;
133*890232f2SAndroid Build Coastguard Worker };
134*890232f2SAndroid Build Coastguard Worker
135*890232f2SAndroid Build Coastguard Worker class UIntegerRegex : public RegexMatcher {
136*890232f2SAndroid Build Coastguard Worker protected:
MatchNumber(const std::string & input) const137*890232f2SAndroid Build Coastguard Worker bool MatchNumber(const std::string &input) const override {
138*890232f2SAndroid Build Coastguard Worker static const std::vector<std::regex> re_list = {
139*890232f2SAndroid Build Coastguard Worker std::regex{ R"(^[+]?[0-9]+$)", std::regex_constants::optimize },
140*890232f2SAndroid Build Coastguard Worker std::regex{ R"(^[+]?0[xX][0-9a-fA-F]+$)",
141*890232f2SAndroid Build Coastguard Worker std::regex_constants::optimize },
142*890232f2SAndroid Build Coastguard Worker // accept -0 number
143*890232f2SAndroid Build Coastguard Worker std::regex{ R"(^[-](?:0[xX])?0+$)", std::regex_constants::optimize }
144*890232f2SAndroid Build Coastguard Worker };
145*890232f2SAndroid Build Coastguard Worker return MatchRegexList(input, re_list);
146*890232f2SAndroid Build Coastguard Worker }
147*890232f2SAndroid Build Coastguard Worker
148*890232f2SAndroid Build Coastguard Worker public:
149*890232f2SAndroid Build Coastguard Worker UIntegerRegex() = default;
150*890232f2SAndroid Build Coastguard Worker virtual ~UIntegerRegex() = default;
151*890232f2SAndroid Build Coastguard Worker };
152*890232f2SAndroid Build Coastguard Worker
153*890232f2SAndroid Build Coastguard Worker class BooleanRegex : public IntegerRegex {
154*890232f2SAndroid Build Coastguard Worker protected:
MatchNumber(const std::string & input) const155*890232f2SAndroid Build Coastguard Worker bool MatchNumber(const std::string &input) const override {
156*890232f2SAndroid Build Coastguard Worker if (input == "true" || input == "false") return true;
157*890232f2SAndroid Build Coastguard Worker return IntegerRegex::MatchNumber(input);
158*890232f2SAndroid Build Coastguard Worker }
159*890232f2SAndroid Build Coastguard Worker
160*890232f2SAndroid Build Coastguard Worker public:
161*890232f2SAndroid Build Coastguard Worker BooleanRegex() = default;
162*890232f2SAndroid Build Coastguard Worker virtual ~BooleanRegex() = default;
163*890232f2SAndroid Build Coastguard Worker };
164*890232f2SAndroid Build Coastguard Worker
165*890232f2SAndroid Build Coastguard Worker class FloatRegex : public RegexMatcher {
166*890232f2SAndroid Build Coastguard Worker protected:
MatchNumber(const std::string & input) const167*890232f2SAndroid Build Coastguard Worker bool MatchNumber(const std::string &input) const override {
168*890232f2SAndroid Build Coastguard Worker static const std::vector<std::regex> re_list = {
169*890232f2SAndroid Build Coastguard Worker // hex-float
170*890232f2SAndroid Build Coastguard Worker std::regex{
171*890232f2SAndroid Build Coastguard Worker R"(^[-+]?0[xX](?:(?:[.][0-9a-fA-F]+)|(?:[0-9a-fA-F]+[.][0-9a-fA-F]*)|(?:[0-9a-fA-F]+))[pP][-+]?[0-9]+$)",
172*890232f2SAndroid Build Coastguard Worker std::regex_constants::optimize },
173*890232f2SAndroid Build Coastguard Worker // dec-float
174*890232f2SAndroid Build Coastguard Worker std::regex{
175*890232f2SAndroid Build Coastguard Worker R"(^[-+]?(?:(?:[.][0-9]+)|(?:[0-9]+[.][0-9]*)|(?:[0-9]+))(?:[eE][-+]?[0-9]+)?$)",
176*890232f2SAndroid Build Coastguard Worker std::regex_constants::optimize },
177*890232f2SAndroid Build Coastguard Worker
178*890232f2SAndroid Build Coastguard Worker std::regex{ R"(^[-+]?(?:nan|inf|infinity)$)",
179*890232f2SAndroid Build Coastguard Worker std::regex_constants::optimize | std::regex_constants::icase }
180*890232f2SAndroid Build Coastguard Worker };
181*890232f2SAndroid Build Coastguard Worker return MatchRegexList(input, re_list);
182*890232f2SAndroid Build Coastguard Worker }
183*890232f2SAndroid Build Coastguard Worker
184*890232f2SAndroid Build Coastguard Worker public:
185*890232f2SAndroid Build Coastguard Worker FloatRegex() = default;
186*890232f2SAndroid Build Coastguard Worker virtual ~FloatRegex() = default;
187*890232f2SAndroid Build Coastguard Worker };
188*890232f2SAndroid Build Coastguard Worker
189*890232f2SAndroid Build Coastguard Worker class ScalarReferenceResult {
190*890232f2SAndroid Build Coastguard Worker private:
ScalarReferenceResult(const char * _type,RegexMatcher::MatchResult _matched)191*890232f2SAndroid Build Coastguard Worker ScalarReferenceResult(const char *_type, RegexMatcher::MatchResult _matched)
192*890232f2SAndroid Build Coastguard Worker : type(_type), matched(_matched) {}
193*890232f2SAndroid Build Coastguard Worker
194*890232f2SAndroid Build Coastguard Worker public:
195*890232f2SAndroid Build Coastguard Worker // Decode scalar type and check if the input string satisfies the scalar type.
Check(uint8_t code,const std::string & input)196*890232f2SAndroid Build Coastguard Worker static ScalarReferenceResult Check(uint8_t code, const std::string &input) {
197*890232f2SAndroid Build Coastguard Worker switch (code) {
198*890232f2SAndroid Build Coastguard Worker case 0x0: return { "double", FloatRegex().Match(input) };
199*890232f2SAndroid Build Coastguard Worker case 0x1: return { "float", FloatRegex().Match(input) };
200*890232f2SAndroid Build Coastguard Worker case 0x2: return { "int8", IntegerRegex().Match(input) };
201*890232f2SAndroid Build Coastguard Worker case 0x3: return { "int16", IntegerRegex().Match(input) };
202*890232f2SAndroid Build Coastguard Worker case 0x4: return { "int32", IntegerRegex().Match(input) };
203*890232f2SAndroid Build Coastguard Worker case 0x5: return { "int64", IntegerRegex().Match(input) };
204*890232f2SAndroid Build Coastguard Worker case 0x6: return { "uint8", UIntegerRegex().Match(input) };
205*890232f2SAndroid Build Coastguard Worker case 0x7: return { "uint16", UIntegerRegex().Match(input) };
206*890232f2SAndroid Build Coastguard Worker case 0x8: return { "uint32", UIntegerRegex().Match(input) };
207*890232f2SAndroid Build Coastguard Worker case 0x9: return { "uint64", UIntegerRegex().Match(input) };
208*890232f2SAndroid Build Coastguard Worker case 0xA: return { "bool", BooleanRegex().Match(input) };
209*890232f2SAndroid Build Coastguard Worker default: return { "float", FloatRegex().Match(input) };
210*890232f2SAndroid Build Coastguard Worker };
211*890232f2SAndroid Build Coastguard Worker }
212*890232f2SAndroid Build Coastguard Worker
213*890232f2SAndroid Build Coastguard Worker const char *type;
214*890232f2SAndroid Build Coastguard Worker const RegexMatcher::MatchResult matched;
215*890232f2SAndroid Build Coastguard Worker };
216*890232f2SAndroid Build Coastguard Worker
Parse(flatbuffers::Parser & parser,const std::string & json,std::string * _text)217*890232f2SAndroid Build Coastguard Worker bool Parse(flatbuffers::Parser &parser, const std::string &json,
218*890232f2SAndroid Build Coastguard Worker std::string *_text) {
219*890232f2SAndroid Build Coastguard Worker auto done = parser.ParseJson(json.c_str());
220*890232f2SAndroid Build Coastguard Worker if (done) {
221*890232f2SAndroid Build Coastguard Worker TEST_EQ(GenerateText(parser, parser.builder_.GetBufferPointer(), _text),
222*890232f2SAndroid Build Coastguard Worker true);
223*890232f2SAndroid Build Coastguard Worker } else {
224*890232f2SAndroid Build Coastguard Worker *_text = parser.error_;
225*890232f2SAndroid Build Coastguard Worker }
226*890232f2SAndroid Build Coastguard Worker return done;
227*890232f2SAndroid Build Coastguard Worker }
228*890232f2SAndroid Build Coastguard Worker
229*890232f2SAndroid Build Coastguard Worker // Utility for test run.
230*890232f2SAndroid Build Coastguard Worker OneTimeTestInit OneTimeTestInit::one_time_init_;
231*890232f2SAndroid Build Coastguard Worker
232*890232f2SAndroid Build Coastguard Worker // llvm std::regex have problem with stack overflow, limit maximum length.
233*890232f2SAndroid Build Coastguard Worker // ./scalar_fuzzer -max_len=3000
LLVMFuzzerTestOneInput(const uint8_t * data,size_t size)234*890232f2SAndroid Build Coastguard Worker extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
235*890232f2SAndroid Build Coastguard Worker // Reserve one byte for Parser flags and one byte for repetition counter.
236*890232f2SAndroid Build Coastguard Worker if (size < 3) return 0;
237*890232f2SAndroid Build Coastguard Worker const uint8_t flags = data[0];
238*890232f2SAndroid Build Coastguard Worker // normalize to ascii alphabet
239*890232f2SAndroid Build Coastguard Worker const int extra_rep_number =
240*890232f2SAndroid Build Coastguard Worker std::max(5, (data[1] > '0' ? (data[1] - '0') : 0));
241*890232f2SAndroid Build Coastguard Worker data += 2;
242*890232f2SAndroid Build Coastguard Worker size -= 2; // bypass
243*890232f2SAndroid Build Coastguard Worker
244*890232f2SAndroid Build Coastguard Worker // Guarantee 0-termination.
245*890232f2SAndroid Build Coastguard Worker const std::string original(reinterpret_cast<const char *>(data), size);
246*890232f2SAndroid Build Coastguard Worker auto input = std::string(original.c_str()); // until '\0'
247*890232f2SAndroid Build Coastguard Worker if (input.size() < kMinInputLength || input.size() > kMaxInputLength)
248*890232f2SAndroid Build Coastguard Worker return 0;
249*890232f2SAndroid Build Coastguard Worker
250*890232f2SAndroid Build Coastguard Worker // Break comments in json to avoid complexity with regex matcher.
251*890232f2SAndroid Build Coastguard Worker // The string " 12345 /* text */" will be accepted if insert it to string
252*890232f2SAndroid Build Coastguard Worker // expression: "table X { Y: " + " 12345 /* text */" + "; }.
253*890232f2SAndroid Build Coastguard Worker // But strings like this will complicate regex matcher.
254*890232f2SAndroid Build Coastguard Worker // We reject this by transform "/* text */ 12345" to "@* text */ 12345".
255*890232f2SAndroid Build Coastguard Worker BreakSequence(input, "//", '@'); // "//" -> "@/"
256*890232f2SAndroid Build Coastguard Worker BreakSequence(input, "/*", '@'); // "/*" -> "@*"
257*890232f2SAndroid Build Coastguard Worker // { "$schema: "text" } is exceptional case.
258*890232f2SAndroid Build Coastguard Worker // This key:value ignored by the parser. Numbers can not have $.
259*890232f2SAndroid Build Coastguard Worker BreakSequence(input, "$schema", '@'); // "$schema" -> "@schema"
260*890232f2SAndroid Build Coastguard Worker // Break all known scalar functions (todo: add them to regex?):
261*890232f2SAndroid Build Coastguard Worker for (auto f : { "deg", "rad", "sin", "cos", "tan", "asin", "acos", "atan" }) {
262*890232f2SAndroid Build Coastguard Worker BreakSequence(input, f, '_'); // ident -> ident
263*890232f2SAndroid Build Coastguard Worker }
264*890232f2SAndroid Build Coastguard Worker
265*890232f2SAndroid Build Coastguard Worker // Extract type of scalar from 'flags' and check if the input string satisfies
266*890232f2SAndroid Build Coastguard Worker // the scalar type.
267*890232f2SAndroid Build Coastguard Worker const auto ref_res =
268*890232f2SAndroid Build Coastguard Worker ScalarReferenceResult::Check(flags & flags_scalar_type, input);
269*890232f2SAndroid Build Coastguard Worker auto &recheck = ref_res.matched;
270*890232f2SAndroid Build Coastguard Worker
271*890232f2SAndroid Build Coastguard Worker // Create parser
272*890232f2SAndroid Build Coastguard Worker flatbuffers::IDLOptions opts;
273*890232f2SAndroid Build Coastguard Worker opts.force_defaults = true;
274*890232f2SAndroid Build Coastguard Worker opts.output_default_scalars_in_json = true;
275*890232f2SAndroid Build Coastguard Worker opts.indent_step = -1;
276*890232f2SAndroid Build Coastguard Worker opts.strict_json = true;
277*890232f2SAndroid Build Coastguard Worker
278*890232f2SAndroid Build Coastguard Worker flatbuffers::Parser parser(opts);
279*890232f2SAndroid Build Coastguard Worker auto schema =
280*890232f2SAndroid Build Coastguard Worker "table X { Y: " + std::string(ref_res.type) + "; } root_type X;";
281*890232f2SAndroid Build Coastguard Worker TEST_EQ_FUNC(parser.Parse(schema.c_str()), true);
282*890232f2SAndroid Build Coastguard Worker
283*890232f2SAndroid Build Coastguard Worker // The fuzzer can adjust the number repetition if a side-effects have found.
284*890232f2SAndroid Build Coastguard Worker // Each test should pass at least two times to ensure that the parser doesn't
285*890232f2SAndroid Build Coastguard Worker // have any hidden-states or locale-depended effects.
286*890232f2SAndroid Build Coastguard Worker for (auto cnt = 0; cnt < (extra_rep_number + 2); cnt++) {
287*890232f2SAndroid Build Coastguard Worker // Each even run (0,2,4..) will test locale independed code.
288*890232f2SAndroid Build Coastguard Worker auto use_locale = !!OneTimeTestInit::test_locale() && (0 == (cnt % 2));
289*890232f2SAndroid Build Coastguard Worker // Set new locale.
290*890232f2SAndroid Build Coastguard Worker if (use_locale) {
291*890232f2SAndroid Build Coastguard Worker FLATBUFFERS_ASSERT(setlocale(LC_ALL, OneTimeTestInit::test_locale()));
292*890232f2SAndroid Build Coastguard Worker }
293*890232f2SAndroid Build Coastguard Worker
294*890232f2SAndroid Build Coastguard Worker // Parse original input as-is.
295*890232f2SAndroid Build Coastguard Worker auto orig_scalar = "{\"Y\" : " + input + "}";
296*890232f2SAndroid Build Coastguard Worker std::string orig_back;
297*890232f2SAndroid Build Coastguard Worker auto orig_done = Parse(parser, orig_scalar, &orig_back);
298*890232f2SAndroid Build Coastguard Worker
299*890232f2SAndroid Build Coastguard Worker if (recheck.res != orig_done) {
300*890232f2SAndroid Build Coastguard Worker // look for "does not fit" or "doesn't fit" or "out of range"
301*890232f2SAndroid Build Coastguard Worker auto not_fit =
302*890232f2SAndroid Build Coastguard Worker (true == recheck.res)
303*890232f2SAndroid Build Coastguard Worker ? ((orig_back.find("does not fit") != std::string::npos) ||
304*890232f2SAndroid Build Coastguard Worker (orig_back.find("out of range") != std::string::npos))
305*890232f2SAndroid Build Coastguard Worker : false;
306*890232f2SAndroid Build Coastguard Worker
307*890232f2SAndroid Build Coastguard Worker if (false == not_fit) {
308*890232f2SAndroid Build Coastguard Worker TEST_OUTPUT_LINE("Stage 1 failed: Parser(%d) != Regex(%d)", orig_done,
309*890232f2SAndroid Build Coastguard Worker recheck.res);
310*890232f2SAndroid Build Coastguard Worker TEST_EQ_STR(orig_back.c_str(),
311*890232f2SAndroid Build Coastguard Worker input.substr(recheck.pos, recheck.len).c_str());
312*890232f2SAndroid Build Coastguard Worker TEST_EQ_FUNC(orig_done, recheck.res);
313*890232f2SAndroid Build Coastguard Worker }
314*890232f2SAndroid Build Coastguard Worker }
315*890232f2SAndroid Build Coastguard Worker
316*890232f2SAndroid Build Coastguard Worker // Try to make quoted string and test it.
317*890232f2SAndroid Build Coastguard Worker std::string qouted_input;
318*890232f2SAndroid Build Coastguard Worker if (true == recheck.quoted) {
319*890232f2SAndroid Build Coastguard Worker // we can't simply remove quotes, they may be nested "'12'".
320*890232f2SAndroid Build Coastguard Worker // Original string "\'12\'" converted to "'12'".
321*890232f2SAndroid Build Coastguard Worker // The string can be an invalid string by JSON rules, but after quotes
322*890232f2SAndroid Build Coastguard Worker // removed can transform to valid.
323*890232f2SAndroid Build Coastguard Worker assert(recheck.len >= 2);
324*890232f2SAndroid Build Coastguard Worker } else {
325*890232f2SAndroid Build Coastguard Worker const auto quote = (flags & flags_quotes_kind) ? '\"' : '\'';
326*890232f2SAndroid Build Coastguard Worker qouted_input = input; // copy
327*890232f2SAndroid Build Coastguard Worker qouted_input.insert(recheck.pos + recheck.len, 1, quote);
328*890232f2SAndroid Build Coastguard Worker qouted_input.insert(recheck.pos, 1, quote);
329*890232f2SAndroid Build Coastguard Worker }
330*890232f2SAndroid Build Coastguard Worker
331*890232f2SAndroid Build Coastguard Worker // Test quoted version of the string
332*890232f2SAndroid Build Coastguard Worker if (!qouted_input.empty()) {
333*890232f2SAndroid Build Coastguard Worker auto fix_scalar = "{\"Y\" : " + qouted_input + "}";
334*890232f2SAndroid Build Coastguard Worker std::string fix_back;
335*890232f2SAndroid Build Coastguard Worker auto fix_done = Parse(parser, fix_scalar, &fix_back);
336*890232f2SAndroid Build Coastguard Worker
337*890232f2SAndroid Build Coastguard Worker if (orig_done != fix_done) {
338*890232f2SAndroid Build Coastguard Worker TEST_OUTPUT_LINE("Stage 2 failed: Parser(%d) != Regex(%d)", fix_done,
339*890232f2SAndroid Build Coastguard Worker orig_done);
340*890232f2SAndroid Build Coastguard Worker TEST_EQ_STR(fix_back.c_str(), orig_back.c_str());
341*890232f2SAndroid Build Coastguard Worker }
342*890232f2SAndroid Build Coastguard Worker if (orig_done) { TEST_EQ_STR(fix_back.c_str(), orig_back.c_str()); }
343*890232f2SAndroid Build Coastguard Worker TEST_EQ_FUNC(fix_done, orig_done);
344*890232f2SAndroid Build Coastguard Worker }
345*890232f2SAndroid Build Coastguard Worker
346*890232f2SAndroid Build Coastguard Worker // Create new parser and test default value
347*890232f2SAndroid Build Coastguard Worker if (true == orig_done) {
348*890232f2SAndroid Build Coastguard Worker flatbuffers::Parser def_parser(opts); // re-use options
349*890232f2SAndroid Build Coastguard Worker auto def_schema = "table X { Y: " + std::string(ref_res.type) + " = " +
350*890232f2SAndroid Build Coastguard Worker input + "; } root_type X;" +
351*890232f2SAndroid Build Coastguard Worker "{}"; // <- with empty json {}!
352*890232f2SAndroid Build Coastguard Worker
353*890232f2SAndroid Build Coastguard Worker auto def_done = def_parser.Parse(def_schema.c_str());
354*890232f2SAndroid Build Coastguard Worker if (false == def_done) {
355*890232f2SAndroid Build Coastguard Worker TEST_OUTPUT_LINE("Stage 3.1 failed with _error = %s",
356*890232f2SAndroid Build Coastguard Worker def_parser.error_.c_str());
357*890232f2SAndroid Build Coastguard Worker FLATBUFFERS_ASSERT(false);
358*890232f2SAndroid Build Coastguard Worker }
359*890232f2SAndroid Build Coastguard Worker // Compare with print.
360*890232f2SAndroid Build Coastguard Worker std::string ref_string, def_string;
361*890232f2SAndroid Build Coastguard Worker FLATBUFFERS_ASSERT(GenerateText(
362*890232f2SAndroid Build Coastguard Worker parser, parser.builder_.GetBufferPointer(), &ref_string));
363*890232f2SAndroid Build Coastguard Worker FLATBUFFERS_ASSERT(GenerateText(
364*890232f2SAndroid Build Coastguard Worker def_parser, def_parser.builder_.GetBufferPointer(), &def_string));
365*890232f2SAndroid Build Coastguard Worker if (ref_string != def_string) {
366*890232f2SAndroid Build Coastguard Worker TEST_OUTPUT_LINE("Stage 3.2 failed: '%s' != '%s'", def_string.c_str(),
367*890232f2SAndroid Build Coastguard Worker ref_string.c_str());
368*890232f2SAndroid Build Coastguard Worker FLATBUFFERS_ASSERT(false);
369*890232f2SAndroid Build Coastguard Worker }
370*890232f2SAndroid Build Coastguard Worker }
371*890232f2SAndroid Build Coastguard Worker
372*890232f2SAndroid Build Coastguard Worker // Restore locale.
373*890232f2SAndroid Build Coastguard Worker if (use_locale) { FLATBUFFERS_ASSERT(setlocale(LC_ALL, "C")); }
374*890232f2SAndroid Build Coastguard Worker }
375*890232f2SAndroid Build Coastguard Worker return 0;
376*890232f2SAndroid Build Coastguard Worker }
377