Hello,

I have been using cakephp for a while, and I have made some updates to
the cakephp testing and code coverage framework which I would like to
submit for review. If there is a better way to achieve this, or this
already exists in cakephp, I would be grateful if someone can send me
pointers.

Changes included in the patch
- Add test hook functions to email sending, Session flash display and
page redirection to enable asserting these operations in the test
suite.

- Remove caching of DB schema during test suite execution. Without
this test suite fails when there are many models & controllers that
use different fixtures

- Enhancements to allow code coverage when executing group test cases,
specifically ALL
   test cases, and provide a clickable file list for code coverage
summary.

- Enable code coverage tracking only while running the actual test
cases, instead of all code.
   Reason: Much quicker execution test suite execution with coverage.

Also is there a good way of checking is the test suite is running as
opposed to real code? I have noticed in different places where they
check the url for the pattern 'test.php', which might fail if this
pattern is part of the url.
I am using a define called 'TEST_SUITE' which I am setting at the
start of the test suite execution, but there should be a better way of
doing this.

The patch follows below.

Cheers,
/Chandan


diff -r 16c58dcbc810 cake/libs/controller/components/email.php
--- a/cake/libs/controller/components/email.php Fri Nov 07 00:17:46
2008 +1100
+++ b/cake/libs/controller/components/email.php Fri Nov 07 01:06:33
2008 +1100
@@ -665,6 +665,18 @@
                }
                return @mail($this->to, $this->__encode($this->subject), $this-
>__message, $this->__header, $this->additionalParams);
        }
+
+/**
+ * Wrapper for Test Suite email testing.
+ * Expects a function called testmail() to handle mail delivery.
+ *
+ * @return bool Success
+ * @access private
+ */
+       function __test() {
+         return @testmail($this->to, $this->__encode($this->subject), $this-
>__message, $this->__header, $this->additionalParams);
+       }
+
 /**
  * Sends out email via SMTP
  *
diff -r 16c58dcbc810 cake/libs/controller/components/session.php
--- a/cake/libs/controller/components/session.php       Fri Nov 07 00:17:46
2008 +1100
+++ b/cake/libs/controller/components/session.php       Fri Nov 07 01:06:33
2008 +1100
@@ -229,10 +229,14 @@
  * @access public
  */
        function setFlash($message, $layout = 'default', $params = array(),
$key = 'flash') {
-               if ($this->__active === true) {
-                       $this->__start();
-                       $this->write('Message.' . $key, compact('message', 
'layout',
'params'));
-               }
+         if(defined('TEST_SUITE')) {
+               testFlashCallback($message, $params);
+         }
+
+         if ($this->__active === true) {
+               $this->__start();
+               $this->write('Message.' . $key, compact('message', 'layout',
'params'));
+         }
        }
 /**
  * Used to renew a session id
diff -r 16c58dcbc810 cake/libs/controller/controller.php
--- a/cake/libs/controller/controller.php       Fri Nov 07 00:17:46 2008
+1100
+++ b/cake/libs/controller/controller.php       Fri Nov 07 01:06:33 2008
+1100
@@ -472,6 +472,11 @@
  * @access public
  */
        function redirect($url, $status = null, $exit = true) {
+           if (defined('TEST_SUITE')) {
+                   setRedirectURL($url);
+                   return;
+           }
+
                $this->autoRender = false;

                if (is_array($status)) {
@@ -1077,4 +1082,4 @@
                return false;
        }
 }
-?>
\ No newline at end of file
+?>
diff -r 16c58dcbc810 cake/libs/model/datasources/dbo/dbo_mysql.php
--- a/cake/libs/model/datasources/dbo/dbo_mysql.php     Fri Nov 07
00:17:46 2008 +1100
+++ b/cake/libs/model/datasources/dbo/dbo_mysql.php     Fri Nov 07
01:06:33 2008 +1100
@@ -158,6 +158,12 @@
  */
        function listSources() {
                $cache = parent::listSources();
+               if (defined('TEST_SUITE')) {
+                 /* During testing we keep adding and dropping tables.
+                  * Relying on cache can cause tests to fail
+                  */
+                 $cache = null;
+               }
                if ($cache != null) {
                        return $cache;
                }
@@ -589,4 +595,4 @@
                return $out;
        }
 }
