<?php
/**
* Copyright (c) 2009, Laurent Laville <pear@laurent-laville.org>
*
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of the authors nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
* PHP version 5
*
* @category PEAR
* @package PEAR_TestListener
* @author Laurent Laville <pear@laurent-laville.org>
* @license http://www.opensource.org/licenses/bsd-license.php BSD
* @version CVS: $Id:$
* @link http://pear.laurent-laville.org/pepr/PEAR_TestListener
* @since File available since Release 0.3.0a1
*/
require_once 'PHPUnit/TextUI/TestRunner.php';
require_once 'PHPUnit/TextUI/Command.php';
require_once 'PEAR/TestListener/Configuration.php';
/**
* A TestRunner for the Command Line Interface (CLI)
* that can be invoked through the PHP interpreter like
*
* php path/to/UnitTest.php [switches]
*
* where [UnitTest.php] and [switches] are analog to the PHPUnit command
*
* phpunit [switches] UnitTest [UnitTest.php]
*
* @category PEAR
* @package PEAR_TestListener
* @author Laurent Laville <pear@laurent-laville.org>
* @license http://www.opensource.org/licenses/bsd-license.php BSD License
* @version Release: @package_version@
* @link http://pear.laurent-laville.org/pepr/PEAR_TestListener
* @since Class available since Release 0.3.0a1
*/
class PEAR_TestRunner extends PHPUnit_TextUI_Command
{
/**
* Runs a test suite, with or without a custom listener
*
* @param mixed $test Test suite
* @param object $listener (optional) A custom PEAR_TestListener
*
* @return PHPUnit_Framework_TestResult
* @throws InvalidArgumentException
*/
public static function run($test, PEAR_TestListener $listener = null)
{
PHPUnit_Util_Filesystem::collectStart();
/* solution to use PHPUnit_TextUI_Command::handleArguments
to retrieve all switches */
$_SERVER['argv'][] = '__dummyTest__';
$args = self::handleArguments();
if (!isset($listener)) {
include_once 'PEAR/TestListener.php';
$logger = self::getLogger();
$listener = new PEAR_TestListener($logger);
}
$args['listeners'] = array($listener);
include_once 'Event/Dispatcher.php';
foreach (PHPUnit_Util_Filesystem::collectEnd() as $blacklistedFile) {
PHPUnit_Util_Filter::addFileToFilter($blacklistedFile, 'PHPUNIT');
}
$result = PHPUnit_TextUI_TestRunner::run($test, $args);
$dispatcher = Event_Dispatcher::getInstance();
$dispatcher->post($result, 'endTestSuite');
return $result;
}
/**
* Facility to define with a simple keyword a log level mask
*
* Defining a log level mask allows you to include and/or exclude specific
* levels of events from being logged.
*
* @param string $condition (optional)
* full - List all messages including debug level
* normal - List all messages except debug level
* never - None messages
* onSuccess - Print only summary results if test suite is successful
* onError - Print test suite summary results
* and errors found when test suite was not successful
* onIncomplete - Print test suite summary results
* with tests skipped or not implemented
* onWarning - Print test suite summary results
* with all messages not ok except debug level
*
* @return integer The current PEAR::Log level mask
*/
public static function logMask($condition = 'normal')
{
include_once 'Log.php';
switch ($condition) {
case 'full':
$mask = PEAR_LOG_ALL;
break;
case 'normal':
$mask = PEAR_LOG_ALL ^ Log::MASK(PEAR_LOG_DEBUG);
break;
case 'onSuccess':
$mask = Log::MASK(PEAR_LOG_NOTICE);
break;
case 'onError':
$mask = Log::MASK(PEAR_LOG_ERR) | Log::MASK(PEAR_LOG_NOTICE);
break;
case 'onIncomplete':
$mask = Log::MASK(PEAR_LOG_WARNING) | Log::MASK(PEAR_LOG_NOTICE);
break;
case 'onWarning':
$mask = Log::MASK(PEAR_LOG_WARNING) | Log::MASK(PEAR_LOG_ERR)
| Log::MASK(PEAR_LOG_NOTICE);
break;
case 'never':
default:
$mask = PEAR_LOG_NONE;
}
return $mask;
}
/**
* Returns an instance of PEAR::Log composite handler
* with all active children
*
* @return PEAR::Log_composite
*/
public function getLogger()
{
/* solution to use PHPUnit_TextUI_Command::handleArguments
to retrieve all switches */
$_SERVER['argv'][] = '__dummyTest__';
$args = self::handleArguments();
$configuration = isset($args['configuration'])
? $args['configuration'] : null;
if (isset($configuration)) {
$xmlConf = PEAR_TestListener_Configuration::getInstance(
$configuration
);
$loggers = $xmlConf->getLoggerConfiguration();
} else {
$loggers = array();
}
// Do we have loggers defined into XML configuration file
if (count($loggers) > 0) {
// YES => initialize them
$childs = array();
foreach ($loggers as $gen => $loggerConf) {
// translate priority name to PEAR_LOG_* integer constant
$loggerConf['level']
= Log::stringToPriority(strtolower($loggerConf['level']));
// build a unique instance of handler detailed by $loggerConf
$handler = $loggerConf['type'];
if ($loggerConf['type'] !== 'composite') {
$handler .= $gen;
}
$$handler = Log::singleton(
$loggerConf['type'],
$loggerConf['name'], $loggerConf['ident'], $loggerConf['conf'],
$loggerConf['level']
);
if (!empty($loggerConf['mask'])) {
$$handler->setMask(hexdec($loggerConf['mask']));
}
$childs[] = $handler;
}
// build a default Log_composite instance
$composite = Log::factory('composite');
$key = array_search('composite', $childs);
if ($key === false) {
// No composite handler defined in XML configuration file
// ==> we take all other handler as child of defaut composite
} else {
// ==> we take only child described as attached to the composite
$validate = $loggers[$key]['_children'];
}
foreach ($childs as $gen => $child) {
if ($child == 'composite') {
continue;
}
if ($key) {
if (array_key_exists($$child->getIdent(), $validate) === false) {
/* this handler does not match ident
to current composite selection */
continue;
}
list(, $type) = explode('_', get_class($$child));
if ($validate[$$child->getIdent()] !== $type) {
/* ident match but not handler type
this handler does not full match
to current composite selection */
continue;
}
}
$composite->addChild($$child);
}
} else {
// NO => Build default composite log handler with only a file child
include_once 'PEAR/Config.php';
$config = PEAR_Config::singleton();
$test_dir = $config->get('test_dir');
$test_dir .= DIRECTORY_SEPARATOR;
$ident = __CLASS__;
$conf = array(
'lineFormat' => '[%1$s] %2$s: %4$s',
'timeFormat' => '%Y-%m-%d %H:%M:%S'
);
$level = PEAR_LOG_INFO;
$filename = $test_dir . $ident.'_'.date('Ymd').'.log';
if (@touch($filename)) {
$file = Log::singleton('file', $filename, $ident, $conf, $level);
} else {
$file = false;
}
$composite = Log::factory('composite');
$composite->addChild($file);
}
return $composite;
}
}
?>