// basictests.cpp : basic unit tests // /** * Copyright (C) 2009 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 . */ #include "pch.h" #include "dbtests.h" #include "../util/base64.h" #include "../util/array.h" #include "../util/text.h" #include "../util/queue.h" #include "../util/paths.h" namespace BasicTests { class Rarely { public: void run() { int first = 0; int second = 0; int third = 0; for( int i = 0; i < 128; ++i ) { incRarely( first ); incRarely2( second ); ONCE ++third; } ASSERT_EQUALS( 1, first ); ASSERT_EQUALS( 1, second ); ASSERT_EQUALS( 1, third ); } private: void incRarely( int &c ) { RARELY ++c; } void incRarely2( int &c ) { RARELY ++c; } }; class Base64Tests { public: void roundTrip( string s ) { ASSERT_EQUALS( s , base64::decode( base64::encode( s ) ) ); } void roundTrip( const unsigned char * _data , int len ) { const char *data = (const char *) _data; string s = base64::encode( data , len ); string out = base64::decode( s ); ASSERT_EQUALS( out.size() , static_cast(len) ); bool broke = false; for ( int i=0; i 1000000 ); ASSERT( t.micros() < 2000000 ); t.reset(); sleepmillis( 1727 ); ASSERT( t.millis() >= 1000 ); ASSERT( t.millis() <= 2500 ); { int total = 1200; int ms = 2; t.reset(); for ( int i=0; i<(total/ms); i++ ) { sleepmillis( ms ); } { int x = t.millis(); if ( x < 1000 || x > 2500 ) { cout << "sleeptest x: " << x << endl; ASSERT( x >= 1000 ); ASSERT( x <= 20000 ); } } } #ifdef __linux__ { int total = 1200; int micros = 100; t.reset(); int numSleeps = 1000*(total/micros); for ( int i=0; i 2500 ) { cout << "sleeptest y: " << y << endl; ASSERT( y >= 1000 ); /* ASSERT( y <= 100000 ); */ } } } #endif } }; class AssertTests { public: int x; AssertTests() { x = 0; } string foo() { x++; return ""; } void run() { uassert( -1 , foo() , 1 ); if( x != 0 ) { ASSERT_EQUALS( 0 , x ); } try { uassert( -1 , foo() , 0 ); } catch ( ... ) {} ASSERT_EQUALS( 1 , x ); } }; namespace ArrayTests { class basic1 { public: void run() { FastArray a(100); a.push_back( 5 ); a.push_back( 6 ); ASSERT_EQUALS( 2 , a.size() ); FastArray::iterator i = a.begin(); ASSERT( i != a.end() ); ASSERT_EQUALS( 5 , *i ); ++i; ASSERT( i != a.end() ); ASSERT_EQUALS( 6 , *i ); ++i; ASSERT( i == a.end() ); } }; }; class ThreadSafeStringTest { public: void run() { ThreadSafeString s; s = "eliot"; ASSERT_EQUALS( s , "eliot" ); ASSERT( s != "eliot2" ); ThreadSafeString s2 = s; ASSERT_EQUALS( s2 , "eliot" ); { string foo; { ThreadSafeString bar; bar = "eliot2"; foo = bar.toString(); } ASSERT_EQUALS( "eliot2" , foo ); } } }; class LexNumCmp { public: void run() { ASSERT( ! isNumber( (char)255 ) ); ASSERT_EQUALS( 0, lexNumCmp( "a", "a" ) ); ASSERT_EQUALS( -1, lexNumCmp( "a", "aa" ) ); ASSERT_EQUALS( 1, lexNumCmp( "aa", "a" ) ); ASSERT_EQUALS( -1, lexNumCmp( "a", "b" ) ); ASSERT_EQUALS( 1, lexNumCmp( "100", "50" ) ); ASSERT_EQUALS( -1, lexNumCmp( "50", "100" ) ); ASSERT_EQUALS( 1, lexNumCmp( "b", "a" ) ); ASSERT_EQUALS( 0, lexNumCmp( "aa", "aa" ) ); ASSERT_EQUALS( -1, lexNumCmp( "aa", "ab" ) ); ASSERT_EQUALS( 1, lexNumCmp( "ab", "aa" ) ); ASSERT_EQUALS( 1, lexNumCmp( "0", "a" ) ); ASSERT_EQUALS( 1, lexNumCmp( "a0", "aa" ) ); ASSERT_EQUALS( -1, lexNumCmp( "a", "0" ) ); ASSERT_EQUALS( -1, lexNumCmp( "aa", "a0" ) ); ASSERT_EQUALS( 0, lexNumCmp( "0", "0" ) ); ASSERT_EQUALS( 0, lexNumCmp( "10", "10" ) ); ASSERT_EQUALS( -1, lexNumCmp( "1", "10" ) ); ASSERT_EQUALS( 1, lexNumCmp( "10", "1" ) ); ASSERT_EQUALS( 1, lexNumCmp( "11", "10" ) ); ASSERT_EQUALS( -1, lexNumCmp( "10", "11" ) ); ASSERT_EQUALS( 1, lexNumCmp( "f11f", "f10f" ) ); ASSERT_EQUALS( -1, lexNumCmp( "f10f", "f11f" ) ); ASSERT_EQUALS( -1, lexNumCmp( "f11f", "f111" ) ); ASSERT_EQUALS( 1, lexNumCmp( "f111", "f11f" ) ); ASSERT_EQUALS( -1, lexNumCmp( "f12f", "f12g" ) ); ASSERT_EQUALS( 1, lexNumCmp( "f12g", "f12f" ) ); ASSERT_EQUALS( 1, lexNumCmp( "aa{", "aab" ) ); ASSERT_EQUALS( -1, lexNumCmp( "aa{", "aa1" ) ); ASSERT_EQUALS( -1, lexNumCmp( "a1{", "a11" ) ); ASSERT_EQUALS( 1, lexNumCmp( "a1{a", "a1{" ) ); ASSERT_EQUALS( -1, lexNumCmp( "a1{", "a1{a" ) ); ASSERT_EQUALS( 1, lexNumCmp("21", "11") ); ASSERT_EQUALS( -1, lexNumCmp("11", "21") ); ASSERT_EQUALS( -1 , lexNumCmp( "a.0" , "a.1" ) ); ASSERT_EQUALS( -1 , lexNumCmp( "a.0.b" , "a.1" ) ); ASSERT_EQUALS( -1 , lexNumCmp( "b." , "b.|" ) ); ASSERT_EQUALS( -1 , lexNumCmp( "b.0e" , (string("b.") + (char)255).c_str() ) ); ASSERT_EQUALS( -1 , lexNumCmp( "b." , "b.0e" ) ); ASSERT_EQUALS( 0, lexNumCmp( "238947219478347782934718234", "238947219478347782934718234")); ASSERT_EQUALS( 0, lexNumCmp( "000238947219478347782934718234", "238947219478347782934718234")); ASSERT_EQUALS( 1, lexNumCmp( "000238947219478347782934718235", "238947219478347782934718234")); ASSERT_EQUALS( -1, lexNumCmp( "238947219478347782934718234", "238947219478347782934718234.1")); ASSERT_EQUALS( 0, lexNumCmp( "238", "000238")); ASSERT_EQUALS( 0, lexNumCmp( "002384", "0002384")); ASSERT_EQUALS( 0, lexNumCmp( "00002384", "0002384")); ASSERT_EQUALS( 0, lexNumCmp( "0", "0")); ASSERT_EQUALS( 0, lexNumCmp( "0000", "0")); ASSERT_EQUALS( 0, lexNumCmp( "0", "000")); ASSERT_EQUALS( -1, lexNumCmp( "0000", "0.0")); ASSERT_EQUALS( 1, lexNumCmp( "2380", "238")); ASSERT_EQUALS( 1, lexNumCmp( "2385", "2384")); ASSERT_EQUALS( 1, lexNumCmp( "2385", "02384")); ASSERT_EQUALS( 1, lexNumCmp( "2385", "002384")); ASSERT_EQUALS( -1, lexNumCmp( "123.234.4567", "00238")); ASSERT_EQUALS( 0, lexNumCmp( "123.234", "00123.234")); ASSERT_EQUALS( 0, lexNumCmp( "a.123.b", "a.00123.b")); ASSERT_EQUALS( 1, lexNumCmp( "a.123.b", "a.b.00123.b")); ASSERT_EQUALS( -1, lexNumCmp( "a.00.0", "a.0.1")); ASSERT_EQUALS( 0, lexNumCmp( "01.003.02", "1.3.2")); ASSERT_EQUALS( -1, lexNumCmp( "1.3.2", "10.300.20")); ASSERT_EQUALS( 0, lexNumCmp( "10.300.20", "000000000000010.0000300.000000020")); ASSERT_EQUALS( 0, lexNumCmp( "0000a", "0a")); ASSERT_EQUALS( -1, lexNumCmp( "a", "0a")); ASSERT_EQUALS( -1, lexNumCmp( "000a", "001a")); ASSERT_EQUALS( 0, lexNumCmp( "010a", "0010a")); } }; class DatabaseValidNames { public: void run() { ASSERT( Database::validDBName( "foo" ) ); ASSERT( ! Database::validDBName( "foo/bar" ) ); ASSERT( ! Database::validDBName( "foo.bar" ) ); ASSERT( isANormalNSName( "asdads" ) ); ASSERT( ! isANormalNSName( "asda$ds" ) ); ASSERT( isANormalNSName( "local.oplog.$main" ) ); } }; class DatabaseOwnsNS { public: void run() { bool isNew = false; // this leaks as ~Database is private // if that changes, should put this on the stack Database * db = new Database( "dbtests_basictests_ownsns" , isNew ); assert( isNew ); ASSERT( db->ownsNS( "dbtests_basictests_ownsns.x" ) ); ASSERT( db->ownsNS( "dbtests_basictests_ownsns.x.y" ) ); ASSERT( ! db->ownsNS( "dbtests_basictests_ownsn.x.y" ) ); ASSERT( ! db->ownsNS( "dbtests_basictests_ownsnsa.x.y" ) ); } }; class NSValidNames { public: void run() { ASSERT( isValidNS( "test.foo" ) ); ASSERT( ! isValidNS( "test." ) ); ASSERT( ! isValidNS( "test" ) ); } }; class PtrTests { public: void run() { scoped_ptr p1 (new int(1)); boost::shared_ptr p2 (new int(2)); scoped_ptr p3 (new int(3)); boost::shared_ptr p4 (new int(4)); //non-const ASSERT_EQUALS( p1.get() , ptr(p1) ); ASSERT_EQUALS( p2.get() , ptr(p2) ); ASSERT_EQUALS( p2.get() , ptr(p2.get()) ); // T* constructor ASSERT_EQUALS( p2.get() , ptr(ptr(p2)) ); // copy constructor ASSERT_EQUALS( *p2 , *ptr(p2)); ASSERT_EQUALS( p2.get() , ptr >(&p2)->get() ); // operator-> //const ASSERT_EQUALS( p1.get() , ptr(p1) ); ASSERT_EQUALS( p2.get() , ptr(p2) ); ASSERT_EQUALS( p2.get() , ptr(p2.get()) ); ASSERT_EQUALS( p3.get() , ptr(p3) ); ASSERT_EQUALS( p4.get() , ptr(p4) ); ASSERT_EQUALS( p4.get() , ptr(p4.get()) ); ASSERT_EQUALS( p2.get() , ptr(ptr(p2)) ); ASSERT_EQUALS( p2.get() , ptr(ptr(p2)) ); // constizing copy constructor ASSERT_EQUALS( *p2 , *ptr(p2)); ASSERT_EQUALS( p2.get() , ptr >(&p2)->get() ); //bool context ASSERT( ptr(p1) ); ASSERT( !ptr(NULL) ); ASSERT( !ptr() ); #if 0 // These shouldn't compile ASSERT_EQUALS( p3.get() , ptr(p3) ); ASSERT_EQUALS( p4.get() , ptr(p4) ); ASSERT_EQUALS( p2.get() , ptr(ptr(p2)) ); #endif } }; struct StringSplitterTest { void test( string s ) { vector v = StringSplitter::split( s , "," ); ASSERT_EQUALS( s , StringSplitter::join( v , "," ) ); } void run() { test( "a" ); test( "a,b" ); test( "a,b,c" ); } }; struct IsValidUTF8Test { // macros used to get valid line numbers #define good(s) ASSERT(isValidUTF8(s)); #define bad(s) ASSERT(!isValidUTF8(s)); void run() { good("A"); good("\xC2\xA2"); // cent: ¢ good("\xE2\x82\xAC"); // euro: € good("\xF0\x9D\x90\x80"); // Blackboard A: 𝐀 //abrupt end bad("\xC2"); bad("\xE2\x82"); bad("\xF0\x9D\x90"); bad("\xC2 "); bad("\xE2\x82 "); bad("\xF0\x9D\x90 "); //too long bad("\xF8\x80\x80\x80\x80"); bad("\xFC\x80\x80\x80\x80\x80"); bad("\xFE\x80\x80\x80\x80\x80\x80"); bad("\xFF\x80\x80\x80\x80\x80\x80\x80"); bad("\xF5\x80\x80\x80"); // U+140000 > U+10FFFF bad("\x80"); //cant start with continuation byte bad("\xC0\x80"); // 2-byte version of ASCII NUL #undef good #undef bad } }; class QueueTest { public: void run() { BlockingQueue q; Timer t; int x; ASSERT( ! q.blockingPop( x , 5 ) ); ASSERT( t.seconds() > 3 && t.seconds() < 9 ); } }; class StrTests { public: void run() { ASSERT_EQUALS( 1u , str::count( "abc" , 'b' ) ); ASSERT_EQUALS( 3u , str::count( "babab" , 'b' ) ); } }; class HostAndPortTests { public: void run() { HostAndPort a( "x1" , 1000 ); HostAndPort b( "x1" , 1000 ); HostAndPort c( "x1" , 1001 ); HostAndPort d( "x2" , 1000 ); ASSERT( a == b ); ASSERT( a != c ); ASSERT( a != d ); } }; class RelativePathTest { public: void run() { RelativePath a = RelativePath::fromRelativePath( "a" ); RelativePath b = RelativePath::fromRelativePath( "a" ); RelativePath c = RelativePath::fromRelativePath( "b" ); RelativePath d = RelativePath::fromRelativePath( "a/b" ); ASSERT( a == b ); ASSERT( a != c ); ASSERT( a != d ); ASSERT( c != d ); } }; class All : public Suite { public: All() : Suite( "basic" ) { } void setupTests() { add< Rarely >(); add< Base64Tests >(); add< stringbuildertests::simple1 >(); add< stringbuildertests::simple2 >(); add< stringbuildertests::reset1 >(); add< stringbuildertests::reset2 >(); add< sleeptest >(); add< AssertTests >(); add< ArrayTests::basic1 >(); add< LexNumCmp >(); add< DatabaseValidNames >(); add< DatabaseOwnsNS >(); add< NSValidNames >(); add< PtrTests >(); add< StringSplitterTest >(); add< IsValidUTF8Test >(); add< QueueTest >(); add< StrTests >(); add< HostAndPortTests >(); add< RelativePathTest >(); } } myall; } // namespace BasicTests