mirror of
https://github.com/open-source-parsers/jsoncpp.git
synced 2024-12-27 11:21:02 +08:00
Added structured error reporting to Reader.
This allows applications for interactively viewing or editing JSON to do a better job of highlighting errors. Also added offset accessors to Value, offering the same sort of functionality even for non-errors. Thanks to Zach Clifford (zacharyc@google.com) for the patch.
This commit is contained in:
parent
642befc836
commit
68db655347
@ -33,6 +33,19 @@ namespace Json {
|
|||||||
typedef char Char;
|
typedef char Char;
|
||||||
typedef const Char *Location;
|
typedef const Char *Location;
|
||||||
|
|
||||||
|
/** \brief An error tagged with where in the JSON text it was encountered.
|
||||||
|
*
|
||||||
|
* The offsets give the [start, limit) range of bytes within the text. Note
|
||||||
|
* that this is bytes, not codepoints.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
struct StructuredError
|
||||||
|
{
|
||||||
|
size_t offset_start;
|
||||||
|
size_t offset_limit;
|
||||||
|
std::string message;
|
||||||
|
};
|
||||||
|
|
||||||
/** \brief Constructs a Reader allowing all features
|
/** \brief Constructs a Reader allowing all features
|
||||||
* for parsing.
|
* for parsing.
|
||||||
*/
|
*/
|
||||||
@ -95,6 +108,14 @@ namespace Json {
|
|||||||
*/
|
*/
|
||||||
std::string getFormattedErrorMessages() const;
|
std::string getFormattedErrorMessages() const;
|
||||||
|
|
||||||
|
/** \brief Returns a vector of structured erros encounted while parsing.
|
||||||
|
* \return A (possibly empty) vector of StructuredError objects. Currently
|
||||||
|
* only one error can be returned, but the caller should tolerate multiple
|
||||||
|
* errors. This can occur if the parser recovers from a non-fatal
|
||||||
|
* parse error and then encounters additional errors.
|
||||||
|
*/
|
||||||
|
std::vector<StructuredError> getStructuredErrors() const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
enum TokenType
|
enum TokenType
|
||||||
{
|
{
|
||||||
|
@ -442,6 +442,13 @@ namespace Json {
|
|||||||
iterator begin();
|
iterator begin();
|
||||||
iterator end();
|
iterator end();
|
||||||
|
|
||||||
|
// Accessors for the [start, limit) range of bytes within the JSON text from
|
||||||
|
// which this value was parsed, if any.
|
||||||
|
void setOffsetStart( size_t start );
|
||||||
|
void setOffsetLimit( size_t limit );
|
||||||
|
size_t getOffsetStart() const;
|
||||||
|
size_t getOffsetLimit() const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
Value &resolveReference( const char *key,
|
Value &resolveReference( const char *key,
|
||||||
bool isStatic );
|
bool isStatic );
|
||||||
@ -509,6 +516,11 @@ namespace Json {
|
|||||||
int memberNameIsStatic_ : 1; // used by the ValueInternalMap container.
|
int memberNameIsStatic_ : 1; // used by the ValueInternalMap container.
|
||||||
# endif
|
# endif
|
||||||
CommentInfo *comments_;
|
CommentInfo *comments_;
|
||||||
|
|
||||||
|
// [start, limit) byte offsets in the source JSON text from which this Value
|
||||||
|
// was extracted.
|
||||||
|
size_t start_;
|
||||||
|
size_t limit_;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
@ -215,9 +215,11 @@ Reader::readValue()
|
|||||||
{
|
{
|
||||||
case tokenObjectBegin:
|
case tokenObjectBegin:
|
||||||
successful = readObject( token );
|
successful = readObject( token );
|
||||||
|
currentValue().setOffsetLimit(current_ - begin_);
|
||||||
break;
|
break;
|
||||||
case tokenArrayBegin:
|
case tokenArrayBegin:
|
||||||
successful = readArray( token );
|
successful = readArray( token );
|
||||||
|
currentValue().setOffsetLimit(current_ - begin_);
|
||||||
break;
|
break;
|
||||||
case tokenNumber:
|
case tokenNumber:
|
||||||
successful = decodeNumber( token );
|
successful = decodeNumber( token );
|
||||||
@ -227,12 +229,18 @@ Reader::readValue()
|
|||||||
break;
|
break;
|
||||||
case tokenTrue:
|
case tokenTrue:
|
||||||
currentValue() = true;
|
currentValue() = true;
|
||||||
|
currentValue().setOffsetStart(token.start_ - begin_);
|
||||||
|
currentValue().setOffsetLimit(token.end_ - begin_);
|
||||||
break;
|
break;
|
||||||
case tokenFalse:
|
case tokenFalse:
|
||||||
currentValue() = false;
|
currentValue() = false;
|
||||||
|
currentValue().setOffsetStart(token.start_ - begin_);
|
||||||
|
currentValue().setOffsetLimit(token.end_ - begin_);
|
||||||
break;
|
break;
|
||||||
case tokenNull:
|
case tokenNull:
|
||||||
currentValue() = Value();
|
currentValue() = Value();
|
||||||
|
currentValue().setOffsetStart(token.start_ - begin_);
|
||||||
|
currentValue().setOffsetLimit(token.end_ - begin_);
|
||||||
break;
|
break;
|
||||||
case tokenArraySeparator:
|
case tokenArraySeparator:
|
||||||
if ( features_.allowDroppedNullPlaceholders_ )
|
if ( features_.allowDroppedNullPlaceholders_ )
|
||||||
@ -241,10 +249,14 @@ Reader::readValue()
|
|||||||
// token.
|
// token.
|
||||||
current_--;
|
current_--;
|
||||||
currentValue() = Value();
|
currentValue() = Value();
|
||||||
|
currentValue().setOffsetStart(current_ - begin_ - 1);
|
||||||
|
currentValue().setOffsetLimit(current_ - begin_);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
// Else, fall through...
|
// Else, fall through...
|
||||||
default:
|
default:
|
||||||
|
currentValue().setOffsetStart(token.start_ - begin_);
|
||||||
|
currentValue().setOffsetLimit(token.end_ - begin_);
|
||||||
return addError( "Syntax error: value, object or array expected.", token );
|
return addError( "Syntax error: value, object or array expected.", token );
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -493,11 +505,12 @@ Reader::readString()
|
|||||||
|
|
||||||
|
|
||||||
bool
|
bool
|
||||||
Reader::readObject( Token &/*tokenStart*/ )
|
Reader::readObject( Token &tokenStart )
|
||||||
{
|
{
|
||||||
Token tokenName;
|
Token tokenName;
|
||||||
std::string name;
|
std::string name;
|
||||||
currentValue() = Value( objectValue );
|
currentValue() = Value( objectValue );
|
||||||
|
currentValue().setOffsetStart(tokenStart.start_ - begin_);
|
||||||
while ( readToken( tokenName ) )
|
while ( readToken( tokenName ) )
|
||||||
{
|
{
|
||||||
bool initialTokenOk = true;
|
bool initialTokenOk = true;
|
||||||
@ -564,9 +577,10 @@ Reader::readObject( Token &/*tokenStart*/ )
|
|||||||
|
|
||||||
|
|
||||||
bool
|
bool
|
||||||
Reader::readArray( Token &/*tokenStart*/ )
|
Reader::readArray( Token &tokenStart )
|
||||||
{
|
{
|
||||||
currentValue() = Value( arrayValue );
|
currentValue() = Value( arrayValue );
|
||||||
|
currentValue().setOffsetStart(tokenStart.start_ - begin_);
|
||||||
skipSpaces();
|
skipSpaces();
|
||||||
if ( *current_ == ']' ) // empty array
|
if ( *current_ == ']' ) // empty array
|
||||||
{
|
{
|
||||||
@ -613,6 +627,8 @@ Reader::decodeNumber( Token &token )
|
|||||||
if ( !decodeNumber( token, decoded ) )
|
if ( !decodeNumber( token, decoded ) )
|
||||||
return false;
|
return false;
|
||||||
currentValue() = decoded;
|
currentValue() = decoded;
|
||||||
|
currentValue().setOffsetStart(token.start_ - begin_);
|
||||||
|
currentValue().setOffsetLimit(token.end_ - begin_);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -678,6 +694,8 @@ Reader::decodeDouble( Token &token )
|
|||||||
if ( !decodeDouble( token, decoded ) )
|
if ( !decodeDouble( token, decoded ) )
|
||||||
return false;
|
return false;
|
||||||
currentValue() = decoded;
|
currentValue() = decoded;
|
||||||
|
currentValue().setOffsetStart(token.start_ - begin_);
|
||||||
|
currentValue().setOffsetLimit(token.end_ - begin_);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -729,6 +747,8 @@ Reader::decodeString( Token &token )
|
|||||||
if ( !decodeString( token, decoded ) )
|
if ( !decodeString( token, decoded ) )
|
||||||
return false;
|
return false;
|
||||||
currentValue() = decoded;
|
currentValue() = decoded;
|
||||||
|
currentValue().setOffsetStart(token.start_ - begin_);
|
||||||
|
currentValue().setOffsetLimit(token.end_ - begin_);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -963,6 +983,25 @@ Reader::getFormattedErrorMessages() const
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
std::vector<Reader::StructuredError>
|
||||||
|
Reader::getStructuredErrors() const
|
||||||
|
{
|
||||||
|
std::vector<Reader::StructuredError> allErrors;
|
||||||
|
for ( Errors::const_iterator itError = errors_.begin();
|
||||||
|
itError != errors_.end();
|
||||||
|
++itError )
|
||||||
|
{
|
||||||
|
const ErrorInfo &error = *itError;
|
||||||
|
Reader::StructuredError structured;
|
||||||
|
structured.offset_start = error.token_.start_ - begin_;
|
||||||
|
structured.offset_limit = error.token_.end_ - begin_;
|
||||||
|
structured.message = error.message_;
|
||||||
|
allErrors.push_back(structured);
|
||||||
|
}
|
||||||
|
return allErrors;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
std::istream& operator>>( std::istream &sin, Value &root )
|
std::istream& operator>>( std::istream &sin, Value &root )
|
||||||
{
|
{
|
||||||
Json::Reader reader;
|
Json::Reader reader;
|
||||||
|
@ -274,6 +274,8 @@ Value::Value( ValueType type )
|
|||||||
, itemIsUsed_( 0 )
|
, itemIsUsed_( 0 )
|
||||||
#endif
|
#endif
|
||||||
, comments_( 0 )
|
, comments_( 0 )
|
||||||
|
, start_( 0 )
|
||||||
|
, limit_( 0 )
|
||||||
{
|
{
|
||||||
switch ( type )
|
switch ( type )
|
||||||
{
|
{
|
||||||
@ -318,6 +320,8 @@ Value::Value( UInt value )
|
|||||||
, itemIsUsed_( 0 )
|
, itemIsUsed_( 0 )
|
||||||
#endif
|
#endif
|
||||||
, comments_( 0 )
|
, comments_( 0 )
|
||||||
|
, start_( 0 )
|
||||||
|
, limit_( 0 )
|
||||||
{
|
{
|
||||||
value_.uint_ = value;
|
value_.uint_ = value;
|
||||||
}
|
}
|
||||||
@ -329,6 +333,8 @@ Value::Value( Int value )
|
|||||||
, itemIsUsed_( 0 )
|
, itemIsUsed_( 0 )
|
||||||
#endif
|
#endif
|
||||||
, comments_( 0 )
|
, comments_( 0 )
|
||||||
|
, start_( 0 )
|
||||||
|
, limit_( 0 )
|
||||||
{
|
{
|
||||||
value_.int_ = value;
|
value_.int_ = value;
|
||||||
}
|
}
|
||||||
@ -342,6 +348,8 @@ Value::Value( Int64 value )
|
|||||||
, itemIsUsed_( 0 )
|
, itemIsUsed_( 0 )
|
||||||
#endif
|
#endif
|
||||||
, comments_( 0 )
|
, comments_( 0 )
|
||||||
|
, start_( 0 )
|
||||||
|
, limit_( 0 )
|
||||||
{
|
{
|
||||||
value_.int_ = value;
|
value_.int_ = value;
|
||||||
}
|
}
|
||||||
@ -354,6 +362,8 @@ Value::Value( UInt64 value )
|
|||||||
, itemIsUsed_( 0 )
|
, itemIsUsed_( 0 )
|
||||||
#endif
|
#endif
|
||||||
, comments_( 0 )
|
, comments_( 0 )
|
||||||
|
, start_( 0 )
|
||||||
|
, limit_( 0 )
|
||||||
{
|
{
|
||||||
value_.uint_ = value;
|
value_.uint_ = value;
|
||||||
}
|
}
|
||||||
@ -366,6 +376,8 @@ Value::Value( double value )
|
|||||||
, itemIsUsed_( 0 )
|
, itemIsUsed_( 0 )
|
||||||
#endif
|
#endif
|
||||||
, comments_( 0 )
|
, comments_( 0 )
|
||||||
|
, start_( 0 )
|
||||||
|
, limit_( 0 )
|
||||||
{
|
{
|
||||||
value_.real_ = value;
|
value_.real_ = value;
|
||||||
}
|
}
|
||||||
@ -377,6 +389,8 @@ Value::Value( const char *value )
|
|||||||
, itemIsUsed_( 0 )
|
, itemIsUsed_( 0 )
|
||||||
#endif
|
#endif
|
||||||
, comments_( 0 )
|
, comments_( 0 )
|
||||||
|
, start_( 0 )
|
||||||
|
, limit_( 0 )
|
||||||
{
|
{
|
||||||
value_.string_ = duplicateStringValue( value );
|
value_.string_ = duplicateStringValue( value );
|
||||||
}
|
}
|
||||||
@ -390,6 +404,8 @@ Value::Value( const char *beginValue,
|
|||||||
, itemIsUsed_( 0 )
|
, itemIsUsed_( 0 )
|
||||||
#endif
|
#endif
|
||||||
, comments_( 0 )
|
, comments_( 0 )
|
||||||
|
, start_( 0 )
|
||||||
|
, limit_( 0 )
|
||||||
{
|
{
|
||||||
value_.string_ = duplicateStringValue( beginValue,
|
value_.string_ = duplicateStringValue( beginValue,
|
||||||
(unsigned int)(endValue - beginValue) );
|
(unsigned int)(endValue - beginValue) );
|
||||||
@ -403,6 +419,8 @@ Value::Value( const std::string &value )
|
|||||||
, itemIsUsed_( 0 )
|
, itemIsUsed_( 0 )
|
||||||
#endif
|
#endif
|
||||||
, comments_( 0 )
|
, comments_( 0 )
|
||||||
|
, start_( 0 )
|
||||||
|
, limit_( 0 )
|
||||||
{
|
{
|
||||||
value_.string_ = duplicateStringValue( value.c_str(),
|
value_.string_ = duplicateStringValue( value.c_str(),
|
||||||
(unsigned int)value.length() );
|
(unsigned int)value.length() );
|
||||||
@ -416,6 +434,8 @@ Value::Value( const StaticString &value )
|
|||||||
, itemIsUsed_( 0 )
|
, itemIsUsed_( 0 )
|
||||||
#endif
|
#endif
|
||||||
, comments_( 0 )
|
, comments_( 0 )
|
||||||
|
, start_( 0 )
|
||||||
|
, limit_( 0 )
|
||||||
{
|
{
|
||||||
value_.string_ = const_cast<char *>( value.c_str() );
|
value_.string_ = const_cast<char *>( value.c_str() );
|
||||||
}
|
}
|
||||||
@ -429,6 +449,8 @@ Value::Value( const CppTL::ConstString &value )
|
|||||||
, itemIsUsed_( 0 )
|
, itemIsUsed_( 0 )
|
||||||
#endif
|
#endif
|
||||||
, comments_( 0 )
|
, comments_( 0 )
|
||||||
|
, start_( 0 )
|
||||||
|
, limit_( 0 )
|
||||||
{
|
{
|
||||||
value_.string_ = duplicateStringValue( value, value.length() );
|
value_.string_ = duplicateStringValue( value, value.length() );
|
||||||
}
|
}
|
||||||
@ -441,6 +463,8 @@ Value::Value( bool value )
|
|||||||
, itemIsUsed_( 0 )
|
, itemIsUsed_( 0 )
|
||||||
#endif
|
#endif
|
||||||
, comments_( 0 )
|
, comments_( 0 )
|
||||||
|
, start_( 0 )
|
||||||
|
, limit_( 0 )
|
||||||
{
|
{
|
||||||
value_.bool_ = value;
|
value_.bool_ = value;
|
||||||
}
|
}
|
||||||
@ -453,6 +477,8 @@ Value::Value( const Value &other )
|
|||||||
, itemIsUsed_( 0 )
|
, itemIsUsed_( 0 )
|
||||||
#endif
|
#endif
|
||||||
, comments_( 0 )
|
, comments_( 0 )
|
||||||
|
, start_( other.start_ )
|
||||||
|
, limit_( other.limit_ )
|
||||||
{
|
{
|
||||||
switch ( type_ )
|
switch ( type_ )
|
||||||
{
|
{
|
||||||
@ -557,6 +583,8 @@ Value::swap( Value &other )
|
|||||||
int temp2 = allocated_;
|
int temp2 = allocated_;
|
||||||
allocated_ = other.allocated_;
|
allocated_ = other.allocated_;
|
||||||
other.allocated_ = temp2;
|
other.allocated_ = temp2;
|
||||||
|
std::swap( start_, other.start_ );
|
||||||
|
std::swap( limit_, other.limit_ );
|
||||||
}
|
}
|
||||||
|
|
||||||
ValueType
|
ValueType
|
||||||
@ -1027,7 +1055,8 @@ void
|
|||||||
Value::clear()
|
Value::clear()
|
||||||
{
|
{
|
||||||
JSON_ASSERT_MESSAGE( type_ == nullValue || type_ == arrayValue || type_ == objectValue, "in Json::Value::clear(): requires complex value" );
|
JSON_ASSERT_MESSAGE( type_ == nullValue || type_ == arrayValue || type_ == objectValue, "in Json::Value::clear(): requires complex value" );
|
||||||
|
start_ = 0;
|
||||||
|
limit_ = 0;
|
||||||
switch ( type_ )
|
switch ( type_ )
|
||||||
{
|
{
|
||||||
#ifndef JSON_VALUE_USE_INTERNAL_MAP
|
#ifndef JSON_VALUE_USE_INTERNAL_MAP
|
||||||
@ -1556,6 +1585,34 @@ Value::getComment( CommentPlacement placement ) const
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
Value::setOffsetStart( size_t start )
|
||||||
|
{
|
||||||
|
start_ = start;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
Value::setOffsetLimit( size_t limit )
|
||||||
|
{
|
||||||
|
limit_ = limit;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
size_t
|
||||||
|
Value::getOffsetStart() const
|
||||||
|
{
|
||||||
|
return start_;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
size_t
|
||||||
|
Value::getOffsetLimit() const
|
||||||
|
{
|
||||||
|
return limit_;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
std::string
|
std::string
|
||||||
Value::toStyledString() const
|
Value::toStyledString() const
|
||||||
{
|
{
|
||||||
|
@ -1474,6 +1474,26 @@ JSONTEST_FIXTURE( ValueTest, checkInteger )
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
JSONTEST_FIXTURE( ValueTest, offsetAccessors )
|
||||||
|
{
|
||||||
|
Json::Value x;
|
||||||
|
JSONTEST_ASSERT( x.getOffsetStart() == 0 );
|
||||||
|
JSONTEST_ASSERT( x.getOffsetLimit() == 0 );
|
||||||
|
x.setOffsetStart(10);
|
||||||
|
x.setOffsetLimit(20);
|
||||||
|
JSONTEST_ASSERT( x.getOffsetStart() == 10 );
|
||||||
|
JSONTEST_ASSERT( x.getOffsetLimit() == 20 );
|
||||||
|
Json::Value y(x);
|
||||||
|
JSONTEST_ASSERT( y.getOffsetStart() == 10 );
|
||||||
|
JSONTEST_ASSERT( y.getOffsetLimit() == 20 );
|
||||||
|
Json::Value z;
|
||||||
|
z.swap(y);
|
||||||
|
JSONTEST_ASSERT( z.getOffsetStart() == 10 );
|
||||||
|
JSONTEST_ASSERT( z.getOffsetLimit() == 20 );
|
||||||
|
JSONTEST_ASSERT( y.getOffsetStart() == 0 );
|
||||||
|
JSONTEST_ASSERT( y.getOffsetLimit() == 0 );
|
||||||
|
}
|
||||||
|
|
||||||
struct WriterTest : JsonTest::TestCase
|
struct WriterTest : JsonTest::TestCase
|
||||||
{
|
{
|
||||||
};
|
};
|
||||||
@ -1490,6 +1510,115 @@ JSONTEST_FIXTURE( WriterTest, dropNullPlaceholders )
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
struct ReaderTest : JsonTest::TestCase
|
||||||
|
{
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
JSONTEST_FIXTURE( ReaderTest, parseWithNoErrors )
|
||||||
|
{
|
||||||
|
Json::Reader reader;
|
||||||
|
Json::Value root;
|
||||||
|
bool ok = reader.parse(
|
||||||
|
"{ \"property\" : \"value\" }",
|
||||||
|
root);
|
||||||
|
JSONTEST_ASSERT( ok );
|
||||||
|
JSONTEST_ASSERT( reader.getFormattedErrorMessages().size() == 0 );
|
||||||
|
JSONTEST_ASSERT( reader.getStructuredErrors().size() == 0 );
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
JSONTEST_FIXTURE( ReaderTest, parseWithNoErrorsTestingOffsets )
|
||||||
|
{
|
||||||
|
Json::Reader reader;
|
||||||
|
Json::Value root;
|
||||||
|
bool ok = reader.parse(
|
||||||
|
"{ \"property\" : [\"value\", \"value2\"], \"obj\" : { \"nested\" : 123, \"bool\" : true}, \"null\" : null, \"false\" : false }",
|
||||||
|
root);
|
||||||
|
JSONTEST_ASSERT( ok );
|
||||||
|
JSONTEST_ASSERT( reader.getFormattedErrorMessages().size() == 0 );
|
||||||
|
JSONTEST_ASSERT( reader.getStructuredErrors().size() == 0 );
|
||||||
|
JSONTEST_ASSERT( root["property"].getOffsetStart() == 15 );
|
||||||
|
JSONTEST_ASSERT( root["property"].getOffsetLimit() == 34 );
|
||||||
|
JSONTEST_ASSERT( root["property"][0].getOffsetStart() == 16 );
|
||||||
|
JSONTEST_ASSERT( root["property"][0].getOffsetLimit() == 23 );
|
||||||
|
JSONTEST_ASSERT( root["property"][1].getOffsetStart() == 25 );
|
||||||
|
JSONTEST_ASSERT( root["property"][1].getOffsetLimit() == 33 );
|
||||||
|
JSONTEST_ASSERT( root["obj"].getOffsetStart() == 44 );
|
||||||
|
JSONTEST_ASSERT( root["obj"].getOffsetLimit() == 76 );
|
||||||
|
JSONTEST_ASSERT( root["obj"]["nested"].getOffsetStart() == 57 );
|
||||||
|
JSONTEST_ASSERT( root["obj"]["nested"].getOffsetLimit() == 60 );
|
||||||
|
JSONTEST_ASSERT( root["obj"]["bool"].getOffsetStart() == 71 );
|
||||||
|
JSONTEST_ASSERT( root["obj"]["bool"].getOffsetLimit() == 75 );
|
||||||
|
JSONTEST_ASSERT( root["null"].getOffsetStart() == 87 );
|
||||||
|
JSONTEST_ASSERT( root["null"].getOffsetLimit() == 91 );
|
||||||
|
JSONTEST_ASSERT( root["false"].getOffsetStart() == 103 );
|
||||||
|
JSONTEST_ASSERT( root["false"].getOffsetLimit() == 108 );
|
||||||
|
JSONTEST_ASSERT( root.getOffsetStart() == 0 );
|
||||||
|
JSONTEST_ASSERT( root.getOffsetLimit() == 110 );
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
JSONTEST_FIXTURE( ReaderTest, parseWithOneError )
|
||||||
|
{
|
||||||
|
Json::Reader reader;
|
||||||
|
Json::Value root;
|
||||||
|
bool ok = reader.parse(
|
||||||
|
"{ \"property\" :: \"value\" }",
|
||||||
|
root);
|
||||||
|
JSONTEST_ASSERT( !ok );
|
||||||
|
JSONTEST_ASSERT( reader.getFormattedErrorMessages() ==
|
||||||
|
"* Line 1, Column 15\n Syntax error: value, object or array expected.\n" );
|
||||||
|
std::vector<Json::Reader::StructuredError> errors =
|
||||||
|
reader.getStructuredErrors();
|
||||||
|
JSONTEST_ASSERT( errors.size() == 1 );
|
||||||
|
JSONTEST_ASSERT( errors.at(0).offset_start == 14 );
|
||||||
|
JSONTEST_ASSERT( errors.at(0).offset_limit == 15 );
|
||||||
|
JSONTEST_ASSERT( errors.at(0).message ==
|
||||||
|
"Syntax error: value, object or array expected." );
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
JSONTEST_FIXTURE( ReaderTest, parseChineseWithOneError )
|
||||||
|
{
|
||||||
|
Json::Reader reader;
|
||||||
|
Json::Value root;
|
||||||
|
bool ok = reader.parse(
|
||||||
|
"{ \"pr佐藤erty\" :: \"value\" }",
|
||||||
|
root);
|
||||||
|
JSONTEST_ASSERT( !ok );
|
||||||
|
JSONTEST_ASSERT( reader.getFormattedErrorMessages() ==
|
||||||
|
"* Line 1, Column 19\n Syntax error: value, object or array expected.\n" );
|
||||||
|
std::vector<Json::Reader::StructuredError> errors =
|
||||||
|
reader.getStructuredErrors();
|
||||||
|
JSONTEST_ASSERT( errors.size() == 1 );
|
||||||
|
JSONTEST_ASSERT( errors.at(0).offset_start == 18 );
|
||||||
|
JSONTEST_ASSERT( errors.at(0).offset_limit == 19 );
|
||||||
|
JSONTEST_ASSERT( errors.at(0).message ==
|
||||||
|
"Syntax error: value, object or array expected." );
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
JSONTEST_FIXTURE( ReaderTest, parseWithDetailError )
|
||||||
|
{
|
||||||
|
Json::Reader reader;
|
||||||
|
Json::Value root;
|
||||||
|
bool ok = reader.parse(
|
||||||
|
"{ \"property\" : \"v\\alue\" }",
|
||||||
|
root);
|
||||||
|
JSONTEST_ASSERT( !ok );
|
||||||
|
JSONTEST_ASSERT( reader.getFormattedErrorMessages() ==
|
||||||
|
"* Line 1, Column 16\n Bad escape sequence in string\nSee Line 1, Column 20 for detail.\n" );
|
||||||
|
std::vector<Json::Reader::StructuredError> errors =
|
||||||
|
reader.getStructuredErrors();
|
||||||
|
JSONTEST_ASSERT( errors.size() == 1 );
|
||||||
|
JSONTEST_ASSERT( errors.at(0).offset_start == 15 );
|
||||||
|
JSONTEST_ASSERT( errors.at(0).offset_limit == 23 );
|
||||||
|
JSONTEST_ASSERT( errors.at(0).message ==
|
||||||
|
"Bad escape sequence in string" );
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
int main( int argc, const char *argv[] )
|
int main( int argc, const char *argv[] )
|
||||||
{
|
{
|
||||||
JsonTest::Runner runner;
|
JsonTest::Runner runner;
|
||||||
@ -1512,6 +1641,14 @@ int main( int argc, const char *argv[] )
|
|||||||
JSONTEST_REGISTER_FIXTURE( runner, ValueTest, compareObject );
|
JSONTEST_REGISTER_FIXTURE( runner, ValueTest, compareObject );
|
||||||
JSONTEST_REGISTER_FIXTURE( runner, ValueTest, compareType );
|
JSONTEST_REGISTER_FIXTURE( runner, ValueTest, compareType );
|
||||||
JSONTEST_REGISTER_FIXTURE( runner, ValueTest, checkInteger );
|
JSONTEST_REGISTER_FIXTURE( runner, ValueTest, checkInteger );
|
||||||
|
JSONTEST_REGISTER_FIXTURE( runner, ValueTest, offsetAccessors );
|
||||||
|
|
||||||
|
JSONTEST_REGISTER_FIXTURE( runner, ReaderTest, parseWithNoErrors );
|
||||||
|
JSONTEST_REGISTER_FIXTURE( runner, ReaderTest, parseWithNoErrorsTestingOffsets );
|
||||||
|
JSONTEST_REGISTER_FIXTURE( runner, ReaderTest, parseWithOneError );
|
||||||
|
JSONTEST_REGISTER_FIXTURE( runner, ReaderTest, parseChineseWithOneError );
|
||||||
|
JSONTEST_REGISTER_FIXTURE( runner, ReaderTest, parseWithDetailError );
|
||||||
|
|
||||||
JSONTEST_REGISTER_FIXTURE( runner, WriterTest, dropNullPlaceholders );
|
JSONTEST_REGISTER_FIXTURE( runner, WriterTest, dropNullPlaceholders );
|
||||||
return runner.runCommandLine( argc, argv );
|
return runner.runCommandLine( argc, argv );
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user