3 namespace RedUNIT\Blackhole;
5 use RedUNIT\Blackhole as Blackhole;
6 use RedBeanPHP\Facade as R;
7 use RedBeanPHP\OODBBean as OODBBean;
8 use RedBeanPHP\Driver\RPDO as RPDO;
9 use RedBeanPHP\Logger\RDefault as RDefault;
10 use RedBeanPHP\RedException as RedException;
11 use RedBeanPHP\BeanHelper\SimpleFacadeBeanHelper as SimpleFacadeBeanHelper;
12 use RedBeanPHP\QueryWriter\AQueryWriter as AQueryWriter;
17 * This test suite contains tests for a various functionalities
18 * and scenarios. For more details please consult the document
19 * section attached to each individual test method listed here.
21 * @file RedUNIT/Blackhole/Misc.php
22 * @desc Tests various features that do not rely on a database connection.
23 * @author Gabor de Mooij and the RedBeanPHP Community
24 * @license New BSD/GPLv2
26 * (c) G.J.G.T. (Gabor) de Mooij and the RedBeanPHP Community.
27 * This source file is subject to the New BSD/GPLv2 License that is bundled
28 * with this source code in the file license.txt.
31 class Misc extends Blackhole
34 * What drivers should be loaded for this test pack?
36 public function getTargetDrivers()
38 return array( 'sqlite' );
42 * Test whether we can use the JSONSerializable interface and
43 * whether old-style JSON is still the same (backwards compatibility).
47 public function testJSONSerialize()
49 $hotel = R::dispense( 'hotel' );
50 $hotel->name = 'Overlook';
51 $room = R::dispense( 'room' );
53 $hotel->ownRoomList[] = $room;
54 $shine = (string) $hotel;
55 asrt( $shine, '{"id":0,"name":"Overlook"}' ); //basic JSON
56 $shine = json_encode( $hotel->jsonSerialize() ); //As of PHP 5.4 json_encode() will call jsonSerializable
57 asrt( $shine, '{"id":0,"name":"Overlook","ownRoom":[{"id":0,"number":237}]}' ); //should get full JSON
61 * Tests max parameter binding.
65 public function testIntegerBindingMax()
67 if ( defined( 'HHVM_VERSION' ) ) return; //not for hhvm...
68 $driver = new RPDO( 'test-sqlite-53', 'user', 'pass' );
69 $max = $driver->getIntegerBindingMax();
70 asrt( $max, 2147483647 );
71 $driver = new RPDO( 'cubrid', 'user', 'pass' );
72 $max = $driver->getIntegerBindingMax();
73 asrt( $max, 2147483647 );
74 $driver = new RPDO( 'other', 'user', 'pass' );
75 $max = $driver->getIntegerBindingMax();
76 asrt( $max, PHP_INT_MAX );
80 * Should not be able to pass invalid mode (must be 0 or 1).
83 public function testInvalidDebugModeException()
88 } catch ( RedException $e ) {
95 * Adding a database twice no longer allowed, causes confusion
96 * and possible damage.
98 public function testAddingTwice()
100 testpack( 'Test adding DB twice.' );
103 R::addDatabase( 'sqlite', '' );
105 } catch ( RedException $ex ) {
111 * Tests whether getID never produces a notice.
115 public function testGetIDShouldNeverPrintNotice()
117 set_error_handler(function($err, $errStr){
118 die('>>>>FAIL :'.$err.' '.$errStr);
120 $bean = new OODBBean;
122 restore_error_handler();
131 public function testSetProperty()
133 $bean = R::dispense( 'bean' );
135 $bean->ownBean = R::dispense( 'bean', 2 );
137 $bean = $bean->fresh();
139 $bean->setProperty( 'ownBean', array(), FALSE, FALSE );
140 asrt( count( $bean->ownBean ), 0 );
141 asrt( count( $bean->getMeta( 'sys.shadow.ownBean' ) ), 2 );
142 asrt( $bean->isTainted(), TRUE );
143 $bean->setProperty( 'ownBean', array(), TRUE, FALSE );
144 asrt( count( $bean->ownBean ), 0 );
145 asrt( count( $bean->getMeta( 'sys.shadow.ownBean' ) ), 0 );
146 asrt( $bean->isTainted(), TRUE );
147 $bean = $bean->fresh();
148 $bean->setProperty( 'ownBean', array(), TRUE, FALSE );
149 asrt( count( $bean->ownBean ), 0 );
150 asrt( count( $bean->getMeta( 'sys.shadow.ownBean' ) ), 0 );
151 asrt( $bean->isTainted(), FALSE );
152 $bean = $bean->fresh();
153 $bean->setProperty( 'ownBean', array(), TRUE, TRUE );
154 asrt( count( $bean->ownBean ), 0 );
155 asrt( count( $bean->getMeta( 'sys.shadow.ownBean' ) ), 0 );
156 asrt( $bean->isTainted(), TRUE );
160 * Tests beansToArray().
164 public function testBeansToArray()
166 testpack('Test R::beansToArray method');
167 $bean1 = R::dispense( 'bean' );
168 $bean1->name = 'hello';
169 $bean2 = R::dispense( 'bean' );
170 $bean2->name = 'world';
171 $beans = array( $bean1, $bean2 );
172 $array = R::beansToArray( $beans );
173 asrt( $array[0]['name'], 'hello' );
174 asrt( $array[1]['name'], 'world' );
178 * Test debugging with custom logger.
182 public function testDebugCustomLogger()
184 testpack( 'Test debug mode with custom logger' );
185 $pdoDriver = new RPDO( R::getDatabaseAdapter()->getDatabase()->getPDO() );
186 $customLogger = new CustomLogger;
187 $pdoDriver->setDebugMode( TRUE, $customLogger );
188 $pdoDriver->Execute( 'SELECT 123' );
189 asrt( count( $customLogger->getLogMessage() ), 1 );
190 $pdoDriver->setDebugMode( TRUE, NULL );
191 asrt( ( $pdoDriver->getLogger() instanceof RDefault ), TRUE );
192 testpack( 'Test bean->getProperties method' );
193 $bean = R::dispense( 'bean' );
194 $bean->property = 'hello';
195 $props = $bean->getProperties();
196 asrt( isset( $props['property'] ), TRUE );
197 asrt( $props['property'], 'hello' );
202 * Test Facade transactions.
208 public function testTransactionInFacade()
210 testpack( 'Test transaction in facade' );
211 $bean = R::dispense( 'bean' );
216 $bean = R::dispense( 'bean' );
219 asrt( R::count( 'bean' ), 1 );
221 asrt( R::count( 'bean' ), 0 );
222 $bean = R::dispense( 'bean' );
224 $id = R::transaction( function() use( &$bean ) {
225 return R::transaction( function() use( &$bean ) {
226 return R::store( $bean );
229 asrt( (int) $id, (int) $bean->id );
231 $bean = R::dispense( 'bean' );
233 $id = R::transaction( function() use( &$bean ) {
234 return R::store( $bean );
236 asrt( (int) $id, (int) $bean->id );
238 $bean = R::dispense( 'bean' );
241 R::transaction( function () use ( $bean ) {
243 R::transaction( function () {
244 throw new\Exception();
247 } catch (\Exception $e ) {
250 asrt( R::count( 'bean' ), 0 );
251 $bean = R::dispense( 'bean' );
254 R::transaction( function () use ( $bean ) {
255 R::transaction( function () use ( $bean ) {
257 throw new\Exception();
260 } catch (\Exception $e ) {
263 asrt( R::count( 'bean' ), 0 );
264 $bean = R::dispense( 'bean' );
267 R::transaction( function () use ( $bean ) {
268 R::transaction( function () use ( $bean ) {
272 } catch (\Exception $e ) {
275 asrt( R::count( 'bean' ), 1 );
278 R::transaction( 'nope' );
280 } catch (\Exception $e ) {
283 testpack( 'Test Camelcase 2 underscore' );
285 'oneACLRoute' => 'one_acl_route',
286 'ALLUPPERCASE' => 'alluppercase',
287 'clientServerArchitecture' => 'client_server_architecture',
288 'camelCase' => 'camel_case',
289 'peer2peer' => 'peer2peer',
290 'fromUs4You' => 'from_us4_you',
291 'lowercase' => 'lowercase',
294 $bean = R::dispense( 'bean' );
295 foreach ( $names as $name => $becomes ) {
297 asrt( isset( $bean->$becomes ), TRUE );
299 testpack( 'Misc Tests' );
303 R::exec( 'SELECT 123' );
304 $out = ob_get_contents();
308 asrt( ( strpos( $out, 'SELECT 123' ) !== FALSE ), TRUE );
312 R::exec( 'SELECT 123' );
313 $out = ob_get_contents();
320 testpack( 'test to string override' );
321 $band = R::dispense( 'band' );
322 $str = strval( $band );
323 asrt( $str, 'bigband' );
324 testpack( 'test whether we can use isset/set in model' );
325 $band->setProperty( 'property1', 123 );
326 asrt( $band->property1, 123 );
327 asrt( $band->checkProperty( 'property1' ), TRUE );
328 asrt( $band->checkProperty( 'property2' ), FALSE );
329 $band = new \Model_Band;
330 $bean = R::dispense( 'band' );
331 $bean->property3 = 123;
332 $band->loadBean( $bean );
333 $bean->property4 = 345;
334 $band->setProperty( 'property1', 123 );
335 asrt( $band->property1, 123 );
336 asrt( $band->checkProperty( 'property1' ), TRUE );
337 asrt( $band->checkProperty( 'property2' ), FALSE );
338 asrt( $band->property3, 123 );
339 asrt( $band->property4, 345 );
340 testpack( 'Can we pass a\PDO object to Setup?' );
341 $pdo = new \PDO( 'sqlite:test.db' );
342 R::addDatabase( 'pdo', $pdo );
343 R::selectDatabase( 'pdo' );
344 R::getCell('SELECT 123;');
345 testpack( 'Test array interface of beans' );
346 $bean = R::dispense( 'bean' );
348 $bean->world = 'planet';
349 asrt( $bean['hello'], 'hi' );
350 asrt( isset( $bean['hello'] ), TRUE );
351 asrt( isset( $bean['bye'] ), FALSE );
352 $bean['world'] = 'sphere';
353 asrt( $bean->world, 'sphere' );
354 foreach ( $bean as $key => $el ) {
355 if ( $el == 'sphere' || $el == 'hi' || $el == 0 ) {
360 if ( $key == 'hello' || $key == 'world' || $key == 'id' ) {
366 asrt( count( $bean ), 3 );
367 unset( $bean['hello'] );
368 asrt( count( $bean ), 2 );
369 asrt( count( R::dispense( 'countable' ) ), 1 );
370 // Otherwise untestable...
371 $bean->setBeanHelper( new SimpleFacadeBeanHelper() );
372 R::getRedBean()->setBeanHelper( new SimpleFacadeBeanHelper() );
374 // Test whether properties like owner and shareditem are still possible
375 testpack( 'Test Bean Interface for Lists' );
376 $bean = R::dispense( 'bean' );
377 // Must not be list, because first char after own is lowercase
378 asrt( is_array( $bean->owner ), FALSE );
379 // Must not be list, because first char after shared is lowercase
380 asrt( is_array( $bean->shareditem ), FALSE );
381 asrt( is_array( $bean->own ), FALSE );
382 asrt( is_array( $bean->shared ), FALSE );
383 asrt( is_array( $bean->own_item ), FALSE );
384 asrt( is_array( $bean->shared_item ), FALSE );
385 asrt( is_array( $bean->{'own item'} ), FALSE );
386 asrt( is_array( $bean->{'shared Item'} ), FALSE );
389 public function testConv2Beans()
391 $row1 = array('id' => 1, 'title'=>'test');
392 $row2 = array('id' => 2, 'title'=>'test2');
393 $beans = R::convertToBeans('page', array($row1, $row2));
394 asrt(count($beans), 2);
395 asrt($beans[2]->title, 'test2');
399 * Test the most important invalid bean combinations.
403 public function testInvalidType()
406 'book_page', //no link beans
409 'bean@', //no invalid symbols
410 'bean#', //no invalid symbols
411 'bean$', //sometimes used in DB, not allowed
412 '__bean',//no prefixes
413 '.bean', //no object notation
414 'bean-item', //no dash
415 'beanOther'); //no camelcase (uppercase because of file system issues)
417 foreach( $invalid as $j ) {
421 } catch( RedException $e ) {
428 * Test whether batch still works if no IDs have been passed.
432 public function testBatch0()
434 $zero = R::batch( 'page', array() );
435 asrt( is_array( $zero ), TRUE );
436 asrt( count( $zero ), 0 );
437 $zero = R::batch( 'page', FALSE );
438 asrt( is_array( $zero ), TRUE );
439 asrt( count( $zero ), 0 );
440 $zero = R::batch( 'page', NULL);
441 asrt( is_array( $zero ), TRUE );
442 asrt( count( $zero ), 0 );
446 * Test whether connection failure does not reveal
451 public function testConnect()
453 $driver = new RPDO( 'dsn:invalid', 'usr', 'psst' );
458 catch( \PDOException $e ) {
459 asrt( strpos( $e->getMessage(), 'invalid' ), FALSE );
460 asrt( strpos( $e->getMessage(), 'usr' ), FALSE );
461 asrt( strpos( $e->getMessage(), 'psst' ), FALSE );
466 * Test whether we can create an instant database using
469 * Probably only works on *NIX systems.
473 public function testSetup()
475 $tmpDir = sys_get_temp_dir();
480 * Test camelCase to snake_case conversions.
484 public function testCamel2Snake()
486 asrt( AQueryWriter::camelsSnake('bookPage'), 'book_page' );
487 asrt( AQueryWriter::camelsSnake('FTP'), 'ftp' );
488 asrt( AQueryWriter::camelsSnake('ACLRules'), 'acl_rules' );
489 asrt( AQueryWriter::camelsSnake('SSHConnectionProxy'), 'ssh_connection_proxy' );
490 asrt( AQueryWriter::camelsSnake('proxyServerFacade'), 'proxy_server_facade' );
491 asrt( AQueryWriter::camelsSnake('proxySSHClient'), 'proxy_ssh_client' );
492 asrt( AQueryWriter::camelsSnake('objectACL2Factory'), 'object_acl2_factory' );
493 asrt( AQueryWriter::camelsSnake('bookItems4Page'), 'book_items4_page' );
494 asrt( AQueryWriter::camelsSnake('book☀Items4Page'), 'book☀_items4_page' );
499 * Custom Logger class.
500 * For testing purposes.
502 class CustomLogger extends RDefault
507 public function getLogMessage()
512 public function log()
514 $this->log = func_get_args();