/*
* Copyright (c) 2008-2014 MongoDB, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.mongodb;
import com.mongodb.util.TestCase;
import org.bson.BSON;
import org.bson.BSONDecoder;
import org.bson.BSONObject;
import org.bson.BasicBSONDecoder;
import org.bson.types.ObjectId;
import org.junit.Test;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Date;
import java.util.List;
import java.util.Random;
import java.util.Set;
import java.util.regex.Pattern;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
@SuppressWarnings({"unchecked", "rawtypes"})
public class ByteTest extends TestCase {
@Test
public void testObject1(){
DBObject o = new BasicDBObject();
o.put( "eliot" , "horowitz" );
o.put( "num" , 517 );
BSONObject read = BSON.decode( BSON.encode( o ) );
assertEquals( "horowitz" , read.get( "eliot" ).toString() );
assertEquals( 517.0 , ((Integer)read.get( "num" )).doubleValue(), .01 );
}
@Test
public void testString()
throws Exception {
String eliot = java.net.URLDecoder.decode( "horowitza%C3%BCa" , "UTF-8" );
DBObject o = new BasicDBObject();
o.put( "eliot" , eliot );
o.put( "num" , 517 );
BSONObject read = BSON.decode( BSON.encode( o ) );
assertEquals( eliot , read.get( "eliot" ).toString() );
assertEquals( 517.0 , ((Integer)read.get( "num" )).doubleValue(), .01 );
}
@Test
public void testObject2(){
DBObject o = new BasicDBObject();
o.put( "eliot" , "horowitz" );
o.put( "num" , 517.3 );
o.put( "z" , "y" );
o.put( "asd" , null );
DBObject o2 = new BasicDBObject();
o2.put( "a" , "b" );
o2.put( "b" , "a" );
o.put( "next" , o2 );
BSONObject read = BSON.decode( BSON.encode( o ) );
assertEquals( "horowitz" , read.get( "eliot" ).toString() );
assertEquals( 517.3 , ((Double)read.get( "num" )).doubleValue(), .01 );
assertEquals( "b" , ((BSONObject)read.get( "next" ) ).get( "a" ).toString() );
assertEquals( "a" , ((BSONObject)read.get( "next" ) ).get( "b" ).toString() );
assertEquals( "y" , read.get( "z" ).toString() );
assertEquals( o.keySet().size() , read.keySet().size() );
}
@Test
public void testArray1(){
DBObject o = new BasicDBObject();
o.put( "eliot" , "horowitz" );
o.put( "num" , 517 );
o.put( "z" , "y" );
o.put( "asd" , null );
o.put( "myt" , true );
o.put( "myf" , false );
List a = new ArrayList();
a.add( "A" );
a.add( "B" );
a.add( "C" );
o.put( "a" , a );
o.put( "d" , new Date() );
//o.put( "r" , Pattern.compile( "\\d+" , "i" ) );
BSONObject read = BSON.decode( BSON.encode( o ) );
assertEquals( "horowitz" , read.get( "eliot" ).toString() );
assertEquals( 517 , ((Integer)read.get( "num" )).intValue() );
assertEquals( "y" , read.get( "z" ).toString() );
assertEquals( o.keySet().size() , read.keySet().size() );
assertEquals( 3 , a.size() );
assertEquals( a.size() , ((List)read.get( "a" ) ).size() );
assertEquals( "A" , ((List)read.get( "a" ) ).get( 0 ).toString() );
assertEquals( "B" , ((List)read.get( "a" ) ).get( 1 ).toString() );
assertEquals( "C" , ((List)read.get( "a" ) ).get( 2 ).toString() );
assertEquals( ((Date)o.get("d")).getTime() , ((Date)read.get("d")).getTime() );
assertEquals( true , (Boolean)o.get("myt") );
assertEquals( false , (Boolean)o.get("myf") );
//assertEquals( o.get( "r" ).toString() , read.get("r").toString() );
}
@Test
public void testArray2(){
DBObject x = new BasicDBObject();
x.put( "a" , new String[]{ "a" , "b" , "c" } );
x.put( "b" , new int[]{ 1 , 2 , 3 } );
BSONObject y = BSON.decode( BSON.encode( x ) );
List l = (List)y.get("a");
assertEquals( 3 , l.size() );
assertEquals( "a" , l.get(0) );
assertEquals( "b" , l.get(1) );
assertEquals( "c" , l.get(2) );
l = (List)y.get("b");
assertEquals( 3 , l.size() );
assertEquals( 1 , l.get(0) );
assertEquals( 2 , l.get(1) );
assertEquals( 3 , l.get(2) );
}
@Test
public void testCharacterEncode(){
DBObject x = new BasicDBObject();
x.put( "a" , new Character[]{ 'a' , 'b' , 'c' } );
x.put( "b" , 's');
BSONObject y = BSON.decode( BSON.encode( x ) );
List l = (List)y.get("a");
assertEquals( 3 , l.size() );
assertEquals( "a" , l.get(0) );
assertEquals( "b" , l.get(1) );
assertEquals( "c" , l.get(2) );
assertEquals( "s" , y.get("b") );
}
@Test
public void testObjectId(){
assertTrue( (new ObjectId()).compareTo( new ObjectId() ) < 0 );
assertTrue( (new ObjectId(0 , 0 , 0 )).compareTo( new ObjectId() ) < 0 );
assertTrue( (new ObjectId(0 , 0 , 0 )).compareTo( new ObjectId( 0 , 0 , 1 ) ) < 0 );
assertTrue( (new ObjectId(5 , 5 , 5 )).compareTo( new ObjectId( 5 , 5 , 6 ) ) < 0 );
assertTrue( (new ObjectId(5 , 5 , 5 )).compareTo( new ObjectId( 5 , 6 , 5 ) ) < 0 );
assertTrue( (new ObjectId(5 , 5 , 5 )).compareTo( new ObjectId( 6 , 5 , 5 ) ) < 0 );
}
@Test
public void testBinary() {
byte barray[] = new byte[256];
for( int i=0; i<256; i++ ) {
barray[i] = (byte)(i-128);
}
DBObject o = new BasicDBObject();
o.put( "bytes", barray );
byte[] encoded = BSON.encode( o );
assertEquals( 273 , encoded.length );
BSONObject read = BSON.decode( encoded );
byte[] b = (byte[])read.get( "bytes" );
assertEquals(barray.length, b.length);
for( int i=0; i<256; i++ ) {
assertEquals( b[i], barray[i] );
}
assertEquals( o.keySet().size() , read.keySet().size() );
}
private void go( DBObject o , int serialized_len ) {
go( o, serialized_len, 0 );
}
private void go( DBObject o , int serialized_len, int transient_fields ) {
byte[] encoded = BSON.encode( o );
assertEquals( serialized_len , encoded.length );
BSONObject read = BSON.decode( encoded );
assertEquals( o.keySet().size() - transient_fields, read.keySet().size() );
if ( transient_fields == 0 )
assertEquals( o , read );
}
@Test
public void testEncodeDecode() {
ArrayList t = new ArrayList();
Object obj = null;
// null object
boolean threw = false;
try {
go(null, 0 );
}
catch( RuntimeException e ) {
threw = true;
}
assertEquals( threw, true );
threw = false;
DBObject o = new BasicDBObject();
int serialized_len = 5;
// empty obj
go( o, 5 );
// _id == null
o.put( "_id" , obj );
assertEquals( Bytes.getType( obj ), Bytes.NULL );
go( o, 10 );
// _id == non-objid
obj = new ArrayList();
o.put( "_id" , obj );
assertEquals( Bytes.getType( obj ), Bytes.ARRAY );
go( o, 15 );
// _id == ObjectId
obj = new ObjectId();
o.put( "_id" , obj );
assertEquals( Bytes.getType( obj ), Bytes.OID );
go( o, 22 );
t.add( "collection" );
o = new BasicDBObject();
o.put( "collection" , collection);
o.put( "_transientFields" , t );
go( o, 5, 2 );
t.clear();
// transientFields
o = new BasicDBObject();
o.put( "_transientFields", new ArrayList() );
go( o, 5, 1 );
t.add( "foo" );
o = new BasicDBObject();
o.put( "_transientFields", t );
o.put( "foo", "bar" );
go( o, 5, 2 );
t.clear();
o = new BasicDBObject();
o.put( "z" , "" );
go( o, 13 );
t.clear();
// $where
/*o = new BasicDBObject();
o.put( "$where", "eval( true )" );
go( o, 30 );
*/
obj = 5;
o = new BasicDBObject();
o.put( "$where", obj );
assertEquals( Bytes.getType( obj ), Bytes.NUMBER_INT );
go( o, 17 );
}
@Test
public void testPatternFlags() {
boolean threw = false;
assertEquals( 0, Bytes.regexFlags( "" ) );
assertEquals( "", Bytes.regexFlags( 0 ) );
try {
Bytes.regexFlags( "f" );
}
catch( RuntimeException e ) {
threw = true;
}
assertEquals( threw, true );
threw = false;
try {
Bytes.regexFlags( 513 );
}
catch( RuntimeException e ) {
threw = true;
}
assertEquals( threw, true );
Pattern lotsoflags = Pattern.compile( "foo", Pattern.CANON_EQ |
Pattern.DOTALL |
Pattern.CASE_INSENSITIVE |
Pattern.UNIX_LINES |
Pattern.MULTILINE |
Pattern.LITERAL |
Pattern.UNICODE_CASE |
Pattern.COMMENTS |
256 );
String s = Bytes.regexFlags( lotsoflags.flags() );
char prev = s.charAt( 0 );
for( int i=1; i<s.length(); i++ ) {
char current = s.charAt( i );
assertTrue( prev < current );
prev = current;
}
int check = Bytes.regexFlags( s );
assertEquals( lotsoflags.flags(), check );
}
@Test
public void testPattern() {
Pattern p = Pattern.compile( "([a-zA-Z0-9_-])([a-zA-Z0-9_.-]*)@(((25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9][0-9]|[0-9])\\.))" );
DBObject o = new BasicDBObject();
o.put( "p", p );
BSONObject read = BSON.decode( BSON.encode( o ) );
Pattern p2 = (Pattern)read.get( "p" );
assertEquals( p2.pattern(), p.pattern() );
assertEquals( o.keySet().size(), read.keySet().size() );
}
@Test
public void testLong() {
long s = -9223372036854775808l;
long m = 1l;
long l = 9223372036854775807l;
DBObject obj = BasicDBObjectBuilder.start().add("s", s).add("m", m).add("l", l).get();
DBCollection c = collection;
c.insert(obj);
DBObject r = c.findOne();
assertEquals(r.get("s"), -9223372036854775808l);
assertEquals(r.get("m"), 1l);
assertEquals(r.get("l"), 9223372036854775807l);
}
@Test
public void testIdOrder() {
DBCollection c = collection;
BasicDBObject x = new BasicDBObject();
x.put( "a" , 5 );
x.put( "_id" , 6 );
BasicDBObject y = new BasicDBObject();
y.put( "b" , 7 );
y.put( "_id" , 8 );
x.put( "c" , y );
c.insert( x );
DBObject out = c.findOne();
_testKeys( new String[]{ "_id" , "a" , "c" } , out.keySet() );
_testKeys( new String[]{ "b" , "_id" } , ((DBObject)out.get( "c" )).keySet() );
}
void _testKeys( String[] want , Set<String> got ){
assertEquals( want.length , got.size() );
int pos = 0;
for ( String s : got ){
assertEquals( want[pos++] , s );
}
}
@Test
public void testBytes2(){
DBObject x = BasicDBObjectBuilder.start( "x" , 1 ).add( "y" , "asdasd" ).get();
byte[] b = Bytes.encode( x );
assertEquals( x , Bytes.decode( b ) );
}
@Test
public void testMany()
throws IOException {
DBObject orig = new BasicDBObject();
orig.put( "a" , 5 );
orig.put( "ab" , 5.1 );
orig.put( "abc" , 5123L );
orig.put( "abcd" , "asdasdasd" );
orig.put( "abcde" , "asdasdasdasdasdasdasdasd" );
orig.put( "abcdef" , Arrays.asList( new String[]{ "asdasdasdasdasdasdasdasd" , "asdasdasdasdasdasdasdasd" } ) );
byte[] b = Bytes.encode( orig );
final int n = 1000;
ByteArrayOutputStream out = new ByteArrayOutputStream();
for ( int i=0; i<n; i++ )
out.write( b );
ByteArrayInputStream in = new ByteArrayInputStream( out.toByteArray() );
BSONDecoder d = new BasicBSONDecoder();
for ( int i=0; i<n; i++ ){
BSONObject x = d.readObject( in );
assertEquals( orig , x );
}
assertEquals( -1 , in.read() );
}
int _fix( int x ){
if ( x < 0 )
return -1;
if ( x > 0 )
return 1;
return 0;
}
@Test
public void testObjcetIdCompare(){
Random r = new Random( 171717 );
List<ObjectId> l = new ArrayList<ObjectId>();
for ( int i=0; i<10000; i++ ){
l.add( new ObjectId( new Date( Math.abs( r.nextLong() ) ) , Math.abs( r.nextInt() ) , Math.abs( r.nextInt() ) ) );
}
for ( int i=1; i<l.size(); i++ ){
int a = _fix( l.get(0).compareTo( l.get(i) ) );
int b = _fix( l.get(0).toString().compareTo( l.get(i).toString() ) );
if ( a == b )
continue;
throw new RuntimeException( "broken [" + l.get(0) + "] [" + l.get(i) + "] a: " + a + " b: " + b );
}
DBCollection c = collection;
for ( ObjectId o : l ){
c.insert( new BasicDBObject( "_id" , o ) );
}
Collections.sort( l );
List<DBObject> out = c.find().sort( new BasicDBObject( "_id" , 1 ) ).toArray();
assertEquals( l.size() , out.size() );
for ( int i=0; i<l.size(); i++ ){
assertEquals( l.get(i) , out.get(i).get( "_id" ) );
}
}
}