1217 lines
43 KiB
C++
1217 lines
43 KiB
C++
// jsobjtests.h : Test suite generator headers.
|
|
//
|
|
|
|
/**
|
|
* Copyright (C) 2008 10gen Inc.
|
|
*
|
|
* This program is free software: you can redistribute it and/or modify
|
|
* it under the terms of the GNU Affero General Public License, version 3,
|
|
* as published by the Free Software Foundation.
|
|
*
|
|
* This program is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU Affero General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU Affero General Public License
|
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
*/
|
|
|
|
#include "../db/jsobj.h"
|
|
#include "../db/json.h"
|
|
|
|
#include "dbtests.h"
|
|
|
|
#include <limits>
|
|
|
|
namespace JsobjTests {
|
|
namespace BSONObjTests {
|
|
class Create {
|
|
public:
|
|
void run() {
|
|
BSONObj b;
|
|
ASSERT_EQUALS( 0, b.nFields() );
|
|
}
|
|
};
|
|
|
|
class Base {
|
|
protected:
|
|
static BSONObj basic( const char *name, int val ) {
|
|
BSONObjBuilder b;
|
|
b.appendInt( name, val );
|
|
return b.doneAndDecouple();
|
|
}
|
|
static BSONObj basic( const char *name, vector< int > val ) {
|
|
BSONObjBuilder b;
|
|
b.appendIntArray( name, val );
|
|
return b.doneAndDecouple();
|
|
}
|
|
template< class T >
|
|
static BSONObj basic( const char *name, T val ) {
|
|
BSONObjBuilder b;
|
|
b.append( name, val );
|
|
return b.doneAndDecouple();
|
|
}
|
|
};
|
|
|
|
class WoCompareBasic : public Base {
|
|
public:
|
|
void run() {
|
|
ASSERT( basic( "a", 1 ).woCompare( basic( "a", 1 ) ) == 0 );
|
|
ASSERT( basic( "a", 2 ).woCompare( basic( "a", 1 ) ) > 0 );
|
|
ASSERT( basic( "a", 1 ).woCompare( basic( "a", 2 ) ) < 0 );
|
|
// field name comparison
|
|
ASSERT( basic( "a", 1 ).woCompare( basic( "b", 1 ) ) < 0 );
|
|
}
|
|
};
|
|
|
|
class NumericCompareBasic : public Base {
|
|
public:
|
|
void run() {
|
|
ASSERT( basic( "a", 1 ).woCompare( basic( "a", 1.0 ) ) == 0 );
|
|
}
|
|
};
|
|
|
|
class WoCompareEmbeddedObject : public Base {
|
|
public:
|
|
void run() {
|
|
ASSERT( basic( "a", basic( "b", 1 ) ).woCompare
|
|
( basic( "a", basic( "b", 1.0 ) ) ) == 0 );
|
|
ASSERT( basic( "a", basic( "b", 1 ) ).woCompare
|
|
( basic( "a", basic( "b", 2 ) ) ) < 0 );
|
|
}
|
|
};
|
|
|
|
class WoCompareEmbeddedArray : public Base {
|
|
public:
|
|
void run() {
|
|
vector< int > i;
|
|
i.push_back( 1 );
|
|
i.push_back( 2 );
|
|
vector< double > d;
|
|
d.push_back( 1 );
|
|
d.push_back( 2 );
|
|
ASSERT( basic( "a", i ).woCompare( basic( "a", d ) ) == 0 );
|
|
|
|
vector< int > j;
|
|
j.push_back( 1 );
|
|
j.push_back( 3 );
|
|
ASSERT( basic( "a", i ).woCompare( basic( "a", j ) ) < 0 );
|
|
}
|
|
};
|
|
|
|
class WoCompareOrdered : public Base {
|
|
public:
|
|
void run() {
|
|
ASSERT( basic( "a", 1 ).woCompare( basic( "a", 1 ), basic( "a", 1 ) ) == 0 );
|
|
ASSERT( basic( "a", 2 ).woCompare( basic( "a", 1 ), basic( "a", 1 ) ) > 0 );
|
|
ASSERT( basic( "a", 1 ).woCompare( basic( "a", 2 ), basic( "a", 1 ) ) < 0 );
|
|
ASSERT( basic( "a", 1 ).woCompare( basic( "a", 1 ), basic( "a", -1 ) ) == 0 );
|
|
ASSERT( basic( "a", 2 ).woCompare( basic( "a", 1 ), basic( "a", -1 ) ) < 0 );
|
|
ASSERT( basic( "a", 1 ).woCompare( basic( "a", 2 ), basic( "a", -1 ) ) > 0 );
|
|
}
|
|
};
|
|
|
|
namespace Validation {
|
|
|
|
class Base {
|
|
public:
|
|
void run() {
|
|
ASSERT( valid().valid() );
|
|
ASSERT( !invalid().valid() );
|
|
}
|
|
protected:
|
|
virtual BSONObj valid() const = 0;
|
|
virtual BSONObj invalid() const = 0;
|
|
static char get( const BSONObj &o, int i ) {
|
|
return o.objdata()[ i ];
|
|
}
|
|
static void set( BSONObj &o, int i, char c ) {
|
|
const_cast< char * >( o.objdata() )[ i ] = c;
|
|
}
|
|
};
|
|
|
|
class BadType : public Base {
|
|
BSONObj valid() const {
|
|
return fromjson( "{\"a\":1}" );
|
|
}
|
|
BSONObj invalid() const {
|
|
BSONObj ret = valid();
|
|
set( ret, 4, 50 );
|
|
return ret;
|
|
}
|
|
};
|
|
|
|
class EooBeforeEnd : public Base {
|
|
BSONObj valid() const {
|
|
return fromjson( "{\"a\":1}" );
|
|
}
|
|
BSONObj invalid() const {
|
|
BSONObj ret = valid();
|
|
// (first byte of size)++
|
|
set( ret, 0, get( ret, 0 ) + 1 );
|
|
// re-read size for BSONObj::details
|
|
return ret.copy();
|
|
}
|
|
};
|
|
|
|
class UndefinedBeforeEnd : public Base {
|
|
BSONObj valid() const {
|
|
return fromjson( "{\"a\":1}" );
|
|
}
|
|
BSONObj invalid() const {
|
|
BSONObj ret = valid();
|
|
set( ret, 4, Undefined );
|
|
return ret;
|
|
}
|
|
};
|
|
|
|
class TotalSizeTooSmall : public Base {
|
|
BSONObj valid() const {
|
|
return fromjson( "{\"a\":1}" );
|
|
}
|
|
BSONObj invalid() const {
|
|
BSONObj ret = valid();
|
|
// (first byte of size)--
|
|
set( ret, 0, get( ret, 0 ) - 1 );
|
|
// re-read size for BSONObj::details
|
|
return ret.copy();
|
|
}
|
|
};
|
|
|
|
class EooMissing : public Base {
|
|
BSONObj valid() const {
|
|
return fromjson( "{\"a\":1}" );
|
|
}
|
|
BSONObj invalid() const {
|
|
BSONObj ret = valid();
|
|
set( ret, ret.objsize() - 1, 0xff );
|
|
// (first byte of size)--
|
|
set( ret, 0, get( ret, 0 ) - 1 );
|
|
// re-read size for BSONObj::details
|
|
return ret.copy();
|
|
}
|
|
};
|
|
|
|
class WrongStringSize : public Base {
|
|
BSONObj valid() const {
|
|
return fromjson( "{\"a\":\"b\"}" );
|
|
}
|
|
BSONObj invalid() const {
|
|
BSONObj ret = valid();
|
|
set( ret, 0, get( ret, 0 ) + 1 );
|
|
set( ret, 7, get( ret, 7 ) + 1 );
|
|
return ret.copy();
|
|
}
|
|
};
|
|
|
|
class WrongSubobjectSize : public Base {
|
|
BSONObj valid() const {
|
|
return fromjson( "{\"a\":{\"b\":1}}" );
|
|
}
|
|
BSONObj invalid() const {
|
|
BSONObj ret = valid();
|
|
set( ret, 0, get( ret, 0 ) + 1 );
|
|
set( ret, 7, get( ret, 7 ) + 1 );
|
|
return ret.copy();
|
|
}
|
|
};
|
|
|
|
class WrongDbrefNsSize : public Base {
|
|
BSONObj valid() const {
|
|
return fromjson( "{ \"a\": Dbref( \"b\", \"ffffffffffffffffffffffff\" ) }" );
|
|
}
|
|
BSONObj invalid() const {
|
|
BSONObj ret = valid();
|
|
set( ret, 0, get( ret, 0 ) + 1 );
|
|
set( ret, 7, get( ret, 7 ) + 1 );
|
|
return ret.copy();
|
|
};
|
|
};
|
|
|
|
class WrongSymbolSize : public Base {
|
|
BSONObj valid() const {
|
|
return fromjson( "{\"a\":\"b\"}" );
|
|
}
|
|
BSONObj invalid() const {
|
|
BSONObj ret = valid();
|
|
set( ret, 4, Symbol );
|
|
set( ret, 0, get( ret, 0 ) + 1 );
|
|
set( ret, 7, get( ret, 7 ) + 1 );
|
|
return ret.copy();
|
|
}
|
|
};
|
|
|
|
class NoFieldNameEnd : public Base {
|
|
BSONObj valid() const {
|
|
return fromjson( "{\"a\":1}" );
|
|
}
|
|
BSONObj invalid() const {
|
|
BSONObj ret = valid();
|
|
memset( const_cast< char * >( ret.objdata() ) + 5, 0xff, ret.objsize() - 5 );
|
|
return ret;
|
|
}
|
|
};
|
|
|
|
class BadRegex : public Base {
|
|
BSONObj valid() const {
|
|
return fromjson( "{\"a\":/c/i}" );
|
|
}
|
|
BSONObj invalid() const {
|
|
BSONObj ret = valid();
|
|
memset( const_cast< char * >( ret.objdata() ) + 7, 0xff, ret.objsize() - 7 );
|
|
return ret;
|
|
}
|
|
};
|
|
|
|
class BadRegexOptions : public Base {
|
|
BSONObj valid() const {
|
|
return fromjson( "{\"a\":/c/i}" );
|
|
}
|
|
BSONObj invalid() const {
|
|
BSONObj ret = valid();
|
|
memset( const_cast< char * >( ret.objdata() ) + 9, 0xff, ret.objsize() - 9 );
|
|
return ret;
|
|
}
|
|
};
|
|
|
|
class NoSize {
|
|
public:
|
|
NoSize( BSONType type ) : type_( type ) {}
|
|
void run() {
|
|
const char data[] = { 0x07, 0x00, 0x00, 0x00, char( type_ ), 'a', 0x00 };
|
|
BSONObj o( data );
|
|
ASSERT( !o.valid() );
|
|
}
|
|
private:
|
|
BSONType type_;
|
|
};
|
|
|
|
// Randomized BSON parsing test. See if we seg fault.
|
|
class Fuzz {
|
|
public:
|
|
void run() {
|
|
BSONObj o = fromjson( "{\"one\":2, \"two\":5, \"three\": {},"
|
|
"\"four\": { \"five\": { \"six\" : 11 } },"
|
|
"\"seven\": [ \"a\", \"bb\", \"ccc\", 5 ],"
|
|
"\"eight\": Dbref( \"rrr\", \"01234567890123456789aaaa\" ),"
|
|
"\"_id\": ObjectId( \"deadbeefdeadbeefdeadbeef\" ),"
|
|
"\"nine\": { \"$binary\": \"abc=\", \"$type\": \"02\" },"
|
|
"\"ten\": Date( 44 ), \"eleven\": /foooooo/i }" );
|
|
for( int i = 4; i < o.objsize(); ++i )
|
|
for( unsigned char j = 1; j; j <<= 1 )
|
|
if ( rand() > int( RAND_MAX * 0.95 ) ) {
|
|
char *c = const_cast< char * >( o.objdata() ) + i;
|
|
if ( *c & j )
|
|
*c &= ~j;
|
|
else
|
|
*c |= j;
|
|
}
|
|
o.valid();
|
|
}
|
|
};
|
|
|
|
// Randomized BSON parsing test. See if we seg fault.
|
|
class RandomBytes {
|
|
public:
|
|
void run() {
|
|
char data[ 104 ];
|
|
*(int *)( data ) = 104;
|
|
for( int i = 4; i < 104; ++i ) {
|
|
data[ i ] = rand();
|
|
}
|
|
BSONObj o( data );
|
|
o.valid();
|
|
}
|
|
};
|
|
|
|
} // namespace Validation
|
|
|
|
namespace JsonStringTests {
|
|
class Empty {
|
|
public:
|
|
void run() {
|
|
BSONObjBuilder b;
|
|
ASSERT_EQUALS( "{}", b.done().jsonString( Strict ) );
|
|
}
|
|
};
|
|
|
|
class SingleStringMember {
|
|
public:
|
|
void run() {
|
|
BSONObjBuilder b;
|
|
b.append( "a", "b" );
|
|
ASSERT_EQUALS( "{ \"a\" : \"b\" }", b.done().jsonString( Strict ) );
|
|
}
|
|
};
|
|
|
|
class EscapedCharacters {
|
|
public:
|
|
void run() {
|
|
BSONObjBuilder b;
|
|
b.append( "a", "\" \\ / \b \f \n \r \t" );
|
|
ASSERT_EQUALS( "{ \"a\" : \"\\\" \\\\ \\/ \\b \\f \\n \\r \\t\" }", b.done().jsonString( Strict ) );
|
|
}
|
|
};
|
|
|
|
// per http://www.ietf.org/rfc/rfc4627.txt, control characters are
|
|
// (U+0000 through U+001F). U+007F is not mentioned as a control character.
|
|
class AdditionalControlCharacters {
|
|
public:
|
|
void run() {
|
|
BSONObjBuilder b;
|
|
b.append( "a", "\x1 \x1f" );
|
|
ASSERT_EQUALS( "{ \"a\" : \"\\u0001 \\u001f\" }", b.done().jsonString( Strict ) );
|
|
}
|
|
};
|
|
|
|
class ExtendedAscii {
|
|
public:
|
|
void run() {
|
|
BSONObjBuilder b;
|
|
b.append( "a", "\x80" );
|
|
ASSERT_EQUALS( "{ \"a\" : \"\x80\" }", b.done().jsonString( Strict ) );
|
|
}
|
|
};
|
|
|
|
class EscapeFieldName {
|
|
public:
|
|
void run() {
|
|
BSONObjBuilder b;
|
|
b.append( "\t", "b" );
|
|
ASSERT_EQUALS( "{ \"\\t\" : \"b\" }", b.done().jsonString( Strict ) );
|
|
}
|
|
};
|
|
|
|
class SingleIntMember {
|
|
public:
|
|
void run() {
|
|
BSONObjBuilder b;
|
|
b.appendInt( "a", 1 );
|
|
ASSERT_EQUALS( "{ \"a\" : 1 }", b.done().jsonString( Strict ) );
|
|
}
|
|
};
|
|
|
|
class SingleNumberMember {
|
|
public:
|
|
void run() {
|
|
BSONObjBuilder b;
|
|
b.append( "a", 1.5 );
|
|
ASSERT_EQUALS( "{ \"a\" : 1.5 }", b.done().jsonString( Strict ) );
|
|
}
|
|
};
|
|
|
|
class InvalidNumbers {
|
|
public:
|
|
void run() {
|
|
BSONObjBuilder b;
|
|
b.append( "a", numeric_limits< double >::infinity() );
|
|
ASSERT_EXCEPTION( b.done().jsonString( Strict ), AssertionException );
|
|
|
|
BSONObjBuilder c;
|
|
c.append( "a", numeric_limits< double >::quiet_NaN() );
|
|
ASSERT_EXCEPTION( c.done().jsonString( Strict ), AssertionException );
|
|
|
|
BSONObjBuilder d;
|
|
d.append( "a", numeric_limits< double >::signaling_NaN() );
|
|
ASSERT_EXCEPTION( d.done().jsonString( Strict ), AssertionException );
|
|
}
|
|
};
|
|
|
|
class NumberPrecision {
|
|
public:
|
|
void run() {
|
|
BSONObjBuilder b;
|
|
b.append( "a", 123456789 );
|
|
ASSERT_EQUALS( "{ \"a\" : 123456789 }", b.done().jsonString( Strict ) );
|
|
}
|
|
};
|
|
|
|
class NegativeNumber {
|
|
public:
|
|
void run() {
|
|
BSONObjBuilder b;
|
|
b.append( "a", -1 );
|
|
ASSERT_EQUALS( "{ \"a\" : -1 }", b.done().jsonString( Strict ) );
|
|
}
|
|
};
|
|
|
|
class SingleBoolMember {
|
|
public:
|
|
void run() {
|
|
BSONObjBuilder b;
|
|
b.appendBool( "a", true );
|
|
ASSERT_EQUALS( "{ \"a\" : true }", b.done().jsonString( Strict ) );
|
|
|
|
BSONObjBuilder c;
|
|
c.appendBool( "a", false );
|
|
ASSERT_EQUALS( "{ \"a\" : false }", c.done().jsonString( Strict ) );
|
|
}
|
|
};
|
|
|
|
class SingleNullMember {
|
|
public:
|
|
void run() {
|
|
BSONObjBuilder b;
|
|
b.appendNull( "a" );
|
|
ASSERT_EQUALS( "{ \"a\" : null }", b.done().jsonString( Strict ) );
|
|
}
|
|
};
|
|
|
|
class SingleObjectMember {
|
|
public:
|
|
void run() {
|
|
BSONObjBuilder b, c;
|
|
b.append( "a", c.done() );
|
|
ASSERT_EQUALS( "{ \"a\" : {} }", b.done().jsonString( Strict ) );
|
|
}
|
|
};
|
|
|
|
class TwoMembers {
|
|
public:
|
|
void run() {
|
|
BSONObjBuilder b;
|
|
b.append( "a", 1 );
|
|
b.append( "b", 2 );
|
|
ASSERT_EQUALS( "{ \"a\" : 1, \"b\" : 2 }", b.done().jsonString( Strict ) );
|
|
}
|
|
};
|
|
|
|
class EmptyArray {
|
|
public:
|
|
void run() {
|
|
vector< int > arr;
|
|
BSONObjBuilder b;
|
|
b.append( "a", arr );
|
|
ASSERT_EQUALS( "{ \"a\" : [] }", b.done().jsonString( Strict ) );
|
|
}
|
|
};
|
|
|
|
class Array {
|
|
public:
|
|
void run() {
|
|
vector< int > arr;
|
|
arr.push_back( 1 );
|
|
arr.push_back( 2 );
|
|
BSONObjBuilder b;
|
|
b.append( "a", arr );
|
|
ASSERT_EQUALS( "{ \"a\" : [ 1, 2 ] }", b.done().jsonString( Strict ) );
|
|
}
|
|
};
|
|
|
|
class DBRef {
|
|
public:
|
|
void run() {
|
|
OID oid;
|
|
memset( &oid, 0xff, 12 );
|
|
BSONObjBuilder b;
|
|
b.appendDBRef( "a", "namespace", oid );
|
|
ASSERT_EQUALS( "{ \"a\" : { \"$ns\" : \"namespace\", \"$id\" : \"ffffffffffffffffffffffff\" } }",
|
|
b.done().jsonString( Strict ) );
|
|
ASSERT_EQUALS( "{ \"a\" : { \"$ns\" : \"namespace\", \"$id\" : \"ffffffffffffffffffffffff\" } }",
|
|
b.done().jsonString( JS ) );
|
|
ASSERT_EQUALS( "{ \"a\" : Dbref( \"namespace\", \"ffffffffffffffffffffffff\" ) }",
|
|
b.done().jsonString( TenGen ) );
|
|
}
|
|
};
|
|
|
|
class DBRefZero {
|
|
public:
|
|
void run() {
|
|
OID oid;
|
|
memset( &oid, 0, 12 );
|
|
BSONObjBuilder b;
|
|
b.appendDBRef( "a", "namespace", oid );
|
|
ASSERT_EQUALS( "{ \"a\" : { \"$ns\" : \"namespace\", \"$id\" : \"000000000000000000000000\" } }",
|
|
b.done().jsonString( Strict ) );
|
|
}
|
|
};
|
|
|
|
class ObjectId {
|
|
public:
|
|
void run() {
|
|
OID oid;
|
|
memset( &oid, 0xff, 12 );
|
|
BSONObjBuilder b;
|
|
b.appendOID( "a", &oid );
|
|
ASSERT_EQUALS( "{ \"a\" : \"ffffffffffffffffffffffff\" }",
|
|
b.done().jsonString( Strict ) );
|
|
ASSERT_EQUALS( "{ \"a\" : ObjectId( \"ffffffffffffffffffffffff\" ) }",
|
|
b.done().jsonString( TenGen ) );
|
|
}
|
|
};
|
|
|
|
class BinData {
|
|
public:
|
|
void run() {
|
|
char z[ 3 ];
|
|
z[ 0 ] = 'a';
|
|
z[ 1 ] = 'b';
|
|
z[ 2 ] = 'c';
|
|
BSONObjBuilder b;
|
|
b.appendBinData( "a", 3, ByteArray, z );
|
|
ASSERT_EQUALS( "{ \"a\" : { \"$binary\" : \"YWJj\", \"$type\" : \"02\" } }",
|
|
b.done().jsonString( Strict ) );
|
|
|
|
BSONObjBuilder c;
|
|
c.appendBinData( "a", 2, ByteArray, z );
|
|
ASSERT_EQUALS( "{ \"a\" : { \"$binary\" : \"YWI=\", \"$type\" : \"02\" } }",
|
|
c.done().jsonString( Strict ) );
|
|
|
|
BSONObjBuilder d;
|
|
d.appendBinData( "a", 1, ByteArray, z );
|
|
ASSERT_EQUALS( "{ \"a\" : { \"$binary\" : \"YQ==\", \"$type\" : \"02\" } }",
|
|
d.done().jsonString( Strict ) );
|
|
}
|
|
};
|
|
|
|
class Symbol {
|
|
public:
|
|
void run() {
|
|
BSONObjBuilder b;
|
|
b.appendSymbol( "a", "b" );
|
|
ASSERT_EQUALS( "{ \"a\" : \"b\" }", b.done().jsonString( Strict ) );
|
|
}
|
|
};
|
|
|
|
class Date {
|
|
public:
|
|
void run() {
|
|
BSONObjBuilder b;
|
|
b.appendDate( "a", 0 );
|
|
ASSERT_EQUALS( "{ \"a\" : { \"$date\" : 0 } }", b.done().jsonString( Strict ) );
|
|
ASSERT_EQUALS( "{ \"a\" : Date( 0 ) }", b.done().jsonString( TenGen ) );
|
|
ASSERT_EQUALS( "{ \"a\" : Date( 0 ) }", b.done().jsonString( JS ) );
|
|
}
|
|
};
|
|
|
|
class Regex {
|
|
public:
|
|
void run() {
|
|
BSONObjBuilder b;
|
|
b.appendRegex( "a", "abc", "i" );
|
|
ASSERT_EQUALS( "{ \"a\" : { \"$regex\" : \"abc\", \"$options\" : \"i\" } }",
|
|
b.done().jsonString( Strict ) );
|
|
ASSERT_EQUALS( "{ \"a\" : /abc/i }", b.done().jsonString( TenGen ) );
|
|
ASSERT_EQUALS( "{ \"a\" : /abc/i }", b.done().jsonString( JS ) );
|
|
}
|
|
};
|
|
|
|
class RegexEscape {
|
|
public:
|
|
void run() {
|
|
BSONObjBuilder b;
|
|
b.appendRegex( "a", "/\"", "i" );
|
|
ASSERT_EQUALS( "{ \"a\" : { \"$regex\" : \"\\/\\\"\", \"$options\" : \"i\" } }",
|
|
b.done().jsonString( Strict ) );
|
|
ASSERT_EQUALS( "{ \"a\" : /\\/\\\"/i }", b.done().jsonString( TenGen ) );
|
|
ASSERT_EQUALS( "{ \"a\" : /\\/\\\"/i }", b.done().jsonString( JS ) );
|
|
}
|
|
};
|
|
|
|
class RegexManyOptions {
|
|
public:
|
|
void run() {
|
|
BSONObjBuilder b;
|
|
b.appendRegex( "a", "z", "abcgimx" );
|
|
ASSERT_EQUALS( "{ \"a\" : { \"$regex\" : \"z\", \"$options\" : \"abcgimx\" } }",
|
|
b.done().jsonString( Strict ) );
|
|
ASSERT_EQUALS( "{ \"a\" : /z/gim }", b.done().jsonString( TenGen ) );
|
|
ASSERT_EQUALS( "{ \"a\" : /z/gim }", b.done().jsonString( JS ) );
|
|
}
|
|
};
|
|
|
|
} // namespace JsonStringTests
|
|
} // namespace BSONObjTests
|
|
|
|
|
|
namespace FromJsonTests {
|
|
|
|
class Base {
|
|
public:
|
|
void run() {
|
|
ASSERT( fromjson( json() ).valid() );
|
|
assertEquals( bson(), fromjson( json() ) );
|
|
assertEquals( bson(), fromjson( bson().jsonString( Strict ) ) );
|
|
assertEquals( bson(), fromjson( bson().jsonString( TenGen ) ) );
|
|
assertEquals( bson(), fromjson( bson().jsonString( JS ) ) );
|
|
}
|
|
protected:
|
|
virtual BSONObj bson() const = 0;
|
|
virtual string json() const = 0;
|
|
private:
|
|
static void assertEquals( const BSONObj &expected, const BSONObj &actual ) {
|
|
if ( expected.woCompare( actual ) ) {
|
|
out() << "Expected: " << expected.toString()
|
|
<< ", got: " << actual.toString();
|
|
}
|
|
ASSERT( !expected.woCompare( actual ) );
|
|
}
|
|
};
|
|
|
|
class Bad {
|
|
public:
|
|
void run() {
|
|
ASSERT_EXCEPTION( fromjson( json() ), MsgAssertionException );
|
|
}
|
|
protected:
|
|
virtual string json() const = 0;
|
|
};
|
|
|
|
class Empty : public Base {
|
|
virtual BSONObj bson() const {
|
|
BSONObjBuilder b;
|
|
return b.doneAndDecouple();
|
|
}
|
|
virtual string json() const {
|
|
return "{}";
|
|
}
|
|
};
|
|
|
|
class EmptyWithSpace : public Base {
|
|
virtual BSONObj bson() const {
|
|
BSONObjBuilder b;
|
|
return b.doneAndDecouple();
|
|
}
|
|
virtual string json() const {
|
|
return "{ }";
|
|
}
|
|
};
|
|
|
|
class SingleString : public Base {
|
|
virtual BSONObj bson() const {
|
|
BSONObjBuilder b;
|
|
b.append( "a", "b" );
|
|
return b.doneAndDecouple();
|
|
}
|
|
virtual string json() const {
|
|
return "{ \"a\" : \"b\" }";
|
|
}
|
|
};
|
|
|
|
class EmptyStrings : public Base {
|
|
virtual BSONObj bson() const {
|
|
BSONObjBuilder b;
|
|
b.append( "", "" );
|
|
return b.doneAndDecouple();
|
|
}
|
|
virtual string json() const {
|
|
return "{ \"\" : \"\" }";
|
|
}
|
|
};
|
|
|
|
class ReservedFieldName : public Bad {
|
|
virtual string json() const {
|
|
return "{ \"$ns\" : \"b\" }";
|
|
}
|
|
};
|
|
|
|
class OkDollarFieldName : public Base {
|
|
virtual BSONObj bson() const {
|
|
BSONObjBuilder b;
|
|
b.append( "$where", 1 );
|
|
return b.doneAndDecouple();
|
|
}
|
|
virtual string json() const {
|
|
return "{ \"$where\" : 1 }";
|
|
}
|
|
};
|
|
|
|
class SingleNumber : public Base {
|
|
virtual BSONObj bson() const {
|
|
BSONObjBuilder b;
|
|
b.append( "a", 1 );
|
|
return b.doneAndDecouple();
|
|
}
|
|
virtual string json() const {
|
|
return "{ \"a\" : 1 }";
|
|
}
|
|
};
|
|
|
|
class FancyNumber {
|
|
public:
|
|
void run() {
|
|
ASSERT_EQUALS( bson().firstElement().number(),
|
|
fromjson( json() ).firstElement().number() );
|
|
}
|
|
virtual BSONObj bson() const {
|
|
BSONObjBuilder b;
|
|
b.append( "a", -4.4433e-2 );
|
|
return b.doneAndDecouple();
|
|
}
|
|
virtual string json() const {
|
|
return "{ \"a\" : -4.4433e-2 }";
|
|
}
|
|
};
|
|
|
|
class TwoElements : public Base {
|
|
virtual BSONObj bson() const {
|
|
BSONObjBuilder b;
|
|
b.append( "a", 1 );
|
|
b.append( "b", "foo" );
|
|
return b.doneAndDecouple();
|
|
}
|
|
virtual string json() const {
|
|
return "{ \"a\" : 1, \"b\" : \"foo\" }";
|
|
}
|
|
};
|
|
|
|
class Subobject : public Base {
|
|
virtual BSONObj bson() const {
|
|
BSONObjBuilder b;
|
|
b.append( "a", 1 );
|
|
BSONObjBuilder c;
|
|
c.append( "z", b.done() );
|
|
return c.doneAndDecouple();
|
|
}
|
|
virtual string json() const {
|
|
return "{ \"z\" : { \"a\" : 1 } }";
|
|
}
|
|
};
|
|
|
|
class ArrayEmpty : public Base {
|
|
virtual BSONObj bson() const {
|
|
vector< int > arr;
|
|
BSONObjBuilder b;
|
|
b.append( "a", arr );
|
|
return b.doneAndDecouple();
|
|
}
|
|
virtual string json() const {
|
|
return "{ \"a\" : [] }";
|
|
}
|
|
};
|
|
|
|
class Array : public Base {
|
|
virtual BSONObj bson() const {
|
|
vector< int > arr;
|
|
arr.push_back( 1 );
|
|
arr.push_back( 2 );
|
|
arr.push_back( 3 );
|
|
BSONObjBuilder b;
|
|
b.append( "a", arr );
|
|
return b.doneAndDecouple();
|
|
}
|
|
virtual string json() const {
|
|
return "{ \"a\" : [ 1, 2, 3 ] }";
|
|
}
|
|
};
|
|
|
|
class True : public Base {
|
|
virtual BSONObj bson() const {
|
|
BSONObjBuilder b;
|
|
b.appendBool( "a", true );
|
|
return b.doneAndDecouple();
|
|
}
|
|
virtual string json() const {
|
|
return "{ \"a\" : true }";
|
|
}
|
|
};
|
|
|
|
class False : public Base {
|
|
virtual BSONObj bson() const {
|
|
BSONObjBuilder b;
|
|
b.appendBool( "a", false );
|
|
return b.doneAndDecouple();
|
|
}
|
|
virtual string json() const {
|
|
return "{ \"a\" : false }";
|
|
}
|
|
};
|
|
|
|
class Null : public Base {
|
|
virtual BSONObj bson() const {
|
|
BSONObjBuilder b;
|
|
b.appendNull( "a" );
|
|
return b.doneAndDecouple();
|
|
}
|
|
virtual string json() const {
|
|
return "{ \"a\" : null }";
|
|
}
|
|
};
|
|
|
|
class EscapedCharacters : public Base {
|
|
virtual BSONObj bson() const {
|
|
BSONObjBuilder b;
|
|
b.append( "a", "\" \\ / \b \f \n \r \t" );
|
|
return b.doneAndDecouple();
|
|
}
|
|
virtual string json() const {
|
|
return "{ \"a\" : \"\\\" \\\\ \\/ \\b \\f \\n \\r \\t\" }";
|
|
}
|
|
};
|
|
|
|
class AllowedControlCharacter : public Base {
|
|
virtual BSONObj bson() const {
|
|
BSONObjBuilder b;
|
|
b.append( "a", "\x7f" );
|
|
return b.doneAndDecouple();
|
|
}
|
|
virtual string json() const {
|
|
return "{ \"a\" : \"\x7f\" }";
|
|
}
|
|
};
|
|
|
|
class EscapeFieldName : public Base {
|
|
virtual BSONObj bson() const {
|
|
BSONObjBuilder b;
|
|
b.append( "\n", "b" );
|
|
return b.doneAndDecouple();
|
|
}
|
|
virtual string json() const {
|
|
return "{ \"\\n\" : \"b\" }";
|
|
}
|
|
};
|
|
|
|
class EscapedUnicodeToUtf8 : public Base {
|
|
virtual BSONObj bson() const {
|
|
BSONObjBuilder b;
|
|
char u[ 7 ];
|
|
u[ 0 ] = 0xe0 | 0x0a;
|
|
u[ 1 ] = 0x80;
|
|
u[ 2 ] = 0x80;
|
|
u[ 3 ] = 0xe0 | 0x0a;
|
|
u[ 4 ] = 0x80;
|
|
u[ 5 ] = 0x80;
|
|
u[ 6 ] = 0;
|
|
b.append( "a", u );
|
|
ASSERT_EQUALS( string( u ), b.done().firstElement().valuestr() );
|
|
return b.doneAndDecouple();
|
|
}
|
|
virtual string json() const {
|
|
return "{ \"a\" : \"\\ua000\\uA000\" }";
|
|
}
|
|
};
|
|
|
|
class Utf8AllOnes : public Base {
|
|
virtual BSONObj bson() const {
|
|
BSONObjBuilder b;
|
|
char u[ 8 ];
|
|
u[ 0 ] = 0x01;
|
|
|
|
u[ 1 ] = 0x7f;
|
|
|
|
u[ 2 ] = 0xdf;
|
|
u[ 3 ] = 0xbf;
|
|
|
|
u[ 4 ] = 0xef;
|
|
u[ 5 ] = 0xbf;
|
|
u[ 6 ] = 0xbf;
|
|
|
|
u[ 7 ] = 0;
|
|
|
|
b.append( "a", u );
|
|
return b.doneAndDecouple();
|
|
}
|
|
virtual string json() const {
|
|
return "{ \"a\" : \"\\u0001\\u007f\\u07ff\\uffff\" }";
|
|
}
|
|
};
|
|
|
|
class Utf8FirstByteOnes : public Base {
|
|
virtual BSONObj bson() const {
|
|
BSONObjBuilder b;
|
|
char u[ 6 ];
|
|
u[ 0 ] = 0xdc;
|
|
u[ 1 ] = 0x80;
|
|
|
|
u[ 2 ] = 0xef;
|
|
u[ 3 ] = 0xbc;
|
|
u[ 4 ] = 0x80;
|
|
|
|
u[ 5 ] = 0;
|
|
|
|
b.append( "a", u );
|
|
return b.doneAndDecouple();
|
|
}
|
|
virtual string json() const {
|
|
return "{ \"a\" : \"\\u0700\\uff00\" }";
|
|
}
|
|
};
|
|
|
|
class DBRef : public Base {
|
|
virtual BSONObj bson() const {
|
|
BSONObjBuilder b;
|
|
OID o;
|
|
memset( &o, 0, 12 );
|
|
b.appendDBRef( "a", "foo", o );
|
|
return b.doneAndDecouple();
|
|
}
|
|
// NOTE Testing other formats handled by by Base class.
|
|
virtual string json() const {
|
|
return "{ \"a\" : { \"$ns\" : \"foo\", \"$id\" : \"000000000000000000000000\" } }";
|
|
}
|
|
};
|
|
|
|
class Oid : public Base {
|
|
virtual BSONObj bson() const {
|
|
BSONObjBuilder b;
|
|
b.appendOID( "_id" );
|
|
return b.doneAndDecouple();
|
|
}
|
|
virtual string json() const {
|
|
return "{ \"_id\" : \"000000000000000000000000\" }";
|
|
}
|
|
};
|
|
|
|
class BinData : public Base {
|
|
virtual BSONObj bson() const {
|
|
char z[ 3 ];
|
|
z[ 0 ] = 'a';
|
|
z[ 1 ] = 'b';
|
|
z[ 2 ] = 'c';
|
|
BSONObjBuilder b;
|
|
b.appendBinData( "a", 3, ByteArray, z );
|
|
return b.doneAndDecouple();
|
|
}
|
|
virtual string json() const {
|
|
return "{ \"a\" : { \"$binary\" : \"YWJj\", \"$type\" : \"02\" } }";
|
|
}
|
|
};
|
|
|
|
class BinDataPaddedSingle : public Base {
|
|
virtual BSONObj bson() const {
|
|
char z[ 2 ];
|
|
z[ 0 ] = 'a';
|
|
z[ 1 ] = 'b';
|
|
BSONObjBuilder b;
|
|
b.appendBinData( "a", 2, ByteArray, z );
|
|
return b.doneAndDecouple();
|
|
}
|
|
virtual string json() const {
|
|
return "{ \"a\" : { \"$binary\" : \"YWI=\", \"$type\" : \"02\" } }";
|
|
}
|
|
};
|
|
|
|
class BinDataPaddedDouble : public Base {
|
|
virtual BSONObj bson() const {
|
|
char z[ 1 ];
|
|
z[ 0 ] = 'a';
|
|
BSONObjBuilder b;
|
|
b.appendBinData( "a", 1, ByteArray, z );
|
|
return b.doneAndDecouple();
|
|
}
|
|
virtual string json() const {
|
|
return "{ \"a\" : { \"$binary\" : \"YQ==\", \"$type\" : \"02\" } }";
|
|
}
|
|
};
|
|
|
|
class BinDataAllChars : public Base {
|
|
virtual BSONObj bson() const {
|
|
char z[] = {
|
|
0x00, 0x10, 0x83, 0x10, 0x51, 0x87, 0x20, 0x92, 0x8B, 0x30,
|
|
0xD3, 0x8F, 0x41, 0x14, 0x93, 0x51, 0x55, 0x97, 0x61, 0x96,
|
|
0x9B, 0x71, 0xD7, 0x9F, 0x82, 0x18, 0xA3, 0x92, 0x59, 0xA7,
|
|
0xA2, 0x9A, 0xAB, 0xB2, 0xDB, 0xAF, 0xC3, 0x1C, 0xB3, 0xD3,
|
|
0x5D, 0xB7, 0xE3, 0x9E, 0xBB, 0xF3, 0xDF, 0xBF
|
|
};
|
|
BSONObjBuilder b;
|
|
b.appendBinData( "a", 48, ByteArray, z );
|
|
return b.doneAndDecouple();
|
|
}
|
|
virtual string json() const {
|
|
return "{ \"a\" : { \"$binary\" : \"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/\", \"$type\" : \"02\" } }";
|
|
}
|
|
};
|
|
|
|
class Date : public Base {
|
|
virtual BSONObj bson() const {
|
|
BSONObjBuilder b;
|
|
b.appendDate( "a", 0 );
|
|
return b.doneAndDecouple();
|
|
}
|
|
virtual string json() const {
|
|
return "{ \"a\" : { \"$date\" : 0 } }";
|
|
}
|
|
};
|
|
|
|
class DateNonzero : public Base {
|
|
virtual BSONObj bson() const {
|
|
BSONObjBuilder b;
|
|
b.appendDate( "a", 100 );
|
|
return b.doneAndDecouple();
|
|
}
|
|
virtual string json() const {
|
|
return "{ \"a\" : { \"$date\" : 100 } }";
|
|
}
|
|
};
|
|
|
|
class DateTooLong : public Bad {
|
|
virtual string json() const {
|
|
stringstream ss;
|
|
ss << "{ \"a\" : { \"$date\" : " << ~(0LL) << "0" << " } }";
|
|
return ss.str();
|
|
}
|
|
};
|
|
|
|
class Regex : public Base {
|
|
virtual BSONObj bson() const {
|
|
BSONObjBuilder b;
|
|
b.appendRegex( "a", "b", "i" );
|
|
return b.doneAndDecouple();
|
|
}
|
|
virtual string json() const {
|
|
return "{ \"a\" : { \"$regex\" : \"b\", \"$options\" : \"i\" } }";
|
|
}
|
|
};
|
|
|
|
class RegexEscape : public Base {
|
|
virtual BSONObj bson() const {
|
|
BSONObjBuilder b;
|
|
b.appendRegex( "a", "\t", "i" );
|
|
return b.doneAndDecouple();
|
|
}
|
|
virtual string json() const {
|
|
return "{ \"a\" : { \"$regex\" : \"\\t\", \"$options\" : \"i\" } }";
|
|
}
|
|
};
|
|
|
|
class RegexWithQuotes : public Base {
|
|
virtual BSONObj bson() const {
|
|
BSONObjBuilder b;
|
|
b.appendRegex( "a", "\"", "" );
|
|
return b.doneAndDecouple();
|
|
}
|
|
virtual string json() const {
|
|
return "{ \"a\" : /\"/ }";
|
|
}
|
|
};
|
|
|
|
class RegexInvalidOption : public Bad {
|
|
virtual string json() const {
|
|
return "{ \"a\" : { \"$regex\" : \"b\", \"$options\" : \"1\" } }";
|
|
}
|
|
};
|
|
|
|
class RegexInvalidOption2 : public Bad {
|
|
virtual string json() const {
|
|
return "{ \"a\" : /b/c }";
|
|
}
|
|
};
|
|
|
|
class Malformed : public Bad {
|
|
string json() const {
|
|
return "{";
|
|
}
|
|
};
|
|
|
|
} // namespace FromJsonTests
|
|
|
|
namespace OIDTests {
|
|
class init1 {
|
|
public:
|
|
void run(){
|
|
OID a;
|
|
OID b;
|
|
|
|
a.init();
|
|
b.init();
|
|
|
|
ASSERT( a != b );
|
|
}
|
|
};
|
|
}
|
|
|
|
class All : public UnitTest::Suite {
|
|
public:
|
|
All() {
|
|
add< BSONObjTests::Create >();
|
|
add< BSONObjTests::WoCompareBasic >();
|
|
add< BSONObjTests::NumericCompareBasic >();
|
|
add< BSONObjTests::WoCompareEmbeddedObject >();
|
|
add< BSONObjTests::WoCompareEmbeddedArray >();
|
|
add< BSONObjTests::WoCompareOrdered >();
|
|
add< BSONObjTests::Validation::BadType >();
|
|
add< BSONObjTests::Validation::EooBeforeEnd >();
|
|
add< BSONObjTests::Validation::UndefinedBeforeEnd >();
|
|
add< BSONObjTests::Validation::TotalSizeTooSmall >();
|
|
add< BSONObjTests::Validation::EooMissing >();
|
|
add< BSONObjTests::Validation::WrongStringSize >();
|
|
add< BSONObjTests::Validation::WrongSubobjectSize >();
|
|
add< BSONObjTests::Validation::WrongDbrefNsSize >();
|
|
add< BSONObjTests::Validation::WrongSymbolSize >();
|
|
add< BSONObjTests::Validation::NoFieldNameEnd >();
|
|
add< BSONObjTests::Validation::BadRegex >();
|
|
add< BSONObjTests::Validation::BadRegexOptions >();
|
|
add< BSONObjTests::Validation::NoSize >( Symbol );
|
|
add< BSONObjTests::Validation::NoSize >( Code );
|
|
add< BSONObjTests::Validation::NoSize >( String );
|
|
add< BSONObjTests::Validation::NoSize >( CodeWScope );
|
|
add< BSONObjTests::Validation::NoSize >( DBRef );
|
|
add< BSONObjTests::Validation::NoSize >( Object );
|
|
add< BSONObjTests::Validation::NoSize >( Array );
|
|
add< BSONObjTests::Validation::NoSize >( BinData );
|
|
add< BSONObjTests::Validation::Fuzz >();
|
|
add< BSONObjTests::Validation::RandomBytes >();
|
|
add< BSONObjTests::JsonStringTests::Empty >();
|
|
add< BSONObjTests::JsonStringTests::SingleStringMember >();
|
|
add< BSONObjTests::JsonStringTests::EscapedCharacters >();
|
|
add< BSONObjTests::JsonStringTests::AdditionalControlCharacters >();
|
|
add< BSONObjTests::JsonStringTests::ExtendedAscii >();
|
|
add< BSONObjTests::JsonStringTests::EscapeFieldName >();
|
|
add< BSONObjTests::JsonStringTests::SingleIntMember >();
|
|
add< BSONObjTests::JsonStringTests::SingleNumberMember >();
|
|
add< BSONObjTests::JsonStringTests::InvalidNumbers >();
|
|
add< BSONObjTests::JsonStringTests::NumberPrecision >();
|
|
add< BSONObjTests::JsonStringTests::NegativeNumber >();
|
|
add< BSONObjTests::JsonStringTests::SingleBoolMember >();
|
|
add< BSONObjTests::JsonStringTests::SingleNullMember >();
|
|
add< BSONObjTests::JsonStringTests::SingleObjectMember >();
|
|
add< BSONObjTests::JsonStringTests::TwoMembers >();
|
|
add< BSONObjTests::JsonStringTests::EmptyArray >();
|
|
add< BSONObjTests::JsonStringTests::Array >();
|
|
add< BSONObjTests::JsonStringTests::DBRef >();
|
|
add< BSONObjTests::JsonStringTests::DBRefZero >();
|
|
add< BSONObjTests::JsonStringTests::ObjectId >();
|
|
add< BSONObjTests::JsonStringTests::BinData >();
|
|
add< BSONObjTests::JsonStringTests::Symbol >();
|
|
add< BSONObjTests::JsonStringTests::Date >();
|
|
add< BSONObjTests::JsonStringTests::Regex >();
|
|
add< BSONObjTests::JsonStringTests::RegexEscape >();
|
|
add< BSONObjTests::JsonStringTests::RegexManyOptions >();
|
|
add< FromJsonTests::Empty >();
|
|
add< FromJsonTests::EmptyWithSpace >();
|
|
add< FromJsonTests::SingleString >();
|
|
add< FromJsonTests::EmptyStrings >();
|
|
add< FromJsonTests::ReservedFieldName >();
|
|
add< FromJsonTests::OkDollarFieldName >();
|
|
add< FromJsonTests::SingleNumber >();
|
|
add< FromJsonTests::FancyNumber >();
|
|
add< FromJsonTests::TwoElements >();
|
|
add< FromJsonTests::Subobject >();
|
|
add< FromJsonTests::ArrayEmpty >();
|
|
add< FromJsonTests::Array >();
|
|
add< FromJsonTests::True >();
|
|
add< FromJsonTests::False >();
|
|
add< FromJsonTests::Null >();
|
|
add< FromJsonTests::EscapedCharacters >();
|
|
add< FromJsonTests::AllowedControlCharacter >();
|
|
add< FromJsonTests::EscapeFieldName >();
|
|
add< FromJsonTests::EscapedUnicodeToUtf8 >();
|
|
add< FromJsonTests::Utf8AllOnes >();
|
|
add< FromJsonTests::Utf8FirstByteOnes >();
|
|
add< FromJsonTests::DBRef >();
|
|
add< FromJsonTests::Oid >();
|
|
add< FromJsonTests::BinData >();
|
|
add< FromJsonTests::BinDataPaddedSingle >();
|
|
add< FromJsonTests::BinDataPaddedDouble >();
|
|
add< FromJsonTests::BinDataAllChars >();
|
|
add< FromJsonTests::Date >();
|
|
add< FromJsonTests::DateNonzero >();
|
|
add< FromJsonTests::DateTooLong >();
|
|
add< FromJsonTests::Regex >();
|
|
add< FromJsonTests::RegexEscape >();
|
|
add< FromJsonTests::RegexWithQuotes >();
|
|
add< FromJsonTests::RegexInvalidOption >();
|
|
add< FromJsonTests::RegexInvalidOption2 >();
|
|
add< FromJsonTests::Malformed >();
|
|
|
|
add< OIDTests::init1 >();
|
|
}
|
|
};
|
|
|
|
} // namespace JsobjTests
|
|
|
|
UnitTest::TestPtr jsobjTests() {
|
|
return UnitTest::createSuite< JsobjTests::All >();
|
|
}
|