'index.php', 'Index_Page1' => 'index.php?i=1', 'Index_Page1000' => 'index.php?i=1000', 'Index_Page0' => array('index.php?i=0', 'Index_Home'), 'Index_Page-1' => 'index.php?i=-1', 'Index_Page_NaN' => array('index.php?i=xbz', 'Index_Home'), 'Feed_Default' => 'feed.php', 'Feed_RSS2' => array('feed.php?feed=rss2', 'Feed_Default'), 'Feed_Atom' => 'feed.php?feed=atom', 'Feed_Invalid' => array('feed.php?feed=winer', 'Feed_Default'), 'Feed_Missing' => array('feed.php?feed=', 'Feed_Default'), 'Syndication' => 'syndication.php', 'Stats_Hit' => 'stats.php', 'Sitemap_Index' => 'sitemap.php', 'Sitemap_Map' => 'sitemap.php?sitemap=1', 'Sitemap_Missing' => array('sitemap.php?sitemap=', 'Sitemap_Map') ); var $_std_funcs = array('findTemplateTags', 'findPHPErrors'); function LPRegression($mode = 'normal') { // set mode $this->_mode = strtolower($mode); } function addSuite($suite) { $this->_suites[] = $suite; } function addTest($test) { $this->_std_tests[] = $test; } function execute($testurl = 'http://localhost', $lpdir = '') { if (count($this->_suites) < 1) { echo "No test suite selected!"; return; } $this->output("
Setting up test framework...");
        
        $this->_testurl = $testurl . '/';
        
        // set LightPress dir (assume we are in $lpdir/testing/ if none provided)
        if (empty($lpdir))
            $lpdir = dirname(dirname(__FILE__));
        $this->_lpdir = $lpdir;
        
        // check for files and modify config to use testing database
        if (@is_readable("$lpdir/classes/Frontend.php") &&
            @is_readable("$lpdir/classes/DBlite/MySQL.php") &&
            @is_readable("$lpdir/config.php") &&
            @is_writable("$lpdir/index.php") &&
            @is_writable("$lpdir/templates")
            ) {
            $this->setupTestingDb("$lpdir/index.php");
        } else {
            if (!@is_writable("$lpdir/index.php"))
                die("index.php not writable in $lpdir");    
            if (!@is_writable("$lpdir/templates"))
                die("templates not writable in $lpdir");    
            die("Cannot find LightPress files config.php and Frontend.php in $lpdir");
        }
        
        // open database connection
        require_once("$lpdir/classes/DBlite/MySQL.php");
        require_once("$lpdir/config.php");
        $this->_db =& new DBlite_MySQL($db_options);
        
        // copy test template files into LP dir
        $this->output("Copying test templates into LP templates directory ...");
        $this->copyTemplates(dirname(__FILE__) . DIRECTORY_SEPARATOR . 'templates',
                             $lpdir . DIRECTORY_SEPARATOR . 'templates');
        
        $this->output("  Test framework ready.
"); // run each test suite foreach($this->_suites as $suite) { $this->runSuite($suite); } // reset config to original $this->resetTestingDb("$lpdir/index.php"); } function setupTestingDb($file, $reset=false) { $indexdata = file($file); $f = fopen($file, 'wb'); foreach ($indexdata as $line=>$data) { if ((strpos($data, 'config.php') !== false) && !$reset) $data .= $this->_regression_config; elseif (strpos($data, $this->_regression_config) !== false) $data = str_replace($this->_regression_config, '', $data); fwrite($f, $data); } fclose($f); } function resetTestingDb($file) { $this->setupTestingDb($file, true); } function copyTemplates($sourcedir, $destdir) { // check directory if (!is_dir($sourcedir)) die("Template directory $sourcedir does not exist!"); // recursively copy files & directories $d = opendir($sourcedir); while ( ($file = readdir($d)) !== false) { if (($file == '.') || ($file == '..') || ($file == 'CVS') || ($file == '.svn')) continue; $srcpath = $sourcedir . DIRECTORY_SEPARATOR . $file; $destpath = $destdir . DIRECTORY_SEPARATOR . $file; if (is_dir($srcpath)) { // create destination directory and copy contents if (!is_dir($destpath)) mkdir($destpath, 0777); $this->copyTemplates($srcpath, $destpath); } else { // copy file copy($srcpath, $destpath); } } } function runSuite($suite) { $this->output("*** RUNNING TEST SUITE $suite ***"); // check for suite directory $suitedir = dirname(__FILE__) . DIRECTORY_SEPARATOR . $suite; if (!is_writable($suitedir)) die("$suitedir not writable"); if (!is_dir($suite)) die("Could not find test suite directory $suite"); $suitedir .= DIRECTORY_SEPARATOR; // include suite test file (file must define $tests array) if (!@is_readable($suitedir . 'tests.php')) die("Could not find tests.php file for test suite $suite : $suitedir"); require_once($suitedir . 'tests.php'); // merge suite tests with standard tests $suite_tests = array_merge($this->_std_tests, $tests); // include suite db data if (!@is_readable($suitedir . 'data.sql')) die("Could not find data.sql file for test suite $suite"); $db_data = file_get_contents($suitedir . 'data.sql'); $queries = explode(";\n", $db_data); // dump existing tables & import new data foreach($this->_db_tables as $table) $this->_db->query("DROP TABLE IF EXISTS {$this->_database}_{$table}"); foreach($queries as $qry) { $qry = trim($qry); if (!empty($qry)) $this->_db->query(trim($qry)); } // fix database settings to match this installation $this->_db->query("UPDATE {$this->_database}_options SET option_value = '" . mysql_escape_string($this->_lpdir) . "' WHERE option_name = 'lp_opt_basedir'"); // run each test $site = $this->_testurl; $mode = $this->_mode; echo "

Test Suite «$suite»

\n "; foreach($suite_tests as $name => $testdata) { // set test data if (is_array($testdata)) { $url = $testdata[0]; $exp_name = (isset($testdata[1]) && ($testdata[1] != '')) ? $testdata[1] : $name; $funcs = (isset($testdata[2]) && ($testdata[2] != '')) ? $testdata[2] : $this->_std_funcs; } else { $url = $testdata; $exp_name = $name; $funcs = $this->_std_funcs; } // set default results $details = ''; $result = 'PASS'; // check result $read = file_get_contents($site . $url); // check if we have a saved result $ext = ((substr($url, 0, 5 ) == 'index') || (substr($url, 0, 11) == 'syndication')) ? '.html' : '.xml'; $exp_file = $exp_name . $ext; $exp_path = $suitedir . $exp_file; $exp_ok = @is_readable($exp_path); // run special tests foreach ($funcs as $fn) { if (method_exists($this, $fn)) { $this->$fn($read, $result, $details); } elseif (function_exists($fn)) { $fn($read, $result, $details); } else { $details .= "\n*** FUNCTION «$fn» NOT FOUND ***"; $result = 'FAIL'; } } // compare vs. existing result (if available & not rebuilding) if ($exp_ok && (strtolower($result) == 'pass') && ($mode != 'rebuild')) { // compare to expected $exp = file_get_contents($exp_path); if ($exp == $read) { // match $result = 'PASS'; $details = "View $exp_file"; } else { // display first mismatched line of the failed test $exp_lines = explode("\n", $exp); $read_lines = explode("\n", $read); $result = 'FAIL'; $details = 'Undefined mismatch'; foreach($exp_lines as $key => $line) { if (!isset($read_lines[$key])) { $details = '
Missing (line ' . ($key+1) . '): ' . htmlentities($line) . '
'; break; } elseif ($read_lines[$key] != $line) { $details = '
Result (line ' . ($key+1) . '): ' .htmlentities($read_lines[$key]) . "\n" .
                                            'Expected:           ' .htmlentities($line) . '
'; break; } } } } // create output file if passed if (strtolower($result) == 'pass') { if (($mode == 'rebuild') || (($mode == 'buildnew') && !$exp_ok)) { if ($name == $exp_name) { // save result as new baseline result $f = fopen($exp_path, 'w'); fwrite($f, $read); fclose($f); $result = 'Saved'; $details = "Results saved to: $exp_file"; } else { // skip tests that use output of other tests $result = 'Skip'; $details = "Skipped build, uses output from test $exp_name"; } } elseif (!$exp_ok) { // no comparison available, save result to temporary file $chk_file = $name . strftime('_%Y.%m.%d-%H.%M.%S') . $ext; $f = fopen($suitedir . $chk_file, 'w'); fwrite($f, $read); fclose($f); $result = 'Check'; $details = "Results saved to: $chk_file"; } } // display result switch (strtolower($result)) { case 'pass': $colour = '#0f0'; break; case 'check': $colour = '#f93'; break; case 'saved': //fall through case 'skip': $colour = '#39f'; break; default: $colour = '#f00'; break; } echo " "; } echo "
TestTest URLResultDetails
$name $url $result $details
\n"; } function findTemplateTags(&$data, &$result, &$details) { if (preg_match('/{[A-Za-z0-9_\-]+}/', $data, $matches)) { $result = 'FAIL'; $data_lines = explode("\n", $data); foreach($data_lines as $num => $line) { if (strpos($line, $matches[0]) !== false) { $details = "Template tag {$matches[0]} found on line " . ($num+1); break; } } } } function findPHPErrors(&$data, &$result, &$details) { $p1 = strpos($data, 'Fatal error:'); $p2 = strpos($data, 'Warning:'); $p3 = strpos($data, 'Notice:'); if (($p1 !== false) || ($p2 !== false) || ($p3 !== false)) { $pos = $p1 + $p2 + $p3; $result = 'FAIL'; $details = substr($data, $pos, strpos($data, "\n", $p1+$p2+$p3) - $pos); } } function output($message) { echo "$message \n"; } } ?>