PHP code
  1. <?php
  2. /**
  3.  * Copyright (c) 2009, Laurent Laville <pear@laurent-laville.org>
  4.  *
  5.  * All rights reserved.
  6.  *
  7.  * Redistribution and use in source and binary forms, with or without
  8.  * modification, are permitted provided that the following conditions
  9.  * are met:
  10.  *
  11.  *     * Redistributions of source code must retain the above copyright
  12.  *       notice, this list of conditions and the following disclaimer.
  13.  *     * Redistributions in binary form must reproduce the above copyright
  14.  *       notice, this list of conditions and the following disclaimer in the
  15.  *       documentation and/or other materials provided with the distribution.
  16.  *     * Neither the name of the authors nor the names of its contributors
  17.  *       may be used to endorse or promote products derived from this software
  18.  *       without specific prior written permission.
  19.  *
  20.  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
  21.  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  22.  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  23.  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
  24.  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
  25.  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
  26.  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
  27.  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
  28.  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
  29.  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
  30.  * POSSIBILITY OF SUCH DAMAGE.
  31.  *
  32.  * PHP version 5
  33.  *
  34.  * @category PEAR
  35.  * @package  PEAR_TestListener
  36.  * @author   Laurent Laville <pear@laurent-laville.org>
  37.  * @license  http://www.opensource.org/licenses/bsd-license.php  BSD
  38.  * @version  CVS: $Id:$
  39.  * @link     http://pear.laurent-laville.org/pepr/PEAR_TestListener
  40.  * @since    File available since Release 0.3.0a1
  41.  */
  42.  
  43. require_once 'PHPUnit/TextUI/TestRunner.php';
  44. require_once 'PHPUnit/TextUI/Command.php';
  45. require_once 'PEAR/TestListener/Configuration.php';
  46.  
  47. /**
  48.  * A TestRunner for the Command Line Interface (CLI)
  49.  * that can be invoked through the PHP interpreter like
  50.  *
  51.  *    php path/to/UnitTest.php [switches]
  52.  *
  53.  * where [UnitTest.php] and [switches] are analog to the PHPUnit command
  54.  *
  55.  *    phpunit [switches] UnitTest [UnitTest.php]
  56.  *
  57.  * @category PEAR
  58.  * @package  PEAR_TestListener
  59.  * @author   Laurent Laville <pear@laurent-laville.org>
  60.  * @license  http://www.opensource.org/licenses/bsd-license.php  BSD License
  61.  * @version  Release: @package_version@
  62.  * @link     http://pear.laurent-laville.org/pepr/PEAR_TestListener
  63.  * @since    Class available since Release 0.3.0a1
  64.  */
  65. class PEAR_TestRunner extends PHPUnit_TextUI_Command
  66. {
  67.     /**
  68.      * Runs a test suite, with or without a custom listener
  69.      *
  70.      * @param mixed  $test     Test suite
  71.      * @param object $listener (optional) A custom PEAR_TestListener
  72.      *
  73.      * @return PHPUnit_Framework_TestResult
  74.      * @throws InvalidArgumentException
  75.      */
  76.     public static function run($test, PEAR_TestListener $listener = null)
  77.     {
  78.         PHPUnit_Util_Filesystem::collectStart();
  79.  
  80.         /*  solution to use PHPUnit_TextUI_Command::handleArguments
  81.             to retrieve all switches  */
  82.         $_SERVER['argv'][] = '__dummyTest__';
  83.  
  84.         $args = self::handleArguments();
  85.  
  86.         if (!isset($listener)) {
  87.             include_once 'PEAR/TestListener.php';
  88.  
  89.             $logger   = self::getLogger();
  90.             $listener = new PEAR_TestListener($logger);
  91.         }
  92.         $args['listeners'] = array($listener);
  93.  
  94.         include_once 'Event/Dispatcher.php';
  95.  
  96.         foreach (PHPUnit_Util_Filesystem::collectEnd() as $blacklistedFile) {
  97.             PHPUnit_Util_Filter::addFileToFilter($blacklistedFile, 'PHPUNIT');
  98.         }
  99.  
  100.         $result = PHPUnit_TextUI_TestRunner::run($test, $args);
  101.  
  102.         $dispatcher = Event_Dispatcher::getInstance();
  103.         $dispatcher->post($result, 'endTestSuite');
  104.  
  105.         return $result;
  106.     }
  107.  
  108.     /**
  109.      * Facility to define with a simple keyword a log level mask
  110.      *
  111.      * Defining a log level mask allows you to include and/or exclude specific
  112.      * levels of events from being logged.
  113.      *
  114.      * @param string $condition (optional)
  115.      *  full         - List all messages including debug level
  116.      *  normal       - List all messages except debug level
  117.      *  never        - None messages
  118.      *  onSuccess    - Print only summary results if test suite is successful
  119.      *  onError      - Print test suite summary results
  120.      *                 and errors found when test suite was not successful
  121.      *  onIncomplete - Print test suite summary results
  122.      *                 with tests skipped or not implemented
  123.      *  onWarning    - Print test suite summary results
  124.      *                 with all messages not ok except debug level
  125.      *
  126.      * @return integer The current PEAR::Log level mask
  127.      */
  128.     public static function logMask($condition = 'normal')
  129.     {
  130.         include_once 'Log.php';
  131.  
  132.         switch ($condition) {
  133.         case 'full':
  134.             $mask = PEAR_LOG_ALL;
  135.             break;
  136.         case 'normal':
  137.             $mask = PEAR_LOG_ALL ^ Log::MASK(PEAR_LOG_DEBUG);
  138.             break;
  139.         case 'onSuccess':
  140.             $mask = Log::MASK(PEAR_LOG_NOTICE);
  141.             break;
  142.         case 'onError':
  143.             $mask = Log::MASK(PEAR_LOG_ERR) | Log::MASK(PEAR_LOG_NOTICE);
  144.             break;
  145.         case 'onIncomplete':
  146.             $mask = Log::MASK(PEAR_LOG_WARNING) | Log::MASK(PEAR_LOG_NOTICE);
  147.             break;
  148.         case 'onWarning':
  149.             $mask = Log::MASK(PEAR_LOG_WARNING) | Log::MASK(PEAR_LOG_ERR)
  150.                 | Log::MASK(PEAR_LOG_NOTICE);
  151.             break;
  152.         case 'never':
  153.         default:
  154.             $mask = PEAR_LOG_NONE;
  155.         }
  156.         return $mask;
  157.     }
  158.  
  159.     /**
  160.      * Returns an instance of PEAR::Log composite handler
  161.      * with all active children
  162.      *
  163.      * @return PEAR::Log_composite
  164.      */
  165.     public function getLogger()
  166.     {
  167.         /*  solution to use PHPUnit_TextUI_Command::handleArguments
  168.             to retrieve all switches  */
  169.         $_SERVER['argv'][] = '__dummyTest__';
  170.  
  171.         $args = self::handleArguments();
  172.  
  173.         $configuration = isset($args['configuration'])
  174.             ? $args['configuration'] : null;
  175.  
  176.         if (isset($configuration)) {
  177.             $xmlConf = PEAR_TestListener_Configuration::getInstance(
  178.                 $configuration
  179.             );
  180.  
  181.             $loggers = $xmlConf->getLoggerConfiguration();
  182.         } else {
  183.             $loggers = array();
  184.         }
  185.  
  186.         // Do we have loggers defined into XML configuration file
  187.         if (count($loggers) > 0) {
  188.             // YES => initialize them
  189.             $childs = array();
  190.  
  191.             foreach ($loggers as $gen => $loggerConf) {
  192.                 // translate priority name to PEAR_LOG_* integer constant
  193.                 $loggerConf['level']
  194.                     = Log::stringToPriority(strtolower($loggerConf['level']));
  195.  
  196.                 // build a unique instance of handler detailed by $loggerConf
  197.                 $handler = $loggerConf['type'];
  198.                 if ($loggerConf['type'] !== 'composite') {
  199.                     $handler .= $gen;
  200.                 }
  201.                 $$handler = Log::singleton(
  202.                     $loggerConf['type'],
  203.                     $loggerConf['name'], $loggerConf['ident'], $loggerConf['conf'],
  204.                     $loggerConf['level']
  205.                 );
  206.                 if (!empty($loggerConf['mask'])) {
  207.                     $$handler->setMask(hexdec($loggerConf['mask']));
  208.                 }
  209.                 $childs[] = $handler;
  210.             }
  211.  
  212.             // build a default Log_composite instance
  213.             $composite = Log::factory('composite');
  214.             $key = array_search('composite', $childs);
  215.             if ($key === false) {
  216.                 // No composite handler defined in XML configuration file
  217.                 // ==> we take all other handler as child of defaut composite
  218.             } else {
  219.                 // ==> we take only child described as attached to the composite
  220.                 $validate = $loggers[$key]['_children'];
  221.             }
  222.             foreach ($childs as $gen => $child) {
  223.                 if ($child == 'composite') {
  224.                     continue;
  225.                 }
  226.                 if ($key) {
  227.                     if (array_key_exists($$child->getIdent(), $validate) === false) {
  228.                         /* this handler does not match ident
  229.                            to current composite selection */
  230.                         continue;
  231.                     }
  232.                     list(, $type) = explode('_', get_class($$child));
  233.                     if ($validate[$$child->getIdent()] !== $type) {
  234.                         /* ident match but not handler type
  235.                            this handler does not full match
  236.                            to current composite selection */
  237.                         continue;
  238.                     }
  239.                 }
  240.                 $composite->addChild($$child);
  241.             }
  242.  
  243.         } else {
  244.             // NO => Build default composite log handler with only a file child
  245.             include_once 'PEAR/Config.php';
  246.  
  247.             $config    = PEAR_Config::singleton();
  248.             $test_dir  = $config->get('test_dir');
  249.             $test_dir .= DIRECTORY_SEPARATOR;
  250.  
  251.             $ident     = __CLASS__;
  252.             $conf      = array(
  253.                 'lineFormat' => '[%1$s] %2$s: %4$s',
  254.                 'timeFormat' => '%Y-%m-%d %H:%M:%S'
  255.                 );
  256.             $level     = PEAR_LOG_INFO;
  257.             $filename  = $test_dir . $ident.'_'.date('Ymd').'.log';
  258.  
  259.             if (@touch($filename)) {
  260.                 $file = Log::singleton('file', $filename, $ident, $conf, $level);
  261.             } else {
  262.                 $file = false;
  263.             }
  264.  
  265.             $composite = Log::factory('composite');
  266.             $composite->addChild($file);
  267.         }
  268.         return $composite;
  269.     }
  270. }
  271. ?>
generated by Generic Syntax Highlighter - GeSHi