15
15
16
16
#include < algorithm> // sort
17
17
#include < cstdio>
18
+ #include < iostream>
18
19
#include < json/json.h>
20
+ #include < memory>
19
21
#include < sstream>
20
22
21
23
struct Options {
@@ -126,19 +128,45 @@ static int parseAndSaveValueTree(const Json::String& input,
126
128
const Json::String& actual,
127
129
const Json::String& kind,
128
130
const Json::Features& features, bool parseOnly,
129
- Json::Value* root) {
130
- Json::Reader reader (features);
131
- bool parsingSuccessful =
132
- reader.parse (input.data (), input.data () + input.size (), *root);
133
- if (!parsingSuccessful) {
134
- printf (" Failed to parse %s file: \n %s\n " , kind.c_str (),
135
- reader.getFormattedErrorMessages ().c_str ());
136
- return 1 ;
131
+ Json::Value* root, bool use_legacy) {
132
+ if (!use_legacy) {
133
+ Json::CharReaderBuilder builder;
134
+
135
+ builder.settings_ [" allowComments" ] = features.allowComments_ ;
136
+ builder.settings_ [" strictRoot" ] = features.strictRoot_ ;
137
+ builder.settings_ [" allowDroppedNullPlaceholders" ] =
138
+ features.allowDroppedNullPlaceholders_ ;
139
+ builder.settings_ [" allowNumericKeys" ] = features.allowNumericKeys_ ;
140
+
141
+ std::unique_ptr<Json::CharReader> reader (builder.newCharReader ());
142
+ Json::String errors;
143
+ const bool parsingSuccessful =
144
+ reader->parse (input.data (), input.data () + input.size (), root, &errors);
145
+
146
+ if (!parsingSuccessful) {
147
+ std::cerr << " Failed to parse " << kind << " file: " << std::endl
148
+ << errors << std::endl;
149
+ return 1 ;
150
+ }
151
+
152
+ // We may instead check the legacy implementation (to ensure it doesn't
153
+ // randomly get broken).
154
+ } else {
155
+ Json::Reader reader (features);
156
+ const bool parsingSuccessful =
157
+ reader.parse (input.data (), input.data () + input.size (), *root);
158
+ if (!parsingSuccessful) {
159
+ std::cerr << " Failed to parse " << kind << " file: " << std::endl
160
+ << reader.getFormatedErrorMessages () << std::endl;
161
+ return 1 ;
162
+ }
137
163
}
164
+
138
165
if (!parseOnly) {
139
166
FILE* factual = fopen (actual.c_str (), " wt" );
140
167
if (!factual) {
141
- printf (" Failed to create %s actual file.\n " , kind.c_str ());
168
+ std::cerr << " Failed to create '" << kind << " ' actual file."
169
+ << std::endl;
142
170
return 2 ;
143
171
}
144
172
printValueTree (factual, *root);
@@ -172,7 +200,7 @@ static int rewriteValueTree(const Json::String& rewritePath,
172
200
*rewrite = write (root);
173
201
FILE* fout = fopen (rewritePath.c_str (), " wt" );
174
202
if (!fout) {
175
- printf ( " Failed to create rewrite file: %s \n " , rewritePath. c_str ()) ;
203
+ std::cerr << " Failed to create rewrite file: " << rewritePath << std::endl ;
176
204
return 2 ;
177
205
}
178
206
fprintf (fout, " %s\n " , rewrite->c_str ());
@@ -193,14 +221,15 @@ static Json::String removeSuffix(const Json::String& path,
193
221
static void printConfig () {
194
222
// Print the configuration used to compile JsonCpp
195
223
#if defined(JSON_NO_INT64)
196
- printf ( " JSON_NO_INT64=1\n " ) ;
224
+ std::cout << " JSON_NO_INT64=1" << std::endl ;
197
225
#else
198
- printf ( " JSON_NO_INT64=0\n " ) ;
226
+ std::cout << " JSON_NO_INT64=0" << std::endl ;
199
227
#endif
200
228
}
201
229
202
230
static int printUsage (const char * argv[]) {
203
- printf (" Usage: %s [--strict] input-json-file" , argv[0 ]);
231
+ std::cout << " Usage: " << argv[0 ] << " [--strict] input-json-file"
232
+ << std::endl;
204
233
return 3 ;
205
234
}
206
235
@@ -230,7 +259,7 @@ static int parseCommandLine(int argc, const char* argv[], Options* opts) {
230
259
} else if (writerName == " BuiltStyledStreamWriter" ) {
231
260
opts->write = &useBuiltStyledStreamWriter;
232
261
} else {
233
- printf ( " Unknown '--json-writer %s' \n " , writerName. c_str ()) ;
262
+ std::cerr << " Unknown '--json-writer' " << writerName << std::endl ;
234
263
return 4 ;
235
264
}
236
265
}
@@ -240,19 +269,20 @@ static int parseCommandLine(int argc, const char* argv[], Options* opts) {
240
269
opts->path = argv[index];
241
270
return 0 ;
242
271
}
243
- static int runTest (Options const & opts) {
272
+
273
+ static int runTest (Options const & opts, bool use_legacy) {
244
274
int exitCode = 0 ;
245
275
246
276
Json::String input = readInputTestFile (opts.path .c_str ());
247
277
if (input.empty ()) {
248
- printf ( " Failed to read input or empty input: %s \n " , opts.path . c_str ()) ;
278
+ std::cerr << " Invalid input file: " << opts.path << std::endl ;
249
279
return 3 ;
250
280
}
251
281
252
282
Json::String basePath = removeSuffix (opts.path , " .json" );
253
283
if (!opts.parseOnly && basePath.empty ()) {
254
- printf ( " Bad input path. Path does not end with '.expected': \n %s \n " ,
255
- opts. path . c_str ()) ;
284
+ std::cerr << " Bad input path ' " << opts. path
285
+ << " '. Must end with '.expected' " << std::endl ;
256
286
return 3 ;
257
287
}
258
288
@@ -262,34 +292,47 @@ static int runTest(Options const& opts) {
262
292
263
293
Json::Value root;
264
294
exitCode = parseAndSaveValueTree (input, actualPath, " input" , opts.features ,
265
- opts.parseOnly , &root);
295
+ opts.parseOnly , &root, use_legacy );
266
296
if (exitCode || opts.parseOnly ) {
267
297
return exitCode;
268
298
}
299
+
269
300
Json::String rewrite;
270
301
exitCode = rewriteValueTree (rewritePath, root, opts.write , &rewrite);
271
302
if (exitCode) {
272
303
return exitCode;
273
304
}
305
+
274
306
Json::Value rewriteRoot;
275
307
exitCode = parseAndSaveValueTree (rewrite, rewriteActualPath, " rewrite" ,
276
- opts.features , opts.parseOnly , &rewriteRoot);
277
- if (exitCode) {
278
- return exitCode;
279
- }
280
- return 0 ;
308
+ opts.features , opts.parseOnly , &rewriteRoot,
309
+ use_legacy);
310
+
311
+ return exitCode;
281
312
}
313
+
282
314
int main (int argc, const char * argv[]) {
283
315
Options opts;
284
316
try {
285
317
int exitCode = parseCommandLine (argc, argv, &opts);
286
318
if (exitCode != 0 ) {
287
- printf ( " Failed to parse command-line." ) ;
319
+ std::cerr << " Failed to parse command-line." << std::endl ;
288
320
return exitCode;
289
321
}
290
- return runTest (opts);
322
+
323
+ const int modern_return_code = runTest (opts, false );
324
+ if (modern_return_code) {
325
+ return modern_return_code;
326
+ }
327
+
328
+ const std::string filename =
329
+ opts.path .substr (opts.path .find_last_of (" \\ /" ) + 1 );
330
+ const bool should_run_legacy = (filename.rfind (" legacy_" , 0 ) == 0 );
331
+ if (should_run_legacy) {
332
+ return runTest (opts, true );
333
+ }
291
334
} catch (const std::exception& e) {
292
- printf ( " Unhandled exception:\n %s \n " , e.what ()) ;
335
+ std::cerr << " Unhandled exception:" << std::endl << e.what () << std::endl ;
293
336
return 1 ;
294
337
}
295
338
}
0 commit comments