blob: 3e6cd5d82e6226cb882d75efd967b50a59b03c8c [file] [log] [blame]
Christopher Dunnf9864232007-06-14 21:01:26 +00001#include <json/json.h>
2#include <algorithm> // sort
3#include <stdio.h>
4
5#if defined(_MSC_VER) && _MSC_VER >= 1310
6# pragma warning( disable: 4996 ) // disable fopen deprecation warning
7#endif
8
9static std::string
10readInputTestFile( const char *path )
11{
12 FILE *file = fopen( path, "rb" );
13 if ( !file )
14 return std::string("");
15 fseek( file, 0, SEEK_END );
16 long size = ftell( file );
17 fseek( file, 0, SEEK_SET );
18 std::string text;
19 char *buffer = new char[size+1];
20 buffer[size] = 0;
21 if ( fread( buffer, 1, size, file ) == (unsigned long)size )
22 text = buffer;
23 fclose( file );
24 delete[] buffer;
25 return text;
26}
27
28
29static void
30printValueTree( FILE *fout, Json::Value &value, const std::string &path = "." )
31{
32 switch ( value.type() )
33 {
34 case Json::nullValue:
35 fprintf( fout, "%s=null\n", path.c_str() );
36 break;
37 case Json::intValue:
Baptiste Lepilleur201fb2c2010-04-19 07:37:41 +000038 fprintf( fout, "%s=%s\n", path.c_str(), Json::valueToString( value.asInt() ).c_str() );
Christopher Dunnf9864232007-06-14 21:01:26 +000039 break;
40 case Json::uintValue:
Baptiste Lepilleur201fb2c2010-04-19 07:37:41 +000041 fprintf( fout, "%s=%s\n", path.c_str(), Json::valueToString( value.asUInt() ).c_str() );
Christopher Dunnf9864232007-06-14 21:01:26 +000042 break;
43 case Json::realValue:
44 fprintf( fout, "%s=%.16g\n", path.c_str(), value.asDouble() );
45 break;
46 case Json::stringValue:
47 fprintf( fout, "%s=\"%s\"\n", path.c_str(), value.asString().c_str() );
48 break;
49 case Json::booleanValue:
50 fprintf( fout, "%s=%s\n", path.c_str(), value.asBool() ? "true" : "false" );
51 break;
52 case Json::arrayValue:
53 {
54 fprintf( fout, "%s=[]\n", path.c_str() );
55 int size = value.size();
56 for ( int index =0; index < size; ++index )
57 {
58 static char buffer[16];
59 sprintf( buffer, "[%d]", index );
60 printValueTree( fout, value[index], path + buffer );
61 }
62 }
63 break;
64 case Json::objectValue:
65 {
66 fprintf( fout, "%s={}\n", path.c_str() );
67 Json::Value::Members members( value.getMemberNames() );
68 std::sort( members.begin(), members.end() );
69 std::string suffix = *(path.end()-1) == '.' ? "" : ".";
70 for ( Json::Value::Members::iterator it = members.begin();
71 it != members.end();
72 ++it )
73 {
74 const std::string &name = *it;
75 printValueTree( fout, value[name], path + suffix + name );
76 }
77 }
78 break;
79 default:
80 break;
81 }
82}
83
84
85static int
86parseAndSaveValueTree( const std::string &input,
87 const std::string &actual,
88 const std::string &kind,
Baptiste Lepilleur88681472009-11-18 21:38:54 +000089 Json::Value &root,
90 const Json::Features &features,
91 bool parseOnly )
Christopher Dunnf9864232007-06-14 21:01:26 +000092{
Baptiste Lepilleur88681472009-11-18 21:38:54 +000093 Json::Reader reader( features );
Christopher Dunnf9864232007-06-14 21:01:26 +000094 bool parsingSuccessful = reader.parse( input, root );
95 if ( !parsingSuccessful )
96 {
97 printf( "Failed to parse %s file: \n%s\n",
98 kind.c_str(),
99 reader.getFormatedErrorMessages().c_str() );
100 return 1;
101 }
102
Baptiste Lepilleur88681472009-11-18 21:38:54 +0000103 if ( !parseOnly )
Christopher Dunnf9864232007-06-14 21:01:26 +0000104 {
Baptiste Lepilleur88681472009-11-18 21:38:54 +0000105 FILE *factual = fopen( actual.c_str(), "wt" );
106 if ( !factual )
107 {
108 printf( "Failed to create %s actual file.\n", kind.c_str() );
109 return 2;
110 }
111 printValueTree( factual, root );
112 fclose( factual );
Christopher Dunnf9864232007-06-14 21:01:26 +0000113 }
Christopher Dunnf9864232007-06-14 21:01:26 +0000114 return 0;
115}
116
117
118static int
119rewriteValueTree( const std::string &rewritePath,
120 const Json::Value &root,
121 std::string &rewrite )
122{
123 //Json::FastWriter writer;
124 //writer.enableYAMLCompatibility();
125 Json::StyledWriter writer;
126 rewrite = writer.write( root );
127 FILE *fout = fopen( rewritePath.c_str(), "wt" );
128 if ( !fout )
129 {
130 printf( "Failed to create rewrite file: %s\n", rewritePath.c_str() );
131 return 2;
132 }
133 fprintf( fout, "%s\n", rewrite.c_str() );
134 fclose( fout );
135 return 0;
136}
137
138
139static std::string
140removeSuffix( const std::string &path,
141 const std::string &extension )
142{
143 if ( extension.length() >= path.length() )
144 return std::string("");
145 std::string suffix = path.substr( path.length() - extension.length() );
146 if ( suffix != extension )
147 return std::string("");
148 return path.substr( 0, path.length() - extension.length() );
149}
150
Baptiste Lepilleur201fb2c2010-04-19 07:37:41 +0000151
152static void
153printConfig()
154{
155 // Print the configuration used to compile JsonCpp
156#if defined(JSON_NO_INT64)
157 printf( "JSON_NO_INT64=1\n" );
158#else
159 printf( "JSON_NO_INT64=0\n" );
160#endif
161}
162
163
Baptiste Lepilleur88681472009-11-18 21:38:54 +0000164static int
165printUsage( const char *argv[] )
Christopher Dunnf9864232007-06-14 21:01:26 +0000166{
Baptiste Lepilleur88681472009-11-18 21:38:54 +0000167 printf( "Usage: %s [--strict] input-json-file", argv[0] );
168 return 3;
169}
170
171
172int
173parseCommandLine( int argc, const char *argv[],
174 Json::Features &features, std::string &path,
175 bool &parseOnly )
176{
177 parseOnly = false;
178 if ( argc < 2 )
Christopher Dunnf9864232007-06-14 21:01:26 +0000179 {
Baptiste Lepilleur88681472009-11-18 21:38:54 +0000180 return printUsage( argv );
Christopher Dunnf9864232007-06-14 21:01:26 +0000181 }
182
Baptiste Lepilleur88681472009-11-18 21:38:54 +0000183 int index = 1;
184 if ( std::string(argv[1]) == "--json-checker" )
185 {
186 features = Json::Features::strictMode();
187 parseOnly = true;
188 ++index;
189 }
190
Baptiste Lepilleur201fb2c2010-04-19 07:37:41 +0000191 if ( std::string(argv[1]) == "--json-config" )
192 {
193 printConfig();
194 return 3;
195 }
196
Baptiste Lepilleur88681472009-11-18 21:38:54 +0000197 if ( index == argc || index + 1 < argc )
198 {
199 return printUsage( argv );
200 }
201
202 path = argv[index];
203 return 0;
204}
205
206
207int main( int argc, const char *argv[] )
208{
209 std::string path;
210 Json::Features features;
211 bool parseOnly;
212 int exitCode = parseCommandLine( argc, argv, features, path, parseOnly );
213 if ( exitCode != 0 )
214 {
215 return exitCode;
216 }
217
218 std::string input = readInputTestFile( path.c_str() );
Christopher Dunnf9864232007-06-14 21:01:26 +0000219 if ( input.empty() )
220 {
Baptiste Lepilleur88681472009-11-18 21:38:54 +0000221 printf( "Failed to read input or empty input: %s\n", path.c_str() );
Christopher Dunnf9864232007-06-14 21:01:26 +0000222 return 3;
223 }
224
225 std::string basePath = removeSuffix( argv[1], ".json" );
Baptiste Lepilleur88681472009-11-18 21:38:54 +0000226 if ( !parseOnly && basePath.empty() )
Christopher Dunnf9864232007-06-14 21:01:26 +0000227 {
Baptiste Lepilleur88681472009-11-18 21:38:54 +0000228 printf( "Bad input path. Path does not end with '.expected':\n%s\n", path.c_str() );
Christopher Dunnf9864232007-06-14 21:01:26 +0000229 return 3;
230 }
231
232 std::string actualPath = basePath + ".actual";
233 std::string rewritePath = basePath + ".rewrite";
234 std::string rewriteActualPath = basePath + ".actual-rewrite";
235
236 Json::Value root;
Baptiste Lepilleur88681472009-11-18 21:38:54 +0000237 exitCode = parseAndSaveValueTree( input, actualPath, "input", root, features, parseOnly );
238 if ( exitCode == 0 && !parseOnly )
Christopher Dunnf9864232007-06-14 21:01:26 +0000239 {
240 std::string rewrite;
241 exitCode = rewriteValueTree( rewritePath, root, rewrite );
242 if ( exitCode == 0 )
243 {
244 Json::Value rewriteRoot;
Baptiste Lepilleur88681472009-11-18 21:38:54 +0000245 exitCode = parseAndSaveValueTree( rewrite, rewriteActualPath,
246 "rewrite", rewriteRoot, features, parseOnly );
Christopher Dunnf9864232007-06-14 21:01:26 +0000247 }
248 }
249
250 return exitCode;
251}
252