Add PHP unit tests and page tests.

Run "composer install", then "composer test".
This commit is contained in:
tim
2026-09-26 03:48:09 +02:00
parent 848c447c5b
commit ed959888b4
42 changed files with 5522 additions and 0 deletions
+82
View File
@@ -0,0 +1,82 @@
<?php
namespace Xxx\Tests\Unit;
use Xxx\Tests\Support\FakeDb;
use Xxx\Tests\Support\PhpProcess;
use Xxx\Tests\Support\TestCase;
// open_db() and db_fail() in open_db.lib.php
class OpenDbTest extends TestCase {
public function testOpenConnectsWithTheConfiguredSettings(): void {
$this->assertTrue(open_db('open'));
$this->assertInstanceOf(FakeDb::class, $GLOBALS['db']);
$this->assertSame(array(array('db.test', 'test-user', 'test-pass', 'test-db')), FakeDb::$connections);
}
public function testOpenTwiceKeepsTheFirstConnection(): void {
open_db('open');
$first = $GLOBALS['db'];
$this->assertFalse(open_db('open'));
$this->assertSame($first, $GLOBALS['db']);
$this->assertCount(1, FakeDb::$connections);
}
public function testCloseClosesAndForgetsTheConnection(): void {
open_db('open');
$connection = $GLOBALS['db'];
$this->assertTrue(open_db('close'));
$this->assertTrue($connection->closed);
$this->assertNull($GLOBALS['db']);
$this->assertFalse(open_db('close'));
}
public function testOpenAfterCloseConnectsAgain(): void {
open_db('open');
open_db('close');
open_db('open');
$this->assertCount(2, FakeDb::$connections);
}
public function testDbHostDefaultsToLocalhost(): void {
$root = var_export(XXX_ROOT, TRUE);
$result = PhpProcess::runPlain(
"require $root . '/vendor/autoload.php';\n" .
"if (!function_exists('mysqli_report')) { define('MYSQLI_REPORT_OFF', 0); function mysqli_report(\$f) { return TRUE; } }\n" .
"require $root . '/open_db.lib.php';\n" .
"\$db_class = Xxx\\Tests\\Support\\FakeDb::class;\n" .
"open_db('open');\n" .
"echo json_encode(Xxx\\Tests\\Support\\FakeDb::\$connections);",
array('XXX_ENV_FILE' => $this->tmp . '/none'));
$this->assertSame('[["localhost",null,null,null]]', $result['stdout'], $result['stderr']);
}
public function testConnectErrorStopsThePageAndLogsTheDetails(): void {
$result = PhpProcess::run('Xxx\Tests\Support\FakeDb::$connectError = "Access denied for user"; open_db("open"); echo "not reached";');
$this->assertSame('<p>Sorry, something went wrong. Please try again later.</p>', $result['stdout']);
$this->assertStringContainsString('xxx: database error at open_db.lib.php:', $result['log']);
$this->assertStringContainsString('connect error (1045) Access denied for user', $result['log']);
$this->assertStringNotContainsString('Access denied', $result['stdout']);
}
public function testDbFailLogsTheCallerAndTheDatabaseError(): void {
$result = PhpProcess::run("open_db('open');\n\$GLOBALS['db']->error = \"Table 'secret' doesn't exist\";\ndb_fail();\necho 'not reached';");
$this->assertSame('<p>Sorry, something went wrong. Please try again later.</p>', $result['stdout']);
$this->assertMatchesRegularExpression("/xxx: database error at xxx-php-\\w+:5: Table 'secret' doesn't exist/", $result['log']);
}
public function testDbFailWithoutAConnection(): void {
$result = PhpProcess::run('db_fail();');
$this->assertStringContainsString('no database connection', $result['log']);
}
public function testDbFailWithDetail(): void {
$result = PhpProcess::run('db_fail("custom detail");');
$this->assertStringContainsString(': custom detail', $result['log']);
}
public function testFailedQueryInTheCodeStopsThePage(): void {
$result = PhpProcess::run('Xxx\Tests\Support\FakeDb::on("/COUNT/", FALSE); open_db("open"); get_count(); echo "not reached";');
$this->assertSame('<p>Sorry, something went wrong. Please try again later.</p>', $result['stdout']);
$this->assertStringContainsString('database error at get_data.lib.php:', $result['log']);
}
}