0
0
mirror of https://github.com/mongodb/mongo.git synced 2024-11-30 17:10:48 +01:00
mongodb/dbtests/updatetests.cpp

786 lines
27 KiB
C++
Raw Normal View History

// updatetests.cpp : unit tests relating to update requests
//
/**
* 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/>.
*/
2009-09-30 20:32:17 +02:00
#include "stdafx.h"
#include "../db/query.h"
#include "../db/db.h"
#include "../db/instance.h"
#include "../db/json.h"
#include "../db/lasterror.h"
#include "../db/update.h"
#include "dbtests.h"
namespace UpdateTests {
class ClientBase {
public:
// NOTE: Not bothering to backup the old error record.
ClientBase() {
mongo::lastError.reset( new LastError() );
}
~ClientBase() {
mongo::lastError.release();
}
protected:
static void insert( const char *ns, BSONObj o ) {
client_.insert( ns, o );
}
static void update( const char *ns, BSONObj q, BSONObj o, bool upsert = 0 ) {
client_.update( ns, Query( q ), o, upsert );
}
static bool error() {
return !client_.getPrevError().getField( "err" ).isNull();
}
DBDirectClient &client() const { return client_; }
private:
static DBDirectClient client_;
};
DBDirectClient ClientBase::client_;
2009-04-03 16:48:26 +02:00
class Fail : public ClientBase {
public:
virtual ~Fail() {}
void run() {
prep();
ASSERT( !error() );
doIt();
ASSERT( error() );
}
protected:
const char *ns() { return "unittests.UpdateTests_Fail"; }
virtual void prep() {
2009-04-03 16:48:26 +02:00
insert( ns(), fromjson( "{a:1}" ) );
}
virtual void doIt() = 0;
};
2009-04-03 16:48:26 +02:00
class ModId : public Fail {
void doIt() {
update( ns(), BSONObj(), fromjson( "{$set:{'_id':4}}" ) );
}
};
2009-04-03 16:48:26 +02:00
class ModNonmodMix : public Fail {
void doIt() {
update( ns(), BSONObj(), fromjson( "{$set:{a:4},z:3}" ) );
2009-04-03 16:48:26 +02:00
}
};
2009-04-03 16:48:26 +02:00
class InvalidMod : public Fail {
void doIt() {
update( ns(), BSONObj(), fromjson( "{$awk:{a:4}}" ) );
2009-04-03 16:48:26 +02:00
}
};
2009-04-03 16:48:26 +02:00
class ModNotFirst : public Fail {
void doIt() {
update( ns(), BSONObj(), fromjson( "{z:3,$set:{a:4}}" ) );
2009-04-03 16:48:26 +02:00
}
};
2009-04-03 16:48:26 +02:00
class ModDuplicateFieldSpec : public Fail {
void doIt() {
update( ns(), BSONObj(), fromjson( "{$set:{a:4},$inc:{a:1}}" ) );
2009-04-03 16:48:26 +02:00
}
};
2009-04-03 16:48:26 +02:00
class IncNonNumber : public Fail {
void doIt() {
update( ns(), BSONObj(), fromjson( "{$inc:{a:'d'}}" ) );
2009-04-03 16:48:26 +02:00
}
};
2009-04-03 16:48:26 +02:00
class PushAllNonArray : public Fail {
void doIt() {
insert( ns(), fromjson( "{a:[1]}" ) );
update( ns(), BSONObj(), fromjson( "{$pushAll:{a:'d'}}" ) );
}
};
class PullAllNonArray : public Fail {
void doIt() {
insert( ns(), fromjson( "{a:[1]}" ) );
update( ns(), BSONObj(), fromjson( "{$pullAll:{a:'d'}}" ) );
}
};
class IncTargetNonNumber : public Fail {
void doIt() {
insert( ns(), BSON( "a" << "a" ) );
update( ns(), BSON( "a" << "a" ), fromjson( "{$inc:{a:1}}" ) );
2009-04-03 16:48:26 +02:00
}
};
2009-04-03 16:48:26 +02:00
class SetBase : public ClientBase {
public:
~SetBase() {
client().dropCollection( ns() );
}
protected:
const char *ns() { return "unittests.updatetests.SetBase"; }
};
2009-04-03 16:48:26 +02:00
class SetNum : public SetBase {
public:
void run() {
client().insert( ns(), BSON( "a" << 1 ) );
client().update( ns(), BSON( "a" << 1 ), BSON( "$set" << BSON( "a" << 4 ) ) );
ASSERT( !client().findOne( ns(), BSON( "a" << 4 ) ).isEmpty() );
}
};
2009-04-03 16:48:26 +02:00
class SetString : public SetBase {
public:
void run() {
client().insert( ns(), BSON( "a" << "b" ) );
client().update( ns(), BSON( "a" << "b" ), BSON( "$set" << BSON( "a" << "c" ) ) );
ASSERT( !client().findOne( ns(), BSON( "a" << "c" ) ).isEmpty() );
}
};
2009-04-03 16:48:26 +02:00
class SetStringDifferentLength : public SetBase {
public:
void run() {
client().insert( ns(), BSON( "a" << "b" ) );
client().update( ns(), BSON( "a" << "b" ), BSON( "$set" << BSON( "a" << "cd" ) ) );
2009-04-03 16:48:26 +02:00
ASSERT( !client().findOne( ns(), BSON( "a" << "cd" ) ).isEmpty() );
}
};
2009-04-03 16:48:26 +02:00
class SetStringToNum : public SetBase {
public:
void run() {
client().insert( ns(), BSON( "a" << "b" ) );
2009-03-24 19:33:36 +01:00
client().update( ns(), Query(), BSON( "$set" << BSON( "a" << 5 ) ) );
ASSERT( !client().findOne( ns(), BSON( "a" << 5 ) ).isEmpty() );
2009-04-03 16:48:26 +02:00
}
};
2009-04-03 16:48:26 +02:00
class SetStringToNumInPlace : public SetBase {
public:
void run() {
client().insert( ns(), BSON( "a" << "bcd" ) );
2009-03-24 19:33:36 +01:00
client().update( ns(), Query(), BSON( "$set" << BSON( "a" << 5.0 ) ) );
2009-04-03 16:48:26 +02:00
ASSERT( !client().findOne( ns(), BSON( "a" << 5.0 ) ).isEmpty() );
}
};
2009-04-03 16:48:26 +02:00
class ModDotted : public SetBase {
public:
void run() {
client().insert( ns(), fromjson( "{a:{b:4}}" ) );
2009-03-24 19:33:36 +01:00
client().update( ns(), Query(), BSON( "$inc" << BSON( "a.b" << 10 ) ) );
2009-04-03 16:48:26 +02:00
ASSERT( !client().findOne( ns(), BSON( "a.b" << 14 ) ).isEmpty() );
2009-03-24 19:33:36 +01:00
client().update( ns(), Query(), BSON( "$set" << BSON( "a.b" << 55 ) ) );
2009-04-03 16:48:26 +02:00
ASSERT( !client().findOne( ns(), BSON( "a.b" << 55 ) ).isEmpty() );
}
};
2009-04-03 16:48:26 +02:00
class SetInPlaceDotted : public SetBase {
public:
void run() {
client().insert( ns(), fromjson( "{a:{b:'cdef'}}" ) );
2009-03-24 19:33:36 +01:00
client().update( ns(), Query(), BSON( "$set" << BSON( "a.b" << "llll" ) ) );
2009-04-03 16:48:26 +02:00
ASSERT( !client().findOne( ns(), BSON( "a.b" << "llll" ) ).isEmpty() );
}
};
2009-04-03 16:48:26 +02:00
class SetRecreateDotted : public SetBase {
public:
void run() {
2009-03-23 23:55:32 +01:00
client().insert( ns(), fromjson( "{'_id':0,a:{b:'cdef'}}" ) );
2009-03-24 19:33:36 +01:00
client().update( ns(), Query(), BSON( "$set" << BSON( "a.b" << "lllll" ) ) );
2009-04-03 16:48:26 +02:00
ASSERT( client().findOne( ns(), BSON( "a.b" << "lllll" ) ).woCompare( fromjson( "{'_id':0,a:{b:'lllll'}}" ) ) == 0 );
}
};
2009-03-23 23:55:32 +01:00
class SetMissingDotted : public SetBase {
public:
void run() {
client().insert( ns(), fromjson( "{'_id':0}" ) );
client().update( ns(), BSONObj(), BSON( "$set" << BSON( "a.b" << "lllll" ) ) );
2009-04-03 16:48:26 +02:00
ASSERT( client().findOne( ns(), BSON( "a.b" << "lllll" ) ).woCompare( fromjson( "{'_id':0,a:{b:'lllll'}}" ) ) == 0 );
2009-03-23 23:55:32 +01:00
}
2009-04-03 16:48:26 +02:00
};
2009-03-23 23:55:32 +01:00
class SetAdjacentDotted : public SetBase {
public:
void run() {
client().insert( ns(), fromjson( "{'_id':0,a:{c:4}}" ) );
2009-03-24 19:33:36 +01:00
client().update( ns(), Query(), BSON( "$set" << BSON( "a.b" << "lllll" ) ) );
2009-12-10 20:29:14 +01:00
ASSERT_EQUALS( client().findOne( ns(), BSON( "a.b" << "lllll" ) ) , fromjson( "{'_id':0,a:{b:'lllll',c:4}}" ) );
2009-03-23 23:55:32 +01:00
}
2009-04-03 16:48:26 +02:00
};
2009-03-23 23:55:32 +01:00
class IncMissing : public SetBase {
public:
void run() {
client().insert( ns(), fromjson( "{'_id':0}" ) );
2009-03-24 19:33:36 +01:00
client().update( ns(), Query(), BSON( "$inc" << BSON( "f" << 3.0 ) ) );
2009-04-03 16:48:26 +02:00
ASSERT( client().findOne( ns(), Query() ).woCompare( fromjson( "{'_id':0,f:3}" ) ) == 0 );
2009-03-23 23:55:32 +01:00
}
2009-04-03 16:48:26 +02:00
};
class MultiInc : public SetBase {
public:
string s(){
stringstream ss;
auto_ptr<DBClientCursor> cc = client().query( ns() , Query().sort( BSON( "_id" << 1 ) ) );
bool first = true;
while ( cc->more() ){
if ( first ) first = false;
else ss << ",";
BSONObj o = cc->next();
ss << o["x"].numberInt();
}
return ss.str();
}
void run(){
client().insert( ns(), BSON( "_id" << 1 << "x" << 1 ) );
client().insert( ns(), BSON( "_id" << 2 << "x" << 5 ) );
ASSERT_EQUALS( "1,5" , s() );
client().update( ns() , BSON( "_id" << 1 ) , BSON( "$inc" << BSON( "x" << 1 ) ) );
ASSERT_EQUALS( "2,5" , s() );
client().update( ns() , BSONObj() , BSON( "$inc" << BSON( "x" << 1 ) ) );
ASSERT_EQUALS( "3,5" , s() );
client().update( ns() , BSONObj() , BSON( "$inc" << BSON( "x" << 1 ) ) , false , true );
ASSERT_EQUALS( "4,6" , s() );
}
};
2009-03-24 16:34:09 +01:00
class UnorderedNewSet : public SetBase {
public:
void run() {
client().insert( ns(), fromjson( "{'_id':0}" ) );
2009-03-24 19:33:36 +01:00
client().update( ns(), Query(), BSON( "$set" << BSON( "f.g.h" << 3.0 << "f.g.a" << 2.0 ) ) );
2009-04-03 16:48:26 +02:00
ASSERT( client().findOne( ns(), Query() ).woCompare( fromjson( "{'_id':0,f:{g:{a:2,h:3}}}" ) ) == 0 );
}
2009-03-24 16:34:09 +01:00
};
class UnorderedNewSetAdjacent : public SetBase {
public:
void run() {
client().insert( ns(), fromjson( "{'_id':0}" ) );
client().update( ns(), BSONObj(), BSON( "$set" << BSON( "f.g.h.b" << 3.0 << "f.g.a.b" << 2.0 ) ) );
2009-04-03 16:48:26 +02:00
ASSERT( client().findOne( ns(), Query() ).woCompare( fromjson( "{'_id':0,f:{g:{a:{b:2},h:{b:3}}}}" ) ) == 0 );
}
2009-03-24 16:34:09 +01:00
};
class ArrayEmbeddedSet : public SetBase {
public:
void run() {
client().insert( ns(), fromjson( "{'_id':0,z:[4,'b']}" ) );
2009-03-24 19:33:36 +01:00
client().update( ns(), Query(), BSON( "$set" << BSON( "z.0" << "a" ) ) );
2009-12-18 23:39:02 +01:00
ASSERT_EQUALS( client().findOne( ns(), Query() ) , fromjson( "{'_id':0,z:['a','b']}" ) );
2009-04-03 16:48:26 +02:00
}
2009-03-24 16:34:09 +01:00
};
2009-04-03 16:48:26 +02:00
2009-03-24 16:34:09 +01:00
class AttemptEmbedInExistingNum : public SetBase {
public:
void run() {
client().insert( ns(), fromjson( "{'_id':0,a:1}" ) );
2009-03-24 19:33:36 +01:00
client().update( ns(), Query(), BSON( "$set" << BSON( "a.b" << 1 ) ) );
2009-04-03 16:48:26 +02:00
ASSERT( client().findOne( ns(), Query() ).woCompare( fromjson( "{'_id':0,a:1}" ) ) == 0 );
}
2009-03-24 16:34:09 +01:00
};
2009-04-03 16:48:26 +02:00
2009-03-24 20:16:44 +01:00
class AttemptEmbedConflictsWithOtherSet : public SetBase {
public:
void run() {
client().insert( ns(), fromjson( "{'_id':0}" ) );
client().update( ns(), Query(), BSON( "$set" << BSON( "a" << 2 << "a.b" << 1 ) ) );
2009-12-10 20:29:14 +01:00
ASSERT_EQUALS( client().findOne( ns(), Query() ) , fromjson( "{'_id':0}" ) );
2009-04-03 16:48:26 +02:00
}
2009-03-24 20:16:44 +01:00
};
class ModMasksEmbeddedConflict : public SetBase {
public:
void run() {
client().insert( ns(), fromjson( "{'_id':0,a:{b:2}}" ) );
client().update( ns(), Query(), BSON( "$set" << BSON( "a" << 2 << "a.b" << 1 ) ) );
2009-04-03 16:48:26 +02:00
ASSERT( client().findOne( ns(), Query() ).woCompare( fromjson( "{'_id':0,a:{b:2}}" ) ) == 0 );
}
2009-03-24 20:16:44 +01:00
};
2009-03-24 16:34:09 +01:00
2009-03-24 20:16:44 +01:00
class ModOverwritesExistingObject : public SetBase {
public:
void run() {
client().insert( ns(), fromjson( "{'_id':0,a:{b:2}}" ) );
client().update( ns(), Query(), BSON( "$set" << BSON( "a" << BSON( "c" << 2 ) ) ) );
2009-04-03 16:48:26 +02:00
ASSERT( client().findOne( ns(), Query() ).woCompare( fromjson( "{'_id':0,a:{c:2}}" ) ) == 0 );
}
};
2009-03-24 20:16:44 +01:00
class InvalidEmbeddedSet : public Fail {
public:
virtual void doIt() {
client().update( ns(), Query(), BSON( "$set" << BSON( "a." << 1 ) ) );
}
};
2009-04-03 16:48:26 +02:00
2009-03-24 20:42:35 +01:00
class UpsertMissingEmbedded : public SetBase {
public:
void run() {
client().update( ns(), Query(), BSON( "$set" << BSON( "a.b" << 1 ) ), true );
ASSERT( !client().findOne( ns(), QUERY( "a.b" << 1 ) ).isEmpty() );
}
};
2009-04-03 16:48:26 +02:00
2009-03-24 23:15:47 +01:00
class Push : public SetBase {
public:
void run() {
client().insert( ns(), fromjson( "{'_id':0,a:[1]}" ) );
client().update( ns(), Query(), BSON( "$push" << BSON( "a" << 5 ) ) );
ASSERT_EQUALS( client().findOne( ns(), Query() ) , fromjson( "{'_id':0,a:[1,5]}" ) );
2009-03-24 23:15:47 +01:00
}
};
2009-04-03 16:48:26 +02:00
2009-03-24 23:42:51 +01:00
class PushInvalidEltType : public SetBase {
public:
void run() {
client().insert( ns(), fromjson( "{'_id':0,a:1}" ) );
client().update( ns(), Query(), BSON( "$push" << BSON( "a" << 5 ) ) );
2009-04-03 16:48:26 +02:00
ASSERT( client().findOne( ns(), Query() ).woCompare( fromjson( "{'_id':0,a:1}" ) ) == 0 );
2009-03-24 23:42:51 +01:00
}
};
2009-04-03 16:48:26 +02:00
2009-03-24 23:42:51 +01:00
class PushConflictsWithOtherMod : public SetBase {
public:
void run() {
client().insert( ns(), fromjson( "{'_id':0,a:[1]}" ) );
client().update( ns(), Query(), BSON( "$set" << BSON( "a" << 1 ) <<"$push" << BSON( "a" << 5 ) ) );
2009-04-03 16:48:26 +02:00
ASSERT( client().findOne( ns(), Query() ).woCompare( fromjson( "{'_id':0,a:[1]}" ) ) == 0 );
2009-03-24 23:42:51 +01:00
}
};
2009-04-03 16:48:26 +02:00
2009-03-24 23:42:51 +01:00
class PushFromNothing : public SetBase {
public:
void run() {
client().insert( ns(), fromjson( "{'_id':0}" ) );
client().update( ns(), Query(), BSON( "$push" << BSON( "a" << 5 ) ) );
ASSERT_EQUALS( client().findOne( ns(), Query() ) , fromjson( "{'_id':0,a:[5]}" ) );
2009-04-03 16:48:26 +02:00
}
2009-03-24 23:42:51 +01:00
};
2009-04-03 16:48:26 +02:00
2009-03-25 15:34:32 +01:00
class PushFromEmpty : public SetBase {
public:
void run() {
client().insert( ns(), fromjson( "{'_id':0,a:[]}" ) );
client().update( ns(), Query(), BSON( "$push" << BSON( "a" << 5 ) ) );
2009-04-03 16:48:26 +02:00
ASSERT( client().findOne( ns(), Query() ).woCompare( fromjson( "{'_id':0,a:[5]}" ) ) == 0 );
}
2009-03-25 15:34:32 +01:00
};
class PushInsideNothing : public SetBase {
public:
void run() {
client().insert( ns(), fromjson( "{'_id':0}" ) );
client().update( ns(), Query(), BSON( "$push" << BSON( "a.b" << 5 ) ) );
2009-04-03 16:48:26 +02:00
ASSERT( client().findOne( ns(), Query() ).woCompare( fromjson( "{'_id':0,a:{b:[5]}}" ) ) == 0 );
}
2009-03-25 15:34:32 +01:00
};
class CantPushInsideOtherMod : public SetBase {
public:
void run() {
client().insert( ns(), fromjson( "{'_id':0}" ) );
client().update( ns(), Query(), BSON( "$set" << BSON( "a" << BSONObj() ) << "$push" << BSON( "a.b" << 5 ) ) );
2009-04-03 16:48:26 +02:00
ASSERT( client().findOne( ns(), Query() ).woCompare( fromjson( "{'_id':0}" ) ) == 0 );
}
2009-03-25 15:34:32 +01:00
};
2009-04-03 16:48:26 +02:00
2009-03-25 15:34:32 +01:00
class CantPushTwice : public SetBase {
public:
void run() {
client().insert( ns(), fromjson( "{'_id':0,a:[]}" ) );
client().update( ns(), Query(), BSON( "$push" << BSON( "a" << 4 ) << "$push" << BSON( "a" << 5 ) ) );
ASSERT( client().findOne( ns(), Query() ).woCompare( fromjson( "{'_id':0,a:[]}" ) ) == 0 );
2009-04-03 16:48:26 +02:00
}
2009-03-25 15:34:32 +01:00
};
2009-04-03 16:48:26 +02:00
2009-03-26 22:34:19 +01:00
class SetEncapsulationConflictsWithExistingType : public SetBase {
public:
void run() {
client().insert( ns(), fromjson( "{'_id':0,a:{b:4}}" ) );
client().update( ns(), Query(), BSON( "$set" << BSON( "a.b.c" << 4.0 ) ) );
ASSERT( client().findOne( ns(), Query() ).woCompare( fromjson( "{'_id':0,a:{b:4}}" ) ) == 0 );
2009-04-03 16:48:26 +02:00
}
2009-03-26 22:34:19 +01:00
};
2009-03-26 22:51:57 +01:00
class CantPushToParent : public SetBase {
public:
void run() {
client().insert( ns(), fromjson( "{'_id':0,a:{b:4}}" ) );
client().update( ns(), Query(), BSON( "$push" << BSON( "a" << 4.0 ) ) );
2009-04-03 16:48:26 +02:00
ASSERT( client().findOne( ns(), Query() ).woCompare( fromjson( "{'_id':0,a:{b:4}}" ) ) == 0 );
2009-03-26 22:51:57 +01:00
}
};
2009-04-03 16:48:26 +02:00
2009-03-26 22:51:57 +01:00
class CantIncParent : public SetBase {
public:
void run() {
client().insert( ns(), fromjson( "{'_id':0,a:{b:4}}" ) );
client().update( ns(), Query(), BSON( "$inc" << BSON( "a" << 4.0 ) ) );
2009-04-03 16:48:26 +02:00
ASSERT( client().findOne( ns(), Query() ).woCompare( fromjson( "{'_id':0,a:{b:4}}" ) ) == 0 );
2009-03-26 22:51:57 +01:00
}
};
2009-04-03 16:48:26 +02:00
2009-03-27 15:36:59 +01:00
class DontDropEmpty : public SetBase {
public:
void run() {
client().insert( ns(), fromjson( "{'_id':0,a:{b:{}}}" ) );
client().update( ns(), Query(), BSON( "$set" << BSON( "a.c" << 4.0 ) ) );
2009-04-03 16:48:26 +02:00
ASSERT( client().findOne( ns(), Query() ).woCompare( fromjson( "{'_id':0,a:{b:{},c:4}}" ) ) == 0 );
2009-03-27 15:36:59 +01:00
}
};
class InsertInEmpty : public SetBase {
public:
void run() {
client().insert( ns(), fromjson( "{'_id':0,a:{b:{}}}" ) );
client().update( ns(), Query(), BSON( "$set" << BSON( "a.b.f" << 4.0 ) ) );
2009-04-03 16:48:26 +02:00
ASSERT( client().findOne( ns(), Query() ).woCompare( fromjson( "{'_id':0,a:{b:{f:4}}}" ) ) == 0 );
2009-03-27 15:36:59 +01:00
}
};
class IndexParentOfMod : public SetBase {
public:
void run() {
client().ensureIndex( ns(), BSON( "a" << 1 ) );
client().insert( ns(), fromjson( "{'_id':0}" ) );
client().update( ns(), Query(), fromjson( "{$set:{'a.b':4}}" ) );
ASSERT_EQUALS( fromjson( "{'_id':0,a:{b:4}}" ) , client().findOne( ns(), Query() ) );
ASSERT_EQUALS( fromjson( "{'_id':0,a:{b:4}}" ) , client().findOne( ns(), fromjson( "{'a.b':4}" ) ) ); // make sure the index works
}
};
2009-04-03 16:48:26 +02:00
class IndexModSet : public SetBase {
public:
void run() {
client().ensureIndex( ns(), BSON( "a.b" << 1 ) );
client().insert( ns(), fromjson( "{'_id':0,a:{b:3}}" ) );
client().update( ns(), Query(), fromjson( "{$set:{'a.b':4}}" ) );
ASSERT_EQUALS( fromjson( "{'_id':0,a:{b:4}}" ) , client().findOne( ns(), Query() ) );
ASSERT_EQUALS( fromjson( "{'_id':0,a:{b:4}}" ) , client().findOne( ns(), fromjson( "{'a.b':4}" ) ) ); // make sure the index works
}
};
class PreserveIdWithIndex : public SetBase { // Not using $set, but base class is still useful
public:
void run() {
client().insert( ns(), BSON( "_id" << 55 << "i" << 5 ) );
client().update( ns(), BSON( "i" << 5 ), BSON( "i" << 6 ) );
ASSERT( !client().findOne( ns(), Query( BSON( "_id" << 55 ) ).hint
( "{\"_id\":ObjectId(\"000000000000000000000000\")}" ) ).isEmpty() );
}
};
2009-05-06 16:19:11 +02:00
class CheckNoMods : public SetBase {
public:
void run() {
client().update( ns(), BSONObj(), BSON( "i" << 5 << "$set" << BSON( "q" << 3 ) ), true );
ASSERT( error() );
}
};
class UpdateMissingToNull : public SetBase {
public:
void run() {
client().insert( ns(), BSON( "a" << 5 ) );
client().update( ns(), BSON( "a" << 5 ), fromjson( "{$set:{b:null}}" ) );
ASSERT_EQUALS( jstNULL, client().findOne( ns(), QUERY( "a" << 5 ) ).getField( "b" ).type() );
}
};
namespace ModSetTests {
class internal1 {
public:
void run(){
BSONObj b = BSON( "$inc" << BSON( "x" << 1 << "a.b" << 1 ) );
2010-01-21 18:29:18 +01:00
ModSet m(b);
ASSERT( m.haveModForField( "x" ) );
ASSERT( m.haveModForField( "a.b" ) );
ASSERT( ! m.haveModForField( "y" ) );
ASSERT( ! m.haveModForField( "a.c" ) );
ASSERT( ! m.haveModForField( "a" ) );
2009-12-10 20:29:14 +01:00
ASSERT( m.haveConflictingMod( "x" ) );
ASSERT( m.haveConflictingMod( "a" ) );
ASSERT( m.haveConflictingMod( "a.b" ) );
ASSERT( ! m.haveConflictingMod( "a.bc" ) );
ASSERT( ! m.haveConflictingMod( "a.c" ) );
ASSERT( ! m.haveConflictingMod( "a.a" ) );
}
};
class Base {
public:
virtual ~Base(){}
void test( BSONObj morig , BSONObj in , BSONObj wanted ){
BSONObj m = morig.copy();
2010-01-21 18:29:18 +01:00
ModSet set(m);
BSONObj out = set.prepare(in)->createNewFromMods();
ASSERT_EQUALS( wanted , out );
}
};
class inc1 : public Base {
public:
void run(){
BSONObj m = BSON( "$inc" << BSON( "x" << 1 ) );
test( m , BSON( "x" << 5 ) , BSON( "x" << 6 ) );
test( m , BSON( "a" << 5 ) , BSON( "a" << 5 << "x" << 1 ) );
test( m , BSON( "z" << 5 ) , BSON( "x" << 1 << "z" << 5 ) );
}
};
class inc2 : public Base {
public:
void run(){
BSONObj m = BSON( "$inc" << BSON( "a.b" << 1 ) );
test( m , BSONObj() , BSON( "a" << BSON( "b" << 1 ) ) );
test( m , BSON( "a" << BSON( "b" << 2 ) ) , BSON( "a" << BSON( "b" << 3 ) ) );
m = BSON( "$inc" << BSON( "a.b" << 1 << "a.c" << 1 ) );
test( m , BSONObj() , BSON( "a" << BSON( "b" << 1 << "c" << 1 ) ) );
}
};
2009-12-10 20:29:14 +01:00
class set1 : public Base {
public:
void run(){
test( BSON( "$set" << BSON( "x" << 17 ) ) , BSONObj() , BSON( "x" << 17 ) );
test( BSON( "$set" << BSON( "x" << 17 ) ) , BSON( "x" << 5 ) , BSON( "x" << 17 ) );
test( BSON( "$set" << BSON( "x.a" << 17 ) ) , BSON( "z" << 5 ) , BSON( "x" << BSON( "a" << 17 )<< "z" << 5 ) );
2009-12-10 20:29:14 +01:00
}
};
class push1 : public Base {
public:
void run(){
test( BSON( "$push" << BSON( "a" << 5 ) ) , fromjson( "{a:[1]}" ) , fromjson( "{a:[1,5]}" ) );
}
};
};
2009-12-21 21:56:56 +01:00
namespace basic {
class Base : public ClientBase {
virtual const char * ns() = 0;
virtual void dotest() = 0;
protected:
void test( const char* initial , const char* mod , const char* after ){
test( fromjson( initial ) , fromjson( mod ) , fromjson( after ) );
}
void test( const BSONObj& initial , const BSONObj& mod , const BSONObj& after ){
client().dropCollection( ns() );
client().insert( ns() , initial );
client().update( ns() , BSONObj() , mod );
ASSERT_EQUALS( after , client().findOne( ns(), BSONObj() ));
client().dropCollection( ns() );
}
2009-12-21 21:56:56 +01:00
public:
Base(){}
virtual ~Base(){
}
2009-12-21 21:56:56 +01:00
void run(){
client().dropCollection( ns() );
dotest();
2009-12-21 21:56:56 +01:00
client().dropCollection( ns() );
}
};
class SingleTest : public Base {
virtual BSONObj initial() = 0;
virtual BSONObj mod() = 0;
virtual BSONObj after() = 0;
void dotest(){
test( initial() , mod() , after() );
}
};
2009-12-21 21:56:56 +01:00
class inc1 : public SingleTest {
2009-12-21 21:56:56 +01:00
virtual BSONObj initial(){
return BSON( "_id" << 1 << "x" << 1 );
}
virtual BSONObj mod(){
return BSON( "$inc" << BSON( "x" << 2 ) );
}
virtual BSONObj after(){
return BSON( "_id" << 1 << "x" << 3 );
}
virtual const char * ns(){
return "unittests.inc1";
}
};
2010-01-26 17:54:45 +01:00
class inc2 : public SingleTest {
virtual BSONObj initial(){
return BSON( "_id" << 1 << "x" << 1 );
}
virtual BSONObj mod(){
return BSON( "$inc" << BSON( "x" << 2.5 ) );
}
virtual BSONObj after(){
return BSON( "_id" << 1 << "x" << 3.5 );
}
virtual const char * ns(){
return "unittests.inc2";
}
};
2009-12-21 21:56:56 +01:00
class bit1 : public Base {
const char * ns(){
return "unittests.bit1";
}
void dotest(){
test( BSON( "_id" << 1 << "x" << 3 ) , BSON( "$bit" << BSON( "x" << BSON( "and" << 2 ) ) ) , BSON( "_id" << 1 << "x" << ( 3 & 2 ) ) );
test( BSON( "_id" << 1 << "x" << 1 ) , BSON( "$bit" << BSON( "x" << BSON( "or" << 4 ) ) ) , BSON( "_id" << 1 << "x" << ( 1 | 4 ) ) );
test( BSON( "_id" << 1 << "x" << 3 ) , BSON( "$bit" << BSON( "x" << BSON( "and" << 2 << "or" << 8 ) ) ) , BSON( "_id" << 1 << "x" << ( ( 3 & 2 ) | 8 ) ) );
test( BSON( "_id" << 1 << "x" << 3 ) , BSON( "$bit" << BSON( "x" << BSON( "or" << 2 << "and" << 8 ) ) ) , BSON( "_id" << 1 << "x" << ( ( 3 | 2 ) & 8 ) ) );
}
};
class unset : public Base {
const char * ns(){
return "unittests.unset";
}
void dotest(){
test( "{_id:1,x:1}" , "{$unset:{x:1}}" , "{_id:1}" );
}
};
class setswitchint : public Base {
const char * ns(){
return "unittests.int1";
}
void dotest(){
test( BSON( "_id" << 1 << "x" << 1 ) , BSON( "$set" << BSON( "x" << 5.6 ) ) , BSON( "_id" << 1 << "x" << 5.6 ) );
test( BSON( "_id" << 1 << "x" << 5.6 ) , BSON( "$set" << BSON( "x" << 1 ) ) , BSON( "_id" << 1 << "x" << 1 ) );
}
};
2009-12-21 21:56:56 +01:00
};
class All : public Suite {
public:
2009-09-17 23:23:38 +02:00
All() : Suite( "update" ) {
}
void setupTests(){
add< ModId >();
add< ModNonmodMix >();
add< InvalidMod >();
add< ModNotFirst >();
add< ModDuplicateFieldSpec >();
add< IncNonNumber >();
add< PushAllNonArray >();
add< PullAllNonArray >();
add< IncTargetNonNumber >();
add< SetNum >();
add< SetString >();
add< SetStringDifferentLength >();
add< SetStringToNum >();
add< SetStringToNumInPlace >();
add< ModDotted >();
add< SetInPlaceDotted >();
2009-04-03 16:48:26 +02:00
add< SetRecreateDotted >();
add< SetMissingDotted >();
add< SetAdjacentDotted >();
add< IncMissing >();
add< MultiInc >();
2009-04-03 16:48:26 +02:00
add< UnorderedNewSet >();
add< UnorderedNewSetAdjacent >();
add< ArrayEmbeddedSet >();
add< AttemptEmbedInExistingNum >();
add< AttemptEmbedConflictsWithOtherSet >();
add< ModMasksEmbeddedConflict >();
add< ModOverwritesExistingObject >();
add< InvalidEmbeddedSet >();
add< UpsertMissingEmbedded >();
add< Push >();
add< PushInvalidEltType >();
add< PushConflictsWithOtherMod >();
add< PushFromNothing >();
add< PushFromEmpty >();
add< PushInsideNothing >();
add< CantPushInsideOtherMod >();
add< CantPushTwice >();
add< SetEncapsulationConflictsWithExistingType >();
add< CantPushToParent >();
add< CantIncParent >();
add< DontDropEmpty >();
add< InsertInEmpty >();
add< IndexParentOfMod >();
add< IndexModSet >();
add< PreserveIdWithIndex >();
2009-05-06 16:19:11 +02:00
add< CheckNoMods >();
add< UpdateMissingToNull >();
2009-12-21 21:56:56 +01:00
add< ModSetTests::internal1 >();
add< ModSetTests::inc1 >();
add< ModSetTests::inc2 >();
2009-12-10 20:29:14 +01:00
add< ModSetTests::set1 >();
add< ModSetTests::push1 >();
2009-12-21 21:56:56 +01:00
add< basic::inc1 >();
2010-01-26 17:54:45 +01:00
add< basic::inc2 >();
add< basic::bit1 >();
add< basic::unset >();
add< basic::setswitchint >();
2009-04-03 16:48:26 +02:00
}
2009-09-17 23:23:38 +02:00
} myall;
2009-04-03 16:48:26 +02:00
} // namespace UpdateTests