2009-04-23 20:28:22 +02:00
// javajstests.cpp
2009-02-03 06:14:14 +01:00
//
/**
* Copyright ( C ) 2009 10 gen 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-04-23 20:28:22 +02:00
# include "../scripting/engine.h"
2009-02-03 06:14:14 +01:00
# include "dbtests.h"
2009-05-27 21:40:57 +02:00
# include "../db/instance.h"
namespace mongo {
bool dbEval ( const char * ns , BSONObj & cmd , BSONObjBuilder & result , string & errmsg ) ;
} // namespace mongo
2009-04-24 04:44:19 +02:00
namespace JSTests {
2009-02-03 06:14:14 +01:00
class Fundamental {
public :
void run ( ) {
2009-02-03 17:50:30 +01:00
// By calling JavaJSImpl() inside run(), we ensure the unit test framework's
// signal handlers are pre-installed from JNI's perspective. This allows
// JNI to catch signals generated within the JVM and forward other signals
// as appropriate.
2009-04-23 20:28:22 +02:00
ScriptEngine : : setup ( ) ;
globalScriptEngine - > runTest ( ) ;
2009-02-03 06:14:14 +01:00
}
} ;
2009-04-24 04:44:19 +02:00
class BasicScope {
public :
void run ( ) {
Scope * s = globalScriptEngine - > createScope ( ) ;
s - > setNumber ( " x " , 5 ) ;
assert ( 5 = = s - > getNumber ( " x " ) ) ;
s - > setNumber ( " x " , 1.67 ) ;
assert ( 1.67 = = s - > getNumber ( " x " ) ) ;
s - > setString ( " s " , " eliot was here " ) ;
assert ( " eliot was here " = = s - > getString ( " s " ) ) ;
s - > setBoolean ( " b " , true ) ;
assert ( s - > getBoolean ( " b " ) ) ;
if ( 0 ) {
s - > setBoolean ( " b " , false ) ;
assert ( ! s - > getBoolean ( " b " ) ) ;
}
delete s ;
}
} ;
2009-04-24 05:52:47 +02:00
class FalseTests {
public :
void run ( ) {
Scope * s = globalScriptEngine - > createScope ( ) ;
assert ( ! s - > getBoolean ( " x " ) ) ;
s - > setString ( " z " , " " ) ;
assert ( ! s - > getBoolean ( " z " ) ) ;
delete s ;
}
} ;
2009-04-24 22:41:40 +02:00
class SimpleFunctions {
public :
void run ( ) {
Scope * s = globalScriptEngine - > createScope ( ) ;
s - > invoke ( " x=5; " , BSONObj ( ) ) ;
assert ( 5 = = s - > getNumber ( " x " ) ) ;
s - > invoke ( " return 17; " , BSONObj ( ) ) ;
assert ( 17 = = s - > getNumber ( " return " ) ) ;
s - > invoke ( " function(){ return 17; } " , BSONObj ( ) ) ;
assert ( 17 = = s - > getNumber ( " return " ) ) ;
s - > setNumber ( " x " , 1.76 ) ;
s - > invoke ( " return x == 1.76; " , BSONObj ( ) ) ;
assert ( s - > getBoolean ( " return " ) ) ;
s - > setNumber ( " x " , 1.76 ) ;
s - > invoke ( " return x == 1.79; " , BSONObj ( ) ) ;
assert ( ! s - > getBoolean ( " return " ) ) ;
delete s ;
}
} ;
2009-04-24 23:19:24 +02:00
class ObjectMapping {
public :
void run ( ) {
Scope * s = globalScriptEngine - > createScope ( ) ;
2009-04-29 17:12:35 +02:00
BSONObj o = BSON ( " x " < < 17 < < " y " < < " eliot " < < " z " < < " sara " ) ;
2009-04-24 23:19:24 +02:00
s - > setObject ( " blah " , o ) ;
2009-04-29 16:29:56 +02:00
2009-04-25 03:27:25 +02:00
s - > invoke ( " return blah.x; " , BSONObj ( ) ) ;
2009-04-29 16:16:39 +02:00
ASSERT_EQUALS ( 17 , s - > getNumber ( " return " ) ) ;
2009-04-29 16:29:56 +02:00
s - > invoke ( " return blah.y; " , BSONObj ( ) ) ;
ASSERT_EQUALS ( " eliot " , s - > getString ( " return " ) ) ;
2009-04-24 23:19:24 +02:00
2009-04-29 17:12:35 +02:00
s - > setThis ( & o ) ;
s - > invoke ( " return this.z; " , BSONObj ( ) ) ;
ASSERT_EQUALS ( " sara " , s - > getString ( " return " ) ) ;
2009-05-14 22:50:14 +02:00
s - > invoke ( " this.z == 'sara'; " , BSONObj ( ) ) ;
ASSERT_EQUALS ( true , s - > getBoolean ( " return " ) ) ;
s - > invoke ( " this.z == 'asara'; " , BSONObj ( ) ) ;
ASSERT_EQUALS ( false , s - > getBoolean ( " return " ) ) ;
2009-04-29 21:45:11 +02:00
s - > invoke ( " return this.x == 17; " , BSONObj ( ) ) ;
ASSERT_EQUALS ( true , s - > getBoolean ( " return " ) ) ;
s - > invoke ( " return this.x == 18; " , BSONObj ( ) ) ;
ASSERT_EQUALS ( false , s - > getBoolean ( " return " ) ) ;
s - > invoke ( " function(){ return this.x == 17; } " , BSONObj ( ) ) ;
ASSERT_EQUALS ( true , s - > getBoolean ( " return " ) ) ;
2009-04-29 17:12:35 +02:00
2009-04-29 21:45:11 +02:00
s - > invoke ( " function(){ return this.x == 18; } " , BSONObj ( ) ) ;
ASSERT_EQUALS ( false , s - > getBoolean ( " return " ) ) ;
s - > invoke ( " function (){ return this.x == 17; } " , BSONObj ( ) ) ;
ASSERT_EQUALS ( true , s - > getBoolean ( " return " ) ) ;
2009-05-21 16:05:26 +02:00
2009-05-06 21:30:05 +02:00
s - > invoke ( " function z(){ return this.x == 18; } " , BSONObj ( ) ) ;
ASSERT_EQUALS ( false , s - > getBoolean ( " return " ) ) ;
2009-05-21 16:05:26 +02:00
s - > invoke ( " x = 5; for( ; x <10; x++){ a = 1; } " , BSONObj ( ) ) ;
ASSERT_EQUALS ( 10 , s - > getNumber ( " x " ) ) ;
2009-04-29 17:12:35 +02:00
2009-04-24 23:19:24 +02:00
delete s ;
}
} ;
2009-05-06 17:53:39 +02:00
class ObjectDecoding {
public :
void run ( ) {
Scope * s = globalScriptEngine - > createScope ( ) ;
s - > invoke ( " z = { num : 1 }; " , BSONObj ( ) ) ;
BSONObj out = s - > getObject ( " z " ) ;
ASSERT_EQUALS ( 1 , out [ " num " ] . number ( ) ) ;
ASSERT_EQUALS ( 1 , out . nFields ( ) ) ;
s - > invoke ( " z = { x : 'eliot' }; " , BSONObj ( ) ) ;
out = s - > getObject ( " z " ) ;
ASSERT_EQUALS ( ( string ) " eliot " , out [ " x " ] . valuestr ( ) ) ;
ASSERT_EQUALS ( 1 , out . nFields ( ) ) ;
BSONObj o = BSON ( " x " < < 17 ) ;
s - > setObject ( " blah " , o ) ;
2009-05-06 18:48:19 +02:00
out = s - > getObject ( " blah " ) ;
ASSERT_EQUALS ( 17 , out [ " x " ] . number ( ) ) ;
2009-05-06 17:53:39 +02:00
delete s ;
}
} ;
2009-04-24 04:44:19 +02:00
2009-05-08 17:02:12 +02:00
class JSOIDTests {
public :
void run ( ) {
2009-05-08 23:04:07 +02:00
# ifdef MOZJS
2009-05-08 17:02:12 +02:00
Scope * s = globalScriptEngine - > createScope ( ) ;
s - > localConnect ( " blah " ) ;
s - > invoke ( " z = { _id : new ObjectId() , a : 123 }; " , BSONObj ( ) ) ;
BSONObj out = s - > getObject ( " z " ) ;
ASSERT_EQUALS ( 123 , out [ " a " ] . number ( ) ) ;
ASSERT_EQUALS ( jstOID , out [ " _id " ] . type ( ) ) ;
OID save = out [ " _id " ] . __oid ( ) ;
s - > setObject ( " a " , out ) ;
s - > invoke ( " y = { _id : a._id , a : 124 }; " , BSONObj ( ) ) ;
out = s - > getObject ( " y " ) ;
ASSERT_EQUALS ( 124 , out [ " a " ] . number ( ) ) ;
ASSERT_EQUALS ( jstOID , out [ " _id " ] . type ( ) ) ;
ASSERT_EQUALS ( out [ " _id " ] . __oid ( ) . str ( ) , save . str ( ) ) ;
s - > invoke ( " y = { _id : new ObjectId( a._id ) , a : 125 }; " , BSONObj ( ) ) ;
out = s - > getObject ( " y " ) ;
ASSERT_EQUALS ( 125 , out [ " a " ] . number ( ) ) ;
ASSERT_EQUALS ( jstOID , out [ " _id " ] . type ( ) ) ;
ASSERT_EQUALS ( out [ " _id " ] . __oid ( ) . str ( ) , save . str ( ) ) ;
delete s ;
2009-05-08 23:22:01 +02:00
# endif
2009-05-08 17:02:12 +02:00
}
} ;
2009-05-10 04:07:36 +02:00
class ObjectModTests {
public :
void run ( ) {
Scope * s = globalScriptEngine - > createScope ( ) ;
BSONObj o = BSON ( " x " < < 17 < < " y " < < " eliot " < < " z " < < " sara " ) ;
s - > setObject ( " blah " , o , true ) ;
s - > invoke ( " blah.a = 19; " , BSONObj ( ) ) ;
BSONObj out = s - > getObject ( " blah " ) ;
ASSERT ( out [ " a " ] . eoo ( ) ) ;
delete s ;
}
} ;
2009-05-14 21:34:14 +02:00
class OtherJSTypes {
public :
void run ( ) {
Scope * s = globalScriptEngine - > createScope ( ) ;
{ // date
BSONObj o ;
{
BSONObjBuilder b ;
b . appendDate ( " d " , 123456789 ) ;
o = b . obj ( ) ;
}
s - > setObject ( " x " , o ) ;
s - > invoke ( " return x.d.getTime() != 12; " , BSONObj ( ) ) ;
ASSERT_EQUALS ( true , s - > getBoolean ( " return " ) ) ;
s - > invoke ( " z = x.d.getTime(); " , BSONObj ( ) ) ;
ASSERT_EQUALS ( 123456789 , s - > getNumber ( " z " ) ) ;
2009-05-14 21:48:53 +02:00
s - > invoke ( " z = { z : x.d } " , BSONObj ( ) ) ;
BSONObj out = s - > getObject ( " z " ) ;
ASSERT ( out [ " z " ] . type ( ) = = Date ) ;
2009-05-14 21:34:14 +02:00
}
2009-05-14 21:48:53 +02:00
{ // regex
BSONObj o ;
{
BSONObjBuilder b ;
b . appendRegex ( " r " , " ^a " , " i " ) ;
o = b . obj ( ) ;
}
s - > setObject ( " x " , o ) ;
s - > invoke ( " z = x.r.test( 'b' ); " , BSONObj ( ) ) ;
ASSERT_EQUALS ( false , s - > getBoolean ( " z " ) ) ;
s - > invoke ( " z = x.r.test( 'a' ); " , BSONObj ( ) ) ;
ASSERT_EQUALS ( true , s - > getBoolean ( " z " ) ) ;
2009-05-14 21:34:14 +02:00
2009-05-14 21:48:53 +02:00
s - > invoke ( " z = x.r.test( 'ba' ); " , BSONObj ( ) ) ;
ASSERT_EQUALS ( false , s - > getBoolean ( " z " ) ) ;
s - > invoke ( " z = { a : x.r }; " , BSONObj ( ) ) ;
2009-05-14 21:34:14 +02:00
2009-05-14 22:11:01 +02:00
BSONObj out = s - > getObject ( " z " ) ;
ASSERT_EQUALS ( ( string ) " ^a " , out [ " a " ] . regex ( ) ) ;
ASSERT_EQUALS ( ( string ) " i " , out [ " a " ] . regexFlags ( ) ) ;
2009-05-14 21:48:53 +02:00
}
2009-05-14 21:34:14 +02:00
delete s ;
}
} ;
2009-05-15 14:31:11 +02:00
class SpecialDBTypes {
public :
void run ( ) {
Scope * s = globalScriptEngine - > createScope ( ) ;
BSONObjBuilder b ;
b . appendTimestamp ( " a " , 123456789 ) ;
b . appendMinKey ( " b " ) ;
b . appendMaxKey ( " c " ) ;
b . appendTimestamp ( " d " , 1234000 , 9876 ) ;
{
BSONObj t = b . done ( ) ;
2009-05-15 19:32:31 +02:00
ASSERT_EQUALS ( 1234000U , t [ " d " ] . timestampTime ( ) ) ;
ASSERT_EQUALS ( 9876U , t [ " d " ] . timestampInc ( ) ) ;
2009-05-15 14:31:11 +02:00
}
2009-05-15 15:19:13 +02:00
2009-05-15 14:31:11 +02:00
s - > setObject ( " z " , b . obj ( ) ) ;
2009-05-15 15:19:13 +02:00
assert ( s - > invoke ( " y = { a : z.a , b : z.b , c : z.c , d: z.d } " , BSONObj ( ) ) = = 0 ) ;
2009-05-15 14:31:11 +02:00
BSONObj out = s - > getObject ( " y " ) ;
ASSERT_EQUALS ( Timestamp , out [ " a " ] . type ( ) ) ;
ASSERT_EQUALS ( MinKey , out [ " b " ] . type ( ) ) ;
ASSERT_EQUALS ( MaxKey , out [ " c " ] . type ( ) ) ;
2009-05-15 15:19:13 +02:00
ASSERT_EQUALS ( Timestamp , out [ " d " ] . type ( ) ) ;
2009-05-15 14:31:11 +02:00
2009-05-15 19:32:31 +02:00
ASSERT_EQUALS ( 9876U , out [ " d " ] . timestampInc ( ) ) ;
ASSERT_EQUALS ( 1234000U , out [ " d " ] . timestampTime ( ) ) ;
ASSERT_EQUALS ( 123456789U , out [ " a " ] . date ( ) ) ;
2009-05-15 14:31:11 +02:00
delete s ;
}
} ;
2009-05-22 16:48:05 +02:00
class TypeConservation {
public :
void run ( ) {
Scope * s = globalScriptEngine - > createScope ( ) ;
// -- A --
BSONObj o ;
{
BSONObjBuilder b ;
b . append ( " a " , ( int ) 5 ) ;
b . append ( " b " , 5.6 ) ;
o = b . obj ( ) ;
}
ASSERT_EQUALS ( NumberInt , o [ " a " ] . type ( ) ) ;
ASSERT_EQUALS ( NumberDouble , o [ " b " ] . type ( ) ) ;
s - > setObject ( " z " , o ) ;
s - > invoke ( " return z " , BSONObj ( ) ) ;
BSONObj out = s - > getObject ( " return " ) ;
ASSERT_EQUALS ( 5 , out [ " a " ] . number ( ) ) ;
ASSERT_EQUALS ( 5.6 , out [ " b " ] . number ( ) ) ;
2009-05-15 14:31:11 +02:00
2009-05-22 16:48:05 +02:00
ASSERT_EQUALS ( NumberDouble , out [ " b " ] . type ( ) ) ;
ASSERT_EQUALS ( NumberInt , out [ " a " ] . type ( ) ) ;
// -- B --
{
BSONObjBuilder b ;
b . append ( " a " , ( int ) 5 ) ;
b . append ( " b " , 5.6 ) ;
o = b . obj ( ) ;
}
s - > setObject ( " z " , o , false ) ;
s - > invoke ( " return z " , BSONObj ( ) ) ;
out = s - > getObject ( " return " ) ;
ASSERT_EQUALS ( 5 , out [ " a " ] . number ( ) ) ;
ASSERT_EQUALS ( 5.6 , out [ " b " ] . number ( ) ) ;
ASSERT_EQUALS ( NumberDouble , out [ " b " ] . type ( ) ) ;
ASSERT_EQUALS ( NumberInt , out [ " a " ] . type ( ) ) ;
2009-05-26 20:43:20 +02:00
2009-05-22 16:48:05 +02:00
2009-05-26 20:43:20 +02:00
// -- C --
2009-05-22 16:48:05 +02:00
2009-05-26 20:43:20 +02:00
{
BSONObjBuilder b ;
{
BSONObjBuilder c ;
c . append ( " 0 " , 5.5 ) ;
c . append ( " 1 " , 6 ) ;
b . appendArray ( " a " , c . obj ( ) ) ;
}
o = b . obj ( ) ;
}
2009-05-22 16:48:05 +02:00
2009-05-26 20:43:20 +02:00
ASSERT_EQUALS ( NumberDouble , o [ " a " ] . embeddedObjectUserCheck ( ) [ " 0 " ] . type ( ) ) ;
ASSERT_EQUALS ( NumberInt , o [ " a " ] . embeddedObjectUserCheck ( ) [ " 1 " ] . type ( ) ) ;
s - > setObject ( " z " , o , false ) ;
out = s - > getObject ( " z " ) ;
ASSERT_EQUALS ( NumberDouble , out [ " a " ] . embeddedObjectUserCheck ( ) [ " 0 " ] . type ( ) ) ;
ASSERT_EQUALS ( NumberInt , out [ " a " ] . embeddedObjectUserCheck ( ) [ " 1 " ] . type ( ) ) ;
2009-05-22 16:48:05 +02:00
2009-05-26 20:43:20 +02:00
s - > invokeSafe ( " z.z = 5; " , BSONObj ( ) ) ;
out = s - > getObject ( " z " ) ;
ASSERT_EQUALS ( 5 , out [ " z " ] . number ( ) ) ;
ASSERT_EQUALS ( NumberDouble , out [ " a " ] . embeddedObjectUserCheck ( ) [ " 0 " ] . type ( ) ) ;
ASSERT_EQUALS ( NumberDouble , out [ " a " ] . embeddedObjectUserCheck ( ) [ " 1 " ] . type ( ) ) ; // TODO: this is technically bad, but here to make sure that i understand the behavior
2009-05-22 16:48:05 +02:00
delete s ;
}
} ;
2009-05-26 22:04:07 +02:00
2009-05-24 03:10:37 +02:00
class WeirdObjects {
public :
BSONObj build ( int depth ) {
BSONObjBuilder b ;
b . append ( " 0 " , depth ) ;
if ( depth > 0 )
b . appendArray ( " 1 " , build ( depth - 1 ) ) ;
return b . obj ( ) ;
}
void run ( ) {
Scope * s = globalScriptEngine - > createScope ( ) ;
s - > localConnect ( " blah " ) ;
for ( int i = 5 ; i < 100 ; i + = 10 ) {
s - > setObject ( " a " , build ( i ) , false ) ;
s - > invokeSafe ( " tojson( a ) " , BSONObj ( ) ) ;
s - > setObject ( " a " , build ( 5 ) , true ) ;
s - > invokeSafe ( " tojson( a ) " , BSONObj ( ) ) ;
}
delete s ;
}
} ;
2009-05-15 14:31:11 +02:00
2009-05-27 21:40:57 +02:00
void dummy_function_to_force_dbeval_cpp_linking ( ) {
BSONObj cmd ;
BSONObjBuilder result ;
string errmsg ;
dbEval ( " " , cmd , result , errmsg ) ;
}
DBDirectClient client ;
2009-05-27 21:20:09 +02:00
class Utf8Check {
public :
2009-05-27 21:43:26 +02:00
Utf8Check ( ) { reset ( ) ; }
~ Utf8Check ( ) { reset ( ) ; }
2009-05-27 21:20:09 +02:00
void run ( ) {
if ( ! globalScriptEngine - > utf8Ok ( ) ) {
log ( ) < < " utf8 not supported " < < endl ;
return ;
}
2009-05-27 21:40:57 +02:00
string utf8ObjSpec = " {'_id':' \\ u0001 \\ u007f \\ u07ff \\ uffff'} " ;
BSONObj utf8Obj = fromjson ( utf8ObjSpec ) ;
client . insert ( ns ( ) , utf8Obj ) ;
client . eval ( " unittest " , " v = db.jstests.utf8check.findOne(); db.jstests.utf8check.remove( {} ); db.jstests.utf8check.insert( v ); " ) ;
check ( utf8Obj , client . findOne ( ns ( ) , BSONObj ( ) ) ) ;
}
private :
void check ( const BSONObj & one , const BSONObj & two ) {
if ( one . woCompare ( two ) ! = 0 ) {
static string fail = string ( " Assertion failure expected " ) + string ( one ) + " , got " + string ( two ) ;
FAIL ( fail . c_str ( ) ) ;
}
2009-05-27 21:20:09 +02:00
}
2009-05-27 21:40:57 +02:00
void reset ( ) {
client . dropCollection ( ns ( ) ) ;
}
static const char * ns ( ) { return " unittest.jstests.utf8check " ; }
2009-05-27 21:20:09 +02:00
} ;
2009-05-27 22:09:59 +02:00
class LongUtf8String {
public :
LongUtf8String ( ) { reset ( ) ; }
~ LongUtf8String ( ) { reset ( ) ; }
void run ( ) {
if ( ! globalScriptEngine - > utf8Ok ( ) )
return ;
2009-05-27 23:32:22 +02:00
client . eval ( " unittest " , " db.jstests.longutf8string.save( {_id:' \\ uffff \\ uffff \\ uffff \\ uffff'} ) " ) ;
2009-05-27 22:09:59 +02:00
}
private :
void reset ( ) {
client . dropCollection ( ns ( ) ) ;
}
static const char * ns ( ) { return " unittest.jstests.longutf8string " ; }
} ;
2009-05-27 21:20:09 +02:00
2009-05-12 22:37:23 +02:00
class All : public Suite {
2009-02-03 06:14:14 +01:00
public :
All ( ) {
add < Fundamental > ( ) ;
2009-04-24 04:44:19 +02:00
add < BasicScope > ( ) ;
2009-04-24 05:52:47 +02:00
add < FalseTests > ( ) ;
2009-04-24 22:41:40 +02:00
add < SimpleFunctions > ( ) ;
2009-04-24 23:19:24 +02:00
add < ObjectMapping > ( ) ;
2009-05-06 17:53:39 +02:00
add < ObjectDecoding > ( ) ;
2009-05-08 17:02:12 +02:00
add < JSOIDTests > ( ) ;
2009-05-10 04:07:36 +02:00
add < ObjectModTests > ( ) ;
2009-05-14 21:34:14 +02:00
add < OtherJSTypes > ( ) ;
2009-05-15 14:31:11 +02:00
add < SpecialDBTypes > ( ) ;
2009-05-22 16:48:05 +02:00
add < TypeConservation > ( ) ;
2009-05-24 03:10:37 +02:00
add < WeirdObjects > ( ) ;
2009-05-27 21:20:09 +02:00
add < Utf8Check > ( ) ;
2009-05-27 22:09:59 +02:00
add < LongUtf8String > ( ) ;
2009-02-03 06:14:14 +01:00
}
} ;
} // namespace JavaJSTests
2009-04-24 04:44:19 +02:00
UnitTest : : TestPtr jsTests ( ) {
return UnitTest : : createSuite < JSTests : : All > ( ) ;
2009-02-03 06:14:14 +01:00
}