mirror of
https://github.com/open-source-parsers/jsoncpp.git
synced 2025-06-07 17:14:56 +02:00
Merge pull request #136 from cdunn2001/test-both-styled-writers
Test both styled writers Not only does this now test StyledStreamWriter the same way as StyledWriter, but it also makes the former work more like the latter, indenting separate lines of a comment before a value. Might break some user tests (as `operator<<()` uses `StyledStreamWriter`) but basically a harmless improvement. All tests pass.
This commit is contained in:
commit
ddb4ff7dec
@ -8,12 +8,22 @@
|
|||||||
|
|
||||||
#include <json/json.h>
|
#include <json/json.h>
|
||||||
#include <algorithm> // sort
|
#include <algorithm> // sort
|
||||||
|
#include <sstream>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
|
|
||||||
#if defined(_MSC_VER) && _MSC_VER >= 1310
|
#if defined(_MSC_VER) && _MSC_VER >= 1310
|
||||||
#pragma warning(disable : 4996) // disable fopen deprecation warning
|
#pragma warning(disable : 4996) // disable fopen deprecation warning
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
struct Options
|
||||||
|
{
|
||||||
|
std::string path;
|
||||||
|
Json::Features features;
|
||||||
|
bool parseOnly;
|
||||||
|
typedef std::string (*writeFuncType)(Json::Value const&);
|
||||||
|
writeFuncType write;
|
||||||
|
};
|
||||||
|
|
||||||
static std::string normalizeFloatingPointStr(double value) {
|
static std::string normalizeFloatingPointStr(double value) {
|
||||||
char buffer[32];
|
char buffer[32];
|
||||||
#if defined(_MSC_VER) && defined(__STDC_SECURE_LIB__)
|
#if defined(_MSC_VER) && defined(__STDC_SECURE_LIB__)
|
||||||
@ -129,11 +139,12 @@ printValueTree(FILE* fout, Json::Value& value, const std::string& path = ".") {
|
|||||||
static int parseAndSaveValueTree(const std::string& input,
|
static int parseAndSaveValueTree(const std::string& input,
|
||||||
const std::string& actual,
|
const std::string& actual,
|
||||||
const std::string& kind,
|
const std::string& kind,
|
||||||
Json::Value& root,
|
|
||||||
const Json::Features& features,
|
const Json::Features& features,
|
||||||
bool parseOnly) {
|
bool parseOnly,
|
||||||
|
Json::Value* root)
|
||||||
|
{
|
||||||
Json::Reader reader(features);
|
Json::Reader reader(features);
|
||||||
bool parsingSuccessful = reader.parse(input, root);
|
bool parsingSuccessful = reader.parse(input, *root);
|
||||||
if (!parsingSuccessful) {
|
if (!parsingSuccessful) {
|
||||||
printf("Failed to parse %s file: \n%s\n",
|
printf("Failed to parse %s file: \n%s\n",
|
||||||
kind.c_str(),
|
kind.c_str(),
|
||||||
@ -147,25 +158,43 @@ static int parseAndSaveValueTree(const std::string& input,
|
|||||||
printf("Failed to create %s actual file.\n", kind.c_str());
|
printf("Failed to create %s actual file.\n", kind.c_str());
|
||||||
return 2;
|
return 2;
|
||||||
}
|
}
|
||||||
printValueTree(factual, root);
|
printValueTree(factual, *root);
|
||||||
fclose(factual);
|
fclose(factual);
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
// static std::string useFastWriter(Json::Value const& root) {
|
||||||
static int rewriteValueTree(const std::string& rewritePath,
|
|
||||||
const Json::Value& root,
|
|
||||||
std::string& rewrite) {
|
|
||||||
// Json::FastWriter writer;
|
// Json::FastWriter writer;
|
||||||
// writer.enableYAMLCompatibility();
|
// writer.enableYAMLCompatibility();
|
||||||
|
// return writer.write(root);
|
||||||
|
// }
|
||||||
|
static std::string useStyledWriter(
|
||||||
|
Json::Value const& root)
|
||||||
|
{
|
||||||
Json::StyledWriter writer;
|
Json::StyledWriter writer;
|
||||||
rewrite = writer.write(root);
|
return writer.write(root);
|
||||||
|
}
|
||||||
|
static std::string useStyledStreamWriter(
|
||||||
|
Json::Value const& root)
|
||||||
|
{
|
||||||
|
Json::StyledStreamWriter writer;
|
||||||
|
std::ostringstream sout;
|
||||||
|
writer.write(sout, root);
|
||||||
|
return sout.str();
|
||||||
|
}
|
||||||
|
static int rewriteValueTree(
|
||||||
|
const std::string& rewritePath,
|
||||||
|
const Json::Value& root,
|
||||||
|
Options::writeFuncType write,
|
||||||
|
std::string* rewrite)
|
||||||
|
{
|
||||||
|
*rewrite = write(root);
|
||||||
FILE* fout = fopen(rewritePath.c_str(), "wt");
|
FILE* fout = fopen(rewritePath.c_str(), "wt");
|
||||||
if (!fout) {
|
if (!fout) {
|
||||||
printf("Failed to create rewrite file: %s\n", rewritePath.c_str());
|
printf("Failed to create rewrite file: %s\n", rewritePath.c_str());
|
||||||
return 2;
|
return 2;
|
||||||
}
|
}
|
||||||
fprintf(fout, "%s\n", rewrite.c_str());
|
fprintf(fout, "%s\n", rewrite->c_str());
|
||||||
fclose(fout);
|
fclose(fout);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@ -194,84 +223,96 @@ static int printUsage(const char* argv[]) {
|
|||||||
return 3;
|
return 3;
|
||||||
}
|
}
|
||||||
|
|
||||||
int parseCommandLine(int argc,
|
static int parseCommandLine(
|
||||||
const char* argv[],
|
int argc, const char* argv[], Options* opts)
|
||||||
Json::Features& features,
|
{
|
||||||
std::string& path,
|
opts->parseOnly = false;
|
||||||
bool& parseOnly) {
|
opts->write = &useStyledWriter;
|
||||||
parseOnly = false;
|
|
||||||
if (argc < 2) {
|
if (argc < 2) {
|
||||||
return printUsage(argv);
|
return printUsage(argv);
|
||||||
}
|
}
|
||||||
|
|
||||||
int index = 1;
|
int index = 1;
|
||||||
if (std::string(argv[1]) == "--json-checker") {
|
if (std::string(argv[index]) == "--json-checker") {
|
||||||
features = Json::Features::strictMode();
|
opts->features = Json::Features::strictMode();
|
||||||
parseOnly = true;
|
opts->parseOnly = true;
|
||||||
++index;
|
++index;
|
||||||
}
|
}
|
||||||
|
if (std::string(argv[index]) == "--json-config") {
|
||||||
if (std::string(argv[1]) == "--json-config") {
|
|
||||||
printConfig();
|
printConfig();
|
||||||
return 3;
|
return 3;
|
||||||
}
|
}
|
||||||
|
if (std::string(argv[index]) == "--json-writer") {
|
||||||
|
++index;
|
||||||
|
std::string const writerName(argv[index++]);
|
||||||
|
if (writerName == "StyledWriter") {
|
||||||
|
opts->write = &useStyledWriter;
|
||||||
|
} else if (writerName == "StyledStreamWriter") {
|
||||||
|
opts->write = &useStyledStreamWriter;
|
||||||
|
} else {
|
||||||
|
printf("Unknown '--json-writer %s'\n", writerName.c_str());
|
||||||
|
return 4;
|
||||||
|
}
|
||||||
|
}
|
||||||
if (index == argc || index + 1 < argc) {
|
if (index == argc || index + 1 < argc) {
|
||||||
return printUsage(argv);
|
return printUsage(argv);
|
||||||
}
|
}
|
||||||
|
opts->path = argv[index];
|
||||||
path = argv[index];
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
static int runTest(Options const& opts)
|
||||||
|
{
|
||||||
|
int exitCode = 0;
|
||||||
|
|
||||||
int main(int argc, const char* argv[]) {
|
std::string input = readInputTestFile(opts.path.c_str());
|
||||||
std::string path;
|
|
||||||
Json::Features features;
|
|
||||||
bool parseOnly;
|
|
||||||
int exitCode = parseCommandLine(argc, argv, features, path, parseOnly);
|
|
||||||
if (exitCode != 0) {
|
|
||||||
return exitCode;
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
|
||||||
std::string input = readInputTestFile(path.c_str());
|
|
||||||
if (input.empty()) {
|
if (input.empty()) {
|
||||||
printf("Failed to read input or empty input: %s\n", path.c_str());
|
printf("Failed to read input or empty input: %s\n", opts.path.c_str());
|
||||||
return 3;
|
return 3;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string basePath = removeSuffix(argv[1], ".json");
|
std::string basePath = removeSuffix(opts.path, ".json");
|
||||||
if (!parseOnly && basePath.empty()) {
|
if (!opts.parseOnly && basePath.empty()) {
|
||||||
printf("Bad input path. Path does not end with '.expected':\n%s\n",
|
printf("Bad input path. Path does not end with '.expected':\n%s\n",
|
||||||
path.c_str());
|
opts.path.c_str());
|
||||||
return 3;
|
return 3;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string actualPath = basePath + ".actual";
|
std::string const actualPath = basePath + ".actual";
|
||||||
std::string rewritePath = basePath + ".rewrite";
|
std::string const rewritePath = basePath + ".rewrite";
|
||||||
std::string rewriteActualPath = basePath + ".actual-rewrite";
|
std::string const rewriteActualPath = basePath + ".actual-rewrite";
|
||||||
|
|
||||||
Json::Value root;
|
Json::Value root;
|
||||||
exitCode = parseAndSaveValueTree(
|
exitCode = parseAndSaveValueTree(
|
||||||
input, actualPath, "input", root, features, parseOnly);
|
input, actualPath, "input",
|
||||||
if (exitCode == 0 && !parseOnly) {
|
opts.features, opts.parseOnly, &root);
|
||||||
|
if (exitCode || opts.parseOnly) {
|
||||||
|
return exitCode;
|
||||||
|
}
|
||||||
std::string rewrite;
|
std::string rewrite;
|
||||||
exitCode = rewriteValueTree(rewritePath, root, rewrite);
|
exitCode = rewriteValueTree(rewritePath, root, opts.write, &rewrite);
|
||||||
if (exitCode == 0) {
|
if (exitCode) {
|
||||||
|
return exitCode;
|
||||||
|
}
|
||||||
Json::Value rewriteRoot;
|
Json::Value rewriteRoot;
|
||||||
exitCode = parseAndSaveValueTree(rewrite,
|
exitCode = parseAndSaveValueTree(
|
||||||
rewriteActualPath,
|
rewrite, rewriteActualPath, "rewrite",
|
||||||
"rewrite",
|
opts.features, opts.parseOnly, &rewriteRoot);
|
||||||
rewriteRoot,
|
if (exitCode) {
|
||||||
features,
|
return exitCode;
|
||||||
parseOnly);
|
|
||||||
}
|
}
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
int main(int argc, const char* argv[]) {
|
||||||
|
Options opts;
|
||||||
|
int exitCode = parseCommandLine(argc, argv, &opts);
|
||||||
|
if (exitCode != 0) {
|
||||||
|
printf("Failed to parse command-line.");
|
||||||
|
return exitCode;
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
return runTest(opts);
|
||||||
}
|
}
|
||||||
catch (const std::exception& e) {
|
catch (const std::exception& e) {
|
||||||
printf("Unhandled exception:\n%s\n", e.what());
|
printf("Unhandled exception:\n%s\n", e.what());
|
||||||
exitCode = 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
return exitCode;
|
|
||||||
}
|
}
|
||||||
|
@ -628,7 +628,20 @@ void StyledStreamWriter::unindent() {
|
|||||||
void StyledStreamWriter::writeCommentBeforeValue(const Value& root) {
|
void StyledStreamWriter::writeCommentBeforeValue(const Value& root) {
|
||||||
if (!root.hasComment(commentBefore))
|
if (!root.hasComment(commentBefore))
|
||||||
return;
|
return;
|
||||||
*document_ << root.getComment(commentBefore);
|
|
||||||
|
*document_ << "\n";
|
||||||
|
writeIndent();
|
||||||
|
const std::string& comment = root.getComment(commentBefore);
|
||||||
|
std::string::const_iterator iter = comment.begin();
|
||||||
|
while (iter != comment.end()) {
|
||||||
|
*document_ << *iter;
|
||||||
|
if (*iter == '\n' &&
|
||||||
|
(iter != comment.end() && *(iter + 1) == '/'))
|
||||||
|
writeIndent();
|
||||||
|
++iter;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Comments are stripped of trailing newlines, so add one here
|
||||||
*document_ << "\n";
|
*document_ << "\n";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -14,6 +14,7 @@ def getStatusOutput(cmd):
|
|||||||
Return int, unicode (for both Python 2 and 3).
|
Return int, unicode (for both Python 2 and 3).
|
||||||
Note: os.popen().close() would return None for 0.
|
Note: os.popen().close() would return None for 0.
|
||||||
"""
|
"""
|
||||||
|
print(cmd, file=sys.stderr)
|
||||||
pipe = os.popen(cmd)
|
pipe = os.popen(cmd)
|
||||||
process_output = pipe.read()
|
process_output = pipe.read()
|
||||||
try:
|
try:
|
||||||
@ -57,7 +58,8 @@ def safeReadFile( path ):
|
|||||||
return '<File "%s" is missing: %s>' % (path,e)
|
return '<File "%s" is missing: %s>' % (path,e)
|
||||||
|
|
||||||
def runAllTests( jsontest_executable_path, input_dir = None,
|
def runAllTests( jsontest_executable_path, input_dir = None,
|
||||||
use_valgrind=False, with_json_checker=False ):
|
use_valgrind=False, with_json_checker=False,
|
||||||
|
writerClass='StyledWriter'):
|
||||||
if not input_dir:
|
if not input_dir:
|
||||||
input_dir = os.path.join( os.getcwd(), 'data' )
|
input_dir = os.path.join( os.getcwd(), 'data' )
|
||||||
tests = glob( os.path.join( input_dir, '*.json' ) )
|
tests = glob( os.path.join( input_dir, '*.json' ) )
|
||||||
@ -72,6 +74,7 @@ def runAllTests( jsontest_executable_path, input_dir = None,
|
|||||||
is_json_checker_test = (input_path in test_jsonchecker) or expect_failure
|
is_json_checker_test = (input_path in test_jsonchecker) or expect_failure
|
||||||
print('TESTING:', input_path, end=' ')
|
print('TESTING:', input_path, end=' ')
|
||||||
options = is_json_checker_test and '--json-checker' or ''
|
options = is_json_checker_test and '--json-checker' or ''
|
||||||
|
options += ' --json-writer %s'%writerClass
|
||||||
cmd = '%s%s %s "%s"' % (
|
cmd = '%s%s %s "%s"' % (
|
||||||
valgrind_path, jsontest_executable_path, options,
|
valgrind_path, jsontest_executable_path, options,
|
||||||
input_path)
|
input_path)
|
||||||
@ -145,7 +148,15 @@ def main():
|
|||||||
else:
|
else:
|
||||||
input_path = None
|
input_path = None
|
||||||
status = runAllTests( jsontest_executable_path, input_path,
|
status = runAllTests( jsontest_executable_path, input_path,
|
||||||
use_valgrind=options.valgrind, with_json_checker=options.with_json_checker )
|
use_valgrind=options.valgrind,
|
||||||
|
with_json_checker=options.with_json_checker,
|
||||||
|
writerClass='StyledWriter')
|
||||||
|
if status:
|
||||||
|
sys.exit( status )
|
||||||
|
status = runAllTests( jsontest_executable_path, input_path,
|
||||||
|
use_valgrind=options.valgrind,
|
||||||
|
with_json_checker=options.with_json_checker,
|
||||||
|
writerClass='StyledStreamWriter')
|
||||||
sys.exit( status )
|
sys.exit( status )
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
|
Loading…
x
Reference in New Issue
Block a user