PageRenderTime 76ms CodeModel.GetById 34ms app.highlight 32ms RepoModel.GetById 1ms app.codeStats 0ms

/test/testsuite/generator/builder/om/GeneratedObjectTest.php

https://github.com/nextbigsound/propel-orm
PHP | 1355 lines | 870 code | 263 blank | 222 comment | 10 complexity | b483411c5e218fb0fdae04ce8cdc4c4b MD5 | raw file
   1<?php
   2
   3/**
   4 * This file is part of the Propel package.
   5 * For the full copyright and license information, please view the LICENSE
   6 * file that was distributed with this source code.
   7 *
   8 * @license    MIT License
   9 */
  10
  11require_once 'tools/helpers/bookstore/BookstoreEmptyTestBase.php';
  12
  13/**
  14 * Tests the generated Object classes.
  15 *
  16 * This test uses generated Bookstore classes to test the behavior of various
  17 * object operations.  The _idea_ here is to test every possible generated method
  18 * from Object.tpl; if necessary, bookstore will be expanded to accommodate this.
  19 *
  20 * The database is relaoded before every test and flushed after every test.  This
  21 * means that you can always rely on the contents of the databases being the same
  22 * for each test method in this class.  See the BookstoreDataPopulator::populate()
  23 * method for the exact contents of the database.
  24 *
  25 * @see        BookstoreDataPopulator
  26 * @author     Hans Lellelid <hans@xmpl.org>
  27 * @package    generator.builder.om
  28 */
  29class GeneratedObjectTest extends BookstoreEmptyTestBase
  30{
  31	protected function setUp()
  32	{
  33		parent::setUp();
  34		require_once 'tools/helpers/bookstore/behavior/TestAuthor.php';
  35	}
  36
  37	/**
  38	 * Test saving an object after setting default values for it.
  39	 */
  40	public function testSaveWithDefaultValues()
  41	{
  42		// From the schema.xml, I am relying on the following:
  43		//  - that 'Penguin' is the default Name for a Publisher
  44		//  - that 2001-01-01 is the default ReviewDate for a Review
  45
  46		// 1) check regular values (VARCHAR)
  47		$pub = new Publisher();
  48		$pub->setName('Penguin');
  49		$pub->save();
  50		$this->assertTrue($pub->getId() !== null, "Expect Publisher to have been saved when default value set.");
  51
  52		// 2) check date/time values
  53		$review = new Review();
  54		// note that this is different from how it's represented in schema, but should resolve to same unix timestamp
  55		$review->setReviewDate('2001-01-01');
  56		$this->assertTrue($review->isModified(), "Expect Review to have been marked 'modified' after default date/time value set.");
  57
  58	}
  59	
  60	/**
  61	 * Test isModified() to be false after setting default value second time
  62	 */
  63	public function testDefaultValueSetTwice()
  64	{
  65    $pub = new Publisher();
  66    $pub->setName('Penguin');
  67    $pub->save();
  68  
  69    $pubId = $pub->getId();
  70    
  71    PublisherPeer::clearInstancePool();
  72    
  73    $pub2 = PublisherPeer::retrieveByPK($pubId);
  74    $pub2->setName('Penguin');
  75    $this->assertFalse($pub2->isModified(), "Expect Publisher to be not modified after setting default value second time.");
  76	}
  77
  78  public function testHasApplyDefaultValues()
  79  {
  80    $this->assertTrue(method_exists('Publisher', 'applyDefaultValues'), 'Tables with default values should have an applyDefaultValues() method');
  81    $this->assertFalse(method_exists('Book', 'applyDefaultValues'), 'Tables with no default values should not have an applyDefaultValues() method');
  82  }
  83
  84	/**
  85	 * Test default return values.
  86	 */
  87	public function testDefaultValues()
  88	{
  89		$r = new Review();
  90		$this->assertEquals('2001-01-01', $r->getReviewDate('Y-m-d'));
  91
  92		$this->assertFalse($r->isModified(), "expected isModified() to be false");
  93
  94		$acct = new BookstoreEmployeeAccount();
  95		$this->assertEquals(true, $acct->getEnabled());
  96		$this->assertFalse($acct->isModified());
  97
  98		$acct->setLogin("testuser");
  99		$acct->setPassword("testpass");
 100		$this->assertTrue($acct->isModified());
 101	}
 102
 103	/**
 104	 * Tests the use of default expressions and the reloadOnInsert and reloadOnUpdate attributes.
 105	 *
 106	 * @link       http://propel.phpdb.org/trac/ticket/378
 107	 * @link       http://propel.phpdb.org/trac/ticket/555
 108	 */
 109	public function testDefaultExpresions()
 110	{
 111		if (Propel::getDb(BookstoreEmployeePeer::DATABASE_NAME) instanceof DBSqlite) {
 112			$this->markTestSkipped("Cannot test default expressions with SQLite");
 113		}
 114
 115		$b = new Bookstore();
 116		$b->setStoreName("Foo!");
 117		$b->save();
 118
 119		$employee = new BookstoreEmployee();
 120		$employee->setName("Johnny Walker");
 121
 122		$acct = new BookstoreEmployeeAccount();
 123		$acct->setBookstoreEmployee($employee);
 124		$acct->setLogin("test-login");
 125
 126		$this->assertNull($acct->getCreated(), "Expected created column to be NULL.");
 127		$this->assertNull($acct->getAuthenticator(), "Expected authenticator column to be NULL.");
 128
 129		$acct->save();
 130
 131		$acct = BookstoreEmployeeAccountPeer::retrieveByPK($acct->getEmployeeId());
 132
 133		$this->assertNotNull($acct->getAuthenticator(), "Expected a valid (non-NULL) authenticator column after save.");
 134		$this->assertEquals('Password', $acct->getAuthenticator(), "Expected authenticator='Password' after save.");
 135		$this->assertNotNull($acct->getCreated(), "Expected a valid date after retrieving saved object.");
 136
 137		$now = new DateTime("now");
 138		$this->assertEquals($now->format("Y-m-d"), $acct->getCreated("Y-m-d"));
 139
 140		$acct->setCreated($now);
 141		$this->assertEquals($now->format("Y-m-d"), $acct->getCreated("Y-m-d"));
 142
 143		// Unfortunately we can't really test the conjunction of reloadOnInsert and reloadOnUpdate when using just
 144		// default values. (At least not in a cross-db way.)
 145	}
 146
 147	/**
 148	 * Tests the use of default expressions and the reloadOnInsert attribute.
 149	 *
 150	 * @link       http://propel.phpdb.org/trac/ticket/378
 151	 * @link       http://propel.phpdb.org/trac/ticket/555
 152	 */
 153	public function testDefaultExpresions_ReloadOnInsert()
 154	{
 155		if (Propel::getDb(BookstoreEmployeePeer::DATABASE_NAME) instanceof DBSqlite) {
 156			$this->markTestSkipped("Cannot test default date expressions with SQLite");
 157		}
 158
 159		// Create a new bookstore, contest, bookstore_contest, and bookstore_contest_entry
 160
 161		$b = new Bookstore();
 162		$b->setStoreName("Barnes & Noble");
 163		$b->save();
 164
 165		$c = new Contest();
 166		$c->setName("Bookathon Contest");
 167		$c->save();
 168
 169		$bc = new BookstoreContest();
 170		$bc->setBookstore($b);
 171		$bc->setContest($c);
 172		$bc->save();
 173
 174		$c = new Customer();
 175		$c->setName("Happy Customer");
 176		$c->save();
 177
 178		$bce = new BookstoreContestEntry();
 179		$bce->setBookstore($b);
 180		$bce->setBookstoreContest($bc);
 181		$bce->setCustomer($c);
 182		$bce->save();
 183
 184		$this->assertNotNull($bce->getEntryDate(), "Expected a non-null entry_date after save.");
 185	}
 186
 187	/**
 188	 * Tests the overriding reloadOnInsert at runtime.
 189	 *
 190	 * @link       http://propel.phpdb.org/trac/ticket/378
 191	 * @link       http://propel.phpdb.org/trac/ticket/555
 192	 */
 193	public function testDefaultExpresions_ReloadOnInsert_Override()
 194	{
 195		if (Propel::getDb(BookstoreEmployeePeer::DATABASE_NAME) instanceof DBSqlite) {
 196			$this->markTestSkipped("Cannot test default date expressions with SQLite");
 197		}
 198
 199		// Create a new bookstore, contest, bookstore_contest, and bookstore_contest_entry
 200		$b = new Bookstore();
 201		$b->setStoreName("Barnes & Noble");
 202		$b->save();
 203
 204		$c = new Contest();
 205		$c->setName("Bookathon Contest");
 206		$c->save();
 207
 208		$bc = new BookstoreContest();
 209		$bc->setBookstore($b);
 210		$bc->setContest($c);
 211		$bc->save();
 212
 213		$c = new Customer();
 214		$c->setName("Happy Customer");
 215		$c->save();
 216
 217		$bce = new BookstoreContestEntry();
 218		$bce->setBookstore($b);
 219		$bce->setBookstoreContest($bc);
 220		$bce->setCustomer($c);
 221		$bce->save(null, $skipReload=true);
 222
 223		$this->assertNull($bce->getEntryDate(), "Expected a NULL entry_date after save.");
 224	}
 225
 226	/**
 227	 * Tests the use of default expressions and the reloadOnUpdate attribute.
 228	 *
 229	 * @link       http://propel.phpdb.org/trac/ticket/555
 230	 */
 231	public function testDefaultExpresions_ReloadOnUpdate()
 232	{
 233		$b = new Bookstore();
 234		$b->setStoreName("Foo!");
 235		$b->save();
 236
 237		$sale = new BookstoreSale();
 238		$sale->setBookstore(BookstorePeer::doSelectOne(new Criteria()));
 239		$sale->setSaleName("Spring Sale");
 240		$sale->save();
 241
 242		// Expect that default values are set, but not default expressions
 243		$this->assertNull($sale->getDiscount(), "Expected discount to be NULL.");
 244
 245		$sale->setSaleName("Winter Clearance");
 246		$sale->save();
 247		// Since reloadOnUpdate = true, we expect the discount to be set now.
 248
 249		$this->assertNotNull($sale->getDiscount(), "Expected discount to be non-NULL after save.");
 250	}
 251
 252	/**
 253	 * Tests the overriding reloadOnUpdate at runtime.
 254	 *
 255	 * @link       http://propel.phpdb.org/trac/ticket/378
 256	 * @link       http://propel.phpdb.org/trac/ticket/555
 257	 */
 258	public function testDefaultExpresions_ReloadOnUpdate_Override()
 259	{
 260		$b = new Bookstore();
 261		$b->setStoreName("Foo!");
 262		$b->save();
 263
 264		$sale = new BookstoreSale();
 265		$sale->setBookstore(BookstorePeer::doSelectOne(new Criteria()));
 266		$sale->setSaleName("Spring Sale");
 267		$sale->save();
 268
 269		// Expect that default values are set, but not default expressions
 270		$this->assertNull($sale->getDiscount(), "Expected discount to be NULL.");
 271
 272		$sale->setSaleName("Winter Clearance");
 273		$sale->save(null, $skipReload=true);
 274
 275		// Since reloadOnUpdate = true, we expect the discount to be set now.
 276
 277		$this->assertNull($sale->getDiscount(), "Expected NULL value for discount after save.");
 278	}
 279
 280	/**
 281	 * Test the behavior of date/time/values.
 282	 * This requires that the model was built with propel.useDateTimeClass=true.
 283	 */
 284	public function testTemporalValues_PreEpoch()
 285	{
 286		$r = new Review();
 287
 288		$preEpochDate = new DateTime('1602-02-02');
 289
 290		$r->setReviewDate($preEpochDate);
 291
 292		$this->assertEquals('1602-02-02', $r->getReviewDate(null)->format("Y-m-d"));
 293
 294		$r->setReviewDate('1702-02-02');
 295
 296		$this->assertTrue($r->isModified());
 297
 298		$this->assertEquals('1702-02-02', $r->getReviewDate(null)->format("Y-m-d"));
 299
 300		// Now test for setting null
 301		$r->setReviewDate(null);
 302		$this->assertNull($r->getReviewDate());
 303
 304	}
 305
 306	/**
 307	 * Test setting invalid date/time.
 308	 */
 309	public function testSetTemporalValue_Invalid()
 310	{
 311		$this->markTestSkipped();
 312		// FIXME - Figure out why this doesn't work (causes a PHP ERROR instead of throwing Exception) in
 313		// the Phing+PHPUnit context
 314		$r = new Review();
 315		try {
 316			$r->setReviewDate("Invalid Date");
 317			$this->fail("Expected PropelException when setting date column w/ invalid date");
 318		} catch (PropelException $x) {
 319			print "Caught expected PropelException: " . $x->__toString();
 320		}
 321	}
 322
 323	/**
 324	 * Test setting TIMESTAMP columns w/ unix int timestamp.
 325	 */
 326	public function testTemporalValues_Unix()
 327	{
 328		$store = new Bookstore();
 329		$store->setStoreName("test");
 330		$store->setStoreOpenTime(strtotime('12:55'));
 331		$store->save();
 332		$this->assertEquals('12:55', $store->getStoreOpenTime(null)->format('H:i'));
 333
 334		$acct = new BookstoreEmployeeAccount();
 335		$acct->setCreated(time());
 336		$this->assertEquals(date('Y-m-d H:i'), $acct->getCreated('Y-m-d H:i'));
 337
 338		$review = new Review();
 339		$review->setReviewDate(time());
 340		$this->assertEquals(date('Y-m-d'), $review->getReviewDate('Y-m-d'));
 341	}
 342
 343	/**
 344	 * Test setting empty temporal values.
 345	 * @link       http://propel.phpdb.org/trac/ticket/586
 346	 */
 347	public function testTemporalValues_Empty()
 348	{
 349		$review = new Review();
 350		$review->setReviewDate('');
 351		$this->assertNull($review->getReviewDate());
 352	}
 353
 354	/**
 355	 * Test setting TIME columns.
 356	 */
 357	public function testTemporalValues_TimeSetting()
 358	{
 359		$store = new Bookstore();
 360		$store->setStoreName("test");
 361		$store->setStoreOpenTime("12:55");
 362		$store->save();
 363
 364		$store = new Bookstore();
 365		$store->setStoreName("test2");
 366		$store->setStoreOpenTime(new DateTime("12:55"));
 367		$store->save();
 368	}
 369
 370	/**
 371	 * Test setting TIME columns.
 372	 */
 373	public function testTemporalValues_DateSetting()
 374	{
 375		BookstoreDataPopulator::populate();
 376
 377		$r = new Review();
 378		$r->setBook(BookPeer::doSelectOne(new Criteria()));
 379		$r->setReviewDate(new DateTime('1999-12-20'));
 380		$r->setReviewedBy("Hans");
 381		$r->setRecommended(false);
 382		$r->save();
 383	}
 384
 385	/**
 386	 * Testing creating & saving new object & instance pool.
 387	 */
 388	public function testObjectInstances_New()
 389	{
 390		$emp = new BookstoreEmployee();
 391		$emp->setName(md5(microtime()));
 392		$emp->save();
 393		$id = $emp->getId();
 394
 395		$retrieved = BookstoreEmployeePeer::retrieveByPK($id);
 396		$this->assertSame($emp, $retrieved, "Expected same object (from instance pool)");
 397	}
 398
 399	/**
 400	 *
 401	 */
 402	public function testObjectInstances_Fkeys()
 403	{
 404		// Establish a relationship between one employee and account
 405		// and then change the employee_id and ensure that the account
 406		// is not pulling the old employee.
 407
 408		$pub1 = new Publisher();
 409		$pub1->setName('Publisher 1');
 410		$pub1->save();
 411
 412		$pub2 = new Publisher();
 413		$pub2->setName('Publisher 2');
 414		$pub2->save();
 415
 416		$book = new Book();
 417		$book->setTitle("Book Title");
 418		$book->setISBN("1234");
 419		$book->setPublisher($pub1);
 420		$book->save();
 421
 422		$this->assertSame($pub1, $book->getPublisher());
 423
 424		// now change values behind the scenes
 425		$con = Propel::getConnection(BookstoreEmployeeAccountPeer::DATABASE_NAME);
 426		$con->exec("UPDATE " . BookPeer::TABLE_NAME . " SET "
 427		. " publisher_id = " . $pub2->getId()
 428		. " WHERE id = " . $book->getId());
 429
 430
 431		$book2 = BookPeer::retrieveByPK($book->getId());
 432		$this->assertSame($book, $book2, "Expected same book object instance");
 433
 434		$this->assertEquals($pub1->getId(), $book->getPublisherId(), "Expected book to have OLD publisher id before reload()");
 435
 436		$book->reload();
 437
 438		$this->assertEquals($pub2->getId(), $book->getPublisherId(), "Expected book to have new publisher id");
 439		$this->assertSame($pub2, $book->getPublisher(), "Expected book to have new publisher object associated.");
 440
 441		// Now let's set it back, just to be double sure ...
 442
 443		$con->exec("UPDATE " . BookPeer::TABLE_NAME . " SET "
 444		. " publisher_id = " . $pub1->getId()
 445		. " WHERE id = " . $book->getId());
 446
 447		$book->reload();
 448
 449		$this->assertEquals($pub1->getId(), $book->getPublisherId(), "Expected book to have old publisher id (again).");
 450		$this->assertSame($pub1, $book->getPublisher(), "Expected book to have old publisher object associated (again).");
 451
 452	}
 453
 454	/**
 455	 * Test the effect of typecast on primary key values and instance pool retrieval.
 456	 */
 457	public function testObjectInstancePoolTypecasting()
 458	{
 459		$reader = new BookReader();
 460		$reader->setName("Tester");
 461		$reader->save();
 462		$readerId = $reader->getId();
 463
 464		$book = new Book();
 465		$book->setTitle("BookTest");
 466		$book->setISBN("TEST");
 467		$book->save();
 468		$bookId = $book->getId();
 469
 470		$opinion = new BookOpinion();
 471		$opinion->setBookId((string)$bookId);
 472		$opinion->setReaderId((string)$readerId);
 473		$opinion->setRating(5);
 474		$opinion->setRecommendToFriend(false);
 475		$opinion->save();
 476
 477
 478		$opinion2 = BookOpinionPeer::retrieveByPK($bookId, $readerId);
 479
 480		$this->assertSame($opinion, $opinion2, "Expected same object to be retrieved from differently type-casted primary key values.");
 481
 482	}
 483
 484	/**
 485	 * Test the reload() method.
 486	 */
 487	public function testReload()
 488	{
 489		BookstoreDataPopulator::populate();
 490		$a = AuthorPeer::doSelectOne(new Criteria());
 491
 492		$origName = $a->getFirstName();
 493
 494		$a->setFirstName(md5(time()));
 495
 496		$this->assertNotEquals($origName, $a->getFirstName());
 497		$this->assertTrue($a->isModified());
 498
 499		$a->reload();
 500
 501		$this->assertEquals($origName, $a->getFirstName());
 502		$this->assertFalse($a->isModified());
 503
 504	}
 505
 506	/**
 507	 * Test reload(deep=true) method.
 508	 */
 509	public function testReloadDeep()
 510	{
 511		BookstoreDataPopulator::populate();
 512		
 513		// arbitrary book
 514		$b = BookPeer::doSelectOne(new Criteria());
 515
 516		// arbitrary, different author
 517		$c = new Criteria();
 518		$c->add(AuthorPeer::ID, $b->getAuthorId(), Criteria::NOT_EQUAL);
 519		$a = AuthorPeer::doSelectOne($c);
 520
 521		$origAuthor = $b->getAuthor();
 522
 523		$b->setAuthor($a);
 524
 525		$this->assertNotEquals($origAuthor, $b->getAuthor(), "Expected just-set object to be different from obj from DB");
 526		$this->assertTrue($b->isModified());
 527
 528		$b->reload($deep=true);
 529
 530		$this->assertEquals($origAuthor, $b->getAuthor(), "Expected object in DB to be restored");
 531		$this->assertFalse($a->isModified());
 532	}
 533
 534	/**
 535	 * Test saving an object and getting correct number of affected rows from save().
 536	 * This includes tests of cascading saves to fk-related objects.
 537	 */
 538	public function testSaveReturnValues()
 539	{
 540
 541		$author = new Author();
 542		$author->setFirstName("Mark");
 543		$author->setLastName("Kurlansky");
 544		// do not save
 545
 546		$pub = new Publisher();
 547		$pub->setName("Penguin Books");
 548		// do not save
 549
 550		$book = new Book();
 551		$book->setTitle("Salt: A World History");
 552		$book->setISBN("0142001619");
 553		$book->setAuthor($author);
 554		$book->setPublisher($pub);
 555
 556		$affected = $book->save();
 557		$this->assertEquals(3, $affected, "Expected 3 affected rows when saving book + publisher + author.");
 558
 559		// change nothing ...
 560		$affected = $book->save();
 561		$this->assertEquals(0, $affected, "Expected 0 affected rows when saving already-saved book.");
 562
 563		// modify the book (UPDATE)
 564		$book->setTitle("Salt A World History");
 565		$affected = $book->save();
 566		$this->assertEquals(1, $affected, "Expected 1 affected row when saving modified book.");
 567
 568		// modify the related author
 569		$author->setLastName("Kurlanski");
 570		$affected = $book->save();
 571		$this->assertEquals(1, $affected, "Expected 1 affected row when saving book with updated author.");
 572
 573		// modify both the related author and the book
 574		$author->setLastName("Kurlansky");
 575		$book->setTitle("Salt: A World History");
 576		$affected = $book->save();
 577		$this->assertEquals(2, $affected, "Expected 2 affected rows when saving updated book with updated author.");
 578
 579	}
 580
 581	/**
 582	 * Test deleting an object using the delete() method.
 583	 */
 584	public function testDelete()
 585	{
 586		BookstoreDataPopulator::populate();
 587
 588		// 1) grab an arbitrary object
 589		$book = BookPeer::doSelectOne(new Criteria());
 590		$bookId = $book->getId();
 591
 592		// 2) delete it
 593		$book->delete();
 594
 595		// 3) make sure it can't be save()d now that it's deleted
 596		try {
 597			$book->setTitle("Will Fail");
 598			$book->save();
 599			$this->fail("Expect an exception to be thrown when attempting to save() a deleted object.");
 600		} catch (PropelException $e) {}
 601
 602		// 4) make sure that it doesn't exist in db
 603		$book = BookPeer::retrieveByPK($bookId);
 604		$this->assertNull($book, "Expect NULL from retrieveByPK on deleted Book.");
 605
 606	}
 607
 608	/**
 609	 *
 610	 */
 611	public function testNoColsModified()
 612	{
 613		$e1 = new BookstoreEmployee();
 614		$e1->setName('Employee 1');
 615
 616		$e2 = new BookstoreEmployee();
 617		$e2->setName('Employee 2');
 618
 619		$super = new BookstoreEmployee();
 620		// we don't know who the supervisor is yet
 621		$super->addSubordinate($e1);
 622		$super->addSubordinate($e2);
 623
 624		$affected = $super->save();
 625
 626	}
 627
 628	/**
 629	 * Tests new one-to-one functionality.
 630	 */
 631	public function testOneToOne()
 632	{
 633		BookstoreDataPopulator::populate();
 634
 635		$emp = BookstoreEmployeePeer::doSelectOne(new Criteria());
 636
 637		$acct = new BookstoreEmployeeAccount();
 638		$acct->setBookstoreEmployee($emp);
 639		$acct->setLogin("testuser");
 640		$acct->setPassword("testpass");
 641
 642		$this->assertSame($emp->getBookstoreEmployeeAccount(), $acct, "Expected same object instance.");
 643	}
 644
 645	/**
 646	 * Test the type sensitivity of the resturning columns.
 647	 *
 648	 */
 649	public function testTypeSensitive()
 650	{
 651		BookstoreDataPopulator::populate();
 652
 653		$book = BookPeer::doSelectOne(new Criteria());
 654
 655		$r = new Review();
 656		$r->setReviewedBy("testTypeSensitive Tester");
 657		$r->setReviewDate(time());
 658		$r->setBook($book);
 659		$r->setRecommended(true);
 660		$r->save();
 661
 662		$id = $r->getId();
 663		unset($r);
 664
 665		// clear the instance cache to force reload from database.
 666		ReviewPeer::clearInstancePool();
 667		BookPeer::clearInstancePool();
 668
 669		// reload and verify that the types are the same
 670		$r2 = ReviewPeer::retrieveByPK($id);
 671
 672		$this->assertType('integer', $r2->getId(), "Expected getId() to return an integer.");
 673		$this->assertType('string', $r2->getReviewedBy(), "Expected getReviewedBy() to return a string.");
 674		$this->assertType('boolean', $r2->getRecommended(), "Expected getRecommended() to return a boolean.");
 675		$this->assertType('Book', $r2->getBook(), "Expected getBook() to return a Book.");
 676		$this->assertType('float', $r2->getBook()->getPrice(), "Expected Book->getPrice() to return a float.");
 677		$this->assertType('DateTime', $r2->getReviewDate(null), "Expected Book->getReviewDate() to return a DateTime.");
 678
 679	}
 680
 681	/**
 682	 * This is a test for expected exceptions when saving UNIQUE.
 683	 * See http://propel.phpdb.org/trac/ticket/2
 684	 */
 685	public function testSaveUnique()
 686	{
 687	  // The whole test is in a transaction, but this test needs real transactions
 688	  $this->con->commit();
 689	  
 690		$emp = new BookstoreEmployee();
 691		$emp->setName(md5(microtime()));
 692
 693		$acct = new BookstoreEmployeeAccount();
 694		$acct->setBookstoreEmployee($emp);
 695		$acct->setLogin("foo");
 696		$acct->setPassword("bar");
 697		$acct->save();
 698
 699		// now attempt to create a new acct
 700		$acct2 = $acct->copy();
 701
 702		try {
 703			$acct2->save();
 704			$this->fail("Expected PropelException in first attempt to save object with duplicate value for UNIQUE constraint.");
 705		} catch (Exception $x) {
 706			try {
 707				// attempt to save it again
 708				$acct3 = $acct->copy();
 709				$acct3->save();
 710				$this->fail("Expected PropelException in second attempt to save object with duplicate value for UNIQUE constraint.");
 711			} catch (Exception $x) {
 712				// this is expected.
 713			}
 714			// now let's double check that it can succeed if we're not violating the constraint.
 715			$acct3->setLogin("foo2");
 716			$acct3->save();
 717		}
 718		
 719		$this->con->beginTransaction();
 720	}
 721
 722	/**
 723	 * Test for correct reporting of isModified().
 724	 */
 725	public function testIsModified()
 726	{
 727		// 1) Basic test
 728
 729		$a = new Author();
 730		$a->setFirstName("John");
 731		$a->setLastName("Doe");
 732		$a->setAge(25);
 733
 734		$this->assertTrue($a->isModified(), "Expected Author to be modified after setting values.");
 735
 736		$a->save();
 737
 738		$this->assertFalse($a->isModified(), "Expected Author to be unmodified after saving set values.");
 739
 740		// 2) Test behavior with setting vars of different types
 741
 742		// checking setting int col to string val
 743		$a->setAge('25');
 744		$this->assertFalse($a->isModified(), "Expected Author to be unmodified after setting int column to string-cast of same value.");
 745
 746		$a->setFirstName("John2");
 747		$this->assertTrue($a->isModified(), "Expected Author to be modified after changing string column value.");
 748
 749		// checking setting string col to int val
 750		$a->setFirstName("1");
 751		$a->save();
 752		$this->assertFalse($a->isModified(), "Expected Author to be unmodified after saving set values.");
 753
 754		$a->setFirstName(1);
 755		$this->assertFalse($a->isModified(), "Expected Author to be unmodified after setting string column to int-cast of same value.");
 756
 757		// 3) Test for appropriate behavior of NULL
 758
 759		// checking "" -> NULL
 760		$a->setFirstName("");
 761		$a->save();
 762		$this->assertFalse($a->isModified(), "Expected Author to be unmodified after saving set values.");
 763
 764		$a->setFirstName(null);
 765		$this->assertTrue($a->isModified(), "Expected Author to be modified after changing empty string column value to NULL.");
 766
 767		$a->setFirstName("John");
 768		$a->setAge(0);
 769		$a->save();
 770		$this->assertFalse($a->isModified(), "Expected Author to be unmodified after saving set values.");
 771
 772		$a->setAge(null);
 773		$this->assertTrue($a->isModified(), "Expected Author to be modified after changing 0-value int column to NULL.");
 774
 775		$a->save();
 776		$this->assertFalse($a->isModified(), "Expected Author to be unmodified after saving set values.");
 777
 778		$a->setAge(0);
 779		$this->assertTrue($a->isModified(), "Expected Author to be modified after changing NULL-value int column to 0.");
 780
 781	}
 782
 783	/**
 784	 * Test the BaseObject#equals().
 785	 */
 786	public function testEquals()
 787	{
 788		BookstoreDataPopulator::populate();
 789
 790		$b = BookPeer::doSelectOne(new Criteria());
 791		$c = new Book();
 792		$c->setId($b->getId());
 793		$this->assertTrue($b->equals($c), "Expected Book objects to be equal()");
 794
 795		$a = new Author();
 796		$a->setId($b->getId());
 797		$this->assertFalse($b->equals($a), "Expected Book and Author with same primary key NOT to match.");
 798	}
 799
 800	/**
 801	 * Test checking for non-default values.
 802	 * @see        http://propel.phpdb.org/trac/ticket/331
 803	 */
 804	public function testHasOnlyDefaultValues()
 805	{
 806		$emp = new BookstoreEmployee();
 807		$emp->setName(md5(microtime()));
 808
 809		$acct2 = new BookstoreEmployeeAccount();
 810
 811		$acct = new BookstoreEmployeeAccount();
 812		$acct->setBookstoreEmployee($emp);
 813		$acct->setLogin("foo");
 814		$acct->setPassword("bar");
 815		$acct->save();
 816
 817		$this->assertFalse($acct->isModified(), "Expected BookstoreEmployeeAccount NOT to be modified after save().");
 818
 819		$acct->setEnabled(true);
 820		$acct->setPassword($acct2->getPassword());
 821
 822		$this->assertTrue($acct->isModified(), "Expected BookstoreEmployeeAccount to be modified after setting default values.");
 823
 824		$this->assertTrue($acct->hasOnlyDefaultValues(), "Expected BookstoreEmployeeAccount to not have only default values.");
 825
 826		$acct->setPassword("bar");
 827		$this->assertFalse($acct->hasOnlyDefaultValues(), "Expected BookstoreEmployeeAccount to have at one non-default value after setting one value to non-default.");
 828
 829		// Test a default date/time value
 830		$r = new Review();
 831		$r->setReviewDate(new DateTime("now"));
 832		$this->assertFalse($r->hasOnlyDefaultValues());
 833	}
 834
 835	public function testDefaultFkColVal()
 836	{
 837		BookstoreDataPopulator::populate();
 838
 839		$sale = new BookstoreSale();
 840		$this->assertEquals(1, $sale->getBookstoreId(), "Expected BookstoreSale object to have a default bookstore_id of 1.");
 841
 842		$bookstore = BookstorePeer::doSelectOne(new Criteria());
 843
 844		$sale->setBookstore($bookstore);
 845		$this->assertEquals($bookstore->getId(), $sale->getBookstoreId(), "Expected FK id to have changed when assigned a valid FK.");
 846
 847		$sale->setBookstore(null);
 848		$this->assertEquals(1, $sale->getBookstoreId(), "Expected BookstoreSale object to have reset to default ID.");
 849
 850		$sale->setPublisher(null);
 851		$this->assertEquals(null, $sale->getPublisherId(), "Expected BookstoreSale object to have reset to NULL publisher ID.");
 852	}
 853
 854	public function testCountRefFk()
 855	{
 856		$book = new Book();
 857		$book->setTitle("Test Book");
 858		$book->setISBN("TT-EE-SS-TT");
 859
 860		$num = 5;
 861
 862		for ($i=2; $i < $num + 2; $i++) {
 863			$r = new Review();
 864			$r->setReviewedBy('Hans ' . $num);
 865			$dt = new DateTime("now");
 866			$dt->modify("-".$i." weeks");
 867			$r->setReviewDate($dt);
 868			$r->setRecommended(($i % 2) == 0);
 869			$book->addReview($r);
 870		}
 871
 872		$this->assertEquals($num, $book->countReviews(), "Expected countReviews to return $num");
 873		$this->assertEquals($num, count($book->getReviews()), "Expected getReviews to return $num reviews");
 874
 875		$book->save();
 876
 877		BookPeer::clearInstancePool();
 878		ReviewPeer::clearInstancePool();
 879
 880		$book = BookPeer::retrieveByPK($book->getId());
 881		$this->assertEquals($num, $book->countReviews(), "Expected countReviews() to return $num (after save)");
 882		$this->assertEquals($num, count($book->getReviews()), "Expected getReviews() to return $num (after save)");
 883
 884		// Now set different criteria and expect different results
 885		$c = new Criteria();
 886		$c->add(ReviewPeer::RECOMMENDED, false);
 887		$this->assertEquals(floor($num/2), $book->countReviews($c), "Expected " . floor($num/2) . " results from countReviews(recomm=false)");
 888
 889		// Change Criteria, run again -- expect different.
 890		$c = new Criteria();
 891		$c->add(ReviewPeer::RECOMMENDED, true);
 892		$this->assertEquals(ceil($num/2), count($book->getReviews($c)), "Expected " . ceil($num/2) . " results from getReviews(recomm=true)");
 893
 894		$this->assertEquals($num, $book->countReviews(), "Expected countReviews to return $num with new empty Criteria");
 895	}
 896
 897	/**
 898	 * Test copyInto method.
 899	 */
 900	public function testCopyInto_Deep()
 901	{
 902		BookstoreDataPopulator::populate();
 903
 904		// Test a "normal" object
 905		$c = new Criteria();
 906		$c->add(BookPeer::TITLE, 'Harry%', Criteria::LIKE);
 907
 908		$book = BookPeer::doSelectOne($c);
 909		$reviews = $book->getReviews();
 910
 911		$b2 = $book->copy(true);
 912		$this->assertType('Book', $b2);
 913		$this->assertNull($b2->getId());
 914
 915		$r2 = $b2->getReviews();
 916
 917		$this->assertEquals(count($reviews), count($r2));
 918
 919		// Test a one-to-one object
 920		$emp = BookstoreEmployeePeer::doSelectOne(new Criteria());
 921		$e2 = $emp->copy(true);
 922
 923		$this->assertType('BookstoreEmployee', $e2);
 924		$this->assertNull($e2->getId());
 925
 926		$this->assertEquals($emp->getBookstoreEmployeeAccount()->getLogin(), $e2->getBookstoreEmployeeAccount()->getLogin());
 927	}
 928	
 929	/**
 930	 * Test copying when an object has composite primary key.
 931	 * @link http://propel.phpdb.org/trac/ticket/618
 932	 */
 933	public function testCopy_CompositePK()
 934	{
 935		$br = new BookReader();
 936		$br->setName("TestReader");
 937		$br->save();
 938		$br->copy();
 939		
 940		$b = new Book();
 941		$b->setTitle("TestBook");
 942		$b->setISBN("XX-XX-XX-XX");
 943		$b->save();
 944		
 945		$op = new BookOpinion();
 946		$op->setBookReader($br);
 947		$op->setBook($b);
 948		$op->setRating(10);
 949		$op->setRecommendToFriend(true);
 950		$op->save();
 951		
 952		
 953		$br2 = $br->copy(true);
 954		
 955		$this->assertNull($br2->getId());
 956		
 957		$opinions = $br2->getBookOpinions();
 958		$this->assertEquals(1, count($opinions), "Expected to have a related BookOpinion after copy()");
 959		
 960		// We DO expect the reader_id to be null
 961		$this->assertNull($opinions[0]->getReaderId());
 962		// but we DO NOT expect the book_id to be null 
 963		$this->assertEquals($op->getBookId(), $opinions[0]->getBookId());
 964	}
 965
 966	public function testToArray()
 967	{
 968		$b = new Book();
 969		$b->setTitle('Don Juan');
 970
 971		$arr1 = $b->toArray();
 972		$expectedKeys = array(
 973			'Id',
 974			'Title',
 975			'ISBN',
 976			'Price',
 977			'PublisherId',
 978			'AuthorId'
 979		);
 980		$this->assertEquals($expectedKeys, array_keys($arr1), 'toArray() returns an associative array with BasePeer::TYPE_PHPNAME keys by default');
 981		$this->assertEquals('Don Juan', $arr1['Title'], 'toArray() returns an associative array representation of the object');
 982	}
 983
 984	public function testToArrayKeyType()
 985	{
 986		$b = new Book();
 987		$b->setTitle('Don Juan');
 988	
 989		$arr1 = $b->toArray(BasePeer::TYPE_COLNAME);
 990		$expectedKeys = array(
 991			BookPeer::ID,
 992			BookPeer::TITLE,
 993			BookPeer::ISBN,
 994			BookPeer::PRICE,
 995			BookPeer::PUBLISHER_ID,
 996			BookPeer::AUTHOR_ID
 997		);
 998		$this->assertEquals($expectedKeys, array_keys($arr1), 'toArray() accepts a $keyType parameter to change the result keys');
 999		$this->assertEquals('Don Juan', $arr1[BookPeer::TITLE], 'toArray() returns an associative array representation of the object');
1000	}	
1001
1002	/**
1003	 * Test the toArray() method with new lazyLoad param.
1004	 * @link       http://propel.phpdb.org/trac/ticket/527
1005	 */
1006	public function testToArrayLazyLoad()
1007	{
1008		BookstoreDataPopulator::populate();
1009
1010		$c = new Criteria();
1011		$c->add(MediaPeer::COVER_IMAGE, null, Criteria::NOT_EQUAL);
1012		$c->add(MediaPeer::EXCERPT, null, Criteria::NOT_EQUAL);
1013
1014		$m = MediaPeer::doSelectOne($c);
1015		if ($m === null) {
1016			$this->fail("Test requires at least one media row w/ cover_image and excerpt NOT NULL");
1017		}
1018
1019		$arr1 = $m->toArray(BasePeer::TYPE_COLNAME);
1020		$this->assertNotNull($arr1[MediaPeer::COVER_IMAGE]);
1021		$this->assertType('resource', $arr1[MediaPeer::COVER_IMAGE]);
1022
1023		$arr2 = $m->toArray(BasePeer::TYPE_COLNAME, false);
1024		$this->assertNull($arr2[MediaPeer::COVER_IMAGE]);
1025		$this->assertNull($arr2[MediaPeer::EXCERPT]);
1026
1027		$diffKeys = array_keys(array_diff($arr1, $arr2));
1028
1029		$expectedDiff = array(MediaPeer::COVER_IMAGE, MediaPeer::EXCERPT);
1030
1031		$this->assertEquals($expectedDiff, $diffKeys);
1032	}
1033	
1034	public function testToArrayIncludeForeignObjects()
1035	{
1036		BookstoreDataPopulator::populate();
1037		BookPeer::clearInstancePool();
1038		AuthorPeer::clearInstancePool();
1039		PublisherPeer::clearInstancePool();
1040		
1041		$c = new Criteria();
1042		$c->add(BookPeer::TITLE, 'Don Juan');
1043		$books = BookPeer::doSelectJoinAuthor($c);
1044		$book = $books[0];
1045		
1046		$arr1 = $book->toArray(BasePeer::TYPE_PHPNAME, null, true);
1047		$expectedKeys = array(
1048			'Id',
1049			'Title',
1050			'ISBN',
1051			'Price',
1052			'PublisherId',
1053			'AuthorId',
1054			'Author'
1055		);
1056		$this->assertEquals($expectedKeys, array_keys($arr1), 'toArray() can return sub arrays for hydrated related objects');
1057		$this->assertEquals('George', $arr1['Author']['FirstName'], 'toArray() can return sub arrays for hydrated related objects');
1058
1059		$c = new Criteria();
1060		$c->add(BookPeer::TITLE, 'Don Juan');
1061		$books = BookPeer::doSelectJoinAll($c);
1062		$book = $books[0];
1063
1064		$arr2 = $book->toArray(BasePeer::TYPE_PHPNAME, null, true);
1065		$expectedKeys = array(
1066			'Id',
1067			'Title',
1068			'ISBN',
1069			'Price',
1070			'PublisherId',
1071			'AuthorId',
1072			'Publisher',
1073			'Author'
1074		);
1075		$this->assertEquals($expectedKeys, array_keys($arr2), 'toArray() can return sub arrays for hydrated related objects');
1076	}
1077
1078	/**
1079	 * Test regexp validator for ticket:542
1080	 * @link       http://propel.phpdb.org/trac/ticket/542
1081	 */
1082	public function testRegexValidator()
1083	{
1084		$b = new Bookstore();
1085		$b->setWebsite("http://this.is.valid.com/foo.bar");
1086		$res = $b->validate();
1087		$this->assertTrue($res, "Expected URL to validate");
1088	}
1089
1090	/**
1091	 * Test that setting the auto-increment primary key will result in exception.
1092	 */
1093	public function testSettingAutoIncrementPK()
1094	{
1095	  // The whole test is in a transaction, but this test needs real transactions
1096	  $this->con->commit();
1097
1098		$b = new Bookstore();
1099		$b->setId(1);
1100		$b->setStoreName("Test");
1101		try {
1102			$b->save();
1103			$this->fail("Expected setting auto-increment primary key to result in Exception");
1104		} catch (Exception $x) {
1105			$this->assertType('PropelException', $x);
1106		}
1107
1108		// ... but we should silently ignore NULL values, since these are really
1109		// the same as "not set" in PHP world.
1110		$b = new Bookstore();
1111		$b->setId(null);
1112		$b->setStoreName("Test2");
1113		try {
1114			$b->save();
1115		} catch (Exception $x) {
1116			$this->fail("Expected no exception when setting auto-increment primary key to NULL");
1117		}
1118		// success ...
1119		
1120		$this->con->beginTransaction();
1121	}
1122	
1123	/**
1124	 * Checks wether we are allowed to specify the primary key on a 
1125	 * table with allowPkInsert=true set
1126	 *
1127	 * saves the object, gets it from data-source again and then compares
1128	 * them for equality (thus the instance pool is also checked) 
1129	 */
1130	public function testAllowPkInsertOnIdMethodNativeTable()
1131	{
1132		$cu = new Customer;
1133		$cu->setPrimaryKey(100000);
1134		$cu->save();
1135		
1136		$this->assertEquals(100000, $cu->getPrimaryKey());
1137		
1138		$cu2 = CustomerPeer::retrieveByPk(100000);
1139				
1140		$this->assertSame($cu, $cu2);
1141	}
1142	/**
1143	 * Checks if it is allowed to save new, empty objects with a auto increment column
1144	 */
1145	public function testAllowEmptyWithAutoIncrement()
1146	{
1147		$bookreader = new BookReader();
1148		$bookreader->save();
1149				
1150		$this->assertFalse($bookreader->isNew() );
1151	}
1152	
1153	/**
1154	 * Test foreign key relationships based on references to unique cols but not PK.
1155	 * @link       http://propel.phpdb.org/trac/ticket/691
1156	 */
1157	public function testUniqueFkRel()
1158	{
1159		$employee = new BookstoreEmployee();
1160		$employee->setName("Johnny Walker");
1161
1162		$acct = new BookstoreEmployeeAccount();
1163		$acct->setBookstoreEmployee($employee);
1164		$acct->setLogin("test-login");
1165		$acct->save();
1166		$acctId = $acct->getEmployeeId();
1167		
1168		$al = new AcctAuditLog();
1169		$al->setBookstoreEmployeeAccount($acct);
1170		$al->save();
1171		$alId = $al->getId();
1172		
1173		BookstoreEmployeePeer::clearInstancePool();
1174		BookstoreEmployeeAccountPeer::clearInstancePool();
1175		AcctAuditLogPeer::clearInstancePool();
1176		
1177		$al2 = AcctAuditLogPeer::retrieveByPK($alId);
1178		/* @var $al2 AcctAuditLog */
1179		$mapacct = $al2->getBookstoreEmployeeAccount();
1180		$lookupacct = BookstoreEmployeeAccountPeer::retrieveByPK($acctId);
1181		
1182		$logs = $lookupacct->getAcctAuditLogs();
1183		
1184		$this->assertTrue(count($logs) == 1, "Expected 1 audit log result.");
1185		$this->assertEquals($logs[0]->getId(), $al->getId(), "Expected returned audit log to match created audit log.");
1186	}
1187	
1188	public function testIsPrimaryKeyNull()
1189	{
1190		$b = new Book();
1191		$this->assertTrue($b->isPrimaryKeyNull());
1192		$b->setPrimaryKey(123);
1193		$this->assertFalse($b->isPrimaryKeyNull());
1194		$b->setPrimaryKey(null);
1195		$this->assertTrue($b->isPrimaryKeyNull());
1196	}
1197	
1198	public function testIsPrimaryKeyNullCompmosite()
1199	{
1200		$b = new BookOpinion();
1201		$this->assertTrue($b->isPrimaryKeyNull());
1202		$b->setPrimaryKey(array(123, 456));
1203		$this->assertFalse($b->isPrimaryKeyNull());
1204		$b->setPrimaryKey(array(123, null));
1205		$this->assertFalse($b->isPrimaryKeyNull());
1206		$b->setPrimaryKey(array(null, 456));
1207		$this->assertFalse($b->isPrimaryKeyNull());
1208		$b->setPrimaryKey(array(null, null));
1209		$this->assertTrue($b->isPrimaryKeyNull());
1210	}
1211	
1212	public function testAddPrimaryString()
1213	{
1214	  $this->assertFalse(method_exists('Author', '__toString'), 'addPrimaryString() does not add a __toString() method if no column has the primaryString attribute');
1215	  $this->assertTrue(method_exists('Book', '__toString'), 'addPrimaryString() adds a __toString() method if a column has the primaryString attribute');
1216	  $book = new Book();
1217	  $book->setTitle('foo');
1218	  $this->assertEquals((string) $book, 'foo', 'addPrimaryString() adds a __toString() method returning the value of the the first column where primaryString is true');
1219	}
1220
1221	public function testPreInsert()
1222	{
1223		$author = new TestAuthor();
1224		$author->setFirstName("bogus");
1225		$author->setLastName("Lastname");
1226		$author->save();
1227		$this->assertEquals('PreInsertedFirstname', $author->getFirstName());
1228	}
1229
1230	public function testPreUpdate()
1231	{
1232		$author = new TestAuthor();
1233		$author->setFirstName("bogus");
1234		$author->setLastName("Lastname");
1235		$author->save();
1236		$author->setNew(false);
1237		$author->save();
1238		$this->assertEquals('PreUpdatedFirstname', $author->getFirstName());
1239	}
1240
1241	public function testPostInsert()
1242	{
1243		$author = new TestAuthor();
1244		$author->setFirstName("bogus");
1245		$author->setLastName("Lastname");
1246		$author->save();
1247		$this->assertEquals('PostInsertedLastName', $author->getLastName());
1248	}
1249
1250	public function testPostUpdate()
1251	{
1252		$author = new TestAuthor();
1253		$author->setFirstName("bogus");
1254		$author->setLastName("Lastname");
1255		$author->save();
1256		$author->setNew(false);
1257		$author->save();
1258		$this->assertEquals('PostUpdatedLastName', $author->getLastName());
1259	}
1260	
1261	public function testPreSave()
1262	{
1263		$author = new TestAuthor();
1264		$author->setFirstName("bogus");
1265		$author->setLastName("Lastname");
1266		$author->save();
1267		$this->assertEquals('pre@save.com', $author->getEmail());
1268	}
1269
1270	public function testPreSaveFalse()
1271	{
1272		$con = Propel::getConnection(AuthorPeer::DATABASE_NAME);
1273		$author = new TestAuthorSaveFalse();
1274		$author->setFirstName("bogus");
1275		$author->setLastName("Lastname");
1276		$res = $author->save($con);
1277		$this->assertEquals(0, $res);
1278		$this->assertEquals('pre@save.com', $author->getEmail());
1279		$this->assertNotEquals(115, $author->getAge());
1280		$this->assertTrue($author->isNew());
1281		$this->assertEquals(1, $con->getNestedTransactionCount());
1282	}
1283
1284	public function testPostSave()
1285	{
1286		$author = new TestAuthor();
1287		$author->setFirstName("bogus");
1288		$author->setLastName("Lastname");
1289		$author->save();
1290		$this->assertEquals(115, $author->getAge());
1291	}
1292
1293	public function testPreDelete()
1294	{
1295		$author = new TestAuthor();
1296		$author->setFirstName("bogus");
1297		$author->setLastName("Lastname");
1298		$author->save();
1299		$author->delete();
1300		$this->assertEquals("Pre-Deleted", $author->getFirstName());
1301	}
1302
1303	public function testPreDeleteFalse()
1304	{
1305		$con = Propel::getConnection(AuthorPeer::DATABASE_NAME);
1306		$author = new TestAuthorDeleteFalse();
1307		$author->setFirstName("bogus");
1308		$author->setLastName("Lastname");
1309		$author->save($con);
1310		$author->delete($con);
1311		$this->assertEquals("Pre-Deleted", $author->getFirstName());
1312		$this->assertNotEquals("Post-Deleted", $author->getLastName());
1313		$this->assertFalse($author->isDeleted());
1314		$this->assertEquals(1, $con->getNestedTransactionCount());
1315	}
1316
1317	public function testPostDelete()
1318	{
1319		$author = new TestAuthor();
1320		$author->setFirstName("bogus");
1321		$author->setLastName("Lastname");
1322		$author->save();
1323		$author->delete();
1324		$this->assertEquals("Post-Deleted", $author->getLastName());
1325	}
1326	
1327	public function testMagicVirtualColumnGetter()
1328	{
1329		$book = new Book();
1330		$book->setVirtualColumn('Foo', 'bar');
1331		$this->assertEquals('bar', $book->getFoo(), 'generated __call() catches getters for virtual columns');
1332		$book = new Book();
1333		$book->setVirtualColumn('foo', 'bar');
1334		$this->assertEquals('bar', $book->getFoo(), 'generated __call() catches getters for virtual columns starting with a lowercase character');
1335	}
1336	
1337	public static function conditionsForTestReadOnly()
1338	{
1339		return array(
1340			array('reload'),
1341			array('delete'),
1342			array('save'),
1343			array('doSave'),
1344		);
1345	}
1346	
1347	/**
1348	 * @dataProvider conditionsForTestReadOnly
1349	 */
1350	public function testReadOnly($method)
1351	{
1352		$cv = new ContestView();
1353		$this->assertFalse(method_exists($cv, $method), 'readOnly tables end up with no ' . $method . ' method in the generated object class');
1354	}
1355}