Current File : //opt/RZphp73/includes/test/PHP_FunctionCallTracer/tests/FunctionCallTracerTest.php
<?php
/**
 * Function Call Tracer
 *
 * PHP version 5
 *
 * 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.
 * + The name of its contributors may not 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.
 *
 * @category  PHP
 * @package   PHP_FunctionCallTracer
 * @author    Michel Corne <mcorne@yahoo.com>
 * @copyright 2007 Michel Corne
 * @license   http://www.opensource.org/licenses/bsd-license.php The BSD License
 * @version   SVN: $Id: FunctionCallTracerTest.php 21 2007-09-03 08:16:02Z mcorne $
 * @link      http://pear.php.net/package/PHP_FunctionCallTracer
 */
// Call tests_FunctionCallTracerTest::main() if this source file is executed directly
if (!defined("PHPUnit_MAIN_METHOD")) {
    define("PHPUnit_MAIN_METHOD", "tests_FunctionCallTracerTest::main");
}

require_once "PHPUnit/Framework/TestCase.php";
require_once "PHPUnit/Framework/TestSuite.php";

require_once 'PHP/FunctionCallTracer.php';

/**
 * Test class for PHP_FunctionCallTracer.
 * Generated by PHPUnit_Util_Skeleton on 2007-05-18 at 18:49:09.
 *
 * @category  PHP
 * @package   PHP_FunctionCallTracer
 * @author    Michel Corne <mcorne@yahoo.com>
 * @copyright 2007 Michel Corne
 * @license   http://www.opensource.org/licenses/bsd-license.php The BSD License
 * @version   Release:@package_version@
 * @link      http://pear.php.net/package/PHP_FunctionCallTracer
 */
class tests_FunctionCallTracerTest extends PHPUnit_Framework_TestCase
{
    /**
     * Runs the test methods of this class.
     *
     * @access public
     * @static
     */
    public static function main()
    {
        require_once "PHPUnit/TextUI/TestRunner.php";

        $suite = new PHPUnit_Framework_TestSuite("PHP_FunctionCallTracerTest");
        $result = PHPUnit_TextUI_TestRunner::run($suite);
    }

    /**
     * Sets up the fixture, for example, open a network connection.
     * This method is called before a test is executed.
     *
     * @access protected
     */
    protected function setUp()
    {
        PHP_FunctionCallTracer::reset();
    }

    /**
     * Tears down the fixture, for example, close a network connection.
     * This method is called after a test is executed.
     *
     * @access protected
     */
    protected function tearDown()
    {
    }

    /**
     * Reads and tidies a generated or reference file
     *
     * @param  string $file the file name
     * @return array  the file content
     * @access private
     */
    private function getFile($file)
    {
        // reads the file, strips trailing spaces and eol characters, removes extra spaces
        $array = file($file);
        $array = array_map('rtrim', $array);
        $array = preg_replace ('/\s\s+/', ' ', $array);

        return $array;
    }

    /**
     * A user function object method calling strtoupper()
     *
     * @param  string $string the original string
     * @return string the string in upper case letters
     * @access private
     */
    private function strtoupperDyn($string)
    {
        return strtoupper($string);
    }

    /**
     * A user function class method calling strtoupper()
     *
     * @param  string $string the original string
     * @return string the string in upper case letters
     * @access private
     * @static
     */
    private static function strtoupperStat($string)
    {
        return strtoupper($string);
    }

    /**
     * A user function object method calling ucfirst()
     *
     * @param  string $string the original string
     * @return string the capitalized string
     * @access private
     */
    private function ucfirstDyn($string)
    {
        return ucfirst($string);
    }

    /**
     * A user function class method calling ucfirst()
     *
     * @param  string $string the original string
     * @return string the capitalized string
     * @access private
     * @static
     */
    private static function ucfirstStat($string)
    {
        return ucfirst($string);
    }

    /**
     * Tests isCallable()
     */
    public function testIsCallable()
    {
        // format: <function/class method>, true|false
        $test = array(// /
            // valid functions/methods
            array('dechex', true),
            array(array(__CLASS__, __FUNCTION__), true),
            array(array($this, __FUNCTION__), true),
            // invalid functions/methods
            array('foo', false),
            array('', false),
            array(array(), false),
            array(array('Foo', 'bar'), false),
            array(array($this, 'bar2'), false),
            array(array(array(), 'bar'), false),
            array(array('Foo', array()), false),
            array(array('Foo', 'bar', 'blah'), false),
            );

        foreach($test as $idx => $values) {
            list($function, $expected) = $values;
            // cheks if the function is callable
            $isCallable = PHP_FunctionCallTracer::isCallable($function);

            $this->assertEquals($expected, $isCallable, 'test #' . $idx);
        }
    }

