Add PHP unit tests and page tests.
Run "composer install", then "composer test".
This commit is contained in:
@@ -0,0 +1,100 @@
|
||||
<?php
|
||||
namespace Xxx\Tests\Support;
|
||||
|
||||
/*
|
||||
* A stand-in for mysqli. open_db() makes one when the global $db_class
|
||||
* names this class. All connections share the static state below, so a
|
||||
* test sees the queries of every connection that the code opened.
|
||||
*
|
||||
* Handlers answer queries: FakeDb::on('/pattern/', $answer), where the
|
||||
* answer is a list of rows, TRUE, FALSE (a failed query) or a function
|
||||
* that takes ($sql, $params) and returns one of these. The handler added
|
||||
* last wins. A query that no handler matches gets no rows (SELECT) or
|
||||
* TRUE (anything else).
|
||||
*/
|
||||
class FakeDb {
|
||||
public static array $log = array();
|
||||
public static array $handlers = array();
|
||||
public static array $connections = array();
|
||||
public static ?string $connectError = NULL;
|
||||
// When set, every query is also appended to this file as a JSON line
|
||||
public static ?string $logFile = NULL;
|
||||
|
||||
public $connect_error = NULL;
|
||||
public $connect_errno = 0;
|
||||
public $error = '';
|
||||
public bool $closed = FALSE;
|
||||
|
||||
public static function reset(): void {
|
||||
self::$log = array();
|
||||
self::$handlers = array();
|
||||
self::$connections = array();
|
||||
self::$connectError = NULL;
|
||||
self::$logFile = NULL;
|
||||
}
|
||||
|
||||
public static function on(string $pattern, $answer): void {
|
||||
self::$handlers[] = array($pattern, $answer);
|
||||
}
|
||||
|
||||
// The SQL of every query so far
|
||||
public static function queries(): array {
|
||||
return array_column(self::$log, 'sql');
|
||||
}
|
||||
|
||||
// The queries whose SQL matches $pattern, each as array('sql' => ..., 'params' => ...)
|
||||
public static function matching(string $pattern): array {
|
||||
return array_values(array_filter(self::$log, function ($entry) use ($pattern) {
|
||||
return preg_match($pattern, $entry['sql']);
|
||||
}));
|
||||
}
|
||||
|
||||
public function __construct(...$args) {
|
||||
self::$connections[] = $args;
|
||||
if (self::$connectError !== NULL) {
|
||||
$this->connect_errno = 1045;
|
||||
$this->connect_error = self::$connectError;
|
||||
}
|
||||
}
|
||||
|
||||
public function real_escape_string($string) {
|
||||
return addslashes((string)$string);
|
||||
}
|
||||
|
||||
public function execute_query($sql, $params = array()) {
|
||||
if (substr_count($sql, '?') !== count($params))
|
||||
throw new \LogicException("Placeholder count does not match the parameters: $sql");
|
||||
return $this->run($sql, array_values($params));
|
||||
}
|
||||
|
||||
public function query($sql) {
|
||||
return $this->run($sql, array());
|
||||
}
|
||||
|
||||
public function close() {
|
||||
$this->closed = TRUE;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
private function run(string $sql, array $params) {
|
||||
$entry = array('sql' => $sql, 'params' => $params);
|
||||
self::$log[] = $entry;
|
||||
if (self::$logFile !== NULL)
|
||||
file_put_contents(self::$logFile, json_encode($entry) . "\n", FILE_APPEND | LOCK_EX);
|
||||
|
||||
$answer = NULL;
|
||||
foreach (array_reverse(self::$handlers) as list($pattern, $handler)) {
|
||||
if (preg_match($pattern, $sql)) {
|
||||
$answer = is_callable($handler) ? $handler($sql, $params) : $handler;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if ($answer === NULL)
|
||||
$answer = preg_match('/^\s*SELECT/i', $sql) ? array() : TRUE;
|
||||
if ($answer === FALSE) {
|
||||
$this->error = 'Fake failure for: ' . $sql;
|
||||
return FALSE;
|
||||
}
|
||||
return is_array($answer) ? new FakeResult($answer) : $answer;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user