Location: PHPKode > projects > phpRack > Test.php
<?php
/**
 * phpRack: Integration Testing Framework
 *
 * This source file is subject to the new BSD license that is bundled
 * with this package in the file LICENSE.txt. It is also available
 * through the world-wide-web at this URL: http://www.phprack.com/LICENSE.txt
 * If you did not receive a copy of the license and are unable to
 * obtain it through the world-wide-web, please send an email
 * to hide@address.com so we can send you a copy immediately.
 *
 * 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.
 *
 * @copyright Copyright (c) phpRack.com
 * @version $Id: Test.php 599 2010-07-06 13:50:14Z hide@address.com $
 * @category phpRack
 */

/**
 * @see phpRack_Runner
 */
require_once PHPRACK_PATH . '/Runner.php';

/**
 * @see phpRack_Assertion
 */
require_once PHPRACK_PATH . '/Assertion.php';

/**
 * Parent class of all integration tests
 *
 * @package Tests
 */
abstract class phpRack_Test
{

    const OK = 'OK';
    const FAILURE = 'FAILURE';

    /**
     * This timezone will be used in there is NO timezone
     * set on the server
     *
     * @see setUp()
     */
    const DEFAULT_TIMEZONE = 'EST';

    /**
     * ID of the test (unique in the system)
     *
     * @var string
     */
    protected $_fileName;

    /**
     * Runner of tests
     *
     * @var phpRack_Runner
     */
    protected $_runner;

    /**
     * Assertion to use
     *
     * @var phpRack_Assertion
     * @see __get()
     */
    protected $_assertion = null;

    /**
     * Ajax options to control front page behavior
     *
     * @var array
     * @see setAjaxOptions()
     * @see getAjaxOptions()
     */
    private $_ajaxOptions = array(
        'autoStart'          => true, // start it when front is loaded
        'reload'             => false, // reload every X seconds, in AJAX
        'linesCount'         => null, // how many lines should be displayed on browser side when we use tailf method
        'secVisible'         => null, // how long these lines should be visible (in seconds)
        'attachOutput'       => false, // attach output to previous result log
        'data'               => array(), // used for store data which should be returned in next ajax query
        'fileLastOffset'     => null, // used for control offset to read in phpRack_Package_Disc_File::tailf()
        'logSizeLimit'       => 100, // maximum size of log, in KB
        'pauseWhenFocusLost' => true, // stop ajax requests when window lost focus
        'tags'               => array(), // used for store available options for parametrized test
        'tag'                => null // selected tag param from front end
    );

    /**
     * Construct the class
     * 
     * This constructor is going to be used only from factory() method. Making
     * this method "private" leads to problems in PHP 5.2.5 and maybe earlier
     * versions.
     *
     * @param string ID of the test, absolute (!) file name
     * @param phpRack_Runner Instance of test runner
     * @return void
     * @see factory()
     */
    protected final function __construct($fileName, phpRack_Runner $runner)
    {
        $this->_fileName = realpath($fileName);
        $this->_runner = $runner;
        $this->_init();
    }

    /**
     * Create new instance of the class, using PHP absolute file name
     *
     * @param string ID of the test, absolute (!) file name
     * @param phpRack_Runner Instance of test runner
     * @return phpRack_Test
     * @throws Exception
     */
    public static function factory($fileName, phpRack_Runner $runner)
    {
        if (!file_exists($fileName)) {
            throw new Exception("File '{$fileName}' is not found");
        }

        if (!preg_match(phpRack_Runner::TEST_PATTERN, $fileName)) {
            throw new Exception("File '{$fileName}' is not named properly, can't run it");
        }

        $className = pathinfo($fileName, PATHINFO_FILENAME);

        // workaround against ZCA static code analysis
        eval('require_once $fileName;');
        
        if (!class_exists($className)) {
            throw new Exception("Class '{$className}' is not defined in '{$fileName}'");
        }
        
        return new $className($fileName, $runner);
    }

