From 07270eb77f4cae99e76668237e246f91de99a0db Mon Sep 17 00:00:00 2001 From: hfuecks Date: Fri, 7 Oct 2005 01:38:37 +0200 Subject: test_suite_kickoff darcs-hash:20051006233837-e96b6-66ac0bf95b0b24fc23921fefaa146e321cebd8c5.gz --- test/README | 84 ++++++++ test/index.php | 173 +++++++++++++++++ test/lib/cli_reporter.php | 92 +++++++++ test/lib/rss_writer_class.php | 370 +++++++++++++++++++++++++++++++++++ test/lib/testmanager.php | 441 ++++++++++++++++++++++++++++++++++++++++++ test/lib/web.inc.php | 48 +++++ test/lib/xml_writer_class.php | 293 ++++++++++++++++++++++++++++ test/remotetests.php | 155 +++++++++++++++ test/rss2html.xsl | 110 +++++++++++ test/runtests.php | 118 +++++++++++ test/tests.css | 27 +++ test/tests.ini | 12 ++ test/webtest-stripper.sh | 41 ++++ 13 files changed, 1964 insertions(+) create mode 100644 test/README create mode 100644 test/index.php create mode 100644 test/lib/cli_reporter.php create mode 100644 test/lib/rss_writer_class.php create mode 100644 test/lib/testmanager.php create mode 100644 test/lib/web.inc.php create mode 100644 test/lib/xml_writer_class.php create mode 100755 test/remotetests.php create mode 100644 test/rss2html.xsl create mode 100755 test/runtests.php create mode 100644 test/tests.css create mode 100644 test/tests.ini create mode 100755 test/webtest-stripper.sh diff --git a/test/README b/test/README new file mode 100644 index 000000000..d651a4a82 --- /dev/null +++ b/test/README @@ -0,0 +1,84 @@ +-------------------------------------------------------------------------------- + Dokuwiki Unit Test Suite +-------------------------------------------------------------------------------- +$Date: 2004/02/14 02:14:50 $ + +Credits: to the WACT team - http://www.phpwact.org, from whom the basis of +this test suite was stolen + +-------------------------------------------------------------------------------- +INSTALLING & SETUP + +1. Grab a copy of the SimpleTest unit testing framework an extract somewhere + + http://www.lastcraft.com/simple_test.php + or + http://sourceforge.net/projects/simpletest + +2. Edit ./tests.ini + + - TEST_ENABLED - set to "1" to allow the test suite to be used + by vistors to your site. Generally best to leave as 0 for + a productive site - running tests alot will hammer the server + Note: you will still be able to run the tests from the command + line even when this is set to 0 + + - WEB_TEST_URL - this is for running "web tests" where SimpleTest + acts as a web browser and executes HTTP requests against pages. + Should point at your Dokuwiki URL e.g. + + http://localhost/dokuwiki + + - PROXY - if you're behind a proxy, specify it here + Note: username / password are optional e.g. + + http://proxyuser:proxypwd@proxy.yourdomain.com:8080 + + - REMOTE_TEST_URL - it's possible to run the full test suite + remotely (over HTTP) with some XML goodness. This should + point at the URL of the test suite you want to test + See the following URL for more info; + http://www.sitepoint.com/blogs/2004/06/15/simple-test-remote-testing/ + + - Simple Test + Update the library_path to point at the directory where you installed + Simple Test + +-------------------------------------------------------------------------------- +RUNNING THE TESTS + +You can run the tests in three ways. From the command line: + + $ ./runtests.php -h + +Using a web browser; + + http://localhost/dokuwiki/test/index.php + +As remote tests run on a remote serveri (specified in tests.ini with REMOTE_TEST_URL) and driven locally from the command line using; + + $ ./remotetests.php -h + + +-------------------------------------------------------------------------------- +ADDING TESTS + +The test cases are kept in the './cases' directory in a directory structure +mirroring that of the Dokuwiki's + +Files with the extension .group.php are group tests (collections of +one or more seperate unit test files) - there should be one group +test per file in Dokuwiki's real directory. + +Individual tests files have the extension .test.php + +To add tests, create a .test.php file in the correct directory under ./cases +Probably best to use one of the existing scripts as a basis + +The test will not be executable via one of the test runners (see above). + +To add it to a group of tests, modify the corresponding .group.php file. + +One exception to the naming convention - files named .webtest.php and +.webgroup.php are run using SimpleTest's browser simulator. + diff --git a/test/index.php b/test/index.php new file mode 100644 index 000000000..b73732712 --- /dev/null +++ b/test/index.php @@ -0,0 +1,173 @@ + 'Simple Test', + 'path' => SIMPLE_TEST)); +} + +function & DW_TESTS_GetReporter() { + static $Reporter = NULL; + if ( !$Reporter ) { + switch ( DW_TESTS_OUTPUT ) { + case DW_TESTS_OUTPUT_XML: + require_once SIMPLE_TEST . 'xml.php'; + $Reporter = new XmlReporter(); + break; + case DW_TESTS_OUTPUT_HTML: + default: + $Reporter = new HTMLReporter(); + break; + } + } + return $Reporter; +} + +function DW_TESTS_PaintRunMore() { + switch ( DW_TESTS_OUTPUT ) { + case DW_TESTS_OUTPUT_XML: + break; + case DW_TESTS_OUTPUT_HTML: + default: + echo "

Run more tests

"; + break; + } +} + +function DW_TESTS_PaintHeader() { + switch ( DW_TESTS_OUTPUT ) { + case DW_TESTS_OUTPUT_XML: + header('Content-Type: text/xml; charset="utf-8"'); + break; + case DW_TESTS_OUTPUT_HTML: + $header = << + + + + + Dokuwiki: Unit Test Suite + + + + +EOD; + echo $header; + default: + break; + } +} + +function DW_TESTS_PaintSuiteHeader() { + switch ( DW_TESTS_OUTPUT ) { + case DW_TESTS_OUTPUT_XML: + break; + case DW_TESTS_OUTPUT_HTML: + default: + echo "

Dokuwiki: Unit Test Suite

\n"; + echo "

