Viewing File: /opt/alt/tests/alt-php84-pecl-redis_6.1.0-7.el8/tests/TestSuite.php
<?php defined('PHPREDIS_TESTRUN') or die("Use TestRedis.php to run tests!\n");
/* A specific exception for when we skip a test */
class TestSkippedException extends Exception {}
// phpunit is such a pain to install, we're going with pure-PHP here.
class TestSuite
{
/* Host and port the unit tests will use */
private string $host;
private ?int $port = 6379;
/* Redis authentication we'll use */
private $auth;
/* Redis server version */
protected $version;
protected bool $is_keydb;
private static bool $colorize = false;
private static $BOLD_ON = "\033[1m";
private static $BOLD_OFF = "\033[0m";
private static $BLACK = "\033[0;30m";
private static $DARKGRAY = "\033[1;30m";
private static $BLUE = "\033[0;34m";
private static $PURPLE = "\033[0;35m";
private static $GREEN = "\033[0;32m";
private static $YELLOW = "\033[0;33m";
private static $RED = "\033[0;31m";
public static array $errors = [];
public static array $warnings = [];
public function __construct(string $host, ?int $port, $auth) {
$this->host = $host;
$this->port = $port;
$this->auth = $auth;
}
public function getHost() { return $this->host; }
public function getPort() { return $this->port; }
public function getAuth() { return $this->auth; }
public static function errorMessage(string $fmt, ...$args) {
$msg = vsprintf($fmt . "\n", $args);
if (defined('STDERR')) {
fwrite(STDERR, $msg);
} else {
echo $msg;
}
}
public static function make_bold(string $msg) {
return self::$colorize ? self::$BOLD_ON . $msg . self::$BOLD_OFF : $msg;
}
public static function make_success(string $msg) {
return self::$colorize ? self::$GREEN . $msg . self::$BOLD_OFF : $msg;
}
public static function make_fail(string $msg) {
return self::$colorize ? self::$RED . $msg . self::$BOLD_OFF : $msg;
}
public static function make_warning(string $msg) {
return self::$colorize ? self::$YELLOW . $msg . self::$BOLD_OFF : $msg;
}
protected function printArg($v) {
if (is_null($v))
return '(null)';
else if ($v === false || $v === true)
return $v ? '(true)' : '(false)';
else if (is_string($v))
return "'$v'";
else
return print_r($v, true);
}
protected function findTestFunction($bt) {
$i = 0;
while (isset($bt[$i])) {
if (substr($bt[$i]['function'], 0, 4) == 'test')
return $bt[$i]['function'];
$i++;
}
return NULL;
}
protected function assertionTrace(?string $fmt = NULL, ...$args) {
$prefix = 'Assertion failed:';
$lines = [];
$bt = debug_backtrace();
$msg = $fmt ? vsprintf($fmt, $args) : NULL;
$fn = $this->findTestFunction($bt);
$lines []= sprintf("%s %s - %s", $prefix, self::make_bold($fn),
$msg ? $msg : '(no message)');
array_shift($bt);
for ($i = 0; $i < count($bt); $i++) {
$file = $bt[$i]['file'];
$line = $bt[$i]['line'];
$fn = $bt[$i+1]['function'] ?? $bt[$i]['function'];
$lines []= sprintf("%s %s:%d (%s)%s",
str_repeat(' ', strlen($prefix)), $file, $line,
$fn, $msg ? " $msg" : '');
if (substr($fn, 0, 4) == 'test')
break;
}
return implode("\n", $lines) . "\n";
}
protected function assert($fmt, ...$args) {
self::$errors []= $this->assertionTrace($fmt, ...$args);
}
protected function assertKeyEquals($expected, $key, $redis = NULL): bool {
$actual = ($redis ??= $this->redis)->get($key);
if ($actual === $expected)
return true;
self::$errors []= $this->assertionTrace("%s !== %s", $this->printArg($actual),
$this->printArg($expected));
return false;
}
protected function assertKeyEqualsWeak($expected, $key, $redis = NULL): bool {
$actual = ($redis ??= $this->redis)->get($key);
if ($actual == $expected)
return true;
self::$errors []= $this->assertionTrace("%s != %s", $this->printArg($actual),
$this->printArg($expected));
return false;
}
protected function assertKeyExists($key, $redis = NULL): bool {
if (($redis ??= $this->redis)->exists($key))
return true;
self::$errors []= $this->assertionTrace("Key '%s' does not exist.", $key);
return false;
}
protected function assertKeyMissing($key, $redis = NULL): bool {
if ( ! ($redis ??= $this->redis)->exists($key))
return true;
self::$errors []= $this->assertionTrace("Key '%s' exists but shouldn't.", $key);
return false;
}
protected function assertTrue($value): bool {
if ($value === true)
return true;
self::$errors []= $this->assertionTrace("%s !== %s", $this->printArg($value),
$this->printArg(true));
return false;
}
protected function assertFalse($value): bool {
if ($value === false)
return true;
self::$errors []= $this->assertionTrace("%s !== %s", $this->printArg($value),
$this->printArg(false));
return false;
}
protected function assertNull($value): bool {
if ($value === NULL)
return true;
self::$errors []= $this->assertionTrace("%s !== %s", $this->printArg($value),
$this->printArg(NULL));
return false;
}
protected function assertInArray($ele, $arr, ?callable $cb = NULL): bool {
$cb ??= function ($v) { return true; };
$key = array_search($ele, $arr);
if ($key !== false && ($valid = $cb($ele)))
return true;
self::$errors []= $this->assertionTrace("%s %s %s", $this->printArg($ele),
$key === false ? 'missing from' : 'is invalid in',
$this->printArg($arr));
return false;
}
protected function assertIsString($v): bool {
if (is_string($v))
return true;
self::$errors []= $this->assertionTrace("%s is not a string", $this->printArg($v));
return false;
}
protected function assertIsBool($v): bool {
if (is_bool($v))
return true;
self::$errors []= $this->assertionTrace("%s is not a boolean", $this->printArg($v));
return false;
}
protected function assertIsInt($v): bool {
if (is_int($v))
return true;
self::$errors []= $this->assertionTrace("%s is not an integer", $this->printArg($v));
return false;
}
protected function assertIsFloat($v): bool {
if (is_float($v))
return true;
self::$errors []= $this->assertionTrace("%s is not a float", $this->printArg($v));
return false;
}
protected function assertIsObject($v, ?string $type = NULL): bool {
if ( ! is_object($v)) {
self::$errors []= $this->assertionTrace("%s is not an object", $this->printArg($v));
return false;
} else if ( $type !== NULL && !($v InstanceOf $type)) {
self::$errors []= $this->assertionTrace("%s is not an instance of %s",
$this->printArg($v), $type);
return false;
}
return true;
}
protected function assertSameType($expected, $actual): bool {
if (gettype($expected) === gettype($actual))
return true;
self::$errors []= $this->assertionTrace("%s is not the same type as %s",
$this->printArg($actual),
$this->printArg($expected));
return false;
}
protected function assertIsArray($v, ?int $size = null): bool {
if ( ! is_array($v)) {
self::$errors []= $this->assertionTrace("%s is not an array", $this->printArg($v));
return false;
}
if ( ! is_null($size) && count($v) != $size) {
self::$errors []= $this->assertionTrace("Array size %d != %d", count($v), $size);
return false;
}
return true;
}
protected function assertArrayKey($arr, $key, ?callable $cb = NULL): bool {
$cb ??= function ($v) { return true; };
if (($exists = isset($arr[$key])) && $cb($arr[$key]))
return true;
if ($exists) {
$msg = sprintf("%s is invalid in %s", $this->printArg($arr[$key]),
$this->printArg($arr));
} else {
$msg = sprintf("%s is not a key in %s", $this->printArg($key),
$this->printArg($arr));
}
self::$errors []= $this->assertionTrace($msg);
return false;
}
protected function assertArrayKeyEquals($arr, $key, $value): bool {
if ( ! isset($arr[$key])) {
self::$errors []= $this->assertionTrace(
"Key '%s' not found in %s", $key, $this->printArg($arr));
return false;
}
if ($arr[$key] !== $value) {
self::$errors []= $this->assertionTrace(
"Value '%s' != '%s' for key '%s' in %s",
$arr[$key], $value, $key, $this->printArg($arr));
return false;
}
return true;
}
protected function assertValidate($val, callable $cb): bool {
if ($cb($val))
return true;
self::$errors []= $this->assertionTrace("%s is invalid.", $this->printArg($val));
return false;
}
protected function assertThrowsMatch($arg, callable $cb, $regex = NULL): bool {
$threw = $match = false;
try {
$cb($arg);
} catch (Exception $ex) {
$threw = true;
$match = !$regex || preg_match($regex, $ex->getMessage());
}
if ($threw && $match)
return true;
$ex = !$threw ? 'no exception' : "no match '$regex'";
self::$errors []= $this->assertionTrace("[$ex]");
return false;
}
protected function assertLTE($maximum, $value): bool {
if ($value <= $maximum)
return true;
self::$errors []= $this->assertionTrace("%s > %s", $value, $maximum);
return false;
}
protected function assertLT($minimum, $value): bool {
if ($value < $minimum)
return true;
self::$errors []= $this->assertionTrace("%s >= %s", $value, $minimum);
return false;
}
protected function assertGT($maximum, $value): bool {
if ($value > $maximum)
return true;
self::$errors [] = $this->assertionTrace("%s <= %s", $maximum, $value);
return false;
}
protected function assertGTE($minimum, $value): bool {
if ($value >= $minimum)
return true;
self::$errors [] = $this->assertionTrace("%s < %s", $minimum, $value);
return false;
}
protected function externalCmdFailure($cmd, $output, $msg = NULL, $exit_code = NULL) {
$bt = debug_backtrace(false);
$lines[] = sprintf("Assertion failed: %s:%d (%s)",
$bt[0]['file'], $bt[0]['line'],
self::make_bold($bt[0]['function']));
if ($msg)
$lines[] = sprintf(" Message: %s", $msg);
if ($exit_code !== NULL)
$lines[] = sprintf(" Exit code: %d", $exit_code);
$lines[] = sprintf( " Command: %s", $cmd);
if ($output)
$lines[] = sprintf(" Output: %s", $output);
self::$errors[] = implode("\n", $lines) . "\n";
}
protected function assertBetween($value, $min, $max, bool $exclusive = false): bool {
if ($min > $max)
[$max, $min] = [$min, $max];
if ($exclusive) {
if ($value > $min && $value < $max)
return true;
} else {
if ($value >= $min && $value <= $max)
return true;
}
self::$errors []= $this->assertionTrace(sprintf("'%s' not between '%s' and '%s'",
$value, $min, $max));
return false;
}
/* Replica of PHPUnit's assertion. Basically are two arrays the same without
' respect to order. */
protected function assertEqualsCanonicalizing($expected, $actual, $keep_keys = false): bool {
if ($expected InstanceOf Traversable)
$expected = iterator_to_array($expected);
if ($actual InstanceOf Traversable)
$actual = iterator_to_array($actual);
if ($keep_keys) {
asort($expected);
asort($actual);
} else {
sort($expected);
sort($actual);
}
if ($expected === $actual)
return true;
self::$errors []= $this->assertionTrace("%s !== %s",
$this->printArg($actual),
$this->printArg($expected));
return false;
}
protected function assertEqualsWeak($expected, $actual): bool {
if ($expected == $actual)
return true;
self::$errors []= $this->assertionTrace("%s != %s", $this->printArg($actual),
$this->printArg($expected));
return false;
}
protected function assertEquals($expected, $actual): bool {
if ($expected === $actual)
return true;
self::$errors[] = $this->assertionTrace("%s !== %s", $this->printArg($actual),
$this->printArg($expected));
return false;
}
public function assertNotEquals($wrong_value, $test_value): bool {
if ($wrong_value !== $test_value)
return true;
self::$errors []= $this->assertionTrace("%s === %s", $this->printArg($wrong_value),
$this->printArg($test_value));
return false;
}
protected function assertStringContains(string $needle, $haystack): bool {
if ( ! is_string($haystack)) {
self::$errors []= $this->assertionTrace("'%s' is not a string", $this->printArg($haystack));
return false;
}
if (strstr($haystack, $needle) !== false)
return true;
self::$errors []= $this->assertionTrace("'%s' not found in '%s'", $needle, $haystack);
}
protected function assertPatternMatch(string $pattern, string $value): bool {
if (preg_match($pattern, $value))
return true;
self::$errors []= $this->assertionTrace("'%s' doesnt match '%s'", $value,
$pattern);
return false;
}
protected function markTestSkipped(string $msg = '') {
$bt = debug_backtrace(false);
self::$warnings []= sprintf("Skipped test: %s:%d (%s) %s\n",
$bt[0]["file"], $bt[0]["line"],
$bt[1]["function"], $msg);
throw new TestSkippedException($msg);
}
private static function getMaxTestLen(array $methods, ?string $limit): int {
$result = 0;
foreach ($methods as $obj_method) {
$name = strtolower($obj_method->name);
if (substr($name, 0, 4) != 'test')
continue;
if ($limit && !strstr($name, $limit))
continue;
if (strlen($name) > $result) {
$result = strlen($name);
}
}
return $result;
}
private static function findFile($path, $file) {
$files = glob($path . '/*', GLOB_NOSORT);
foreach ($files as $test) {
$test = basename($test);
if (strcasecmp($file, $test) == 0)
return $path . '/' . $test;
}
return NULL;
}
/* Small helper method that tries to load a custom test case class */
public static function loadTestClass($class) {
$filename = "{$class}.php";
if (($sp = getenv('PHPREDIS_TEST_SEARCH_PATH'))) {
$fullname = self::findFile($sp, $filename);
} else {
$fullname = self::findFile(__DIR__, $filename);
}
if ( ! $fullname)
die("Fatal: Couldn't find $filename\n");
require_once($fullname);
if ( ! class_exists($class))
die("Fatal: Loaded '$filename' but didn't find class '$class'\n");
/* Loaded the file and found the class, return it */
return $class;
}
/* Flag colorization */
public static function flagColorization(bool $override) {
self::$colorize = $override && function_exists('posix_isatty') &&
defined('STDOUT') && posix_isatty(STDOUT);
}
public static function run($class_name, ?string $limit = NULL,
?string $host = NULL, ?int $port = NULL,
$auth = NULL)
{
if ($limit)
$limit = strtolower($limit);
$rc = new ReflectionClass($class_name);
$methods = $rc->GetMethods(ReflectionMethod::IS_PUBLIC);
$max_test_len = self::getMaxTestLen($methods, $limit);
foreach($methods as $m) {
$name = $m->name;
if (substr($name, 0, 4) !== 'test')
continue;
/* If we're trying to limit to a specific test and can't match the
* substring, skip */
if ($limit && stristr($name, $limit) === false) {
continue;
}
$padded_name = str_pad($name, $max_test_len + 1);
echo self::make_bold($padded_name);
$count = count($class_name::$errors);
$rt = new $class_name($host, $port, $auth);
try {
$rt->setUp();
$rt->$name();
if ($count === count($class_name::$errors)) {
$result = self::make_success('PASSED');
} else {
$result = self::make_fail('FAILED');
}
} catch (Exception $e) {
/* We may have simply skipped the test */
if ($e instanceof TestSkippedException) {
$result = self::make_warning('SKIPPED');
} else {
$class_name::$errors[] = "Uncaught exception '".$e->getMessage()."' ($name)\n";
$result = self::make_fail('FAILED');
}
}
echo "[" . $result . "]\n";
}
echo "\n";
echo implode('', $class_name::$warnings) . "\n";
if (empty($class_name::$errors)) {
echo "All tests passed. \o/\n";
return 0;
}
echo implode('', $class_name::$errors);
return 1;
}
}
?>
Back to Directory
File Manager
<