<?php /** * Global state for SimpleTest and kicker script in future versions. * @package SimpleTest * @subpackage UnitTester * @version $Id: simpletest.php 2011 2011-04-29 08:22:48Z pp11 $ */ /**#@+ * include SimpleTest files */ require_once(dirname(__FILE__) . '/reflection_php5.php'); require_once(dirname(__FILE__) . '/default_reporter.php'); require_once(dirname(__FILE__) . '/compatibility.php'); /**#@-*/ /** * Registry and test context. Includes a few * global options that I'm slowly getting rid of. * @package SimpleTest * @subpackage UnitTester */ class SimpleTest { /** * Reads the SimpleTest version from the release file. * @return string Version string. */ static function getVersion() { $content = file(dirname(__FILE__) . '/VERSION'); return trim($content[0]); } /** * Sets the name of a test case to ignore, usually * because the class is an abstract case that should * @param string $class Add a class to ignore. */ static function ignore($class) { $registry = &SimpleTest::getRegistry(); $registry['IgnoreList'][strtolower($class)] = true; } /** * Scans the now complete ignore list, and adds * all parent classes to the list. If a class * is not a runnable test case, then it's parents * wouldn't be either. This is syntactic sugar * to cut down on ommissions of ignore()'s or * missing abstract declarations. This cannot * be done whilst loading classes wiithout forcing * a particular order on the class declarations and * the ignore() calls. It's just nice to have the ignore() * calls at the top of the file before the actual declarations. * @param array $classes Class names of interest. */ static function ignoreParentsIfIgnored($classes) { $registry = &SimpleTest::getRegistry(); foreach ($classes as $class) { if (SimpleTest::isIgnored($class)) { $reflection = new SimpleReflection($class); if ($parent = $reflection->getParent()) { SimpleTest::ignore($parent); } } } } /** * Puts the object to the global pool of 'preferred' objects * which can be retrieved with SimpleTest :: preferred() method. * Instances of the same class are overwritten. * @param object $object Preferred object * @see preferred() */ static function prefer($object) { $registry = &SimpleTest::getRegistry(); $registry['Preferred'][] = $object; } /** * Retrieves 'preferred' objects from global pool. Class filter * can be applied in order to retrieve the object of the specific * class * @param array|string $classes Allowed classes or interfaces. * @return array|object|null * @see prefer() */ static function preferred($classes) { if (! is_array($classes)) { $classes = array($classes); } $registry = &SimpleTest::getRegistry(); for ($i = count($registry['Preferred']) - 1; $i >= 0; $i--) { foreach ($classes as $class) { if (SimpleTestCompatibility::isA($registry['Preferred'][$i], $class)) { return $registry['Preferred'][$i]; } } } return null; } /** * Test to see if a test case is in the ignore * list. Quite obviously the ignore list should * be a separate object and will be one day. * This method is internal to SimpleTest. Don't * use it. * @param string $class Class name to test. * @return boolean True if should not be run. */ static function isIgnored($class) { $registry = &SimpleTest::getRegistry(); return isset($registry['IgnoreList'][strtolower($class)]); } /** * Sets proxy to use on all requests for when * testing from behind a firewall. Set host * to false to disable. This will take effect * if there are no other proxy settings. * @param string $proxy Proxy host as URL. * @param string $username Proxy username for authentication. * @param string $password Proxy password for authentication. */ static function useProxy($proxy, $username = false, $password = false) { $registry = &SimpleTest::getRegistry(); $registry['DefaultProxy'] = $proxy; $registry['DefaultProxyUsername'] = $username; $registry['DefaultProxyPassword'] = $password; } /** * Accessor for default proxy host. * @return string Proxy URL. */ static function getDefaultProxy() { $registry = &SimpleTest::getRegistry(); return $registry['DefaultProxy']; } /** * Accessor for default proxy username. * @return string Proxy username for authentication. */ static function getDefaultProxyUsername() { $registry = &SimpleTest::getRegistry(); return $registry['DefaultProxyUsername']; } /** * Accessor for default proxy password. * @return string Proxy password for authentication. */ static function getDefaultProxyPassword() { $registry = &SimpleTest::getRegistry(); return $registry['DefaultProxyPassword']; } /** * Accessor for default HTML parsers. * @return array List of parsers to try in * order until one responds true * to can(). */ static function getParsers() { $registry = &SimpleTest::getRegistry(); return $registry['Parsers']; } /** * Set the list of HTML parsers to attempt to use by default. * @param array $parsers List of parsers to try in * order until one responds true * to can(). */ static function setParsers($parsers) { $registry = &SimpleTest::getRegistry(); $registry['Parsers'] = $parsers; } /** * Accessor for global registry of options. * @return hash All stored values. */ protected static function &getRegistry() { static $registry = false; if (! $registry) { $registry = SimpleTest::getDefaults(); } return $registry; } /** * Accessor for the context of the current * test run. * @return SimpleTestContext Current test run. */ static function getContext() { static $context = false; if (! $context) { $context = new SimpleTestContext(); } return $context; } /** * Constant default values. * @return hash All registry defaults. */ protected static function getDefaults() { return array( 'Parsers' => false, 'MockBaseClass' => 'SimpleMock', 'IgnoreList' => array(), 'DefaultProxy' => false, 'DefaultProxyUsername' => false, 'DefaultProxyPassword' => false, 'Preferred' => array(new HtmlReporter(), new TextReporter(), new XmlReporter())); } /** * @deprecated */ static function setMockBaseClass($mock_base) { $registry = &SimpleTest::getRegistry(); $registry['MockBaseClass'] = $mock_base; } /** * @deprecated */ static function getMockBaseClass() { $registry = &SimpleTest::getRegistry(); return $registry['MockBaseClass']; } } /** * Container for all components for a specific * test run. Makes things like error queues * available to PHP event handlers, and also * gets around some nasty reference issues in * the mocks. * @package SimpleTest */ class SimpleTestContext { private $test; private $reporter; private $resources; /** * Clears down the current context. * @access public */ function clear() { $this->resources = array(); } /** * Sets the current test case instance. This * global instance can be used by the mock objects * to send message to the test cases. * @param SimpleTestCase $test Test case to register. */ function setTest($test) { $this->clear(); $this->test = $test; } /** * Accessor for currently running test case. * @return SimpleTestCase Current test. */ function getTest() { return $this->test; } /** * Sets the current reporter. This * global instance can be used by the mock objects * to send messages. * @param SimpleReporter $reporter Reporter to register. */ function setReporter($reporter) { $this->clear(); $this->reporter = $reporter; } /** * Accessor for current reporter. * @return SimpleReporter Current reporter. */ function getReporter() { return $this->reporter; } /** * Accessor for the Singleton resource. * @return object Global resource. */ function get($resource) { if (! isset($this->resources[$resource])) { $this->resources[$resource] = new $resource(); } return $this->resources[$resource]; } } /** * Interrogates the stack trace to recover the * failure point. * @package SimpleTest * @subpackage UnitTester */ class SimpleStackTrace { private $prefixes; /** * Stashes the list of target prefixes. * @param array $prefixes List of method prefixes * to search for. */ function __construct($prefixes) { $this->prefixes = $prefixes; } /** * Extracts the last method name that was not within * Simpletest itself. Captures a stack trace if none given. * @param array $stack List of stack frames. * @return string Snippet of test report with line * number and file. */ function traceMethod($stack = false) { $stack = $stack ? $stack : $this->captureTrace(); foreach ($stack as $frame) { if ($this->frameLiesWithinSimpleTestFolder($frame)) { continue; } if ($this->frameMatchesPrefix($frame)) { return ' at [' . $frame['file'] . ' line ' . $frame['line'] . ']'; } } return ''; } /** * Test to see if error is generated by SimpleTest itself. * @param array $frame PHP stack frame. * @return boolean True if a SimpleTest file. */ protected function frameLiesWithinSimpleTestFolder($frame) { if (isset($frame['file'])) { $path = substr(SIMPLE_TEST, 0, -1); if (strpos($frame['file'], $path) === 0) { if (dirname($frame['file']) == $path) { return true; } } } return false; } /** * Tries to determine if the method call is an assert, etc. * @param array $frame PHP stack frame. * @return boolean True if matches a target. */ protected function frameMatchesPrefix($frame) { foreach ($this->prefixes as $prefix) { if (strncmp($frame['function'], $prefix, strlen($prefix)) == 0) { return true; } } return false; } /** * Grabs a current stack trace. * @return array Fulle trace. */ protected function captureTrace() { if (function_exists('debug_backtrace')) { return array_reverse(debug_backtrace()); } return array(); } } ?>