blob: dfb6150e06f52b1d70bc44bccaf11073bf705acf [file] [log] [blame]
Baptiste Lepilleur7469f1d2010-04-20 21:35:19 +00001// Copyright 2007-2010 Baptiste Lepilleur
2// Distributed under MIT license, or public domain if desired and
3// recognized in your jurisdiction.
4// See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE
5
Baptiste Lepilleurfa130ef2010-12-24 12:47:14 +00006/* This executable is used for testing parser/writer using real JSON files.
7 */
8
9
Christopher Dunnf9864232007-06-14 21:01:26 +000010#include <json/json.h>
11#include <algorithm> // sort
12#include <stdio.h>
13
14#if defined(_MSC_VER) && _MSC_VER >= 1310
15# pragma warning( disable: 4996 ) // disable fopen deprecation warning
16#endif
17
18static std::string
19readInputTestFile( const char *path )
20{
21 FILE *file = fopen( path, "rb" );
22 if ( !file )
23 return std::string("");
24 fseek( file, 0, SEEK_END );
25 long size = ftell( file );
26 fseek( file, 0, SEEK_SET );
27 std::string text;
28 char *buffer = new char[size+1];
29 buffer[size] = 0;
30 if ( fread( buffer, 1, size, file ) == (unsigned long)size )
31 text = buffer;
32 fclose( file );
33 delete[] buffer;
34 return text;
35}
36
37
38static void
39printValueTree( FILE *fout, Json::Value &value, const std::string &path = "." )
40{
41 switch ( value.type() )
42 {
43 case Json::nullValue:
44 fprintf( fout, "%s=null\n", path.c_str() );
45 break;
46 case Json::intValue:
Baptiste Lepilleur842e9ac2010-12-27 17:45:23 +000047 fprintf( fout, "%s=%s\n", path.c_str(), Json::valueToString( value.asLargestInt() ).c_str() );
Christopher Dunnf9864232007-06-14 21:01:26 +000048 break;
49 case Json::uintValue:
Baptiste Lepilleur842e9ac2010-12-27 17:45:23 +000050 fprintf( fout, "%s=%s\n", path.c_str(), Json::valueToString( value.asLargestUInt() ).c_str() );
Christopher Dunnf9864232007-06-14 21:01:26 +000051 break;
52 case Json::realValue:
53 fprintf( fout, "%s=%.16g\n", path.c_str(), value.asDouble() );
54 break;
55 case Json::stringValue:
56 fprintf( fout, "%s=\"%s\"\n", path.c_str(), value.asString().c_str() );
57 break;
58 case Json::booleanValue:
59 fprintf( fout, "%s=%s\n", path.c_str(), value.asBool() ? "true" : "false" );
60 break;
61 case Json::arrayValue:
62 {
63 fprintf( fout, "%s=[]\n", path.c_str() );
64 int size = value.size();
65 for ( int index =0; index < size; ++index )
66 {
67 static char buffer[16];
68 sprintf( buffer, "[%d]", index );
69 printValueTree( fout, value[index], path + buffer );
70 }
71 }
72 break;
73 case Json::objectValue:
74 {
75 fprintf( fout, "%s={}\n", path.c_str() );
76 Json::Value::Members members( value.getMemberNames() );
77 std::sort( members.begin(), members.end() );
78 std::string suffix = *(path.end()-1) == '.' ? "" : ".";
79 for ( Json::Value::Members::iterator it = members.begin();
80 it != members.end();
81 ++it )
82 {
83 const std::string &name = *it;
84 printValueTree( fout, value[name], path + suffix + name );
85 }
86 }
87 break;
88 default:
89 break;
90 }
91}
92
93
94static int
95parseAndSaveValueTree( const std::string &input,
96 const std::string &actual,
97 const std::string &kind,
Baptiste Lepilleur88681472009-11-18 21:38:54 +000098 Json::Value &root,
99 const Json::Features &features,
100 bool parseOnly )
Christopher Dunnf9864232007-06-14 21:01:26 +0000101{
Baptiste Lepilleur88681472009-11-18 21:38:54 +0000102 Json::Reader reader( features );
Christopher Dunnf9864232007-06-14 21:01:26 +0000103 bool parsingSuccessful = reader.parse( input, root );
104 if ( !parsingSuccessful )
105 {
106 printf( "Failed to parse %s file: \n%s\n",
107 kind.c_str(),
Baptiste Lepilleurb2e8ccc2011-05-01 16:27:55 +0000108 reader.getFormattedErrorMessages().c_str() );
Christopher Dunnf9864232007-06-14 21:01:26 +0000109 return 1;
110 }
111
Baptiste Lepilleur88681472009-11-18 21:38:54 +0000112 if ( !parseOnly )
Christopher Dunnf9864232007-06-14 21:01:26 +0000113 {
Baptiste Lepilleur88681472009-11-18 21:38:54 +0000114 FILE *factual = fopen( actual.c_str(), "wt" );
115 if ( !factual )
116 {
117 printf( "Failed to create %s actual file.\n", kind.c_str() );
118 return 2;
119 }
120 printValueTree( factual, root );
121 fclose( factual );
Christopher Dunnf9864232007-06-14 21:01:26 +0000122 }
Christopher Dunnf9864232007-06-14 21:01:26 +0000123 return 0;
124}
125
126
127static int
128rewriteValueTree( const std::string &rewritePath,
129 const Json::Value &root,
130 std::string &rewrite )
131{
132 //Json::FastWriter writer;
133 //writer.enableYAMLCompatibility();
134 Json::StyledWriter writer;
135 rewrite = writer.write( root );
136 FILE *fout = fopen( rewritePath.c_str(), "wt" );
137 if ( !fout )
138 {
139 printf( "Failed to create rewrite file: %s\n", rewritePath.c_str() );
140 return 2;
141 }
142 fprintf( fout, "%s\n", rewrite.c_str() );
143 fclose( fout );
144 return 0;
145}
146
147
148static std::string
149removeSuffix( const std::string &path,
150 const std::string &extension )
151{
152 if ( extension.length() >= path.length() )
153 return std::string("");
154 std::string suffix = path.substr( path.length() - extension.length() );
155 if ( suffix != extension )
156 return std::string("");
157 return path.substr( 0, path.length() - extension.length() );
158}
159
Baptiste Lepilleur201fb2c2010-04-19 07:37:41 +0000160
161static void
162printConfig()
163{
164 // Print the configuration used to compile JsonCpp
165#if defined(JSON_NO_INT64)
166 printf( "JSON_NO_INT64=1\n" );
167#else
168 printf( "JSON_NO_INT64=0\n" );
169#endif
170}
171
172
Baptiste Lepilleur88681472009-11-18 21:38:54 +0000173static int
174printUsage( const char *argv[] )
Christopher Dunnf9864232007-06-14 21:01:26 +0000175{
Baptiste Lepilleur88681472009-11-18 21:38:54 +0000176 printf( "Usage: %s [--strict] input-json-file", argv[0] );
177 return 3;
178}
179
180
181int
182parseCommandLine( int argc, const char *argv[],
183 Json::Features &features, std::string &path,
184 bool &parseOnly )
185{
186 parseOnly = false;
187 if ( argc < 2 )
Christopher Dunnf9864232007-06-14 21:01:26 +0000188 {
Baptiste Lepilleur88681472009-11-18 21:38:54 +0000189 return printUsage( argv );
Christopher Dunnf9864232007-06-14 21:01:26 +0000190 }
191
Baptiste Lepilleur88681472009-11-18 21:38:54 +0000192 int index = 1;
193 if ( std::string(argv[1]) == "--json-checker" )
194 {
195 features = Json::Features::strictMode();
196 parseOnly = true;
197 ++index;
198 }
199
Baptiste Lepilleur201fb2c2010-04-19 07:37:41 +0000200 if ( std::string(argv[1]) == "--json-config" )
201 {
202 printConfig();
203 return 3;
204 }
205
Baptiste Lepilleur88681472009-11-18 21:38:54 +0000206 if ( index == argc || index + 1 < argc )
207 {
208 return printUsage( argv );
209 }
210
211 path = argv[index];
212 return 0;
213}
214
215
216int main( int argc, const char *argv[] )
217{
218 std::string path;
219 Json::Features features;
220 bool parseOnly;
221 int exitCode = parseCommandLine( argc, argv, features, path, parseOnly );
222 if ( exitCode != 0 )
223 {
224 return exitCode;
225 }
226
Baptiste Lepilleur842e9ac2010-12-27 17:45:23 +0000227 try
Christopher Dunnf9864232007-06-14 21:01:26 +0000228 {
Baptiste Lepilleur842e9ac2010-12-27 17:45:23 +0000229 std::string input = readInputTestFile( path.c_str() );
230 if ( input.empty() )
Christopher Dunnf9864232007-06-14 21:01:26 +0000231 {
Baptiste Lepilleur842e9ac2010-12-27 17:45:23 +0000232 printf( "Failed to read input or empty input: %s\n", path.c_str() );
233 return 3;
Christopher Dunnf9864232007-06-14 21:01:26 +0000234 }
Baptiste Lepilleur842e9ac2010-12-27 17:45:23 +0000235
236 std::string basePath = removeSuffix( argv[1], ".json" );
237 if ( !parseOnly && basePath.empty() )
238 {
239 printf( "Bad input path. Path does not end with '.expected':\n%s\n", path.c_str() );
240 return 3;
241 }
242
243 std::string actualPath = basePath + ".actual";
244 std::string rewritePath = basePath + ".rewrite";
245 std::string rewriteActualPath = basePath + ".actual-rewrite";
246
247 Json::Value root;
248 exitCode = parseAndSaveValueTree( input, actualPath, "input", root, features, parseOnly );
249 if ( exitCode == 0 && !parseOnly )
250 {
251 std::string rewrite;
252 exitCode = rewriteValueTree( rewritePath, root, rewrite );
253 if ( exitCode == 0 )
254 {
255 Json::Value rewriteRoot;
256 exitCode = parseAndSaveValueTree( rewrite, rewriteActualPath,
257 "rewrite", rewriteRoot, features, parseOnly );
258 }
259 }
260 }
261 catch ( const std::exception &e )
262 {
263 printf( "Unhandled exception:\n%s\n", e.what() );
264 exitCode = 1;
Christopher Dunnf9864232007-06-14 21:01:26 +0000265 }
266
267 return exitCode;
268}
269