Test groups"; + echo " || Test cases"; + echo " || Web Test Groups"; + echo " || Web Test Cases

"; + break; + } +} + +function DW_TESTS_PaintCaseList() { + switch ( DW_TESTS_OUTPUT ) { + case DW_TESTS_OUTPUT_XML: + //echo XMLTestManager::getTestCaseList(TEST_CASES); + break; + case DW_TESTS_OUTPUT_HTML: + default: + //echo HTMLTestManager::getTestCaseList(TEST_CASES); + break; + } +} + +function DW_TESTS_PaintGroupTestList() { + switch ( DW_TESTS_OUTPUT ) { + case DW_TESTS_OUTPUT_XML: + //echo XMLTestManager::getGroupTestList(TEST_GROUPS); + break; + case DW_TESTS_OUTPUT_HTML: + default: + //echo HTMLTestManager::getGroupTestList(TEST_GROUPS); + break; + } +} + +function DW_TESTS_PaintFooter() { + switch ( DW_TESTS_OUTPUT ) { + case DW_TESTS_OUTPUT_XML: + break; + case DW_TESTS_OUTPUT_HTML: + default: + $footer = << + +EOD; + echo $footer; + break; + } +} + +/** OUTPUT STARTS HERE **/ + +// If it's a group test +if (isset($_GET['run'])) { + switch ( $_GET['run'] ) { + /* + TestManager::runGroupTest(ucfirst($_GET['run']), + TEST_GROUPS, + DW_TESTS_GetReporter()); + TestManager::runTestCase($_GET['case'], DW_TESTS_GetReporter()); + DW_TESTS_PaintRunMore(); + */ + default: + TestManager::runAllTests(DW_TESTS_GetReporter()); + break; + } + DW_TESTS_PaintRunMore(); + exit(); +} + +// Else it's the main page +DW_TESTS_PaintHeader(); + +DW_TESTS_PaintSuiteHeader(); + +if (isset($_GET['show']) && $_GET['show'] == 'cases') { + DW_TESTS_PaintCaseList(); +} else { + /* no group specified, so list them all */ + DW_TESTS_PaintGroupTestList(); +} + +DW_TESTS_PaintFooter(); +?> \ No newline at end of file diff --git a/test/lib/cli_reporter.php b/test/lib/cli_reporter.php new file mode 100644 index 000000000..e5eb76697 --- /dev/null +++ b/test/lib/cli_reporter.php @@ -0,0 +1,92 @@ +"); +} + +if (! defined('ST_FAILS_RETURN_CODE')) { + define('ST_FAILS_RETURN_CODE', 1); +} + +if (version_compare(phpversion(), '4.3.0', '<') || + php_sapi_name() == 'cgi') { + define('STDOUT', fopen('php://stdout', 'w')); + define('STDERR', fopen('php://stderr', 'w')); + register_shutdown_function( + create_function('', 'fclose(STDOUT); fclose(STDERR); return true;')); +} + +/** + * Minimal command line test displayer. Writes fail details to STDERR. Returns 0 + * to the shell if all tests pass, ST_FAILS_RETURN_CODE if any test fails. + */ +class CLIReporter extends SimpleReporter { + + var $faildetail_separator = ST_FAILDETAIL_SEPARATOR; + + function CLIReporter($faildetail_separator = NULL) { + $this->SimpleReporter(); + if (! is_null($faildetail_separator)) { + $this->setFailDetailSeparator($faildetail_separator); + } + } + + function setFailDetailSeparator($separator) { + $this->faildetail_separator = $separator; + } + + /** + * Return a formatted faildetail for printing. + */ + function &_paintTestFailDetail(&$message) { + $buffer = ''; + $faildetail = $this->getTestList(); + array_shift($faildetail); + $buffer .= implode($this->faildetail_separator, $faildetail); + $buffer .= $this->faildetail_separator . "$message\n"; + return $buffer; + } + + /** + * Paint fail faildetail to STDERR. + */ + function paintFail($message) { + parent::paintFail($message); + fwrite(STDERR, 'FAIL' . $this->faildetail_separator . + $this->_paintTestFailDetail($message)); + } + + /** + * Paint exception faildetail to STDERR. + */ + function paintException($message) { + parent::paintException($message); + fwrite(STDERR, 'EXCEPTION' . $this->faildetail_separator . + $this->_paintTestFailDetail($message)); + } + + /** + * Paint a footer with test case name, timestamp, counts of fails and + * exceptions. + */ + function paintFooter($test_name) { + $buffer = $this->getTestCaseProgress() . '/' . + $this->getTestCaseCount() . ' test cases complete: '; + + if (0 < ($this->getFailCount() + $this->getExceptionCount())) { + $buffer .= $this->getPassCount() . " passes"; + if (0 < $this->getFailCount()) { + $buffer .= ", " . $this->getFailCount() . " fails"; + } + if (0 < $this->getExceptionCount()) { + $buffer .= ", " . $this->getExceptionCount() . " exceptions"; + } + $buffer .= ".\n"; + fwrite(STDOUT, $buffer); + exit(ST_FAILS_RETURN_CODE); + } else { + fwrite(STDOUT, $buffer . $this->getPassCount() . " passes.\n"); + } + } +} +?> diff --git a/test/lib/rss_writer_class.php b/test/lib/rss_writer_class.php new file mode 100644 index 000000000..7b9beae5f --- /dev/null +++ b/test/lib/rss_writer_class.php @@ -0,0 +1,370 @@ +error=("required ".$scope." property \"".$property."\" is already set"); + return 0; + } + $required[$property]=1; + $required_properties++; + } + else + { + if(IsSet($optional[$property])) + { + if($optional[$property]) + { + $this->error=("optional ".$scope." property \"".$property."\" is already set"); + return 0; + } + $optional[$property]=1; + } + else + { + if(GetType($colon=strpos($property,":",0))=="integer") + { + $namespace=substr($property,0,$colon); + if(!(!strcmp($namespace,"rdf") || IsSet($this->rssnamespaces[$namespace]))) + $this->error=("the name space of property \"".$property."\" was not declared"); + } + else + $this->error=("\"".$property."\" is not a supported ".$scope." property"); + } + } + if(!($this->adddatatag($property,$noattributes,$properties[$property],$parent,$path))) + return 0; + Next($properties); + $end=(GetType($property=Key($properties))!="string"); + } + if($required_propertieserror=("it was not specified the required ".$scope." property \"".$property."\""); + return 0; + } + Next($required); + $end=(GetType($property=Key($required))!="string"); + } + } + return 1; + } + + /* + * Public functions + * + */ + Function addchannel(&$properties) + { + if(strcmp($this->error,"")) + return 0; + if(strcmp($this->channel,"")) + { + $this->error="a channel was already added"; + return 0; + } + $channel_attributes=array(); + switch($this->specification) + { + case "0.9": + $root="rdf:RDF"; + $attributes=array("xmlns:rdf"=>"http://www.w3.org/1999/02/22-rdf-syntax-ns#","xmlns"=>"http://my.netscape.com/rdf/simple/0.9/"); + $required=array("description"=>0,"link"=>0,"title"=>0); + $optional=array(); + break; + case "0.91": + $root="rss"; + $attributes=array("version"=>$this->specification); + $required=array("description"=>0,"language"=>0,"link"=>0,"title"=>0); + $optional=array("copyright"=>0,"docs"=>0,"lastBuildDate"=>0,"managingEditor"=>0,"pubDate"=>0,"rating"=>0,"webMaster"=>0); + break; + case "1.0": + if(!strcmp($this->about,"")) + { + $this->error="it was not specified the about URL attribute"; + return 0; + } + $root="rdf:RDF"; + $attributes=array("xmlns:rdf"=>"http://www.w3.org/1999/02/22-rdf-syntax-ns#","xmlns"=>"http://purl.org/rss/1.0/"); + Reset($this->rssnamespaces); + $end=(GetType($namespace=Key($this->rssnamespaces))!="string"); + for(;!$end;) + { + if(!strcmp($namespace,"rdf")) + { + $this->error="the rdf namespace is being redeclared"; + return 0; + } + $attributes[("xmlns:".$namespace)]=$this->rssnamespaces[$namespace]; + Next($this->rssnamespaces); + $end=(GetType($namespace=Key($this->rssnamespaces))!="string"); + } + $channel_attributes=array("rdf:about"=>$this->about); + $required=array("description"=>0,"link"=>0,"title"=>0); + $optional=array(); + break; + default: + $this->error="it was not specified a supported RSS specification version"; + return 0; + } + $this->addtag($root,$attributes,"",$path,1); + $this->root=$path; + if(!($this->addtag("channel",$channel_attributes,$this->root,$path,1))) + return 0; + if(!($this->addrssproperties($properties,$path,$required,$optional,"channel"))) + return 0; + $this->channel=$path; + return 1; + } + + Function additem(&$properties) + { + if(strcmp($this->error,"")) + return 0; + if(!strcmp($this->channel,"")) + { + $this->error="the channel was not yet added"; + return 0; + } + if(strcmp($this->textinput,"")) + { + $this->error="items can not be added to the channel after defining the textinput"; + return 0; + } + $attributes=array(); + switch($this->specification) + { + case "0.9": + $parent=$this->root; + break; + case "0.91": + $parent=$this->channel; + break; + case "1.0": + if(IsSet($properties["link"])) + $attributes["rdf:about"]=$properties["link"]; + $parent=$this->root; + break; + default: + $this->error="it was not specified a supported RSS specification version"; + return 0; + } + if(!($this->addtag("item",$attributes,$parent,$path,1))) + return 0; + $required=array("link"=>0,"title"=>0); + $optional=array("description"=>0); + if(!($this->addrssproperties($properties,$path,$required,$optional,"item"))) + return 0; + if(!strcmp($this->specification,"1.0")) + { + if(!strcmp($this->itemsequence,"")) + { + $attributes=array(); + if(!($this->addtag("items",$attributes,$this->channel,$path,1) && $this->addtag("rdf:Seq",$attributes,$path,$path,1))) + return 0; + $this->itemsequence=$path; + } + $attributes=array("rdf:resource"=>$properties["link"]); + if(!($this->addtag("rdf:li",$attributes,$this->itemsequence,$path,0))) + return 0; + } + $this->items++; + return 1; + } + + Function addimage(&$properties) + { + if(strcmp($this->error,"")) + return 0; + if(!strcmp($this->channel,"")) + { + $this->error="the channel was not yet added"; + return 0; + } + if(strcmp($this->image,"")) + { + $this->error="the channel image was already associated"; + return 0; + } + if($this->items!=0) + { + $this->error="the image can only be defined before adding the channel items"; + return 0; + } + $attributes=array(); + switch($this->specification) + { + case "0.9": + $parent=$this->root; + break; + case "0.91": + $parent=$this->channel; + break; + case "1.0": + if(IsSet($properties["url"])) + $attributes["rdf:about"]=$properties["url"]; + $parent=$this->root; + break; + default: + $this->error="it was not specified a supported RSS specification version"; + return 0; + } + if(!($this->addtag("image",$attributes,$parent,$path,1))) + return 0; + $this->image=$path; + $required=array("link"=>0,"title"=>0,"url"=>0); + $optional=array("description"=>0,"width"=>0,"height"=>0); + if(!($this->addrssproperties($properties,$this->image,$required,$optional,"image"))) + return 0; + if(!strcmp($this->specification,"1.0")) + { + $attributes=array("rdf:resource"=>$properties["url"]); + return $this->addtag("image",$attributes,$this->channel,$path,0); + } + return 1; + } + + Function addtextinput(&$properties) + { + if(strcmp($this->error,"")) + return 0; + if(!strcmp($this->channel,"")) + { + $this->error="the channel was not yet added"; + return 0; + } + if(strcmp($this->textinput,"")) + { + $this->error="the channel text input was already associated"; + return 0; + } + if($this->items==0 && !$this->allownoitems) + { + $this->error="it were not specified any items before defining the channel text input"; + return 0; + } + $attributes=array(); + switch($this->specification) + { + case "0.9": + $parent=$this->root; + break; + case "0.91": + $parent=$this->channel; + break; + case "1.0": + if(IsSet($properties["link"])) + $attributes["rdf:about"]=$properties["link"]; + $parent=$this->root; + break; + default: + $this->error="it was not specified a supported RSS specification version"; + return 0; + } + if(!($this->addtag("textinput",$attributes,$parent,$path,1))) + return 0; + $this->textinput=$path; + $required=array("description"=>0,"link"=>0,"name"=>0,"title"=>0); + $optional=array(); + if(!($this->addrssproperties($properties,$this->textinput,$required,$optional,"textinput"))) + return 0; + if(!strcmp($this->specification,"1.0")) + { + $attributes=array("rdf:resource"=>$properties["link"]); + return $this->addtag("textinput",$attributes,$this->channel,$path,0); + } + return 1; + } + + Function writerss(&$output) + { + if(strcmp($this->error,"")) + return 0; + if(!strcmp($this->channel,"")) + { + $this->error="it was not defined the RSS channel"; + return 0; + } + if($this->items==0 && !$this->allownoitems) + { + $this->error="it were not defined any RSS channel items"; + return 0; + } + switch($this->specification) + { + case "0.9": + $this->dtdtype="PUBLIC"; + $this->dtddefinition="-//Netscape Communications//DTD RSS 0.9//EN"; + $this->dtdurl="http://my.netscape.com/publish/formats/rss-0.9.dtd"; + break; + case "0.91": + $this->dtdtype="PUBLIC"; + $this->dtddefinition="-//Netscape Communications//DTD RSS 0.91//EN"; + $this->dtdurl="http://my.netscape.com/publish/formats/rss-0.91.dtd"; + break; + case "1.0": + $this->dtdtype=""; + break; + default: + $this->error="it was not specified a supported RSS specification version"; + return 0; + } + return $this->write($output); + } +}; + +} +?> \ No newline at end of file diff --git a/test/lib/testmanager.php b/test/lib/testmanager.php new file mode 100644 index 000000000..6ad53b00d --- /dev/null +++ b/test/lib/testmanager.php @@ -0,0 +1,441 @@ + $value) { + define($key, $value); + } + TestManager::_installSimpleTest(); + } + + function _installSimpleTest() { + require_once SIMPLE_TEST . 'unit_tester.php'; + require_once SIMPLE_TEST . 'web_tester.php'; + require_once SIMPLE_TEST . 'mock_objects.php'; + require_once 'web.inc.php'; + } + + function runAllTests(&$reporter) { + $manager =& new TestManager(); + $test_cases =& $manager->_getTestFileList(); + $test =& new GroupTest('All Tests'); + foreach ($test_cases as $test_case) { + $test->addTestFile($test_case); + } + $test->run($reporter); + } + + function runTestCase($testcase_file, &$reporter) { + $manager =& new TestManager(); + + if (! file_exists($testcase_file)) { + trigger_error("Test case {$testcase_file} cannot be found", + E_USER_ERROR); + } + + $test =& new GroupTest("Individual test case: " . $testcase_file); + $test->addTestFile($testcase_file); + $test->run($reporter); + } + + function runGroupTest($group_test_name, $group_test_directory, &$reporter) { + $manager =& new TestManager(); + + $file_path = $group_test_directory . DIRECTORY_SEPARATOR . + strtolower($group_test_name) . $manager->_grouptest_extension; + + if (! file_exists($file_path)) { + trigger_error("Group test {$group_test_name} cannot be found at {$file_path}", + E_USER_ERROR); + } + + require_once $file_path; + $test =& new GroupTest($group_test_name . ' group test'); + foreach ($manager->_getGroupTestClassNames($file_path) as $group_test) { + $test->addTestCase(new $group_test()); + } + $test->run($reporter); + } + + function addTestCasesFromDirectory(&$group_test, $directory = '.') { + $manager =& new TestManager(); + $test_cases =& $manager->_getTestFileList($directory); + foreach ($test_cases as $test_case) { + $group_test->addTestFile($test_case); + } + } + + function &getTestCaseList($directory = '.') { + $manager =& new TestManager(); + return $manager->_getTestCaseList($directory); + } + + function &_getTestCaseList($directory = '.') { + $file_list =& $this->_getTestFileList($directory); + $testcases = array(); + foreach ($file_list as $testcase_file) { + $testcases[$testcase_file] = str_replace($directory . '/', '', $testcase_file); + } + return $testcases; + } + + function &_getTestFileList($directory = '.') { + return $this->_getRecursiveFileList($directory, + array(&$this, '_isTestCaseFile')); + } + + function &getGroupTestList($directory = '.') { + $manager =& new TestManager(); + return $manager->_getTestGroupList($directory); + } + + function &_getTestGroupFileList($directory = '.') { + return $this->_getRecursiveFileList($directory, + array(&$this, '_isTestGroupFile')); + } + + function &_getTestGroupList($directory = '.') { + $file_list =& $this->_getTestGroupFileList($directory); + $grouptests = array(); + foreach ($file_list as $grouptest_file) { + $grouptests[$grouptest_file] = str_replace($this->_grouptest_extension, '', + basename($grouptest_file)); + } + sort($grouptests); + return $grouptests; + } + + function &_getGroupTestClassNames($grouptest_file) { + $file = implode("\n", file($grouptest_file)); + preg_match("~lass\s+?(.*)\s+?extends GroupTest~", $file, $matches); + if (! empty($matches)) { + unset($matches[0]); + return $matches; + } else { + return array(); + } + } + + function &_getRecursiveFileList($directory = '.', $file_test_function) { + $dh = opendir($directory); + if (! is_resource($dh)) { + trigger_error("Couldn't open {$directory}", E_USER_ERROR); + } + + $file_list = array(); + while ($file = readdir($dh)) { + $file_path = $directory . DIRECTORY_SEPARATOR . $file; + + if (0 === strpos($file, '.')) continue; + + if (is_dir($file_path)) { + $file_list = + array_merge($file_list, + $this->_getRecursiveFileList($file_path, + $file_test_function)); + } + if ($file_test_function[0]->$file_test_function[1]($file)) { + $file_list[] = $file_path; + } + } + closedir($dh); + return $file_list; + } + + function _isTestCaseFile($file) { + return $this->_hasExpectedExtension($file, $this->_testcase_extension); + } + + function _isTestGroupFile($file) { + return $this->_hasExpectedExtension($file, $this->_grouptest_extension); + } + + function _hasExpectedExtension($file, $extension) { + return $extension == + strtolower(substr($file, (0 - strlen($extension)))); + } +} + +/** +* @package WACT_TESTS +*/ +class CLITestManager extends TestManager { + function &getGroupTestList($directory = '.') { + $manager =& new CLITestManager(); + $group_tests =& $manager->_getTestGroupList($directory); + + $buffer = "Available grouptests:\n"; + foreach ($group_tests as $group_test) { + $buffer .= " " . $group_test . "\n"; + } + return $buffer . "\n"; + } + + function &getTestCaseList($directory = '.') { + $manager =& new CLITestManager(); + $test_cases =& $manager->_getTestCaseList($directory); + + $buffer = "Available test cases:\n"; + foreach ($test_cases as $test_case_file => $test_case) { + $buffer .= " " . $test_case_file . "\n"; + } + return $buffer . "\n"; + } +} + +class HTMLTestManager extends TestManager { + var $_url; + + function HTMLTestManager() { + $this->_url = $_SERVER['PHP_SELF']; + } + + function getBaseURL() { + return $this->_url; + } + + function &getGroupTestList($directory = '.') { + $manager =& new HTMLTestManager(); + $group_tests =& $manager->_getTestGroupList($directory); + + if (1 > count($group_tests)) { + return "

No test groups set up!

"; + } + $buffer = "

Available test groups:

\n\n"; + } + + function &getTestCaseList($directory = '.') { + $manager =& new HTMLTestManager(); + $testcases =& $manager->_getTestCaseList($directory); + + if (1 > count($testcases)) { + return "

No test cases set up!

"; + } + $buffer = "

Available test cases:

\n
    "; + foreach ($testcases as $testcase_file => $testcase) { + $buffer .= "
  • " . + $testcase . "
  • \n"; + } + return $buffer . "
\n"; + } +} + +/** +* @package WACT_TESTS +*/ +class XMLTestManager extends HTMLTestManager { + + function XMLTestManager() { + parent::HTMLTestManager(); + } + + function &getGroupTestList($directory = '.') { + + $manager =& new XMLTestManager(); + $group_tests =& $manager->_getTestGroupList($directory); + + $rss = & $manager->_getRssWriter(); + + if (1 > count($group_tests)) { + $rss->writeRss($output); + return $output; + } + + $properties["title"]="All Tests"; + $properties["description"]="All Tests"; + $properties["link"]='http://'.$_SERVER['SERVER_NAME']. + $manager->getBaseURL()."?group=all&output=xml"; + + $rss->additem($properties); + + foreach ($group_tests as $group_test) { + $properties["title"]=$group_test; + $properties["description"]=$group_test; + $properties["link"]='http://'.$_SERVER['SERVER_NAME']. + $manager->getBaseURL(). + "?group={$group_test}&output=xml"; + + $rss->additem($properties); + } + + $rss->writeRss($output); + return $output; + + } + + function &getTestCaseList($directory = '.') { + + $manager =& new XMLTestManager(); + $testcases =& $manager->_getTestCaseList($directory); + + $rss = & $manager->_getRssWriter(); + + if (1 > count($testcases)) { + $rss->writeRss($output); + return $output; + } + + foreach ($testcases as $testcase_file => $testcase) { + $properties["title"]=$testcase; + $properties["description"]=$testcase; + $properties["link"]='http://'.$_SERVER['SERVER_NAME']. + $manager->getBaseURL()."?case=" . + urlencode($testcase_file) . "&output=xml"; + + // Comment this out for performance? + $properties["dc:date"]=gmdate("Y-m-d\TH:i:sO",filemtime($testcase_file)); + + $rss->additem($properties); + } + + $rss->writeRss($output); + return $output; + } + + function &_getRssWriter() { + + $wact_url = 'http://'.$_SERVER['SERVER_NAME'].str_replace('index.php','',$_SERVER['PHP_SELF']); + + require_once TEST_ROOT . '/lib/xml_writer_class.php'; + require_once TEST_ROOT . '/lib/rss_writer_class.php'; + + $rss_writer_object=& new rss_writer_class(); + $rss_writer_object->specification="1.0"; + $rss_writer_object->about=$wact_url."index.php?output=xml"; + $rss_writer_object->stylesheet=$wact_url."rss2html.xsl"; + $rss_writer_object->rssnamespaces["dc"]="http://purl.org/dc/elements/1.1/"; + + // Channel Properties + $properties=array(); + $properties["title"]="WACT Unit Test Cases"; + $properties["description"]="WACT Unit Test Cases"; + $properties["link"]="http://wact.sourceforge.net/"; + $properties["dc:date"]=gmdate("Y-m-d\TH:i:sO"); + $rss_writer_object->addchannel($properties); + + // Logo like this (if we had one) + /* + $properties=array(); + $properties["url"]="http://www.phpclasses.org/graphics/logo.gif"; + $properties["link"]="http://www.phpclasses.org/"; + $properties["title"]="PHP Classes repository logo"; + $properties["description"]="Repository of components and other resources for PHP developers"; + $rss_writer_object->addimage($properties); + */ + + return $rss_writer_object; + } + +} + +/** +* @package WACT_TESTS +*/ +class RemoteTestManager extends TestManager { + + function RemoteTestManager() { + parent::TestManager(); + } + + function _installSimpleTest() { + parent::_installSimpleTest(); + require_once SIMPLE_TEST . 'remote.php'; + } + + function runAllTests(&$reporter, $url = FALSE) { + $groups = RemoteTestManager::getGroupTestList($url); + + $T = &new RemoteTestCase($groups['All Tests']); + $T->run($reporter); + } + + function runTestCase($case_file,& $reporter, $url = FALSE) { + $cases = RemoteTestManager::getTestCaseList($url); + + $T = &new RemoteTestCase($cases[$case_file]); + $T->run($reporter); + } + + function runGroupTest($group_name, &$reporter, $url = FALSE) { + $groups = RemoteTestManager::getGroupTestList($url); + + $T = &new RemoteTestCase($groups[$group_name]); + $T->run($reporter); + } + + function & getGroupTestList($url = FALSE) { + + if ( !$url ) { + $url = REMOTE_TEST_HTTP_PATH; + } + + $url .= '?output=xml'; + + $manager =& new RemoteTestManager(); + $rss = & $manager->_getRssReader($url); + + $groupList = array(); + + foreach ($rss->getItems() as $item) { + $groupList[$item['title']] = $item['link']; + } + + return $groupList; + } + + function &getTestCaseList($url = FALSE) { + if ( !$url ) { + $url = REMOTE_TEST_HTTP_PATH; + } + + $url .= '?show=cases&output=xml'; + + $manager =& new RemoteTestManager(); + $rss = & $manager->_getRssReader($url); + + $caseList = array(); + + foreach ($rss->getItems() as $item) { + $caseList[$item['title']] = $item['link']; + } + + return $caseList; + } + + function &_getRssReader($url) { + require_once "XML/RSS.php"; + + $rss_reader =& new XML_RSS($url); + + $status = $rss_reader->parse(); + + if (PEAR::isError($status) ) { + trigger_error($status->getMessage(),E_USER_WARNING); + } + + return $rss_reader; + } + +} +?> diff --git a/test/lib/web.inc.php b/test/lib/web.inc.php new file mode 100644 index 000000000..88020bd2a --- /dev/null +++ b/test/lib/web.inc.php @@ -0,0 +1,48 @@ +assertResponse(array(200)); + $this->assertNoUnwantedPattern('/Warning:/i'); + $this->assertNoUnwantedPattern('/Error:/i'); + $this->assertNoUnwantedPattern('/Fatal error/i'); + } + + function assertWantedLiteral($str) { + $this->assertWantedPattern('/' . preg_quote($str, '/'). '/'); + } + + function assertNoUnWantedLiteral($str) { + $this->assertNoUnWantedPattern('/' . preg_quote($str, '/'). '/'); + } + + function &_fileToPattern($file) { + $file_as_array = file($file); + $pattern = '#^'; + foreach ($file_as_array as $line) { + /* strip trailing newline */ + if ($line[strlen($line) - 1] == "\n") { + $line = substr($line, 0, strlen($line) - 1); + } + $line = preg_quote($line, '#'); + + /* replace paths with wildcard */ + $line = preg_replace("#'/[^']*#", "'.*", $line); + + $pattern .= $line . '\n'; + } + /* strip final newline */ + $pattern = substr($pattern, 0, strlen($pattern) - 2); + $pattern .= '$#i'; + return $pattern; + } + +} +?> diff --git a/test/lib/xml_writer_class.php b/test/lib/xml_writer_class.php new file mode 100644 index 000000000..d82637e9b --- /dev/null +++ b/test/lib/xml_writer_class.php @@ -0,0 +1,293 @@ +inputencoding,$this->outputencoding)) + $encodeddata=$this->escapedata($data); + else + { + switch(strtolower($this->outputencoding)) + { + case "utf-8": + if(!strcmp(strtolower($this->inputencoding),"iso-8859-1")) + { + $encoded_data=utf8_encode($this->escapedata($data)); + $encodeddata=$encoded_data; + } + else + { + $this->error=("can not encode iso-8859-1 data in ".$this->outputencoding); + return 0; + } + break; + case "iso-8859-1": + if(!strcmp(strtolower($this->inputencoding),"utf-8")) + { + $decoded=utf8_decode($data); + $encodeddata=$this->escapedata($decoded); + } + else + { + $this->error=("can not encode utf-8 data in ".$this->outputencoding); + return 0; + } + break; + default: + $this->error=("can not encode data in ".$this->inputencoding); + return 0; + } + } + return 1; + } + + Function writetag(&$output,$path,$indent) + { + $tag=$this->structure[$path]["Tag"]; + $output.=("<".$tag); + $attributecount=count($this->structure[$path]["Attributes"]); + if($attributecount>0) + { + $attributes=$this->structure[$path]["Attributes"]; + Reset($attributes); + $end=(GetType($key=Key($attributes))!="string"); + for(;!$end;) + { + $output.=(" ".$key."=\"".$attributes[$key]."\""); + Next($attributes); + $end=(GetType($key=Key($attributes))!="string"); + } + } + $elements=$this->structure[$path]["Elements"]; + if($elements>0) + { + $output.=">"; + $doindent=$this->structure[$path]["Indent"]; + $elementindent=(($doindent) ? $this->linebreak.$indent.$this->indenttext : ""); + $element=0; + for(;$element<$elements;) + { + $elementpath=($path.",".strval($element)); + $output.=$elementindent; + if(IsSet($this->nodes[$elementpath])) + { + if(!($this->writetag($output,$elementpath,$indent.$this->indenttext))) + return 0; + } + else + $output.=$this->structure[$elementpath]; + $element++; + } + $output.=((($doindent) ? $this->linebreak.$indent : "").""); + } + else + $output.="/>"; + return 1; + } + + /* + * Public functions + * + */ + Function write(&$output) + { + if(strcmp($this->error,"")) + return 0; + if(!(IsSet($this->structure["0"]))) + { + $this->error="XML document structure is empty"; + return 0; + } + $output=("outputencoding."\"?>".$this->linebreak); + if(strcmp($this->dtdtype,"")) + { + $output.=("structure["0"]["Tag"]." "); + switch($this->dtdtype) + { + case "INTERNAL": + if(!strcmp($this->dtddefinition,"")) + { + $this->error="it was not specified a valid internal DTD definition"; + return 0; + } + $output.=("[".$this->linebreak.$this->dtddefinition.$this->linebreak."]"); + break; + case "SYSTEM": + if(!strcmp($this->dtdurl,"")) + { + $this->error="it was not specified a valid system DTD url"; + return 0; + } + $output.="SYSTEM"; + if(strcmp($this->dtddefinition,"")) + $output.=(" \"".$this->dtddefinition."\""); + $output.=(" \"".$this->dtdurl."\""); + break; + case "PUBLIC": + if(!strcmp($this->dtddefinition,"")) + { + $this->error="it was not specified a valid public DTD definition"; + return 0; + } + $output.=("PUBLIC \"".$this->dtddefinition."\""); + if(strcmp($this->dtdurl,"")) + $output.=(" \"".$this->dtdurl."\""); + break; + default: + $this->error="it was not specified a valid DTD type"; + return 0; + } + $output.=(">".$this->linebreak); + } + if(strcmp($this->stylesheet,"")) + { + if(!strcmp($this->stylesheettype,"")) + { + $this->error="it was not specified a valid stylesheet type"; + return 0; + } + $output.=("stylesheettype."\" href=\"".$this->stylesheet."\"?>".$this->linebreak); + } + if(strcmp($this->generatedcomment,"")) + $output.=("".$this->linebreak); + return $this->writetag($output,"0",""); + } + + Function addtag($tag,&$attributes,$parent,&$path,$indent) + { + if(strcmp($this->error,"")) + return 0; + $path=((!strcmp($parent,"")) ? "0" : ($parent.",".strval($this->structure[$parent]["Elements"]))); + if(IsSet($this->structure[$path])) + { + $this->error=("tag with path ".$path." is already defined"); + return 0; + } + $encodedattributes=array(); + Reset($attributes); + $end=(GetType($attribute_name=Key($attributes))!="string"); + for(;!$end;) + { + $encodedattributes[$attribute_name]=""; + if(!($this->encodedata($attributes[$attribute_name],$encoded_data))) + return 0; + $encodedattributes[$attribute_name]=$encoded_data; + Next($attributes); + $end=(GetType($attribute_name=Key($attributes))!="string"); + } + $this->structure[$path]=array( + "Tag"=>$tag, + "Attributes"=>$encodedattributes, + "Elements"=>0, + "Indent"=>$indent + ); + $this->nodes[$path]=1; + if(strcmp($parent,"")) + $this->structure[$parent]["Elements"]=($this->structure[$parent]["Elements"]+1); + return 1; + } + + Function adddata($data,$parent,&$path) + { + if(strcmp($this->error,"")) + return 0; + if(!(IsSet($this->structure[$parent]))) + { + $this->error=("the parent tag path".$path."is not defined"); + return 0; + } + if(!strcmp($data,"")) + return 1; + $path=($parent.",".strval($this->structure[$parent]["Elements"])); + if(!($this->encodedata($data,$encoded_data))) + return 0; + $this->structure[$path]=$encoded_data; + $this->structure[$parent]["Elements"]=($this->structure[$parent]["Elements"]+1); + return 1; + } + + Function adddatatag($tag,&$attributes,$data,$parent,&$path) + { + return $this->addtag($tag,$attributes,$parent,$path,0) && $this->adddata($data,$path,$datapath); + } +}; + +} +?> \ No newline at end of file diff --git a/test/remotetests.php b/test/remotetests.php new file mode 100755 index 000000000..f4d1af869 --- /dev/null +++ b/test/remotetests.php @@ -0,0 +1,155 @@ +#!/usr/bin/php -q +'; +$opt_group_list = FALSE; +$opt_case_list = FALSE; +$opt_casefile = FALSE; +$opt_groupfile = FALSE; + +/* only allow cmd line options if PEAR Console_Getopt is available */ +@include_once 'Console/Getopt.php'; /* PEAR lib */ +if (class_exists('Console_Getopt')) { + + $argv = Console_Getopt::readPHPArgv(); + if (PEAR::isError($argv)) { + die('Fatal Error: ' . $argv->getMessage()) . "\n"; + } + + $short_opts = "u:f:g:hlcs:p:"; + $long_opts = array( + "help", "url=", "file=", "group=", + "glist", "clist", "separator=", "path=" + ); + $options = Console_Getopt::getopt($argv, $short_opts, $long_opts); + if (PEAR::isError($options)) { + usage($available_grouptests); + } + + foreach ($options[0] as $option) { + switch ($option[0]) { + case 'h': + case '--help': + usage(); + break; + case 'u': + case '--url': + $opt_url = $option[1]; + break; + case 'f': + case '--file': + $opt_casefile = $option[1]; + break; + case 'g': + case '--group': + $opt_groupfile = $option[1]; + break; + case 'l': + case '--glist': + $opt_group_list = TRUE; + break; + case 'c': + case '--clist': + $opt_case_list = TRUE; + break; + case 's': + case '--separator': + $opt_separator = $option[1]; + break; + case 'p': + case '--path': + if (file_exists($option[1])) { + define('SIMPLE_TEST', $option[1]); + } + break; + } + } +} + + +if ( !defined('SIMPLE_TEST') ) { + define('SIMPLE_TEST', ConfigManager::getOptionAsPath('tests', 'simpletest', 'library_path')); +} +if (!@include_once SIMPLE_TEST . 'runner.php') { + RaiseError('runtime', 'LIBRARY_REQUIRED', array( + 'library' => 'Simple Test', + 'path' => SIMPLE_TEST)); +} +require_once 'lib/cli_reporter.php'; + +/* list tests */ +if ($opt_group_list || $opt_case_list ) { + + if ($opt_group_list) { + $gList = RemoteTestManager::getGroupTestList($opt_url); + + foreach ( $gList as $gName => $gUrl ) { + fwrite(STDOUT,"[$gName] $gUrl\n"); + } + } + + if ($opt_case_list) { + $cList = RemoteTestManager::getTestCaseList($opt_url); + + foreach ( $cList as $cName => $cUrl ) { + fwrite(STDOUT,"[$cName] $cUrl\n"); + } + } + + exit(0); +} + +/* run a test case */ +if ($opt_casefile) { + RemoteTestManager::runTestCase( + $opt_casefile, new CLIReporter($opt_separator), $opt_url + ); + exit(0); +} + +/* run a grouptest */ +if ($opt_groupfile) { + RemoteTestManager::runGroupTest( + $opt_groupfile, new CLIReporter($opt_separator), $opt_url + ); + exit(0); +} +/* run all tests */ +RemoteTestManager::runAllTests(new CLIReporter($opt_separator), $opt_url); +exit(0); +?> \ No newline at end of file diff --git a/test/rss2html.xsl b/test/rss2html.xsl new file mode 100644 index 000000000..ae56d2c20 --- /dev/null +++ b/test/rss2html.xsl @@ -0,0 +1,110 @@ + + + + + + + + + + + + + + + + + + +<xsl:for-each select="rdf:RDF/rss:channel"> +<xsl:value-of select="rss:description"/> +</xsl:for-each> + + + + + +
+ + + + + + 0 + + +
+
+ +
+
+ + +
+ + + + ( + + ) + +
+
+ +
    +
    + +
  • + + + + + ( + +) +
  • +
    +
    +
    +
+ + +
+ + + POST +
+ + + text + + + + + submit + +
+
+
+ + + +
+ +
\ No newline at end of file diff --git a/test/runtests.php b/test/runtests.php new file mode 100755 index 000000000..bd8a38b74 --- /dev/null +++ b/test/runtests.php @@ -0,0 +1,118 @@ +#!/usr/bin/php -q +'; +$opt_list = FALSE; +$opt_casefile = FALSE; +$opt_groupfile = FALSE; + +/* only allow cmd line options if PEAR Console_Getopt is available */ +@include_once 'Console/Getopt.php'; /* PEAR lib */ +if (class_exists('Console_Getopt')) { + + $argv = Console_Getopt::readPHPArgv(); + if (PEAR::isError($argv)) { + die('Fatal Error: ' . $argv->getMessage()) . "\n"; + } + + $short_opts = "f:g:hls:p:"; + $long_opts = array("help", "file=", "group=", "list", "separator=", "path="); + $options = Console_Getopt::getopt($argv, $short_opts, $long_opts); + if (PEAR::isError($options)) { + usage($available_grouptests); + } + + foreach ($options[0] as $option) { + switch ($option[0]) { + case 'h': + case '--help': + usage(); + break; + case 'f': + case '--file': + $opt_casefile = $option[1]; + break; + case 'g': + case '--group': + $opt_groupfile = $option[1]; + break; + case 'l': + case '--list': + $opt_list = TRUE; + break; + case 's': + case '--separator': + $opt_separator = $option[1]; + break; + case 'p': + case '--path': + if (file_exists($option[1])) { + define('SIMPLE_TEST', $option[1]); + } + break; + } + } +} + +if (!@include_once SIMPLE_TEST . 'reporter.php') { + die("Where's Simple Test ?!? Not at ".SIMPLE_TEST); +} + +require_once 'lib/cli_reporter.php'; + +/* list grouptests */ +if ($opt_list) { + echo CLITestManager::getGroupTestList(TEST_GROUPS); + echo CLITestManager::getTestCaseList(TEST_CASES); + exit(0); +} +/* run a test case */ +if ($opt_casefile) { + TestManager::runTestCase($opt_casefile, new CLIReporter($opt_separator)); + exit(0); +} +/* run a grouptest */ +if ($opt_groupfile) { + TestManager::runGroupTest($opt_groupfile, TEST_GROUPS, + new CLIReporter($opt_separator)); + exit(0); +} +/* run all tests */ +TestManager::runAllTests(new CLIReporter($opt_separator)); +exit(0); +?> diff --git a/test/tests.css b/test/tests.css new file mode 100644 index 000000000..c20d8bb4f --- /dev/null +++ b/test/tests.css @@ -0,0 +1,27 @@ +body { + background-color:#eee; + color:#000; + font:100%/1.2em Georgia,Verdana,Arial,Helvetica,sans-serif; + margin-left:20ex; + max-width:120ex; + } + +#sf { float:right; } + +h1 { + background-image:url(rephlux.png); + background-repeat:no-repeat; + margin-top:0; + padding:20px 0 0 90px; + color:#600; + font-size:3em; + line-height: 1em; + background-color:inherit; + border-bottom:9px double #333; + } + +pre { + font-size:120%; + line-height:1.2em; + color:#006; + } \ No newline at end of file diff --git a/test/tests.ini b/test/tests.ini new file mode 100644 index 000000000..cb16d4f1b --- /dev/null +++ b/test/tests.ini @@ -0,0 +1,12 @@ +TEST_ENABLED = 0 + +; For performing "web tests" - PHP scripts acting as web browser +WEB_TEST_URL = http://localhost/dokuwiki + +; See http://www.sitepoint.com/blogs/2004/06/15/simple-test-remote-testing/ +REMOTE_TEST_URL = http://localhost/dokuwiki/test/index.php + +;PROXY = http://proxyuser:proxypwd@proxy.yourdomain.com:8080 + +; Path to Simple Test +SIMPLE_TEST = ../../simpletest/ diff --git a/test/webtest-stripper.sh b/test/webtest-stripper.sh new file mode 100755 index 000000000..f7991cc0b --- /dev/null +++ b/test/webtest-stripper.sh @@ -0,0 +1,41 @@ +#!/bin/sh +################################################################################ +# Quick script to make simpletest web test fail output more legible +# +# Run the web test group from the command line w/ the command: +# +# $ ./runtests.php -g [GROUP] 2> tmp +# +# redirecting the error messages to the file tmp +# +# Then run this command on the tmp file +# +# $ ./webtest-stripper.sh tmp +# +################################################################################ + +usage="Usage: ${0} [WEB_TEST_OUTPUT_FILE]"; + +if [ -z "$1" ]; then + echo $usage; + exit 1; +elif [ ! -f "$1" ]; then + echo "${1} is not a file!"; + echo $usage; + exit 1; +fi + +sed -e 's/\\n/\ +/g' "${1}" |\ +sed -e 's/\\//g' |\ +sed -e 's/FAIL.*Pattern \[\#\^/EXPECTED:\ +/g' |\ +sed -e 's/\$#i\].*string \[/\ +\ +GOT:\ +/g' |\ +sed -e 's/\]$/\ +----------------------------------------------------------------\ +/g' + +exit 0 \ No newline at end of file -- cgit v1.2.3