Initial Commit

This commit is contained in:
Riley Schneider
2025-12-03 16:38:10 +01:00
parent c5e26bf594
commit b732d8d4b5
17680 changed files with 5977495 additions and 2 deletions

View File

@@ -0,0 +1,363 @@
<?php
/**
* PHPUnit
*
* Copyright (c) 2001-2013, Sebastian Bergmann <sebastian@phpunit.de>.
* 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 Sebastian Bergmann nor the names of his
* 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.
*
* @package PHPUnit
* @subpackage Util
* @author Sebastian Bergmann <sebastian@phpunit.de>
* @copyright 2001-2013 Sebastian Bergmann <sebastian@phpunit.de>
* @license http://www.opensource.org/licenses/BSD-3-Clause The BSD 3-Clause License
* @link http://www.phpunit.de/
* @since File available since Release 3.1.0
*/
/**
* Class helpers.
*
* @package PHPUnit
* @subpackage Util
* @author Sebastian Bergmann <sebastian@phpunit.de>
* @copyright 2001-2013 Sebastian Bergmann <sebastian@phpunit.de>
* @license http://www.opensource.org/licenses/BSD-3-Clause The BSD 3-Clause License
* @link http://www.phpunit.de/
* @since Class available since Release 3.1.0
*/
class PHPUnit_Util_Class
{
protected static $buffer = array();
/**
* Starts the collection of loaded classes.
*
*/
public static function collectStart()
{
self::$buffer = get_declared_classes();
}
/**
* Stops the collection of loaded classes and
* returns the names of the loaded classes.
*
* @return array
*/
public static function collectEnd()
{
return array_values(
array_diff(get_declared_classes(), self::$buffer)
);
}
/**
* Returns the class hierarchy for a given class.
*
* @param string $className
* @param boolean $asReflectionObjects
* @return array
*/
public static function getHierarchy($className, $asReflectionObjects = FALSE)
{
if ($asReflectionObjects) {
$classes = array(new ReflectionClass($className));
} else {
$classes = array($className);
}
$done = FALSE;
while (!$done) {
if ($asReflectionObjects) {
$class = new ReflectionClass(
$classes[count($classes)-1]->getName()
);
} else {
$class = new ReflectionClass($classes[count($classes)-1]);
}
$parent = $class->getParentClass();
if ($parent !== FALSE) {
if ($asReflectionObjects) {
$classes[] = $parent;
} else {
$classes[] = $parent->getName();
}
} else {
$done = TRUE;
}
}
return $classes;
}
/**
* Returns the parameters of a function or method.
*
* @param ReflectionFunction|ReflectionMethod $method
* @param boolean $forCall
* @return string
* @since Method available since Release 3.2.0
*/
public static function getMethodParameters($method, $forCall = FALSE)
{
$parameters = array();
foreach ($method->getParameters() as $i => $parameter) {
$name = '$' . $parameter->getName();
/* Note: PHP extensions may use empty names for reference arguments
* or "..." for methods taking a variable number of arguments.
*/
if ($name === '$' || $name === '$...') {
$name = '$arg' . $i;
}
$default = '';
$reference = '';
$typeHint = '';
if (!$forCall) {
if ($parameter->isArray()) {
$typeHint = 'array ';
}
else if (version_compare(PHP_VERSION, '5.4', '>') &&
$parameter->isCallable()) {
$typeHint = 'callable ';
}
else {
try {
$class = $parameter->getClass();
}
catch (ReflectionException $e) {
$class = FALSE;
}
if ($class) {
$typeHint = $class->getName() . ' ';
}
}
if ($parameter->isDefaultValueAvailable()) {
$value = $parameter->getDefaultValue();
$default = ' = ' . var_export($value, TRUE);
}
else if ($parameter->isOptional()) {
$default = ' = null';
}
}
if ($parameter->isPassedByReference()) {
$reference = '&';
}
$parameters[] = $typeHint . $reference . $name . $default;
}
return join(', ', $parameters);
}
/**
* Returns the package information of a user-defined class.
*
* @param string $className
* @param string $docComment
* @return array
*/
public static function getPackageInformation($className, $docComment)
{
$result = array(
'namespace' => '',
'fullPackage' => '',
'category' => '',
'package' => '',
'subpackage' => ''
);
if (strpos($className, '\\') !== FALSE) {
$result['namespace'] = self::arrayToName(
explode('\\', $className)
);
}
if (preg_match('/@category[\s]+([\.\w]+)/', $docComment, $matches)) {
$result['category'] = $matches[1];
}
if (preg_match('/@package[\s]+([\.\w]+)/', $docComment, $matches)) {
$result['package'] = $matches[1];
$result['fullPackage'] = $matches[1];
}
if (preg_match('/@subpackage[\s]+([\.\w]+)/', $docComment, $matches)) {
$result['subpackage'] = $matches[1];
$result['fullPackage'] .= '.' . $matches[1];
}
if (empty($result['fullPackage'])) {
$result['fullPackage'] = self::arrayToName(
explode('_', str_replace('\\', '_', $className)), '.'
);
}
return $result;
}
/**
* Returns the value of a static attribute.
* This also works for attributes that are declared protected or private.
*
* @param string $className
* @param string $attributeName
* @return mixed
* @throws PHPUnit_Framework_Exception
* @since Method available since Release 3.4.0
*/
public static function getStaticAttribute($className, $attributeName)
{
if (!is_string($className)) {
throw PHPUnit_Util_InvalidArgumentHelper::factory(1, 'string');
}
if (!class_exists($className)) {
throw PHPUnit_Util_InvalidArgumentHelper::factory(1, 'class name');
}
if (!is_string($attributeName)) {
throw PHPUnit_Util_InvalidArgumentHelper::factory(2, 'string');
}
$class = new ReflectionClass($className);
while ($class) {
$attributes = $class->getStaticProperties();
if (array_key_exists($attributeName, $attributes)) {
return $attributes[$attributeName];
}
$class = $class->getParentClass();
}
throw new PHPUnit_Framework_Exception(
sprintf(
'Attribute "%s" not found in class.',
$attributeName
)
);
}
/**
* Returns the value of an object's attribute.
* This also works for attributes that are declared protected or private.
*
* @param object $object
* @param string $attributeName
* @return mixed
* @throws PHPUnit_Framework_Exception
* @since Method available since Release 3.4.0
*/
public static function getObjectAttribute($object, $attributeName)
{
if (!is_object($object)) {
throw PHPUnit_Util_InvalidArgumentHelper::factory(1, 'object');
}
if (!is_string($attributeName)) {
throw PHPUnit_Util_InvalidArgumentHelper::factory(2, 'string');
}
try {
$attribute = new ReflectionProperty($object, $attributeName);
}
catch (ReflectionException $e) {
$reflector = new ReflectionObject($object);
while ($reflector = $reflector->getParentClass()) {
try {
$attribute = $reflector->getProperty($attributeName);
break;
}
catch(ReflectionException $e) {
}
}
}
if (isset($attribute)) {
if (!$attribute || $attribute->isPublic()) {
return $object->$attributeName;
}
$attribute->setAccessible(TRUE);
$value = $attribute->getValue($object);
$attribute->setAccessible(FALSE);
return $value;
}
throw new PHPUnit_Framework_Exception(
sprintf(
'Attribute "%s" not found in object.',
$attributeName
)
);
}
/**
* Returns the package information of a user-defined class.
*
* @param array $parts
* @param string $join
* @return string
* @since Method available since Release 3.2.12
*/
protected static function arrayToName(array $parts, $join = '\\')
{
$result = '';
if (count($parts) > 1) {
array_pop($parts);
$result = join($join, $parts);
}
return $result;
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,102 @@
<?php
/**
* PHPUnit
*
* Copyright (c) 2002-2010, Sebastian Bergmann <sebastian@phpunit.de>.
* 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 Sebastian Bergmann nor the names of his
* 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.
*
* @package PHPUnit
* @subpackage Framework
* @author Ralph Schindler <ralph.schindler@zend.com>
* @author Sebastian Bergmann <sebastian@phpunit.de>
* @copyright 2002-2010 Sebastian Bergmann <sebastian@phpunit.de>
* @license http://www.opensource.org/licenses/BSD-3-Clause The BSD 3-Clause License
* @link http://www.phpunit.de/
* @since File available since Release 3.5.7
*/
/**
* Class to hold the information about a deprecated feature that was used
*
* @package PHPUnit
* @subpackage Framework
* @author Ralph Schindler <ralph.schindler@zend.com>
* @author Sebastian Bergmann <sebastian@phpunit.de>
* @copyright 2002-2010 Sebastian Bergmann <sebastian@phpunit.de>
* @license http://www.opensource.org/licenses/BSD-3-Clause The BSD 3-Clause License
* @link http://www.phpunit.de/
* @since Interface available since Release 3.5.7
*/
class PHPUnit_Util_DeprecatedFeature
{
/**
* @var array
*/
protected $traceInfo = array();
/**
* @var string
*/
protected $message = NULL;
/**
* @param string $message
* @param array $traceInfo
*/
public function __construct($message, array $traceInfo = array())
{
$this->message = $message;
$this->traceInfo = $traceInfo;
}
/**
* Build a string representation of the deprecated feature that was raised
*
* @return string
*/
public function __toString()
{
$string = '';
if (isset($this->traceInfo['file'])) {
$string .= $this->traceInfo['file'];
if (isset($this->traceInfo['line'])) {
$string .= ':' . $this->traceInfo['line'] . ' - ';
}
}
$string .= $this->message;
return $string;
}
}

View File

@@ -0,0 +1,201 @@
<?php
/**
* PHPUnit
*
* Copyright (c) 2002-2010, Sebastian Bergmann <sebastian@phpunit.de>.
* 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 Sebastian Bergmann nor the names of his
* 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.
*
* @package PHPUnit
* @subpackage Framework
* @author Ralph Schindler <ralph.schindler@zend.com>
* @author Sebastian Bergmann <sebastian@phpunit.de>
* @copyright 2002-2010 Sebastian Bergmann <sebastian@phpunit.de>
* @license http://www.opensource.org/licenses/BSD-3-Clause The BSD 3-Clause License
* @link http://www.phpunit.de/
* @since File available since Release 3.5.7
*/
/**
* Test Listener that tracks the usage of deprecated features.
*
* @package PHPUnit
* @subpackage Framework
* @author Ralph Schindler <ralph.schindler@zend.com>
* @author Sebastian Bergmann <sebastian@phpunit.de>
* @copyright 2002-2010 Sebastian Bergmann <sebastian@phpunit.de>
* @license http://www.opensource.org/licenses/BSD-3-Clause The BSD 3-Clause License
* @link http://www.phpunit.de/
* @since Class available since Release 3.5.7
*/
class PHPUnit_Util_DeprecatedFeature_Logger implements PHPUnit_Framework_TestListener
{
/**
* @var PHPUnit_Framework_TestCase
*/
protected static $currentTest = NULL;
/**
* This is the publically accessible API for notifying the system that a
* deprecated feature has been used.
*
* If it is run via a TestRunner and the test extends
* PHPUnit_Framework_TestCase, then this will inject the result into the
* test runner for display, if not, it will throw the notice to STDERR.
*
* @param string $message
* @param int|bool $backtraceDepth
*/
public static function log($message, $backtraceDepth = 2)
{
if ($backtraceDepth !== FALSE) {
$trace = debug_backtrace(FALSE);
if (is_int($backtraceDepth)) {
$traceItem = $trace[$backtraceDepth];
}
if (!isset($traceItem['file'])) {
$reflectionClass = new ReflectionClass($traceItem['class']);
$traceItem['file'] = $reflectionClass->getFileName();
}
if (!isset($traceItem['line']) &&
isset($traceItem['class']) &&
isset($traceItem['function'])) {
if (!isset($reflectionClass)) {
$reflectionClass = new ReflectionClass($traceItem['class']);
}
$method = $reflectionClass->getMethod($traceItem['function']);
$traceItem['line'] = '(between ' . $method->getStartLine() .
' and ' . $method->getEndLine() . ')';
}
}
$deprecatedFeature = new PHPUnit_Util_DeprecatedFeature(
$message, $traceItem
);
if (self::$currentTest instanceof PHPUnit_Framework_TestCase) {
$result = self::$currentTest->getTestResultObject();
$result->addDeprecatedFeature($deprecatedFeature);
} else {
file_put_contents('php://stderr', $deprecatedFeature);
}
}
/**
* An error occurred.
*
* @param PHPUnit_Framework_Test $test
* @param Exception $e
* @param float $time
*/
public function addError(PHPUnit_Framework_Test $test, Exception $e, $time)
{
}
/**
* A failure occurred.
*
* @param PHPUnit_Framework_Test $test
* @param PHPUnit_Framework_AssertionFailedError $e
* @param float $time
*/
public function addFailure(PHPUnit_Framework_Test $test, PHPUnit_Framework_AssertionFailedError $e, $time)
{
}
/**
* Incomplete test.
*
* @param PHPUnit_Framework_Test $test
* @param Exception $e
* @param float $time
*/
public function addIncompleteTest(PHPUnit_Framework_Test $test, Exception $e, $time)
{
}
/**
* Skipped test.
*
* @param PHPUnit_Framework_Test $test
* @param Exception $e
* @param float $time
* @since Method available since Release 3.0.0
*/
public function addSkippedTest(PHPUnit_Framework_Test $test, Exception $e, $time)
{
}
/**
* A test suite started.
*
* @param PHPUnit_Framework_TestSuite $suite
* @since Method available since Release 2.2.0
*/
public function startTestSuite(PHPUnit_Framework_TestSuite $suite)
{
}
/**
* A test suite ended.
*
* @param PHPUnit_Framework_TestSuite $suite
* @since Method available since Release 2.2.0
*/
public function endTestSuite(PHPUnit_Framework_TestSuite $suite)
{
}
/**
* A test started.
*
* @param PHPUnit_Framework_Test $test
*/
public function startTest(PHPUnit_Framework_Test $test)
{
self::$currentTest = $test;
}
/**
* A test ended.
*
* @param PHPUnit_Framework_Test $test
* @param float $time
*/
public function endTest(PHPUnit_Framework_Test $test, $time)
{
self::$currentTest = NULL;
}
}

View File

@@ -0,0 +1,292 @@
<?php
/**
* PHPUnit
*
* Copyright (c) 2001-2013, Sebastian Bergmann <sebastian@phpunit.de>.
* 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 Sebastian Bergmann nor the names of his
* 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.
*
* @package PHPUnit
* @subpackage Util
* @author Sebastian Bergmann <sebastian@phpunit.de>
* @author Kore Nordmann <mail@kore-nordmann.de>
* @copyright 2001-2013 Sebastian Bergmann <sebastian@phpunit.de>
* @license http://www.opensource.org/licenses/BSD-3-Clause The BSD 3-Clause License
* @link http://www.phpunit.de/
* @since File available since Release 3.4.0
*/
/**
* Diff implementation.
*
* @package PHPUnit
* @subpackage Util
* @author Sebastian Bergmann <sebastian@phpunit.de>
* @author Kore Nordmann <mail@kore-nordmann.de>
* @copyright 2001-2013 Sebastian Bergmann <sebastian@phpunit.de>
* @license http://www.opensource.org/licenses/BSD-3-Clause The BSD 3-Clause License
* @link http://www.phpunit.de/
* @since Class available since Release 3.4.0
*/
class PHPUnit_Util_Diff
{
/**
* Returns the diff between two arrays or strings as string.
*
* @param array|string $from
* @param array|string $to
* @return string
*/
public static function diff($from, $to)
{
$buffer= "--- Expected\n+++ Actual\n";
$diff = self::diffToArray($from,$to);
$inOld = FALSE;
$i = 0;
$old = array();
foreach ($diff as $line) {
if ($line[1] === 0 /* OLD */) {
if ($inOld === FALSE) {
$inOld = $i;
}
}
else if ($inOld !== FALSE) {
if (($i - $inOld) > 5) {
$old[$inOld] = $i - 1;
}
$inOld = FALSE;
}
++$i;
}
$start = isset($old[0]) ? $old[0] : 0;
$end = count($diff);
$i = 0;
if ($tmp = array_search($end, $old)) {
$end = $tmp;
}
$newChunk = TRUE;
for ($i = $start; $i < $end; $i++) {
if (isset($old[$i])) {
$buffer .= "\n";
$newChunk = TRUE;
$i = $old[$i];
}
if ($newChunk) {
$buffer .= "@@ @@\n";
$newChunk = FALSE;
}
if ($diff[$i][1] === 1 /* ADDED */) {
$buffer .= '+' . $diff[$i][0] . "\n";
}
else if ($diff[$i][1] === 2 /* REMOVED */) {
$buffer .= '-' . $diff[$i][0] . "\n";
}
else {
$buffer .= ' ' . $diff[$i][0] . "\n";
}
}
return $buffer;
}
/**
* Returns the diff between two arrays or strings as array.
*
* every array-entry containts two elements:
* - [0] => string $token
* - [1] => 2|1|0
*
* - 2: REMOVED: $token was removed from $from
* - 1: ADDED: $token was added to $from
* - 0: OLD: $token is not changed in $to
*
* @param array|string $from
* @param array|string $to
* @return array
*/
public static function diffToArray($from, $to)
{
preg_match_all('(\r\n|\r|\n)', $from, $fromMatches);
preg_match_all('(\r\n|\r|\n)', $to, $toMatches);
if (is_string($from)) {
$from = preg_split('(\r\n|\r|\n)', $from);
}
if (is_string($to)) {
$to = preg_split('(\r\n|\r|\n)', $to);
}
$start = array();
$end = array();
$fromLength = count($from);
$toLength = count($to);
$length = min($fromLength, $toLength);
for ($i = 0; $i < $length; ++$i) {
if ($from[$i] === $to[$i]) {
$start[] = $from[$i];
unset($from[$i], $to[$i]);
} else {
break;
}
}
$length -= $i;
for ($i = 1; $i < $length; ++$i) {
if ($from[$fromLength - $i] === $to[$toLength - $i]) {
array_unshift($end, $from[$fromLength - $i]);
unset($from[$fromLength - $i], $to[$toLength - $i]);
} else {
break;
}
}
$common = self::longestCommonSubsequence(
array_values($from), array_values($to)
);
$diff = array();
$line = 0;
if (isset($fromMatches[0]) && $toMatches[0] &&
count($fromMatches[0]) === count($toMatches[0]) &&
$fromMatches[0] !== $toMatches[0]) {
$diff[] = array(
'#Warning: Strings contain different line endings!', 0
);
}
foreach ($start as $token) {
$diff[] = array($token, 0 /* OLD */);
}
reset($from);
reset($to);
foreach ($common as $token) {
while ((($fromToken = reset($from)) !== $token)) {
$diff[] = array(array_shift($from), 2 /* REMOVED */);
}
while ((($toToken = reset($to)) !== $token)) {
$diff[] = array(array_shift($to), 1 /* ADDED */);
}
$diff[] = array($token, 0 /* OLD */);
array_shift($from);
array_shift($to);
}
while (($token = array_shift($from)) !== NULL) {
$diff[] = array($token, 2 /* REMOVED */);
}
while (($token = array_shift($to)) !== NULL) {
$diff[] = array($token, 1 /* ADDED */);
}
foreach ($end as $token) {
$diff[] = array($token, 0 /* OLD */);
}
return $diff;
}
/**
* Calculates the longest common subsequence of two arrays.
*
* @param array $from
* @param array $to
* @return array
*/
protected static function longestCommonSubsequence(array $from, array $to)
{
$common = array();
$matrix = array();
$fromLength = count($from);
$toLength = count($to);
for ($i = 0; $i <= $fromLength; ++$i) {
$matrix[$i][0] = 0;
}
for ($j = 0; $j <= $toLength; ++$j) {
$matrix[0][$j] = 0;
}
for ($i = 1; $i <= $fromLength; ++$i) {
for ($j = 1; $j <= $toLength; ++$j) {
$matrix[$i][$j] = max(
$matrix[$i-1][$j],
$matrix[$i][$j-1],
$from[$i-1] === $to[$j-1] ? $matrix[$i-1][$j-1] + 1 : 0
);
}
}
$i = $fromLength;
$j = $toLength;
while ($i > 0 && $j > 0) {
if ($from[$i-1] === $to[$j-1]) {
array_unshift($common, $from[$i-1]);
--$i;
--$j;
}
else if ($matrix[$i][$j-1] > $matrix[$i-1][$j]) {
--$j;
}
else {
--$i;
}
}
return $common;
}
}

View File

@@ -0,0 +1,132 @@
<?php
/**
* PHPUnit
*
* Copyright (c) 2001-2013, Sebastian Bergmann <sebastian@phpunit.de>.
* 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 Sebastian Bergmann nor the names of his
* 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.
*
* @package PHPUnit
* @subpackage Util
* @author Sebastian Bergmann <sebastian@phpunit.de>
* @copyright 2001-2013 Sebastian Bergmann <sebastian@phpunit.de>
* @license http://www.opensource.org/licenses/BSD-3-Clause The BSD 3-Clause License
* @link http://www.phpunit.de/
* @since File available since Release 2.3.0
*/
// Workaround for http://bugs.php.net/bug.php?id=47987,
// see https://github.com/sebastianbergmann/phpunit/issues#issue/125 for details
require_once __DIR__ . '/../Framework/Error.php';
require_once __DIR__ . '/../Framework/Error/Notice.php';
require_once __DIR__ . '/../Framework/Error/Warning.php';
require_once __DIR__ . '/../Framework/Error/Deprecated.php';
/**
* Error handler that converts PHP errors and warnings to exceptions.
*
* @package PHPUnit
* @subpackage Util
* @author Sebastian Bergmann <sebastian@phpunit.de>
* @copyright 2001-2013 Sebastian Bergmann <sebastian@phpunit.de>
* @license http://www.opensource.org/licenses/BSD-3-Clause The BSD 3-Clause License
* @link http://www.phpunit.de/
* @since Class available since Release 3.3.0
*/
class PHPUnit_Util_ErrorHandler
{
protected static $errorStack = array();
/**
* Returns the error stack.
*
* @return array
*/
public static function getErrorStack()
{
return self::$errorStack;
}
/**
* @param integer $errno
* @param string $errstr
* @param string $errfile
* @param integer $errline
* @throws PHPUnit_Framework_Error
*/
public static function handleError($errno, $errstr, $errfile, $errline)
{
if (!($errno & error_reporting())) {
return FALSE;
}
self::$errorStack[] = array($errno, $errstr, $errfile, $errline);
$trace = debug_backtrace(FALSE);
array_shift($trace);
foreach ($trace as $frame) {
if ($frame['function'] == '__toString') {
return FALSE;
}
}
if ($errno == E_NOTICE || $errno == E_USER_NOTICE || $errno == E_STRICT) {
if (PHPUnit_Framework_Error_Notice::$enabled !== TRUE) {
return FALSE;
}
$exception = 'PHPUnit_Framework_Error_Notice';
}
else if ($errno == E_WARNING || $errno == E_USER_WARNING) {
if (PHPUnit_Framework_Error_Warning::$enabled !== TRUE) {
return FALSE;
}
$exception = 'PHPUnit_Framework_Error_Warning';
}
else if ($errno == E_DEPRECATED || $errno == E_USER_DEPRECATED) {
if (PHPUnit_Framework_Error_Deprecated::$enabled !== TRUE) {
return FALSE;
}
$exception = 'PHPUnit_Framework_Error_Deprecated';
}
else {
$exception = 'PHPUnit_Framework_Error';
}
throw new $exception($errstr, $errno, $errfile, $errline);
}
}

View File

@@ -0,0 +1,107 @@
<?php
/**
* PHPUnit
*
* Copyright (c) 2001-2013, Sebastian Bergmann <sebastian@phpunit.de>.
* 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 Sebastian Bergmann nor the names of his
* 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.
*
* @package PHPUnit
* @subpackage Util
* @author Sebastian Bergmann <sebastian@phpunit.de>
* @copyright 2001-2013 Sebastian Bergmann <sebastian@phpunit.de>
* @license http://www.opensource.org/licenses/BSD-3-Clause The BSD 3-Clause License
* @link http://www.phpunit.de/
* @since File available since Release 2.3.0
*/
/**
* Utility methods to load PHP sourcefiles.
*
* @package PHPUnit
* @subpackage Util
* @author Sebastian Bergmann <sebastian@phpunit.de>
* @copyright 2001-2013 Sebastian Bergmann <sebastian@phpunit.de>
* @license http://www.opensource.org/licenses/BSD-3-Clause The BSD 3-Clause License
* @link http://www.phpunit.de/
* @since Class available since Release 2.3.0
*/
class PHPUnit_Util_Fileloader
{
/**
* Checks if a PHP sourcefile is readable.
* The sourcefile is loaded through the load() method.
*
* @param string $filename
* @throws PHPUnit_Framework_Exception
*/
public static function checkAndLoad($filename)
{
$includePathFilename = stream_resolve_include_path($filename);
if (!$includePathFilename || !is_readable($includePathFilename)) {
throw new PHPUnit_Framework_Exception(
sprintf('Cannot open file "%s".' . "\n", $filename)
);
}
self::load($includePathFilename);
return $includePathFilename;
}
/**
* Loads a PHP sourcefile.
*
* @param string $filename
* @return mixed
* @since Method available since Release 3.0.0
*/
public static function load($filename)
{
$oldVariableNames = array_keys(get_defined_vars());
include_once $filename;
$newVariables = get_defined_vars();
$newVariableNames = array_diff(
array_keys($newVariables), $oldVariableNames
);
foreach ($newVariableNames as $variableName) {
if ($variableName != 'oldVariableNames') {
$GLOBALS[$variableName] = $newVariables[$variableName];
}
}
return $filename;
}
}

View File

@@ -0,0 +1,81 @@
<?php
/**
* PHPUnit
*
* Copyright (c) 2001-2013, Sebastian Bergmann <sebastian@phpunit.de>.
* 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 Sebastian Bergmann nor the names of his
* 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.
*
* @package PHPUnit
* @subpackage Util
* @author Sebastian Bergmann <sebastian@phpunit.de>
* @copyright 2001-2013 Sebastian Bergmann <sebastian@phpunit.de>
* @license http://www.opensource.org/licenses/BSD-3-Clause The BSD 3-Clause License
* @link http://www.phpunit.de/
* @since File available since Release 3.0.0
*/
/**
* Filesystem helpers.
*
* @package PHPUnit
* @subpackage Util
* @author Sebastian Bergmann <sebastian@phpunit.de>
* @copyright 2001-2013 Sebastian Bergmann <sebastian@phpunit.de>
* @license http://www.opensource.org/licenses/BSD-3-Clause The BSD 3-Clause License
* @link http://www.phpunit.de/
* @since Class available since Release 3.0.0
*/
class PHPUnit_Util_Filesystem
{
/**
* @var array
*/
protected static $buffer = array();
/**
* Maps class names to source file names:
* - PEAR CS: Foo_Bar_Baz -> Foo/Bar/Baz.php
* - Namespace: Foo\Bar\Baz -> Foo/Bar/Baz.php
*
* @param string $className
* @return string
* @since Method available since Release 3.4.0
*/
public static function classNameToFilename($className)
{
return str_replace(
array('_', '\\'),
DIRECTORY_SEPARATOR,
$className
) . '.php';
}
}

View File

@@ -0,0 +1,146 @@
<?php
/**
* PHPUnit
*
* Copyright (c) 2001-2013, Sebastian Bergmann <sebastian@phpunit.de>.
* 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 Sebastian Bergmann nor the names of his
* 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.
*
* @package PHPUnit
* @subpackage Util
* @author Sebastian Bergmann <sebastian@phpunit.de>
* @copyright 2001-2013 Sebastian Bergmann <sebastian@phpunit.de>
* @license http://www.opensource.org/licenses/BSD-3-Clause The BSD 3-Clause License
* @link http://www.phpunit.de/
* @since File available since Release 2.0.0
*/
/**
* Utility class for code filtering.
*
* @package PHPUnit
* @subpackage Util
* @author Sebastian Bergmann <sebastian@phpunit.de>
* @copyright 2001-2013 Sebastian Bergmann <sebastian@phpunit.de>
* @license http://www.opensource.org/licenses/BSD-3-Clause The BSD 3-Clause License
* @link http://www.phpunit.de/
* @since Class available since Release 2.0.0
*/
class PHPUnit_Util_Filter
{
/**
* Filters stack frames from PHPUnit classes.
*
* @param Exception $e
* @param boolean $asString
* @return string
*/
public static function getFilteredStacktrace(Exception $e, $asString = TRUE)
{
$prefix = FALSE;
$script = realpath($GLOBALS['_SERVER']['SCRIPT_NAME']);
if (defined('__PHPUNIT_PHAR__')) {
$prefix = 'phar://' . __PHPUNIT_PHAR__ . '/';
}
if (!defined('PHPUNIT_TESTSUITE')) {
$blacklist = PHPUnit_Util_GlobalState::phpunitFiles();
} else {
$blacklist = array();
}
if ($asString === TRUE) {
$filteredStacktrace = '';
} else {
$filteredStacktrace = array();
}
if ($e instanceof PHPUnit_Framework_SyntheticError) {
$eTrace = $e->getSyntheticTrace();
$eFile = $e->getSyntheticFile();
$eLine = $e->getSyntheticLine();
} else {
if ($e->getPrevious()) {
$eTrace = $e->getPrevious()->getTrace();
} else {
$eTrace = $e->getTrace();
}
$eFile = $e->getFile();
$eLine = $e->getLine();
}
if (!self::frameExists($eTrace, $eFile, $eLine)) {
array_unshift(
$eTrace, array('file' => $eFile, 'line' => $eLine)
);
}
foreach ($eTrace as $frame) {
if (isset($frame['file']) && is_file($frame['file']) &&
!isset($blacklist[$frame['file']]) &&
strpos($frame['file'], $prefix) !== 0 &&
$frame['file'] !== $script) {
if ($asString === TRUE) {
$filteredStacktrace .= sprintf(
"%s:%s\n",
$frame['file'],
isset($frame['line']) ? $frame['line'] : '?'
);
} else {
$filteredStacktrace[] = $frame;
}
}
}
return $filteredStacktrace;
}
/**
* @param array $trace
* @param string $file
* @param int $line
* @return boolean
* @since Method available since Release 3.3.2
*/
public static function frameExists(array $trace, $file, $line)
{
foreach ($trace as $frame) {
if (isset($frame['file']) && $frame['file'] == $file &&
isset($frame['line']) && $frame['line'] == $line) {
return TRUE;
}
}
return FALSE;
}
}

View File

@@ -0,0 +1,207 @@
<?php
/**
* PHPUnit
*
* Copyright (c) 2001-2013, Sebastian Bergmann <sebastian@phpunit.de>.
* 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 Sebastian Bergmann nor the names of his
* 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.
*
* @package PHPUnit
* @subpackage Util
* @author Sebastian Bergmann <sebastian@phpunit.de>
* @copyright 2001-2013 Sebastian Bergmann <sebastian@phpunit.de>
* @license http://www.opensource.org/licenses/BSD-3-Clause The BSD 3-Clause License
* @link http://www.phpunit.de/
* @since File available since Release 3.0.0
*/
/**
* Command-line options parsing class.
*
* @package PHPUnit
* @subpackage Util
* @author Andrei Zmievski <andrei@php.net>
* @author Sebastian Bergmann <sebastian@phpunit.de>
* @copyright 2001-2013 Sebastian Bergmann <sebastian@phpunit.de>
* @license http://www.opensource.org/licenses/BSD-3-Clause The BSD 3-Clause License
* @link http://www.phpunit.de/
* @since Class available since Release 3.0.0
*/
class PHPUnit_Util_Getopt
{
public static function getopt(array $args, $short_options, $long_options = NULL)
{
if (empty($args)) {
return array(array(), array());
}
$opts = array();
$non_opts = array();
if ($long_options) {
sort($long_options);
}
if (isset($args[0][0]) && $args[0][0] != '-') {
array_shift($args);
}
reset($args);
array_map('trim', $args);
while (list($i, $arg) = each($args)) {
if ($arg == '') {
continue;
}
if ($arg == '--') {
$non_opts = array_merge($non_opts, array_slice($args, $i + 1));
break;
}
if ($arg[0] != '-' ||
(strlen($arg) > 1 && $arg[1] == '-' && !$long_options)) {
$non_opts = array_merge($non_opts, array_slice($args, $i));
break;
}
elseif (strlen($arg) > 1 && $arg[1] == '-') {
self::parseLongOption(
substr($arg, 2), $long_options, $opts, $args
);
}
else {
self::parseShortOption(
substr($arg, 1), $short_options, $opts, $args
);
}
}
return array($opts, $non_opts);
}
protected static function parseShortOption($arg, $short_options, &$opts, &$args)
{
$argLen = strlen($arg);
for ($i = 0; $i < $argLen; $i++) {
$opt = $arg[$i];
$opt_arg = NULL;
if (($spec = strstr($short_options, $opt)) === FALSE ||
$arg[$i] == ':') {
throw new PHPUnit_Framework_Exception(
"unrecognized option -- $opt"
);
}
if (strlen($spec) > 1 && $spec[1] == ':') {
if (strlen($spec) > 2 && $spec[2] == ':') {
if ($i + 1 < $argLen) {
$opts[] = array($opt, substr($arg, $i + 1));
break;
}
} else {
if ($i + 1 < $argLen) {
$opts[] = array($opt, substr($arg, $i + 1));
break;
}
else if (list(, $opt_arg) = each($args)) {
}
else {
throw new PHPUnit_Framework_Exception(
"option requires an argument -- $opt"
);
}
}
}
$opts[] = array($opt, $opt_arg);
}
}
protected static function parseLongOption($arg, $long_options, &$opts, &$args)
{
$count = count($long_options);
$list = explode('=', $arg);
$opt = $list[0];
$opt_arg = NULL;
if (count($list) > 1) {
$opt_arg = $list[1];
}
$opt_len = strlen($opt);
for ($i = 0; $i < $count; $i++) {
$long_opt = $long_options[$i];
$opt_start = substr($long_opt, 0, $opt_len);
if ($opt_start != $opt) {
continue;
}
$opt_rest = substr($long_opt, $opt_len);
if ($opt_rest != '' && $opt[0] != '=' && $i + 1 < $count &&
$opt == substr($long_options[$i+1], 0, $opt_len)) {
throw new PHPUnit_Framework_Exception(
"option --$opt is ambiguous"
);
}
if (substr($long_opt, -1) == '=') {
if (substr($long_opt, -2) != '==') {
if (!strlen($opt_arg) &&
!(list(, $opt_arg) = each($args))) {
throw new PHPUnit_Framework_Exception(
"option --$opt requires an argument"
);
}
}
}
else if ($opt_arg) {
throw new PHPUnit_Framework_Exception(
"option --$opt doesn't allow an argument"
);
}
$opts[] = array('--' . $opt, $opt_arg);
return;
}
throw new PHPUnit_Framework_Exception("unrecognized option --$opt");
}
}

View File

@@ -0,0 +1,426 @@
<?php
/**
* PHPUnit
*
* Copyright (c) 2001-2013, Sebastian Bergmann <sebastian@phpunit.de>.
* 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 Sebastian Bergmann nor the names of his
* 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.
*
* @package PHPUnit
* @subpackage Util
* @author Sebastian Bergmann <sebastian@phpunit.de>
* @copyright 2001-2013 Sebastian Bergmann <sebastian@phpunit.de>
* @license http://www.opensource.org/licenses/BSD-3-Clause The BSD 3-Clause License
* @link http://www.phpunit.de/
* @since File available since Release 3.4.0
*/
/**
*
*
* @package PHPUnit
* @subpackage Util
* @author Sebastian Bergmann <sebastian@phpunit.de>
* @copyright 2001-2013 Sebastian Bergmann <sebastian@phpunit.de>
* @license http://www.opensource.org/licenses/BSD-3-Clause The BSD 3-Clause License
* @link http://www.phpunit.de/
* @since Class available since Release 3.4.0
*/
class PHPUnit_Util_GlobalState
{
/**
* @var array
*/
protected static $globals = array();
/**
* @var array
*/
protected static $staticAttributes = array();
/**
* @var array
*/
protected static $superGlobalArrays = array(
'_ENV',
'_POST',
'_GET',
'_COOKIE',
'_SERVER',
'_FILES',
'_REQUEST'
);
/**
* @var array
*/
protected static $superGlobalArraysLong = array(
'HTTP_ENV_VARS',
'HTTP_POST_VARS',
'HTTP_GET_VARS',
'HTTP_COOKIE_VARS',
'HTTP_SERVER_VARS',
'HTTP_POST_FILES'
);
/**
* @var array
*/
protected static $phpunitFiles;
public static function backupGlobals(array $blacklist)
{
self::$globals = array();
$superGlobalArrays = self::getSuperGlobalArrays();
foreach ($superGlobalArrays as $superGlobalArray) {
if (!in_array($superGlobalArray, $blacklist)) {
self::backupSuperGlobalArray($superGlobalArray);
}
}
foreach (array_keys($GLOBALS) as $key) {
if ($key != 'GLOBALS' &&
!in_array($key, $superGlobalArrays) &&
!in_array($key, $blacklist) &&
!$GLOBALS[$key] instanceof Closure) {
self::$globals['GLOBALS'][$key] = serialize($GLOBALS[$key]);
}
}
}
public static function restoreGlobals(array $blacklist)
{
if (ini_get('register_long_arrays') == '1') {
$superGlobalArrays = array_merge(
self::$superGlobalArrays, self::$superGlobalArraysLong
);
} else {
$superGlobalArrays = self::$superGlobalArrays;
}
foreach ($superGlobalArrays as $superGlobalArray) {
if (!in_array($superGlobalArray, $blacklist)) {
self::restoreSuperGlobalArray($superGlobalArray);
}
}
foreach (array_keys($GLOBALS) as $key) {
if ($key != 'GLOBALS' &&
!in_array($key, $superGlobalArrays) &&
!in_array($key, $blacklist)) {
if (isset(self::$globals['GLOBALS'][$key])) {
$GLOBALS[$key] = unserialize(
self::$globals['GLOBALS'][$key]
);
} else {
unset($GLOBALS[$key]);
}
}
}
self::$globals = array();
}
protected static function backupSuperGlobalArray($superGlobalArray)
{
self::$globals[$superGlobalArray] = array();
if (isset($GLOBALS[$superGlobalArray]) &&
is_array($GLOBALS[$superGlobalArray])) {
foreach ($GLOBALS[$superGlobalArray] as $key => $value) {
self::$globals[$superGlobalArray][$key] = serialize($value);
}
}
}
protected static function restoreSuperGlobalArray($superGlobalArray)
{
if (isset($GLOBALS[$superGlobalArray]) &&
is_array($GLOBALS[$superGlobalArray]) &&
isset(self::$globals[$superGlobalArray])) {
$keys = array_keys(
array_merge(
$GLOBALS[$superGlobalArray], self::$globals[$superGlobalArray]
)
);
foreach ($keys as $key) {
if (isset(self::$globals[$superGlobalArray][$key])) {
$GLOBALS[$superGlobalArray][$key] = unserialize(
self::$globals[$superGlobalArray][$key]
);
} else {
unset($GLOBALS[$superGlobalArray][$key]);
}
}
}
self::$globals[$superGlobalArray] = array();
}
public static function getIncludedFilesAsString()
{
$blacklist = self::phpunitFiles();
$files = get_included_files();
$prefix = FALSE;
$result = '';
if (defined('__PHPUNIT_PHAR__')) {
$prefix = 'phar://' . __PHPUNIT_PHAR__ . '/';
}
for ($i = count($files) - 1; $i > 0; $i--) {
$file = $files[$i];
if ($prefix !== FALSE) {
$file = str_replace($prefix, '', $file);
}
if (!isset($blacklist[$file]) && is_file($file)) {
$result = 'require_once \'' . $file . "';\n" . $result;
}
}
return $result;
}
public static function getConstantsAsString()
{
$constants = get_defined_constants(TRUE);
$result = '';
if (isset($constants['user'])) {
foreach ($constants['user'] as $name => $value) {
$result .= sprintf(
'if (!defined(\'%s\')) define(\'%s\', %s);' . "\n",
$name,
$name,
self::exportVariable($value)
);
}
}
return $result;
}
public static function getGlobalsAsString()
{
$result = '';
$superGlobalArrays = self::getSuperGlobalArrays();
foreach ($superGlobalArrays as $superGlobalArray) {
if (isset($GLOBALS[$superGlobalArray]) &&
is_array($GLOBALS[$superGlobalArray])) {
foreach (array_keys($GLOBALS[$superGlobalArray]) as $key) {
if ($GLOBALS[$superGlobalArray][$key] instanceof Closure) {
continue;
}
$result .= sprintf(
'$GLOBALS[\'%s\'][\'%s\'] = %s;' . "\n",
$superGlobalArray,
$key,
self::exportVariable($GLOBALS[$superGlobalArray][$key])
);
}
}
}
$blacklist = $superGlobalArrays;
$blacklist[] = 'GLOBALS';
$blacklist[] = '_PEAR_Config_instance';
foreach (array_keys($GLOBALS) as $key) {
if (!in_array($key, $blacklist) && !$GLOBALS[$key] instanceof Closure) {
$result .= sprintf(
'$GLOBALS[\'%s\'] = %s;' . "\n",
$key,
self::exportVariable($GLOBALS[$key])
);
}
}
return $result;
}
protected static function getSuperGlobalArrays()
{
if (ini_get('register_long_arrays') == '1') {
return array_merge(
self::$superGlobalArrays, self::$superGlobalArraysLong
);
} else {
return self::$superGlobalArrays;
}
}
public static function backupStaticAttributes(array $blacklist)
{
self::$staticAttributes = array();
$declaredClasses = get_declared_classes();
$declaredClassesNum = count($declaredClasses);
for ($i = $declaredClassesNum - 1; $i >= 0; $i--) {
if (strpos($declaredClasses[$i], 'PHPUnit') !== 0 &&
strpos($declaredClasses[$i], 'File_Iterator') !== 0 &&
strpos($declaredClasses[$i], 'PHP_CodeCoverage') !== 0 &&
strpos($declaredClasses[$i], 'PHP_Invoker') !== 0 &&
strpos($declaredClasses[$i], 'PHP_Timer') !== 0 &&
strpos($declaredClasses[$i], 'PHP_TokenStream') !== 0 &&
strpos($declaredClasses[$i], 'Symfony') !== 0 &&
strpos($declaredClasses[$i], 'Text_Template') !== 0 &&
!$declaredClasses[$i] instanceof PHPUnit_Framework_Test) {
$class = new ReflectionClass($declaredClasses[$i]);
if (!$class->isUserDefined()) {
break;
}
$backup = array();
foreach ($class->getProperties() as $attribute) {
if ($attribute->isStatic()) {
$name = $attribute->getName();
if (!isset($blacklist[$declaredClasses[$i]]) ||
!in_array($name, $blacklist[$declaredClasses[$i]])) {
$attribute->setAccessible(TRUE);
$value = $attribute->getValue();
if (!$value instanceof Closure) {
$backup[$name] = serialize($value);
}
}
}
}
if (!empty($backup)) {
self::$staticAttributes[$declaredClasses[$i]] = $backup;
}
}
}
}
public static function restoreStaticAttributes()
{
foreach (self::$staticAttributes as $className => $staticAttributes) {
foreach ($staticAttributes as $name => $value) {
$reflector = new ReflectionProperty($className, $name);
$reflector->setAccessible(TRUE);
$reflector->setValue(unserialize($value));
}
}
self::$staticAttributes = array();
}
protected static function exportVariable($variable)
{
if (is_scalar($variable) || is_null($variable) ||
(is_array($variable) && self::arrayOnlyContainsScalars($variable))) {
return var_export($variable, TRUE);
}
return 'unserialize(\'' .
str_replace("'", "\'", serialize($variable)) .
'\')';
}
protected static function arrayOnlyContainsScalars(array $array)
{
$result = TRUE;
foreach ($array as $element) {
if (is_array($element)) {
$result = self::arrayOnlyContainsScalars($element);
}
else if (!is_scalar($element) && !is_null($element)) {
$result = FALSE;
}
if ($result === FALSE) {
break;
}
}
return $result;
}
/**
* @return array
* @since Method available since Release 3.6.0
*/
public static function phpunitFiles()
{
if (self::$phpunitFiles === NULL) {
self::addDirectoryContainingClassToPHPUnitFilesList('File_Iterator');
self::addDirectoryContainingClassToPHPUnitFilesList('PHP_CodeCoverage');
self::addDirectoryContainingClassToPHPUnitFilesList('PHP_Invoker');
self::addDirectoryContainingClassToPHPUnitFilesList('PHP_Timer');
self::addDirectoryContainingClassToPHPUnitFilesList('PHP_Token');
self::addDirectoryContainingClassToPHPUnitFilesList('PHPUnit_Framework_TestCase', 2);
self::addDirectoryContainingClassToPHPUnitFilesList('PHPUnit_Extensions_Database_TestCase', 2);
self::addDirectoryContainingClassToPHPUnitFilesList('PHPUnit_Framework_MockObject_Generator', 2);
self::addDirectoryContainingClassToPHPUnitFilesList('PHPUnit_Extensions_SeleniumTestCase', 2);
self::addDirectoryContainingClassToPHPUnitFilesList('PHPUnit_Extensions_Story_TestCase', 2);
self::addDirectoryContainingClassToPHPUnitFilesList('Text_Template');
}
return self::$phpunitFiles;
}
/**
* @param string $className
* @param integer $parent
* @since Method available since Release 3.7.2
*/
protected static function addDirectoryContainingClassToPHPUnitFilesList($className, $parent = 1)
{
if (!class_exists($className)) {
return;
}
$reflector = new ReflectionClass($className);
$directory = $reflector->getFileName();
for ($i = 0; $i < $parent; $i++) {
$directory = dirname($directory);
}
$facade = new File_Iterator_Facade;
foreach ($facade->getFilesAsArray($directory, '.php') as $file) {
self::$phpunitFiles[$file] = TRUE;
}
}
}

View File

@@ -0,0 +1,80 @@
<?php
/**
* PHPUnit
*
* Copyright (c) 2001-2013, Sebastian Bergmann <sebastian@phpunit.de>.
* 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 Sebastian Bergmann nor the names of his
* 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.
*
* @package PHPUnit
* @subpackage Util
* @author Sebastian Bergmann <sebastian@phpunit.de>
* @copyright 2001-2013 Sebastian Bergmann <sebastian@phpunit.de>
* @license http://www.opensource.org/licenses/BSD-3-Clause The BSD 3-Clause License
* @link http://www.phpunit.de/
* @since File available since Release 3.4.0
*/
/**
* Factory for PHPUnit_Framework_Exception objects that are used to describe
* invalid arguments passed to a function or method.
*
* @package PHPUnit
* @subpackage Util
* @author Sebastian Bergmann <sebastian@phpunit.de>
* @copyright 2001-2013 Sebastian Bergmann <sebastian@phpunit.de>
* @license http://www.opensource.org/licenses/BSD-3-Clause The BSD 3-Clause License
* @link http://www.phpunit.de/
* @since Class available since Release 3.4.0
*/
class PHPUnit_Util_InvalidArgumentHelper
{
/**
* @param integer $argument
* @param string $type
* @param mixed $value
*/
public static function factory($argument, $type, $value = NULL)
{
$stack = debug_backtrace(FALSE);
return new PHPUnit_Framework_Exception(
sprintf(
'Argument #%d%sof %s::%s() must be a %s',
$argument,
$value !== NULL ? ' (' . $value . ')' : ' ',
$stack[1]['class'],
$stack[1]['function'],
$type
)
);
}
}

View File

@@ -0,0 +1,254 @@
<?php
/**
* PHPUnit
*
* Copyright (c) 2001-2013, Sebastian Bergmann <sebastian@phpunit.de>.
* 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 Sebastian Bergmann nor the names of his
* 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.
*
* @package PHPUnit
* @subpackage Util_Log
* @author Sebastian Bergmann <sebastian@phpunit.de>
* @copyright 2001-2013 Sebastian Bergmann <sebastian@phpunit.de>
* @license http://www.opensource.org/licenses/BSD-3-Clause The BSD 3-Clause License
* @link http://www.phpunit.de/
* @since File available since Release 3.0.0
*/
/**
* A TestListener that generates JSON messages.
*
* @package PHPUnit
* @subpackage Util_Log
* @author Sebastian Bergmann <sebastian@phpunit.de>
* @copyright 2001-2013 Sebastian Bergmann <sebastian@phpunit.de>
* @license http://www.opensource.org/licenses/BSD-3-Clause The BSD 3-Clause License
* @link http://www.phpunit.de/
* @since Class available since Release 3.0.0
*/
class PHPUnit_Util_Log_JSON extends PHPUnit_Util_Printer implements PHPUnit_Framework_TestListener
{
/**
* @var string
*/
protected $currentTestSuiteName = '';
/**
* @var string
*/
protected $currentTestName = '';
/**
* @var boolean
* @access private
*/
protected $currentTestPass = TRUE;
/**
* An error occurred.
*
* @param PHPUnit_Framework_Test $test
* @param Exception $e
* @param float $time
*/
public function addError(PHPUnit_Framework_Test $test, Exception $e, $time)
{
$this->writeCase(
'error',
$time,
PHPUnit_Util_Filter::getFilteredStacktrace($e, FALSE),
$e->getMessage(),
$test
);
$this->currentTestPass = FALSE;
}
/**
* A failure occurred.
*
* @param PHPUnit_Framework_Test $test
* @param PHPUnit_Framework_AssertionFailedError $e
* @param float $time
*/
public function addFailure(PHPUnit_Framework_Test $test, PHPUnit_Framework_AssertionFailedError $e, $time)
{
$this->writeCase(
'fail',
$time,
PHPUnit_Util_Filter::getFilteredStacktrace($e, FALSE),
$e->getMessage(),
$test
);
$this->currentTestPass = FALSE;
}
/**
* Incomplete test.
*
* @param PHPUnit_Framework_Test $test
* @param Exception $e
* @param float $time
*/
public function addIncompleteTest(PHPUnit_Framework_Test $test, Exception $e, $time)
{
$this->writeCase(
'error',
$time,
PHPUnit_Util_Filter::getFilteredStacktrace($e, FALSE),
'Incomplete Test: ' . $e->getMessage(),
$test
);
$this->currentTestPass = FALSE;
}
/**
* Skipped test.
*
* @param PHPUnit_Framework_Test $test
* @param Exception $e
* @param float $time
*/
public function addSkippedTest(PHPUnit_Framework_Test $test, Exception $e, $time)
{
$this->writeCase(
'error',
$time,
PHPUnit_Util_Filter::getFilteredStacktrace($e, FALSE),
'Skipped Test: ' . $e->getMessage(),
$test
);
$this->currentTestPass = FALSE;
}
/**
* A testsuite started.
*
* @param PHPUnit_Framework_TestSuite $suite
*/
public function startTestSuite(PHPUnit_Framework_TestSuite $suite)
{
$this->currentTestSuiteName = $suite->getName();
$this->currentTestName = '';
$this->write(
array(
'event' => 'suiteStart',
'suite' => $this->currentTestSuiteName,
'tests' => count($suite)
)
);
}
/**
* A testsuite ended.
*
* @param PHPUnit_Framework_TestSuite $suite
*/
public function endTestSuite(PHPUnit_Framework_TestSuite $suite)
{
$this->currentTestSuiteName = '';
$this->currentTestName = '';
}
/**
* A test started.
*
* @param PHPUnit_Framework_Test $test
*/
public function startTest(PHPUnit_Framework_Test $test)
{
$this->currentTestName = PHPUnit_Util_Test::describe($test);
$this->currentTestPass = TRUE;
$this->write(
array(
'event' => 'testStart',
'suite' => $this->currentTestSuiteName,
'test' => $this->currentTestName
)
);
}
/**
* A test ended.
*
* @param PHPUnit_Framework_Test $test
* @param float $time
*/
public function endTest(PHPUnit_Framework_Test $test, $time)
{
if ($this->currentTestPass) {
$this->writeCase('pass', $time, array(), '', $test);
}
}
/**
* @param string $status
* @param float $time
* @param array $trace
* @param string $message
*/
protected function writeCase($status, $time, array $trace = array(), $message = '', $test = NULL)
{
$output = '';
if ($test !== NULL && $test->hasOutput()) {
$output = $test->getActualOutput();
}
$this->write(
array(
'event' => 'test',
'suite' => $this->currentTestSuiteName,
'test' => $this->currentTestName,
'status' => $status,
'time' => $time,
'trace' => $trace,
'message' => PHPUnit_Util_String::convertToUtf8($message),
'output' => $output,
)
);
}
/**
* @param string $buffer
*/
public function write($buffer)
{
if (defined('JSON_PRETTY_PRINT')) {
parent::write(json_encode($buffer, JSON_PRETTY_PRINT));
} else {
parent::write(json_encode($buffer));
}
}
}

View File

@@ -0,0 +1,482 @@
<?php
/**
* PHPUnit
*
* Copyright (c) 2001-2013, Sebastian Bergmann <sebastian@phpunit.de>.
* 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 Sebastian Bergmann nor the names of his
* 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.
*
* @package PHPUnit
* @subpackage Util_Log
* @author Sebastian Bergmann <sebastian@phpunit.de>
* @copyright 2001-2013 Sebastian Bergmann <sebastian@phpunit.de>
* @license http://www.opensource.org/licenses/BSD-3-Clause The BSD 3-Clause License
* @link http://www.phpunit.de/
* @since File available since Release 2.3.0
*/
/**
* A TestListener that generates a logfile of the test execution in XML markup.
*
* The XML markup used is the same as the one that is used by the JUnit Ant task.
*
* @package PHPUnit
* @subpackage Util_Log
* @author Sebastian Bergmann <sebastian@phpunit.de>
* @copyright 2001-2013 Sebastian Bergmann <sebastian@phpunit.de>
* @license http://www.opensource.org/licenses/BSD-3-Clause The BSD 3-Clause License
* @link http://www.phpunit.de/
* @since Class available since Release 2.1.0
*/
class PHPUnit_Util_Log_JUnit extends PHPUnit_Util_Printer implements PHPUnit_Framework_TestListener
{
/**
* @var DOMDocument
*/
protected $document;
/**
* @var DOMElement
*/
protected $root;
/**
* @var boolean
*/
protected $logIncompleteSkipped = FALSE;
/**
* @var boolean
*/
protected $writeDocument = TRUE;
/**
* @var DOMElement[]
*/
protected $testSuites = array();
/**
* @var integer[]
*/
protected $testSuiteTests = array(0);
/**
* @var integer[]
*/
protected $testSuiteAssertions = array(0);
/**
* @var integer[]
*/
protected $testSuiteErrors = array(0);
/**
* @var integer[]
*/
protected $testSuiteFailures = array(0);
/**
* @var integer[]
*/
protected $testSuiteTimes = array(0);
/**
* @var integer
*/
protected $testSuiteLevel = 0;
/**
* @var DOMElement
*/
protected $currentTestCase = NULL;
/**
* @var boolean
*/
protected $attachCurrentTestCase = TRUE;
/**
* Constructor.
*
* @param mixed $out
* @param boolean $logIncompleteSkipped
*/
public function __construct($out = NULL, $logIncompleteSkipped = FALSE)
{
$this->document = new DOMDocument('1.0', 'UTF-8');
$this->document->formatOutput = TRUE;
$this->root = $this->document->createElement('testsuites');
$this->document->appendChild($this->root);
parent::__construct($out);
$this->logIncompleteSkipped = $logIncompleteSkipped;
}
/**
* Flush buffer and close output.
*
*/
public function flush()
{
if ($this->writeDocument === TRUE) {
$this->write($this->getXML());
}
parent::flush();
}
/**
* An error occurred.
*
* @param PHPUnit_Framework_Test $test
* @param Exception $e
* @param float $time
*/
public function addError(PHPUnit_Framework_Test $test, Exception $e, $time)
{
if ($this->currentTestCase !== NULL) {
if ($test instanceof PHPUnit_Framework_SelfDescribing) {
$buffer = $test->toString() . "\n";
} else {
$buffer = '';
}
$buffer .= PHPUnit_Framework_TestFailure::exceptionToString($e) .
"\n" .
PHPUnit_Util_Filter::getFilteredStacktrace($e);
$error = $this->document->createElement(
'error', PHPUnit_Util_XML::prepareString($buffer)
);
$error->setAttribute('type', get_class($e));
$this->currentTestCase->appendChild($error);
$this->testSuiteErrors[$this->testSuiteLevel]++;
}
}
/**
* A failure occurred.
*
* @param PHPUnit_Framework_Test $test
* @param PHPUnit_Framework_AssertionFailedError $e
* @param float $time
*/
public function addFailure(PHPUnit_Framework_Test $test, PHPUnit_Framework_AssertionFailedError $e, $time)
{
if ($this->currentTestCase !== NULL) {
if (!$test instanceof PHPUnit_Framework_Warning) {
if ($test instanceof PHPUnit_Framework_SelfDescribing) {
$buffer = $test->toString() . "\n";
} else {
$buffer = '';
}
$buffer .= PHPUnit_Framework_TestFailure::exceptionToString($e) .
"\n" .
PHPUnit_Util_Filter::getFilteredStacktrace($e);
$failure = $this->document->createElement(
'failure', PHPUnit_Util_XML::prepareString($buffer)
);
$failure->setAttribute('type', get_class($e));
$this->currentTestCase->appendChild($failure);
$this->testSuiteFailures[$this->testSuiteLevel]++;
}
}
}
/**
* Incomplete test.
*
* @param PHPUnit_Framework_Test $test
* @param Exception $e
* @param float $time
*/
public function addIncompleteTest(PHPUnit_Framework_Test $test, Exception $e, $time)
{
if ($this->logIncompleteSkipped && $this->currentTestCase !== NULL) {
$error = $this->document->createElement(
'error',
PHPUnit_Util_XML::prepareString(
"Incomplete Test\n" .
PHPUnit_Util_Filter::getFilteredStacktrace($e)
)
);
$error->setAttribute('type', get_class($e));
$this->currentTestCase->appendChild($error);
$this->testSuiteErrors[$this->testSuiteLevel]++;
} else {
$this->attachCurrentTestCase = FALSE;
}
}
/**
* Skipped test.
*
* @param PHPUnit_Framework_Test $test
* @param Exception $e
* @param float $time
* @since Method available since Release 3.0.0
*/
public function addSkippedTest(PHPUnit_Framework_Test $test, Exception $e, $time)
{
if ($this->logIncompleteSkipped && $this->currentTestCase !== NULL) {
$error = $this->document->createElement(
'error',
PHPUnit_Util_XML::prepareString(
"Skipped Test\n" .
PHPUnit_Util_Filter::getFilteredStacktrace($e)
)
);
$error->setAttribute('type', get_class($e));
$this->currentTestCase->appendChild($error);
$this->testSuiteErrors[$this->testSuiteLevel]++;
} else {
$this->attachCurrentTestCase = FALSE;
}
}
/**
* A testsuite started.
*
* @param PHPUnit_Framework_TestSuite $suite
* @since Method available since Release 2.2.0
*/
public function startTestSuite(PHPUnit_Framework_TestSuite $suite)
{
$testSuite = $this->document->createElement('testsuite');
$testSuite->setAttribute('name', $suite->getName());
if (class_exists($suite->getName(), FALSE)) {
try {
$class = new ReflectionClass($suite->getName());
$testSuite->setAttribute('file', $class->getFileName());
$packageInformation = PHPUnit_Util_Class::getPackageInformation(
$suite->getName(), $class->getDocComment()
);
if (!empty($packageInformation['namespace'])) {
$testSuite->setAttribute(
'namespace', $packageInformation['namespace']
);
}
if (!empty($packageInformation['fullPackage'])) {
$testSuite->setAttribute(
'fullPackage', $packageInformation['fullPackage']
);
}
if (!empty($packageInformation['category'])) {
$testSuite->setAttribute(
'category', $packageInformation['category']
);
}
if (!empty($packageInformation['package'])) {
$testSuite->setAttribute(
'package', $packageInformation['package']
);
}
if (!empty($packageInformation['subpackage'])) {
$testSuite->setAttribute(
'subpackage', $packageInformation['subpackage']
);
}
}
catch (ReflectionException $e) {
}
}
if ($this->testSuiteLevel > 0) {
$this->testSuites[$this->testSuiteLevel]->appendChild($testSuite);
} else {
$this->root->appendChild($testSuite);
}
$this->testSuiteLevel++;
$this->testSuites[$this->testSuiteLevel] = $testSuite;
$this->testSuiteTests[$this->testSuiteLevel] = 0;
$this->testSuiteAssertions[$this->testSuiteLevel] = 0;
$this->testSuiteErrors[$this->testSuiteLevel] = 0;
$this->testSuiteFailures[$this->testSuiteLevel] = 0;
$this->testSuiteTimes[$this->testSuiteLevel] = 0;
}
/**
* A testsuite ended.
*
* @param PHPUnit_Framework_TestSuite $suite
* @since Method available since Release 2.2.0
*/
public function endTestSuite(PHPUnit_Framework_TestSuite $suite)
{
$this->testSuites[$this->testSuiteLevel]->setAttribute(
'tests', $this->testSuiteTests[$this->testSuiteLevel]
);
$this->testSuites[$this->testSuiteLevel]->setAttribute(
'assertions', $this->testSuiteAssertions[$this->testSuiteLevel]
);
$this->testSuites[$this->testSuiteLevel]->setAttribute(
'failures', $this->testSuiteFailures[$this->testSuiteLevel]
);
$this->testSuites[$this->testSuiteLevel]->setAttribute(
'errors', $this->testSuiteErrors[$this->testSuiteLevel]
);
$this->testSuites[$this->testSuiteLevel]->setAttribute(
'time', sprintf('%F', $this->testSuiteTimes[$this->testSuiteLevel])
);
if ($this->testSuiteLevel > 1) {
$this->testSuiteTests[$this->testSuiteLevel - 1] += $this->testSuiteTests[$this->testSuiteLevel];
$this->testSuiteAssertions[$this->testSuiteLevel - 1] += $this->testSuiteAssertions[$this->testSuiteLevel];
$this->testSuiteErrors[$this->testSuiteLevel - 1] += $this->testSuiteErrors[$this->testSuiteLevel];
$this->testSuiteFailures[$this->testSuiteLevel - 1] += $this->testSuiteFailures[$this->testSuiteLevel];
$this->testSuiteTimes[$this->testSuiteLevel - 1] += $this->testSuiteTimes[$this->testSuiteLevel];
}
$this->testSuiteLevel--;
}
/**
* A test started.
*
* @param PHPUnit_Framework_Test $test
*/
public function startTest(PHPUnit_Framework_Test $test)
{
if (!$test instanceof PHPUnit_Framework_Warning) {
$testCase = $this->document->createElement('testcase');
$testCase->setAttribute('name', $test->getName());
if ($test instanceof PHPUnit_Framework_TestCase) {
$class = new ReflectionClass($test);
$methodName = $test->getName();
if ($class->hasMethod($methodName)) {
$method = $class->getMethod($test->getName());
$testCase->setAttribute('class', $class->getName());
$testCase->setAttribute('file', $class->getFileName());
$testCase->setAttribute('line', $method->getStartLine());
}
}
$this->currentTestCase = $testCase;
}
}
/**
* A test ended.
*
* @param PHPUnit_Framework_Test $test
* @param float $time
*/
public function endTest(PHPUnit_Framework_Test $test, $time)
{
if (!$test instanceof PHPUnit_Framework_Warning) {
if ($this->attachCurrentTestCase) {
if ($test instanceof PHPUnit_Framework_TestCase) {
$numAssertions = $test->getNumAssertions();
$this->testSuiteAssertions[$this->testSuiteLevel] += $numAssertions;
$this->currentTestCase->setAttribute(
'assertions', $numAssertions
);
}
$this->currentTestCase->setAttribute(
'time', sprintf('%F', $time)
);
$this->testSuites[$this->testSuiteLevel]->appendChild(
$this->currentTestCase
);
$this->testSuiteTests[$this->testSuiteLevel]++;
$this->testSuiteTimes[$this->testSuiteLevel] += $time;
}
}
$this->attachCurrentTestCase = TRUE;
$this->currentTestCase = NULL;
}
/**
* Returns the XML as a string.
*
* @return string
* @since Method available since Release 2.2.0
*/
public function getXML()
{
return $this->document->saveXML();
}
/**
* Enables or disables the writing of the document
* in flush().
*
* This is a "hack" needed for the integration of
* PHPUnit with Phing.
*
* @return string
* @since Method available since Release 2.2.0
*/
public function setWriteDocument($flag)
{
if (is_bool($flag)) {
$this->writeDocument = $flag;
}
}
}

View File

@@ -0,0 +1,250 @@
<?php
/**
* PHPUnit
*
* Copyright (c) 2001-2013, Sebastian Bergmann <sebastian@phpunit.de>.
* 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 Sebastian Bergmann nor the names of his
* 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.
*
* @package PHPUnit
* @subpackage Util_Log
* @author Sebastian Bergmann <sebastian@phpunit.de>
* @copyright 2001-2013 Sebastian Bergmann <sebastian@phpunit.de>
* @license http://www.opensource.org/licenses/BSD-3-Clause The BSD 3-Clause License
* @link http://www.phpunit.de/
* @since File available since Release 3.0.0
*/
/**
* A TestListener that generates a logfile of the
* test execution using the Test Anything Protocol (TAP).
*
* @package PHPUnit
* @subpackage Util_Log
* @author Sebastian Bergmann <sebastian@phpunit.de>
* @copyright 2001-2013 Sebastian Bergmann <sebastian@phpunit.de>
* @license http://www.opensource.org/licenses/BSD-3-Clause The BSD 3-Clause License
* @link http://www.phpunit.de/
* @since Class available since Release 3.0.0
*/
class PHPUnit_Util_Log_TAP extends PHPUnit_Util_Printer implements PHPUnit_Framework_TestListener
{
/**
* @var integer
*/
protected $testNumber = 0;
/**
* @var integer
*/
protected $testSuiteLevel = 0;
/**
* @var boolean
*/
protected $testSuccessful = TRUE;
/**
* Constructor.
*
* @param mixed $out
* @throws PHPUnit_Framework_Exception
* @since Method available since Release 3.3.4
*/
public function __construct($out = NULL)
{
parent::__construct($out);
$this->write("TAP version 13\n");
}
/**
* An error occurred.
*
* @param PHPUnit_Framework_Test $test
* @param Exception $e
* @param float $time
*/
public function addError(PHPUnit_Framework_Test $test, Exception $e, $time)
{
$this->writeNotOk($test, 'Error');
}
/**
* A failure occurred.
*
* @param PHPUnit_Framework_Test $test
* @param PHPUnit_Framework_AssertionFailedError $e
* @param float $time
*/
public function addFailure(PHPUnit_Framework_Test $test, PHPUnit_Framework_AssertionFailedError $e, $time)
{
$this->writeNotOk($test, 'Failure');
$message = explode(
"\n", PHPUnit_Framework_TestFailure::exceptionToString($e)
);
$diagnostic = array(
'message' => $message[0],
'severity' => 'fail'
);
if ($e instanceof PHPUnit_Framework_ExpectationFailedException) {
$cf = $e->getComparisonFailure();
if ($cf !== NULL) {
$diagnostic['data'] = array(
'got' => $cf->getActual(),
'expected' => $cf->getExpected()
);
}
}
$yaml = new Symfony\Component\Yaml\Dumper;
$this->write(
sprintf(
" ---\n%s ...\n",
$yaml->dump($diagnostic, 2, 2)
)
);
}
/**
* Incomplete test.
*
* @param PHPUnit_Framework_Test $test
* @param Exception $e
* @param float $time
*/
public function addIncompleteTest(PHPUnit_Framework_Test $test, Exception $e, $time)
{
$this->writeNotOk($test, '', 'TODO Incomplete Test');
}
/**
* Skipped test.
*
* @param PHPUnit_Framework_Test $test
* @param Exception $e
* @param float $time
* @since Method available since Release 3.0.0
*/
public function addSkippedTest(PHPUnit_Framework_Test $test, Exception $e, $time)
{
$this->write(
sprintf(
"ok %d - # SKIP%s\n",
$this->testNumber,
$e->getMessage() != '' ? ' ' . $e->getMessage() : ''
)
);
$this->testSuccessful = FALSE;
}
/**
* A testsuite started.
*
* @param PHPUnit_Framework_TestSuite $suite
*/
public function startTestSuite(PHPUnit_Framework_TestSuite $suite)
{
$this->testSuiteLevel++;
}
/**
* A testsuite ended.
*
* @param PHPUnit_Framework_TestSuite $suite
*/
public function endTestSuite(PHPUnit_Framework_TestSuite $suite)
{
$this->testSuiteLevel--;
if ($this->testSuiteLevel == 0) {
$this->write(sprintf("1..%d\n", $this->testNumber));
}
}
/**
* A test started.
*
* @param PHPUnit_Framework_Test $test
*/
public function startTest(PHPUnit_Framework_Test $test)
{
$this->testNumber++;
$this->testSuccessful = TRUE;
}
/**
* A test ended.
*
* @param PHPUnit_Framework_Test $test
* @param float $time
*/
public function endTest(PHPUnit_Framework_Test $test, $time)
{
if ($this->testSuccessful === TRUE) {
$this->write(
sprintf(
"ok %d - %s\n",
$this->testNumber,
PHPUnit_Util_Test::describe($test)
)
);
}
}
/**
* @param PHPUnit_Framework_Test $test
* @param string $prefix
* @param string $directive
*/
protected function writeNotOk(PHPUnit_Framework_Test $test, $prefix = '', $directive = '')
{
$this->write(
sprintf(
"not ok %d - %s%s%s\n",
$this->testNumber,
$prefix != '' ? $prefix . ': ' : '',
PHPUnit_Util_Test::describe($test),
$directive != '' ? ' # ' . $directive : ''
)
);
$this->testSuccessful = FALSE;
}
}

View File

@@ -0,0 +1,332 @@
<?php
/**
* PHPUnit
*
* Copyright (c) 2001-2013, Sebastian Bergmann <sebastian@phpunit.de>.
* 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 Sebastian Bergmann nor the names of his
* 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.
*
* @package PHPUnit
* @subpackage Util
* @author Sebastian Bergmann <sebastian@phpunit.de>
* @copyright 2001-2013 Sebastian Bergmann <sebastian@phpunit.de>
* @license http://www.opensource.org/licenses/BSD-3-Clause The BSD 3-Clause License
* @link http://www.phpunit.de/
* @since File available since Release 3.4.0
*/
/**
* Utility methods for PHP sub-processes.
*
* @package PHPUnit
* @subpackage Util
* @author Sebastian Bergmann <sebastian@phpunit.de>
* @copyright 2001-2013 Sebastian Bergmann <sebastian@phpunit.de>
* @license http://www.opensource.org/licenses/BSD-3-Clause The BSD 3-Clause License
* @link http://www.phpunit.de/
* @since Class available since Release 3.4.0
*/
abstract class PHPUnit_Util_PHP
{
/**
* @var string $phpBinary
*/
protected $phpBinary;
/**
* Returns the path to a PHP interpreter.
*
* PHPUnit_Util_PHP::$phpBinary contains the path to the PHP
* interpreter.
*
* When not set, the following assumptions will be made:
*
* 1. When PHPUnit is run using the CLI SAPI and the $_SERVER['_']
* variable does not contain the string "PHPUnit", $_SERVER['_']
* is assumed to contain the path to the current PHP interpreter
* and that will be used.
*
* 2. When PHPUnit is run using the CLI SAPI and the $_SERVER['_']
* variable contains the string "PHPUnit", the file that $_SERVER['_']
* points to is assumed to be the PHPUnit TextUI CLI wrapper script
* "phpunit" and the binary set up using #! on that file's first
* line of code is assumed to contain the path to the current PHP
* interpreter and that will be used.
*
* 3. When the PHP CLI/CGI binary configured with the PEAR Installer
* (php_bin configuration value) is readable, it will be used.
*
* 4. The current PHP interpreter is assumed to be in the $PATH and
* to be invokable through "php".
*
* @return string
*/
protected function getPhpBinary()
{
if ($this->phpBinary === NULL) {
if (defined("PHP_BINARY")) {
$this->phpBinary = PHP_BINARY;
} else if (PHP_SAPI == 'cli' && isset($_SERVER['_'])) {
if (strpos($_SERVER['_'], 'phpunit') !== FALSE) {
$file = file($_SERVER['_']);
if (strpos($file[0], ' ') !== FALSE) {
$tmp = explode(' ', $file[0]);
$this->phpBinary = trim($tmp[1]);
} else {
$this->phpBinary = ltrim(trim($file[0]), '#!');
}
} else if (strpos(basename($_SERVER['_']), 'php') !== FALSE) {
$this->phpBinary = $_SERVER['_'];
}
}
if ($this->phpBinary === NULL) {
$possibleBinaryLocations = array(
PHP_BINDIR . '/php',
PHP_BINDIR . '/php-cli.exe',
PHP_BINDIR . '/php.exe',
'C:\long_subdirectory_for\xampp\php\.\php.exe',
);
foreach ($possibleBinaryLocations as $binary) {
if (is_readable($binary)) {
$this->phpBinary = $binary;
break;
}
}
}
if (!is_readable($this->phpBinary)) {
$this->phpBinary = 'php';
} else {
$this->phpBinary = escapeshellarg($this->phpBinary);
}
}
return $this->phpBinary;
}
/**
* @return PHPUnit_Util_PHP
* @since Method available since Release 3.5.12
*/
public static function factory()
{
if (DIRECTORY_SEPARATOR == '\\') {
return new PHPUnit_Util_PHP_Windows;
}
return new PHPUnit_Util_PHP_Default;
}
/**
* Runs a single job (PHP code) using a separate PHP process.
*
* @param string $job
* @param PHPUnit_Framework_TestCase $test
* @param PHPUnit_Framework_TestResult $result
* @return array|null
* @throws PHPUnit_Framework_Exception
*/
public function runJob($job, PHPUnit_Framework_Test $test = NULL, PHPUnit_Framework_TestResult $result = NULL)
{
$process = proc_open(
$this->getPhpBinary(),
array(
0 => array('pipe', 'r'),
1 => array('pipe', 'w'),
2 => array('pipe', 'w')
),
$pipes
);
if (!is_resource($process)) {
throw new PHPUnit_Framework_Exception(
'Unable to create process for process isolation.'
);
}
if ($result !== NULL) {
$result->startTest($test);
}
$this->process($pipes[0], $job);
fclose($pipes[0]);
$stdout = stream_get_contents($pipes[1]);
fclose($pipes[1]);
$stderr = stream_get_contents($pipes[2]);
fclose($pipes[2]);
proc_close($process);
$this->cleanup();
if ($result !== NULL) {
$this->processChildResult($test, $result, $stdout, $stderr);
} else {
return array('stdout' => $stdout, 'stderr' => $stderr);
}
}
/**
* @param resource $pipe
* @param string $job
* @since Method available since Release 3.5.12
*/
abstract protected function process($pipe, $job);
/**
* @since Method available since Release 3.5.12
*/
protected function cleanup()
{
}
/**
* Processes the TestResult object from an isolated process.
*
* @param PHPUnit_Framework_TestCase $test
* @param PHPUnit_Framework_TestResult $result
* @param string $stdout
* @param string $stderr
* @since Method available since Release 3.5.0
*/
protected function processChildResult(PHPUnit_Framework_Test $test, PHPUnit_Framework_TestResult $result, $stdout, $stderr)
{
$time = 0;
if (!empty($stderr)) {
$result->addError(
$test,
new PHPUnit_Framework_Exception(trim($stderr)), $time
);
} else {
set_error_handler(function($errno, $errstr, $errfile, $errline) {
throw new ErrorException($errstr, $errno, $errno, $errfile, $errline);
});
try {
$childResult = unserialize($stdout);
restore_error_handler();
} catch (ErrorException $e) {
restore_error_handler();
$childResult = FALSE;
$result->addError(
$test, new PHPUnit_Framework_Exception(trim($stdout), 0, $e), $time
);
}
if ($childResult !== FALSE) {
if (!empty($childResult['output'])) {
print $childResult['output'];
}
$test->setResult($childResult['testResult']);
$test->addToAssertionCount($childResult['numAssertions']);
$childResult = $childResult['result'];
if ($result->getCollectCodeCoverageInformation()) {
$result->getCodeCoverage()->merge(
$childResult->getCodeCoverage()
);
}
$time = $childResult->time();
$notImplemented = $childResult->notImplemented();
$skipped = $childResult->skipped();
$errors = $childResult->errors();
$failures = $childResult->failures();
if (!empty($notImplemented)) {
$result->addError(
$test, $this->getException($notImplemented[0]), $time
);
}
else if (!empty($skipped)) {
$result->addError(
$test, $this->getException($skipped[0]), $time
);
}
else if (!empty($errors)) {
$result->addError(
$test, $this->getException($errors[0]), $time
);
}
else if (!empty($failures)) {
$result->addFailure(
$test, $this->getException($failures[0]), $time
);
}
}
}
$result->endTest($test, $time);
}
/**
* Gets the thrown exception from a PHPUnit_Framework_TestFailure.
*
* @param PHPUnit_Framework_TestFailure $error
* @since Method available since Release 3.6.0
* @see https://github.com/sebastianbergmann/phpunit/issues/74
*/
protected function getException(PHPUnit_Framework_TestFailure $error)
{
$exception = $error->thrownException();
if ($exception instanceof __PHP_Incomplete_Class) {
$exceptionArray = array();
foreach ((array)$exception as $key => $value) {
$key = substr($key, strrpos($key, "\0") + 1);
$exceptionArray[$key] = $value;
}
$exception = new PHPUnit_Framework_SyntheticError(
sprintf(
'%s: %s',
$exceptionArray['_PHP_Incomplete_Class_Name'],
$exceptionArray['message']
),
$exceptionArray['code'],
$exceptionArray['file'],
$exceptionArray['line'],
$exceptionArray['trace']
);
}
return $exception;
}
}

View File

@@ -0,0 +1,67 @@
<?php
/**
* PHPUnit
*
* Copyright (c) 2001-2013, Sebastian Bergmann <sebastian@phpunit.de>.
* 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 Sebastian Bergmann nor the names of his
* 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.
*
* @package PHPUnit
* @subpackage Util
* @author Sebastian Bergmann <sebastian@phpunit.de>
* @copyright 2001-2013 Sebastian Bergmann <sebastian@phpunit.de>
* @license http://www.opensource.org/licenses/BSD-3-Clause The BSD 3-Clause License
* @link http://www.phpunit.de/
* @since File available since Release 3.5.12
*/
/**
* Default utility for PHP sub-processes.
*
* @package PHPUnit
* @subpackage Util
* @author Sebastian Bergmann <sebastian@phpunit.de>
* @copyright 2001-2013 Sebastian Bergmann <sebastian@phpunit.de>
* @license http://www.opensource.org/licenses/BSD-3-Clause The BSD 3-Clause License
* @link http://www.phpunit.de/
* @since Class available since Release 3.5.12
*/
class PHPUnit_Util_PHP_Default extends PHPUnit_Util_PHP
{
/**
* @param resource $pipe
* @since Method available since Release 3.5.12
*/
protected function process($pipe, $job)
{
fwrite($pipe, $job);
}
}

View File

@@ -0,0 +1,90 @@
<?php
/**
* PHPUnit
*
* Copyright (c) 2001-2013, Sebastian Bergmann <sebastian@phpunit.de>.
* 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 Sebastian Bergmann nor the names of his
* 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.
*
* @package PHPUnit
* @subpackage Util
* @author Sebastian Bergmann <sebastian@phpunit.de>
* @copyright 2001-2013 Sebastian Bergmann <sebastian@phpunit.de>
* @license http://www.opensource.org/licenses/BSD-3-Clause The BSD 3-Clause License
* @link http://www.phpunit.de/
* @since File available since Release 3.5.12
*/
/**
* Windows utility for PHP sub-processes.
*
* @package PHPUnit
* @subpackage Util
* @author Sebastian Bergmann <sebastian@phpunit.de>
* @copyright 2001-2013 Sebastian Bergmann <sebastian@phpunit.de>
* @license http://www.opensource.org/licenses/BSD-3-Clause The BSD 3-Clause License
* @link http://www.phpunit.de/
* @since Class available since Release 3.5.12
*/
class PHPUnit_Util_PHP_Windows extends PHPUnit_Util_PHP
{
/**
* @var string
*/
protected $tempFile;
/**
* @param resource $pipe
* @since Method available since Release 3.5.12
*/
protected function process($pipe, $job)
{
if (!($this->tempFile = tempnam(sys_get_temp_dir(), 'PHPUnit')) ||
file_put_contents($this->tempFile, $job) === FALSE) {
throw new PHPUnit_Framework_Exception(
'Unable to write temporary files for process isolation.'
);
}
fwrite(
$pipe,
"<?php require_once " . var_export($this->tempFile, TRUE) . "; ?>"
);
}
/**
* @since Method available since Release 3.5.12
*/
protected function cleanup()
{
unlink($this->tempFile);
}
}

View File

@@ -0,0 +1,208 @@
<?php
/**
* PHPUnit
*
* Copyright (c) 2001-2013, Sebastian Bergmann <sebastian@phpunit.de>.
* 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 Sebastian Bergmann nor the names of his
* 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.
*
* @package PHPUnit
* @subpackage Util
* @author Sebastian Bergmann <sebastian@phpunit.de>
* @copyright 2001-2013 Sebastian Bergmann <sebastian@phpunit.de>
* @license http://www.opensource.org/licenses/BSD-3-Clause The BSD 3-Clause License
* @link http://www.phpunit.de/
* @since File available since Release 2.0.0
*/
/**
* Utility class that can print to STDOUT or write to a file.
*
* @package PHPUnit
* @subpackage Util
* @author Sebastian Bergmann <sebastian@phpunit.de>
* @copyright 2001-2013 Sebastian Bergmann <sebastian@phpunit.de>
* @license http://www.opensource.org/licenses/BSD-3-Clause The BSD 3-Clause License
* @link http://www.phpunit.de/
* @since Class available since Release 2.0.0
*/
class PHPUnit_Util_Printer
{
/**
* If TRUE, flush output after every write.
*
* @var boolean
*/
protected $autoFlush = FALSE;
/**
* @var resource
*/
protected $out;
/**
* @var string
*/
protected $outTarget;
/**
* @var boolean
*/
protected $printsHTML = FALSE;
/**
* Constructor.
*
* @param mixed $out
* @throws PHPUnit_Framework_Exception
*/
public function __construct($out = NULL)
{
if ($out !== NULL) {
if (is_string($out)) {
if (strpos($out, 'socket://') === 0) {
$out = explode(':', str_replace('socket://', '', $out));
if (sizeof($out) != 2) {
throw new PHPUnit_Framework_Exception;
}
$this->out = fsockopen($out[0], $out[1]);
} else {
if (strpos($out, 'php://') === FALSE &&
!is_dir(dirname($out))) {
mkdir(dirname($out), 0777, TRUE);
}
$this->out = fopen($out, 'wt');
}
$this->outTarget = $out;
} else {
$this->out = $out;
}
}
}
/**
* Flush buffer, optionally tidy up HTML, and close output if it's not to a php stream
*/
public function flush()
{
if ($this->out && strncmp($this->outTarget, 'php://', 6) !== 0) {
fclose($this->out);
}
if ($this->printsHTML === TRUE &&
$this->outTarget !== NULL &&
strpos($this->outTarget, 'php://') !== 0 &&
strpos($this->outTarget, 'socket://') !== 0 &&
extension_loaded('tidy')) {
file_put_contents(
$this->outTarget,
tidy_repair_file(
$this->outTarget, array('indent' => TRUE, 'wrap' => 0), 'utf8'
)
);
}
}
/**
* Performs a safe, incremental flush.
*
* Do not confuse this function with the flush() function of this class,
* since the flush() function may close the file being written to, rendering
* the current object no longer usable.
*
* @since Method available since Release 3.3.0
*/
public function incrementalFlush()
{
if ($this->out) {
fflush($this->out);
} else {
flush();
}
}
/**
* @param string $buffer
*/
public function write($buffer)
{
if ($this->out) {
fwrite($this->out, $buffer);
if ($this->autoFlush) {
$this->incrementalFlush();
}
} else {
if (PHP_SAPI != 'cli') {
$buffer = htmlspecialchars($buffer);
}
print $buffer;
if ($this->autoFlush) {
$this->incrementalFlush();
}
}
}
/**
* Check auto-flush mode.
*
* @return boolean
* @since Method available since Release 3.3.0
*/
public function getAutoFlush()
{
return $this->autoFlush;
}
/**
* Set auto-flushing mode.
*
* If set, *incremental* flushes will be done after each write. This should
* not be confused with the different effects of this class' flush() method.
*
* @param boolean $autoFlush
* @since Method available since Release 3.3.0
*/
public function setAutoFlush($autoFlush)
{
if (is_bool($autoFlush)) {
$this->autoFlush = $autoFlush;
} else {
throw PHPUnit_Util_InvalidArgumentHelper::factory(1, 'boolean');
}
}
}

View File

@@ -0,0 +1,118 @@
<?php
/**
* PHPUnit
*
* Copyright (c) 2001-2013, Sebastian Bergmann <sebastian@phpunit.de>.
* 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 Sebastian Bergmann nor the names of his
* 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.
*
* @package PHPUnit
* @subpackage Util
* @author Sebastian Bergmann <sebastian@phpunit.de>
* @copyright 2001-2013 Sebastian Bergmann <sebastian@phpunit.de>
* @license http://www.opensource.org/licenses/BSD-3-Clause The BSD 3-Clause License
* @link http://www.phpunit.de/
* @since File available since Release 3.6.0
*/
/**
* String helpers.
*
* @package PHPUnit
* @subpackage Util
* @author Sebastian Bergmann <sebastian@phpunit.de>
* @copyright 2001-2013 Sebastian Bergmann <sebastian@phpunit.de>
* @license http://www.opensource.org/licenses/BSD-3-Clause The BSD 3-Clause License
* @link http://www.phpunit.de/
* @since Class available since Release 3.6.0
*/
class PHPUnit_Util_String
{
/**
* Converts a string to UTF-8 encoding.
*
* @param string $string
* @return string
*/
public static function convertToUtf8($string)
{
if (!self::isUtf8($string)) {
if (function_exists('mb_convert_encoding')) {
$string = mb_convert_encoding($string, 'UTF-8');
} else {
$string = utf8_encode($string);
}
}
return $string;
}
/**
* Checks a string for UTF-8 encoding.
*
* @param string $string
* @return boolean
*/
protected static function isUtf8($string)
{
$length = strlen($string);
for ($i = 0; $i < $length; $i++) {
if (ord($string[$i]) < 0x80) {
$n = 0;
}
else if ((ord($string[$i]) & 0xE0) == 0xC0) {
$n = 1;
}
else if ((ord($string[$i]) & 0xF0) == 0xE0) {
$n = 2;
}
else if ((ord($string[$i]) & 0xF0) == 0xF0) {
$n = 3;
}
else {
return FALSE;
}
for ($j = 0; $j < $n; $j++) {
if ((++$i == $length) || ((ord($string[$i]) & 0xC0) != 0x80)) {
return FALSE;
}
}
}
return TRUE;
}
}

View File

@@ -0,0 +1,602 @@
<?php
/**
* PHPUnit
*
* Copyright (c) 2001-2013, Sebastian Bergmann <sebastian@phpunit.de>.
* 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 Sebastian Bergmann nor the names of his
* 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.
*
* @package PHPUnit
* @subpackage Util
* @author Sebastian Bergmann <sebastian@phpunit.de>
* @copyright 2001-2013 Sebastian Bergmann <sebastian@phpunit.de>
* @license http://www.opensource.org/licenses/BSD-3-Clause The BSD 3-Clause License
* @link http://www.phpunit.de/
* @since File available since Release 3.0.0
*/
/**
* Test helpers.
*
* @package PHPUnit
* @subpackage Util
* @author Sebastian Bergmann <sebastian@phpunit.de>
* @copyright 2001-2013 Sebastian Bergmann <sebastian@phpunit.de>
* @license http://www.opensource.org/licenses/BSD-3-Clause The BSD 3-Clause License
* @link http://www.phpunit.de/
* @since Class available since Release 3.0.0
*/
class PHPUnit_Util_Test
{
const REGEX_DATA_PROVIDER = '/@dataProvider\s+([a-zA-Z0-9._:-\\\\x7f-\xff]+)/';
const REGEX_EXPECTED_EXCEPTION = '(@expectedException\s+([:.\w\\\\x7f-\xff]+)(?:[\t ]+(\S*))?(?:[\t ]+(\S*))?\s*$)m';
const REGEX_REQUIRES_VERSION = '/@requires\s+(?P<name>PHP(?:Unit)?)\s+(?P<value>[\d\.-]+(dev|(RC|alpha|beta)[\d\.])?)[ \t]*\r?$/m';
const REGEX_REQUIRES = '/@requires\s+(?P<name>function|extension)\s(?P<value>([^ ]+))\r?$/m';
const SMALL = 0;
const MEDIUM = 1;
const LARGE = 2;
private static $annotationCache = array();
protected static $templateMethods = array(
'setUp', 'assertPreConditions', 'assertPostConditions', 'tearDown'
);
/**
* @param PHPUnit_Framework_Test $test
* @param boolean $asString
* @return mixed
*/
public static function describe(PHPUnit_Framework_Test $test, $asString = TRUE)
{
if ($asString) {
if ($test instanceof PHPUnit_Framework_SelfDescribing) {
return $test->toString();
} else {
return get_class($test);
}
} else {
if ($test instanceof PHPUnit_Framework_TestCase) {
return array(
get_class($test), $test->getName()
);
}
else if ($test instanceof PHPUnit_Framework_SelfDescribing) {
return array('', $test->toString());
}
else {
return array('', get_class($test));
}
}
}
/**
* Returns the requirements for a test.
*
* @param string $className
* @param string $methodName
* @return array
* @since Method available since Release 3.6.0
*/
public static function getRequirements($className, $methodName)
{
$reflector = new ReflectionClass($className);
$docComment = $reflector->getDocComment();
$reflector = new ReflectionMethod($className, $methodName);
$docComment .= "\n" . $reflector->getDocComment();
$requires = array();
if ($count = preg_match_all(self::REGEX_REQUIRES_VERSION, $docComment, $matches)) {
for ($i = 0; $i < $count; $i++) {
$requires[$matches['name'][$i]] = $matches['value'][$i];
}
}
if ($count = preg_match_all(self::REGEX_REQUIRES, $docComment, $matches)) {
for ($i = 0; $i < $count; $i++) {
$name = $matches['name'][$i] . 's';
if (!isset($requires[$name])) {
$requires[$name] = array();
}
$requires[$name][] = $matches['value'][$i];
}
}
return $requires;
}
/**
* Returns the expected exception for a test.
*
* @param string $className
* @param string $methodName
* @return array
* @since Method available since Release 3.3.6
*/
public static function getExpectedException($className, $methodName)
{
$reflector = new ReflectionMethod($className, $methodName);
$docComment = $reflector->getDocComment();
$docComment = substr($docComment, 3, -2);
if (preg_match(self::REGEX_EXPECTED_EXCEPTION, $docComment, $matches)) {
$annotations = self::parseTestMethodAnnotations(
$className, $methodName
);
$class = $matches[1];
$code = NULL;
$message = '';
if (isset($matches[2])) {
$message = trim($matches[2]);
}
else if (isset($annotations['method']['expectedExceptionMessage'])) {
$message = self::_parseAnnotationContent(
$annotations['method']['expectedExceptionMessage'][0]
);
}
if (isset($matches[3])) {
$code = $matches[3];
}
else if (isset($annotations['method']['expectedExceptionCode'])) {
$code = self::_parseAnnotationContent(
$annotations['method']['expectedExceptionCode'][0]
);
}
if (is_numeric($code)) {
$code = (int)$code;
}
else if (is_string($code) && defined($code)) {
$code = (int)constant($code);
}
return array(
'class' => $class, 'code' => $code, 'message' => $message
);
}
return FALSE;
}
/**
* Parse annotation content to use constant/class constant values
*
* Constants are specified using a starting '@'. For example: @ClassName::CONST_NAME
*
* If the constant is not found the string is used as is to ensure maximum BC.
*
* @param string $message
* @return string
*/
protected static function _parseAnnotationContent($message)
{
if (strpos($message, '::') !== FALSE && count(explode('::', $message) == 2)) {
if (defined($message)) {
$message = constant($message);
}
}
return $message;
}
/**
* Returns the provided data for a method.
*
* @param string $className
* @param string $methodName
* @param string $docComment
* @return mixed array|Iterator when a data provider is specified and exists
* false when a data provider is specified and does not exist
* null when no data provider is specified
* @since Method available since Release 3.2.0
*/
public static function getProvidedData($className, $methodName)
{
$reflector = new ReflectionMethod($className, $methodName);
$docComment = $reflector->getDocComment();
$data = NULL;
if (preg_match(self::REGEX_DATA_PROVIDER, $docComment, $matches)) {
$dataProviderMethodNameNamespace = explode('\\', $matches[1]);
$leaf = explode('::', array_pop($dataProviderMethodNameNamespace));
$dataProviderMethodName = array_pop($leaf);
if (!empty($dataProviderMethodNameNamespace)) {
$dataProviderMethodNameNamespace = join('\\', $dataProviderMethodNameNamespace) . '\\';
} else {
$dataProviderMethodNameNamespace = '';
}
if (!empty($leaf)) {
$dataProviderClassName = $dataProviderMethodNameNamespace . array_pop($leaf);
} else {
$dataProviderClassName = $className;
}
$dataProviderClass = new ReflectionClass($dataProviderClassName);
$dataProviderMethod = $dataProviderClass->getMethod(
$dataProviderMethodName
);
if ($dataProviderMethod->isStatic()) {
$object = NULL;
} else {
$object = $dataProviderClass->newInstance();
}
if ($dataProviderMethod->getNumberOfParameters() == 0) {
$data = $dataProviderMethod->invoke($object);
} else {
$data = $dataProviderMethod->invoke($object, $methodName);
}
}
if ($data !== NULL) {
foreach ($data as $key => $value) {
if (!is_array($value)) {
throw new PHPUnit_Framework_Exception(
sprintf(
'Data set %s is invalid.',
is_int($key) ? '#' . $key : '"' . $key . '"'
)
);
}
}
}
return $data;
}
/**
* @param string $className
* @param string $methodName
* @return array
* @throws ReflectionException
* @since Method available since Release 3.4.0
*/
public static function parseTestMethodAnnotations($className, $methodName = '')
{
if (!isset(self::$annotationCache[$className])) {
$class = new ReflectionClass($className);
self::$annotationCache[$className] = self::parseAnnotations($class->getDocComment());
}
if (!empty($methodName) && !isset(self::$annotationCache[$className . '::' . $methodName])) {
try {
$method = new ReflectionMethod($className, $methodName);
$annotations = self::parseAnnotations($method->getDocComment());
} catch (ReflectionException $e) {
$annotations = array();
}
self::$annotationCache[$className . '::' . $methodName] = $annotations;
}
return array(
'class' => self::$annotationCache[$className],
'method' => !empty($methodName) ? self::$annotationCache[$className . '::' . $methodName] : array()
);
}
/**
* @param string $docblock
* @return array
* @since Method available since Release 3.4.0
*/
private static function parseAnnotations($docblock)
{
$annotations = array();
// Strip away the docblock header and footer to ease parsing of one line annotations
$docblock = substr($docblock, 3, -2);
if (preg_match_all('/@(?P<name>[A-Za-z_-]+)(?:[ \t]+(?P<value>.*?))?[ \t]*\r?$/m', $docblock, $matches)) {
$numMatches = count($matches[0]);
for ($i = 0; $i < $numMatches; ++$i) {
$annotations[$matches['name'][$i]][] = $matches['value'][$i];
}
}
return $annotations;
}
/**
* Returns the backup settings for a test.
*
* @param string $className
* @param string $methodName
* @return array
* @since Method available since Release 3.4.0
*/
public static function getBackupSettings($className, $methodName)
{
return array(
'backupGlobals' => self::getBooleanAnnotationSetting(
$className, $methodName, 'backupGlobals'
),
'backupStaticAttributes' => self::getBooleanAnnotationSetting(
$className, $methodName, 'backupStaticAttributes'
)
);
}
/**
* Returns the dependencies for a test class or method.
*
* @param string $className
* @param string $methodName
* @return array
* @since Method available since Release 3.4.0
*/
public static function getDependencies($className, $methodName)
{
$annotations = self::parseTestMethodAnnotations(
$className, $methodName
);
$dependencies = array();
if (isset($annotations['class']['depends'])) {
$dependencies = $annotations['class']['depends'];
}
if (isset($annotations['method']['depends'])) {
$dependencies = array_merge(
$dependencies, $annotations['method']['depends']
);
}
return array_unique($dependencies);
}
/**
* Returns the error handler settings for a test.
*
* @param string $className
* @param string $methodName
* @return boolean
* @since Method available since Release 3.4.0
*/
public static function getErrorHandlerSettings($className, $methodName)
{
return self::getBooleanAnnotationSetting(
$className, $methodName, 'errorHandler'
);
}
/**
* Returns the groups for a test class or method.
*
* @param string $className
* @param string $methodName
* @return array
* @since Method available since Release 3.2.0
*/
public static function getGroups($className, $methodName = '')
{
$annotations = self::parseTestMethodAnnotations(
$className, $methodName
);
$groups = array();
if (isset($annotations['method']['author'])) {
$groups = $annotations['method']['author'];
}
else if (isset($annotations['class']['author'])) {
$groups = $annotations['class']['author'];
}
if (isset($annotations['class']['group'])) {
$groups = array_merge($groups, $annotations['class']['group']);
}
if (isset($annotations['method']['group'])) {
$groups = array_merge($groups, $annotations['method']['group']);
}
if (isset($annotations['class']['ticket'])) {
$groups = array_merge($groups, $annotations['class']['ticket']);
}
if (isset($annotations['method']['ticket'])) {
$groups = array_merge($groups, $annotations['method']['ticket']);
}
foreach (array('small', 'medium', 'large') as $size) {
if (isset($annotations['method'][$size])) {
$groups[] = $size;
}
else if (isset($annotations['class'][$size])) {
$groups[] = $size;
}
}
return array_unique($groups);
}
/**
* Returns the size of the test.
*
* @param string $className
* @param string $methodName
* @return integer
* @since Method available since Release 3.6.0
*/
public static function getSize($className, $methodName)
{
$groups = array_flip(self::getGroups($className, $methodName));
$size = self::SMALL;
$class = new ReflectionClass($className);
if ((class_exists('PHPUnit_Extensions_Database_TestCase', FALSE) &&
$class->isSubclassOf('PHPUnit_Extensions_Database_TestCase')) ||
(class_exists('PHPUnit_Extensions_SeleniumTestCase', FALSE) &&
$class->isSubclassOf('PHPUnit_Extensions_SeleniumTestCase'))) {
$size = self::LARGE;
}
else if (isset($groups['medium'])) {
$size = self::MEDIUM;
}
else if (isset($groups['large'])) {
$size = self::LARGE;
}
return $size;
}
/**
* Returns the tickets for a test class or method.
*
* @param string $className
* @param string $methodName
* @return array
* @since Method available since Release 3.4.0
*/
public static function getTickets($className, $methodName)
{
$annotations = self::parseTestMethodAnnotations(
$className, $methodName
);
$tickets = array();
if (isset($annotations['class']['ticket'])) {
$tickets = $annotations['class']['ticket'];
}
if (isset($annotations['method']['ticket'])) {
$tickets = array_merge($tickets, $annotations['method']['ticket']);
}
return array_unique($tickets);
}
/**
* Returns the output buffering settings for a test.
*
* @param string $className
* @param string $methodName
* @return boolean
* @since Method available since Release 3.4.0
*/
public static function getOutputBufferingSettings($className, $methodName)
{
return self::getBooleanAnnotationSetting(
$className, $methodName, 'outputBuffering'
);
}
/**
* Returns the process isolation settings for a test.
*
* @param string $className
* @param string $methodName
* @return boolean
* @since Method available since Release 3.4.1
*/
public static function getProcessIsolationSettings($className, $methodName)
{
$annotations = self::parseTestMethodAnnotations(
$className, $methodName
);
if (isset($annotations['class']['runTestsInSeparateProcesses']) ||
isset($annotations['method']['runInSeparateProcess'])) {
return TRUE;
} else {
return FALSE;
}
}
/**
* Returns the preserve global state settings for a test.
*
* @param string $className
* @param string $methodName
* @return boolean
* @since Method available since Release 3.4.0
*/
public static function getPreserveGlobalStateSettings($className, $methodName)
{
return self::getBooleanAnnotationSetting(
$className, $methodName, 'preserveGlobalState'
);
}
/**
* @param string $className
* @param string $methodName
* @param string $settingName
* @return boolean
* @since Method available since Release 3.4.0
*/
private static function getBooleanAnnotationSetting($className, $methodName, $settingName)
{
$annotations = self::parseTestMethodAnnotations(
$className, $methodName
);
$result = NULL;
if (isset($annotations['class'][$settingName])) {
if ($annotations['class'][$settingName][0] == 'enabled') {
$result = TRUE;
}
else if ($annotations['class'][$settingName][0] == 'disabled') {
$result = FALSE;
}
}
if (isset($annotations['method'][$settingName])) {
if ($annotations['method'][$settingName][0] == 'enabled') {
$result = TRUE;
}
else if ($annotations['method'][$settingName][0] == 'disabled') {
$result = FALSE;
}
}
return $result;
}
}

View File

@@ -0,0 +1,177 @@
<?php
/**
* PHPUnit
*
* Copyright (c) 2001-2013, Sebastian Bergmann <sebastian@phpunit.de>.
* 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 Sebastian Bergmann nor the names of his
* 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.
*
* @package PHPUnit
* @subpackage Util_TestDox
* @author Sebastian Bergmann <sebastian@phpunit.de>
* @copyright 2001-2013 Sebastian Bergmann <sebastian@phpunit.de>
* @license http://www.opensource.org/licenses/BSD-3-Clause The BSD 3-Clause License
* @link http://www.phpunit.de/
* @since File available since Release 2.3.0
*/
/**
* Prettifies class and method names for use in TestDox documentation.
*
* @package PHPUnit
* @subpackage Util_TestDox
* @author Sebastian Bergmann <sebastian@phpunit.de>
* @copyright 2001-2013 Sebastian Bergmann <sebastian@phpunit.de>
* @license http://www.opensource.org/licenses/BSD-3-Clause The BSD 3-Clause License
* @link http://www.phpunit.de/
* @since Class available since Release 2.1.0
*/
class PHPUnit_Util_TestDox_NamePrettifier
{
/**
* @var string
*/
protected $prefix = 'Test';
/**
* @var string
*/
protected $suffix = 'Test';
/**
* @var array
*/
protected $strings = array();
/**
* Prettifies the name of a test class.
*
* @param string $name
* @return string
*/
public function prettifyTestClass($name)
{
$title = $name;
if ($this->suffix !== NULL &&
$this->suffix == substr($name, -1 * strlen($this->suffix))) {
$title = substr($title, 0, strripos($title, $this->suffix));
}
if ($this->prefix !== NULL &&
$this->prefix == substr($name, 0, strlen($this->prefix))) {
$title = substr($title, strlen($this->prefix));
}
return $title;
}
/**
* Prettifies the name of a test method.
*
* @param string $name
* @return string
*/
public function prettifyTestMethod($name)
{
$buffer = '';
if (!is_string($name) || strlen($name) == 0) {
return $buffer;
}
$string = preg_replace('#\d+$#', '', $name, -1, $count);
if (in_array($string, $this->strings)) {
$name = $string;
} else if ($count == 0) {
$this->strings[] = $string;
}
if (strpos($name, '_') !== FALSE) {
return str_replace('_', ' ', $name);
}
$max = strlen($name);
if (substr($name, 0, 4) == 'test') {
$offset = 4;
} else {
$offset = 0;
$name[0] = strtoupper($name[0]);
}
$wasNumeric = FALSE;
for ($i = $offset; $i < $max; $i++) {
if ($i > $offset &&
ord($name[$i]) >= 65 &&
ord($name[$i]) <= 90) {
$buffer .= ' ' . strtolower($name[$i]);
} else {
$isNumeric = is_numeric($name[$i]);
if (!$wasNumeric && $isNumeric) {
$buffer .= ' ';
$wasNumeric = TRUE;
}
if ($wasNumeric && !$isNumeric) {
$wasNumeric = FALSE;
}
$buffer .= $name[$i];
}
}
return $buffer;
}
/**
* Sets the prefix of test names.
*
* @param string $prefix
*/
public function setPrefix($prefix)
{
$this->prefix = $prefix;
}
/**
* Sets the suffix of test names.
*
* @param string $prefix
*/
public function setSuffix($suffix)
{
$this->suffix = $suffix;
}
}

View File

@@ -0,0 +1,347 @@
<?php
/**
* PHPUnit
*
* Copyright (c) 2001-2013, Sebastian Bergmann <sebastian@phpunit.de>.
* 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 Sebastian Bergmann nor the names of his
* 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.
*
* @package PHPUnit
* @subpackage Util_TestDox
* @author Sebastian Bergmann <sebastian@phpunit.de>
* @copyright 2001-2013 Sebastian Bergmann <sebastian@phpunit.de>
* @license http://www.opensource.org/licenses/BSD-3-Clause The BSD 3-Clause License
* @link http://www.phpunit.de/
* @since File available since Release 2.3.0
*/
/**
* Base class for printers of TestDox documentation.
*
* @package PHPUnit
* @subpackage Util_TestDox
* @author Sebastian Bergmann <sebastian@phpunit.de>
* @copyright 2001-2013 Sebastian Bergmann <sebastian@phpunit.de>
* @license http://www.opensource.org/licenses/BSD-3-Clause The BSD 3-Clause License
* @link http://www.phpunit.de/
* @since Class available since Release 2.1.0
*/
abstract class PHPUnit_Util_TestDox_ResultPrinter extends PHPUnit_Util_Printer implements PHPUnit_Framework_TestListener
{
/**
* @var PHPUnit_Util_TestDox_NamePrettifier
*/
protected $prettifier;
/**
* @var string
*/
protected $testClass = '';
/**
* @var integer
*/
protected $testStatus = FALSE;
/**
* @var array
*/
protected $tests = array();
/**
* @var integer
*/
protected $successful = 0;
/**
* @var integer
*/
protected $failed = 0;
/**
* @var integer
*/
protected $skipped = 0;
/**
* @var integer
*/
protected $incomplete = 0;
/**
* @var string
*/
protected $testTypeOfInterest = 'PHPUnit_Framework_TestCase';
/**
* @var string
*/
protected $currentTestClassPrettified;
/**
* @var string
*/
protected $currentTestMethodPrettified;
/**
* Constructor.
*
* @param resource $out
*/
public function __construct($out = NULL)
{
parent::__construct($out);
$this->prettifier = new PHPUnit_Util_TestDox_NamePrettifier;
$this->startRun();
}
/**
* Flush buffer and close output.
*
*/
public function flush()
{
$this->doEndClass();
$this->endRun();
parent::flush();
}
/**
* An error occurred.
*
* @param PHPUnit_Framework_Test $test
* @param Exception $e
* @param float $time
*/
public function addError(PHPUnit_Framework_Test $test, Exception $e, $time)
{
if ($test instanceof $this->testTypeOfInterest) {
$this->testStatus = PHPUnit_Runner_BaseTestRunner::STATUS_ERROR;
$this->failed++;
}
}
/**
* A failure occurred.
*
* @param PHPUnit_Framework_Test $test
* @param PHPUnit_Framework_AssertionFailedError $e
* @param float $time
*/
public function addFailure(PHPUnit_Framework_Test $test, PHPUnit_Framework_AssertionFailedError $e, $time)
{
if ($test instanceof $this->testTypeOfInterest) {
$this->testStatus = PHPUnit_Runner_BaseTestRunner::STATUS_FAILURE;
$this->failed++;
}
}
/**
* Incomplete test.
*
* @param PHPUnit_Framework_Test $test
* @param Exception $e
* @param float $time
*/
public function addIncompleteTest(PHPUnit_Framework_Test $test, Exception $e, $time)
{
if ($test instanceof $this->testTypeOfInterest) {
$this->testStatus = PHPUnit_Runner_BaseTestRunner::STATUS_INCOMPLETE;
$this->incomplete++;
}
}
/**
* Skipped test.
*
* @param PHPUnit_Framework_Test $test
* @param Exception $e
* @param float $time
* @since Method available since Release 3.0.0
*/
public function addSkippedTest(PHPUnit_Framework_Test $test, Exception $e, $time)
{
if ($test instanceof $this->testTypeOfInterest) {
$this->testStatus = PHPUnit_Runner_BaseTestRunner::STATUS_SKIPPED;
$this->skipped++;
}
}
/**
* A testsuite started.
*
* @param PHPUnit_Framework_TestSuite $suite
* @since Method available since Release 2.2.0
*/
public function startTestSuite(PHPUnit_Framework_TestSuite $suite)
{
}
/**
* A testsuite ended.
*
* @param PHPUnit_Framework_TestSuite $suite
* @since Method available since Release 2.2.0
*/
public function endTestSuite(PHPUnit_Framework_TestSuite $suite)
{
}
/**
* A test started.
*
* @param PHPUnit_Framework_Test $test
*/
public function startTest(PHPUnit_Framework_Test $test)
{
if ($test instanceof $this->testTypeOfInterest) {
$class = get_class($test);
if ($this->testClass != $class) {
if ($this->testClass != '') {
$this->doEndClass();
}
$this->currentTestClassPrettified = $this->prettifier->prettifyTestClass($class);
$this->startClass($class);
$this->testClass = $class;
$this->tests = array();
}
$prettified = FALSE;
if ($test instanceof PHPUnit_Framework_TestCase &&
!$test instanceof PHPUnit_Framework_Warning) {
$annotations = $test->getAnnotations();
if (isset($annotations['method']['testdox'][0])) {
$this->currentTestMethodPrettified = $annotations['method']['testdox'][0];
$prettified = TRUE;
}
}
if (!$prettified) {
$this->currentTestMethodPrettified = $this->prettifier->prettifyTestMethod($test->getName(FALSE));
}
$this->testStatus = PHPUnit_Runner_BaseTestRunner::STATUS_PASSED;
}
}
/**
* A test ended.
*
* @param PHPUnit_Framework_Test $test
* @param float $time
*/
public function endTest(PHPUnit_Framework_Test $test, $time)
{
if ($test instanceof $this->testTypeOfInterest) {
if (!isset($this->tests[$this->currentTestMethodPrettified])) {
if ($this->testStatus == PHPUnit_Runner_BaseTestRunner::STATUS_PASSED) {
$this->tests[$this->currentTestMethodPrettified]['success'] = 1;
$this->tests[$this->currentTestMethodPrettified]['failure'] = 0;
} else {
$this->tests[$this->currentTestMethodPrettified]['success'] = 0;
$this->tests[$this->currentTestMethodPrettified]['failure'] = 1;
}
} else {
if ($this->testStatus == PHPUnit_Runner_BaseTestRunner::STATUS_PASSED) {
$this->tests[$this->currentTestMethodPrettified]['success']++;
} else {
$this->tests[$this->currentTestMethodPrettified]['failure']++;
}
}
$this->currentTestClassPrettified = NULL;
$this->currentTestMethodPrettified = NULL;
}
}
/**
* @since Method available since Release 2.3.0
*/
protected function doEndClass()
{
foreach ($this->tests as $name => $data) {
$this->onTest($name, $data['failure'] == 0);
}
$this->endClass($this->testClass);
}
/**
* Handler for 'start run' event.
*
*/
protected function startRun()
{
}
/**
* Handler for 'start class' event.
*
* @param string $name
*/
protected function startClass($name)
{
}
/**
* Handler for 'on test' event.
*
* @param string $name
* @param boolean $success
*/
protected function onTest($name, $success = TRUE)
{
}
/**
* Handler for 'end class' event.
*
* @param string $name
*/
protected function endClass($name)
{
}
/**
* Handler for 'end run' event.
*
*/
protected function endRun()
{
}
}

View File

@@ -0,0 +1,123 @@
<?php
/**
* PHPUnit
*
* Copyright (c) 2001-2013, Sebastian Bergmann <sebastian@phpunit.de>.
* 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 Sebastian Bergmann nor the names of his
* 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.
*
* @package PHPUnit
* @subpackage Util_TestDox
* @author Sebastian Bergmann <sebastian@phpunit.de>
* @copyright 2001-2013 Sebastian Bergmann <sebastian@phpunit.de>
* @license http://www.opensource.org/licenses/BSD-3-Clause The BSD 3-Clause License
* @link http://www.phpunit.de/
* @since File available since Release 2.3.0
*/
/**
* Prints TestDox documentation in HTML format.
*
* @package PHPUnit
* @subpackage Util_TestDox
* @author Sebastian Bergmann <sebastian@phpunit.de>
* @copyright 2001-2013 Sebastian Bergmann <sebastian@phpunit.de>
* @license http://www.opensource.org/licenses/BSD-3-Clause The BSD 3-Clause License
* @link http://www.phpunit.de/
* @since Class available since Release 2.1.0
*/
class PHPUnit_Util_TestDox_ResultPrinter_HTML extends PHPUnit_Util_TestDox_ResultPrinter
{
/**
* @var boolean
*/
protected $printsHTML = TRUE;
/**
* Handler for 'start run' event.
*
*/
protected function startRun()
{
$this->write('<html><body>');
}
/**
* Handler for 'start class' event.
*
* @param string $name
*/
protected function startClass($name)
{
$this->write(
'<h2 id="' . $name . '">' . $this->currentTestClassPrettified .
'</h2><ul>'
);
}
/**
* Handler for 'on test' event.
*
* @param string $name
* @param boolean $success
*/
protected function onTest($name, $success = TRUE)
{
if (!$success) {
$strikeOpen = '<strike>';
$strikeClose = '</strike>';
} else {
$strikeOpen = '';
$strikeClose = '';
}
$this->write('<li>' . $strikeOpen . $name . $strikeClose . '</li>');
}
/**
* Handler for 'end class' event.
*
* @param string $name
*/
protected function endClass($name)
{
$this->write('</ul>');
}
/**
* Handler for 'end run' event.
*
*/
protected function endRun()
{
$this->write('</body></html>');
}
}

View File

@@ -0,0 +1,95 @@
<?php
/**
* PHPUnit
*
* Copyright (c) 2001-2013, Sebastian Bergmann <sebastian@phpunit.de>.
* 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 Sebastian Bergmann nor the names of his
* 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.
*
* @package PHPUnit
* @subpackage Util_TestDox
* @author Sebastian Bergmann <sebastian@phpunit.de>
* @copyright 2001-2013 Sebastian Bergmann <sebastian@phpunit.de>
* @license http://www.opensource.org/licenses/BSD-3-Clause The BSD 3-Clause License
* @link http://www.phpunit.de/
* @since File available since Release 2.3.0
*/
/**
* Prints TestDox documentation in text format.
*
* @package PHPUnit
* @subpackage Util_TestDox
* @author Sebastian Bergmann <sebastian@phpunit.de>
* @copyright 2001-2013 Sebastian Bergmann <sebastian@phpunit.de>
* @license http://www.opensource.org/licenses/BSD-3-Clause The BSD 3-Clause License
* @link http://www.phpunit.de/
* @since Class available since Release 2.1.0
*/
class PHPUnit_Util_TestDox_ResultPrinter_Text extends PHPUnit_Util_TestDox_ResultPrinter
{
/**
* Handler for 'start class' event.
*
* @param string $name
*/
protected function startClass($name)
{
$this->write($this->currentTestClassPrettified . "\n");
}
/**
* Handler for 'on test' event.
*
* @param string $name
* @param boolean $success
*/
protected function onTest($name, $success = TRUE)
{
if ($success) {
$this->write(' [x] ');
} else {
$this->write(' [ ] ');
}
$this->write($name . "\n");
}
/**
* Handler for 'end class' event.
*
* @param string $name
*/
protected function endClass($name)
{
$this->write("\n");
}
}

View File

@@ -0,0 +1,148 @@
<?php
/**
* PHPUnit
*
* Copyright (c) 2001-2013, Sebastian Bergmann <sebastian@phpunit.de>.
* 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 Sebastian Bergmann nor the names of his
* 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.
*
* @package PHPUnit
* @subpackage Util
* @author Sebastian Bergmann <sebastian@phpunit.de>
* @copyright 2001-2013 Sebastian Bergmann <sebastian@phpunit.de>
* @license http://www.opensource.org/licenses/BSD-3-Clause The BSD 3-Clause License
* @link http://www.phpunit.de/
* @since File available since Release 3.1.0
*/
/**
* Iterator for test suites.
*
* @package PHPUnit
* @subpackage Util
* @author Sebastian Bergmann <sebastian@phpunit.de>
* @copyright 2001-2013 Sebastian Bergmann <sebastian@phpunit.de>
* @license http://www.opensource.org/licenses/BSD-3-Clause The BSD 3-Clause License
* @link http://www.phpunit.de/
* @since Class available since Release 3.1.0
*/
class PHPUnit_Util_TestSuiteIterator implements RecursiveIterator
{
/**
* @var integer
*/
protected $position;
/**
* @var PHPUnit_Framework_Test[]
*/
protected $tests;
/**
* Constructor.
*
* @param PHPUnit_Framework_TestSuite $suite
*/
public function __construct(PHPUnit_Framework_TestSuite $testSuite)
{
$this->tests = $testSuite->tests();
}
/**
* Rewinds the Iterator to the first element.
*
*/
public function rewind()
{
$this->position = 0;
}
/**
* Checks if there is a current element after calls to rewind() or next().
*
* @return boolean
*/
public function valid()
{
return $this->position < count($this->tests);
}
/**
* Returns the key of the current element.
*
* @return integer
*/
public function key()
{
return $this->position;
}
/**
* Returns the current element.
*
* @return PHPUnit_Framework_Test
*/
public function current()
{
return $this->valid() ? $this->tests[$this->position] : NULL;
}
/**
* Moves forward to next element.
*
*/
public function next()
{
$this->position++;
}
/**
* Returns the sub iterator for the current element.
*
* @return PHPUnit_Util_TestSuiteIterator
*/
public function getChildren()
{
return new PHPUnit_Util_TestSuiteIterator(
$this->tests[$this->position]
);
}
/**
* Checks whether the current element has children.
*
* @return boolean
*/
public function hasChildren()
{
return $this->tests[$this->position] instanceof PHPUnit_Framework_TestSuite;
}
}

View File

@@ -0,0 +1,303 @@
<?php
/**
* PHPUnit
*
* Copyright (c) 2001-2013, Sebastian Bergmann <sebastian@phpunit.de>.
* 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 Sebastian Bergmann nor the names of his
* 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.
*
* @package PHPUnit
* @subpackage Util
* @author Sebastian Bergmann <sebastian@phpunit.de>
* @copyright 2001-2013 Sebastian Bergmann <sebastian@phpunit.de>
* @license http://www.opensource.org/licenses/BSD-3-Clause The BSD 3-Clause License
* @link http://www.phpunit.de/
* @since File available since Release 3.0.0
*/
/**
* Utility class for textual type (and value) representation.
*
* @package PHPUnit
* @subpackage Util
* @author Sebastian Bergmann <sebastian@phpunit.de>
* @copyright 2001-2013 Sebastian Bergmann <sebastian@phpunit.de>
* @license http://www.opensource.org/licenses/BSD-3-Clause The BSD 3-Clause License
* @link http://www.phpunit.de/
* @since Class available since Release 3.0.0
*/
class PHPUnit_Util_Type
{
public static function isType($type)
{
return in_array(
$type,
array(
'numeric',
'integer',
'int',
'float',
'string',
'boolean',
'bool',
'null',
'array',
'object',
'resource',
'scalar'
)
);
}
/**
* Exports a value into a string
*
* The output of this method is similar to the output of print_r(), but
* improved in various aspects:
*
* - NULL is rendered as "null" (instead of "")
* - TRUE is rendered as "true" (instead of "1")
* - FALSE is rendered as "false" (instead of "")
* - Strings are always quoted with single quotes
* - Carriage returns and newlines are normalized to \n
* - Recursion and repeated rendering is treated properly
*
* @param mixed $value The value to export
* @param integer $indentation The indentation level of the 2nd+ line
* @return string
* @since Method available since Release 3.6.0
*/
public static function export($value, $indentation = 0)
{
return self::recursiveExport($value, $indentation);
}
/**
* Recursive implementation of export
*
* @param mixed $value The value to export
* @param integer $indentation The indentation level of the 2nd+ line
* @param array $processedObjects Contains all objects that were already
* rendered
* @return string
* @since Method available since Release 3.6.0
* @see PHPUnit_Util_Type::export
*/
protected static function recursiveExport($value, $indentation, &$processedObjects = array())
{
if ($value === NULL) {
return 'null';
}
if ($value === TRUE) {
return 'true';
}
if ($value === FALSE) {
return 'false';
}
if (is_string($value)) {
// Match for most non printable chars somewhat taking multibyte chars into account
if (preg_match('/[^\x09-\x0d\x20-\xff]/', $value)) {
return 'Binary String: 0x' . bin2hex($value);
}
return "'" .
str_replace(array("\r\n", "\n\r", "\r"), array("\n", "\n", "\n"), $value) .
"'";
}
$origValue = $value;
if (is_object($value)) {
if (in_array($value, $processedObjects, TRUE)) {
return sprintf(
'%s Object (*RECURSION*)',
get_class($value)
);
}
$processedObjects[] = $value;
// Convert object to array
$value = self::toArray($value);
}
if (is_array($value)) {
$whitespace = str_repeat(' ', $indentation);
// There seems to be no other way to check arrays for recursion
// http://www.php.net/manual/en/language.types.array.php#73936
preg_match_all('/\n \[(\w+)\] => Array\s+\*RECURSION\*/', print_r($value, TRUE), $matches);
$recursiveKeys = array_unique($matches[1]);
// Convert to valid array keys
// Numeric integer strings are automatically converted to integers
// by PHP
foreach ($recursiveKeys as $key => $recursiveKey) {
if ((string)(integer)$recursiveKey === $recursiveKey) {
$recursiveKeys[$key] = (integer)$recursiveKey;
}
}
$content = '';
foreach ($value as $key => $val) {
if (in_array($key, $recursiveKeys, TRUE)) {
$val = 'Array (*RECURSION*)';
}
else {
$val = self::recursiveExport($val, $indentation+1, $processedObjects);
}
$content .= $whitespace . ' ' . self::export($key) . ' => ' . $val . "\n";
}
if (strlen($content) > 0) {
$content = "\n" . $content . $whitespace;
}
return sprintf(
"%s (%s)",
is_object($origValue) ? get_class($origValue) . ' Object' : 'Array',
$content
);
}
if (is_double($value) && (double)(integer)$value === $value) {
return $value . '.0';
}
return (string)$value;
}
/**
* Exports a value into a single-line string
*
* The output of this method is similar to the output of
* PHPUnit_Util_Type::export. This method guarantees thought that the
* result contains now newlines.
*
* Newlines are replaced by the visible string '\n'. Contents of arrays
* and objects (if any) are replaced by '...'.
*
* @param mixed $value The value to export
* @param integer $indentation The indentation level of the 2nd+ line
* @return string
* @see PHPUnit_Util_Type::export
*/
public static function shortenedExport($value)
{
if (is_string($value)) {
return self::shortenedString($value);
}
if (is_object($value)) {
return sprintf(
'%s Object (%s)',
get_class($value),
count(self::toArray($value)) > 0 ? '...' : ''
);
}
if (is_array($value)) {
return sprintf(
'Array (%s)',
count($value) > 0 ? '...' : ''
);
}
return self::export($value);
}
/**
* Shortens a string and converts all new lines to '\n'
*
* @param string $string The string to shorten
* @param integer $max The maximum length for the string
* @return string
*/
public static function shortenedString($string, $maxLength = 40)
{
$string = self::export($string);
if (strlen($string) > $maxLength) {
$string = substr($string, 0, $maxLength - 10) . '...' . substr($string, -7);
}
return str_replace("\n", '\n', $string);
}
/**
* Converts an object to an array containing all of its private, protected
* and public properties.
*
* @param object $object
* @return array
* @since Method available since Release 3.6.0
*/
public static function toArray($object)
{
$array = array();
foreach ((array)$object as $key => $value) {
// properties are transformed to keys in the following way:
// private $property => "\0Classname\0property"
// protected $property => "\0*\0property"
// public $property => "property"
if (preg_match('/^\0.+\0(.+)$/', $key, $matches)) {
$key = $matches[1];
}
$array[$key] = $value;
}
// Some internal classes like SplObjectStorage don't work with the
// above (fast) mechanism nor with reflection
// Format the output similarly to print_r() in this case
if ($object instanceof SplObjectStorage) {
foreach ($object as $key => $value) {
$array[spl_object_hash($value)] = array(
'obj' => $value,
'inf' => $object->getInfo(),
);
}
}
return $array;
}
}

View File

@@ -0,0 +1,920 @@
<?php
/**
* PHPUnit
*
* Copyright (c) 2001-2013, Sebastian Bergmann <sebastian@phpunit.de>.
* 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 Sebastian Bergmann nor the names of his
* 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.
*
* @package PHPUnit
* @subpackage Util
* @author Sebastian Bergmann <sebastian@phpunit.de>
* @copyright 2001-2013 Sebastian Bergmann <sebastian@phpunit.de>
* @license http://www.opensource.org/licenses/BSD-3-Clause The BSD 3-Clause License
* @link http://www.phpunit.de/
* @since File available since Release 3.2.0
*/
/**
* XML helpers.
*
* @package PHPUnit
* @subpackage Util
* @author Sebastian Bergmann <sebastian@phpunit.de>
* @copyright 2001-2013 Sebastian Bergmann <sebastian@phpunit.de>
* @license http://www.opensource.org/licenses/BSD-3-Clause The BSD 3-Clause License
* @link http://www.phpunit.de/
* @since Class available since Release 3.2.0
*/
class PHPUnit_Util_XML
{
/**
* @param string $string
* @return string
* @author Kore Nordmann <mail@kore-nordmann.de>
* @since Method available since Release 3.4.6
*/
public static function prepareString($string)
{
return preg_replace_callback(
'/[\\x00-\\x04\\x0b\\x0c\\x0e-\\x1f\\x7f]/',
function ($matches)
{
return sprintf('&#x%02x;', ord($matches[0]));
},
htmlspecialchars(
PHPUnit_Util_String::convertToUtf8($string), ENT_COMPAT, 'UTF-8'
)
);
}
/**
* Loads an XML (or HTML) file into a DOMDocument object.
*
* @param string $filename
* @param boolean $isHtml
* @param boolean $xinclude
* @return DOMDocument
* @since Method available since Release 3.3.0
*/
public static function loadFile($filename, $isHtml = FALSE, $xinclude = FALSE)
{
$reporting = error_reporting(0);
$contents = file_get_contents($filename);
error_reporting($reporting);
if ($contents === FALSE) {
throw new PHPUnit_Framework_Exception(
sprintf(
'Could not read "%s".',
$filename
)
);
}
return self::load($contents, $isHtml, $filename, $xinclude);
}
/**
* Load an $actual document into a DOMDocument. This is called
* from the selector assertions.
*
* If $actual is already a DOMDocument, it is returned with
* no changes. Otherwise, $actual is loaded into a new DOMDocument
* as either HTML or XML, depending on the value of $isHtml. If $isHtml is
* false and $xinclude is true, xinclude is performed on the loaded
* DOMDocument.
*
* Note: prior to PHPUnit 3.3.0, this method loaded a file and
* not a string as it currently does. To load a file into a
* DOMDocument, use loadFile() instead.
*
* @param string|DOMDocument $actual
* @param boolean $isHtml
* @param string $filename
* @param boolean $xinclude
* @return DOMDocument
* @since Method available since Release 3.3.0
* @author Mike Naberezny <mike@maintainable.com>
* @author Derek DeVries <derek@maintainable.com>
* @author Tobias Schlitt <toby@php.net>
*/
public static function load($actual, $isHtml = FALSE, $filename = '', $xinclude = FALSE)
{
if ($actual instanceof DOMDocument) {
return $actual;
}
$document = new DOMDocument;
$internal = libxml_use_internal_errors(TRUE);
$message = '';
$reporting = error_reporting(0);
if ($isHtml) {
$loaded = $document->loadHTML($actual);
} else {
$loaded = $document->loadXML($actual);
}
if ('' !== $filename) {
// Necessary for xinclude
$document->documentURI = $filename;
}
if (!$isHtml && $xinclude) {
$document->xinclude();
}
foreach (libxml_get_errors() as $error) {
$message .= $error->message;
}
libxml_use_internal_errors($internal);
error_reporting($reporting);
if ($loaded === FALSE) {
if ($filename != '') {
throw new PHPUnit_Framework_Exception(
sprintf(
'Could not load "%s".%s',
$filename,
$message != '' ? "\n" . $message : ''
)
);
} else {
throw new PHPUnit_Framework_Exception($message);
}
}
return $document;
}
/**
*
*
* @param DOMNode $node
* @return string
* @since Method available since Release 3.4.0
*/
public static function nodeToText(DOMNode $node)
{
if ($node->childNodes->length == 1) {
return $node->nodeValue;
}
$result = '';
foreach ($node->childNodes as $childNode) {
$result .= $node->ownerDocument->saveXML($childNode);
}
return $result;
}
/**
*
*
* @param DOMNode $node
* @since Method available since Release 3.3.0
* @author Mattis Stordalen Flister <mattis@xait.no>
*/
public static function removeCharacterDataNodes(DOMNode $node)
{
if ($node->hasChildNodes()) {
for ($i = $node->childNodes->length - 1; $i >= 0; $i--) {
if (($child = $node->childNodes->item($i)) instanceof DOMCharacterData) {
$node->removeChild($child);
}
}
}
}
/**
* "Convert" a DOMElement object into a PHP variable.
*
* @param DOMElement $element
* @return mixed
* @since Method available since Release 3.4.0
*/
public static function xmlToVariable(DOMElement $element)
{
$variable = NULL;
switch ($element->tagName) {
case 'array': {
$variable = array();
foreach ($element->getElementsByTagName('element') as $element) {
$value = self::xmlToVariable($element->childNodes->item(1));
if ($element->hasAttribute('key')) {
$variable[(string)$element->getAttribute('key')] = $value;
} else {
$variable[] = $value;
}
}
}
break;
case 'object': {
$className = $element->getAttribute('class');
if ($element->hasChildNodes()) {
$arguments = $element->childNodes->item(1)->childNodes;
$constructorArgs = array();
foreach ($arguments as $argument) {
if ($argument instanceof DOMElement) {
$constructorArgs[] = self::xmlToVariable($argument);
}
}
$class = new ReflectionClass($className);
$variable = $class->newInstanceArgs($constructorArgs);
} else {
$variable = new $className;
}
}
break;
case 'boolean': {
$variable = $element->nodeValue == 'true' ? TRUE : FALSE;
}
break;
case 'integer':
case 'double':
case 'string': {
$variable = $element->nodeValue;
settype($variable, $element->tagName);
}
break;
}
return $variable;
}
/**
* Validate list of keys in the associative array.
*
* @param array $hash
* @param array $validKeys
* @return array
* @throws PHPUnit_Framework_Exception
* @since Method available since Release 3.3.0
* @author Mike Naberezny <mike@maintainable.com>
* @author Derek DeVries <derek@maintainable.com>
*/
public static function assertValidKeys(array $hash, array $validKeys)
{
$valids = array();
// Normalize validation keys so that we can use both indexed and
// associative arrays.
foreach ($validKeys as $key => $val) {
is_int($key) ? $valids[$val] = NULL : $valids[$key] = $val;
}
$validKeys = array_keys($valids);
// Check for invalid keys.
foreach ($hash as $key => $value) {
if (!in_array($key, $validKeys)) {
$unknown[] = $key;
}
}
if (!empty($unknown)) {
throw new PHPUnit_Framework_Exception(
'Unknown key(s): ' . implode(', ', $unknown)
);
}
// Add default values for any valid keys that are empty.
foreach ($valids as $key => $value) {
if (!isset($hash[$key])) {
$hash[$key] = $value;
}
}
return $hash;
}
/**
* Parse a CSS selector into an associative array suitable for
* use with findNodes().
*
* @param string $selector
* @param mixed $content
* @return array
* @since Method available since Release 3.3.0
* @author Mike Naberezny <mike@maintainable.com>
* @author Derek DeVries <derek@maintainable.com>
*/
public static function convertSelectToTag($selector, $content = TRUE)
{
$selector = trim(preg_replace("/\s+/", " ", $selector));
// substitute spaces within attribute value
while (preg_match('/\[[^\]]+"[^"]+\s[^"]+"\]/', $selector)) {
$selector = preg_replace(
'/(\[[^\]]+"[^"]+)\s([^"]+"\])/', "$1__SPACE__$2", $selector
);
}
if (strstr($selector, ' ')) {
$elements = explode(' ', $selector);
} else {
$elements = array($selector);
}
$previousTag = array();
foreach (array_reverse($elements) as $element) {
$element = str_replace('__SPACE__', ' ', $element);
// child selector
if ($element == '>') {
$previousTag = array('child' => $previousTag['descendant']);
continue;
}
$tag = array();
// match element tag
preg_match("/^([^\.#\[]*)/", $element, $eltMatches);
if (!empty($eltMatches[1])) {
$tag['tag'] = $eltMatches[1];
}
// match attributes (\[[^\]]*\]*), ids (#[^\.#\[]*),
// and classes (\.[^\.#\[]*))
preg_match_all(
"/(\[[^\]]*\]*|#[^\.#\[]*|\.[^\.#\[]*)/", $element, $matches
);
if (!empty($matches[1])) {
$classes = array();
$attrs = array();
foreach ($matches[1] as $match) {
// id matched
if (substr($match, 0, 1) == '#') {
$tag['id'] = substr($match, 1);
}
// class matched
else if (substr($match, 0, 1) == '.') {
$classes[] = substr($match, 1);
}
// attribute matched
else if (substr($match, 0, 1) == '[' &&
substr($match, -1, 1) == ']') {
$attribute = substr($match, 1, strlen($match) - 2);
$attribute = str_replace('"', '', $attribute);
// match single word
if (strstr($attribute, '~=')) {
list($key, $value) = explode('~=', $attribute);
$value = "regexp:/.*\b$value\b.*/";
}
// match substring
else if (strstr($attribute, '*=')) {
list($key, $value) = explode('*=', $attribute);
$value = "regexp:/.*$value.*/";
}
// exact match
else {
list($key, $value) = explode('=', $attribute);
}
$attrs[$key] = $value;
}
}
if ($classes) {
$tag['class'] = join(' ', $classes);
}
if ($attrs) {
$tag['attributes'] = $attrs;
}
}
// tag content
if (is_string($content)) {
$tag['content'] = $content;
}
// determine previous child/descendants
if (!empty($previousTag['descendant'])) {
$tag['descendant'] = $previousTag['descendant'];
}
else if (!empty($previousTag['child'])) {
$tag['child'] = $previousTag['child'];
}
$previousTag = array('descendant' => $tag);
}
return $tag;
}
/**
* Parse an $actual document and return an array of DOMNodes
* matching the CSS $selector. If an error occurs, it will
* return FALSE.
*
* To only return nodes containing a certain content, give
* the $content to match as a string. Otherwise, setting
* $content to TRUE will return all nodes matching $selector.
*
* The $actual document may be a DOMDocument or a string
* containing XML or HTML, identified by $isHtml.
*
* @param array $selector
* @param string $content
* @param mixed $actual
* @param boolean $isHtml
* @return false|array
* @since Method available since Release 3.3.0
* @author Mike Naberezny <mike@maintainable.com>
* @author Derek DeVries <derek@maintainable.com>
* @author Tobias Schlitt <toby@php.net>
*/
public static function cssSelect($selector, $content, $actual, $isHtml = TRUE)
{
$matcher = self::convertSelectToTag($selector, $content);
$dom = self::load($actual, $isHtml);
$tags = self::findNodes($dom, $matcher, $isHtml);
return $tags;
}
/**
* Parse out the options from the tag using DOM object tree.
*
* @param DOMDocument $dom
* @param array $options
* @param boolean $isHtml
* @return array
* @since Method available since Release 3.3.0
* @author Mike Naberezny <mike@maintainable.com>
* @author Derek DeVries <derek@maintainable.com>
* @author Tobias Schlitt <toby@php.net>
*/
public static function findNodes(DOMDocument $dom, array $options, $isHtml = TRUE)
{
$valid = array(
'id', 'class', 'tag', 'content', 'attributes', 'parent',
'child', 'ancestor', 'descendant', 'children'
);
$filtered = array();
$options = self::assertValidKeys($options, $valid);
// find the element by id
if ($options['id']) {
$options['attributes']['id'] = $options['id'];
}
if ($options['class']) {
$options['attributes']['class'] = $options['class'];
}
// find the element by a tag type
if ($options['tag']) {
if ($isHtml) {
$elements = self::getElementsByCaseInsensitiveTagName(
$dom, $options['tag']
);
} else {
$elements = $dom->getElementsByTagName($options['tag']);
}
foreach ($elements as $element) {
$nodes[] = $element;
}
if (empty($nodes)) {
return FALSE;
}
}
// no tag selected, get them all
else {
$tags = array(
'a', 'abbr', 'acronym', 'address', 'area', 'b', 'base', 'bdo',
'big', 'blockquote', 'body', 'br', 'button', 'caption', 'cite',
'code', 'col', 'colgroup', 'dd', 'del', 'div', 'dfn', 'dl',
'dt', 'em', 'fieldset', 'form', 'frame', 'frameset', 'h1', 'h2',
'h3', 'h4', 'h5', 'h6', 'head', 'hr', 'html', 'i', 'iframe',
'img', 'input', 'ins', 'kbd', 'label', 'legend', 'li', 'link',
'map', 'meta', 'noframes', 'noscript', 'object', 'ol', 'optgroup',
'option', 'p', 'param', 'pre', 'q', 'samp', 'script', 'select',
'small', 'span', 'strong', 'style', 'sub', 'sup', 'table',
'tbody', 'td', 'textarea', 'tfoot', 'th', 'thead', 'title',
'tr', 'tt', 'ul', 'var'
);
foreach ($tags as $tag) {
if ($isHtml) {
$elements = self::getElementsByCaseInsensitiveTagName(
$dom, $tag
);
} else {
$elements = $dom->getElementsByTagName($tag);
}
foreach ($elements as $element) {
$nodes[] = $element;
}
}
if (empty($nodes)) {
return FALSE;
}
}
// filter by attributes
if ($options['attributes']) {
foreach ($nodes as $node) {
$invalid = FALSE;
foreach ($options['attributes'] as $name => $value) {
// match by regexp if like "regexp:/foo/i"
if (preg_match('/^regexp\s*:\s*(.*)/i', $value, $matches)) {
if (!preg_match($matches[1], $node->getAttribute($name))) {
$invalid = TRUE;
}
}
// class can match only a part
else if ($name == 'class') {
// split to individual classes
$findClasses = explode(
' ', preg_replace("/\s+/", " ", $value)
);
$allClasses = explode(
' ',
preg_replace("/\s+/", " ", $node->getAttribute($name))
);
// make sure each class given is in the actual node
foreach ($findClasses as $findClass) {
if (!in_array($findClass, $allClasses)) {
$invalid = TRUE;
}
}
}
// match by exact string
else {
if ($node->getAttribute($name) != $value) {
$invalid = TRUE;
}
}
}
// if every attribute given matched
if (!$invalid) {
$filtered[] = $node;
}
}
$nodes = $filtered;
$filtered = array();
if (empty($nodes)) {
return FALSE;
}
}
// filter by content
if ($options['content'] !== NULL) {
foreach ($nodes as $node) {
$invalid = FALSE;
// match by regexp if like "regexp:/foo/i"
if (preg_match('/^regexp\s*:\s*(.*)/i', $options['content'], $matches)) {
if (!preg_match($matches[1], self::getNodeText($node))) {
$invalid = TRUE;
}
}
// match empty string
else if ($options['content'] === '') {
if (self::getNodeText($node) !== '') {
$invalid = TRUE;
}
}
// match by exact string
else if (strstr(self::getNodeText($node), $options['content']) === FALSE) {
$invalid = TRUE;
}
if (!$invalid) {
$filtered[] = $node;
}
}
$nodes = $filtered;
$filtered = array();
if (empty($nodes)) {
return FALSE;
}
}
// filter by parent node
if ($options['parent']) {
$parentNodes = self::findNodes($dom, $options['parent'], $isHtml);
$parentNode = isset($parentNodes[0]) ? $parentNodes[0] : NULL;
foreach ($nodes as $node) {
if ($parentNode !== $node->parentNode) {
continue;
}
$filtered[] = $node;
}
$nodes = $filtered;
$filtered = array();
if (empty($nodes)) {
return FALSE;
}
}
// filter by child node
if ($options['child']) {
$childNodes = self::findNodes($dom, $options['child'], $isHtml);
$childNodes = !empty($childNodes) ? $childNodes : array();
foreach ($nodes as $node) {
foreach ($node->childNodes as $child) {
foreach ($childNodes as $childNode) {
if ($childNode === $child) {
$filtered[] = $node;
}
}
}
}
$nodes = $filtered;
$filtered = array();
if (empty($nodes)) {
return FALSE;
}
}
// filter by ancestor
if ($options['ancestor']) {
$ancestorNodes = self::findNodes($dom, $options['ancestor'], $isHtml);
$ancestorNode = isset($ancestorNodes[0]) ? $ancestorNodes[0] : NULL;
foreach ($nodes as $node) {
$parent = $node->parentNode;
while ($parent && $parent->nodeType != XML_HTML_DOCUMENT_NODE) {
if ($parent === $ancestorNode) {
$filtered[] = $node;
}
$parent = $parent->parentNode;
}
}
$nodes = $filtered;
$filtered = array();
if (empty($nodes)) {
return FALSE;
}
}
// filter by descendant
if ($options['descendant']) {
$descendantNodes = self::findNodes($dom, $options['descendant'], $isHtml);
$descendantNodes = !empty($descendantNodes) ? $descendantNodes : array();
foreach ($nodes as $node) {
foreach (self::getDescendants($node) as $descendant) {
foreach ($descendantNodes as $descendantNode) {
if ($descendantNode === $descendant) {
$filtered[] = $node;
}
}
}
}
$nodes = $filtered;
$filtered = array();
if (empty($nodes)) {
return FALSE;
}
}
// filter by children
if ($options['children']) {
$validChild = array('count', 'greater_than', 'less_than', 'only');
$childOptions = self::assertValidKeys(
$options['children'], $validChild
);
foreach ($nodes as $node) {
$childNodes = $node->childNodes;
foreach ($childNodes as $childNode) {
if ($childNode->nodeType !== XML_CDATA_SECTION_NODE &&
$childNode->nodeType !== XML_TEXT_NODE) {
$children[] = $childNode;
}
}
// we must have children to pass this filter
if (!empty($children)) {
// exact count of children
if ($childOptions['count'] !== NULL) {
if (count($children) !== $childOptions['count']) {
break;
}
}
// range count of children
else if ($childOptions['less_than'] !== NULL &&
$childOptions['greater_than'] !== NULL) {
if (count($children) >= $childOptions['less_than'] ||
count($children) <= $childOptions['greater_than']) {
break;
}
}
// less than a given count
else if ($childOptions['less_than'] !== NULL) {
if (count($children) >= $childOptions['less_than']) {
break;
}
}
// more than a given count
else if ($childOptions['greater_than'] !== NULL) {
if (count($children) <= $childOptions['greater_than']) {
break;
}
}
// match each child against a specific tag
if ($childOptions['only']) {
$onlyNodes = self::findNodes(
$dom, $childOptions['only'], $isHtml
);
// try to match each child to one of the 'only' nodes
foreach ($children as $child) {
$matched = FALSE;
foreach ($onlyNodes as $onlyNode) {
if ($onlyNode === $child) {
$matched = TRUE;
}
}
if (!$matched) {
break(2);
}
}
}
$filtered[] = $node;
}
}
$nodes = $filtered;
$filtered = array();
if (empty($nodes)) {
return;
}
}
// return the first node that matches all criteria
return !empty($nodes) ? $nodes : array();
}
/**
* Recursively get flat array of all descendants of this node.
*
* @param DOMNode $node
* @return array
* @since Method available since Release 3.3.0
* @author Mike Naberezny <mike@maintainable.com>
* @author Derek DeVries <derek@maintainable.com>
*/
protected static function getDescendants(DOMNode $node)
{
$allChildren = array();
$childNodes = $node->childNodes ? $node->childNodes : array();
foreach ($childNodes as $child) {
if ($child->nodeType === XML_CDATA_SECTION_NODE ||
$child->nodeType === XML_TEXT_NODE) {
continue;
}
$children = self::getDescendants($child);
$allChildren = array_merge($allChildren, $children, array($child));
}
return isset($allChildren) ? $allChildren : array();
}
/**
* Gets elements by case insensitive tagname.
*
* @param DOMDocument $dom
* @param string $tag
* @return DOMNodeList
* @since Method available since Release 3.4.0
*/
protected static function getElementsByCaseInsensitiveTagName(DOMDocument $dom, $tag)
{
$elements = $dom->getElementsByTagName(strtolower($tag));
if ($elements->length == 0) {
$elements = $dom->getElementsByTagName(strtoupper($tag));
}
return $elements;
}
/**
* Get the text value of this node's child text node.
*
* @param DOMNode $node
* @return string
* @since Method available since Release 3.3.0
* @author Mike Naberezny <mike@maintainable.com>
* @author Derek DeVries <derek@maintainable.com>
*/
protected static function getNodeText(DOMNode $node)
{
if (!$node->childNodes instanceof DOMNodeList) {
return '';
}
$result = '';
foreach ($node->childNodes as $childNode) {
if ($childNode->nodeType === XML_TEXT_NODE ||
$childNode->nodeType === XML_CDATA_SECTION_NODE) {
$result .= trim($childNode->data) . ' ';
} else {
$result .= self::getNodeText($childNode);
}
}
return str_replace(' ', ' ', $result);
}
}