// jsobjtests.cpp - Tests for jsobj.{h,cpp} code
//
/**
* 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 .
*
* As a special exception, the copyright holders give permission to link the
* code of portions of this program with the OpenSSL library under certain
* conditions as described in each individual source file and distribute
* linked combinations including the program with the OpenSSL library. You
* must comply with the GNU Affero General Public License in all respects
* for all of the code used other than as permitted herein. If you modify
* file(s) with this exception, you may extend this exception to your
* version of the file(s), but you are not obligated to do so. If you do not
* wish to do so, delete this exception statement from your version. If you
* delete this exception statement from all source files in the program,
* then also delete it in the license file.
*/
#define MONGO_LOG_DEFAULT_COMPONENT ::mongo::logger::LogComponent::kDefault
#define MONGO_PCH_WHITELISTED
#include "mongo/platform/basic.h"
#include "mongo/pch.h"
#undef MONGO_PCH_WHITELISTED
#include
#include "mongo/bson/util/builder.h"
#include "mongo/db/jsobj.h"
#include "mongo/db/json.h"
#include "mongo/db/storage/mmap_v1/btree/key.h"
#include "mongo/dbtests/dbtests.h"
#include "mongo/platform/float_utils.h"
#include "mongo/util/allocator.h"
#include "mongo/util/embedded_builder.h"
#include "mongo/util/log.h"
#include "mongo/util/stringutils.h"
namespace mongo {
typedef std::map BSONMap;
BSONMap bson2map(const BSONObj& obj) {
BSONMap m;
BSONObjIterator it(obj);
while (it.more()) {
BSONElement e = it.next();
m[e.fieldName()] = e;
}
return m;
}
void dotted2nested(BSONObjBuilder& b, const BSONObj& obj) {
//use map to sort fields
BSONMap sorted = bson2map(obj);
EmbeddedBuilder eb(&b);
for(BSONMap::const_iterator it=sorted.begin(); it!=sorted.end(); ++it) {
eb.appendAs(it->second, it->first);
}
eb.done();
}
// {a.b:1} -> {a: {b:1}}
BSONObj dotted2nested(const BSONObj& obj) {
BSONObjBuilder b;
dotted2nested(b, obj);
return b.obj();
}
// {a: {b:1}} -> {a.b:1}
void nested2dotted(BSONObjBuilder& b, const BSONObj& obj, const string& base="") {
BSONObjIterator it(obj);
while (it.more()) {
BSONElement e = it.next();
if (e.type() == Object) {
string newbase = base + e.fieldName() + ".";
nested2dotted(b, e.embeddedObject(), newbase);
}
else {
string newbase = base + e.fieldName();
b.appendAs(e, newbase);
}
}
}
BSONObj nested2dotted(const BSONObj& obj) {
BSONObjBuilder b;
nested2dotted(b, obj);
return b.obj();
}
FieldCompareResult compareDottedFieldNames( const string& l , const string& r ,
const LexNumCmp& cmp ) {
static int maxLoops = 1024 * 1024;
size_t lstart = 0;
size_t rstart = 0;
for ( int i=0; i 0 )
return RIGHT_BEFORE;
lstart = lend + 1;
rstart = rend + 1;
if ( lstart >= l.size() ) {
if ( rstart >= r.size() )
return SAME;
return RIGHT_SUBFIELD;
}
if ( rstart >= r.size() )
return LEFT_SUBFIELD;
}
log() << "compareDottedFieldNames ERROR l: " << l << " r: " << r << " TOO MANY LOOPS" << endl;
verify(0);
return SAME; // will never get here
}
}
namespace JsobjTests {
void keyTest(const BSONObj& o, bool mustBeCompact = false) {
static KeyV1Owned *kLast;
static BSONObj last;
KeyV1Owned *key = new KeyV1Owned(o);
KeyV1Owned& k = *key;
ASSERT( !mustBeCompact || k.isCompactFormat() );
BSONObj x = k.toBson();
int res = o.woCompare(x, BSONObj(), /*considerfieldname*/false);
if( res ) {
cout << o.toString() << endl;
k.toBson();
cout << x.toString() << endl;
o.woCompare(x, BSONObj(), /*considerfieldname*/false);
ASSERT( res == 0 );
}
ASSERT( k.woEqual(k) );
ASSERT( !k.isCompactFormat() || k.dataSize() < o.objsize() );
{
// check BSONObj::equal. this part not a KeyV1 test.
int res = o.woCompare(last);
ASSERT( (res==0) == o.equal(last) );
}
if( kLast ) {
int r1 = o.woCompare(last, BSONObj(), false);
int r2 = k.woCompare(*kLast, Ordering::make(BSONObj()));
bool ok = (r1<0 && r2<0) || (r1>0&&r2>0) || r1==r2;
if( !ok ) {
cout << "r1r2 " << r1 << ' ' << r2 << endl;
cout << "o:" << o.toString() << endl;
cout << "last:" << last.toString() << endl;
cout << "k:" << k.toString() << endl;
cout << "kLast:" << kLast->toString() << endl;
int r3 = k.woCompare(*kLast, Ordering::make(BSONObj()));
cout << r3 << endl;
}
ASSERT(ok);
if( k.isCompactFormat() && kLast->isCompactFormat() ) { // only check if not bson as bson woEqual is broken! (or was may2011)
if( k.woEqual(*kLast) != (r2 == 0) ) { // check woEqual matches
cout << r2 << endl;
cout << k.toString() << endl;
cout << kLast->toString() << endl;
k.woEqual(*kLast);
ASSERT(false);
}
}
}
delete kLast;
kLast = key;
last = o.getOwned();
}
class BufBuilderBasic {
public:
void run() {
{
BufBuilder b( 0 );
b.appendStr( "foo" );
ASSERT_EQUALS( 4, b.len() );
ASSERT( strcmp( "foo", b.buf() ) == 0 );
}
{
mongo::StackBufBuilder b;
b.appendStr( "foo" );
ASSERT_EQUALS( 4, b.len() );
ASSERT( strcmp( "foo", b.buf() ) == 0 );
}
}
};
class BufBuilderReallocLimit {
public:
void run() {
BufBuilder b;
unsigned int written = 0;
try {
for (; written <= 64 * 1024 * 1024 + 1; ++written)
// (re)alloc past the buffer 64mb limit
b.appendStr("a");
}
catch (const AssertionException&) { }
// assert half of max buffer size was allocated before exception is thrown
ASSERT(written == mongo::BufferMaxSize / 2);
}
};
class BSONElementBasic {
public:
void run() {
ASSERT_EQUALS( 1, BSONElement().size() );
BSONObj x;
ASSERT_EQUALS( 1, x.firstElement().size() );
}
};
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.append( name, val );
return b.obj();
}
static BSONObj basic( const char *name, vector< int > val ) {
BSONObjBuilder b;
b.append( name, val );
return b.obj();
}
template< class T >
static BSONObj basic( const char *name, T val ) {
BSONObjBuilder b;
b.append( name, val );
return b.obj();
}
};
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 IsPrefixOf : public Base {
public:
void run() {
{
BSONObj k = BSON( "x" << 1 );
verify( ! k.isPrefixOf( BSON( "a" << 1 ) ) );
verify( k.isPrefixOf( BSON( "x" << 1 ) ) );
verify( k.isPrefixOf( BSON( "x" << 1 << "a" << 1 ) ) );
verify( ! k.isPrefixOf( BSON( "a" << 1 << "x" << 1 ) ) );
}
{
BSONObj k = BSON( "x" << 1 << "y" << 1 );
verify( ! k.isPrefixOf( BSON( "x" << 1 ) ) );
verify( ! k.isPrefixOf( BSON( "x" << 1 << "z" << 1 ) ) );
verify( k.isPrefixOf( BSON( "x" << 1 << "y" << 1 ) ) );
verify( k.isPrefixOf( BSON( "x" << 1 << "y" << 1 << "z" << 1 ) ) );
}
{
BSONObj k = BSON( "x" << 1 );
verify( ! k.isPrefixOf( BSON( "x" << "hi" ) ) );
verify( k.isPrefixOf( BSON( "x" << 1 << "a" << "hi" ) ) );
}
{
BSONObj k = BSON( "x" << 1 );
verify( k.isFieldNamePrefixOf( BSON( "x" << "hi" ) ) );
verify( ! k.isFieldNamePrefixOf( BSON( "a" << 1 ) ) );
}
}
};
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 );
}
};
class WoCompareDifferentLength : public Base {
public:
void run() {
ASSERT( BSON( "a" << 1 ).woCompare( BSON( "a" << 1 << "b" << 1 ) ) < 0 );
ASSERT( BSON( "a" << 1 << "b" << 1 ).woCompare( BSON( "a" << 1 ) ) > 0 );
}
};
class WoSortOrder : public Base {
public:
void run() {
ASSERT( BSON( "a" << 1 ).woSortOrder( BSON( "a" << 2 ), BSON( "b" << 1 << "a" << 1 ) ) < 0 );
ASSERT( fromjson( "{a:null}" ).woSortOrder( BSON( "b" << 1 ), BSON( "a" << 1 ) ) == 0 );
}
};
class MultiKeySortOrder : public Base {
public:
void run() {
ASSERT( BSON( "x" << "a" ).woCompare( BSON( "x" << "b" ) ) < 0 );
ASSERT( BSON( "x" << "b" ).woCompare( BSON( "x" << "a" ) ) > 0 );
ASSERT( BSON( "x" << "a" << "y" << "a" ).woCompare( BSON( "x" << "a" << "y" << "b" ) ) < 0 );
ASSERT( BSON( "x" << "a" << "y" << "a" ).woCompare( BSON( "x" << "b" << "y" << "a" ) ) < 0 );
ASSERT( BSON( "x" << "a" << "y" << "a" ).woCompare( BSON( "x" << "b" ) ) < 0 );
ASSERT( BSON( "x" << "c" ).woCompare( BSON( "x" << "b" << "y" << "h" ) ) > 0 );
ASSERT( BSON( "x" << "b" << "y" << "b" ).woCompare( BSON( "x" << "c" ) ) < 0 );
BSONObj key = BSON( "x" << 1 << "y" << 1 );
ASSERT( BSON( "x" << "c" ).woSortOrder( BSON( "x" << "b" << "y" << "h" ) , key ) > 0 );
ASSERT( BSON( "x" << "b" << "y" << "b" ).woCompare( BSON( "x" << "c" ) , key ) < 0 );
key = BSON( "" << 1 << "" << 1 );
ASSERT( BSON( "" << "c" ).woSortOrder( BSON( "" << "b" << "" << "h" ) , key ) > 0 );
ASSERT( BSON( "" << "b" << "" << "b" ).woCompare( BSON( "" << "c" ) , key ) < 0 );
{
// test a big key
string x(2000, 'z');
BSONObj o = BSON( "q" << x );
keyTest(o, false);
}
{
string y(200, 'w');
BSONObjBuilder b;
for( int i = 0; i < 10; i++ ) {
b.append("x", y);
}
keyTest(b.obj(), true);
}
{
double nan = numeric_limits::quiet_NaN();
BSONObj o = BSON( "y" << nan );
keyTest(o);
}
{
BSONObjBuilder b;
b.append( "" , "c" );
b.appendNull( "" );
BSONObj o = b.obj();
keyTest(o);
ASSERT( o.woSortOrder( BSON( "" << "b" << "" << "h" ) , key ) > 0 );
ASSERT( BSON( "" << "b" << "" << "h" ).woSortOrder( o , key ) < 0 );
}
ASSERT( BSON( "" << "a" ).woCompare( BSON( "" << "a" << "" << "c" ) ) < 0 );
{
BSONObjBuilder b;
b.append( "" , "a" );
b.appendNull( "" );
ASSERT( b.obj().woCompare( BSON( "" << "a" << "" << "c" ) ) < 0 ); // SERVER-282
}
}
};
class Nan : public Base {
public:
void run() {
double inf = numeric_limits< double >::infinity();
double nan = numeric_limits< double >::quiet_NaN();
double nan2 = numeric_limits< double >::signaling_NaN();
ASSERT( isNaN(nan) );
ASSERT( isNaN(nan2) );
ASSERT( !isNaN(inf) );
ASSERT( BSON( "a" << inf ).woCompare( BSON( "a" << inf ) ) == 0 );
ASSERT( BSON( "a" << inf ).woCompare( BSON( "a" << 1 ) ) > 0 );
ASSERT( BSON( "a" << 1 ).woCompare( BSON( "a" << inf ) ) < 0 );
ASSERT( BSON( "a" << nan ).woCompare( BSON( "a" << nan ) ) == 0 );
ASSERT( BSON( "a" << nan ).woCompare( BSON( "a" << 1 ) ) < 0 );
ASSERT( BSON( "a" << nan ).woCompare( BSON( "a" << 5000000000LL ) ) < 0 );
{
KeyV1Owned a( BSON( "a" << nan ) );
KeyV1Owned b( BSON( "a" << 1 ) );
Ordering o = Ordering::make(BSON("a"<<1));
ASSERT( a.woCompare(b, o) < 0 );
}
ASSERT( BSON( "a" << 1 ).woCompare( BSON( "a" << nan ) ) > 0 );
ASSERT( BSON( "a" << nan2 ).woCompare( BSON( "a" << nan2 ) ) == 0 );
ASSERT( BSON( "a" << nan2 ).woCompare( BSON( "a" << 1 ) ) < 0 );
ASSERT( BSON( "a" << 1 ).woCompare( BSON( "a" << nan2 ) ) > 0 );
ASSERT( BSON( "a" << inf ).woCompare( BSON( "a" << nan ) ) > 0 );
ASSERT( BSON( "a" << inf ).woCompare( BSON( "a" << nan2 ) ) > 0 );
ASSERT( BSON( "a" << nan ).woCompare( BSON( "a" << nan2 ) ) == 0 );
}
};
class AsTempObj {
public:
void run() {
{
BSONObjBuilder bb;
bb << "a" << 1;
BSONObj tmp = bb.asTempObj();
ASSERT(tmp.objsize() == 4+(1+2+4)+1);
ASSERT(tmp.valid());
ASSERT(tmp.hasField("a"));
ASSERT(!tmp.hasField("b"));
ASSERT(tmp == BSON("a" << 1));
bb << "b" << 2;
BSONObj obj = bb.obj();
ASSERT_EQUALS(obj.objsize() , 4+(1+2+4)+(1+2+4)+1);
ASSERT(obj.valid());
ASSERT(obj.hasField("a"));
ASSERT(obj.hasField("b"));
ASSERT(obj == BSON("a" << 1 << "b" << 2));
}
{
BSONObjBuilder bb;
bb << "a" << GT << 1;
BSONObj tmp = bb.asTempObj();
ASSERT(tmp.objsize() == 4+(1+2+(4+1+4+4+1))+1);
ASSERT(tmp.valid());
ASSERT(tmp.hasField("a"));
ASSERT(!tmp.hasField("b"));
ASSERT(tmp == BSON("a" << BSON("$gt" << 1)));
bb << "b" << LT << 2;
BSONObj obj = bb.obj();
ASSERT(obj.objsize() == 4+(1+2+(4+1+4+4+1))+(1+2+(4+1+4+4+1))+1);
ASSERT(obj.valid());
ASSERT(obj.hasField("a"));
ASSERT(obj.hasField("b"));
ASSERT(obj == BSON("a" << BSON("$gt" << 1)
<< "b" << BSON("$lt" << 2)));
}
{
BSONObjBuilder bb(32);
bb << "a" << 1;
BSONObj tmp = bb.asTempObj();
ASSERT(tmp.objsize() == 4+(1+2+4)+1);
ASSERT(tmp.valid());
ASSERT(tmp.hasField("a"));
ASSERT(!tmp.hasField("b"));
ASSERT(tmp == BSON("a" << 1));
//force a realloc
BSONArrayBuilder arr;
for (int i=0; i < 10000; i++) {
arr << i;
}
bb << "b" << arr.arr();
BSONObj obj = bb.obj();
ASSERT(obj.valid());
ASSERT(obj.hasField("a"));
ASSERT(obj.hasField("b"));
}
}
};
struct AppendIntOrLL {
void run() {
const long long billion = 1000*1000*1000;
long long n = 0x3333111122224444LL;
{
double d = (double) n;
BSONObj a = BSON( "x" << n );
BSONObj b = BSON( "x" << d );
long long back = (long long) d;
//3719
////// int res = a.woCompare(b);
ASSERT( n > back );
//ASSERT( res > 0 ); // SERVER-3719
keyTest(a, false);
KeyV1Owned A(a);
KeyV1Owned B(b);
//3719
////// int res2 = A.woCompare(B, Ordering::make(BSONObj()));
// ASSERT( res2 > 0 ); // SERVER-3719
// fixing requires an index v# change.
cout << "todo fix SERVER-3719 and uncomment test in AppendIntOrLL" << endl;
n++;
}
{
BSONObjBuilder b;
b.appendIntOrLL("L4", -4*billion);
keyTest(b.obj());
keyTest( BSON("" << billion) );
}
BSONObjBuilder b;
b.appendIntOrLL("i1", 1);
b.appendIntOrLL("i2", -1);
b.appendIntOrLL("i3", 1*billion);
b.appendIntOrLL("i4", -1*billion);
b.appendIntOrLL("L1", 2*billion);
b.appendIntOrLL("L2", -2*billion);
b.appendIntOrLL("L3", 4*billion);
b.appendIntOrLL("L4", -4*billion);
b.appendIntOrLL("L5", 16*billion);
b.appendIntOrLL("L6", -16*billion);
BSONObj o = b.obj();
keyTest(o);
ASSERT(o["i1"].type() == NumberInt);
ASSERT(o["i1"].number() == 1);
ASSERT(o["i2"].type() == NumberInt);
ASSERT(o["i2"].number() == -1);
ASSERT(o["i3"].type() == NumberInt);
ASSERT(o["i3"].number() == 1*billion);
ASSERT(o["i4"].type() == NumberInt);
ASSERT(o["i4"].number() == -1*billion);
ASSERT(o["L1"].isNumber());
ASSERT(o["L1"].number() == 2*billion);
ASSERT(o["L2"].isNumber());
ASSERT(o["L2"].number() == -2*billion);
ASSERT(o["L3"].type() == NumberLong);
ASSERT(o["L3"].number() == 4*billion);
ASSERT(o["L4"].type() == NumberLong);
ASSERT(o["L4"].number() == -4*billion);
ASSERT(o["L5"].type() == NumberLong);
ASSERT(o["L5"].number() == 16*billion);
ASSERT(o["L6"].type() == NumberLong);
ASSERT(o["L6"].number() == -16*billion);
}
};
struct AppendNumber {
void run() {
BSONObjBuilder b;
b.appendNumber( "a" , 5 );
b.appendNumber( "b" , 5.5 );
b.appendNumber( "c" , (1024LL*1024*1024)-1 );
b.appendNumber( "d" , (1024LL*1024*1024*1024)-1 );
b.appendNumber( "e" , 1024LL*1024*1024*1024*1024*1024 );
BSONObj o = b.obj();
keyTest(o);
ASSERT( o["a"].type() == NumberInt );
ASSERT( o["b"].type() == NumberDouble );
ASSERT( o["c"].type() == NumberInt );
ASSERT( o["d"].type() == NumberDouble );
ASSERT( o["e"].type() == NumberLong );
}
};
class ToStringArray {
public:
void run() {
string spec = "{ a: [ \"a\", \"b\" ] }";
ASSERT_EQUALS( spec, fromjson( spec ).toString() );
BSONObj x = BSON( "a" << "astring" << "b" << "str" );
keyTest(x);
keyTest(x);
BSONObj y = BSON( "a" << "astring" << "b" << "stra" );
keyTest(y);
y = BSON( "a" << "" );
keyTest(y);
keyTest( BSON("abc" << true ) );
keyTest( BSON("abc" << false ) );
keyTest( BSON("abc" << false << "b" << true ) );
Date_t now = jsTime();
keyTest( BSON("" << now << "" << 3 << "" << jstNULL << "" << true) );
keyTest( BSON("" << now << "" << 3 << "" << BSONObj() << "" << true) );
{
{
// check signed dates with new key format
KeyV1Owned a( BSONObjBuilder().appendDate("", -50).obj() );
KeyV1Owned b( BSONObjBuilder().appendDate("", 50).obj() );
ASSERT( a.woCompare(b, Ordering::make(BSONObj())) < 0 );
}
{
// backward compatibility
KeyBson a( BSONObjBuilder().appendDate("", -50).obj() );
KeyBson b( BSONObjBuilder().appendDate("", 50).obj() );
ASSERT( a.woCompare(b, Ordering::make(BSONObj())) > 0 );
}
{
// this is an uncompactable key:
BSONObj uc1 = BSONObjBuilder().appendDate("", -50).appendCode("", "abc").obj();
BSONObj uc2 = BSONObjBuilder().appendDate("", 55).appendCode("", "abc").obj();
ASSERT( uc1.woCompare(uc2, Ordering::make(BSONObj())) < 0 );
{
KeyV1Owned a(uc1);
KeyV1Owned b(uc2);
ASSERT( !a.isCompactFormat() );
ASSERT( a.woCompare(b, Ordering::make(BSONObj())) < 0 );
}
{
KeyBson a(uc1);
KeyBson b(uc2);
ASSERT( !a.isCompactFormat() );
ASSERT( a.woCompare(b, Ordering::make(BSONObj())) > 0 );
}
}
}
{
BSONObjBuilder b;
b.appendBinData("f", 8, (BinDataType) 1, "aaaabbbb");
b.appendBinData("e", 3, (BinDataType) 1, "aaa");
b.appendBinData("b", 1, (BinDataType) 1, "x");
BSONObj o = b.obj();
keyTest( o, true );
}
{
// check (non)equality
BSONObj a = BSONObjBuilder().appendBinData("", 8, (BinDataType) 1, "abcdefgh").obj();
BSONObj b = BSONObjBuilder().appendBinData("", 8, (BinDataType) 1, "abcdefgj").obj();
ASSERT( !a.equal(b) );
int res_ab = a.woCompare(b);
ASSERT( res_ab != 0 );
keyTest( a, true );
keyTest( b, true );
// check subtypes do not equal
BSONObj c = BSONObjBuilder().appendBinData("", 8, (BinDataType) 4, "abcdefgh").obj();
BSONObj d = BSONObjBuilder().appendBinData("", 8, (BinDataType) 0x81, "abcdefgh").obj();
ASSERT( !a.equal(c) );
int res_ac = a.woCompare(c);
ASSERT( res_ac != 0 );
keyTest( c, true );
ASSERT( !a.equal(d) );
int res_ad = a.woCompare(d);
ASSERT( res_ad != 0 );
keyTest( d, true );
KeyV1Owned A(a);
KeyV1Owned B(b);
KeyV1Owned C(c);
KeyV1Owned D(d);
ASSERT( !A.woEqual(B) );
ASSERT( A.woCompare(B, Ordering::make(BSONObj())) < 0 && res_ab < 0 );
ASSERT( !A.woEqual(C) );
ASSERT( A.woCompare(C, Ordering::make(BSONObj())) < 0 && res_ac < 0 );
ASSERT( !A.woEqual(D) );
ASSERT( A.woCompare(D, Ordering::make(BSONObj())) < 0 && res_ad < 0 );
}
{
BSONObjBuilder b;
b.appendBinData("f", 33, (BinDataType) 1, "123456789012345678901234567890123");
BSONObj o = b.obj();
keyTest( o, false );
}
{
for( int i = 1; i <= 3; i++ ) {
for( int j = 1; j <= 3; j++ ) {
BSONObjBuilder b;
b.appendBinData("f", i, (BinDataType) j, "abc");
BSONObj o = b.obj();
keyTest( o, j != ByteArrayDeprecated );
}
}
}
{
BSONObjBuilder b;
b.appendBinData("f", 1, (BinDataType) 133, "a");
BSONObj o = b.obj();
keyTest( o, true );
}
{
BSONObjBuilder b;
b.append("AA", 3);
b.appendBinData("f", 0, (BinDataType) 0, "");
b.appendBinData("e", 3, (BinDataType) 7, "aaa");
b.appendBinData("b", 1, (BinDataType) 128, "x");
b.append("z", 3);
b.appendBinData("bb", 0, (BinDataType) 129, "x");
BSONObj o = b.obj();
keyTest( o, true );
}
{
// 9 is not supported in compact format. so test a non-compact case here.
BSONObjBuilder b;
b.appendBinData("f", 9, (BinDataType) 0, "aaaabbbbc");
BSONObj o = b.obj();
keyTest( o );
}
}
};
class ToStringNumber {
public:
void run() {
BSONObjBuilder b;
b.append( "a" , (int)4 );
b.append( "b" , (double)5 );
b.append( "c" , (long long)6 );
b.append( "d" , 123.456789123456789123456789123456789 );
b.append( "e" , 123456789.123456789123456789123456789 );
b.append( "f" , 1234567891234567891234.56789123456789 );
b.append( "g" , -123.456 );
b.append( "h" , 0.0 );
b.append( "i" , -0.0 );
BSONObj x = b.obj();
keyTest(x);
ASSERT_EQUALS( "4", x["a"].toString( false , true ) );
ASSERT_EQUALS( "5.0", x["b"].toString( false , true ) );
ASSERT_EQUALS( "6", x["c"].toString( false , true ) );
ASSERT_EQUALS( "123.4567891234568" , x["d"].toString( false , true ) );
ASSERT_EQUALS( "123456789.1234568" , x["e"].toString( false , true ) );
// ASSERT_EQUALS( "1.234567891234568e+21" , x["f"].toString( false , true ) ); // windows and *nix are different - TODO, work around for test or not bother?
ASSERT_EQUALS( "-123.456" , x["g"].toString( false , true ) );
ASSERT_EQUALS( "0.0" , x["h"].toString( false , true ) );
ASSERT_EQUALS( "-0.0" , x["i"].toString( false , true ) );
}
};
class NullString {
public:
void run() {
{
BSONObjBuilder b;
const char x[] = {'a', 0, 'b', 0};
b.append("field", x, 4);
b.append("z", true);
BSONObj B = b.obj();
//cout << B.toString() << endl;
BSONObjBuilder a;
const char xx[] = {'a', 0, 'c', 0};
a.append("field", xx, 4);
a.append("z", true);
BSONObj A = a.obj();
BSONObjBuilder c;
const char xxx[] = {'a', 0, 'c', 0, 0};
c.append("field", xxx, 5);
c.append("z", true);
BSONObj C = c.obj();
// test that nulls are ok within bson strings
ASSERT( !(A == B) );
ASSERT( A > B );
ASSERT( !(B == C) );
ASSERT( C > B );
// check iteration is ok
ASSERT( B["z"].Bool() && A["z"].Bool() && C["z"].Bool() );
}
BSONObjBuilder b;
b.append("a", "a\0b", 4);
string z("a\0b", 3);
b.append("b", z);
b.appendAs(b.asTempObj()["a"], "c");
BSONObj o = b.obj();
keyTest(o);
stringstream ss;
ss << 'a' << '\0' << 'b';
ASSERT_EQUALS(o["a"].valuestrsize(), 3+1);
ASSERT_EQUALS(o["a"].str(), ss.str());
ASSERT_EQUALS(o["b"].valuestrsize(), 3+1);
ASSERT_EQUALS(o["b"].str(), ss.str());
ASSERT_EQUALS(o["c"].valuestrsize(), 3+1);
ASSERT_EQUALS(o["c"].str(), ss.str());
}
};
class AppendAs {
public:
void run() {
BSONObjBuilder b;
{
BSONObj foo = BSON( "foo" << 1 );
b.appendAs( foo.firstElement(), "bar" );
}
ASSERT_EQUALS( BSON( "bar" << 1 ), b.done() );
}
};
class GetField {
public:
void run(){
BSONObj o = BSON( "a" << 1 <<
"b" << BSON( "a" << 2 ) <<
"c" << BSON_ARRAY( BSON( "a" << 3 ) << BSON( "a" << 4 ) ) );
ASSERT_EQUALS( 1 , o.getFieldDotted( "a" ).numberInt() );
ASSERT_EQUALS( 2 , o.getFieldDotted( "b.a" ).numberInt() );
ASSERT_EQUALS( 3 , o.getFieldDotted( "c.0.a" ).numberInt() );
ASSERT_EQUALS( 4 , o.getFieldDotted( "c.1.a" ).numberInt() );
ASSERT( o.getFieldDotted( "x" ).eoo() );
ASSERT( o.getFieldDotted( "a.x" ).eoo() );
ASSERT( o.getFieldDotted( "x.y" ).eoo() );
ASSERT( o.getFieldDotted( "" ).eoo() );
ASSERT( o.getFieldDotted( "." ).eoo() );
ASSERT( o.getFieldDotted( ".." ).eoo() );
ASSERT( o.getFieldDotted( "..." ).eoo() );
ASSERT( o.getFieldDotted( "a." ).eoo() );
ASSERT( o.getFieldDotted( ".a" ).eoo() );
ASSERT( o.getFieldDotted( "b.a." ).eoo() );
keyTest(o);
}
};
class ToStringRecursionDepth {
public:
// create a nested BSON object with the specified recursion depth
BSONObj recursiveBSON( int depth ) {
BSONObjBuilder b;
if ( depth==0 ) {
b << "name" << "Joe";
return b.obj();
}
b.append( "test", recursiveBSON( depth - 1) );
return b.obj();
}
void run() {
BSONObj nestedBSON;
StringBuilder s;
string nestedBSONString;
size_t found;
// recursion depth one less than max allowed-- do not shorten the string
nestedBSON = recursiveBSON( BSONObj::maxToStringRecursionDepth - 1 );
nestedBSON.toString( s, true, false );
nestedBSONString = s.str();
found = nestedBSONString.find( "..." );
// did not find the "..." pattern
ASSERT_EQUALS( found!=string::npos, false );
// recursion depth is equal to max allowed -- do not shorten the string
nestedBSON = recursiveBSON( BSONObj::maxToStringRecursionDepth );
nestedBSON.toString( s, true, false );
nestedBSONString = s.str();
found = nestedBSONString.find( "..." );
// did not find the "..." pattern
ASSERT_EQUALS( found!=string::npos, false );
// recursion depth - one greater than max allowed -- shorten the string
nestedBSON = recursiveBSON( BSONObj::maxToStringRecursionDepth + 1 );
nestedBSON.toString( s, false, false );
nestedBSONString = s.str();
found = nestedBSONString.find( "..." );
// found the "..." pattern
ASSERT_EQUALS( found!=string::npos, true );
/* recursion depth - one greater than max allowed but with full=true
* should fail with an assertion
*/
nestedBSON = recursiveBSON( BSONObj::maxToStringRecursionDepth + 1 );
ASSERT_THROWS( nestedBSON.toString( s, false, true ) , UserException );
}
};
class StringWithNull {
public:
void run() {
const string input = string("a") + '\0' + 'b';
ASSERT_EQUALS(input.size(), 3U);
BSONObj obj = BSON("str" << input);
const string output = obj.firstElement().String();
ASSERT_EQUALS(escape(output), escape(input)); // for better failure output
ASSERT_EQUALS(output, input);
}
};
namespace Validation {
class Base {
public:
virtual ~Base() {}
void run() {
ASSERT( valid().valid() );
ASSERT( !invalid().valid() );
}
protected:
virtual BSONObj valid() const { return BSONObj(); }
virtual BSONObj invalid() const { return BSONObj(); }
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 Undefined : public Base {
public:
void run() {
BSONObjBuilder b;
b.appendNull( "a" );
BSONObj o = b.done();
set( o, 4, mongo::Undefined );
ASSERT( o.valid() );
}
};
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, (char) 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();
ASSERT_EQUALS( ret.firstElement().valuestr()[0] , 'b' );
ASSERT_EQUALS( ret.firstElement().valuestr()[1] , 0 );
((char*)ret.firstElement().valuestr())[1] = 1;
return ret.copy();
}
};
class ZeroStringSize : public Base {
BSONObj valid() const {
return fromjson( "{\"a\":\"b\"}" );
}
BSONObj invalid() const {
BSONObj ret = valid();
set( ret, 7, 0 );
return ret;
}
};
class NegativeStringSize : public Base {
BSONObj valid() const {
return fromjson( "{\"a\":\"b\"}" );
}
BSONObj invalid() const {
BSONObj ret = valid();
set( ret, 10, -100 );
return ret;
}
};
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 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 CodeWScopeBase : public Base {
BSONObj valid() const {
BSONObjBuilder b;
BSONObjBuilder scope;
scope.append( "a", "b" );
b.appendCodeWScope( "c", "d", scope.done() );
return b.obj();
}
BSONObj invalid() const {
BSONObj ret = valid();
modify( ret );
return ret;
}
protected:
virtual void modify( BSONObj &o ) const = 0;
};
class CodeWScopeSmallSize : public CodeWScopeBase {
void modify( BSONObj &o ) const {
set( o, 7, 7 );
}
};
class CodeWScopeZeroStrSize : public CodeWScopeBase {
void modify( BSONObj &o ) const {
set( o, 11, 0 );
}
};
class CodeWScopeSmallStrSize : public CodeWScopeBase {
void modify( BSONObj &o ) const {
set( o, 11, 1 );
}
};
class CodeWScopeNoSizeForObj : public CodeWScopeBase {
void modify( BSONObj &o ) const {
set( o, 7, 13 );
}
};
class CodeWScopeSmallObjSize : public CodeWScopeBase {
void modify( BSONObj &o ) const {
set( o, 17, 1 );
}
};
class CodeWScopeBadObject : public CodeWScopeBase {
void modify( BSONObj &o ) const {
set( o, 21, JSTypeMax + 1 );
}
};
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_;
};
} // namespace Validation
} // namespace BSONObjTests
namespace OIDTests {
class init1 {
public:
void run() {
OID a;
OID b;
a.init();
b.init();
ASSERT( a != b );
}
};
class initParse1 {
public:
void run() {
OID a;
OID b;
a.init();
b.init( a.toString() );
ASSERT( a == b );
}
};
class append {
public:
void run() {
BSONObjBuilder b;
b.appendOID( "a" , 0 );
b.appendOID( "b" , 0 , false );
b.appendOID( "c" , 0 , true );
BSONObj o = b.obj();
keyTest(o);
ASSERT( o["a"].__oid().toString() == "000000000000000000000000" );
ASSERT( o["b"].__oid().toString() == "000000000000000000000000" );
ASSERT( o["c"].__oid().toString() != "000000000000000000000000" );
}
};
class increasing {
public:
BSONObj g() {
BSONObjBuilder b;
b.appendOID( "_id" , 0 , true );
return b.obj();
}
void run() {
BSONObj a = g();
BSONObj b = g();
ASSERT( a.woCompare( b ) < 0 );
// yes, there is a 1/1000 chance this won't increase time(0)
// and therefore inaccurately say the function is behaving
// buf if its broken, it will fail 999/1000, so i think that's good enough
sleepsecs( 1 );
BSONObj c = g();
ASSERT( a.woCompare( c ) < 0 );
}
};
class ToDate {
public:
void run() {
OID oid;
const Date_t base( ::time( 0 ) );
oid.init( base );
ASSERT_EQUALS( base.millis / 1000, oid.asDateT().millis / 1000 );
ASSERT_EQUALS( base.toTimeT(), oid.asTimeT() );
}
};
class FromDate {
public:
void run() {
OID min, oid, max;
Date_t now = jsTime();
oid.init(); // slight chance this has different time. If its a problem, can change.
min.init(now);
max.init(now, true);
ASSERT_EQUALS( (unsigned)oid.asTimeT() , now/1000 );
ASSERT_EQUALS( (unsigned)min.asTimeT() , now/1000 );
ASSERT_EQUALS( (unsigned)max.asTimeT() , now/1000 );
ASSERT( BSON("" << min).woCompare( BSON("" << oid) ) < 0 );
ASSERT( BSON("" << max).woCompare( BSON("" << oid) )> 0 );
}
};
} // namespace OIDTests
namespace ValueStreamTests {
class LabelBase {
public:
virtual ~LabelBase() {}
void run() {
ASSERT( !expected().woCompare( actual() ) );
}
protected:
virtual BSONObj expected() = 0;
virtual BSONObj actual() = 0;
};
class LabelBasic : public LabelBase {
BSONObj expected() {
return BSON( "a" << ( BSON( "$gt" << 1 ) ) );
}
BSONObj actual() {
return BSON( "a" << GT << 1 );
}
};
class LabelShares : public LabelBase {
BSONObj expected() {
return BSON( "z" << "q" << "a" << ( BSON( "$gt" << 1 ) ) << "x" << "p" );
}
BSONObj actual() {
return BSON( "z" << "q" << "a" << GT << 1 << "x" << "p" );
}
};
class LabelDouble : public LabelBase {
BSONObj expected() {
return BSON( "a" << ( BSON( "$gt" << 1 << "$lte" << "x" ) ) );
}
BSONObj actual() {
return BSON( "a" << GT << 1 << LTE << "x" );
}
};
class LabelDoubleShares : public LabelBase {
BSONObj expected() {
return BSON( "z" << "q" << "a" << ( BSON( "$gt" << 1 << "$lte" << "x" ) ) << "x" << "p" );
}
BSONObj actual() {
return BSON( "z" << "q" << "a" << GT << 1 << LTE << "x" << "x" << "p" );
}
};
class LabelSize : public LabelBase {
BSONObj expected() {
return BSON( "a" << BSON( "$size" << 4 ) );
}
BSONObj actual() {
return BSON( "a" << mongo::BSIZE << 4 );
}
};
class LabelMulti : public LabelBase {
BSONObj expected() {
return BSON( "z" << "q"
<< "a" << BSON( "$gt" << 1 << "$lte" << "x" )
<< "b" << BSON( "$ne" << 1 << "$ne" << "f" << "$ne" << 22.3 )
<< "x" << "p" );
}
BSONObj actual() {
return BSON( "z" << "q"
<< "a" << GT << 1 << LTE << "x"
<< "b" << NE << 1 << NE << "f" << NE << 22.3
<< "x" << "p" );
}
};
class LabelishOr : public LabelBase {
BSONObj expected() {
return BSON( "$or" << BSON_ARRAY(
BSON("a" << BSON( "$gt" << 1 << "$lte" << "x" ))
<< BSON("b" << BSON( "$ne" << 1 << "$ne" << "f" << "$ne" << 22.3 ))
<< BSON("x" << "p" )));
}
BSONObj actual() {
return OR( BSON( "a" << GT << 1 << LTE << "x"),
BSON( "b" << NE << 1 << NE << "f" << NE << 22.3),
BSON( "x" << "p" ) );
}
};
class Unallowed {
public:
void run() {
ASSERT_THROWS( BSON( GT << 4 ), MsgAssertionException );
ASSERT_THROWS( BSON( "a" << 1 << GT << 4 ), MsgAssertionException );
}
};
class ElementAppend {
public:
void run() {
BSONObj a = BSON( "a" << 17 );
BSONObj b = BSON( "b" << a["a"] );
ASSERT_EQUALS( NumberInt , a["a"].type() );
ASSERT_EQUALS( NumberInt , b["b"].type() );
ASSERT_EQUALS( 17 , b["b"].number() );
}
};
class AllTypes {
public:
void run() {
// These are listed in order of BSONType
ASSERT_EQUALS(objTypeOf(MINKEY), MinKey);
ASSERT_EQUALS(arrTypeOf(MINKEY), MinKey);
// EOO not valid in middle of BSONObj
ASSERT_EQUALS(objTypeOf(1.0), NumberDouble);
ASSERT_EQUALS(arrTypeOf(1.0), NumberDouble);
ASSERT_EQUALS(objTypeOf(""), String);
ASSERT_EQUALS(arrTypeOf(""), String);
ASSERT_EQUALS(objTypeOf(string()), String);
ASSERT_EQUALS(arrTypeOf(string()), String);
ASSERT_EQUALS(objTypeOf(StringData("")), String);
ASSERT_EQUALS(arrTypeOf(StringData("")), String);
ASSERT_EQUALS(objTypeOf(BSONObj()), Object);
ASSERT_EQUALS(arrTypeOf(BSONObj()), Object);
ASSERT_EQUALS(objTypeOf(BSONArray()), Array);
ASSERT_EQUALS(arrTypeOf(BSONArray()), Array);
ASSERT_EQUALS(objTypeOf(BSONBinData("", 0, BinDataGeneral)), BinData);
ASSERT_EQUALS(arrTypeOf(BSONBinData("", 0, BinDataGeneral)), BinData);
ASSERT_EQUALS(objTypeOf(BSONUndefined), Undefined);
ASSERT_EQUALS(arrTypeOf(BSONUndefined), Undefined);
ASSERT_EQUALS(objTypeOf(OID()), jstOID);
ASSERT_EQUALS(arrTypeOf(OID()), jstOID);
ASSERT_EQUALS(objTypeOf(true), Bool);
ASSERT_EQUALS(arrTypeOf(true), Bool);
ASSERT_EQUALS(objTypeOf(Date_t()), Date);
ASSERT_EQUALS(arrTypeOf(Date_t()), Date);
ASSERT_EQUALS(objTypeOf(BSONNULL), jstNULL);
ASSERT_EQUALS(arrTypeOf(BSONNULL), jstNULL);
ASSERT_EQUALS(objTypeOf(BSONRegEx("", "")), RegEx);
ASSERT_EQUALS(arrTypeOf(BSONRegEx("", "")), RegEx);
ASSERT_EQUALS(objTypeOf(BSONDBRef("", OID())), DBRef);
ASSERT_EQUALS(arrTypeOf(BSONDBRef("", OID())), DBRef);
ASSERT_EQUALS(objTypeOf(BSONCode("")), Code);
ASSERT_EQUALS(arrTypeOf(BSONCode("")), Code);
ASSERT_EQUALS(objTypeOf(BSONSymbol("")), Symbol);
ASSERT_EQUALS(arrTypeOf(BSONSymbol("")), Symbol);
ASSERT_EQUALS(objTypeOf(BSONCodeWScope("", BSONObj())), CodeWScope);
ASSERT_EQUALS(arrTypeOf(BSONCodeWScope("", BSONObj())), CodeWScope);
ASSERT_EQUALS(objTypeOf(1), NumberInt);
ASSERT_EQUALS(arrTypeOf(1), NumberInt);
ASSERT_EQUALS(objTypeOf(OpTime()), Timestamp);
ASSERT_EQUALS(arrTypeOf(OpTime()), Timestamp);
ASSERT_EQUALS(objTypeOf(1LL), NumberLong);
ASSERT_EQUALS(arrTypeOf(1LL), NumberLong);
ASSERT_EQUALS(objTypeOf(MAXKEY), MaxKey);
ASSERT_EQUALS(arrTypeOf(MAXKEY), MaxKey);
}
template
BSONType objTypeOf(const T& thing) {
return BSON("" << thing).firstElement().type();
}
template
BSONType arrTypeOf(const T& thing) {
return BSON_ARRAY(thing).firstElement().type();
}
};
} // namespace ValueStreamTests
class SubObjectBuilder {
public:
void run() {
BSONObjBuilder b1;
b1.append( "a", "bcd" );
BSONObjBuilder b2( b1.subobjStart( "foo" ) );
b2.append( "ggg", 44.0 );
b2.done();
b1.append( "f", 10.0 );
BSONObj ret = b1.done();
ASSERT( ret.valid() );
ASSERT( ret.woCompare( fromjson( "{a:'bcd',foo:{ggg:44},f:10}" ) ) == 0 );
}
};
class DateBuilder {
public:
void run() {
BSONObj o = BSON("" << Date_t(1234567890));
ASSERT( o.firstElement().type() == Date );
ASSERT( o.firstElement().date() == Date_t(1234567890) );
}
};
class DateNowBuilder {
public:
void run() {
Date_t before = jsTime();
BSONObj o = BSON("now" << DATENOW);
Date_t after = jsTime();
ASSERT( o.valid() );
BSONElement e = o["now"];
ASSERT( e.type() == Date );
ASSERT( e.date() >= before );
ASSERT( e.date() <= after );
}
};
class TimeTBuilder {
public:
void run() {
Date_t before = jsTime();
sleepmillis(2);
time_t now = jsTime().toTimeT();
sleepmillis(2);
Date_t after = jsTime();
BSONObjBuilder b;
b.appendTimeT("now", now);
BSONObj o = b.obj();
ASSERT( o.valid() );
BSONElement e = o["now"];
ASSERT( e.type() == Date );
ASSERT( e.date()/1000 >= before/1000 );
ASSERT( e.date()/1000 <= after/1000 );
}
};
class MinMaxKeyBuilder {
public:
void run() {
BSONObj min = BSON( "a" << MINKEY );
BSONObj max = BSON( "b" << MAXKEY );
ASSERT( min.valid() );
ASSERT( max.valid() );
BSONElement minElement = min["a"];
BSONElement maxElement = max["b"];
ASSERT( minElement.type() == MinKey );
ASSERT( maxElement.type() == MaxKey );
}
};
class MinMaxElementTest {
public:
BSONObj min( int t ) {
BSONObjBuilder b;
b.appendMinForType( "a" , t );
return b.obj();
}
BSONObj max( int t ) {
BSONObjBuilder b;
b.appendMaxForType( "a" , t );
return b.obj();
}
void run() {
for ( int t=1; t= 0 );
ASSERT( min( t ).woCompare( min( t ) ) == 0 );
ASSERT( max( t ).woCompare( max( t ) ) == 0 );
}
}
};
class ExtractFieldsTest {
public:
void run() {
BSONObj x = BSON( "a" << 10 << "b" << 11 );
verify( BSON( "a" << 10 ).woCompare( x.extractFields( BSON( "a" << 1 ) ) ) == 0 );
verify( BSON( "b" << 11 ).woCompare( x.extractFields( BSON( "b" << 1 ) ) ) == 0 );
verify( x.woCompare( x.extractFields( BSON( "a" << 1 << "b" << 1 ) ) ) == 0 );
verify( (string)"a" == x.extractFields( BSON( "a" << 1 << "c" << 1 ) ).firstElementFieldName() );
}
};
class ComparatorTest {
public:
BSONObj one( string s ) {
return BSON( "x" << s );
}
BSONObj two( string x , string y ) {
BSONObjBuilder b;
b.append( "x" , x );
if ( y.size() )
b.append( "y" , y );
else
b.appendNull( "y" );
return b.obj();
}
void test( BSONObj order , BSONObj l , BSONObj r , bool wanted ) {
BSONObjCmp c( order );
bool got = c(l,r);
if ( got == wanted )
return;
cout << " order: " << order << " l: " << l << "r: " << r << " wanted: " << wanted << " got: " << got << endl;
}
void lt( BSONObj order , BSONObj l , BSONObj r ) {
test( order , l , r , 1 );
}
void run() {
BSONObj s = BSON( "x" << 1 );
BSONObj c = BSON( "x" << 1 << "y" << 1 );
test( s , one( "A" ) , one( "B" ) , 1 );
test( s , one( "B" ) , one( "A" ) , 0 );
test( c , two( "A" , "A" ) , two( "A" , "B" ) , 1 );
test( c , two( "A" , "A" ) , two( "B" , "A" ) , 1 );
test( c , two( "B" , "A" ) , two( "A" , "B" ) , 0 );
lt( c , one("A") , two( "A" , "A" ) );
lt( c , one("A") , one( "B" ) );
lt( c , two("A","") , two( "B" , "A" ) );
lt( c , two("B","A") , two( "C" , "A" ) );
lt( c , two("B","A") , one( "C" ) );
lt( c , two("B","A") , two( "C" , "" ) );
}
};
class CompatBSON {
public:
#define JSONBSONTEST(j,s) ASSERT_EQUALS( fromjson( j ).objsize() , s );
#define RAWBSONTEST(j,s) ASSERT_EQUALS( j.objsize() , s );
void run() {
JSONBSONTEST( "{ 'x' : true }" , 9 );
JSONBSONTEST( "{ 'x' : null }" , 8 );
JSONBSONTEST( "{ 'x' : 5.2 }" , 16 );
JSONBSONTEST( "{ 'x' : 'eliot' }" , 18 );
JSONBSONTEST( "{ 'x' : 5.2 , 'y' : 'truth' , 'z' : 1.1 }" , 40 );
JSONBSONTEST( "{ 'a' : { 'b' : 1.1 } }" , 24 );
JSONBSONTEST( "{ 'x' : 5.2 , 'y' : { 'a' : 'eliot' , b : true } , 'z' : null }" , 44 );
JSONBSONTEST( "{ 'x' : 5.2 , 'y' : [ 'a' , 'eliot' , 'b' , true ] , 'z' : null }" , 62 );
RAWBSONTEST( BSON( "x" << 4 ) , 12 );
}
};
class CompareDottedFieldNamesTest {
public:
void t( FieldCompareResult res , const string& l , const string& r ) {
LexNumCmp cmp( true );
ASSERT_EQUALS( res , compareDottedFieldNames( l , r , cmp ) );
ASSERT_EQUALS( -1 * res , compareDottedFieldNames( r , l , cmp ) );
}
void run() {
t( SAME , "x" , "x" );
t( SAME , "x.a" , "x.a" );
t( SAME , "x.4" , "x.4" );
t( LEFT_BEFORE , "a" , "b" );
t( RIGHT_BEFORE , "b" , "a" );
t( LEFT_BEFORE , "x.04" , "x.4" );
t( LEFT_SUBFIELD , "a.x" , "a" );
t( LEFT_SUBFIELD , "a.4" , "a" );
}
};
class CompareDottedArrayFieldNamesTest {
public:
void t( FieldCompareResult res , const string& l , const string& r ) {
LexNumCmp cmp( false ); // Specify numeric comparison for array field names.
ASSERT_EQUALS( res , compareDottedFieldNames( l , r , cmp ) );
ASSERT_EQUALS( -1 * res , compareDottedFieldNames( r , l , cmp ) );
}
void run() {
t( SAME , "0" , "0" );
t( SAME , "1" , "1" );
t( SAME , "0.1" , "0.1" );
t( SAME , "0.a" , "0.a" );
t( LEFT_BEFORE , "0" , "1" );
t( LEFT_BEFORE , "2" , "10" );
t( RIGHT_BEFORE , "1" , "0" );
t( RIGHT_BEFORE , "10" , "2" );
t( LEFT_SUBFIELD , "5.4" , "5" );
t( LEFT_SUBFIELD , "5.x" , "5" );
}
};
struct NestedDottedConversions {
void t(const BSONObj& nest, const BSONObj& dot) {
ASSERT_EQUALS( nested2dotted(nest), dot);
ASSERT_EQUALS( nest, dotted2nested(dot));
}
void run() {
t( BSON("a" << BSON("b" << 1)), BSON("a.b" << 1) );
t( BSON("a" << BSON("b" << 1 << "c" << 1)), BSON("a.b" << 1 << "a.c" << 1) );
t( BSON("a" << BSON("b" << 1 << "c" << 1) << "d" << 1), BSON("a.b" << 1 << "a.c" << 1 << "d" << 1) );
t( BSON("a" << BSON("b" << 1 << "c" << 1 << "e" << BSON("f" << 1)) << "d" << 1), BSON("a.b" << 1 << "a.c" << 1 << "a.e.f" << 1 << "d" << 1) );
}
};
struct BSONArrayBuilderTest {
void run() {
int i = 0;
BSONObjBuilder objb;
BSONArrayBuilder arrb;
objb << objb.numStr(i++) << 100;
arrb << 100;
objb << objb.numStr(i++) << 1.0;
arrb << 1.0;
objb << objb.numStr(i++) << "Hello";
arrb << "Hello";
objb << objb.numStr(i++) << string("World");
arrb << string("World");
objb << objb.numStr(i++) << BSON( "a" << 1 << "b" << "foo" );
arrb << BSON( "a" << 1 << "b" << "foo" );
objb << objb.numStr(i++) << BSON( "a" << 1)["a"];
arrb << BSON( "a" << 1)["a"];
OID oid;
oid.init();
objb << objb.numStr(i++) << oid;
arrb << oid;
objb.appendUndefined(objb.numStr(i++));
arrb.appendUndefined();
objb.appendRegex(objb.numStr(i++), "test", "imx");
arrb.appendRegex("test", "imx");
objb.appendBinData(objb.numStr(i++), 4, BinDataGeneral, "wow");
arrb.appendBinData(4, BinDataGeneral, "wow");
objb.appendCode(objb.numStr(i++), "function(){ return 1; }");
arrb.appendCode("function(){ return 1; }");
objb.appendCodeWScope(objb.numStr(i++), "function(){ return a; }", BSON("a" << 1));
arrb.appendCodeWScope("function(){ return a; }", BSON("a" << 1));
time_t dt(0);
objb.appendTimeT(objb.numStr(i++), dt);
arrb.appendTimeT(dt);
Date_t date(0);
objb.appendDate(objb.numStr(i++), date);
arrb.appendDate(date);
objb.append(objb.numStr(i++), BSONRegEx("test2", "s"));
arrb.append(BSONRegEx("test2", "s"));
BSONObj obj = objb.obj();
BSONArray arr = arrb.arr();
ASSERT_EQUALS(obj, arr);
BSONObj o = BSON( "obj" << obj << "arr" << arr << "arr2" << BSONArray(obj)
<< "regex" << BSONRegEx("reg", "x"));
keyTest(o);
ASSERT_EQUALS(o["obj"].type(), Object);
ASSERT_EQUALS(o["arr"].type(), Array);
ASSERT_EQUALS(o["arr2"].type(), Array);
ASSERT_EQUALS(o["regex"].type(), RegEx);
}
};
struct ArrayMacroTest {
void run() {
BSONArray arr = BSON_ARRAY( "hello" << 1 << BSON( "foo" << BSON_ARRAY( "bar" << "baz" << "qux" ) ) );
BSONObj obj = BSON( "0" << "hello"
<< "1" << 1
<< "2" << BSON( "foo" << BSON_ARRAY( "bar" << "baz" << "qux" ) ) );
ASSERT_EQUALS(arr, obj);
ASSERT_EQUALS(arr["2"].type(), Object);
ASSERT_EQUALS(arr["2"].embeddedObject()["foo"].type(), Array);
}
};
class NumberParsing {
public:
void run() {
BSONObjBuilder a;
BSONObjBuilder b;
a.append( "a" , (int)1 );
ASSERT( b.appendAsNumber( "a" , "1" ) );
a.append( "b" , 1.1 );
ASSERT( b.appendAsNumber( "b" , "1.1" ) );
a.append( "c" , (int)-1 );
ASSERT( b.appendAsNumber( "c" , "-1" ) );
a.append( "d" , -1.1 );
ASSERT( b.appendAsNumber( "d" , "-1.1" ) );
a.append( "e" , (long long)32131231231232313LL );
ASSERT( b.appendAsNumber( "e" , "32131231231232313" ) );
ASSERT( ! b.appendAsNumber( "f" , "zz" ) );
ASSERT( ! b.appendAsNumber( "f" , "5zz" ) );
ASSERT( ! b.appendAsNumber( "f" , "zz5" ) );
ASSERT_EQUALS( a.obj() , b.obj() );
}
};
class bson2settest {
public:
void run() {
BSONObj o = BSON( "z" << 1 << "a" << 2 << "m" << 3 << "c" << 4 );
BSONObjIteratorSorted i( o );
stringstream ss;
while ( i.more() )
ss << i.next().fieldName();
ASSERT_EQUALS( "acmz" , ss.str() );
{
Timer t;
for ( int i=0; i<10000; i++ ) {
BSONObjIteratorSorted j( o );
int l = 0;
while ( j.more() )
l += strlen( j.next().fieldName() );
}
//unsigned long long tm = t.micros();
//cout << "time: " << tm << endl;
}
BSONObj o2 = BSON( "2" << "a" << "11" << "b" );
BSONObjIteratorSorted i2( o2 );
// First field in sorted order should be "11" due use of a lexical comparison.
ASSERT_EQUALS( "11", string( i2.next().fieldName() ) );
}
};
class BSONArrayIteratorSorted {
public:
void run() {
BSONArrayBuilder bab;
for( int i = 0; i < 11; ++i ) {
bab << "a";
}
BSONArray arr = bab.arr();
// The sorted iterator should perform numeric comparisons and return results in the same
// order as the unsorted iterator.
BSONObjIterator unsorted( arr );
mongo::BSONArrayIteratorSorted sorted( arr );
while( unsorted.more() ) {
ASSERT( sorted.more() );
ASSERT_EQUALS( string( unsorted.next().fieldName() ), sorted.next().fieldName() );
}
ASSERT( !sorted.more() );
}
};
class checkForStorageTests {
public:
void good( string s ) {
good( fromjson( s ) );
}
void good( BSONObj o ) {
if ( o.okForStorageAsRoot() )
return;
throw UserException( 12528 , (string)"should be ok for storage:" + o.toString() );
}
void bad( string s ) {
bad( fromjson( s ) );
}
void bad( BSONObj o ) {
if ( ! o.okForStorageAsRoot() )
return;
throw UserException( 12529 , (string)"should NOT be ok for storage:" + o.toString() );
}
void run() {
// basic docs are good
good( "{}" );
good( "{x:1}" );
good( "{x:{a:2}}" );
// no dots allowed
bad( "{'x.y':1}" );
bad( "{'x\\.y':1}" );
// Check for $
bad( "{x:{'$a':2}}" );
good( "{'a$b':2}" );
good( "{'a$': {b: 2}}" );
good( "{'a$':2}" );
good( "{'a $ a': 'foo'}" );
// Queries are not ok
bad( "{num: {$gt: 1}}" );
bad( "{_id: {$regex:'test'}}" );
bad( "{$gt: 2}" );
bad( "{a : { oo: [ {$bad:1}, {good:1}] }}");
good( "{a : { oo: [ {'\\\\$good':1}, {good:1}] }}");
// DBRef stuff -- json parser can't handle this yet
good( BSON("a" << BSON("$ref" << "coll" << "$id" << 1)) );
good( BSON("a" << BSON("$ref" << "coll" << "$id" << 1 << "$db" << "a")) );
good( BSON("a" << BSON("$ref" << "coll" << "$id" << 1 << "stuff" << 1)) );
good( BSON("a" << BSON("$ref" << "coll" << "$id" << 1 << "$db" <<
"a" << "stuff" << 1)) );
bad( BSON("a" << BSON("$ref" << 1 << "$id" << 1)) );
bad( BSON("a" << BSON("$ref" << 1 << "$id" << 1 << "$db" << "a")) );
bad( BSON("a" << BSON("$ref" << "coll" << "$id" << 1 << "$db" << 1)) );
bad( BSON("a" << BSON("$ref" << "coll")) );
bad( BSON("a" << BSON("$ref" << "coll" << "$db" << "db")) );
bad( BSON("a" << BSON("$id" << 1)) );
bad( BSON("a" << BSON("$id" << 1 << "$ref" << "coll")) );
bad( BSON("a" << BSON("$ref" << "coll" << "$id" << 1 << "$hater" << 1)) );
bad( BSON("a" << BSON("$ref" << "coll" << "$id" << 1 << "dot.dot" << 1)) );
// _id isn't a RegEx, or Array
good( "{_id: 0}" );
good( "{_id: {a:1, b:1}}" );
good( "{_id: {rx: /a/}}" );
good( "{_id: {rx: {$regex: 'a'}}}" );
bad( "{_id: /a/ }" );
bad( "{_id: /a/, other:1}" );
bad( "{hi:1, _id: /a/ }" );
bad( "{_id: /a/i }" );
bad( "{first:/f/i, _id: /a/i }" );
//Not really a regex type
bad( "{_id: {$regex: 'a'} }" );
bad( "{_id: {$regex: 'a', $options:'i'} }" );
bad( "{_id: [1,2]}" );
bad( "{_id: [1]}" );
}
};
class InvalidIDFind {
public:
void run() {
BSONObj x = BSON( "_id" << 5 << "t" << 2 );
{
char * crap = (char*)mongoMalloc( x.objsize() );
memcpy( crap , x.objdata() , x.objsize() );
BSONObj y( crap );
ASSERT_EQUALS( x , y );
free( crap );
}
{
char * crap = (char*)mongoMalloc( x.objsize() );
memcpy( crap , x.objdata() , x.objsize() );
int * foo = (int*)crap;
foo[0] = 123123123;
int state = 0;
try {
BSONObj y( crap );
state = 1;
}
catch ( std::exception& e ) {
state = 2;
ASSERT( strstr( e.what() , "_id: 5" ) != NULL );
}
free( crap );
ASSERT_EQUALS( 2 , state );
}
}
};
class ElementSetTest {
public:
void run() {
BSONObj x = BSON( "a" << 1 << "b" << 1 << "c" << 2 );
BSONElement a = x["a"];
BSONElement b = x["b"];
BSONElement c = x["c"];
//cout << "c: " << c << endl;
ASSERT( a.woCompare( b ) != 0 );
ASSERT( a.woCompare( b , false ) == 0 );
BSONElementSet s;
s.insert( a );
ASSERT_EQUALS( 1U , s.size() );
s.insert( b );
ASSERT_EQUALS( 1U , s.size() );
ASSERT( ! s.count( c ) );
ASSERT( s.find( a ) != s.end() );
ASSERT( s.find( b ) != s.end() );
ASSERT( s.find( c ) == s.end() );
s.insert( c );
ASSERT_EQUALS( 2U , s.size() );
ASSERT( s.find( a ) != s.end() );
ASSERT( s.find( b ) != s.end() );
ASSERT( s.find( c ) != s.end() );
ASSERT( s.count( a ) );
ASSERT( s.count( b ) );
ASSERT( s.count( c ) );
{
BSONElementSet x;
BSONObj o = fromjson( "{ 'a' : [ 1 , 2 , 1 ] }" );
BSONObjIterator i( o["a"].embeddedObjectUserCheck() );
while ( i.more() ) {
x.insert( i.next() );
}
ASSERT_EQUALS( 2U , x.size() );
}
}
};
class EmbeddedNumbers {
public:
void run() {
BSONObj x = BSON( "a" << BSON( "b" << 1 ) );
BSONObj y = BSON( "a" << BSON( "b" << 1.0 ) );
keyTest(x); keyTest(y);
ASSERT_EQUALS( x , y );
ASSERT_EQUALS( 0 , x.woCompare( y ) );
}
};
class BuilderPartialItearte {
public:
void run() {
{
BSONObjBuilder b;
b.append( "x" , 1 );
b.append( "y" , 2 );
BSONObjIterator i = b.iterator();
ASSERT( i.more() );
ASSERT_EQUALS( 1 , i.next().numberInt() );
ASSERT( i.more() );
ASSERT_EQUALS( 2 , i.next().numberInt() );
ASSERT( ! i.more() );
b.append( "z" , 3 );
i = b.iterator();
ASSERT( i.more() );
ASSERT_EQUALS( 1 , i.next().numberInt() );
ASSERT( i.more() );
ASSERT_EQUALS( 2 , i.next().numberInt() );
ASSERT( i.more() );
ASSERT_EQUALS( 3 , i.next().numberInt() );
ASSERT( ! i.more() );
ASSERT_EQUALS( BSON( "x" << 1 << "y" << 2 << "z" << 3 ) , b.obj() );
}
}
};
class BSONForEachTest {
public:
void run() {
BSONObj obj = BSON("a" << 1 << "a" << 2 << "a" << 3);
int count = 0;
BSONForEach(e, obj) {
ASSERT_EQUALS( e.fieldName() , string("a") );
count += e.Int();
}
ASSERT_EQUALS( count , 1+2+3 );
}
};
class CompareOps {
public:
void run() {
BSONObj a = BSON("a"<<1);
BSONObj b = BSON("a"<<1);
BSONObj c = BSON("a"<<2);
BSONObj d = BSON("a"<<3);
BSONObj e = BSON("a"<<4);
BSONObj f = BSON("a"<<4);
ASSERT( ! ( a < b ) );
ASSERT( a <= b );
ASSERT( a < c );
ASSERT( f > d );
ASSERT( f >= e );
ASSERT( ! ( f > e ) );
}
};
class NestedBuilderOversize {
public:
void run() {
try {
BSONObjBuilder outer;
BSONObjBuilder inner(outer.subobjStart("inner"));
string bigStr(1000, 'x');
while (true) {
ASSERT_LESS_THAN_OR_EQUALS(inner.len(), BufferMaxSize);
inner.append("", bigStr);
}
ASSERT(!"Expected Throw");
} catch (const DBException& e) {
if (e.getCode() != 13548) // we expect the code for oversized buffer
throw;
}
}
};
class All : public Suite {
public:
All() : Suite( "jsobj" ) {
}
void setupTests() {
add< BufBuilderBasic >();
add< BufBuilderReallocLimit >();
add< BSONElementBasic >();
add< BSONObjTests::NullString >();
add< BSONObjTests::Create >();
add< BSONObjTests::WoCompareBasic >();
add< BSONObjTests::NumericCompareBasic >();
add< BSONObjTests::WoCompareEmbeddedObject >();
add< BSONObjTests::WoCompareEmbeddedArray >();
add< BSONObjTests::WoCompareOrdered >();
add< BSONObjTests::WoCompareDifferentLength >();
add< BSONObjTests::WoSortOrder >();
add< BSONObjTests::IsPrefixOf >();
add< BSONObjTests::MultiKeySortOrder > ();
add< BSONObjTests::Nan >();
add< BSONObjTests::AsTempObj >();
add< BSONObjTests::AppendIntOrLL >();
add< BSONObjTests::AppendNumber >();
add< BSONObjTests::ToStringArray >();
add< BSONObjTests::ToStringNumber >();
add< BSONObjTests::AppendAs >();
add< BSONObjTests::GetField >();
add< BSONObjTests::ToStringRecursionDepth >();
add< BSONObjTests::StringWithNull >();
add< BSONObjTests::Validation::BadType >();
add< BSONObjTests::Validation::EooBeforeEnd >();
add< BSONObjTests::Validation::Undefined >();
add< BSONObjTests::Validation::TotalSizeTooSmall >();
add< BSONObjTests::Validation::EooMissing >();
add< BSONObjTests::Validation::WrongStringSize >();
add< BSONObjTests::Validation::ZeroStringSize >();
add< BSONObjTests::Validation::NegativeStringSize >();
add< BSONObjTests::Validation::WrongSubobjectSize >();
add< BSONObjTests::Validation::WrongDbrefNsSize >();
add< BSONObjTests::Validation::NoFieldNameEnd >();
add< BSONObjTests::Validation::BadRegex >();
add< BSONObjTests::Validation::BadRegexOptions >();
add< BSONObjTests::Validation::CodeWScopeSmallSize >();
add< BSONObjTests::Validation::CodeWScopeZeroStrSize >();
add< BSONObjTests::Validation::CodeWScopeSmallStrSize >();
add< BSONObjTests::Validation::CodeWScopeNoSizeForObj >();
add< BSONObjTests::Validation::CodeWScopeSmallObjSize >();
add< BSONObjTests::Validation::CodeWScopeBadObject >();
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< OIDTests::init1 >();
add< OIDTests::initParse1 >();
add< OIDTests::append >();
add< OIDTests::increasing >();
add< OIDTests::ToDate >();
add< OIDTests::FromDate >();
add< ValueStreamTests::LabelBasic >();
add< ValueStreamTests::LabelShares >();
add< ValueStreamTests::LabelDouble >();
add< ValueStreamTests::LabelDoubleShares >();
add< ValueStreamTests::LabelSize >();
add< ValueStreamTests::LabelMulti >();
add< ValueStreamTests::LabelishOr >();
add< ValueStreamTests::Unallowed >();
add< ValueStreamTests::ElementAppend >();
add< ValueStreamTests::AllTypes >();
add< SubObjectBuilder >();
add< DateBuilder >();
add< DateNowBuilder >();
add< TimeTBuilder >();
add< MinMaxKeyBuilder >();
add< MinMaxElementTest >();
add< ComparatorTest >();
add< ExtractFieldsTest >();
add< CompatBSON >();
add< CompareDottedFieldNamesTest >();
add< CompareDottedArrayFieldNamesTest >();
add< NestedDottedConversions >();
add< BSONArrayBuilderTest >();
add< ArrayMacroTest >();
add< NumberParsing >();
add< bson2settest >();
add< BSONArrayIteratorSorted >();
add< checkForStorageTests >();
add< InvalidIDFind >();
add< ElementSetTest >();
add< EmbeddedNumbers >();
add< BuilderPartialItearte >();
add< BSONForEachTest >();
add< CompareOps >();
add< NestedBuilderOversize >();
}
};
SuiteInstance myall;
} // namespace JsobjTests