aboutsummaryrefslogtreecommitdiff
path: root/src/jsontestrunner/main.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/jsontestrunner/main.cpp')
-rw-r--r--src/jsontestrunner/main.cpp341
1 files changed, 203 insertions, 138 deletions
diff --git a/src/jsontestrunner/main.cpp b/src/jsontestrunner/main.cpp
index ba98587..3452c59 100644
--- a/src/jsontestrunner/main.cpp
+++ b/src/jsontestrunner/main.cpp
@@ -1,39 +1,49 @@
-// Copyright 2007-2010 Baptiste Lepilleur
+// Copyright 2007-2010 Baptiste Lepilleur and The JsonCpp Authors
// Distributed under MIT license, or public domain if desired and
// recognized in your jurisdiction.
// See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE
+#if defined(__GNUC__)
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
+#elif defined(_MSC_VER)
+#pragma warning(disable : 4996)
+#endif
+
/* This executable is used for testing parser/writer using real JSON files.
*/
-#include <json/json.h>
#include <algorithm> // sort
-#include <stdio.h>
+#include <cstdio>
+#include <iostream>
+#include <json/json.h>
+#include <memory>
+#include <sstream>
-#if defined(_MSC_VER) && _MSC_VER >= 1310
-#pragma warning(disable : 4996) // disable fopen deprecation warning
-#endif
+struct Options {
+ Json::String path;
+ Json::Features features;
+ bool parseOnly;
+ using writeFuncType = Json::String (*)(Json::Value const&);
+ writeFuncType write;
+};
-static std::string normalizeFloatingPointStr(double value) {
+static Json::String normalizeFloatingPointStr(double value) {
char buffer[32];
-#if defined(_MSC_VER) && defined(__STDC_SECURE_LIB__)
- sprintf_s(buffer, sizeof(buffer), "%.16g", value);
-#else
- snprintf(buffer, sizeof(buffer), "%.16g", value);
-#endif
+ jsoncpp_snprintf(buffer, sizeof(buffer), "%.16g", value);
buffer[sizeof(buffer) - 1] = 0;
- std::string s(buffer);
- std::string::size_type index = s.find_last_of("eE");
- if (index != std::string::npos) {
- std::string::size_type hasSign =
+ Json::String s(buffer);
+ Json::String::size_type index = s.find_last_of("eE");
+ if (index != Json::String::npos) {
+ Json::String::size_type hasSign =
(s[index + 1] == '+' || s[index + 1] == '-') ? 1 : 0;
- std::string::size_type exponentStartIndex = index + 1 + hasSign;
- std::string normalized = s.substr(0, exponentStartIndex);
- std::string::size_type indexDigit =
+ Json::String::size_type exponentStartIndex = index + 1 + hasSign;
+ Json::String normalized = s.substr(0, exponentStartIndex);
+ Json::String::size_type indexDigit =
s.find_first_not_of('0', exponentStartIndex);
- std::string exponent = "0";
- if (indexDigit !=
- std::string::npos) // There is an exponent different from 0
+ Json::String exponent = "0";
+ if (indexDigit != Json::String::npos) // There is an exponent different
+ // from 0
{
exponent = s.substr(indexDigit);
}
@@ -42,25 +52,26 @@ static std::string normalizeFloatingPointStr(double value) {
return s;
}
-static std::string readInputTestFile(const char* path) {
+static Json::String readInputTestFile(const char* path) {
FILE* file = fopen(path, "rb");
if (!file)
- return std::string("");
+ return "";
fseek(file, 0, SEEK_END);
- long size = ftell(file);
+ auto const size = ftell(file);
+ auto const usize = static_cast<size_t>(size);
fseek(file, 0, SEEK_SET);
- std::string text;
- char* buffer = new char[size + 1];
+ auto buffer = new char[size + 1];
buffer[size] = 0;
- if (fread(buffer, 1, size, file) == (unsigned long)size)
+ Json::String text;
+ if (fread(buffer, 1, usize, file) == usize)
text = buffer;
fclose(file);
delete[] buffer;
return text;
}
-static void
-printValueTree(FILE* fout, Json::Value& value, const std::string& path = ".") {
+static void printValueTree(FILE* fout, Json::Value& value,
+ const Json::String& path = ".") {
if (value.hasComment(Json::commentBefore)) {
fprintf(fout, "%s\n", value.getComment(Json::commentBefore).c_str());
}
@@ -69,21 +80,15 @@ printValueTree(FILE* fout, Json::Value& value, const std::string& path = ".") {
fprintf(fout, "%s=null\n", path.c_str());
break;
case Json::intValue:
- fprintf(fout,
- "%s=%s\n",
- path.c_str(),
+ fprintf(fout, "%s=%s\n", path.c_str(),
Json::valueToString(value.asLargestInt()).c_str());
break;
case Json::uintValue:
- fprintf(fout,
- "%s=%s\n",
- path.c_str(),
+ fprintf(fout, "%s=%s\n", path.c_str(),
Json::valueToString(value.asLargestUInt()).c_str());
break;
case Json::realValue:
- fprintf(fout,
- "%s=%s\n",
- path.c_str(),
+ fprintf(fout, "%s=%s\n", path.c_str(),
normalizeFloatingPointStr(value.asDouble()).c_str());
break;
case Json::stringValue:
@@ -94,14 +99,10 @@ printValueTree(FILE* fout, Json::Value& value, const std::string& path = ".") {
break;
case Json::arrayValue: {
fprintf(fout, "%s=[]\n", path.c_str());
- int size = value.size();
- for (int index = 0; index < size; ++index) {
+ Json::ArrayIndex size = value.size();
+ for (Json::ArrayIndex index = 0; index < size; ++index) {
static char buffer[16];
-#if defined(_MSC_VER) && defined(__STDC_SECURE_LIB__)
- sprintf_s(buffer, sizeof(buffer), "[%d]", index);
-#else
- snprintf(buffer, sizeof(buffer), "[%d]", index);
-#endif
+ jsoncpp_snprintf(buffer, sizeof(buffer), "[%u]", index);
printValueTree(fout, value[index], path + buffer);
}
} break;
@@ -109,11 +110,8 @@ printValueTree(FILE* fout, Json::Value& value, const std::string& path = ".") {
fprintf(fout, "%s={}\n", path.c_str());
Json::Value::Members members(value.getMemberNames());
std::sort(members.begin(), members.end());
- std::string suffix = *(path.end() - 1) == '.' ? "" : ".";
- for (Json::Value::Members::iterator it = members.begin();
- it != members.end();
- ++it) {
- const std::string& name = *it;
+ Json::String suffix = *(path.end() - 1) == '.' ? "" : ".";
+ for (const auto& name : members) {
printValueTree(fout, value[name], path + suffix + name);
}
} break;
@@ -126,152 +124,219 @@ printValueTree(FILE* fout, Json::Value& value, const std::string& path = ".") {
}
}
-static int parseAndSaveValueTree(const std::string& input,
- const std::string& actual,
- const std::string& kind,
- Json::Value& root,
- const Json::Features& features,
- bool parseOnly) {
- Json::Reader reader(features);
- bool parsingSuccessful = reader.parse(input, root);
- if (!parsingSuccessful) {
- printf("Failed to parse %s file: \n%s\n",
- kind.c_str(),
- reader.getFormattedErrorMessages().c_str());
- return 1;
+static int parseAndSaveValueTree(const Json::String& input,
+ const Json::String& actual,
+ const Json::String& kind,
+ const Json::Features& features, bool parseOnly,
+ Json::Value* root, bool use_legacy) {
+ if (!use_legacy) {
+ Json::CharReaderBuilder builder;
+
+ builder.settings_["allowComments"] = features.allowComments_;
+ builder.settings_["strictRoot"] = features.strictRoot_;
+ builder.settings_["allowDroppedNullPlaceholders"] =
+ features.allowDroppedNullPlaceholders_;
+ builder.settings_["allowNumericKeys"] = features.allowNumericKeys_;
+
+ std::unique_ptr<Json::CharReader> reader(builder.newCharReader());
+ Json::String errors;
+ const bool parsingSuccessful =
+ reader->parse(input.data(), input.data() + input.size(), root, &errors);
+
+ if (!parsingSuccessful) {
+ std::cerr << "Failed to parse " << kind << " file: " << std::endl
+ << errors << std::endl;
+ return 1;
+ }
+
+ // We may instead check the legacy implementation (to ensure it doesn't
+ // randomly get broken).
+ } else {
+ Json::Reader reader(features);
+ const bool parsingSuccessful =
+ reader.parse(input.data(), input.data() + input.size(), *root);
+ if (!parsingSuccessful) {
+ std::cerr << "Failed to parse " << kind << " file: " << std::endl
+ << reader.getFormatedErrorMessages() << std::endl;
+ return 1;
+ }
}
if (!parseOnly) {
FILE* factual = fopen(actual.c_str(), "wt");
if (!factual) {
- printf("Failed to create %s actual file.\n", kind.c_str());
+ std::cerr << "Failed to create '" << kind << "' actual file."
+ << std::endl;
return 2;
}
- printValueTree(factual, root);
+ printValueTree(factual, *root);
fclose(factual);
}
return 0;
}
-
-static int rewriteValueTree(const std::string& rewritePath,
- const Json::Value& root,
- std::string& rewrite) {
- // Json::FastWriter writer;
- // writer.enableYAMLCompatibility();
+// static Json::String useFastWriter(Json::Value const& root) {
+// Json::FastWriter writer;
+// writer.enableYAMLCompatibility();
+// return writer.write(root);
+// }
+static Json::String useStyledWriter(Json::Value const& root) {
Json::StyledWriter writer;
- rewrite = writer.write(root);
+ return writer.write(root);
+}
+static Json::String useStyledStreamWriter(Json::Value const& root) {
+ Json::StyledStreamWriter writer;
+ Json::OStringStream sout;
+ writer.write(sout, root);
+ return sout.str();
+}
+static Json::String useBuiltStyledStreamWriter(Json::Value const& root) {
+ Json::StreamWriterBuilder builder;
+ return Json::writeString(builder, root);
+}
+static int rewriteValueTree(const Json::String& rewritePath,
+ const Json::Value& root,
+ Options::writeFuncType write,
+ Json::String* rewrite) {
+ *rewrite = write(root);
FILE* fout = fopen(rewritePath.c_str(), "wt");
if (!fout) {
- printf("Failed to create rewrite file: %s\n", rewritePath.c_str());
+ std::cerr << "Failed to create rewrite file: " << rewritePath << std::endl;
return 2;
}
- fprintf(fout, "%s\n", rewrite.c_str());
+ fprintf(fout, "%s\n", rewrite->c_str());
fclose(fout);
return 0;
}
-static std::string removeSuffix(const std::string& path,
- const std::string& extension) {
+static Json::String removeSuffix(const Json::String& path,
+ const Json::String& extension) {
if (extension.length() >= path.length())
- return std::string("");
- std::string suffix = path.substr(path.length() - extension.length());
+ return Json::String("");
+ Json::String suffix = path.substr(path.length() - extension.length());
if (suffix != extension)
- return std::string("");
+ return Json::String("");
return path.substr(0, path.length() - extension.length());
}
static void printConfig() {
// Print the configuration used to compile JsonCpp
#if defined(JSON_NO_INT64)
- printf("JSON_NO_INT64=1\n");
+ std::cout << "JSON_NO_INT64=1" << std::endl;
#else
- printf("JSON_NO_INT64=0\n");
+ std::cout << "JSON_NO_INT64=0" << std::endl;
#endif
}
static int printUsage(const char* argv[]) {
- printf("Usage: %s [--strict] input-json-file", argv[0]);
+ std::cout << "Usage: " << argv[0] << " [--strict] input-json-file"
+ << std::endl;
return 3;
}
-int parseCommandLine(int argc,
- const char* argv[],
- Json::Features& features,
- std::string& path,
- bool& parseOnly) {
- parseOnly = false;
+static int parseCommandLine(int argc, const char* argv[], Options* opts) {
+ opts->parseOnly = false;
+ opts->write = &useStyledWriter;
if (argc < 2) {
return printUsage(argv);
}
-
int index = 1;
- if (std::string(argv[1]) == "--json-checker") {
- features = Json::Features::strictMode();
- parseOnly = true;
+ if (Json::String(argv[index]) == "--json-checker") {
+ opts->features = Json::Features::strictMode();
+ opts->parseOnly = true;
++index;
}
-
- if (std::string(argv[1]) == "--json-config") {
+ if (Json::String(argv[index]) == "--json-config") {
printConfig();
return 3;
}
-
+ if (Json::String(argv[index]) == "--json-writer") {
+ ++index;
+ Json::String const writerName(argv[index++]);
+ if (writerName == "StyledWriter") {
+ opts->write = &useStyledWriter;
+ } else if (writerName == "StyledStreamWriter") {
+ opts->write = &useStyledStreamWriter;
+ } else if (writerName == "BuiltStyledStreamWriter") {
+ opts->write = &useBuiltStyledStreamWriter;
+ } else {
+ std::cerr << "Unknown '--json-writer' " << writerName << std::endl;
+ return 4;
+ }
+ }
if (index == argc || index + 1 < argc) {
return printUsage(argv);
}
-
- path = argv[index];
+ opts->path = argv[index];
return 0;
}
-int main(int argc, const char* argv[]) {
- std::string path;
- Json::Features features;
- bool parseOnly;
- int exitCode = parseCommandLine(argc, argv, features, path, parseOnly);
- if (exitCode != 0) {
+static int runTest(Options const& opts, bool use_legacy) {
+ int exitCode = 0;
+
+ Json::String input = readInputTestFile(opts.path.c_str());
+ if (input.empty()) {
+ std::cerr << "Invalid input file: " << opts.path << std::endl;
+ return 3;
+ }
+
+ Json::String basePath = removeSuffix(opts.path, ".json");
+ if (!opts.parseOnly && basePath.empty()) {
+ std::cerr << "Bad input path '" << opts.path
+ << "'. Must end with '.expected'" << std::endl;
+ return 3;
+ }
+
+ Json::String const actualPath = basePath + ".actual";
+ Json::String const rewritePath = basePath + ".rewrite";
+ Json::String const rewriteActualPath = basePath + ".actual-rewrite";
+
+ Json::Value root;
+ exitCode = parseAndSaveValueTree(input, actualPath, "input", opts.features,
+ opts.parseOnly, &root, use_legacy);
+ if (exitCode || opts.parseOnly) {
+ return exitCode;
+ }
+
+ Json::String rewrite;
+ exitCode = rewriteValueTree(rewritePath, root, opts.write, &rewrite);
+ if (exitCode) {
return exitCode;
}
+ Json::Value rewriteRoot;
+ exitCode = parseAndSaveValueTree(rewrite, rewriteActualPath, "rewrite",
+ opts.features, opts.parseOnly, &rewriteRoot,
+ use_legacy);
+
+ return exitCode;
+}
+
+int main(int argc, const char* argv[]) {
+ Options opts;
try {
- std::string input = readInputTestFile(path.c_str());
- if (input.empty()) {
- printf("Failed to read input or empty input: %s\n", path.c_str());
- return 3;
+ int exitCode = parseCommandLine(argc, argv, &opts);
+ if (exitCode != 0) {
+ std::cerr << "Failed to parse command-line." << std::endl;
+ return exitCode;
}
- std::string basePath = removeSuffix(argv[1], ".json");
- if (!parseOnly && basePath.empty()) {
- printf("Bad input path. Path does not end with '.expected':\n%s\n",
- path.c_str());
- return 3;
+ const int modern_return_code = runTest(opts, false);
+ if (modern_return_code) {
+ return modern_return_code;
}
- std::string actualPath = basePath + ".actual";
- std::string rewritePath = basePath + ".rewrite";
- std::string rewriteActualPath = basePath + ".actual-rewrite";
-
- Json::Value root;
- exitCode = parseAndSaveValueTree(
- input, actualPath, "input", root, features, parseOnly);
- if (exitCode == 0 && !parseOnly) {
- std::string rewrite;
- exitCode = rewriteValueTree(rewritePath, root, rewrite);
- if (exitCode == 0) {
- Json::Value rewriteRoot;
- exitCode = parseAndSaveValueTree(rewrite,
- rewriteActualPath,
- "rewrite",
- rewriteRoot,
- features,
- parseOnly);
- }
+ const std::string filename =
+ opts.path.substr(opts.path.find_last_of("\\/") + 1);
+ const bool should_run_legacy = (filename.rfind("legacy_", 0) == 0);
+ if (should_run_legacy) {
+ return runTest(opts, true);
}
+ } catch (const std::exception& e) {
+ std::cerr << "Unhandled exception:" << std::endl << e.what() << std::endl;
+ return 1;
}
- catch (const std::exception& e) {
- printf("Unhandled exception:\n%s\n", e.what());
- exitCode = 1;
- }
-
- return exitCode;
}
+
+#if defined(__GNUC__)
+#pragma GCC diagnostic pop
+#endif