    /**
     * Dispatches property-like calls to the class
     *
     * @param string Name of the property to get
     * @return mixed
     * @throws Exception If nothing found
     */
    public final function __get($name)
    {
        if ($name == 'assert') {
            if (!isset($this->_assertion)) {
                $this->_assertion = phpRack_Assertion::factory($this);
            }
            return $this->_assertion;
        }
        throw new Exception("Property '{$name}' not found in " . get_class($this));
    }

    /**
     * Get unique test ID (file name of the test)
     *
     * @return string
     * @see $this->_fileName
     */
    public function getFileName()
    {
        return $this->_fileName;
    }

    /**
     * Get label of the test
     *
     * @return string
     */
    public function getLabel()
    {
        return ltrim(substr($this->_fileName, strlen($this->_runner->getDir())), '/');
    }

    /**
     * Run the test and return result
     *
     * @return phpRack_Result
     * @see phpRack_Runner::run()
     */
    public final function run()
    {
        // clean all previous results, if any
        $this->assert->getResult()->clean();

        // find all methods that start with "test" and call them
        $rc = new ReflectionClass($this);
        foreach ($rc->getMethods() as $method) {
            if (!preg_match('/^test/', $method->getName())) {
                continue;
            }
            try {
                $this->setUp();
                
                // to avoid test cancelation because time is over
                set_time_limit(0);

                call_user_func(
                    array($this, $method->getName()),
                    $this->_ajaxOptions['tag']
                );
                $this->tearDown();
            } catch (Exception $e) {
                $this->assert->getResult()->addLog(
                    sprintf(
                        '[Exception] %s: %s "%s"',
                        $method->getName(),
                        get_class($e),
                        $e->getMessage()
                    )
                )
                ->fail();
            }
        }

        // add final log line, summarizing the test execution
        $this->assert->getResult()->addLog(
            sprintf(
                'Finished %s, %0.3fsec',
                get_class($this),
                $this->assert->getResult()->getDuration()
            )
        );

        // return instance of phpRack_Result class
        return $this->assert->getResult();
    }

    /**
     * Setup test environment, if necessary, before running every test
     *
     * @return void
     * @see run()
     */
    public function setUp()
    {
        // Check the default time zone
        $defaultTimeZone = ini_get('date.timezone');
        if (empty($defaultTimeZone)) {
            ini_set('date.timezone', self::DEFAULT_TIMEZONE);
            $this->_log(
                'INI setting date.timezone is not set. ' .
                self::DEFAULT_TIMEZONE . ' set as the time zone. ' .
                'Please set date.timezone to you current time zone'
            );
        }
    }

    /**
     * Clean environment if necessary
     *
     * @return void
     * @see run()
     */
    public function tearDown()
    {
    }

    /**
     * Set ajax options
     *
     * @param array List of options to set
     * @return void
     * @see phpRack_Package_Disc_File::tail()
     */
    public function setAjaxOptions($options)
    {
        foreach ($options as $name=>$value) {
            if (!array_key_exists($name, $this->_ajaxOptions)) {
                throw new Exception("AJAX option '{$name}' is not valid");
                continue;
            }
            $this->_ajaxOptions[$name] = $value;
        }
    }

    /**
     * Get ajax options
     *
     * @return array
     * @see phpRack_Runner::run()
     * @see index.phtml
     */
    public function getAjaxOptions()
    {
        return $this->_ajaxOptions;
    }

    /**
     * Simple assertion method to compare two values
     *
     * @param mixed What we're expecting to have
     * @param mixed What we actually have
     * @param string Optional message to show
     * @return $this
     */
    public function assertEquals($dest, $src, $message = null) 
    {
        if ($dest != $src) {
            if (!is_null($message)) {
                $this->_log($message);
            }
            $this->assert->fail("Comparison failed");
        } else {
            $this->_log("Comparison succeeded");
        }
        return $this;
    }

    /**
     * Allow child class to overwrite test default options, by overwritting this method
     * If you want disable ajax auto start it is proper place for that
     *
     * @return void
     * @see __construct()
     */
    protected function _init()
    {

    }

    /**
     * Log one message
     *
     * @param string The message
     * @return void
     */
    protected function _log($message)
    {
        $this->assert->getResult()->addLog($message);
    }
}
Return current item: phpRack