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();
}
?>