-?>
\ No newline at end of file
+?>
diff -r 16c58dcbc810 cake/tests/lib/code_coverage_manager.php
--- a/cake/tests/lib/code_coverage_manager.php  Fri Nov 07 00:17:46
2008 +1100
+++ b/cake/tests/lib/code_coverage_manager.php  Fri Nov 07 01:06:33
2008 +1100
@@ -116,6 +116,65 @@
                $manager->testCaseFile = $testCaseFile;
                xdebug_start_code_coverage(XDEBUG_CC_UNUSED | 
XDEBUG_CC_DEAD_CODE);
        }
+
+       /* Added by CK for group coverage testing */
+       var $groupCoverageData = array();
+       var $groupTestCase     = '';
+       function startGroupCoverage($testCaseGroup, &$reporter) {
+         $manager =& CodeCoverageManager::getInstance();
+         if (!$manager->testCaseFile)
+               $manager->testCaseFile = $testCaseGroup;
+         if (!$manager->reporter)
+               $manager->reporter = $reporter;
+
+         if (isset($_GET['app'])) {
+               $manager->appTest = true;
+         }
+
+         if (isset($_GET['group'])) {
+               $manager->groupTest = true;
+         }
+
+         if (isset($_GET['plugin'])) {
+               $manager->pluginTest = Inflector::underscore($_GET['plugin']);
+         }
+
+         xdebug_start_code_coverage(XDEBUG_CC_UNUSED );
+       }
+
+       function pauseGroupCoverage() {
+         $dump = xdebug_get_code_coverage();
+         $manager =& CodeCoverageManager::getInstance();
+         $manager->mergeCoverage($dump);
+
+         xdebug_stop_code_coverage();
+       }
+
+       function reportGroupCoverage() {
+         $fd = fopen('/tmp/xdd.log', 'w');
+         $manager =& CodeCoverageManager::getInstance();
+         $manager->mergeCoverage($manager->groupCoverageData);
+         fwrite($fd, print_r($manager->groupCoverageData, true));
+         fclose($fd);
+       }
+
+       function mergeCoverage($dump) {
+         foreach ($dump as $file => $cov) {
+               if (isset($this->groupCoverageData[$file])) {
+               $so_far = &$this->groupCoverageData[$file];
+               foreach ($cov as $line => $count) {
+                 if (isset($so_far[$line])) {
+                       $so_far[$line] += $count;
+                 } else {
+                       $so_far[$line] = $count;
+                 }
+               }
+               } else {
+                 $this->groupCoverageData[$file] = $cov;
+               }
+         }
+       }
+
 /**
  * Stops the current code coverage analyzation and dumps a nice
report depending on the reporter that was passed to start()
  *
@@ -131,8 +190,11 @@
                                trigger_error('This test object file is 
invalid: ' .
$testObjectFile);
                                return ;
                        }
+                       /*
                        $dump = xdebug_get_code_coverage();
                        xdebug_stop_code_coverage();
+                       */
+                       $dump = $manager->groupCoverageData;
                        $coverageData = array();

                        foreach ($dump as $file => $data) {
@@ -150,7 +212,7 @@

                        switch (get_class($manager->reporter)) {
                                case 'CakeHtmlReporter':
-                                       $result = 
$manager->reportCaseHtmlDiff(@file($testObjectFile),
$coverageData, $execCodeLines, $manager->numDiffContextLines);
+                                 $result = 
$manager->reportCaseHtmlDiff(@file($testObjectFile),
$coverageData, $execCodeLines, $manager->numDiffContextLines, $tmp1,
$tmp2);
                                        break;
                                case 'CLIReporter':
                                        $result = 
$manager->reportCaseCli(@file($testObjectFile),
$coverageData, $execCodeLines, $manager->numDiffContextLines);
@@ -160,8 +222,27 @@
                                        break;
                        }
                } else {
+                 $coverageData = array();
+                 $testObjectFiles = array();
+                 if ($manager->testCaseFile == 'all') {
+                       $dump = $manager->groupCoverageData;
+
+                       $app_path = ROOT . DS. APP_DIR;
+                       $test_path = $app_path . DS . 'tests';
+                       $webroot_path = $app_path . DS . 'webroot';
+
+                       foreach ($dump as $file => $data) {
+                         if (preg_match('#' . $app_path . '#', $file) &&
+                                 !preg_match('#' . $test_path . '#', $file) &&
+                                 !preg_match('#' . $webroot_path . '#', 
$file)) {
+                                       $coverageData[$file] = $data;
+                                       $testObjectFiles[] = $file;
+                               }
+                       }
+                       /* Sort for a better presentation */
+                       sort($testObjectFiles, SORT_REGULAR);
+                 } else {
                        $testObjectFiles = $manager-
>__testObjectFilesFromGroupFile($manager->testCaseFile, $manager-
>appTest);
-
                        foreach ($testObjectFiles as $file) {
                                if (!file_exists($file)) {
                                        trigger_error('This test object file is 
invalid: ' . $file);
@@ -170,34 +251,34 @@
                        }
                        $dump = xdebug_get_code_coverage();
                        xdebug_stop_code_coverage();
-                       $coverageData = array();
                        foreach ($dump as $file => $data) {
                                if (in_array($file, $testObjectFiles)) {
                                        $coverageData[$file] = $data;
                                }
                        }
+                 }
+
+                 if (empty($coverageData) && $output) {
+                       echo 'The test object files are never loaded.';
+                 }
+                 $execCodeLines = $manager-
>__getExecutableLines($testObjectFiles);
+                 $result = '';

-                       if (empty($coverageData) && $output) {
-                               echo 'The test object files are never loaded.';
-                       }
-                       $execCodeLines = 
$manager->__getExecutableLines($testObjectFiles);
-                       $result = '';
-
-                       switch (get_class($manager->reporter)) {
-                               case 'CakeHtmlReporter':
-                                       $result = 
$manager->reportGroupHtml($testObjectFiles,
$coverageData, $execCodeLines, $manager->numDiffContextLines);
-                                       break;
-                               case 'CLIReporter':
-                                       $result = 
$manager->reportGroupCli($testObjectFiles,
$coverageData, $execCodeLines, $manager->numDiffContextLines);
-                                       break;
-                               default:
-                                       trigger_error('Currently only HTML and 
CLI reporting is
supported for code coverage analysis.');
-                                       break;
-                       }
+                 switch (get_class($manager->reporter)) {
+                 case 'CakeHtmlReporter':
+                       $result = $manager->reportGroupHtml($testObjectFiles,
$coverageData, $execCodeLines, $manager->numDiffContextLines);
+                       break;
+                 case 'CLIReporter':
+                       $result = $manager->reportGroupCli($testObjectFiles,
$coverageData, $execCodeLines, $manager->numDiffContextLines);
+                       break;
+                 default:
+                       trigger_error('Currently only HTML and CLI reporting is 
supported
for code coverage analysis.');
+                       break;
+                 }
                }

                if ($output) {
-                       echo $result;
+                 echo $result;
                }
        }
 /**
@@ -244,7 +325,8 @@
  * @param string $output
  * @return void
  */
-       function reportCaseHtmlDiff($testObjectFile, $coverageData,
$execCodeLines, $numContextLines) {
+       function reportCaseHtmlDiff($testObjectFile, $coverageData,
$execCodeLines, $numContextLines,
+                                                               &$lineCountOut, 
&$coveredCountOut) {
                $manager = CodeCoverageManager::getInstance();
                $total = count($testObjectFile);
                $lines = array();
@@ -292,7 +374,7 @@
                                                }
                                        }

-                                       if ($j == $numContextLines) {
+                                       if ($j == $numContextLines && 
isset($lines[$key-1])) {
                                                $lineBeforeIsEndBlock = 
strpos($lines[$key-1], 'end') !==
false;
                                                $lineBeforeIsShown = 
strpos($lines[$key-1], 'show') !== false;
                                                $lineBeforeIsUncovered = 
strpos($lines[$key-1], 'uncovered') !
== false;
@@ -348,6 +430,11 @@
                                $report .= $manager->__paintCodeline($class, 
$num, $line);
                        }
                }
+
+               // Return coverage info
+               $lineCountOut = $lineCount;
+               $coveredCountOut = $coveredCount;
+
                return $manager->__paintHeader($lineCount, $coveredCount, 
$report);
        }
 /**
@@ -410,11 +497,24 @@
                                                $class = 'covered';
                                                $coveredCount++;
                                        }
+
                                } else {
                                        $class = 'ignored';
                                }
                        }
-                       $report .= 
$manager->__paintGroupResultLine($objFilename,
$lineCount, $coveredCount);
+                       $file_id = preg_replace('#[/.]#', '_', $objFilename);
+
+
+                       $file_result = 
$manager->reportCaseHtmlDiff(@file($objFilename),
$coverageData[$objFilename],
+                                                                               
                                $execCodeLines[$objFilename], $manager-
>numDiffContextLines,
+                                                                               
                                $lineCount, $coveredCount);
+
+                       $file_summary = 
$manager->__paintGroupResultLine($objFilename,
$lineCount, $coveredCount);
+
+                       $report .= "<span class='link' onclick='var elem =
document.getElementById(\"$file_id\");
elem.style.display=(elem.style.display == \"inline\")?\"none\":\"inline
\"'>$file_summary</span>";
+
+                       $report .= "<span style='display:none' id='$file_id' 
onclick='var
elem = document.getElementById(\"$file_id\"); elem.style.display=\"none
\"'>$file_result</span>";
+
                }
                return $manager->__paintGroupResultHeader($report);
        }
@@ -482,14 +582,12 @@
                $folder =& new Folder();
                $folder->cd(ROOT . DS . CAKE_TESTS_LIB);
                $contents = $folder->ls();
-
                if (in_array(basename($testFile), $contents[1])) {
                        $testFile = basename($testFile);
                        $path = ROOT . DS . CAKE_TESTS_LIB;
                }
                $path .= $testFile;
                $realpath = realpath($path);
-
                if ($realpath) {
                        return $realpath;
                }
@@ -627,7 +725,7 @@
                if ($codeCoverage > 80) {
                        $class = 'result-good';
                }
-               return '<p>Code Coverage for ' . $file . ': <span class="' .
$class . '">' . $codeCoverage . '%</span></p>';
+               return '<p class="' . $class . '">Code Coverage for ' . $file . 
':
<span>' . $codeCoverage . '%</span></p>';
        }
 /**
  * Paints the headline for code coverage analysis
@@ -691,7 +789,7 @@
                }
                return ($lineCount != 0)
                                ? round(100 * $coveredCount / $lineCount, 2)
-                               : '0.00';
+                               : '100.00';
        }
 /**
  * Gets us the base path to look for the test files



--~--~---------~--~----~------------~-------~--~----~
You received this message because you are subscribed to the Google Groups 
"CakePHP" group.
To post to this group, send email to [email protected]
To unsubscribe from this group, send email to [EMAIL PROTECTED]
For more options, visit this group at 
http://groups.google.com/group/cake-php?hl=en
-~----------~----~----~----~------~----~------~--~---

Reply via email to