mirror of
https://github.com/open-source-parsers/jsoncpp.git
synced 2025-05-29 22:32:42 +02:00
- added Features class that describes allowed extension for Reader, to allow for strict configuration
- added tests from json.org jsonchecker and modified jsontestrunner to use strict parsing mode when executing them
This commit is contained in:
parent
64e07e54ed
commit
8868147835
@ -42,3 +42,6 @@ and TARGET may be:
|
|||||||
doc: build documentation
|
doc: build documentation
|
||||||
doc-dist: build documentation tarball
|
doc-dist: build documentation tarball
|
||||||
|
|
||||||
|
To run the test manually:
|
||||||
|
cd test
|
||||||
|
python runjsontests.py "path to jsontest.exe"
|
||||||
|
42
include/json/features.h
Normal file
42
include/json/features.h
Normal file
@ -0,0 +1,42 @@
|
|||||||
|
#ifndef CPPTL_JSON_FEATURES_H_INCLUDED
|
||||||
|
# define CPPTL_JSON_FEATURES_H_INCLUDED
|
||||||
|
|
||||||
|
# include "forwards.h"
|
||||||
|
|
||||||
|
namespace Json {
|
||||||
|
|
||||||
|
/** \brief Configuration passed to reader and writer.
|
||||||
|
* This configuration object can be used to force the Reader or Writer
|
||||||
|
* to behave in a standard conforming way.
|
||||||
|
*/
|
||||||
|
class JSON_API Features
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
/** \brief A configuration that allows all features and assumes all strings are UTF-8.
|
||||||
|
* - C & C++ comments are allowed
|
||||||
|
* - Root object can be any JSON value
|
||||||
|
* - Assumes Value strings are encoded in UTF-8
|
||||||
|
*/
|
||||||
|
static Features all();
|
||||||
|
|
||||||
|
/** \brief A configuration that is strictly compatible with the JSON specification.
|
||||||
|
* - Comments are forbidden.
|
||||||
|
* - Root object must be either an array or an object value.
|
||||||
|
* - Assumes Value strings are encoded in UTF-8
|
||||||
|
*/
|
||||||
|
static Features strictMode();
|
||||||
|
|
||||||
|
/** \brief Initialize the configuration like JsonConfig::allFeatures;
|
||||||
|
*/
|
||||||
|
Features();
|
||||||
|
|
||||||
|
/// \c true if comments are allowed. Default: \c true.
|
||||||
|
bool allowComments_;
|
||||||
|
|
||||||
|
/// \c true if root must be either an array or an object value. Default: \c false.
|
||||||
|
bool strictRoot_;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace Json
|
||||||
|
|
||||||
|
#endif // CPPTL_JSON_FEATURES_H_INCLUDED
|
@ -9,6 +9,9 @@ namespace Json {
|
|||||||
class Reader;
|
class Reader;
|
||||||
class StyledWriter;
|
class StyledWriter;
|
||||||
|
|
||||||
|
// features.h
|
||||||
|
class Features;
|
||||||
|
|
||||||
// value.h
|
// value.h
|
||||||
class StaticString;
|
class StaticString;
|
||||||
class Path;
|
class Path;
|
||||||
|
@ -5,5 +5,6 @@
|
|||||||
# include "value.h"
|
# include "value.h"
|
||||||
# include "reader.h"
|
# include "reader.h"
|
||||||
# include "writer.h"
|
# include "writer.h"
|
||||||
|
# include "features.h"
|
||||||
|
|
||||||
#endif // JSON_JSON_H_INCLUDED
|
#endif // JSON_JSON_H_INCLUDED
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
#ifndef CPPTL_JSON_READER_H_INCLUDED
|
#ifndef CPPTL_JSON_READER_H_INCLUDED
|
||||||
# define CPPTL_JSON_READER_H_INCLUDED
|
# define CPPTL_JSON_READER_H_INCLUDED
|
||||||
|
|
||||||
# include "forwards.h"
|
# include "features.h"
|
||||||
# include "value.h"
|
# include "value.h"
|
||||||
# include <deque>
|
# include <deque>
|
||||||
# include <stack>
|
# include <stack>
|
||||||
@ -10,10 +10,7 @@
|
|||||||
|
|
||||||
namespace Json {
|
namespace Json {
|
||||||
|
|
||||||
class Value;
|
|
||||||
|
|
||||||
/** \brief Unserialize a <a HREF="http://www.json.org">JSON</a> document into a Value.
|
/** \brief Unserialize a <a HREF="http://www.json.org">JSON</a> document into a Value.
|
||||||
*
|
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
class JSON_API Reader
|
class JSON_API Reader
|
||||||
@ -22,14 +19,24 @@ namespace Json {
|
|||||||
typedef char Char;
|
typedef char Char;
|
||||||
typedef const Char *Location;
|
typedef const Char *Location;
|
||||||
|
|
||||||
|
/** \brief Constructs a Reader allowing all features
|
||||||
|
* for parsing.
|
||||||
|
*/
|
||||||
Reader();
|
Reader();
|
||||||
|
|
||||||
|
/** \brief Constructs a Reader allowing the specified feature set
|
||||||
|
* for parsing.
|
||||||
|
*/
|
||||||
|
Reader( const Features &features );
|
||||||
|
|
||||||
/** \brief Read a Value from a <a HREF="http://www.json.org">JSON</a> document.
|
/** \brief Read a Value from a <a HREF="http://www.json.org">JSON</a> document.
|
||||||
* \param document UTF-8 encoded string containing the document to read.
|
* \param document UTF-8 encoded string containing the document to read.
|
||||||
* \param root [out] Contains the root value of the document if it was
|
* \param root [out] Contains the root value of the document if it was
|
||||||
* successfully parsed.
|
* successfully parsed.
|
||||||
* \param collectComments \c true to collect comment and allow writing them back during
|
* \param collectComments \c true to collect comment and allow writing them back during
|
||||||
* serialization, \c false to discard comments.
|
* serialization, \c false to discard comments.
|
||||||
|
* This parameter is ignored if Features::allowComments_
|
||||||
|
* is \c false.
|
||||||
* \return \c true if the document was successfully parsed, \c false if an error occurred.
|
* \return \c true if the document was successfully parsed, \c false if an error occurred.
|
||||||
*/
|
*/
|
||||||
bool parse( const std::string &document,
|
bool parse( const std::string &document,
|
||||||
@ -42,6 +49,8 @@ namespace Json {
|
|||||||
* successfully parsed.
|
* successfully parsed.
|
||||||
* \param collectComments \c true to collect comment and allow writing them back during
|
* \param collectComments \c true to collect comment and allow writing them back during
|
||||||
* serialization, \c false to discard comments.
|
* serialization, \c false to discard comments.
|
||||||
|
* This parameter is ignored if Features::allowComments_
|
||||||
|
* is \c false.
|
||||||
* \return \c true if the document was successfully parsed, \c false if an error occurred.
|
* \return \c true if the document was successfully parsed, \c false if an error occurred.
|
||||||
*/
|
*/
|
||||||
bool parse( const char *beginDoc, const char *endDoc,
|
bool parse( const char *beginDoc, const char *endDoc,
|
||||||
@ -50,7 +59,7 @@ namespace Json {
|
|||||||
|
|
||||||
/// \brief Parse from input stream.
|
/// \brief Parse from input stream.
|
||||||
/// \see Json::operator>>(std::istream&, Json::Value&).
|
/// \see Json::operator>>(std::istream&, Json::Value&).
|
||||||
bool parse( std::istream&,
|
bool parse( std::istream &is,
|
||||||
Value &root,
|
Value &root,
|
||||||
bool collectComments = true );
|
bool collectComments = true );
|
||||||
|
|
||||||
@ -152,6 +161,7 @@ namespace Json {
|
|||||||
Location lastValueEnd_;
|
Location lastValueEnd_;
|
||||||
Value *lastValue_;
|
Value *lastValue_;
|
||||||
std::string commentsBefore_;
|
std::string commentsBefore_;
|
||||||
|
Features features_;
|
||||||
bool collectComments_;
|
bool collectComments_;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -86,9 +86,11 @@ static int
|
|||||||
parseAndSaveValueTree( const std::string &input,
|
parseAndSaveValueTree( const std::string &input,
|
||||||
const std::string &actual,
|
const std::string &actual,
|
||||||
const std::string &kind,
|
const std::string &kind,
|
||||||
Json::Value &root )
|
Json::Value &root,
|
||||||
|
const Json::Features &features,
|
||||||
|
bool parseOnly )
|
||||||
{
|
{
|
||||||
Json::Reader reader;
|
Json::Reader reader( features );
|
||||||
bool parsingSuccessful = reader.parse( input, root );
|
bool parsingSuccessful = reader.parse( input, root );
|
||||||
if ( !parsingSuccessful )
|
if ( !parsingSuccessful )
|
||||||
{
|
{
|
||||||
@ -98,14 +100,17 @@ parseAndSaveValueTree( const std::string &input,
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
FILE *factual = fopen( actual.c_str(), "wt" );
|
if ( !parseOnly )
|
||||||
if ( !factual )
|
|
||||||
{
|
{
|
||||||
printf( "Failed to create %s actual file.\n", kind.c_str() );
|
FILE *factual = fopen( actual.c_str(), "wt" );
|
||||||
return 2;
|
if ( !factual )
|
||||||
|
{
|
||||||
|
printf( "Failed to create %s actual file.\n", kind.c_str() );
|
||||||
|
return 2;
|
||||||
|
}
|
||||||
|
printValueTree( factual, root );
|
||||||
|
fclose( factual );
|
||||||
}
|
}
|
||||||
printValueTree( factual, root );
|
|
||||||
fclose( factual );
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -143,25 +148,65 @@ removeSuffix( const std::string &path,
|
|||||||
return path.substr( 0, path.length() - extension.length() );
|
return path.substr( 0, path.length() - extension.length() );
|
||||||
}
|
}
|
||||||
|
|
||||||
int main( int argc, const char *argv[] )
|
static int
|
||||||
|
printUsage( const char *argv[] )
|
||||||
{
|
{
|
||||||
if ( argc != 2 )
|
printf( "Usage: %s [--strict] input-json-file", argv[0] );
|
||||||
|
return 3;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int
|
||||||
|
parseCommandLine( int argc, const char *argv[],
|
||||||
|
Json::Features &features, std::string &path,
|
||||||
|
bool &parseOnly )
|
||||||
|
{
|
||||||
|
parseOnly = false;
|
||||||
|
if ( argc < 2 )
|
||||||
{
|
{
|
||||||
printf( "Usage: %s input-json-file", argv[0] );
|
return printUsage( argv );
|
||||||
return 3;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string input = readInputTestFile( argv[1] );
|
int index = 1;
|
||||||
|
if ( std::string(argv[1]) == "--json-checker" )
|
||||||
|
{
|
||||||
|
features = Json::Features::strictMode();
|
||||||
|
parseOnly = true;
|
||||||
|
++index;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( index == argc || index + 1 < argc )
|
||||||
|
{
|
||||||
|
return printUsage( argv );
|
||||||
|
}
|
||||||
|
|
||||||
|
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 )
|
||||||
|
{
|
||||||
|
return exitCode;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string input = readInputTestFile( path.c_str() );
|
||||||
if ( input.empty() )
|
if ( input.empty() )
|
||||||
{
|
{
|
||||||
printf( "Failed to read input or empty input: %s\n", argv[1] );
|
printf( "Failed to read input or empty input: %s\n", path.c_str() );
|
||||||
return 3;
|
return 3;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string basePath = removeSuffix( argv[1], ".json" );
|
std::string basePath = removeSuffix( argv[1], ".json" );
|
||||||
if ( basePath.empty() )
|
if ( !parseOnly && basePath.empty() )
|
||||||
{
|
{
|
||||||
printf( "Bad input path. Path does not end with '.expected':\n%s\n", argv[1] );
|
printf( "Bad input path. Path does not end with '.expected':\n%s\n", path.c_str() );
|
||||||
return 3;
|
return 3;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -170,15 +215,16 @@ int main( int argc, const char *argv[] )
|
|||||||
std::string rewriteActualPath = basePath + ".actual-rewrite";
|
std::string rewriteActualPath = basePath + ".actual-rewrite";
|
||||||
|
|
||||||
Json::Value root;
|
Json::Value root;
|
||||||
int exitCode = parseAndSaveValueTree( input, actualPath, "input", root );
|
exitCode = parseAndSaveValueTree( input, actualPath, "input", root, features, parseOnly );
|
||||||
if ( exitCode == 0 )
|
if ( exitCode == 0 && !parseOnly )
|
||||||
{
|
{
|
||||||
std::string rewrite;
|
std::string rewrite;
|
||||||
exitCode = rewriteValueTree( rewritePath, root, rewrite );
|
exitCode = rewriteValueTree( rewritePath, root, rewrite );
|
||||||
if ( exitCode == 0 )
|
if ( exitCode == 0 )
|
||||||
{
|
{
|
||||||
Json::Value rewriteRoot;
|
Json::Value rewriteRoot;
|
||||||
exitCode = parseAndSaveValueTree( rewrite, rewriteActualPath, "rewrite", rewriteRoot );
|
exitCode = parseAndSaveValueTree( rewrite, rewriteActualPath,
|
||||||
|
"rewrite", rewriteRoot, features, parseOnly );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -13,6 +13,36 @@
|
|||||||
|
|
||||||
namespace Json {
|
namespace Json {
|
||||||
|
|
||||||
|
// Implementation of class Features
|
||||||
|
// ////////////////////////////////
|
||||||
|
|
||||||
|
Features::Features()
|
||||||
|
: allowComments_( true )
|
||||||
|
, strictRoot_( false )
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Features
|
||||||
|
Features::all()
|
||||||
|
{
|
||||||
|
return Features();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Features
|
||||||
|
Features::strictMode()
|
||||||
|
{
|
||||||
|
Features features;
|
||||||
|
features.allowComments_ = false;
|
||||||
|
features.strictRoot_ = true;
|
||||||
|
return features;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Implementation of class Reader
|
||||||
|
// ////////////////////////////////
|
||||||
|
|
||||||
|
|
||||||
static inline bool
|
static inline bool
|
||||||
in( Reader::Char c, Reader::Char c1, Reader::Char c2, Reader::Char c3, Reader::Char c4 )
|
in( Reader::Char c, Reader::Char c1, Reader::Char c2, Reader::Char c3, Reader::Char c4 )
|
||||||
{
|
{
|
||||||
@ -77,9 +107,17 @@ static std::string codePointToUTF8(unsigned int cp)
|
|||||||
// //////////////////////////////////////////////////////////////////
|
// //////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
Reader::Reader()
|
Reader::Reader()
|
||||||
|
: features_( Features::all() )
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Reader::Reader( const Features &features )
|
||||||
|
: features_( features )
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
bool
|
bool
|
||||||
Reader::parse( const std::string &document,
|
Reader::parse( const std::string &document,
|
||||||
Value &root,
|
Value &root,
|
||||||
@ -91,6 +129,7 @@ Reader::parse( const std::string &document,
|
|||||||
return parse( begin, end, root, collectComments );
|
return parse( begin, end, root, collectComments );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
bool
|
bool
|
||||||
Reader::parse( std::istream& sin,
|
Reader::parse( std::istream& sin,
|
||||||
Value &root,
|
Value &root,
|
||||||
@ -113,6 +152,11 @@ Reader::parse( const char *beginDoc, const char *endDoc,
|
|||||||
Value &root,
|
Value &root,
|
||||||
bool collectComments )
|
bool collectComments )
|
||||||
{
|
{
|
||||||
|
if ( !features_.allowComments_ )
|
||||||
|
{
|
||||||
|
collectComments = false;
|
||||||
|
}
|
||||||
|
|
||||||
begin_ = beginDoc;
|
begin_ = beginDoc;
|
||||||
end_ = endDoc;
|
end_ = endDoc;
|
||||||
collectComments_ = collectComments;
|
collectComments_ = collectComments;
|
||||||
@ -130,6 +174,19 @@ Reader::parse( const char *beginDoc, const char *endDoc,
|
|||||||
skipCommentTokens( token );
|
skipCommentTokens( token );
|
||||||
if ( collectComments_ && !commentsBefore_.empty() )
|
if ( collectComments_ && !commentsBefore_.empty() )
|
||||||
root.setComment( commentsBefore_, commentAfter );
|
root.setComment( commentsBefore_, commentAfter );
|
||||||
|
if ( features_.strictRoot_ )
|
||||||
|
{
|
||||||
|
if ( !root.isArray() && !root.isObject() )
|
||||||
|
{
|
||||||
|
// Set error location to start of doc, ideally should be first token found in doc
|
||||||
|
token.type_ = tokenError;
|
||||||
|
token.start_ = beginDoc;
|
||||||
|
token.end_ = endDoc;
|
||||||
|
addError( "A valid JSON document must be either an array or an object value.",
|
||||||
|
token );
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
return successful;
|
return successful;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -188,11 +245,18 @@ Reader::readValue()
|
|||||||
void
|
void
|
||||||
Reader::skipCommentTokens( Token &token )
|
Reader::skipCommentTokens( Token &token )
|
||||||
{
|
{
|
||||||
do
|
if ( features_.allowComments_ )
|
||||||
|
{
|
||||||
|
do
|
||||||
|
{
|
||||||
|
readToken( token );
|
||||||
|
}
|
||||||
|
while ( token.type_ == tokenComment );
|
||||||
|
}
|
||||||
|
else
|
||||||
{
|
{
|
||||||
readToken( token );
|
readToken( token );
|
||||||
}
|
}
|
||||||
while ( token.type_ == tokenComment );
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -169,6 +169,9 @@
|
|||||||
<File
|
<File
|
||||||
RelativePath="..\..\include\json\config.h">
|
RelativePath="..\..\include\json\config.h">
|
||||||
</File>
|
</File>
|
||||||
|
<File
|
||||||
|
RelativePath="..\..\include\json\features.h">
|
||||||
|
</File>
|
||||||
<File
|
<File
|
||||||
RelativePath="..\..\include\json\forwards.h">
|
RelativePath="..\..\include\json\forwards.h">
|
||||||
</File>
|
</File>
|
||||||
|
1
test/jsonchecker/fail1.json
Normal file
1
test/jsonchecker/fail1.json
Normal file
@ -0,0 +1 @@
|
|||||||
|
"A JSON payload should be an object or array, not a string."
|
1
test/jsonchecker/fail10.json
Normal file
1
test/jsonchecker/fail10.json
Normal file
@ -0,0 +1 @@
|
|||||||
|
{"Extra value after close": true} "misplaced quoted value"
|
1
test/jsonchecker/fail11.json
Normal file
1
test/jsonchecker/fail11.json
Normal file
@ -0,0 +1 @@
|
|||||||
|
{"Illegal expression": 1 + 2}
|
1
test/jsonchecker/fail12.json
Normal file
1
test/jsonchecker/fail12.json
Normal file
@ -0,0 +1 @@
|
|||||||
|
{"Illegal invocation": alert()}
|
1
test/jsonchecker/fail13.json
Normal file
1
test/jsonchecker/fail13.json
Normal file
@ -0,0 +1 @@
|
|||||||
|
{"Numbers cannot have leading zeroes": 013}
|
1
test/jsonchecker/fail14.json
Normal file
1
test/jsonchecker/fail14.json
Normal file
@ -0,0 +1 @@
|
|||||||
|
{"Numbers cannot be hex": 0x14}
|
1
test/jsonchecker/fail15.json
Normal file
1
test/jsonchecker/fail15.json
Normal file
@ -0,0 +1 @@
|
|||||||
|
["Illegal backslash escape: \x15"]
|
1
test/jsonchecker/fail16.json
Normal file
1
test/jsonchecker/fail16.json
Normal file
@ -0,0 +1 @@
|
|||||||
|
[\naked]
|
1
test/jsonchecker/fail17.json
Normal file
1
test/jsonchecker/fail17.json
Normal file
@ -0,0 +1 @@
|
|||||||
|
["Illegal backslash escape: \017"]
|
1
test/jsonchecker/fail18.json
Normal file
1
test/jsonchecker/fail18.json
Normal file
@ -0,0 +1 @@
|
|||||||
|
[[[[[[[[[[[[[[[[[[[["Too deep"]]]]]]]]]]]]]]]]]]]]
|
1
test/jsonchecker/fail19.json
Normal file
1
test/jsonchecker/fail19.json
Normal file
@ -0,0 +1 @@
|
|||||||
|
{"Missing colon" null}
|
1
test/jsonchecker/fail2.json
Normal file
1
test/jsonchecker/fail2.json
Normal file
@ -0,0 +1 @@
|
|||||||
|
["Unclosed array"
|
1
test/jsonchecker/fail20.json
Normal file
1
test/jsonchecker/fail20.json
Normal file
@ -0,0 +1 @@
|
|||||||
|
{"Double colon":: null}
|
1
test/jsonchecker/fail21.json
Normal file
1
test/jsonchecker/fail21.json
Normal file
@ -0,0 +1 @@
|
|||||||
|
{"Comma instead of colon", null}
|
1
test/jsonchecker/fail22.json
Normal file
1
test/jsonchecker/fail22.json
Normal file
@ -0,0 +1 @@
|
|||||||
|
["Colon instead of comma": false]
|
1
test/jsonchecker/fail23.json
Normal file
1
test/jsonchecker/fail23.json
Normal file
@ -0,0 +1 @@
|
|||||||
|
["Bad value", truth]
|
1
test/jsonchecker/fail24.json
Normal file
1
test/jsonchecker/fail24.json
Normal file
@ -0,0 +1 @@
|
|||||||
|
['single quote']
|
1
test/jsonchecker/fail25.json
Normal file
1
test/jsonchecker/fail25.json
Normal file
@ -0,0 +1 @@
|
|||||||
|
[" tab character in string "]
|
1
test/jsonchecker/fail26.json
Normal file
1
test/jsonchecker/fail26.json
Normal file
@ -0,0 +1 @@
|
|||||||
|
["tab\ character\ in\ string\ "]
|
2
test/jsonchecker/fail27.json
Normal file
2
test/jsonchecker/fail27.json
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
["line
|
||||||
|
break"]
|
2
test/jsonchecker/fail28.json
Normal file
2
test/jsonchecker/fail28.json
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
["line\
|
||||||
|
break"]
|
1
test/jsonchecker/fail29.json
Normal file
1
test/jsonchecker/fail29.json
Normal file
@ -0,0 +1 @@
|
|||||||
|
[0e]
|
1
test/jsonchecker/fail3.json
Normal file
1
test/jsonchecker/fail3.json
Normal file
@ -0,0 +1 @@
|
|||||||
|
{unquoted_key: "keys must be quoted"}
|
1
test/jsonchecker/fail30.json
Normal file
1
test/jsonchecker/fail30.json
Normal file
@ -0,0 +1 @@
|
|||||||
|
[0e+]
|
1
test/jsonchecker/fail31.json
Normal file
1
test/jsonchecker/fail31.json
Normal file
@ -0,0 +1 @@
|
|||||||
|
[0e+-1]
|
1
test/jsonchecker/fail32.json
Normal file
1
test/jsonchecker/fail32.json
Normal file
@ -0,0 +1 @@
|
|||||||
|
{"Comma instead if closing brace": true,
|
1
test/jsonchecker/fail33.json
Normal file
1
test/jsonchecker/fail33.json
Normal file
@ -0,0 +1 @@
|
|||||||
|
["mismatch"}
|
1
test/jsonchecker/fail4.json
Normal file
1
test/jsonchecker/fail4.json
Normal file
@ -0,0 +1 @@
|
|||||||
|
["extra comma",]
|
1
test/jsonchecker/fail5.json
Normal file
1
test/jsonchecker/fail5.json
Normal file
@ -0,0 +1 @@
|
|||||||
|
["double extra comma",,]
|
1
test/jsonchecker/fail6.json
Normal file
1
test/jsonchecker/fail6.json
Normal file
@ -0,0 +1 @@
|
|||||||
|
[ , "<-- missing value"]
|
1
test/jsonchecker/fail7.json
Normal file
1
test/jsonchecker/fail7.json
Normal file
@ -0,0 +1 @@
|
|||||||
|
["Comma after the close"],
|
1
test/jsonchecker/fail8.json
Normal file
1
test/jsonchecker/fail8.json
Normal file
@ -0,0 +1 @@
|
|||||||
|
["Extra close"]]
|
1
test/jsonchecker/fail9.json
Normal file
1
test/jsonchecker/fail9.json
Normal file
@ -0,0 +1 @@
|
|||||||
|
{"Extra comma": true,}
|
58
test/jsonchecker/pass1.json
Normal file
58
test/jsonchecker/pass1.json
Normal file
@ -0,0 +1,58 @@
|
|||||||
|
[
|
||||||
|
"JSON Test Pattern pass1",
|
||||||
|
{"object with 1 member":["array with 1 element"]},
|
||||||
|
{},
|
||||||
|
[],
|
||||||
|
-42,
|
||||||
|
true,
|
||||||
|
false,
|
||||||
|
null,
|
||||||
|
{
|
||||||
|
"integer": 1234567890,
|
||||||
|
"real": -9876.543210,
|
||||||
|
"e": 0.123456789e-12,
|
||||||
|
"E": 1.234567890E+34,
|
||||||
|
"": 23456789012E66,
|
||||||
|
"zero": 0,
|
||||||
|
"one": 1,
|
||||||
|
"space": " ",
|
||||||
|
"quote": "\"",
|
||||||
|
"backslash": "\\",
|
||||||
|
"controls": "\b\f\n\r\t",
|
||||||
|
"slash": "/ & \/",
|
||||||
|
"alpha": "abcdefghijklmnopqrstuvwyz",
|
||||||
|
"ALPHA": "ABCDEFGHIJKLMNOPQRSTUVWYZ",
|
||||||
|
"digit": "0123456789",
|
||||||
|
"0123456789": "digit",
|
||||||
|
"special": "`1~!@#$%^&*()_+-={':[,]}|;.</>?",
|
||||||
|
"hex": "\u0123\u4567\u89AB\uCDEF\uabcd\uef4A",
|
||||||
|
"true": true,
|
||||||
|
"false": false,
|
||||||
|
"null": null,
|
||||||
|
"array":[ ],
|
||||||
|
"object":{ },
|
||||||
|
"address": "50 St. James Street",
|
||||||
|
"url": "http://www.JSON.org/",
|
||||||
|
"comment": "// /* <!-- --",
|
||||||
|
"# -- --> */": " ",
|
||||||
|
" s p a c e d " :[1,2 , 3
|
||||||
|
|
||||||
|
,
|
||||||
|
|
||||||
|
4 , 5 , 6 ,7 ],"compact":[1,2,3,4,5,6,7],
|
||||||
|
"jsontext": "{\"object with 1 member\":[\"array with 1 element\"]}",
|
||||||
|
"quotes": "" \u0022 %22 0x22 034 "",
|
||||||
|
"\/\\\"\uCAFE\uBABE\uAB98\uFCDE\ubcda\uef4A\b\f\n\r\t`1~!@#$%^&*()_+-=[]{}|;:',./<>?"
|
||||||
|
: "A key can be any string"
|
||||||
|
},
|
||||||
|
0.5 ,98.6
|
||||||
|
,
|
||||||
|
99.44
|
||||||
|
,
|
||||||
|
|
||||||
|
1066,
|
||||||
|
1e1,
|
||||||
|
0.1e1,
|
||||||
|
1e-1,
|
||||||
|
1e00,2e+00,2e-00
|
||||||
|
,"rosebud"]
|
1
test/jsonchecker/pass2.json
Normal file
1
test/jsonchecker/pass2.json
Normal file
@ -0,0 +1 @@
|
|||||||
|
[[[[[[[[[[[[[[[[[[["Not too deep"]]]]]]]]]]]]]]]]]]]
|
6
test/jsonchecker/pass3.json
Normal file
6
test/jsonchecker/pass3.json
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
{
|
||||||
|
"JSON Test Pattern pass3": {
|
||||||
|
"The outermost value": "must be an object or array.",
|
||||||
|
"In this test": "It is an object."
|
||||||
|
}
|
||||||
|
}
|
3
test/jsonchecker/readme.txt
Normal file
3
test/jsonchecker/readme.txt
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
Test suite from http://json.org/JSON_checker/.
|
||||||
|
|
||||||
|
If the JSON_checker is working correctly, it must accept all of the pass*.json files and reject all of the fail*.json files.
|
@ -3,6 +3,7 @@ import os
|
|||||||
import os.path
|
import os.path
|
||||||
from glob import glob
|
from glob import glob
|
||||||
|
|
||||||
|
RUN_JSONCHECKER = True
|
||||||
|
|
||||||
def compareOutputs( expected, actual, message ):
|
def compareOutputs( expected, actual, message ):
|
||||||
expected = expected.strip().replace('\r','').split('\n')
|
expected = expected.strip().replace('\r','').split('\n')
|
||||||
@ -39,7 +40,10 @@ def runAllTests( jsontest_executable_path, input_dir = None ):
|
|||||||
if not input_dir:
|
if not input_dir:
|
||||||
input_dir = os.getcwd()
|
input_dir = os.getcwd()
|
||||||
tests = glob( os.path.join( input_dir, '*.json' ) )
|
tests = glob( os.path.join( input_dir, '*.json' ) )
|
||||||
test_jsonchecker = glob( os.path.join( input_dir, 'jsonchecker', '*.json' ) )
|
if RUN_JSONCHECKER:
|
||||||
|
test_jsonchecker = glob( os.path.join( input_dir, 'jsonchecker', '*.json' ) )
|
||||||
|
else:
|
||||||
|
test_jsonchecker = []
|
||||||
failed_tests = []
|
failed_tests = []
|
||||||
for input_path in tests + test_jsonchecker:
|
for input_path in tests + test_jsonchecker:
|
||||||
is_json_checker_test = input_path in test_jsonchecker
|
is_json_checker_test = input_path in test_jsonchecker
|
||||||
@ -54,7 +58,8 @@ def runAllTests( jsontest_executable_path, input_dir = None ):
|
|||||||
if expect_failure:
|
if expect_failure:
|
||||||
if status is None:
|
if status is None:
|
||||||
print 'FAILED'
|
print 'FAILED'
|
||||||
failed_tests.append( (input_path, 'Parsing should have failed') )
|
failed_tests.append( (input_path, 'Parsing should have failed:\n%s' %
|
||||||
|
safeReadFile(input_path)) )
|
||||||
else:
|
else:
|
||||||
print 'OK'
|
print 'OK'
|
||||||
else:
|
else:
|
||||||
|
Loading…
x
Reference in New Issue
Block a user