diff options
Diffstat (limited to 'inc/PHPUnit')
-rwxr-xr-x | inc/PHPUnit/Assert.php | 384 | ||||
-rwxr-xr-x | inc/PHPUnit/GUI/Gtk.php | 698 | ||||
-rwxr-xr-x | inc/PHPUnit/GUI/HTML.php | 210 | ||||
-rwxr-xr-x | inc/PHPUnit/GUI/SetupDecorator.php | 167 | ||||
-rwxr-xr-x | inc/PHPUnit/RepeatedTest.php | 112 | ||||
-rwxr-xr-x | inc/PHPUnit/Skeleton.php | 406 | ||||
-rwxr-xr-x | inc/PHPUnit/TestCase.php | 237 | ||||
-rwxr-xr-x | inc/PHPUnit/TestDecorator.php | 110 | ||||
-rwxr-xr-x | inc/PHPUnit/TestFailure.php | 88 | ||||
-rwxr-xr-x | inc/PHPUnit/TestListener.php | 120 | ||||
-rwxr-xr-x | inc/PHPUnit/TestResult.php | 300 | ||||
-rwxr-xr-x | inc/PHPUnit/TestSuite.php | 220 |
12 files changed, 3052 insertions, 0 deletions
diff --git a/inc/PHPUnit/Assert.php b/inc/PHPUnit/Assert.php new file mode 100755 index 00000000000..74806458bd3 --- /dev/null +++ b/inc/PHPUnit/Assert.php @@ -0,0 +1,384 @@ +<?php +// +// +------------------------------------------------------------------------+ +// | PEAR :: PHPUnit | +// +------------------------------------------------------------------------+ +// | Copyright (c) 2002-2005 Sebastian Bergmann <sb@sebastian-bergmann.de>. | +// +------------------------------------------------------------------------+ +// | This source file is subject to version 3.00 of the PHP License, | +// | that is available at http://www.php.net/license/3_0.txt. | +// | If you did not receive a copy of the PHP license and are unable to | +// | obtain it through the world-wide-web, please send a note to | +// | license@php.net so we can mail you a copy immediately. | +// +------------------------------------------------------------------------+ +// +// $Id: Assert.php,v 1.25 2005/01/31 04:57:16 sebastian Exp $ +// + +/** + * A set of assert methods. + * + * @author Sebastian Bergmann <sb@sebastian-bergmann.de> + * @copyright Copyright © 2002-2005 Sebastian Bergmann <sb@sebastian-bergmann.de> + * @license http://www.php.net/license/3_0.txt The PHP License, Version 3.0 + * @category Testing + * @package PHPUnit + */ +class PHPUnit_Assert { + /** + * @var boolean + * @access private + */ + var $_looselyTyped = FALSE; + + /** + * Asserts that a haystack contains a needle. + * + * @param mixed + * @param mixed + * @param string + * @access public + * @since 1.1.0 + */ + function assertContains($needle, $haystack, $message = '') { + if (is_string($needle) && is_string($haystack)) { + $this->assertTrue(strpos($haystack, $needle) !== FALSE ? TRUE : FALSE); + } + + else if (is_array($haystack) && !is_object($needle)) { + $this->assertTrue(in_array($needle, $haystack), $message); + } + + else { + $this->fail('Unsupported parameter passed to assertContains().'); + } + } + + /** + * Asserts that a haystack does not contain a needle. + * + * @param mixed + * @param mixed + * @param string + * @access public + * @since 1.1.0 + */ + function assertNotContains($needle, $haystack, $message = '') { + if (is_string($needle) && is_string($haystack)) { + $this->assertFalse(strpos($haystack, $needle) !== FALSE ? TRUE : FALSE); + } + + else if (is_array($haystack) && !is_object($needle)) { + $this->assertFalse(in_array($needle, $haystack), $message); + } + + else { + $this->fail('Unsupported parameter passed to assertNotContains().'); + } + } + + /** + * Asserts that two variables are equal. + * + * @param mixed + * @param mixed + * @param string + * @param mixed + * @access public + */ + function assertEquals($expected, $actual, $message = '', $delta = 0) { + if ((is_array($actual) && is_array($expected)) || + (is_object($actual) && is_object($expected))) { + if (is_array($actual) && is_array($expected)) { + ksort($actual); + ksort($expected); + } + + if ($this->_looselyTyped) { + $actual = $this->_convertToString($actual); + $expected = $this->_convertToString($expected); + } + + $actual = serialize($actual); + $expected = serialize($expected); + + $message = sprintf( + '%sexpected %s, actual %s', + + !empty($message) ? $message . ' ' : '', + $expected, + $actual + ); + + if ($actual !== $expected) { + return $this->fail($message); + } + } + + elseif (is_numeric($actual) && is_numeric($expected)) { + $message = sprintf( + '%sexpected %s%s, actual %s', + + !empty($message) ? $message . ' ' : '', + $expected, + ($delta != 0) ? ('+/- ' . $delta) : '', + $actual + ); + + if (!($actual >= ($expected - $delta) && $actual <= ($expected + $delta))) { + return $this->fail($message); + } + } + + else { + $message = sprintf( + '%sexpected %s, actual %s', + + !empty($message) ? $message . ' ' : '', + $expected, + $actual + ); + + if ($actual !== $expected) { + return $this->fail($message); + } + } + } + + /** + * Asserts that two variables reference the same object. + * This requires the Zend Engine 2 to work. + * + * @param object + * @param object + * @param string + * @access public + * @deprecated + */ + function assertSame($expected, $actual, $message = '') { + if (!version_compare(phpversion(), '5.0.0', '>=')) { + $this->fail('assertSame() only works with PHP >= 5.0.0.'); + } + + if ((is_object($expected) || is_null($expected)) && + (is_object($actual) || is_null($actual))) { + $message = sprintf( + '%sexpected two variables to reference the same object', + + !empty($message) ? $message . ' ' : '' + ); + + if ($expected !== $actual) { + return $this->fail($message); + } + } else { + $this->fail('Unsupported parameter passed to assertSame().'); + } + } + + /** + * Asserts that two variables do not reference the same object. + * This requires the Zend Engine 2 to work. + * + * @param object + * @param object + * @param string + * @access public + * @deprecated + */ + function assertNotSame($expected, $actual, $message = '') { + if (!version_compare(phpversion(), '5.0.0', '>=')) { + $this->fail('assertNotSame() only works with PHP >= 5.0.0.'); + } + + if ((is_object($expected) || is_null($expected)) && + (is_object($actual) || is_null($actual))) { + $message = sprintf( + '%sexpected two variables to reference different objects', + + !empty($message) ? $message . ' ' : '' + ); + + if ($expected === $actual) { + return $this->fail($message); + } + } else { + $this->fail('Unsupported parameter passed to assertNotSame().'); + } + } + + /** + * Asserts that a variable is not NULL. + * + * @param mixed + * @param string + * @access public + */ + function assertNotNull($actual, $message = '') { + $message = sprintf( + '%sexpected NOT NULL, actual NULL', + + !empty($message) ? $message . ' ' : '' + ); + + if (is_null($actual)) { + return $this->fail($message); + } + } + + /** + * Asserts that a variable is NULL. + * + * @param mixed + * @param string + * @access public + */ + function assertNull($actual, $message = '') { + $message = sprintf( + '%sexpected NULL, actual NOT NULL', + + !empty($message) ? $message . ' ' : '' + ); + + if (!is_null($actual)) { + return $this->fail($message); + } + } + + /** + * Asserts that a condition is true. + * + * @param boolean + * @param string + * @access public + */ + function assertTrue($condition, $message = '') { + $message = sprintf( + '%sexpected TRUE, actual FALSE', + + !empty($message) ? $message . ' ' : '' + ); + + if (!$condition) { + return $this->fail($message); + } + } + + /** + * Asserts that a condition is false. + * + * @param boolean + * @param string + * @access public + */ + function assertFalse($condition, $message = '') { + $message = sprintf( + '%sexpected FALSE, actual TRUE', + + !empty($message) ? $message . ' ' : '' + ); + + if ($condition) { + return $this->fail($message); + } + } + + /** + * Asserts that a string matches a given regular expression. + * + * @param string + * @param string + * @param string + * @access public + */ + function assertRegExp($pattern, $string, $message = '') { + $message = sprintf( + '%s"%s" does not match pattern "%s"', + + !empty($message) ? $message . ' ' : '', + $string, + $pattern + ); + + if (!preg_match($pattern, $string)) { + return $this->fail($message); + } + } + + /** + * Asserts that a string does not match a given regular expression. + * + * @param string + * @param string + * @param string + * @access public + * @since 1.1.0 + */ + function assertNotRegExp($pattern, $string, $message = '') { + $message = sprintf( + '%s"%s" matches pattern "%s"', + + !empty($message) ? $message . ' ' : '', + $string, + $pattern + ); + + if (preg_match($pattern, $string)) { + return $this->fail($message); + } + } + + /** + * Asserts that a variable is of a given type. + * + * @param string $expected + * @param mixed $actual + * @param optional string $message + * @access public + */ + function assertType($expected, $actual, $message = '') { + return $this->assertEquals( + $expected, + gettype($actual), + $message + ); + } + + /** + * Converts a value to a string. + * + * @param mixed $value + * @access private + */ + function _convertToString($value) { + foreach ($value as $k => $v) { + if (is_array($v)) { + $value[$k] = $this->_convertToString($value[$k]); + } else { + settype($value[$k], 'string'); + } + } + + return $value; + } + + /** + * @param boolean $looselyTyped + * @access public + */ + function setLooselyTyped($looselyTyped) { + if (is_bool($looselyTyped)) { + $this->_looselyTyped = $looselyTyped; + } + } + + /** + * Fails a test with the given message. + * + * @param string + * @access protected + * @abstract + */ + function fail($message = '') { /* abstract */ } +} +?> diff --git a/inc/PHPUnit/GUI/Gtk.php b/inc/PHPUnit/GUI/Gtk.php new file mode 100755 index 00000000000..fdd3a9931e5 --- /dev/null +++ b/inc/PHPUnit/GUI/Gtk.php @@ -0,0 +1,698 @@ +<?php +/* vim: set expandtab tabstop=4 shiftwidth=4: */ +// +----------------------------------------------------------------------+ +// | PHP Version 4 | +// +----------------------------------------------------------------------+ +// | Copyright (c) 2004 Scott Mattocks | +// +----------------------------------------------------------------------+ +// | This source file is subject to version 3.0 of the PHP license, | +// | that is bundled with this package in the file LICENSE, and is | +// | available through the world-wide-web at the following url: | +// | http://www.php.net/license/3_0.txt. | +// | If you did not receive a copy of the PHP license and are unable to | +// | obtain it through the world-wide-web, please send a note to | +// | license@php.net so we can mail you a copy immediately. | +// +----------------------------------------------------------------------+ +// | Author: Scott Mattocks <scottmattocks@php.net> | +// +----------------------------------------------------------------------+ +// +// $Id: Gtk.php,v 1.2 2004/11/25 09:06:55 sebastian Exp $ +/** + * GTK GUI interface for PHPUnit. + * + * This class is a PHP port of junit.awtui.testrunner. Documentation + * for junit.awtui.testrunner can be found at + * http://junit.sourceforge.net + * + * Due to the limitations of PHP4 and PHP-Gtk, this class can not + * duplicate all of the functionality of the JUnit GUI. Some of the + * things this class cannot do include: + * - Reloading the class for each run + * - Stopping the test in progress + * + * To use simply intantiate the class and call main() + * $gtk =& new PHPUnit_GUI_Gtk; + * $gtk->main(); + * + * Once the window has finished loading, you can enter the name of + * a class that has been loaded (include/require some where in your + * code, or you can pass the name of the file containing the class. + * + * You can also load classes using the SetupDecorator class. + * require_once 'PHPUnit/GUI/SetupDecorator.php'; + * require_once 'PHPUnit/GUI/Gtk.php'; + * $gui = new PHPUnit_GUI_SetupDecorator(new PHPUnit_GUI_Gtk()); + * $gui->getSuitesFromDir('/path/to/test','.*\.php$',array('index.php','sql.php')); + * $gui->show(); + * + * @todo Allow file drop. (Gtk_FileDrop) + * + * @author Scott Mattocks + * @copyright Copyright © 2004 Scott Mattocks + * @license PHP 3.0 + * @version @VER@ + * @category PHP + * @package PHPUnit + * @subpackage GUI + */ +class PHPUnit_GUI_Gtk { + + /** + * The main gtk window + * @var object + */ + var $gui; + /** + * The text entry that contains the name of the + * file that holds the test(s)/suite(s). + * @var object + */ + var $suiteField; + /** + * The label that shows the number of tests that + * were run. + * @var object + */ + var $numberOfRuns; + /** + * The label that shows the number of errors that + * were encountered. + * @var object + */ + var $numberOfErrors; + /** + * The label that shows the number of failures + * that were encountered. + * @var object + */ + var $numberOfFailures; + /** + * The label for reporting user messages. + * @var object + */ + var $statusLine; + /** + * The text area for reporting messages from successful + * test runs. (not necessarily successful tests) + * @var object + */ + var $reportArea; + /** + * The text area for reporting errors encountered when + * running tests. + * @var object + */ + var $dumpArea; + /** + * The progress bar indicator. Shows the percentage of + * passed tests. + * @var object + */ + var $progress; + /** + * A checkbox for the user to indicate whether or not they + * would like to see results from all tests or just failures. + * @object + */ + var $showPassed; + + /** + * Constructor. + * + * The constructor checks for the gtk extension and loads it + * if needed. Then it creates the GUI. The GUI is not shown + * nor is the main gtk loop started until main() is called. + * + * @access public + * @param none + * @return void + */ + function PHPUnit_GUI_Gtk() + { + // Check for php-gtk extension. + if (!extension_loaded('gtk')) { + dl( 'php_gtk.' . PHP_SHLIB_SUFFIX); + } + + // Create the interface but don't start the loop + $this->_createUI(); + } + /** + * Start the main gtk loop. + * + * main() first sets the default state of the showPassed + * check box. Next all widgets that are part of the GUI + * are shown. Finally the main gtk loop is started. + * + * @access public + * @param boolean $showPassed + * @return void + */ + function main($showPassed = true) + { + $this->showPassed->set_active($showPassed); + $this->gui->show_all(); + + gtk::main(); + } + /** + * Create the user interface. + * + * The user interface is pretty simple. It consists of a + * menu, text entry, run button, some labels, a progress + * indicator, and a couple of areas for notification of + * any messages. + * + * @access private + * @param none + * @return void + */ + function _createUI() + { + // Create a window. + $window =& new GtkWindow; + $window->set_title('PHPUnit Gtk'); + $window->set_usize(400, -1); + + // Create the main box. + $mainBox =& new GtkVBox; + $window->add($mainBox); + + // Start with the menu. + $mainBox->pack_start($this->_createMenu()); + + // Then add the suite field entry. + $mainBox->pack_start($this->_createSuiteEntry()); + + // Then add the report labels. + $mainBox->pack_start($this->_createReportLabels()); + + // Next add the progress bar. + $mainBox->pack_start($this->_createProgressBar()); + + // Then add the report area and the dump area. + $mainBox->pack_start($this->_createReportAreas()); + + // Finish off with the status line. + $mainBox->pack_start($this->_createStatusLine()); + + // Connect the destroy signal. + $window->connect_object('destroy', array('gtk', 'main_quit')); + + // Assign the member. + $this->gui =& $window; + } + /** + * Create the menu. + * + * The menu is very simple. It an exit menu item, which exits + * the application, and an about menu item, which shows some + * basic information about the application itself. + * + * @access private + * @param none + * @return &object The GtkMenuBar + */ + function &_createMenu() + { + // Create the menu bar. + $menuBar =& new GtkMenuBar; + + // Create the main (only) menu item. + $phpHeader =& new GtkMenuItem('PHPUnit'); + + // Add the menu item to the menu bar. + $menuBar->append($phpHeader); + + // Create the PHPUnit menu. + $phpMenu =& new GtkMenu; + + // Add the menu items + $about =& new GtkMenuItem('About...'); + $about->connect('activate', array(&$this, 'about')); + $phpMenu->append($about); + + $exit =& new GtkMenuItem('Exit'); + $exit->connect_object('activate', array('gtk', 'main_quit')); + $phpMenu->append($exit); + + // Complete the menu. + $phpHeader->set_submenu($phpMenu); + + return $menuBar; + } + /** + * Create the suite entry and related widgets. + * + * The suite entry has some supporting components such as a + * label, the show passed check box and the run button. All + * of these items are packed into two nested boxes. + * + * @access private + * @param none + * @return &object A box that contains all of the suite entry pieces. + */ + function &_createSuiteEntry() + { + // Create the outermost box. + $outerBox =& new GtkVBox; + + // Create the suite label, box, and field. + $suiteLabel =& new GtkLabel('Test class name:'); + $suiteBox =& new GtkHBox; + $this->suiteField =& new GtkEntry; + $this->suiteField->set_text($suiteName != NULL ? $suiteName : ''); + + // Create the button the user will use to start the test. + $runButton =& new GtkButton('Run'); + $runButton->connect_object('clicked', array(&$this, 'run')); + + // Create the check box that lets the user show only failures. + $this->showPassed =& new GtkCheckButton('Show passed tests'); + + // Add the components to their respective boxes. + $suiteLabel->set_alignment(0, 0); + $outerBox->pack_start($suiteLabel); + $outerBox->pack_start($suiteBox); + $outerBox->pack_start($this->showPassed); + + $suiteBox->pack_start($this->suiteField); + $suiteBox->pack_start($runButton); + + return $outerBox; + } + + /** + * Create the labels that tell the user what has happened. + * + * There are three labels, one each for total runs, errors and + * failures. There is also one label for each of these that + * describes what the label is. It could be done with one label + * instead of two but that would make updates much harder. + * + * @access private + * @param none + * @return &object A box containing the labels. + */ + function &_createReportLabels() + { + // Create a box to hold everything. + $labelBox =& new GtkHBox; + + // Create the non-updated labels. + $numberOfRuns =& new GtkLabel('Runs:'); + $numberOfErrors =& new GtkLabel('Errors:'); + $numberOfFailures =& new GtkLabel('Failures:'); + + // Create the labels that will be updated. + // These are asssigned to members to make it easier to + // set their values later. + $this->numberOfRuns =& new GtkLabel(0); + $this->numberOfErrors =& new GtkLabel(0); + $this->numberOfFailures =& new GtkLabel(0); + + // Pack everything in. + $labelBox->pack_start($numberOfRuns); + $labelBox->pack_start($this->numberOfRuns); + $labelBox->pack_start($numberOfErrors); + $labelBox->pack_start($this->numberOfErrors); + $labelBox->pack_start($numberOfFailures); + $labelBox->pack_start($this->numberOfFailures); + + return $labelBox; + } + + /** + * Create the success/failure indicator. + * + * A GtkProgressBar is used to visually indicate how many + * tests were successful compared to how many were not. The + * progress bar shows the percentage of success and will + * change from green to red if there are any failures. + * + * @access private + * @param none + * @return &object The progress bar + */ + function &_createProgressBar() + { + // Create the progress bar. + $this->progress =& new GtkProgressBar(new GtkAdjustment(0, 0, 1, .1, 1, 0)); + + // Set the progress bar to print the percentage. + $this->progress->set_show_text(true); + + return $this->progress; + } + + /** + * Create the report text areas. + * + * The report area consists of one text area for failures, one + * text area for errors and one label for identification purposes. + * All three widgets are packed into a box. + * + * @access private + * @param none + * @return &object The box containing the report areas. + */ + function &_createReportAreas() + { + // Create the containing box. + $reportBox =& new GtkVBox; + + // Create the identification label + $reportLabel =& new GtkLabel('Errors and Failures:'); + $reportLabel->set_alignment(0, 0); + + // Create the scrolled windows for the text areas. + $reportScroll =& new GtkScrolledWindow; + $dumpScroll =& new GtkScrolledWindow; + + // Make the scroll areas big enough. + $reportScroll->set_usize(-1, 150); + $dumpScroll->set_usize(-1, 150); + + // Only show the vertical scroll bar when needed. + // Never show the horizontal scroll bar. + $reportScroll->set_policy(GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC); + $dumpScroll->set_policy(GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC); + + // Create the text areas. + $this->reportArea =& new GtkText; + $this->dumpArea =& new GtkText; + + // Don't let words get broken. + $this->reportArea->set_word_wrap(true); + $this->dumpArea->set_word_wrap(true); + + // Pack everything in. + $reportBox->pack_start($reportLabel); + $reportScroll->add($this->reportArea); + $reportBox->pack_start($reportScroll); + $dumpScroll->add($this->dumpArea); + $reportBox->pack_start($dumpScroll); + + return $reportBox; + } + + /** + * Create a status label. + * + * A status line at the bottom of the application is used + * to notify the user of non-test related messages such as + * failures loading a test suite. + * + * @access private + * @param none + * @return &object The status label. + */ + function &_createStatusLine() + { + // Create the status label. + $this->statusLine =& new GtkLabel(''); + $this->statusLine->set_alignment(0, 0); + + return $this->statusLine; + } + + /** + * Show a popup with information about the application. + * + * The popup should show information about the version, + * the author, the license, where to get the latest + * version and a short description. + * + * @access public + * @param none + * @return void + */ + function about() + { + // Create the new window. + $about =& new GtkWindow; + $about->set_title('About PHPUnit GUI Gtk'); + $about->set_usize(250, -1); + + // Put two vboxes in the hbox. + $vBox =& new GtkVBox; + $about->add($vBox); + + // Create the labels. + $version =& new GtkLabel(" Version: 1.0"); + $license =& new GtkLabel(" License: PHP License v3.0"); + $where =& new GtkLabel(" Download from: http://pear.php.net/PHPUnit/"); + $unitAuth =& new GtkLabel(" PHPUnit Author: Sebastian Bergman"); + $gtkAuth =& new GtkLabel(" Gtk GUI Author: Scott Mattocks"); + + // Align everything to the left + $where->set_alignment(0, .5); + $version->set_alignment(0, .5); + $license->set_alignment(0, .5); + $gtkAuth->set_alignment(0, .5); + $unitAuth->set_alignment(0, .5); + + // Pack everything into the vBox; + $vBox->pack_start($version); + $vBox->pack_start($license); + $vBox->pack_start($where); + $vBox->pack_start($unitAuth); + $vBox->pack_start($gtkAuth); + + // Connect the destroy signal. + $about->connect('destroy', array('gtk', 'true')); + + // Show the goods. + $about->show_all(); + } + + /** + * Load the test suite. + * + * This method tries to load test suite based on the user + * info. If the user passes the name of a tests suite, it + * is instantiated and a new object is returned. If the + * user passes a file that contains a test suite, the class + * is instantiated and a new object is returned. If the user + * passes a file that contains a test case, the test case is + * passed to a new test suite and the new suite object is + * returned. + * + * @access public + * @param string The file that contains a test case/suite or the classname. + * @return &object The new test suite. + */ + function &loadTest(&$file) + { + // Check to see if a class name was given. + if (is_a($file, 'PHPUnit_TestSuite')) { + return $file; + } elseif (class_exists($file)) { + require_once 'PHPUnit/TestSuite.php'; + return new PHPUnit_TestSuite($file); + } + + // Check that the file exists. + if (!@is_readable($file)) { + $this->_showStatus('Cannot find file: ' . $file); + return false; + } + + $this->_showStatus('Loading test suite...'); + + // Instantiate the class. + // If the path is /path/to/test/TestClass.php + // the class name should be test_TestClass + require_once $file; + $className = str_replace(DIRECTORY_SEPARATOR, '_', $file); + $className = substr($className, 0, strpos($className, '.')); + + require_once 'PHPUnit/TestSuite.php'; + return new PHPUnit_TestSuite($className); + } + + /** + * Run the test suite. + * + * This method runs the test suite and updates the messages + * for the user. When finished it changes the status line + * to 'Test Complete' + * + * @access public + * @param none + * @return void + */ + function runTest() + { + // Notify the user that the test is running. + $this->_showStatus('Running Test...'); + + // Run the test. + $result = PHPUnit::run($this->suite); + + // Update the labels. + $this->_setLabelValue($this->numberOfRuns, $result->runCount()); + $this->_setLabelValue($this->numberOfErrors, $result->errorCount()); + $this->_setLabelValue($this->numberOfFailures, $result->failureCount()); + + // Update the progress bar. + $this->_updateProgress($result->runCount(), + $result->errorCount(), + $result->failureCount() + ); + + // Show the errors. + $this->_showFailures($result->errors(), $this->dumpArea); + + // Show the messages from the tests. + if ($this->showPassed->get_active()) { + // Show failures and success. + $this->_showAll($result, $this->reportArea); + } else { + // Show only failures. + $this->_showFailures($result->failures(), $this->reportArea); + } + + // Update the status message. + $this->_showStatus('Test complete'); + } + + /** + * Set the text of a label. + * + * Change the text of a given label. + * + * @access private + * @param widget &$label The label whose value is to be changed. + * @param string $value The new text of the label. + * @return void + */ + function _setLabelValue(&$label, $value) + { + $label->set_text($value); + } + + /** + * The main work of the application. + * + * Load the test suite and then execute the tests. + * + * @access public + * @param none + * @return void + */ + function run() + { + // Load the test suite. + $this->suite =& $this->loadTest($this->suiteField->get_text()); + + // Check to make sure the suite was loaded properly. + if (!is_object($this->suite)) { + // Raise an error. + $this->_showStatus('Could not load test suite.'); + return false; + } + + // Run the tests. + $this->runTest(); + } + + /** + * Update the status message. + * + * @access private + * @param string $status The new message. + * @return void + */ + function _showStatus($status) + { + $this->statusLine->set_text($status); + } + + /** + * Alias for main() + * + * @see main + */ + function show($showPassed = true) + { + $this->main($showPassed); + } + + /** + * Add a suite to the tests. + * + * This method is require by SetupDecorator. It adds a + * suite to the the current set of suites. + * + * @access public + * @param object $testSuite The suite to add. + * @return void + */ + function addSuites($testSuite) + { + if (!is_array($testSuite)) { + settype($testSuite, 'array'); + } + + foreach ($testSuite as $suite) { + + if (is_a($this->suite, 'PHPUnit_TestSuite')) { + $this->suite->addTestSuite($suite->getName()); + } else { + $this->suite =& $this->loadTest($suite); + } + + // Set the suite field. + $text = $this->suiteField->get_text(); + if (empty($text)) { + $this->suiteField->set_text($this->suite->getName()); + } + } + } + + /** + * Show all test messages. + * + * @access private + * @param object The TestResult from the test suite. + * @return void + */ + function _showAll(&$result) + { + // Clear the area first. + $this->reportArea->delete_text(0, -1); + $this->reportArea->insert_text($result->toString(), 0); + } + + /** + * Show failure/error messages in the given text area. + * + * @access private + * @param object &$results The results of the test. + * @param widget &$area The area to show the results in. + */ + function _showFailures(&$results, &$area) + { + $area->delete_text(0, -1); + foreach (array_reverse($results, true) as $result) { + $area->insert_text($result->toString(), 0); + } + } + + /** + * Update the progress indicator. + * + * @access private + * @param integer $runs + * @param integer $errors + * @param integer $failures + * @return void + */ + function _updateProgress($runs, $errors, $failures) + { + $percentage = 1 - (($errors + $failures) / $runs); + $this->progress->set_percentage($percentage); + } +} +?>
\ No newline at end of file diff --git a/inc/PHPUnit/GUI/HTML.php b/inc/PHPUnit/GUI/HTML.php new file mode 100755 index 00000000000..773ab9af9f3 --- /dev/null +++ b/inc/PHPUnit/GUI/HTML.php @@ -0,0 +1,210 @@ +<?php +// +// +------------------------------------------------------------------------+ +// | PEAR :: PHPUnit | +// +------------------------------------------------------------------------+ +// | Copyright (c) 2002-2005 Sebastian Bergmann <sb@sebastian-bergmann.de>. | +// +------------------------------------------------------------------------+ +// | This source file is subject to version 3.00 of the PHP License, | +// | that is available at http://www.php.net/license/3_0.txt. | +// | If you did not receive a copy of the PHP license and are unable to | +// | obtain it through the world-wide-web, please send a note to | +// | license@php.net so we can mail you a copy immediately. | +// +------------------------------------------------------------------------+ +// +// $Id: HTML.php,v 1.17 2005/01/07 07:34:05 sebastian Exp $ +// + +/** + * This class provides a HTML GUI. + * + * @author Wolfram Kriesing <wolfram@kriesing.de> + * @license http://www.php.net/license/3_0.txt The PHP License, Version 3.0 + * @category Testing + * @package PHPUnit + * @subpackage GUI + */ +class PHPUnit_GUI_HTML +{ + var $_suites = array(); + + /** + * the current implementation of PHPUnit is designed + * this way that adding a suite to another suite only + * grabs all the tests and adds them to the suite, so you + * have no chance to find out which test goes with which suite + * therefore you can simply pass an array of suites to this constructor here + * + * @param array The suites to be tested. If not given, then you might + * be using the SetupDecorator, which detects them automatically + * when calling getSuitesFromDir() + */ + function PHPUnit_GUI_HTML($suites = array()) + { + if (!is_array($suites)) { + $this->_suites = array($suites); + } else { + $this->_suites = $suites; + } + } + + /** + * Add suites to the GUI + * + * @param object this should be an instance of PHPUnit_TestSuite + */ + function addSuites($suites) + { + $this->_suites = array_merge($this->_suites,$suites); + } + + /** + * this prints the HTML code straight out + * + */ + function show() + { + $request = $_REQUEST; + $showPassed = FALSE; + $submitted = @$request['submitted']; + + if ($submitted) { + $showPassed = @$request['showOK'] ? TRUE : FALSE; + } + + $suiteResults = array(); + + foreach ($this->_suites as $aSuite) { + $aSuiteResult = array(); + + // remove the first directory's name from the test-suite name, since it + // mostly is something like 'tests' or alike + $removablePrefix = explode('_',$aSuite->getName()); + $aSuiteResult['name'] = str_replace($removablePrefix[0].'_', '', $aSuite->getName()); + + if ($submitted && isset($request[$aSuiteResult['name']])) { + $result = PHPUnit::run($aSuite); + + $aSuiteResult['counts']['run'] = $result->runCount(); + $aSuiteResult['counts']['error'] = $result->errorCount(); + $aSuiteResult['counts']['failure'] = $result->failureCount(); + + $aSuiteResult['results'] = $this->_prepareResult($result,$showPassed); + + $per = 100/$result->runCount(); + $failed = ($per*$result->errorCount())+($per*$result->failureCount()); + $aSuiteResult['percent'] = round(100-$failed,2); + } else { + $aSuiteResult['addInfo'] = 'NOT EXECUTED'; + } + + $suiteResults[] = $aSuiteResult; + } + + $final['name'] = 'OVERALL RESULT'; + $final['counts'] = array(); + $final['percent'] = 0; + $numExecutedTests = 0; + + foreach ($suiteResults as $aSuiteResult) { + if (sizeof(@$aSuiteResult['counts'])) { + foreach ($aSuiteResult['counts'] as $key=>$aCount) { + if (!isset($final['counts'][$key])) { + $final['counts'][$key] = 0; + } + + $final['counts'][$key] += $aCount; + } + } + } + + if (isset($final['counts']['run'])) { + $per = 100/$final['counts']['run']; + $failed = ($per*$final['counts']['error'])+($per*$final['counts']['failure']); + $final['percent'] = round(100-$failed,2); + } else { + $final['percent'] = 0; + } + + array_unshift($suiteResults,$final); + + include 'PHPUnit/GUI/HTML.tpl'; + } + + function _prepareResult($result,$showPassed) + { + $ret = array(); + $failures = $result->failures(); + + foreach($failures as $aFailure) { + $ret['failures'][] = $this->_prepareFailure($aFailure); + } + + $errors = $result->errors(); + + foreach($errors as $aError) { + $ret['errors'][] = $this->_prepareErrors($aError); + } + + if ($showPassed) { + $passed = $result->passedTests(); + + foreach($passed as $aPassed) { + $ret['passed'][] = $this->_preparePassedTests($aPassed); + } + } + + return $ret; + } + + function _prepareFailure($failure) + { + $test = $failure->failedTest(); + $ret['testName'] = $test->getName(); + $exception = $failure->thrownException(); + + // a serialized string starts with a 'character:decimal:{' + // if so we try to unserialize it + // this piece of the regular expression is for detecting a serialized + // type like 'a:3:' for an array with three element or an object i.e. 'O:12:"class":3' + $serialized = '(\w:\d+:(?:"[^"]+":\d+:)?\{.*\})'; + + // Spaces might make a diff, so we shall show them properly (since a + // user agent ignores them). + if (preg_match('/^(.*)expected ' . $serialized . ', actual ' . $serialized . '$/sU', $exception, $matches)) { + ob_start(); + print_r(unserialize($matches[2])); + $ret['expected'] = htmlspecialchars($matches[1]) . "<pre>" . htmlspecialchars(rtrim(ob_get_contents())) . "</pre>"; + // Improved compatibility, ob_clean() would be PHP >= 4.2.0 only. + ob_end_clean(); + + ob_start(); + print_r(unserialize($matches[3])); + $ret['actual'] = htmlspecialchars($matches[1]) . "<pre>" . htmlspecialchars(rtrim(ob_get_contents())) . "</pre>"; + ob_end_clean(); + } + + else if (preg_match('/^(.*)expected (.*), actual (.*)$/sU', $exception, $matches)) { + $ret['expected'] = nl2br(str_replace(" ", " ", htmlspecialchars($matches[1] . $matches[2]))); + $ret['actual'] = nl2br(str_replace(" ", " ", htmlspecialchars($matches[1] . $matches[3]))); + } else { + $ret['message'] = nl2br(str_replace(" ", " ", htmlspecialchars($exception))); + } + + return $ret; + } + + function _preparePassedTests($passed) + { + $ret['testName'] = $passed->getName(); + return $ret; + } + + function _prepareError($error) + { + $ret['testName'] = $error->getName(); + $ret['message'] = $error->toString(); + return $ret; + } +} +?> diff --git a/inc/PHPUnit/GUI/SetupDecorator.php b/inc/PHPUnit/GUI/SetupDecorator.php new file mode 100755 index 00000000000..73c3d8298e2 --- /dev/null +++ b/inc/PHPUnit/GUI/SetupDecorator.php @@ -0,0 +1,167 @@ +<?php +// +// +------------------------------------------------------------------------+ +// | PEAR :: PHPUnit | +// +------------------------------------------------------------------------+ +// | Copyright (c) 2002-2005 Sebastian Bergmann <sb@sebastian-bergmann.de>. | +// +------------------------------------------------------------------------+ +// | This source file is subject to version 3.00 of the PHP License, | +// | that is available at http://www.php.net/license/3_0.txt. | +// | If you did not receive a copy of the PHP license and are unable to | +// | obtain it through the world-wide-web, please send a note to | +// | license@php.net so we can mail you a copy immediately. | +// +------------------------------------------------------------------------+ +// +// $Id: SetupDecorator.php,v 1.12 2005/05/14 05:58:38 sebastian Exp $ +// + +/** + * This decorator actually just adds the functionality to read the + * test-suite classes from a given directory and instanciate them + * automatically, use it as given in the example below. + * + * <code> + * <?php + * $gui = new PHPUnit_GUI_SetupDecorator(new PHPUnit_GUI_HTML()); + * $gui->getSuitesFromDir('/path/to/dir/tests','.*\.php$',array('index.php','sql.php')); + * $gui->show(); + * ?> + * </code> + * + * The example calls this class and tells it to: + * + * - find all file under the directory /path/to/dir/tests + * - for files, which end with '.php' (this is a piece of a regexp, that's why the . is escaped) + * - and to exclude the files 'index.php' and 'sql.php' + * - and include all the files that are left in the tests. + * + * Given that the path (the first parameter) ends with 'tests' it will be assumed + * that the classes are named tests_* where * is the directory plus the filename, + * according to PEAR standards. + * + * So that: + * + * - 'testMe.php' in the dir 'tests' bill be assumed to contain a class tests_testMe + * - '/moretests/aTest.php' should contain a class 'tests_moretests_aTest' + * + * @author Wolfram Kriesing <wolfram@kriesing.de> + * @license http://www.php.net/license/3_0.txt The PHP License, Version 3.0 + * @category Testing + * @package PHPUnit + * @subpackage GUI + */ +class PHPUnit_GUI_SetupDecorator +{ + /** + * + * + */ + function PHPUnit_GUI_SetupDecorator(&$gui) + { + $this->_gui = &$gui; + } + + /** + * just forwarding the action to the decorated class. + * + */ + function show($showPassed=TRUE) + { + $this->_gui->show($showPassed); + } + + /** + * Setup test suites that can be found in the given directory + * Using the second parameter you can also choose a subsets of the files found + * in the given directory. I.e. only all the files that contain '_UnitTest_', + * in order to do this simply call it like this: + * <code>getSuitesFromDir($dir,'.*_UnitTest_.*')</code>. + * There you can already see that the pattern is built for the use within a regular expression. + * + * @param string the directory where to search for test-suite files + * @param string the pattern (a regexp) by which to find the files + * @param array an array of file names that shall be excluded + */ + function getSuitesFromDir($dir, $filenamePattern = '', $exclude = array()) + { + if ($dir{strlen($dir)-1} == DIRECTORY_SEPARATOR) { + $dir = substr($dir, 0, -1); + } + + $files = $this->_getFiles($dir, $filenamePattern, $exclude, realpath($dir . '/..')); + asort($files); + + foreach ($files as $className => $aFile) { + include_once($aFile); + + if (class_exists($className)) { + $suites[] =& new PHPUnit_TestSuite($className); + } else { + trigger_error("$className could not be found in $dir$aFile!"); + } + } + + $this->_gui->addSuites($suites); + } + + /** + * This method searches recursively through the directories + * to find all the files that shall be added to the be visible. + * + * @param string the path where find the files + * @param srting the string pattern by which to find the files + * @param string the file names to be excluded + * @param string the root directory, which serves as the prefix to the fully qualified filename + * @access private + */ + function _getFiles($dir, $filenamePattern, $exclude, $rootDir) + { + $files = array(); + + if ($dp = opendir($dir)) { + while (FALSE !== ($file = readdir($dp))) { + $filename = $dir . DIRECTORY_SEPARATOR . $file; + $match = TRUE; + + if ($filenamePattern && !preg_match("~$filenamePattern~", $file)) { + $match = FALSE; + } + + if (sizeof($exclude)) { + foreach ($exclude as $aExclude) { + if (strpos($file, $aExclude) !== FALSE) { + $match = FALSE; + break; + } + } + } + + if (is_file($filename) && $match) { + $tmp = str_replace($rootDir, '', $filename); + + if (strpos($tmp, DIRECTORY_SEPARATOR) === 0) { + $tmp = substr($tmp, 1); + } + + if (strpos($tmp, '/') === 0) { + $tmp = substr($tmp, 1); + } + + $className = str_replace(DIRECTORY_SEPARATOR, '_', $tmp); + $className = basename($className, '.php'); + + $files[$className] = $filename; + } + + if ($file != '.' && $file != '..' && is_dir($filename)) { + $files = array_merge($files, $this->_getFiles($filename, $filenamePattern, $exclude, $rootDir)); + } + } + + closedir($dp); + } + + return $files; + } +} +?> diff --git a/inc/PHPUnit/RepeatedTest.php b/inc/PHPUnit/RepeatedTest.php new file mode 100755 index 00000000000..f8cbbc640f6 --- /dev/null +++ b/inc/PHPUnit/RepeatedTest.php @@ -0,0 +1,112 @@ +<?php +// +// +------------------------------------------------------------------------+ +// | PEAR :: PHPUnit | +// +------------------------------------------------------------------------+ +// | Copyright (c) 2002-2005 Sebastian Bergmann <sb@sebastian-bergmann.de>. | +// +------------------------------------------------------------------------+ +// | This source file is subject to version 3.00 of the PHP License, | +// | that is available at http://www.php.net/license/3_0.txt. | +// | If you did not receive a copy of the PHP license and are unable to | +// | obtain it through the world-wide-web, please send a note to | +// | license@php.net so we can mail you a copy immediately. | +// +------------------------------------------------------------------------+ +// +// $Id: RepeatedTest.php,v 1.10 2004/12/22 08:06:11 sebastian Exp $ +// + +require_once 'PHPUnit/TestDecorator.php'; + +/** + * A Decorator that runs a test repeatedly. + * + * Here is an example: + * + * <code> + * <?php + * require_once 'PHPUnit.php'; + * require_once 'PHPUnit/RepeatedTest.php'; + * + * class MathTest extends PHPUnit_TestCase { + * var $fValue1; + * var $fValue2; + * + * function MathTest($name) { + * $this->PHPUnit_TestCase($name); + * } + * + * function setUp() { + * $this->fValue1 = 2; + * $this->fValue2 = 3; + * } + * + * function testAdd() { + * $this->assertTrue($this->fValue1 + $this->fValue2 == 5); + * } + * } + * + * $suite = new PHPUnit_TestSuite; + * + * $suite->addTest( + * new PHPUnit_RepeatedTest( + * new MathTest('testAdd'), + * 10 + * ) + * ); + * + * $result = PHPUnit::run($suite); + * print $result->toString(); + * ?> + * </code> + * + * @author Sebastian Bergmann <sb@sebastian-bergmann.de> + * @copyright Copyright © 2002-2005 Sebastian Bergmann <sb@sebastian-bergmann.de> + * @license http://www.php.net/license/3_0.txt The PHP License, Version 3.0 + * @category Testing + * @package PHPUnit + */ +class PHPUnit_RepeatedTest extends PHPUnit_TestDecorator { + /** + * @var integer + * @access private + */ + var $_timesRepeat = 1; + + /** + * Constructor. + * + * @param object + * @param integer + * @access public + */ + function PHPUnit_RepeatedTest(&$test, $timesRepeat = 1) { + $this->PHPUnit_TestDecorator($test); + $this->_timesRepeat = $timesRepeat; + } + + /** + * Counts the number of test cases that + * will be run by this test. + * + * @return integer + * @access public + */ + function countTestCases() { + return $this->_timesRepeat * $this->_test->countTestCases(); + } + + /** + * Runs the decorated test and collects the + * result in a TestResult. + * + * @param object + * @access public + * @abstract + */ + function run(&$result) { + for ($i = 0; $i < $this->_timesRepeat; $i++) { + $this->_test->run($result); + } + } +} +?> diff --git a/inc/PHPUnit/Skeleton.php b/inc/PHPUnit/Skeleton.php new file mode 100755 index 00000000000..81fe3149066 --- /dev/null +++ b/inc/PHPUnit/Skeleton.php @@ -0,0 +1,406 @@ +<?php +// +// +------------------------------------------------------------------------+ +// | PEAR :: PHPUnit | +// +------------------------------------------------------------------------+ +// | Copyright (c) 2002-2004 Sebastian Bergmann <sb@sebastian-bergmann.de>. | +// +------------------------------------------------------------------------+ +// | This source file is subject to version 3.00 of the PHP License, | +// | that is available at http://www.php.net/license/3_0.txt. | +// | If you did not receive a copy of the PHP license and are unable to | +// | obtain it through the world-wide-web, please send a note to | +// | license@php.net so we can mail you a copy immediately. | +// +------------------------------------------------------------------------+ +// +// $Id: Skeleton.php,v 1.6 2004/12/22 08:06:11 sebastian Exp $ +// + +/** + * Class for creating a PHPUnit_TestCase skeleton file. + * + * This class will take a classname as a parameter on construction and will + * create a PHP file that contains the skeleton of a PHPUnit_TestCase + * subclass. The test case will contain a test foreach method of the class. + * Methods of the parent class will, by default, be excluded from the test + * class. Passing and optional construction parameter will include them. + * + * Example + * + * <?php + * require_once 'PHPUnit/Skeleton.php'; + * $ps = new PHPUnit_Skeleton('PHPUnit_Skeleton', 'PHPUnit/Skeleton.php'); + * + * // Generate the test class. + * // Default settings will not include any parent class methods, but + * // will include private methods. + * $ps->createTestClass(); + * + * // Write the new test class to file. + * // By default, code to run the test will be included. + * $ps->writeTestClass(); + * ?> + * + * Now open the skeleton class and fill in the details. + * If you run the test as is, all tests will fail and + * you will see plenty of undefined constant errors. + * + * @author Scott Mattocks <scott@crisscott.com> + * @copyright Copyright © 2002-2005 Sebastian Bergmann <sb@sebastian-bergmann.de> + * @license http://www.php.net/license/3_0.txt The PHP License, Version 3.0 + * @category Testing + * @package PHPUnit + */ +class PHPUnit_Skeleton { + /** + * Path to the class file to create a skeleton for. + * @var string + */ + var $classPath; + + /** + * The name of the class + * @var string + */ + var $className; + + /** + * Path to the configuration file needed by class to test. + * @var string + */ + var $configFile; + + /** + * Whether or not to include the methods of the parent class when testing. + * @var boolean + */ + var $includeParents; + + /** + * Whether or not to test private methods. + * @var boolean + */ + var $includePrivate; + + /** + * The test class that will be created. + * @var string + */ + var $testClass; + + /** + * Constructor. Sets the class members and check that the class + * to test is accessible. + * + * @access public + * @param string $className + * @param string $classPath + * @param boolean $includeParents Wheter to include the parent's methods in the test. + * @return void + */ + function PHPUnit_Skeleton($className, $classPath, $includeParents = FALSE, $includePrivate = TRUE) { + // Set up the members. + if (@is_readable($classPath)) { + $this->className = $className; + $this->classPath = $classPath; + } else { + $this->_handleErrors($classPath . ' is not readable. Cannot create test class.'); + } + + // Do we want to include parent methods? + $this->includeParents = $includeParents; + + // Do we want to allow private methods? + $this->includePrivate = $includePrivate; + } + + /** + * The class to test may require a special config file before it can be + * instantiated. This method lets you set that file. + * + * @access public + * @param string $configPath + * @return void + */ + function setConfigFile($configFile) { + // Check that the file is readable + if (@is_readable($configFile)) { + $this->configFile = $configFile; + } else { + $this->_handleErrors($configFile . ' is not readable. Cannot create test class.'); + } + } + + /** + * Create the code that will be the skeleton of the test case. + * + * The test case must have a clss definition, one var, a constructor + * setUp, tearDown, and methods. Optionally and by default the code + * to run the test is added when the class is written to file. + * + * @access public + * @param none + * @return void + */ + function createTestClass() { + // Instantiate the object. + if (isset($this->configFile)) { + require_once $this->configFile; + } + + require_once $this->classPath; + + // Get the methods. + $classMethods = get_class_methods($this->className); + + // Remove the parent methods if needed. + if (!$this->includeParents) { + $parentMethods = get_class_methods(get_parent_class($this->className)); + + if (count($parentMethods)) { + $classMethods = array_diff($classMethods, $parentMethods); + } + } + + // Create the class definition, constructor, setUp and tearDown. + $this->_createDefinition(); + $this->_createConstructor(); + $this->_createSetUpTearDown(); + + if (count($classMethods)) { + // Foreach method create a test case. + foreach ($classMethods as $method) { + // Unless it is the constructor. + if (strcasecmp($this->className, $method) !== 0) { + // Check for private methods. + if (!$this->includePrivate && strpos($method, '_') === 0) { + continue; + } else { + $this->_createMethod($method); + } + } + } + } + + // Finis off the class. + $this->_finishClass(); + } + + /** + * Create the class definition. + * + * The definition consist of a header comment, require statment + * for getting the PHPUnit file, the actual class definition, + * and the definition of the class member variable. + * + * All of the code needed for the new class is stored in the + * testClass member. + * + * @access private + * @param none + * @return void + */ + function _createDefinition() { + // Create header comment. + $this->testClass = + "/**\n" . + " * PHPUnit test case for " . $this->className . "\n" . + " * \n" . + " * The method skeletons below need to be filled in with \n" . + " * real data so that the tests will run correctly. Replace \n" . + " * all EXPECTED_VAL and PARAM strings with real data. \n" . + " * \n" . + " * Created with PHPUnit_Skeleton on " . date('Y-m-d') . "\n" . + " */\n"; + + // Add the require statements. + $this->testClass .= "require_once 'PHPUnit.php';\n"; + + // Add the class definition and variable definition. + $this->testClass .= + "class " . $this->className . "Test extends PHPUnit_TestCase {\n\n" . + " var \$" . $this->className . ";\n\n"; + } + + /** + * Create the class constructor. (PHP4 style) + * + * The constructor simply calls the PHPUnit_TestCase method. + * This code is taken from the PHPUnit documentation. + * + * All of the code needed for the new class is stored in the + * testClass member. + * + * @access private + * @param none + * @return void + */ + function _createConstructor() { + // Create the test class constructor. + $this->testClass.= + " function " . $this->className . "Test(\$name)\n" . + " {\n" . + " \$this->PHPUnit_TestCase(\$name);\n" . + " }\n\n"; + } + + /** + * Create setUp and tearDown methods. + * + * The setUp method creates the instance of the object to test. + * The tearDown method releases the instance. + * This code is taken from the PHPUnit documentation. + * + * All of the code needed for the new class is stored in the + * testClass member. + * + * @access private + * @param none + * @return void + */ + function _createSetUpTearDown() { + // Create the setUp method. + $this->testClass .= + " function setUp()\n" . + " {\n"; + + if (isset($this->configFile)) { + $this->testClass .= + " require_once '" . $this->configFile . "';\n"; + } + + $this->testClass .= + " require_once '" . $this->classPath . "';\n" . + " \$this->" . $this->className . " =& new " . $this->className . "(PARAM);\n" . + " }\n\n"; + + // Create the tearDown method. + $this->testClass .= + " function tearDown()\n" . + " {\n" . + " unset(\$this->" . $this->className . ");\n" . + " }\n\n"; + } + + /** + * Create a basic skeleton for test methods. + * + * This code is taken from the PHPUnit documentation. + * + * All of the code needed for the new class is stored in the + * testClass member. + * + * @access private + * @param none + * @return void + */ + function _createMethod($methodName) { + // Create a test method. + $this->testClass .= + " function test" . $methodName . "()\n" . + " {\n" . + " \$result = \$this->" . $this->className . "->" . $methodName . "(PARAM);\n" . + " \$expected = EXPECTED_VAL;\n" . + " \$this->assertEquals(\$expected, \$result);\n" . + " }\n\n"; + } + + /** + * Add the closing brace needed for a proper class definition. + * + * All of the code needed for the new class is stored in the + * testClass member. + * + * @access private + * @param none + * @return void + */ + function _finishClass() { + // Close off the class. + $this->testClass.= "}\n"; + } + + /** + * Create the code that will actually run the test. + * + * This code is added by default so that the test can be run + * just by running the file. To have it not added pass false + * as the second parameter to the writeTestClass method. + * This code is taken from the PHPUnit documentation. + * + * All of the code needed for the new class is stored in the + * testClass member. + * + * @access private + * @param none + * @return void + */ + function _createTest() { + // Create a call to the test. + $test = + "// Running the test.\n" . + "\$suite = new PHPUnit_TestSuite('" . $this->className . "Test');\n" . + "\$result = PHPUnit::run(\$suite);\n" . + "echo \$result->toString();\n"; + + return $test; + } + + /** + * Write the test class to file. + * + * This will write the test class created using the createTestClass + * method to a file called <className>Test.php. By default the file + * is written to the current directory and will have code to run + * the test appended to the bottom of the file. + * + * @access public + * @param string $destination The directory to write the file to. + * @param boolean $addTest Wheter to add the test running code. + * @return void + */ + function writeTestClass($destination = './', $addTest = TRUE) { + // Check for something to write to file. + if (!isset($this->testClass)) { + $this->_handleErrors('Noting to write.', PHPUS_WARNING); + return; + } + + // Open the destination file. + $fp = fopen($destination . $this->className . 'Test.php', 'w'); + fwrite($fp, "<?php\n"); + + // Write the test class. + fwrite($fp, $this->testClass); + + // Add the call to test the class in the file if we were asked to. + if ($addTest) { + fwrite($fp, $this->_createTest()); + } + + // Close the file. + fwrite($fp, "?>\n"); + fclose($fp); + } + + /** + * Error handler. + * + * This method should be rewritten to use the prefered error + * handling method. (PEAR_ErrorStack) + * + * @access private + * @param string $message The error message. + * @param integer $type An indication of the severity of the error. + * @return void Code may cause PHP to exit. + */ + function _handleErrors($message, $type = E_USER_ERROR) { + // For now just echo the message. + echo $message; + + // Check to see if we should quit. + if ($type == E_USER_ERROR) { + exit; + } + } +} +?> diff --git a/inc/PHPUnit/TestCase.php b/inc/PHPUnit/TestCase.php new file mode 100755 index 00000000000..69594ed2f8e --- /dev/null +++ b/inc/PHPUnit/TestCase.php @@ -0,0 +1,237 @@ +<?php +// +// +------------------------------------------------------------------------+ +// | PEAR :: PHPUnit | +// +------------------------------------------------------------------------+ +// | Copyright (c) 2002-2005 Sebastian Bergmann <sb@sebastian-bergmann.de>. | +// +------------------------------------------------------------------------+ +// | This source file is subject to version 3.00 of the PHP License, | +// | that is available at http://www.php.net/license/3_0.txt. | +// | If you did not receive a copy of the PHP license and are unable to | +// | obtain it through the world-wide-web, please send a note to | +// | license@php.net so we can mail you a copy immediately. | +// +------------------------------------------------------------------------+ +// +// $Id: TestCase.php,v 1.16 2004/12/22 08:06:11 sebastian Exp $ +// + +require_once 'PHPUnit/Assert.php'; +require_once 'PHPUnit/TestResult.php'; + +/** + * A TestCase defines the fixture to run multiple tests. + * + * To define a TestCase + * + * 1) Implement a subclass of PHPUnit_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: + * + * <code> + * <?php + * class MathTest extends PHPUnit_TestCase { + * var $fValue1; + * var $fValue2; + * + * function MathTest($name) { + * $this->PHPUnit_TestCase($name); + * } + * + * function setUp() { + * $this->fValue1 = 2; + * $this->fValue2 = 3; + * } + * } + * ?> + * </code> + * + * For each test implement a method which interacts with the fixture. + * Verify the expected results with assertions specified by calling + * assert with a boolean. + * + * <code> + * <?php + * function testPass() { + * $this->assertTrue($this->fValue1 + $this->fValue2 == 5); + * } + * ?> + * </code> + * + * @author Sebastian Bergmann <sb@sebastian-bergmann.de> + * @copyright Copyright © 2002-2005 Sebastian Bergmann <sb@sebastian-bergmann.de> + * @license http://www.php.net/license/3_0.txt The PHP License, Version 3.0 + * @category Testing + * @package PHPUnit + */ +class PHPUnit_TestCase extends PHPUnit_Assert { + /** + * @var boolean + * @access private + */ + var $_failed = FALSE; + + /** + * The name of the test case. + * + * @var string + * @access private + */ + var $_name = ''; + + /** + * PHPUnit_TestResult object + * + * @var object + * @access private + */ + var $_result; + + /** + * Constructs a test case with the given name. + * + * @param string + * @access public + */ + function PHPUnit_TestCase($name = FALSE) { + if ($name !== FALSE) { + $this->setName($name); + } + } + + /** + * Counts the number of test cases executed by run(TestResult result). + * + * @return integer + * @access public + */ + function countTestCases() { + return 1; + } + + /** + * Gets the name of a TestCase. + * + * @return string + * @access public + */ + function getName() { + return $this->_name; + } + + /** + * Runs the test case and collects the results in a given TestResult object. + * + * @param object + * @return object + * @access public + */ + function run(&$result) { + $this->_result = &$result; + $this->_result->run($this); + + return $this->_result; + } + + /** + * Runs the bare test sequence. + * + * @access public + */ + function runBare() { + $this->setUp(); + $this->runTest(); + $this->tearDown(); + $this->pass(); + } + + /** + * Override to run the test and assert its state. + * + * @access protected + */ + function runTest() { + call_user_func( + array( + &$this, + $this->_name + ) + ); + } + + /** + * Sets the name of a TestCase. + * + * @param string + * @access public + */ + function setName($name) { + $this->_name = $name; + } + + /** + * Returns a string representation of the test case. + * + * @return string + * @access public + */ + function toString() { + return ''; + } + + /** + * Creates a default TestResult object. + * + * @return object + * @access protected + */ + function &createResult() { + return new PHPUnit_TestResult; + } + + /** + * Fails a test with the given message. + * + * @param string + * @access protected + */ + function fail($message = '') { + $this->_result->addFailure($this, $message); + $this->_failed = TRUE; + } + + /** + * Passes a test. + * + * @access protected + */ + function pass() { + if (!$this->_failed) { + $this->_result->addPassedTest($this); + } + } + + /** + * Sets up the fixture, for example, open a network connection. + * This method is called before a test is executed. + * + * @access protected + * @abstract + */ + function setUp() { /* abstract */ } + + /** + * Tears down the fixture, for example, close a network connection. + * This method is called after a test is executed. + * + * @access protected + * @abstract + */ + function tearDown() { /* abstract */ } +} +?> diff --git a/inc/PHPUnit/TestDecorator.php b/inc/PHPUnit/TestDecorator.php new file mode 100755 index 00000000000..6486309a70b --- /dev/null +++ b/inc/PHPUnit/TestDecorator.php @@ -0,0 +1,110 @@ +<?php +// +// +------------------------------------------------------------------------+ +// | PEAR :: PHPUnit | +// +------------------------------------------------------------------------+ +// | Copyright (c) 2002-2005 Sebastian Bergmann <sb@sebastian-bergmann.de>. | +// +------------------------------------------------------------------------+ +// | This source file is subject to version 3.00 of the PHP License, | +// | that is available at http://www.php.net/license/3_0.txt. | +// | If you did not receive a copy of the PHP license and are unable to | +// | obtain it through the world-wide-web, please send a note to | +// | license@php.net so we can mail you a copy immediately. | +// +------------------------------------------------------------------------+ +// +// $Id: TestDecorator.php,v 1.12 2005/05/14 05:58:38 sebastian Exp $ +// + +require_once 'PHPUnit/TestCase.php'; +require_once 'PHPUnit/TestSuite.php'; + +/** + * A Decorator for Tests. + * + * Use TestDecorator as the base class for defining new + * test decorators. Test decorator subclasses can be introduced + * to add behaviour before or after a test is run. + * + * @author Sebastian Bergmann <sb@sebastian-bergmann.de> + * @copyright Copyright © 2002-2005 Sebastian Bergmann <sb@sebastian-bergmann.de> + * @license http://www.php.net/license/3_0.txt The PHP License, Version 3.0 + * @category Testing + * @package PHPUnit + */ +class PHPUnit_TestDecorator { + /** + * The Test to be decorated. + * + * @var object + * @access protected + */ + var $_test = NULL; + + /** + * Constructor. + * + * @param object + * @access public + */ + function PHPUnit_TestDecorator(&$test) { + if (is_object($test) && + (is_a($test, 'PHPUnit_TestCase') || + is_a($test, 'PHPUnit_TestSuite'))) { + + $this->_test = &$test; + } + } + + /** + * Runs the test and collects the + * result in a TestResult. + * + * @param object + * @access public + */ + function basicRun(&$result) { + $this->_test->run($result); + } + + /** + * Counts the number of test cases that + * will be run by this test. + * + * @return integer + * @access public + */ + function countTestCases() { + return $this->_test->countTestCases(); + } + + /** + * Returns the test to be run. + * + * @return object + * @access public + */ + function &getTest() { + return $this->_test; + } + + /** + * Runs the decorated test and collects the + * result in a TestResult. + * + * @param object + * @access public + * @abstract + */ + function run(&$result) { /* abstract */ } + + /** + * Returns a string representation of the test. + * + * @return string + * @access public + */ + function toString() { + return $this->_test->toString(); + } +} +?> diff --git a/inc/PHPUnit/TestFailure.php b/inc/PHPUnit/TestFailure.php new file mode 100755 index 00000000000..69c8b80bcbb --- /dev/null +++ b/inc/PHPUnit/TestFailure.php @@ -0,0 +1,88 @@ +<?php +// +// +------------------------------------------------------------------------+ +// | PEAR :: PHPUnit | +// +------------------------------------------------------------------------+ +// | Copyright (c) 2002-2005 Sebastian Bergmann <sb@sebastian-bergmann.de>. | +// +------------------------------------------------------------------------+ +// | This source file is subject to version 3.00 of the PHP License, | +// | that is available at http://www.php.net/license/3_0.txt. | +// | If you did not receive a copy of the PHP license and are unable to | +// | obtain it through the world-wide-web, please send a note to | +// | license@php.net so we can mail you a copy immediately. | +// +------------------------------------------------------------------------+ +// +// $Id: TestFailure.php,v 1.10 2005/05/14 05:58:38 sebastian Exp $ +// + +/** + * A TestFailure collects a failed test together with the caught exception. + * + * @author Sebastian Bergmann <sb@sebastian-bergmann.de> + * @copyright Copyright © 2002-2005 Sebastian Bergmann <sb@sebastian-bergmann.de> + * @license http://www.php.net/license/3_0.txt The PHP License, Version 3.0 + * @category Testing + * @package PHPUnit + */ +class PHPUnit_TestFailure { + /** + * @var object + * @access private + */ + var $_failedTest; + + /** + * @var string + * @access private + */ + var $_thrownException; + + /** + * Constructs a TestFailure with the given test and exception. + * + * @param object + * @param string + * @access public + */ + function PHPUnit_TestFailure(&$failedTest, &$thrownException) { + $this->_failedTest = &$failedTest; + $this->_thrownException = &$thrownException; + } + + /** + * Gets the failed test. + * + * @return object + * @access public + */ + function &failedTest() { + return $this->_failedTest; + } + + /** + * Gets the thrown exception. + * + * @return object + * @access public + */ + function &thrownException() { + return $this->_thrownException; + } + + /** + * Returns a short description of the failure. + * + * @return string + * @access public + */ + function toString() { + return sprintf( + "TestCase %s->%s() failed: %s\n", + + get_class($this->_failedTest), + $this->_failedTest->getName(), + $this->_thrownException + ); + } +} +?> diff --git a/inc/PHPUnit/TestListener.php b/inc/PHPUnit/TestListener.php new file mode 100755 index 00000000000..7685df46792 --- /dev/null +++ b/inc/PHPUnit/TestListener.php @@ -0,0 +1,120 @@ +<?php +// +// +------------------------------------------------------------------------+ +// | PEAR :: PHPUnit | +// +------------------------------------------------------------------------+ +// | Copyright (c) 2002-2005 Sebastian Bergmann <sb@sebastian-bergmann.de>. | +// +------------------------------------------------------------------------+ +// | This source file is subject to version 3.00 of the PHP License, | +// | that is available at http://www.php.net/license/3_0.txt. | +// | If you did not receive a copy of the PHP license and are unable to | +// | obtain it through the world-wide-web, please send a note to | +// | license@php.net so we can mail you a copy immediately. | +// +------------------------------------------------------------------------+ +// +// $Id: TestListener.php,v 1.9 2004/12/22 08:06:11 sebastian Exp $ +// + +/** + * A Listener for test progress. + * + * Here is an example: + * + * <code> + * <?php + * require_once 'PHPUnit.php'; + * require_once 'PHPUnit/TestListener.php'; + * + * class MathTest extends PHPUnit_TestCase { + * var $fValue1; + * var $fValue2; + * + * function MathTest($name) { + * $this->PHPUnit_TestCase($name); + * } + * + * function setUp() { + * $this->fValue1 = 2; + * $this->fValue2 = 3; + * } + * + * function testAdd() { + * $this->assertTrue($this->fValue1 + $this->fValue2 == 4); + * } + * } + * + * class MyListener extends PHPUnit_TestListener { + * function addError(&$test, &$t) { + * print "MyListener::addError() called.\n"; + * } + * + * function addFailure(&$test, &$t) { + * print "MyListener::addFailure() called.\n"; + * } + * + * function endTest(&$test) { + * print "MyListener::endTest() called.\n"; + * } + * + * function startTest(&$test) { + * print "MyListener::startTest() called.\n"; + * } + * } + * + * $suite = new PHPUnit_TestSuite; + * $suite->addTest(new MathTest('testAdd')); + * + * $result = new PHPUnit_TestResult; + * $result->addListener(new MyListener); + * + * $suite->run($result); + * print $result->toString(); + * ?> + * </code> + * + * @author Sebastian Bergmann <sb@sebastian-bergmann.de> + * @copyright Copyright © 2002-2005 Sebastian Bergmann <sb@sebastian-bergmann.de> + * @license http://www.php.net/license/3_0.txt The PHP License, Version 3.0 + * @category Testing + * @package PHPUnit + */ +class PHPUnit_TestListener { + /** + * An error occurred. + * + * @param object + * @param object + * @access public + * @abstract + */ + function addError(&$test, &$t) { /*abstract */ } + + /** + * A failure occurred. + * + * @param object + * @param object + * @access public + * @abstract + */ + function addFailure(&$test, &$t) { /*abstract */ } + + /** + * A test ended. + * + * @param object + * @access public + * @abstract + */ + function endTest(&$test) { /*abstract */ } + + /** + * A test started. + * + * @param object + * @access public + * @abstract + */ + function startTest(&$test) { /*abstract */ } +} +?> diff --git a/inc/PHPUnit/TestResult.php b/inc/PHPUnit/TestResult.php new file mode 100755 index 00000000000..ee60b2c5b50 --- /dev/null +++ b/inc/PHPUnit/TestResult.php @@ -0,0 +1,300 @@ +<?php +// +// +------------------------------------------------------------------------+ +// | PEAR :: PHPUnit | +// +------------------------------------------------------------------------+ +// | Copyright (c) 2002-2005 Sebastian Bergmann <sb@sebastian-bergmann.de>. | +// +------------------------------------------------------------------------+ +// | This source file is subject to version 3.00 of the PHP License, | +// | that is available at http://www.php.net/license/3_0.txt. | +// | If you did not receive a copy of the PHP license and are unable to | +// | obtain it through the world-wide-web, please send a note to | +// | license@php.net so we can mail you a copy immediately. | +// +------------------------------------------------------------------------+ +// +// $Id: TestResult.php,v 1.13 2005/05/14 05:58:38 sebastian Exp $ +// + +require_once 'PHPUnit/TestFailure.php'; +require_once 'PHPUnit/TestListener.php'; + +/** + * A TestResult collects the results of executing a test case. + * + * @author Sebastian Bergmann <sb@sebastian-bergmann.de> + * @copyright Copyright © 2002-2005 Sebastian Bergmann <sb@sebastian-bergmann.de> + * @license http://www.php.net/license/3_0.txt The PHP License, Version 3.0 + * @category Testing + * @package PHPUnit + */ +class PHPUnit_TestResult { + /** + * @var array + * @access protected + */ + var $_errors = array(); + + /** + * @var array + * @access protected + */ + var $_failures = array(); + + /** + * @var array + * @access protected + */ + var $_listeners = array(); + + /** + * @var array + * @access protected + */ + var $_passedTests = array(); + + /** + * @var integer + * @access protected + */ + var $_runTests = 0; + + /** + * @var boolean + * @access private + */ + var $_stop = FALSE; + + /** + * Adds an error to the list of errors. + * The passed in exception caused the error. + * + * @param object + * @param object + * @access public + */ + function addError(&$test, &$t) { + $this->_errors[] = new PHPUnit_TestFailure($test, $t); + + for ($i = 0; $i < sizeof($this->_listeners); $i++) { + $this->_listeners[$i]->addError($test, $t); + } + } + + /** + * Adds a failure to the list of failures. + * The passed in exception caused the failure. + * + * @param object + * @param object + * @access public + */ + function addFailure(&$test, &$t) { + $this->_failures[] = new PHPUnit_TestFailure($test, $t); + + for ($i = 0; $i < sizeof($this->_listeners); $i++) { + $this->_listeners[$i]->addFailure($test, $t); + } + } + + /** + * Registers a TestListener. + * + * @param object + * @access public + */ + function addListener(&$listener) { + if (is_object($listener) && + is_a($listener, 'PHPUnit_TestListener')) { + $this->_listeners[] = &$listener; + } + } + + /** + * Adds a passed test to the list of passed tests. + * + * @param object + * @access public + */ + function addPassedTest(&$test) { + $this->_passedTests[] = &$test; + } + + /** + * Informs the result that a test was completed. + * + * @param object + * @access public + */ + function endTest(&$test) { + for ($i = 0; $i < sizeof($this->_listeners); $i++) { + $this->_listeners[$i]->endTest($test); + } + } + + /** + * Gets the number of detected errors. + * + * @return integer + * @access public + */ + function errorCount() { + return sizeof($this->_errors); + } + + /** + * Returns an Enumeration for the errors. + * + * @return array + * @access public + */ + function &errors() { + return $this->_errors; + } + + /** + * Gets the number of detected failures. + * + * @return integer + * @access public + */ + function failureCount() { + return sizeof($this->_failures); + } + + /** + * Returns an Enumeration for the failures. + * + * @return array + * @access public + */ + function &failures() { + return $this->_failures; + } + + /** + * Returns an Enumeration for the passed tests. + * + * @return array + * @access public + */ + function &passedTests() { + return $this->_passedTests; + } + + /** + * Unregisters a TestListener. + * This requires the Zend Engine 2 (to work properly). + * + * @param object + * @access public + */ + function removeListener(&$listener) { + for ($i = 0; $i < sizeof($this->_listeners); $i++) { + if ($this->_listeners[$i] === $listener) { + unset($this->_listeners[$i]); + } + } + } + + /** + * Runs a TestCase. + * + * @param object + * @access public + */ + function run(&$test) { + $this->startTest($test); + $this->_runTests++; + $test->runBare(); + $this->endTest($test); + } + + /** + * Gets the number of run tests. + * + * @return integer + * @access public + */ + function runCount() { + return $this->_runTests; + } + + /** + * Checks whether the test run should stop. + * + * @access public + */ + function shouldStop() { + return $this->_stop; + } + + /** + * Informs the result that a test will be started. + * + * @param object + * @access public + */ + function startTest(&$test) { + for ($i = 0; $i < sizeof($this->_listeners); $i++) { + $this->_listeners[$i]->startTest($test); + } + } + + /** + * Marks that the test run should stop. + * + * @access public + */ + function stop() { + $this->_stop = TRUE; + } + + /** + * Returns a HTML representation of the test result. + * + * @return string + * @access public + */ + function toHTML() { + return '<pre>' . htmlspecialchars($this->toString()) . '</pre>'; + } + + /** + * Returns a text representation of the test result. + * + * @return string + * @access public + */ + function toString() { + $result = ''; + + foreach ($this->_passedTests as $passedTest) { + $result .= sprintf( + "TestCase %s->%s() passed\n", + + get_class($passedTest), + $passedTest->getName() + ); + } + + foreach ($this->_failures as $failedTest) { + $result .= $failedTest->toString(); + } + + return $result; + } + /** + * Returns whether the entire test was successful or not. + * + * @return boolean + * @access public + */ + function wasSuccessful() { + if (empty($this->_errors) && empty($this->_failures)) { + return TRUE; + } else { + return FALSE; + } + } +} +?> diff --git a/inc/PHPUnit/TestSuite.php b/inc/PHPUnit/TestSuite.php new file mode 100755 index 00000000000..f2396748ba3 --- /dev/null +++ b/inc/PHPUnit/TestSuite.php @@ -0,0 +1,220 @@ +<?php +// +// +------------------------------------------------------------------------+ +// | PEAR :: PHPUnit | +// +------------------------------------------------------------------------+ +// | Copyright (c) 2002-2005 Sebastian Bergmann <sb@sebastian-bergmann.de>. | +// +------------------------------------------------------------------------+ +// | This source file is subject to version 3.00 of the PHP License, | +// | that is available at http://www.php.net/license/3_0.txt. | +// | If you did not receive a copy of the PHP license and are unable to | +// | obtain it through the world-wide-web, please send a note to | +// | license@php.net so we can mail you a copy immediately. | +// +------------------------------------------------------------------------+ +// +// $Id: TestSuite.php,v 1.14 2005/05/14 05:58:38 sebastian Exp $ +// + +require_once 'PHPUnit/TestCase.php'; + +/** + * A TestSuite is a Composite of Tests. It runs a collection of test cases. + * + * Here is an example using the dynamic test definition. + * + * <code> + * <?php + * $suite = new PHPUnit_TestSuite(); + * $suite->addTest(new MathTest('testPass')); + * ?> + * </code> + * + * Alternatively, a TestSuite can extract the tests to be run automatically. + * To do so you pass the classname of your TestCase class to the TestSuite + * constructor. + * + * <code> + * <?php + * $suite = new TestSuite('classname'); + * ?> + * </code> + * + * This constructor creates a suite with all the methods starting with + * "test" that take no arguments. + * + * @author Sebastian Bergmann <sb@sebastian-bergmann.de> + * @copyright Copyright © 2002-2005 Sebastian Bergmann <sb@sebastian-bergmann.de> + * @license http://www.php.net/license/3_0.txt The PHP License, Version 3.0 + * @category Testing + * @package PHPUnit + */ +class PHPUnit_TestSuite { + /** + * The name of the test suite. + * + * @var string + * @access private + */ + var $_name = ''; + + /** + * The tests in the test suite. + * + * @var array + * @access private + */ + var $_tests = array(); + + /** + * Constructs a TestSuite. + * + * @param mixed + * @access public + */ + function PHPUnit_TestSuite($test = FALSE) { + if ($test !== FALSE) { + $this->setName($test); + $this->addTestSuite($test); + } + } + + /** + * Adds a test to the suite. + * + * @param object + * @access public + */ + function addTest(&$test) { + $this->_tests[] = &$test; + } + + /** + * Adds the tests from the given class to the suite. + * + * @param string + * @access public + */ + function addTestSuite($testClass) { + if (class_exists($testClass)) { + $methods = get_class_methods($testClass); + $parentClasses = array(strtolower($testClass)); + $parentClass = $testClass; + + while(is_string($parentClass = get_parent_class($parentClass))) { + $parentClasses[] = $parentClass; + } + + foreach ($methods as $method) { + if (substr($method, 0, 4) == 'test' && + !in_array($method, $parentClasses)) { + $this->addTest(new $testClass($method)); + } + } + } + } + + /** + * Counts the number of test cases that will be run by this test. + * + * @return integer + * @access public + */ + function countTestCases() { + $count = 0; + + foreach ($this->_tests as $test) { + $count += $test->countTestCases(); + } + + return $count; + } + + /** + * Returns the name of the suite. + * + * @return string + * @access public + */ + function getName() { + return $this->_name; + } + + /** + * Runs the tests and collects their result in a TestResult. + * + * @param object + * @access public + */ + function run(&$result) { + for ($i = 0; $i < sizeof($this->_tests) && !$result->shouldStop(); $i++) { + $this->_tests[$i]->run($result); + } + } + + /** + * Runs a test. + * + * @param object + * @param object + * @access public + */ + function runTest(&$test, &$result) { + $test->run($result); + } + + /** + * Sets the name of the suite. + * + * @param string + * @access public + */ + function setName($name) { + $this->_name = $name; + } + + /** + * Returns the test at the given index. + * + * @param integer + * @return object + * @access public + */ + function &testAt($index) { + if (isset($this->_tests[$index])) { + return $this->_tests[$index]; + } else { + return FALSE; + } + } + + /** + * Returns the number of tests in this suite. + * + * @return integer + * @access public + */ + function testCount() { + return sizeof($this->_tests); + } + + /** + * Returns the tests as an enumeration. + * + * @return array + * @access public + */ + function &tests() { + return $this->_tests; + } + + /** + * Returns a string representation of the test suite. + * + * @return string + * @access public + */ + function toString() { + return ''; + } +} +?> |