1<?php 2// +----------------------------------------------------------------------+ 3// | PHP versions 4 and 5 | 4// +----------------------------------------------------------------------+ 5// | Copyright (c) 1998-2008 Manuel Lemos, Paul Cooper, Lorenzo Alberton | 6// | All rights reserved. | 7// +----------------------------------------------------------------------+ 8// | MDB2 is a merge of PEAR DB and Metabases that provides a unified DB | 9// | API as well as database abstraction for PHP applications. | 10// | This LICENSE is in the BSD license style. | 11// | | 12// | Redistribution and use in source and binary forms, with or without | 13// | modification, are permitted provided that the following conditions | 14// | are met: | 15// | | 16// | Redistributions of source code must retain the above copyright | 17// | notice, this list of conditions and the following disclaimer. | 18// | | 19// | Redistributions in binary form must reproduce the above copyright | 20// | notice, this list of conditions and the following disclaimer in the | 21// | documentation and/or other materials provided with the distribution. | 22// | | 23// | Neither the name of Manuel Lemos, Tomas V.V.Cox, Stig. S. Bakken, | 24// | Lukas Smith nor the names of his contributors may be used to endorse | 25// | or promote products derived from this software without specific prior| 26// | written permission. | 27// | | 28// | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | 29// | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | 30// | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS | 31// | FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE | 32// | REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, | 33// | INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, | 34// | BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS| 35// | OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED | 36// | AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | 37// | LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY| 38// | WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE | 39// | POSSIBILITY OF SUCH DAMAGE. | 40// +----------------------------------------------------------------------+ 41// | Authors: Paul Cooper <pgc@ucecom.com> | 42// | Lorenzo Alberton <l dot alberton at quipo dot it> | 43// | Daniel Convissor <danielc@php.net> | 44// +----------------------------------------------------------------------+ 45// 46// $Id: ManagerTest.php 327313 2012-08-27 15:16:42Z danielc $ 47 48require_once dirname(__DIR__) . '/autoload.inc'; 49 50class Standard_ManagerTest extends Standard_Abstract { 51 //test table name (it is dynamically created/dropped) 52 public $table = 'newtable'; 53 54 /** 55 * The non-standard helper 56 * @var Nonstandard_Base 57 */ 58 protected $nonstd; 59 60 61 /** 62 * Can not use setUp() because we are using a dataProvider to get multiple 63 * MDB2 objects per test. 64 * 65 * @param array $ci an associative array with two elements. The "dsn" 66 * element must contain an array of DSN information. 67 * The "options" element must be an array of connection 68 * options. 69 */ 70 protected function manualSetUp($ci) { 71 parent::manualSetUp($ci); 72 73 $this->nonstd = Nonstandard_Base::factory($this->db, $this); 74 75 $this->db->loadModule('Manager', null, true); 76 $this->fields = array( 77 'id' => array( 78 'type' => 'integer', 79 'unsigned' => true, 80 'notnull' => true, 81 'default' => 0, 82 ), 83 'somename' => array( 84 'type' => 'text', 85 'length' => 12, 86 ), 87 'somedescription' => array( 88 'type' => 'text', 89 'length' => 12, 90 ), 91 'sex' => array( 92 'type' => 'text', 93 'length' => 1, 94 'default' => 'M', 95 ), 96 ); 97 $options = array(); 98 if ('mysql' == substr($this->db->phptype, 0, 5)) { 99 $options['type'] = 'innodb'; 100 } 101 if (!$this->tableExists($this->table)) { 102 $result = $this->db->manager->createTable($this->table, $this->fields, $options); 103 $this->checkResultForErrors($result, 'createTable'); 104 } 105 } 106 107 public function tearDown() { 108 if (!$this->db || MDB2::isError($this->db)) { 109 return; 110 } 111 if ($this->tableExists($this->table)) { 112 $this->db->manager->dropTable($this->table); 113 } 114 parent::tearDown(); 115 } 116 117 /** 118 * @covers MDB2_Driver_Manager_Common::createTable() 119 * @covers MDB2_Driver_Manager_Common::listTables() 120 * @covers MDB2_Driver_Manager_Common::dropTable() 121 * @dataProvider provider 122 */ 123 public function testTableActions($ci) { 124 $this->manualSetUp($ci); 125 126 // Make sure it doesn't exist before trying to create it. 127 if ($this->methodExists($this->db->manager, 'dropTable')) { 128 $this->db->manager->dropTable($this->table); 129 } else { 130 $this->db->exec("DROP TABLE $this->table"); 131 } 132 133 $action = 'createTable'; 134 if (!$this->methodExists($this->db->manager, $action)) { 135 $this->markTestSkipped("Driver lacks $action() method"); 136 } 137 $result = $this->db->manager->createTable($this->table, $this->fields); 138 $this->checkResultForErrors($result, $action); 139 $this->assertEquals(MDB2_OK, $result, 140 "$action did not return MDB2_OK"); 141 142 $action = 'listTables'; 143 if ($this->methodExists($this->db->manager, $action)) { 144 $result = $this->db->manager->listTables(); 145 $this->checkResultForErrors($result, $action); 146 $this->assertContains($this->table, $result, 147 "Result of $action() does not contain expected value"); 148 } 149 150 $action = 'dropTable'; 151 if (!$this->methodExists($this->db->manager, $action)) { 152 $this->db->exec("DROP TABLE $this->table"); 153 $this->markTestSkipped("Driver lacks $action() method"); 154 } 155 $result = $this->db->manager->dropTable($this->table); 156 $this->checkResultForErrors($result, $action); 157 $this->assertEquals(MDB2_OK, $result, 158 "$action did not return MDB2_OK"); 159 160 // Check that it's actually gone. 161 if ($this->tableExists($this->table)) { 162 $this->fail("dropTable() passed but the table still exists"); 163 } 164 } 165 166 /** 167 * Create a sample table, test the new fields, and drop it. 168 * @dataProvider provider 169 */ 170 public function testCreateAutoIncrementTable($ci) { 171 $this->manualSetUp($ci); 172 173 if (!$this->methodExists($this->db->manager, 'createTable')) { 174 $this->markTestSkipped("Driver lacks createTable() method"); 175 } 176 if ($this->tableExists($this->table)) { 177 $this->db->manager->dropTable($this->table); 178 } 179 $seq_name = $this->table; 180 if ('ibase' == $this->db->phptype) { 181 $seq_name .= '_id'; 182 } 183 //remove existing PK sequence 184 $sequences = $this->db->manager->listSequences(); 185 if (in_array($seq_name, $sequences)) { 186 $this->db->manager->dropSequence($seq_name); 187 } 188 189 $action = 'createTable'; 190 $fields = $this->fields; 191 $fields['id']['autoincrement'] = true; 192 $result = $this->db->manager->createTable($this->table, $fields); 193 $this->checkResultForErrors($result, $action); 194 $this->assertEquals(MDB2_OK, $result, 195 "$action did not return MDB2_OK"); 196 197 $query = 'INSERT INTO '.$this->db->quoteIdentifier($this->table, true); 198 $query.= ' (somename, somedescription)'; 199 $query.= ' VALUES (:somename, :somedescription)'; 200 $stmt = $this->db->prepare($query, array('text', 'text'), MDB2_PREPARE_MANIP); 201 $this->checkResultForErrors($stmt, 'prepare'); 202 203 $values = array( 204 'somename' => 'foo', 205 'somedescription' => 'bar', 206 ); 207 $rows = 5; 208 for ($i =0; $i < $rows; ++$i) { 209 $result = $stmt->execute($values); 210 $this->checkResultForErrors($result, 'execute'); 211 } 212 $stmt->free(); 213 214 $query = 'SELECT id FROM '.$this->table; 215 $data = $this->db->queryCol($query, 'integer'); 216 $this->checkResultForErrors($data, 'queryCol'); 217 for ($i=0; $i<$rows; ++$i) { 218 if (!isset($data[$i])) { 219 $this->fail('Error in data returned by select'); 220 } 221 if ($data[$i] !== ($i+1)) { 222 $this->fail('Error executing autoincrementing insert'); 223 } 224 } 225 } 226 227 /** 228 * @dataProvider provider 229 */ 230 public function testListTableFields($ci) { 231 $this->manualSetUp($ci); 232 233 if (!$this->methodExists($this->db->manager, 'listTableFields')) { 234 $this->markTestSkipped("Driver lacks listTableFields() method"); 235 } 236 $this->assertEquals( 237 array_keys($this->fields), 238 $this->db->manager->listTableFields($this->table), 239 'Error creating table: incorrect fields' 240 ); 241 } 242 243 /** 244 * @covers MDB2_Driver_Manager_Common::createIndex() 245 * @covers MDB2_Driver_Manager_Common::listTableIndexes() 246 * @covers MDB2_Driver_Manager_Common::dropIndex() 247 * @dataProvider provider 248 */ 249 public function testIndexActions($ci) { 250 $this->manualSetUp($ci); 251 252 $index = array( 253 'fields' => array( 254 'somename' => array( 255 'sorting' => 'ascending', 256 ), 257 ), 258 ); 259 $name = 'simpleindex'; 260 261 $action = 'createIndex'; 262 if (!$this->methodExists($this->db->manager, $action)) { 263 $this->markTestSkipped("Driver lacks $action() method"); 264 } 265 $result = $this->db->manager->createIndex($this->table, $name, $index); 266 $this->checkResultForErrors($result, $action); 267 $this->assertEquals(MDB2_OK, $result, 268 "$action did not return MDB2_OK"); 269 270 $action = 'listTableIndexes'; 271 if ($this->methodExists($this->db->manager, $action)) { 272 $result = $this->db->manager->listTableIndexes($this->table); 273 $this->checkResultForErrors($result, $action); 274 $this->assertContains($name, $result, 275 "Result of $action() does not contain expected value"); 276 } 277 278 $action = 'dropIndex'; 279 if (!$this->methodExists($this->db->manager, $action)) { 280 $this->markTestSkipped("Driver lacks $action() method"); 281 } 282 $result = $this->db->manager->dropIndex($this->table, $name); 283 $this->checkResultForErrors($result, $action); 284 $this->assertEquals(MDB2_OK, $result, 285 "$action did not return MDB2_OK"); 286 287 // Check that it's actually gone. 288 $action = 'listTableIndexes'; 289 if ($this->methodExists($this->db->manager, $action)) { 290 $result = $this->db->manager->listTableIndexes($this->table); 291 $this->checkResultForErrors($result, $action); 292 $this->assertNotContains($name, $result, 293 "dropIndex() passed but the index is still there"); 294 } 295 } 296 297 /** 298 * @dataProvider provider 299 */ 300 public function testCreatePrimaryKey($ci) { 301 $this->manualSetUp($ci); 302 303 if (!$this->methodExists($this->db->manager, 'createConstraint')) { 304 $this->markTestSkipped("Driver lacks createConstraint() method"); 305 } 306 $constraint = array( 307 'fields' => array( 308 'id' => array( 309 'sorting' => 'ascending', 310 ), 311 ), 312 'primary' => true, 313 ); 314 $name = 'pkindex'; 315 316 $action = 'createConstraint'; 317 if (!$this->methodExists($this->db->manager, $action)) { 318 $this->markTestSkipped("Driver lacks $action() method"); 319 } 320 $result = $this->db->manager->createConstraint($this->table, $name, $constraint); 321 $this->checkResultForErrors($result, $action); 322 $this->assertEquals(MDB2_OK, $result, 323 "$action did not return MDB2_OK"); 324 } 325 326 /** 327 * @covers MDB2_Driver_Manager_Common::createConstraint() 328 * @covers MDB2_Driver_Manager_Common::listTableConstraints() 329 * @covers MDB2_Driver_Manager_Common::dropConstraint() 330 * @dataProvider provider 331 */ 332 public function testConstraintActions($ci) { 333 $this->manualSetUp($ci); 334 335 $constraint = array( 336 'fields' => array( 337 'id' => array( 338 'sorting' => 'ascending', 339 ), 340 ), 341 'unique' => true, 342 ); 343 $name = 'uniqueindex'; 344 345 $action = 'createConstraint'; 346 if (!$this->methodExists($this->db->manager, $action)) { 347 $this->markTestSkipped("Driver lacks $action() method"); 348 } 349 // Make sure it doesn't exist before trying to create it. 350 $this->db->manager->dropConstraint($this->table, $name); 351 $result = $this->db->manager->createConstraint($this->table, $name, $constraint); 352 $this->checkResultForErrors($result, $action); 353 $this->assertEquals(MDB2_OK, $result, 354 "$action did not return MDB2_OK"); 355 356 $action = 'listTableConstraints'; 357 $result = $this->db->manager->listTableConstraints($this->table); 358 $this->checkResultForErrors($result, $action); 359 $this->assertContains($name, $result, 360 "Result of $action() does not contain expected value"); 361 362 $action = 'dropConstraint'; 363 $result = $this->db->manager->dropConstraint($this->table, $name); 364 $this->checkResultForErrors($result, $action); 365 $this->assertEquals(MDB2_OK, $result, 366 "$action did not return MDB2_OK"); 367 368 // Check that it's actually gone. 369 $action = 'listTableConstraints'; 370 $result = $this->db->manager->listTableConstraints($this->table); 371 $this->checkResultForErrors($result, $action); 372 $this->assertNotContains($name, $result, 373 "dropConstraint() passed but the constraint is still there"); 374 } 375 376 /** 377 * MYSQL NOTE: If this test fails with native code 1005 378 * "Can't create table './peartest/#sql-540_2c871.frm' (errno: 150)" 379 * that means your server's default storage engine is MyISAM. 380 * Edit my.cnf to have "default-storage-engine = InnoDB" 381 * 382 * @dataProvider provider 383 */ 384 public function testCreateForeignKeyConstraint($ci) { 385 $this->manualSetUp($ci); 386 387 $constraint = array( 388 'fields' => array( 389 'id' => array( 390 'sorting' => 'ascending', 391 ), 392 ), 393 'foreign' => true, 394 'references' => array( 395 'table' => $this->table_users, 396 'fields' => array( 397 'user_id' => array( 398 'position' => 1, 399 ), 400 ), 401 ), 402 'initiallydeferred' => false, 403 'deferrable' => false, 404 'match' => 'SIMPLE', 405 'onupdate' => 'CASCADE', 406 'ondelete' => 'CASCADE', 407 ); 408 409 $name = 'fkconstraint'; 410 411 $action = 'createConstraint'; 412 if (!$this->methodExists($this->db->manager, $action)) { 413 $this->markTestSkipped("Driver lacks $action() method"); 414 } 415 // Make sure it doesn't exist before trying to create it. 416 $this->db->manager->dropConstraint($this->table, $name); 417 $result = $this->db->manager->createConstraint($this->table, $name, $constraint); 418 $this->checkResultForErrors($result, $action); 419 $this->assertEquals(MDB2_OK, $result, 420 "$action did not return MDB2_OK"); 421 422 $action = 'listTableConstraints'; 423 $result = $this->db->manager->listTableConstraints($this->table); 424 $this->checkResultForErrors($result, $action); 425 $name_idx = $this->db->getIndexName($name); 426 $this->checkResultForErrors($name_idx, 'getIndexName'); 427 $this->assertTrue(in_array($name_idx, $result) 428 || in_array($name, $result), 429 "Result of $action() does not contain expected value"); 430 431 432 //now check that it is enforced... 433 434 //insert a row in the primary table 435 $result = $this->db->exec('INSERT INTO ' . $this->table_users . ' (user_id) VALUES (1)'); 436 $this->checkResultForErrors($result, 'exec'); 437 438 //insert a row in the FK table with an id that references 439 //the newly inserted row on the primary table: should not fail 440 $query = 'INSERT INTO '.$this->db->quoteIdentifier($this->table, true) 441 .' ('.$this->db->quoteIdentifier('id', true).') VALUES (1)'; 442 $result = $this->db->exec($query); 443 $this->checkResultForErrors($result, 'exec'); 444 445 //try to insert a row into the FK table with an id that does not 446 //exist in the primary table: should fail 447 $query = 'INSERT INTO '.$this->db->quoteIdentifier($this->table, true) 448 .' ('.$this->db->quoteIdentifier('id', true).') VALUES (123456)'; 449 $this->db->pushErrorHandling(PEAR_ERROR_RETURN); 450 $this->db->expectError('*'); 451 $result = $this->db->exec($query); 452 $this->db->popExpect(); 453 $this->db->popErrorHandling(); 454 $this->assertInstanceOf('MDB2_Error', $result, 455 'Foreign Key constraint was not enforced for INSERT query'); 456 $this->assertEquals(MDB2_ERROR_CONSTRAINT, $result->getCode(), 457 "Wrong error code. See full output for clues.\n" 458 . $result->getUserInfo()); 459 460 //try to update the first row of the FK table with an id that does not 461 //exist in the primary table: should fail 462 $query = 'UPDATE '.$this->db->quoteIdentifier($this->table, true) 463 .' SET '.$this->db->quoteIdentifier('id', true).' = 123456 ' 464 .' WHERE '.$this->db->quoteIdentifier('id', true).' = 1'; 465 $this->db->expectError('*'); 466 $result = $this->db->exec($query); 467 $this->db->popExpect(); 468 $this->assertInstanceOf('MDB2_Error', $result, 469 'Foreign Key constraint was not enforced for UPDATE query'); 470 $this->assertEquals(MDB2_ERROR_CONSTRAINT, $result->getCode(), 471 "Wrong error code. See full output for clues.\n" 472 . $result->getUserInfo()); 473 474 $numrows_query = 'SELECT COUNT(*) FROM '. $this->db->quoteIdentifier($this->table, true); 475 $numrows = $this->db->queryOne($numrows_query, 'integer'); 476 $this->assertEquals(1, $numrows, 'Invalid number of rows in the FK table'); 477 478 //update the PK value of the primary table: the new value should be 479 //propagated to the FK table (ON UPDATE CASCADE) 480 $result = $this->db->exec('UPDATE ' . $this->table_users . ' SET user_id = 2'); 481 $this->checkResultForErrors($result, 'exec'); 482 483 $numrows = $this->db->queryOne($numrows_query, 'integer'); 484 $this->assertEquals(1, $numrows, 'Invalid number of rows in the FK table'); 485 486 $query = 'SELECT id FROM '.$this->db->quoteIdentifier($this->table, true); 487 $newvalue = $this->db->queryOne($query, 'integer'); 488 $this->assertEquals(2, $newvalue, 'The value of the FK field was not updated (CASCADE failed)'); 489 490 //delete the row of the primary table: the row in the FK table should be 491 //deleted automatically (ON DELETE CASCADE) 492 $result = $this->db->exec('DELETE FROM ' . $this->table_users); 493 $this->checkResultForErrors($result, 'exec'); 494 495 $numrows = $this->db->queryOne($numrows_query, 'integer'); 496 $this->assertEquals(0, $numrows, 'Invalid number of rows in the FK table (CASCADE failed)'); 497 498 499 $action = 'dropConstraint'; 500 $result = $this->db->manager->dropConstraint($this->table, $name); 501 $this->checkResultForErrors($result, $action); 502 $this->assertEquals(MDB2_OK, $result, 503 "$action did not return MDB2_OK"); 504 } 505 506 /** 507 * @dataProvider provider 508 */ 509 public function testDropPrimaryKey($ci) { 510 $this->manualSetUp($ci); 511 512 if (!$this->methodExists($this->db->manager, 'dropConstraint')) { 513 $this->markTestSkipped("Driver lacks dropConstraint() method"); 514 } 515 $index = array( 516 'fields' => array( 517 'id' => array( 518 'sorting' => 'ascending', 519 ), 520 ), 521 'primary' => true, 522 ); 523 $name = 'pkindex'; 524 525 $action = 'createConstraint'; 526 $result = $this->db->manager->createConstraint($this->table, $name, $index); 527 $this->checkResultForErrors($result, $action); 528 $this->assertEquals(MDB2_OK, $result, 529 "$action did not return MDB2_OK"); 530 531 $action = 'dropConstraint'; 532 $result = $this->db->manager->dropConstraint($this->table, $name, true); 533 $this->checkResultForErrors($result, $action); 534 $this->assertEquals(MDB2_OK, $result, 535 "$action did not return MDB2_OK"); 536 } 537 538 /** 539 * @dataProvider provider 540 */ 541 public function testListDatabases($ci) { 542 $this->manualSetUp($ci); 543 544 $action = 'listDatabases'; 545 if (!$this->methodExists($this->db->manager, $action)) { 546 $this->markTestSkipped("Driver lacks $action() method"); 547 } 548 $result = $this->db->manager->listDatabases(); 549 $this->checkResultForErrors($result, $action); 550 $this->assertTrue(in_array(strtolower($this->database), $result), 'Error listing databases'); 551 } 552 553 /** 554 * @dataProvider provider 555 */ 556 public function testAlterTable($ci) { 557 $this->manualSetUp($ci); 558 559 $newer = 'newertable'; 560 if ($this->tableExists($newer)) { 561 $this->db->manager->dropTable($newer); 562 } 563 $changes = array( 564 'add' => array( 565 'quota' => array( 566 'type' => 'integer', 567 'unsigned' => 1, 568 ), 569 'note' => array( 570 'type' => 'text', 571 'length' => '20', 572 ), 573 ), 574 'rename' => array( 575 'sex' => array( 576 'name' => 'gender', 577 'definition' => array( 578 'type' => 'text', 579 'length' => 1, 580 'default' => 'M', 581 ), 582 ), 583 ), 584 'change' => array( 585 'id' => array( 586 'unsigned' => false, 587 'definition' => array( 588 'type' => 'integer', 589 'notnull' => false, 590 'default' => 0, 591 ), 592 ), 593 'somename' => array( 594 'length' => '20', 595 'definition' => array( 596 'type' => 'text', 597 'length' => 20, 598 ), 599 ) 600 ), 601 'remove' => array( 602 'somedescription' => array(), 603 ), 604 'name' => $newer, 605 ); 606 607 $action = 'alterTable'; 608 if (!$this->methodExists($this->db->manager, $action)) { 609 $this->markTestSkipped("Driver lacks $action() method"); 610 } 611 $this->db->expectError(MDB2_ERROR_CANNOT_ALTER); 612 $result = $this->db->manager->alterTable($this->table, $changes, true); 613 $this->db->popExpect(); 614 $this->checkResultForErrors($result, $action); 615 $this->assertEquals(MDB2_OK, $result, 616 "$action did not return MDB2_OK"); 617 618 $result = $this->db->manager->alterTable($this->table, $changes, false); 619 $this->checkResultForErrors($result, $action); 620 $this->assertEquals(MDB2_OK, $result, 621 "$action did not return MDB2_OK"); 622 } 623 624 /** 625 * @dataProvider provider 626 */ 627 public function testAlterTable2($ci) { 628 $this->manualSetUp($ci); 629 630 $newer = 'newertable2'; 631 if ($this->tableExists($newer)) { 632 $this->db->manager->dropTable($newer); 633 } 634 $changes_all = array( 635 'add' => array( 636 'quota' => array( 637 'type' => 'integer', 638 'unsigned' => 1, 639 ), 640 ), 641 'rename' => array( 642 'sex' => array( 643 'name' => 'gender', 644 'definition' => array( 645 'type' => 'text', 646 'length' => 1, 647 'default' => 'M', 648 ), 649 ), 650 ), 651 'change' => array( 652 'somename' => array( 653 'length' => '20', 654 'definition' => array( 655 'type' => 'text', 656 'length' => 20, 657 ), 658 ) 659 ), 660 'remove' => array( 661 'somedescription' => array(), 662 ), 663 'name' => $newer, 664 ); 665 666 $action = 'alterTable'; 667 if (!$this->methodExists($this->db->manager, $action)) { 668 $this->markTestSkipped("Driver lacks $action() method"); 669 } 670 671 foreach ($changes_all as $type => $change) { 672 $changes = array($type => $change); 673 $this->db->expectError(MDB2_ERROR_CANNOT_ALTER); 674 $result = $this->db->manager->alterTable($this->table, $changes, true); 675 $this->db->popExpect(); 676 $this->checkResultForErrors($result, $action); 677 $this->assertEquals(MDB2_OK, $result, 678 "$action did not return MDB2_OK"); 679 680 $result = $this->db->manager->alterTable($this->table, $changes, false); 681 $this->checkResultForErrors($result, $action); 682 $this->assertEquals(MDB2_OK, $result, 683 "$action did not return MDB2_OK"); 684 685 switch ($type) { 686 case 'add': 687 $altered_table_fields = $this->db->manager->listTableFields($this->table); 688 $this->checkResultForErrors($altered_table_fields, 'listTableFields'); 689 foreach ($change as $newfield => $dummy) { 690 $this->assertContains($newfield, $altered_table_fields, 691 "Field '$newfield' was not added"); 692 } 693 break; 694 case 'rename': 695 $altered_table_fields = $this->db->manager->listTableFields($this->table); 696 $this->checkResultForErrors($altered_table_fields, 'listTableFields'); 697 foreach ($change as $oldfield => $newfield) { 698 $this->assertNotContains($oldfield, $altered_table_fields, 699 "Field '$oldfield' was not renamed"); 700 701 $this->assertContains($newfield['name'], $altered_table_fields, 702 "While '$oldfield' is gone, '{$newfield['name']}' is not there"); 703 } 704 break; 705 case 'change': 706 break; 707 case 'remove': 708 $altered_table_fields = $this->db->manager->listTableFields($this->table); 709 $this->checkResultForErrors($altered_table_fields, 'listTableFields'); 710 foreach ($change as $newfield => $dummy) { 711 $this->assertNotContains($newfield, $altered_table_fields, 712 "Field '$oldfield' was not removed"); 713 } 714 break; 715 case 'name': 716 if ($this->tableExists($newer)) { 717 $this->db->manager->dropTable($newer); 718 } else { 719 $this->fail('Error: table "'.$this->table.'" not renamed'); 720 } 721 break; 722 } 723 } 724 } 725 726 /** 727 * @dataProvider provider 728 */ 729 public function testTruncateTable($ci) { 730 $this->manualSetUp($ci); 731 732 if (!$this->methodExists($this->db->manager, 'truncateTable')) { 733 $this->markTestSkipped("Driver lacks truncateTable() method"); 734 } 735 736 $query = 'INSERT INTO '.$this->table; 737 $query.= ' (id, somename, somedescription)'; 738 $query.= ' VALUES (:id, :somename, :somedescription)'; 739 $stmt = $this->db->prepare($query, array('integer', 'text', 'text'), MDB2_PREPARE_MANIP); 740 $this->checkResultForErrors($stmt, 'prepare'); 741 742 $rows = 5; 743 for ($i=1; $i<=$rows; ++$i) { 744 $values = array( 745 'id' => $i, 746 'somename' => 'foo'.$i, 747 'somedescription' => 'bar'.$i, 748 ); 749 $result = $stmt->execute($values); 750 $this->checkResultForErrors($result, 'execute'); 751 } 752 $stmt->free(); 753 $count = $this->db->queryOne('SELECT COUNT(*) FROM '.$this->table, 'integer'); 754 $this->checkResultForErrors($count, 'queryOne'); 755 $this->assertEquals($rows, $count, 'Error: invalid number of rows returned'); 756 757 $action = 'truncateTable'; 758 $result = $this->db->manager->truncateTable($this->table); 759 $this->checkResultForErrors($result, $action); 760 $this->assertEquals(MDB2_OK, $result, 761 "$action did not return MDB2_OK"); 762 763 $count = $this->db->queryOne('SELECT COUNT(*) FROM '.$this->table, 'integer'); 764 $this->checkResultForErrors($count, 'queryOne'); 765 $this->assertEquals(0, $count, 'Error: invalid number of rows returned'); 766 } 767 768 /** 769 * @dataProvider provider 770 */ 771 public function testListTablesNoTable($ci) { 772 $this->manualSetUp($ci); 773 774 if (!$this->methodExists($this->db->manager, 'listTables')) { 775 $this->markTestSkipped("Driver lacks listTables() method"); 776 } 777 $result = $this->db->manager->dropTable($this->table); 778 $this->assertFalse($this->tableExists($this->table), 'Error listing tables'); 779 } 780 781 /** 782 * @covers MDB2_Driver_Manager_Common::createSequence() 783 * @covers MDB2_Driver_Manager_Common::listSequences() 784 * @covers MDB2_Driver_Manager_Common::dropSequence() 785 * @dataProvider provider 786 */ 787 public function testSequences($ci) { 788 $this->manualSetUp($ci); 789 790 $name = 'testsequence'; 791 792 $action = 'createSequence'; 793 if (!$this->methodExists($this->db->manager, $action)) { 794 $this->markTestSkipped("Driver lacks $action() method"); 795 } 796 // Make sure it doesn't exist before trying to create it. 797 $this->db->manager->dropSequence($name); 798 $result = $this->db->manager->createSequence($name); 799 $this->checkResultForErrors($result, $action); 800 $this->assertEquals(MDB2_OK, $result, 801 "$action did not return MDB2_OK"); 802 803 $action = 'listSequences'; 804 $result = $this->db->manager->listSequences(); 805 $this->checkResultForErrors($result, $action); 806 $this->assertContains($name, $result, 807 "Result of $action() does not contain expected value"); 808 809 $action = 'dropSequence'; 810 $result = $this->db->manager->dropSequence($name); 811 $this->checkResultForErrors($result, $action); 812 $this->assertEquals(MDB2_OK, $result, 813 "$action did not return MDB2_OK"); 814 815 // Check that it's actually gone. 816 $action = 'listSequences'; 817 $result = $this->db->manager->listSequences(); 818 $this->checkResultForErrors($result, $action); 819 $this->assertNotContains($name, $result, 820 "dropSequence() passed but the sequence is still there"); 821 } 822 823 /** 824 * @covers MDB2_Driver_Manager_Common::listTableTriggers() 825 * @dataProvider provider 826 */ 827 public function testListTableTriggers($ci) { 828 $this->manualSetUp($ci); 829 830 if (!$this->nonstd) { 831 $this->markTestSkipped('No Nonstandard Helper for this phptype.'); 832 } 833 834 $name = 'test_newtrigger'; 835 836 /* 837 * Have test suite helper functions setup the environment. 838 */ 839 $this->nonstd->dropTrigger($name, $this->table); 840 $result = $this->nonstd->createTrigger($name, $this->table); 841 $this->checkResultForErrors($result, 'create trigger helper'); 842 843 844 /* 845 * The actual tests. 846 */ 847 $action = 'listTableTriggers'; 848 $result = $this->db->manager->listTableTriggers($this->table); 849 $this->checkResultForErrors($result, $action); 850 $this->assertContains($name, $result, 851 "Result of $action() does not contain expected value"); 852 853 $action = 'listTableTriggers on non-existant table'; 854 $result = $this->db->manager->listTableTriggers('fake_table'); 855 $this->checkResultForErrors($result, $action); 856 $this->assertNotContains($name, $result, 857 "$action should not contain this view"); 858 859 860 /* 861 * Have test suite helper functions clean up the environment. 862 */ 863 $result = $this->nonstd->dropTrigger($name, $this->table); 864 $this->checkResultForErrors($result, 'drop trigger helper'); 865 } 866 867 /** 868 * @covers MDB2_Driver_Manager_Common::listTableViews() 869 * @dataProvider provider 870 */ 871 public function testListTableViews($ci) { 872 $this->manualSetUp($ci); 873 874 if (!$this->nonstd) { 875 $this->markTestSkipped('No Nonstandard Helper for this phptype.'); 876 } 877 878 $name = 'test_newview'; 879 880 /* 881 * Have test suite helper functions setup the environment. 882 */ 883 $this->nonstd->dropView($name); 884 $result = $this->nonstd->createView($name, $this->table); 885 $this->checkResultForErrors($result, 'create view helper'); 886 887 888 /* 889 * The actual tests. 890 */ 891 $action = 'listTableViews'; 892 $result = $this->db->manager->listTableViews($this->table); 893 $this->checkResultForErrors($result, $action); 894 $this->assertContains($name, $result, 895 "Result of $action() does not contain expected value"); 896 897 $action = 'listTableViews on non-existant table'; 898 $result = $this->db->manager->listTableViews('fake_table'); 899 $this->checkResultForErrors($result, $action); 900 $this->assertNotContains($name, $result, 901 "$action should not contain this view"); 902 903 904 /* 905 * Have test suite helper functions clean up the environment. 906 */ 907 $result = $this->nonstd->dropView($name); 908 $this->checkResultForErrors($result, 'drop view helper'); 909 } 910 911 /** 912 * Test listUsers() 913 * @dataProvider provider 914 */ 915 public function testListUsers($ci) { 916 $this->manualSetUp($ci); 917 918 $action = 'listUsers'; 919 $result = $this->db->manager->listUsers(); 920 $this->checkResultForErrors($result, $action); 921 $result = array_map('strtolower', $result); 922 $this->assertContains(strtolower($this->db->dsn['username']), $result, 923 "Result of $action() does not contain expected value"); 924 } 925 926 /** 927 * @covers MDB2_Driver_Manager_Common::listFunctions() 928 * @dataProvider provider 929 */ 930 public function testFunctionActions($ci) { 931 $this->manualSetUp($ci); 932 933 if (!$this->nonstd) { 934 $this->markTestSkipped('No Nonstandard Helper for this phptype.'); 935 } 936 937 $name = 'test_add'; 938 939 /* 940 * Have test suite helper functions setup the environment. 941 */ 942 $this->nonstd->dropFunction($name); 943 $this->db->pushErrorHandling(PEAR_ERROR_RETURN); 944 $this->db->expectError('*'); 945 $result = $this->nonstd->createFunction($name); 946 $this->db->popExpect(); 947 $this->db->popErrorHandling(); 948 $this->checkResultForErrors($result, 'crete function helper'); 949 950 951 /* 952 * The actual tests. 953 */ 954 $action = 'listFunctions'; 955 $result = $this->db->manager->listFunctions(); 956 $this->checkResultForErrors($result, $action); 957 $this->assertContains($name, $result, 958 "Result of $action() does not contain expected value"); 959 960 961 /* 962 * Have test suite helper functions clean up the environment. 963 */ 964 $result = $this->nonstd->dropFunction($name); 965 $this->checkResultForErrors($result, 'drop function helper'); 966 } 967 968 /** 969 * @covers MDB2_Driver_Manager_Common::createDatabase() 970 * @covers MDB2_Driver_Manager_Common::alterDatabase() 971 * @covers MDB2_Driver_Manager_Common::listDatabases() 972 * @covers MDB2_Driver_Manager_Common::dropDatabase() 973 * @dataProvider provider 974 */ 975 public function testCrudDatabase($ci) { 976 $this->manualSetUp($ci); 977 978 $name = 'mdb2_test_newdb'; 979 $rename = $name . '_renamed'; 980 $unlink = false; 981 switch ($this->db->phptype) { 982 case 'sqlite': 983 $name = tempnam(sys_get_temp_dir(), $name); 984 $rename = $name . '_renamed'; 985 unlink($name); 986 $unlink = true; 987 break; 988 } 989 990 $options = array( 991 'charset' => 'UTF8', 992 'collation' => 'utf8_bin', 993 ); 994 $changes = array( 995 'name' => $rename, 996 'charset' => 'UTF8', 997 ); 998 if ('pgsql' == substr($this->db->phptype, 0, 5)) { 999 $options['charset'] = 'WIN1252'; 1000 } 1001 if ('mssql' == substr($this->db->phptype, 0, 5)) { 1002 $options['collation'] = 'WIN1252'; 1003 $options['collation'] = 'Latin1_General_BIN'; 1004 } 1005 1006 $action = 'createDatabase'; 1007 $result = $this->db->manager->createDatabase($name, $options); 1008 $this->checkResultForErrors($result, $action); 1009 $this->assertEquals(MDB2_OK, $result, 1010 "$action did not return MDB2_OK"); 1011 1012 $action = 'listDatabases'; 1013 $result = $this->db->manager->listDatabases(); 1014 $this->checkResultForErrors($result, $action); 1015 $this->assertContains($name, $result, 1016 "Result of $action() does not contain expected value"); 1017 1018 $action = 'alterDatabase'; 1019 $result = $this->db->manager->alterDatabase($name, $changes); 1020 $this->checkResultForErrors($result, $action); 1021 $this->assertEquals(MDB2_OK, $result, 1022 "$action did not return MDB2_OK"); 1023 1024 $action = 'listDatabases'; 1025 $result = $this->db->manager->listDatabases(); 1026 $this->checkResultForErrors($result, $action); 1027 if (!in_array($rename, $result)) { 1028 $this->db->manager->dropDatabase($name); 1029 $this->fail('Error: could not find renamed database'); 1030 } 1031 1032 $action = 'dropDatabase'; 1033 $result = $this->db->manager->dropDatabase($rename); 1034 $this->checkResultForErrors($result, $action); 1035 $this->assertEquals(MDB2_OK, $result, 1036 "$action did not return MDB2_OK"); 1037 1038 // Check that it's actually gone. 1039 $action = 'listDatabases'; 1040 $result = $this->db->manager->listDatabases(); 1041 $this->checkResultForErrors($result, $action); 1042 $this->assertNotContains($rename, $result, 1043 "dropDatabase() passed but the database is still there"); 1044 } 1045 1046 /** 1047 * Test vacuum 1048 * @dataProvider provider 1049 */ 1050 public function testVacuum($ci) { 1051 $this->manualSetUp($ci); 1052 1053 $action = 'vacuum table'; 1054 $result = $this->db->manager->vacuum($this->table); 1055 $this->checkResultForErrors($result, $action); 1056 $this->assertEquals(MDB2_OK, $result, 1057 "$action did not return MDB2_OK"); 1058 1059 $action = 'vacuum and analyze table'; 1060 $options = array( 1061 'analyze' => true, 1062 'full' => true, 1063 'freeze' => true, 1064 ); 1065 $result = $this->db->manager->vacuum($this->table, $options); 1066 $this->checkResultForErrors($result, $action); 1067 $this->assertEquals(MDB2_OK, $result, 1068 "$action did not return MDB2_OK"); 1069 1070 $action = 'vacuum all tables'; 1071 $result = $this->db->manager->vacuum(); 1072 $this->checkResultForErrors($result, $action); 1073 $this->assertEquals(MDB2_OK, $result, 1074 "$action did not return MDB2_OK"); 1075 } 1076} 1077