From 16f3bd4e2334491152510598f861a1f6c1ecdae2 Mon Sep 17 00:00:00 2001 From: Frank Karlitschek Date: Wed, 10 Mar 2010 13:03:40 +0100 Subject: commiting ownCloud 1.0 beta 1 --- inc/PHPUnit/GUI/Gtk.php | 698 +++++++++++++++++++++++++++++++++++++ inc/PHPUnit/GUI/HTML.php | 210 +++++++++++ inc/PHPUnit/GUI/SetupDecorator.php | 167 +++++++++ 3 files changed, 1075 insertions(+) create mode 100755 inc/PHPUnit/GUI/Gtk.php create mode 100755 inc/PHPUnit/GUI/HTML.php create mode 100755 inc/PHPUnit/GUI/SetupDecorator.php (limited to 'inc/PHPUnit/GUI') 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 @@ + | +// +----------------------------------------------------------------------+ +// +// $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 @@ +. | +// +------------------------------------------------------------------------+ +// | 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 + * @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]) . "
" . htmlspecialchars(rtrim(ob_get_contents())) . "
"; + // 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]) . "
" . htmlspecialchars(rtrim(ob_get_contents())) . "
"; + 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 @@ +. | +// +------------------------------------------------------------------------+ +// | 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. + * + * + * getSuitesFromDir('/path/to/dir/tests','.*\.php$',array('index.php','sql.php')); + * $gui->show(); + * ?> + * + * + * 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 + * @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: + * getSuitesFromDir($dir,'.*_UnitTest_.*'). + * 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; + } +} +?> -- cgit v1.2.3