* Copyright 2005-2010, Cake Software Foundation, Inc. (http://cakefoundation.org) * * Licensed under The Open Group Test Suite License * Redistributions of files must retain the above copyright notice. * * @copyright Copyright 2005-2010, Cake Software Foundation, Inc. (http://cakefoundation.org) * @link http://book.cakephp.org/view/1196/Testing CakePHP(tm) Tests * @package cake * @subpackage cake.cake.tests.lib * @since CakePHP(tm) v 1.2.0.4433 * @license http://www.opensource.org/licenses/opengroup.php The Open Group Test Suite License */ define('CORE_TEST_CASES', TEST_CAKE_CORE_INCLUDE_PATH . 'tests' . DS . 'cases'); define('CORE_TEST_GROUPS', TEST_CAKE_CORE_INCLUDE_PATH . 'tests' . DS . 'groups'); define('APP_TEST_CASES', TESTS . 'cases'); define('APP_TEST_GROUPS', TESTS . 'groups'); /** * TestManager is the base class that handles loading and initiating the running * of TestCase and TestSuite classes that the user has selected. * * @package cake * @subpackage cake.cake.tests.lib */ class TestManager { /** * Extension suffix for test case files. * * @var string */ var $_testExtension = '.test.php'; /** * Extension suffix for group test case files. * * @var string */ var $_groupExtension = '.group.php'; /** * Is this test an AppTest? * * @var boolean */ var $appTest = false; /** * Is this test a plugin test? * * @var mixed boolean false or string name of the plugin being used. */ var $pluginTest = false; /** * Constructor for the TestManager class * * @return void * @access public */ function TestManager() { $this->_installSimpleTest(); if (isset($_GET['app'])) { $this->appTest = true; } if (isset($_GET['plugin'])) { $this->pluginTest = htmlentities($_GET['plugin']); } } /** * Includes the required simpletest files in order for the testsuite to run * * @return void * @access public */ function _installSimpleTest() { App::import('Vendor', array( 'simpletest' . DS . 'unit_tester', 'simpletest' . DS . 'mock_objects', 'simpletest' . DS . 'web_tester' )); require_once(CAKE_TESTS_LIB . 'cake_web_test_case.php'); require_once(CAKE_TESTS_LIB . 'cake_test_case.php'); } /** * Runs all tests in the Application depending on the current appTest setting * * @param Object $reporter Reporter object for the tests being run. * @param boolean $testing Are tests supposed to be auto run. Set to true to return testcase list. * @return mixed * @access public */ function runAllTests(&$reporter, $testing = false) { $testCases =& $this->_getTestFileList($this->_getTestsPath()); if ($this->appTest) { $test =& new TestSuite(__('All App Tests', true)); } else if ($this->pluginTest) { $test =& new TestSuite(sprintf(__('All %s Plugin Tests', true), Inflector::humanize($this->pluginTest))); } else { $test =& new TestSuite(__('All Core Tests', true)); } if ($testing) { return $testCases; } foreach ($testCases as $testCase) { $test->addTestFile($testCase); } return $test->run($reporter); } /** * Runs a specific test case file * * @param string $testCaseFile Filename of the test to be run. * @param Object $reporter Reporter instance to attach to the test case. * @param boolean $testing Set to true if testing, otherwise test case will be run. * @return mixed Result of test case being run. * @access public */ function runTestCase($testCaseFile, &$reporter, $testing = false) { $testCaseFileWithPath = $this->_getTestsPath() . DS . $testCaseFile; if (!file_exists($testCaseFileWithPath) || strpos($testCaseFileWithPath, '..')) { trigger_error( sprintf(__("Test case %s cannot be found", true), htmlentities($testCaseFile)), E_USER_ERROR ); return false; } if ($testing) { return true; } $test =& new TestSuite(sprintf(__('Individual test case: %s', true), $testCaseFile)); $test->addTestFile($testCaseFileWithPath); return $test->run($reporter); } /** * Runs a specific group test file * * @param string $groupTestName GroupTest that you want to run. * @param Object $reporter Reporter instance to use with the group test being run. * @return mixed Results of group test being run. * @access public */ function runGroupTest($groupTestName, &$reporter) { $filePath = $this->_getTestsPath('groups') . DS . strtolower($groupTestName) . $this->_groupExtension; if (!file_exists($filePath) || strpos($filePath, '..')) { trigger_error(sprintf( __("Group test %s cannot be found at %s", true), htmlentities($groupTestName), htmlentities($filePath) ), E_USER_ERROR ); } require_once $filePath; $test =& new TestSuite(sprintf(__('%s group test', true), $groupTestName)); foreach ($this->_getGroupTestClassNames($filePath) as $groupTest) { $testCase = new $groupTest(); $test->addTestCase($testCase); if (isset($testCase->label)) { $test->_label = $testCase->label; } } return $test->run($reporter); } /** * Adds all testcases in a given directory to a given GroupTest object * * @param object $groupTest Instance of TestSuite/GroupTest that files are to be added to. * @param string $directory The directory to add tests from. * @return void * @access public * @static */ function addTestCasesFromDirectory(&$groupTest, $directory = '.') { $manager =& new TestManager(); $testCases =& $manager->_getTestFileList($directory); foreach ($testCases as $testCase) { $groupTest->addTestFile($testCase); } } /** * Adds a specific test file and thereby all of its test cases and group tests to a given group test file * * @param object $groupTest Instance of TestSuite/GroupTest that a file should be added to. * @param string $file The file name, minus the suffix to add. * @return void * @access public * @static */ function addTestFile(&$groupTest, $file) { $manager =& new TestManager(); if (file_exists($file . $manager->_testExtension)) { $file .= $manager->_testExtension; } elseif (file_exists($file . $manager->_groupExtension)) { $file .= $manager->_groupExtension; } $groupTest->addTestFile($file); } /** * Returns a list of test cases found in the current valid test case path * * @access public * @static */ function &getTestCaseList() { $manager =& new TestManager(); $return = $manager->_getTestCaseList($manager->_getTestsPath()); return $return; } /** * Builds the list of test cases from a given directory * * @param string $directory Directory to get test case list from. * @access protected */ function &_getTestCaseList($directory = '.') { $fileList =& $this->_getTestFileList($directory); $testCases = array(); foreach ($fileList as $testCaseFile) { $testCases[$testCaseFile] = str_replace($directory . DS, '', $testCaseFile); } return $testCases; } /** * Returns a list of test files from a given directory * * @param string $directory Directory to get test case files from. * @access protected */ function &_getTestFileList($directory = '.') { $return = $this->_getRecursiveFileList($directory, array(&$this, '_isTestCaseFile')); return $return; } /** * Returns a list of group tests found in the current valid test case path * * @access public * @static */ function &getGroupTestList() { $manager =& new TestManager(); $return = $manager->_getTestGroupList($manager->_getTestsPath('groups')); return $return; } /** * Returns a list of group test files from a given directory * * @param string $directory The directory to get group test files from. * @access protected */ function &_getTestGroupFileList($directory = '.') { $return = $this->_getRecursiveFileList($directory, array(&$this, '_isTestGroupFile')); return $return; } /** * Returns a list of group test files from a given directory * * @param string $directory The directory to get group tests from. * @access protected */ function &_getTestGroupList($directory = '.') { $fileList =& $this->_getTestGroupFileList($directory); $groupTests = array(); foreach ($fileList as $groupTestFile) { $groupTests[$groupTestFile] = str_replace($this->_groupExtension, '', basename($groupTestFile)); } sort($groupTests); return $groupTests; } /** * Returns a list of class names from a group test file * * @param string $groupTestFile The groupTest file to scan for TestSuite classnames. * @access protected */ function &_getGroupTestClassNames($groupTestFile) { $file = implode("\n", file($groupTestFile)); preg_match("~lass\s+?(.*)\s+?extends TestSuite~", $file, $matches); if (!empty($matches)) { unset($matches[0]); return $matches; } $matches = array(); return $matches; } /** * Gets a recursive list of files from a given directory and matches then against * a given fileTestFunction, like isTestCaseFile() * * @param string $directory The directory to scan for files. * @param mixed $fileTestFunction * @access protected */ function &_getRecursiveFileList($directory = '.', $fileTestFunction) { $fileList = array(); if (!is_dir($directory)) { return $fileList; } $files = glob($directory . DS . '*'); $files = $files ? $files : array(); foreach ($files as $file) { if (is_dir($file)) { $fileList = array_merge($fileList, $this->_getRecursiveFileList($file, $fileTestFunction)); } elseif ($fileTestFunction[0]->$fileTestFunction[1]($file)) { $fileList[] = $file; } } return $fileList; } /** * Tests if a file has the correct test case extension * * @param string $file * @return boolean Whether $file is a test case. * @access protected */ function _isTestCaseFile($file) { return $this->_hasExpectedExtension($file, $this->_testExtension); } /** * Tests if a file has the correct group test extension * * @param string $file * @return boolean Whether $file is a group * @access protected */ function _isTestGroupFile($file) { return $this->_hasExpectedExtension($file, $this->_groupExtension); } /** * Check if a file has a specific extension * * @param string $file * @param string $extension * @return void * @access protected */ function _hasExpectedExtension($file, $extension) { return $extension == strtolower(substr($file, (0 - strlen($extension)))); } /** * Returns the given path to the test files depending on a given type of tests (cases, group, ..) * * @param string $type either 'cases' or 'groups' * @return string The path tests are located on * @access protected */ function _getTestsPath($type = 'cases') { if (!empty($this->appTest)) { if ($type == 'cases') { $result = APP_TEST_CASES; } else if ($type == 'groups') { $result = APP_TEST_GROUPS; } } else if (!empty($this->pluginTest)) { $_pluginBasePath = APP . 'plugins' . DS . $this->pluginTest . DS . 'tests'; $pluginPath = App::pluginPath($this->pluginTest); if (file_exists($pluginPath . DS . 'tests')) { $_pluginBasePath = $pluginPath . DS . 'tests'; } $result = $_pluginBasePath . DS . $type; } else { if ($type == 'cases') { $result = CORE_TEST_CASES; } else if ($type == 'groups') { $result = CORE_TEST_GROUPS; } } return $result; } /** * Get the extension for either 'group' or 'test' types. * * @param string $type Type of test to get, either 'test' or 'group' * @return string Extension suffix for test. * @access public */ function getExtension($type = 'test') { if ($type == 'test' || $type == 'case') { return $this->_testExtension; } return $this->_groupExtension; } }