    /**
     * Tests setUserFunctions()
     */
    public function testSetUserFunctions()
    {
        // format: <functions/methods>, <expected valid ones>, <expected invalid ones>
        $test = array(// /
            array(// a single function name
                array('dechex'),
                array('dechex'),
                array(),
                ),
            array(// a callable single class method
                array(array(__CLASS__, __FUNCTION__)),
                array(array(__CLASS__, __FUNCTION__)),
                array(),
                ),
            array(// a callable single object method
                array(array($this, __FUNCTION__)),
                array(array($this, __FUNCTION__)),
                array(),
                ),
            array(// 2 functions names but callable
                array('dechex', 'ucfirst'),
                array('dechex', 'ucfirst'),
                array(),
                ),
            array(// an invalid class method but seen as 2 invalid functions
                array(array(__CLASS__, 'foo')),
                array(),
                array(array(__CLASS__, 'foo')),
                ),
            array(// a set of funtions/methods
                array(// /
                    // valid functions/methods
                    'dechex',
                    array(__CLASS__, __FUNCTION__),
                    array($this, __FUNCTION__),
                    // invalid functions/methods
                    'foo',
                    '',
                    array(),
                    array('foo'),
                    array('Foo', 'bar'),
                    array($this, 'bar2'),
                    array(array(), 'bar'),
                    array('Foo', array()),
                    array('Foo', 'bar', 'bar2'),
                    ),
                array(// valid functions/methods
                    'dechex',
                    array(__CLASS__, __FUNCTION__),
                    array($this, __FUNCTION__),
                    ),
                array(// invalid functions/methods
                    'foo',
                    '',
                    array(),
                    array('foo'),
                    array('Foo', 'bar'),
                    array($this, 'bar2'),
                    array(array(), 'bar'),
                    array('Foo', array()),
                    array('Foo', 'bar', 'bar2'),
                    ),
                ),
            );

        foreach($test as $idx => $values) {
            list($userFct, $expectedValidFct, $expectedInvalidFct) = $values;

            if ($expectedInvalidFct) {
                // restores the original keys of the invalid functions
                $low = count($expectedValidFct);
                $high = count($expectedInvalidFct) + $low - 1;
                $expectedInvalidFct = array_combine(range($low, $high), $expectedInvalidFct);
            }
            // captures the expected valid and invalid functions/methods
            $expected = array($expectedValidFct, $expectedInvalidFct);
            // sets the valid and invalid functions/methods
            $callback = array('PHP_FunctionCallTracer', 'setUserFunctions');
            $setUserFct = call_user_func_array($callback, $userFct);

            $this->assertEquals($expected, $setUserFct, 'test #' . $idx);
        }
    }

    /**
     * Tests tidyMethodName()
     */
    public function testTidyMethodName()
    {
        // format: <function/class method>, <expected tidied function/class method>
        $test = array(// /
            array('foo', 'foo'),
            array(array(__CLASS__, __FUNCTION__), __CLASS__ . '::' . __FUNCTION__),
            array(array($this, __FUNCTION__), __CLASS__ . '->' . __FUNCTION__),
            array('', '???'),
            array(array('', ''), '???::???'),
            array(array(array(), true), '???::???'),
            );

        foreach($test as $idx => $values) {
            list($function, $expected) = $values;
            // tidies the class/object method names
            $tidied = PHP_FunctionCallTracer::tidyMethodName($function);

            $this->assertEquals($expected, $tidied, 'test #' . $idx);
        }
    }

    /**
     * Tests getTrace()
     */
    public function testGetTrace()
    {
        $userFct = array(// /
            // valid functions/methods
            'dechex',
            array(__CLASS__, __FUNCTION__),
            array($this, __FUNCTION__),
            // invalid functions/methods
            'foo',
            '',
            array(),
            array('foo'),
            array('Foo', 'bar'),
            array(__CLASS__, 'bar2'),
            array($this, 'bar2'),
            array(array(), 'bar'),
            array('Foo', array()),
            array('Foo', 'bar', 'bar2'),
            );

        $expectedValidFct = array(// /
            'dechex',
            __CLASS__ . '::' . __FUNCTION__,
            __CLASS__ . '->' . __FUNCTION__,
            );

        $expectedInvalidFct = array(// /
            'foo',
            '???',
            '???::???',
            'foo::???',
            'Foo::bar',
            __CLASS__ . '::bar2',
            __CLASS__ . '->bar2',
            '???::bar',
            'Foo::???',
            'Foo::bar',
            );

        $low = count($expectedValidFct);
        $high = $low + count($expectedInvalidFct) - 1;
        $expectedInvalidFct = array_combine(range($low, $high), $expectedInvalidFct);

        $expected = array(// /
            'php_uname' => '',
            'date' => '',
            'user_functions' => $expectedValidFct,
            'invalid_user_functions' => $expectedInvalidFct,
            'calls' => array(),
            );
        // sets the valid and invalid functions/methods
        $callback = array('PHP_FunctionCallTracer', 'setUserFunctions');
        $setUserFct = call_user_func_array($callback, $userFct);
        // captures the trace, resets the (dynamic) PHP version details and the date
        $trace = PHP_FunctionCallTracer::getTrace(false);
        $trace['php_uname'] and $trace['php_uname'] = '';
        $trace['date'] and $trace['date'] = '';

        $this->assertEquals($expected, $trace);
    }

