diff --git a/src/TUnit/framework/ConsoleTestRunner.php b/src/TUnit/framework/ConsoleTestRunner.php
index a8b7f4a..389b3f1 100644
--- a/src/TUnit/framework/ConsoleTestRunner.php
+++ b/src/TUnit/framework/ConsoleTestRunner.php
@@ -40,6 +40,16 @@
}
}
+ /**
+ * {@inheritdoc}
+ *
+ * @author Tommy Montgomery
+ * @since 1.0
+ * @version 1.0
+ * @uses getOption()
+ * @uses CoverageReporter::createConsoleReport()
+ * @uses CoverageReporter::createHtmlReport()
+ */
protected function postRun() {
$html = $this->getOption('coverage-html');
$console = $this->getOption('coverage-console');
diff --git a/src/TUnit/framework/mock/MockObjectCreator.php b/src/TUnit/framework/mock/MockObjectCreator.php
index c3a8aa0..1504d8b 100644
--- a/src/TUnit/framework/mock/MockObjectCreator.php
+++ b/src/TUnit/framework/mock/MockObjectCreator.php
@@ -66,10 +66,19 @@
throw new LogicException('The class "' . $class . '" is final and cannot be mocked');
}
+ $constructor = $refClass->getConstructor();
+ if ($constructor === null) {
+ $constructor = '__construct';
+ $callParent = false;
+ } else {
+ $constructor = $constructor->getName();
+ }
+
$this->referenceObject = $refClass;
+
$this->methods = array(
'default' => array(
- $this->referenceObject->getConstructor()->getName() => array(
+ $constructor => array(
'body' => '',
'call_parent' => (bool)$callParent
)
diff --git a/src/TUnit/framework/reporting/CoverageReporter.php b/src/TUnit/framework/reporting/CoverageReporter.php
index b3bd6db..6e81885 100644
--- a/src/TUnit/framework/reporting/CoverageReporter.php
+++ b/src/TUnit/framework/reporting/CoverageReporter.php
@@ -2,8 +2,10 @@
class CoverageReporter {
- const UNUSED = -1;
- const DEAD = -2;
+ const UNUSED = -1;
+ const DEAD = -2;
+
+ const TEMPLATE_DIR = 'template';
private function __construct() {}
@@ -45,24 +47,130 @@
fwrite(STDOUT, " Executable: $totloc (" . round($totcloc / $totloc * 100, 2) . "%)\n");
}
- public static function createXmlReport($file, array $coverageData) {
-
- }
-
public static function createHtmlReport($dir, array $coverageData) {
if (!is_dir($dir)) {
throw new TUnitException($dir . ' is not a directory');
}
-
-
$coverageData = CoverageFilter::filter($coverageData);
+
+ $baseDir = array();
foreach ($coverageData as $file => $data) {
- foreach ($data as $unitsCovered) {
-
+ $dirs = explode(DIRECTORY_SEPARATOR, dirname($file));
+ if (empty($baseDir)) {
+ $baseDir = $dirs;
+ } else {
+ for ($i = 0, $len = count($dirs); $i < $len; $i++) {
+ if (!isset($baseDir[$i]) || $baseDir[$i] !== $dirs[$i]) {
+ break;
+ }
+ }
+
+ $baseDir = array_slice($dirs, 0, $i);
}
}
+ $baseDir = implode(DIRECTORY_SEPARATOR, $baseDir) . DIRECTORY_SEPARATOR;
+
+ $totalData = array();
+ foreach ($coverageData as $file => $data) {
+ $totalData[$file] = array(
+ 'loc' => 0,
+ 'dloc' => 0,
+ 'cloc' => 0
+ );
+
+ foreach ($data as $line => $unitsCovered) {
+ $totalData[$file]['loc']++;
+ if ($unitsCovered > 0) {
+ $totalData[$file]['cloc']++;
+ } else if ($unitsCovered === self::DEAD) {
+ $totalData[$file]['dloc']++;
+ }
+ }
+
+ self::writeHtmlFile($file, $baseDir, $dir, $data);
+ }
+
+ //copy css over
+ $template = dirname(__FILE__) . DIRECTORY_SEPARATOR . self::TEMPLATE_DIR . DIRECTORY_SEPARATOR;
+ copy($template . 'style.css', $dir . DIRECTORY_SEPARATOR . 'style.css');
+ }
+
+ private static function writeHtmlFile($sourceFile, $baseDir, $coverageDir, array $data) {
+ $lines = file($sourceFile, FILE_IGNORE_NEW_LINES);
+ $code = '';
+ $lineNumbers = '';
+ for ($i = 1, $len = count($lines); $i <= $len; $i++) {
+ $lineNumbers .= '
';
+ $code .= ' 0) {
+ $code .= 'covered';
+ } else if ($data[$i] === self::DEAD) {
+ $code .= 'dead';
+ } else if ($data[$i] === self::UNUSED) {
+ $code .= 'uncovered';
+ }
+
+ $code .= '">';
+ } else {
+ $code .= '>';
+ }
+
+ if (empty($lines[$i])) {
+ $lines[$i] = ' ';
+ }
+
+ $code .= htmlentities(str_replace("\t", ' ', $lines[$i - 1]), ENT_QUOTES) ."
\n";
+ }
+
+ unset($lines);
+
+ $fileName = str_replace(array($baseDir, DIRECTORY_SEPARATOR), array('', '_'), $sourceFile);
+ $newFile = $coverageDir . DIRECTORY_SEPARATOR . $fileName . '.html';
+
+ $link = '' . $baseDir . '';
+ $dirs = preg_split('@\\' . DIRECTORY_SEPARATOR . '@', str_replace($baseDir, '', dirname($sourceFile) . DIRECTORY_SEPARATOR), -1, PREG_SPLIT_NO_EMPTY);
+ $path = '';
+ foreach ($dirs as $dir) {
+ $path = ltrim($path . '_' . $dir, '_');
+ $link .= '' . $dir . '' . DIRECTORY_SEPARATOR;
+ }
+
+ $template = file_get_contents(dirname(__FILE__) . DIRECTORY_SEPARATOR . self::TEMPLATE_DIR . DIRECTORY_SEPARATOR . 'file.html');
+ $template = preg_replace(
+ array(
+ '/\$\{title\}/',
+ '/\$\{file\.name\}/',
+ '/\$\{line.numbers\}/',
+ '/\$\{code\}/',
+ '/\$\{timestamp\}/',
+ '/\$\{product\.name\}/',
+ '/\$\{product\.version\}/',
+ '/\$\{product\.website\}/',
+ '/\$\{product\.author\}/'
+ ),
+ array(
+ Product::NAME . ' - Coverage Report',
+ $link . basename($sourceFile),
+ $lineNumbers,
+ $code,
+ date('Y-m-d H:i:s'),
+ Product::NAME,
+ Product::VERSION,
+ Product::WEBSITE,
+ Product::AUTHOR
+ ),
+ $template
+ );
+
+ return file_put_contents($newFile, $template);
+ }
+
+ private static function writeHtmlDir(array $data) {
+
}
}
diff --git a/src/TUnit/framework/reporting/template/file.html b/src/TUnit/framework/reporting/template/file.html
new file mode 100644
index 0000000..ba91835
--- /dev/null
+++ b/src/TUnit/framework/reporting/template/file.html
@@ -0,0 +1,39 @@
+
+
+
+
+ ${title}
+
+
+
+
+
+
+
+
+
+
+
+
+${line.numbers}
+
+
+${code}
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/src/TUnit/framework/reporting/template/style.css b/src/TUnit/framework/reporting/template/style.css
new file mode 100644
index 0000000..e86d469
--- /dev/null
+++ b/src/TUnit/framework/reporting/template/style.css
@@ -0,0 +1,46 @@
+html {
+ overflow: auto;
+}
+body {
+ background-color: #FFFFCC;
+ color: #000000;
+}
+
+#code-wrapper {
+ background-color: #FFFFFF;
+ font-family: Consolas, "Courier New", monospace;
+ font-size: 16px;
+ border: 2px solid #000000;
+}
+#line-numbers {
+ background-color: #CCCCCC;
+ float: left;
+ text-align: right;
+ padding: 0 5px;
+ border-right: 2px solid #000000;
+}
+#line-numbers a {
+ color: #000000;
+ text-decoration: none;
+ display: block;
+}
+#line-numbers div {
+ white-space: pre;
+}
+#code {
+ padding-left: 10px;
+ overflow: auto;
+}
+#code div {
+ white-space: pre;
+}
+
+.covered {
+ background-color: #66FF66;
+}
+.uncovered {
+ background-color: #FF6666;
+}
+.dead {
+ background-color: #999999;
+}
\ No newline at end of file
diff --git a/src/TUnit/util/entry_console.php b/src/TUnit/util/entry_console.php
index 38a683f..7be46f4 100644
--- a/src/TUnit/util/entry_console.php
+++ b/src/TUnit/util/entry_console.php
@@ -48,7 +48,7 @@
->addSwitch(new CliSwitch('usage', null, false, null, 'Display this help message'))
->addSwitch(new CliSwitch('recursive', null, false, null, 'Recurse into subdirectories'))
->addSwitch(new CliSwitch('bootstrap', 'b', false, 'file', 'File to include before tests are run'))
- ->addSwitch(new CliSwitch('coverage-xml', null, false, 'file', 'Generate code coverage report in XML clover format (requires xdebug)'))
+ //->addSwitch(new CliSwitch('coverage-xml', null, false, 'file', 'Generate code coverage report in XML clover format (requires xdebug)'))
->addSwitch(new CliSwitch('coverage-html', null, false, 'dir', 'Generate code coverage report in HTML (requires xdebug, optionally uses ezComponents)'))
->addSwitch(new CliSwitch('coverage-console', null, false, null, 'Generate code coverage report suitable for console viewing'));