. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * * Neither the name of Sebastian Bergmann nor the names of his * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. * * @category Testing * @package PHPUnit * @author Sebastian Bergmann * @copyright 2002-2008 Sebastian Bergmann * @license http://www.opensource.org/licenses/bsd-license.php BSD License * @version SVN: $Id: TestCase.php 2135 2008-01-17 10:45:15Z sb $ * @link http://www.phpunit.de/ * @since File available since Release 2.0.0 */ require_once 'PHPUnit/Framework.php'; require_once 'PHPUnit/Framework/MockObject/Mock.php'; require_once 'PHPUnit/Framework/MockObject/Matcher/InvokedAtLeastOnce.php'; require_once 'PHPUnit/Framework/MockObject/Matcher/InvokedAtIndex.php'; require_once 'PHPUnit/Framework/MockObject/Matcher/InvokedCount.php'; require_once 'PHPUnit/Framework/MockObject/Stub.php'; require_once 'PHPUnit/Runner/BaseTestRunner.php'; require_once 'PHPUnit/Util/Filter.php'; PHPUnit_Util_Filter::addFileToFilter(__FILE__, 'PHPUNIT'); if (! class_exists('PHPUnit_Framework_TestCase', FALSE)) { /** * A TestCase defines the fixture to run multiple tests. * * To define a TestCase * * 1) Implement a subclass of PHPUnit_Framework_TestCase. * 2) Define instance variables that store the state of the fixture. * 3) Initialize the fixture state by overriding setUp(). * 4) Clean-up after a test by overriding tearDown(). * * Each test runs in its own fixture so there can be no side effects * among test runs. * * Here is an example: * * * value1 = 2; * $this->value2 = 3; * } * } * ?> * * * For each test implement a method which interacts with the fixture. * Verify the expected results with assertions specified by calling * assert with a boolean. * * * assertTrue($this->value1 + $this->value2 == 5); * } * ?> * * * @category Testing * @package PHPUnit * @author Sebastian Bergmann * @copyright 2002-2008 Sebastian Bergmann * @license http://www.opensource.org/licenses/bsd-license.php BSD License * @version Release: 3.2.9 * @link http://www.phpunit.de/ * @since Class available since Release 2.0.0 * @abstract */ abstract class PHPUnit_Framework_TestCase extends PHPUnit_Framework_Assert implements PHPUnit_Framework_Test, PHPUnit_Framework_SelfDescribing { /** * Enable or disable the backup and restoration of the $GLOBALS array. * Overwrite this attribute in a child class of TestCase. * Setting this attribute in setUp() has no effect! * * @var boolean * @access protected */ protected $backupGlobals = TRUE; /** * Enable or disable creating the $GLOBALS reference that is required * for the "global" keyword to work correctly. * Overwrite this attribute in a child class of TestCase. * Setting this attribute in setUp() has no effect! * * @var boolean * @access protected */ protected $createGlobalsReference = FALSE; /** * @var array * @access protected */ protected $data = array(); /** * @var string * @access protected */ protected $dataName = ''; /** * The name of the expected Exception. * * @var mixed * @access protected */ protected $expectedException = NULL; /** * The message of the expected Exception. * * @var string * @access protected */ protected $expectedExceptionMessage = ''; /** * Fixture that is shared between the tests of a test suite. * * @var mixed * @access protected */ protected $sharedFixture; /** * The name of the test case. * * @var string * @access protected */ protected $name = NULL; /** * @var Exception * @access protected */ protected $exception = NULL; /** * @var string * @access protected */ protected $exceptionMessage = NULL; /** * @var integer * @access protected */ protected $exceptionCode = 0; /** * @var Array * @access protected */ protected $iniSettings = array(); /** * @var Array * @access protected */ protected $locale = array(); /** * @var Array * @access protected */ protected $mockObjects = array(); /** * Constructs a test case with the given name. * * @param string $name * @param array $data * @param string $dataName * @access public */ public function __construct($name = NULL, array $data = array(), $dataName = '') { if ($name !== NULL) { $this->setName($name); } $this->data = $data; $this->dataName = $dataName; } /** * Returns a string representation of the test case. * * @return string * @access public */ public function toString() { $class = new ReflectionClass($this); $buffer = sprintf('%s(%s)', $this->getName(), $class->name); if (! empty($this->data)) { if (is_string($this->dataName)) { $buffer .= sprintf(' with data set "%s"', $this->dataName); } else { $buffer .= sprintf(' with data set #%d (%s)', $this->dataName, $this->dataToString($this->data)); } } return $buffer; } /** * Counts the number of test cases executed by run(TestResult result). * * @return integer * @access public */ public function count() { return 1; } /** * Gets the name of a TestCase. * * @return string * @access public */ public function getName() { return $this->name; } /** * @return string * @access public * @since Method available since Release 3.2.0 */ public function getExpectedException() { return $this->expectedException; } /** * @param mixed $exceptionName * @param string $exceptionMessage * @param integer $exceptionCode * @access public * @since Method available since Release 3.2.0 */ public function setExpectedException($exceptionName, $exceptionMessage = '', $exceptionCode = 0) { $this->expectedException = $exceptionName; $this->expectedExceptionMessage = $exceptionMessage; $this->expectedExceptionCode = $exceptionCode; } /** * Returns the status of this test. * * @return integer * @since Method available since Release 3.1.0 */ public function getStatus() { if ($this->exception === NULL) { return PHPUnit_Runner_BaseTestRunner::STATUS_PASSED; } if ($this->exception instanceof PHPUnit_Framework_IncompleteTest) { return PHPUnit_Runner_BaseTestRunner::STATUS_INCOMPLETE; } if ($this->exception instanceof PHPUnit_Framework_SkippedTest) { return PHPUnit_Runner_BaseTestRunner::STATUS_SKIPPED; } if ($this->exception instanceof PHPUnit_Framework_AssertionFailedError) { return PHPUnit_Runner_BaseTestRunner::STATUS_FAILURE; } return PHPUnit_Runner_BaseTestRunner::STATUS_ERROR; } /** * Returns whether or not this test has failed. * * @return boolean * @since Method available since Release 3.0.0 */ public function hasFailed() { $status = $this->getStatus(); return $status == PHPUnit_Runner_BaseTestRunner::STATUS_FAILURE || $status == PHPUnit_Runner_BaseTestRunner::STATUS_ERROR; } /** * Runs the test case and collects the results in a TestResult object. * If no TestResult object is passed a new one will be created. * * @param PHPUnit_Framework_TestResult $result * @return PHPUnit_Framework_TestResult * @throws InvalidArgumentException * @access public */ public function run(PHPUnit_Framework_TestResult $result = NULL) { if ($result === NULL) { $result = $this->createResult(); } $result->run($this); return $result; } /** * Runs the bare test sequence. * * @access public */ public function runBare() { // Backup the $GLOBALS array. if ($this->backupGlobals === TRUE) { $globalsBackup = serialize($GLOBALS); } // Set up the fixture. $this->setUp(); // Run the test. try { // Assert pre-conditions. $this->assertPreConditions(); $this->runTest(); // Assert post-conditions. $this->assertPostConditions(); // Verify Mock Object conditions. foreach ($this->mockObjects as $mockObject) { $mockObject->verify(); } $this->mockObjects = array(); } catch (Exception $e) { $this->exception = $e; } // Tear down the fixture. $this->tearDown(); // Restore the $GLOBALS array. if ($this->backupGlobals === TRUE) { $GLOBALS = unserialize($globalsBackup); if ($this->createGlobalsReference) { $GLOBALS['GLOBALS'] = &$GLOBALS; } } // Clean up INI settings. foreach ($this->iniSettings as $varName => $oldValue) { ini_set($varName, $oldValue); } $this->iniSettings = array(); // Clean up locale settings. foreach ($this->locale as $category => $locale) { setlocale($category, $locale); } // Clean up stat cache. clearstatcache(); // Workaround for missing "finally". if ($this->exception !== NULL) { throw $this->exception; } } /** * Override to run the test and assert its state. * * @throws RuntimeException * @access protected */ protected function runTest() { if ($this->name === NULL) { throw new RuntimeException('PHPUnit_Framework_TestCase::$name must not be NULL.'); } try { $class = new ReflectionClass($this); $method = $class->getMethod($this->name); } catch (ReflectionException $e) { $this->fail($e->getMessage()); } try { if (empty($this->data)) { $method->invoke($this); } else { $method->invokeArgs($this, $this->data); } } catch (Exception $e) { if (is_string($this->expectedException) && $e instanceof $this->expectedException) { if (is_string($this->expectedExceptionMessage) && ! empty($this->expectedExceptionMessage)) { $this->assertContains($this->expectedExceptionMessage, $e->getMessage()); } if (is_int($this->expectedExceptionCode) && $this->expectedExceptionCode !== 0) { $this->assertEquals($this->expectedExceptionCode, $e->getCode()); } return; } else { throw $e; } } if ($this->expectedException !== NULL) { $this->fail('Expected exception ' . $this->expectedException); } } /** * Sets the name of a TestCase. * * @param string * @access public */ public function setName($name) { $this->name = $name; } /** * Sets the shared fixture. * * @param mixed $sharedFixture * @access public * @since Method available since Release 3.1.0 */ public function setSharedFixture($sharedFixture) { $this->sharedFixture = $sharedFixture; } /** * This method is a wrapper for the ini_set() function that automatically * resets the modified php.ini setting to its original value after the * test is run. * * @param string $varName * @param string $newValue * @throws InvalidArgumentException * @throws RuntimeException * @access protected * @since Method available since Release 3.0.0 */ protected function iniSet($varName, $newValue) { if (! is_string($varName) || ! is_string($newValue)) { throw new InvalidArgumentException(); } $currentValue = ini_set($varName, $newValue); if ($currentValue !== FALSE) { $this->iniSettings[$varName] = $currentValue; } else { throw new RuntimeException(); } } /** * This method is a wrapper for the setlocale() function that automatically * resets the locale to its original value after the test is run. * * @param integer $category * @param string $locale * @throws InvalidArgumentException * @throws RuntimeException * @access protected * @since Method available since Release 3.1.0 */ protected function setLocale() { $args = func_get_args(); if (count($args) < 2) { throw new InvalidArgumentException(); } $category = $args[0]; $locale = $args[1]; if (! in_array($category, array(LC_ALL, LC_COLLATE, LC_CTYPE, LC_MONETARY, LC_NUMERIC, LC_TIME, LC_MESSAGES))) { throw new InvalidArgumentException(); } if (! is_array($locale) && ! is_string($locale)) { throw new InvalidArgumentException(); } $this->locale[$category] = setlocale($category, NULL); $result = call_user_func_array('setlocale', $args); if ($result === FALSE) { throw new RuntimeException('The locale functionality is not implemented on your platform, ' . 'the specified locale does not exist or the category name is ' . 'invalid.'); } } /** * Returns a mock object for the specified class. * * @param string $className * @param array $methods * @param array $arguments * @param string $mockClassName * @param boolean $callOriginalConstructor * @param boolean $callOriginalClone * @param boolean $callAutoload * @return object * @access protected * @since Method available since Release 3.0.0 */ protected function getMock($className, array $methods = array(), array $arguments = array(), $mockClassName = '', $callOriginalConstructor = TRUE, $callOriginalClone = TRUE, $callAutoload = TRUE) { if (! is_string($className) || ! is_string($mockClassName)) { throw new InvalidArgumentException(); } $mock = PHPUnit_Framework_MockObject_Mock::generate($className, $methods, $mockClassName, $callOriginalConstructor, $callOriginalClone, $callAutoload); $mockClass = new ReflectionClass($mock->mockClassName); $mockObject = $mockClass->newInstanceArgs($arguments); $this->mockObjects[] = $mockObject; return $mockObject; } /** * Returns a matcher that matches when the method it is evaluated for * is executed zero or more times. * * @return PHPUnit_Framework_MockObject_Matcher_AnyInvokedCount * @access protected * @since Method available since Release 3.0.0 */ protected function any() { return new PHPUnit_Framework_MockObject_Matcher_AnyInvokedCount(); } /** * Returns a matcher that matches when the method it is evaluated for * is never executed. * * @return PHPUnit_Framework_MockObject_Matcher_InvokedCount * @access protected * @since Method available since Release 3.0.0 */ protected function never() { return new PHPUnit_Framework_MockObject_Matcher_InvokedCount(0); } /** * Returns a matcher that matches when the method it is evaluated for * is executed at least once. * * @return PHPUnit_Framework_MockObject_Matcher_InvokedAtLeastOnce * @access protected * @since Method available since Release 3.0.0 */ protected function atLeastOnce() { return new PHPUnit_Framework_MockObject_Matcher_InvokedAtLeastOnce(); } /** * Returns a matcher that matches when the method it is evaluated for * is executed exactly once. * * @return PHPUnit_Framework_MockObject_Matcher_InvokedCount * @access protected * @since Method available since Release 3.0.0 */ protected function once() { return new PHPUnit_Framework_MockObject_Matcher_InvokedCount(1); } /** * Returns a matcher that matches when the method it is evaluated for * is executed exactly $count times. * * @param integer $count * @return PHPUnit_Framework_MockObject_Matcher_InvokedCount * @access protected * @since Method available since Release 3.0.0 */ protected function exactly($count) { return new PHPUnit_Framework_MockObject_Matcher_InvokedCount($count); } /** * Returns a matcher that matches when the method it is evaluated for * is invoked at the given $index. * * @param integer $index * @return PHPUnit_Framework_MockObject_Matcher_InvokedAtIndex * @access protected * @since Method available since Release 3.0.0 */ protected function at($index) { return new PHPUnit_Framework_MockObject_Matcher_InvokedAtIndex($index); } /** * * * @param mixed $value * @return PHPUnit_Framework_MockObject_Stub_Return * @access protected * @since Method available since Release 3.0.0 */ protected function returnValue($value) { return new PHPUnit_Framework_MockObject_Stub_Return($value); } /** * * * @param Exception $exception * @return PHPUnit_Framework_MockObject_Stub_Exception * @access protected * @since Method available since Release 3.1.0 */ protected function throwException(Exception $exception) { return new PHPUnit_Framework_MockObject_Stub_Exception($exception); } /** * * * @param mixed $value, ... * @return PHPUnit_Framework_MockObject_Stub_ConsecutiveCalls * @access protected * @since Method available since Release 3.0.0 */ protected function onConsecutiveCalls() { $args = func_get_args(); return new PHPUnit_Framework_MockObject_Stub_ConsecutiveCalls($args); } /** * @param mixed $data * @return string * @access protected * @since Method available since Release 3.2.1 */ protected function dataToString($data) { $result = array(); foreach ($data as $_data) { if (is_array($_data)) { $result[] = 'array(' . $this->dataToString($_data) . ')'; } else if (is_object($_data)) { $object = new ReflectionObject($_data); if ($object->hasMethod('__toString')) { $result[] = (string)$_data; } else { $result[] = get_class($_data); } } else if (is_resource($_data)) { $result[] = ''; } else { $result[] = var_export($_data, TRUE); } } return join(', ', $result); } /** * Creates a default TestResult object. * * @return PHPUnit_Framework_TestResult * @access protected */ protected function createResult() { return new PHPUnit_Framework_TestResult(); } /** * Sets up the fixture, for example, open a network connection. * This method is called before a test is executed. * * @access protected */ protected function setUp() {} /** * Performs assertions shared by all tests of a test case. * * This method is called before the execution of a test starts * and after setUp() is called. * * @access protected * @since Method available since Release 3.2.8 */ protected function assertPreConditions() {} /** * Performs assertions shared by all tests of a test case. * * This method is called before the execution of a test ends * and before tearDown() is called. * * @access protected * @since Method available since Release 3.2.8 */ protected function assertPostConditions() { // assertPostConditions() was named sharedAssertions() in // PHPUnit 3.0.0-3.2.7. if (method_exists($this, 'sharedAssertions')) { $this->sharedAssertions(); } } /** * Tears down the fixture, for example, close a network connection. * This method is called after a test is executed. * * @access protected */ protected function tearDown() {} } } ?>