    /**
     * Tests putTrace()
     */
    public function testPutTrace()
    {
        // test the display of the trace to the standard output
        $trace = array();
        ob_start() and PHP_FunctionCallTracer::putTrace() and
        $trace = ob_get_contents() and ob_end_clean();
        $this->assertNotEquals(array(), $trace);
        // test the writing of the trace in a file
        $file = tempnam('/tmp', 'fct');
        $trace = PHP_FunctionCallTracer::putTrace($file);
        @unlink($file);
        $this->assertNotEquals(array(), $trace);
    }

    /**
     * Tests filterTrace()
     */
    public function testFilterTrace()
    {
        // format: <trace>, <keys to keep>, <filtered trace>
        $test = array(// /
            array(array('a', 'b', 'c'), array(1, 2), array(1 => 'b', 2 => 'c')),
            array(array('a', 'b', 'c'), 1, array(1 => 'b')),
            array('a', 0, array('a')),
            array(array(), array(), array()),
            array('', '', array()),
            );

        foreach($test as $idx => $values) {
            list($trace, $keys, $expected) = $values;
            // filters the trace
            $filtered = PHP_FunctionCallTracer::filterTrace($trace, $keys);

            $this->assertEquals($expected, $filtered, 'test #' . $idx);
        }
    }

    /**
     * Tests createStackKey()
     */
    public function testCreateStackKey()
    {
        // format: <trace>, <expected unserialized key>
        $test = array(// /
            array(// /
                array(array(), array('file' => 'foo', 'line' => 0, 'class' => 'bar',
                        'type' => '::', 'function' => 'blah')),
                array(array('file' => 'foo', 'line' => 0, 'class' => 'bar',
                        'type' => '::', 'function' => 'blah')),
                ),
            array(// /
                array(array(), array('file' => 'foo', 'line' => 0, 'class' => 'bar',
                        'type' => '::', 'function' => 'blah', 'dummy' => 0), array()),
                array(array('file' => 'foo', 'line' => 0, 'class' => 'bar',
                        'type' => '::', 'function' => 'blah'), array()),
                ),
            array(// /
                array(array(), array('file' => 'foo', 'line' => 0, 'function' => 'blah')),
                array(array('file' => 'foo', 'line' => 0, 'function' => 'blah')),
                ),
            array(// /
                array(array(), array('file' => 'foo', 'line' => 0, 'function' => 'blah',
                        'dummy' => 0)),
                array(array('file' => 'foo', 'line' => 0, 'function' => 'blah')),
                ),
            array(// /
                array(array('file' => 'foo', 'line' => 0, 'function' => 'blah',
                        'dummy' => 0)),
                array(),
                ),
            );

        foreach($test as $idx => $values) {
            list($trace, $expected) = $values;
            // creates the call ID stack key
            $key = PHP_FunctionCallTracer::createStackKey($trace);

            $this->assertEquals($expected, unserialize($key), 'test #' . $idx);
        }
    }

    /**
     * Integration tests
     */
    public function testTrace()
    {
        $test = array(// /
            'NoUserFct.php',
            'OneUserFct.php',
            'MultiUserFct.php',
            'SimpleCall.php',
            'RecursiveCall.php',
            'ComplexCall.php',
            'Integrated.php',
            );
        foreach($test as $file) {
            // creates the input, reference and generated file names
            $inFile = "data/$file";
            $file = str_replace('.php', '.txt', $file);
            $refFile = "reference/$file";
            $generFile = "generated/$file";
            // loads/runs the test and captures the trace
            file_exists($inFile) or
            $this->fail("Error! Cannot access the data file: $inFile");
            require_once $inFile;
            $trace = PHP_FunctionCallTracer::getTrace(false);
            // tidies the trace: removes dynamic content and file paths
            $trace['php_uname'] and $trace['php_uname'] = 'REMOVED FOR TESTING';
            $trace['date'] and $trace['date'] = 'REMOVED FOR TESTING';
            $callback = create_function('&$value, $key',
                '$key === "file" and $value = ".../" . basename($value);');
            array_walk_recursive($trace, $callback);
            $trace = print_r($trace, true);
            // stores the trace
            @file_put_contents($generFile, $trace) or
            $this->fail("Error! Cannot write the generated file: $generFile");
            // reads the generated file
            file_exists($generFile) or
            $this->fail("Error! Cannot access the generated file: $generFile");
            $generated = $this->getFile($generFile);
            // reads the reference file
            file_exists($refFile) or
            $this->fail("Error! Cannot access the reference file: $refFile");
            $reference = $this->getFile($refFile);
            if ($diff = array_diff_assoc($reference, $generated)) {
                // the generated file is different from the reference
                $key = key($diff);
                // sets the line number of the first different line, builds the error message
                $lineNb = $key + 1;
                $error[] = "ERROR! Test: $file, line: $lineNb";
                $error[] = "expecting :{$reference[$key]}";
                $error[] = "instead of:{$generated[$key]}";
                $this->fail(implode("\n", $error));
            }
        }
    }
}
// Call tests_FunctionCallTracerTest::main() if this source file is executed directly.
if (PHPUnit_MAIN_METHOD == "tests_FunctionCallTracerTest::main") {
    tests_FunctionCallTracerTest::main();
}

?>