From f22e53fdc9352e90a798aa77b74b1157018444da Mon Sep 17 00:00:00 2001 From: "J. King" Date: Thu, 22 Nov 2018 19:55:54 -0500 Subject: [PATCH] Align result tests with driver tests --- tests/cases/Db/BaseDriver.php | 9 +- tests/cases/Db/BaseResult.php | 112 ++++++++++++++ tests/cases/Db/PostgreSQL/TestCreation.php | 2 +- tests/cases/Db/SQLite3/TestCreation.php | 2 +- tests/cases/Db/SQLite3/TestDriver.php | 2 +- tests/cases/Db/SQLite3/TestResult.php | 33 ++++ tests/cases/Db/SQLite3/TestUpdate.php | 2 +- tests/cases/Db/SQLite3PDO/TestCreation.php | 2 +- tests/cases/Db/SQLite3PDO/TestUpdate.php | 2 +- tests/cases/Db/TestResult.php | 155 ------------------- tests/cases/Db/TestResultPDO.php | 52 +++++++ tests/cases/Db/TestStatement.php | 52 ++----- tests/cases/Feed/TestFeed.php | 2 +- tests/cases/Feed/TestFetching.php | 2 +- tests/cases/REST/NextCloudNews/TestV1_2.php | 2 +- tests/cases/REST/TestREST.php | 4 +- tests/cases/REST/TinyTinyRSS/TestAPI.php | 6 +- tests/cases/REST/TinyTinyRSS/TestIcon.php | 4 +- tests/cases/Service/TestService.php | 2 +- tests/cases/User/TestInternal.php | 2 +- tests/cases/User/TestUser.php | 2 +- tests/lib/AbstractTest.php | 163 +------------------- tests/lib/Database/Setup.php | 2 +- tests/lib/DatabaseInformation.php | 111 +++++++++++++ tests/phpunit.xml | 10 +- 25 files changed, 358 insertions(+), 379 deletions(-) create mode 100644 tests/cases/Db/BaseResult.php create mode 100644 tests/cases/Db/SQLite3/TestResult.php delete mode 100644 tests/cases/Db/TestResult.php create mode 100644 tests/cases/Db/TestResultPDO.php create mode 100644 tests/lib/DatabaseInformation.php diff --git a/tests/cases/Db/BaseDriver.php b/tests/cases/Db/BaseDriver.php index 4b6d68ab..a6e7f372 100644 --- a/tests/cases/Db/BaseDriver.php +++ b/tests/cases/Db/BaseDriver.php @@ -8,7 +8,7 @@ namespace JKingWeb\Arsse\TestCase\Db; use JKingWeb\Arsse\Db\Statement; use JKingWeb\Arsse\Db\Result; - +use JKingWeb\Arsse\Test\DatabaseInformation; abstract class BaseDriver extends \JKingWeb\Arsse\Test\AbstractTest { protected $drv; @@ -22,12 +22,13 @@ abstract class BaseDriver extends \JKingWeb\Arsse\Test\AbstractTest { ]; public function setUp() { - $this->setConf($this->conf); - $this->interface = $this->getDbInterface($this->implementation); + self::setConf($this->conf); + $info = new DatabaseInformation($this->implementation); + $this->interface = ($info->interfaceConstructor)(); if (!$this->interface) { $this->markTestSkipped("$this->implementation database driver not available"); } - $this->drv = $this->getDbDriver($this->implementation); + $this->drv = new $info->driverClass; $this->exec("DROP TABLE IF EXISTS arsse_test"); $this->exec("DROP TABLE IF EXISTS arsse_meta"); $this->exec("CREATE TABLE arsse_meta(key varchar(255) primary key not null, value text)"); diff --git a/tests/cases/Db/BaseResult.php b/tests/cases/Db/BaseResult.php new file mode 100644 index 00000000..a4708dde --- /dev/null +++ b/tests/cases/Db/BaseResult.php @@ -0,0 +1,112 @@ +implementation); + $this->interface = ($info->interfaceConstructor)(); + if (!$this->interface) { + $this->markTestSkipped("$this->implementation database driver not available"); + } + $this->resultClass = $info->resultClass; + $this->stringOutput = $info->stringOutput; + $this->exec("DROP TABLE IF EXISTS arsse_meta"); + } + + public function tearDown() { + $this->exec("DROP TABLE IF EXISTS arsse_meta"); + } + + public function testConstructResult() { + $this->assertInstanceOf(Result::class, new $this->resultClass(...$this->makeResult("SELECT 1"))); + } + + public function testGetChangeCountAndLastInsertId() { + $this->makeResult("CREATE TABLE arsse_meta(key varchar(255) primary key not null, value text)"); + $out = $this->makeResult("INSERT INTO arsse_meta(key,value) values('test', 1)"); + $rows = $out[1][0]; + $id = $out[1][1]; + $r = new $this->resultClass(...$out); + $this->assertSame((int) $rows, $r->changes()); + $this->assertSame((int) $id, $r->lastId()); + } + + public function testIterateOverResults() { + $exp = [0 => 1, 1 => 2, 2 => 3]; + $exp = $this->stringOutput ? $this->stringify($exp) : $exp; + foreach (new $this->resultClass(...$this->makeResult("SELECT 1 as col union select 2 as col union select 3 as col")) as $index => $row) { + $rows[$index] = $row['col']; + } + $this->assertSame($exp, $rows); + } + + public function testIterateOverResultsTwice() { + $exp = [0 => 1, 1 => 2, 2 => 3]; + $exp = $this->stringOutput ? $this->stringify($exp) : $exp; + $result = new $this->resultClass(...$this->makeResult("SELECT 1 as col union select 2 as col union select 3 as col")); + foreach ($result as $index => $row) { + $rows[$index] = $row['col']; + } + $this->assertSame($exp, $rows); + $this->assertException("resultReused", "Db"); + foreach ($result as $row) { + $rows[] = $row['col']; + } + } + + public function testGetSingleValues() { + $exp = [1867, 1970, 2112]; + $exp = $this->stringOutput ? $this->stringify($exp) : $exp; + $test = new $this->resultClass(...$this->makeResult("SELECT 1867 as year union select 1970 as year union select 2112 as year")); + $this->assertSame($exp[0], $test->getValue()); + $this->assertSame($exp[1], $test->getValue()); + $this->assertSame($exp[2], $test->getValue()); + $this->assertSame(null, $test->getValue()); + } + + public function testGetFirstValuesOnly() { + $exp = [1867, 1970, 2112]; + $exp = $this->stringOutput ? $this->stringify($exp) : $exp; + $test = new $this->resultClass(...$this->makeResult("SELECT 1867 as year, 19 as century union select 1970 as year, 20 as century union select 2112 as year, 22 as century")); + $this->assertSame($exp[0], $test->getValue()); + $this->assertSame($exp[1], $test->getValue()); + $this->assertSame($exp[2], $test->getValue()); + $this->assertSame(null, $test->getValue()); + } + + public function testGetRows() { + $exp = [ + ['album' => '2112', 'track' => '2112'], + ['album' => 'Clockwork Angels', 'track' => 'The Wreckers'], + ]; + $test = new $this->resultClass(...$this->makeResult("SELECT '2112' as album, '2112' as track union select 'Clockwork Angels' as album, 'The Wreckers' as track")); + $this->assertSame($exp[0], $test->getRow()); + $this->assertSame($exp[1], $test->getRow()); + $this->assertSame(null, $test->getRow()); + } + + public function testGetAllRows() { + $exp = [ + ['album' => '2112', 'track' => '2112'], + ['album' => 'Clockwork Angels', 'track' => 'The Wreckers'], + ]; + $test = new $this->resultClass(...$this->makeResult("SELECT '2112' as album, '2112' as track union select 'Clockwork Angels' as album, 'The Wreckers' as track")); + $this->assertEquals($exp, $test->getAll()); + } +} diff --git a/tests/cases/Db/PostgreSQL/TestCreation.php b/tests/cases/Db/PostgreSQL/TestCreation.php index 1190736c..fdc473b1 100644 --- a/tests/cases/Db/PostgreSQL/TestCreation.php +++ b/tests/cases/Db/PostgreSQL/TestCreation.php @@ -14,7 +14,7 @@ use JKingWeb\Arsse\Db\PostgreSQL\Driver; class TestCreation extends \JKingWeb\Arsse\Test\AbstractTest { /** @dataProvider provideConnectionStrings */ public function testGenerateConnectionString(bool $pdo, string $user, string $pass, string $db, string $host, int $port, string $service, string $exp) { - $this->setConf(); + self::setConf(); $timeout = (string) ceil(Arsse::$conf->dbTimeoutConnect ?? 0); $postfix = "application_name='arsse' client_encoding='UTF8' connect_timeout='$timeout'"; $act = Driver::makeConnectionString($pdo, $user, $pass, $db, $host, $port, $service); diff --git a/tests/cases/Db/SQLite3/TestCreation.php b/tests/cases/Db/SQLite3/TestCreation.php index 86ba40be..124c76a0 100644 --- a/tests/cases/Db/SQLite3/TestCreation.php +++ b/tests/cases/Db/SQLite3/TestCreation.php @@ -107,7 +107,7 @@ class TestCreation extends \JKingWeb\Arsse\Test\AbstractTest { chmod($path."Awal/arsse.db-wal", 0111); chmod($path."Ashm/arsse.db-shm", 0111); // set up configuration - $this->setConf(); + self::setConf(); } public function tearDown() { diff --git a/tests/cases/Db/SQLite3/TestDriver.php b/tests/cases/Db/SQLite3/TestDriver.php index 3316a01a..58ef4bfd 100644 --- a/tests/cases/Db/SQLite3/TestDriver.php +++ b/tests/cases/Db/SQLite3/TestDriver.php @@ -49,7 +49,7 @@ class TestDriver extends \JKingWeb\Arsse\TestCase\Db\BaseDriver { public function provideDrivers() { $this->clearData(); - $this->setConf([ + self::setConf([ 'dbTimeoutExec' => 0.5, 'dbSQLite3Timeout' => 0, 'dbSQLite3File' => tempnam(sys_get_temp_dir(), 'ook'), diff --git a/tests/cases/Db/SQLite3/TestResult.php b/tests/cases/Db/SQLite3/TestResult.php new file mode 100644 index 00000000..2f655e7e --- /dev/null +++ b/tests/cases/Db/SQLite3/TestResult.php @@ -0,0 +1,33 @@ + + */ +class TestResult extends \JKingWeb\Arsse\TestCase\Db\BaseResult { + protected $implementation = "SQLite 3"; + + public function tearDown() { + parent::tearDown(); + $this->interface->close(); + unset($this->interface); + } + + protected function exec(string $q) { + $this->interface->exec($q); + } + + protected function makeResult(string $q): array { + $set = $this->interface->query($q); + $rows = $this->interface->changes(); + $id = $this->interface->lastInsertRowID(); + return [$set, [$rows, $id]]; + } +} diff --git a/tests/cases/Db/SQLite3/TestUpdate.php b/tests/cases/Db/SQLite3/TestUpdate.php index 7347eca3..a2a70b0b 100644 --- a/tests/cases/Db/SQLite3/TestUpdate.php +++ b/tests/cases/Db/SQLite3/TestUpdate.php @@ -31,7 +31,7 @@ class TestUpdate extends \JKingWeb\Arsse\Test\AbstractTest { } $this->clearData(); $this->vfs = vfsStream::setup("schemata", null, ['SQLite3' => []]); - $this->setConf($conf); + self::setConf($conf); $this->base = $this->vfs->url(); $this->path = $this->base."/SQLite3/"; $this->drv = new Driver(); diff --git a/tests/cases/Db/SQLite3PDO/TestCreation.php b/tests/cases/Db/SQLite3PDO/TestCreation.php index bec51619..acae72b1 100644 --- a/tests/cases/Db/SQLite3PDO/TestCreation.php +++ b/tests/cases/Db/SQLite3PDO/TestCreation.php @@ -108,7 +108,7 @@ class TestCreation extends \JKingWeb\Arsse\Test\AbstractTest { chmod($path."Awal/arsse.db-wal", 0111); chmod($path."Ashm/arsse.db-shm", 0111); // set up configuration - $this->setConf(); + self::setConf(); } public function tearDown() { diff --git a/tests/cases/Db/SQLite3PDO/TestUpdate.php b/tests/cases/Db/SQLite3PDO/TestUpdate.php index d58f971c..409de79c 100644 --- a/tests/cases/Db/SQLite3PDO/TestUpdate.php +++ b/tests/cases/Db/SQLite3PDO/TestUpdate.php @@ -32,7 +32,7 @@ class TestUpdate extends \JKingWeb\Arsse\Test\AbstractTest { $this->clearData(); $this->vfs = vfsStream::setup("schemata", null, ['SQLite3' => []]); $conf['dbDriver'] = PDODriver::class; - $this->setConf($conf); + self::setConf($conf); $this->base = $this->vfs->url(); $this->path = $this->base."/SQLite3/"; $this->drv = new PDODriver(); diff --git a/tests/cases/Db/TestResult.php b/tests/cases/Db/TestResult.php deleted file mode 100644 index d0074bcc..00000000 --- a/tests/cases/Db/TestResult.php +++ /dev/null @@ -1,155 +0,0 @@ - - * @covers \JKingWeb\Arsse\Db\SQLite3\Result - */ -class TestResult extends \JKingWeb\Arsse\Test\AbstractTest { - public function provideResults() { - $this->setConf(); - $interfaces = $this->provideDbInterfaces(); - $constructors = [ - 'SQLite 3' => function(string $query) use($interfaces) { - $drv = $interfaces['SQLite 3']['interface']; - $set = $drv->query($query); - $rows = $drv->changes(); - $id = $drv->lastInsertRowID(); - return [$set, [$rows, $id]]; - }, - ]; - foreach ($constructors as $drv => $func) { - yield $drv => [isset($interfaces[$drv]['interface']), $interfaces[$drv]['stringOutput'], $interfaces[$drv]['result'], $func]; - } - // there is only one PDO result implementation, so we test the first implementation we find - $pdo = array_reduce($interfaces, function ($carry, $item) { - return $carry ?? ($item['interface'] instanceof \PDO ? $item : null); - }) ?? $interfaces['PDO SQLite 3']; - yield "PDO" => [isset($pdo['interface']), $pdo['stringOutput'], $pdo['result'], function(string $query) use($pdo) { - $drv = $pdo['interface']; - $set = $drv->query($query); - $rows = $set->rowCount(); - $id = $drv->lastInsertID(); - return [$set, [$rows, $id]]; - }]; - } - - /** @dataProvider provideResults */ - public function testConstructResult(bool $driverTestable, bool $stringCoersion, string $class, \Closure $func) { - if (!$driverTestable) { - $this->markTestSkipped(); - } - $this->assertInstanceOf(Result::class, new $class(...$func("SELECT 1"))); - } - - /** @dataProvider provideResults */ - public function testGetChangeCountAndLastInsertId(bool $driverTestable, bool $stringCoersion, string $class, \Closure $func) { - if (!$driverTestable) { - $this->markTestSkipped(); - } - $func("CREATE TABLE if not exists arsse_meta(key varchar(255) primary key not null, value text)"); - $out = $func("INSERT INTO arsse_meta(key,value) values('test', 1)"); - $rows = $out[1][0]; - $id = $out[1][1]; - $r = new $class(...$out); - $this->assertSame((int) $rows, $r->changes()); - $this->assertSame((int) $id, $r->lastId()); - } - - /** @dataProvider provideResults */ - public function testIterateOverResults(bool $driverTestable, bool $stringCoersion, string $class, \Closure $func) { - if (!$driverTestable) { - $this->markTestSkipped(); - } - $exp = [0 => 1, 1 => 2, 2 => 3]; - $exp = $stringCoersion ? $this->stringify($exp) : $exp; - foreach (new $class(...$func("SELECT 1 as col union select 2 as col union select 3 as col")) as $index => $row) { - $rows[$index] = $row['col']; - } - $this->assertSame($exp, $rows); - } - - /** @dataProvider provideResults */ - public function testIterateOverResultsTwice(bool $driverTestable, bool $stringCoersion, string $class, \Closure $func) { - if (!$driverTestable) { - $this->markTestSkipped(); - } - $exp = [0 => 1, 1 => 2, 2 => 3]; - $exp = $stringCoersion ? $this->stringify($exp) : $exp; - $result = new $class(...$func("SELECT 1 as col union select 2 as col union select 3 as col")); - foreach ($result as $index => $row) { - $rows[$index] = $row['col']; - } - $this->assertSame($exp, $rows); - $this->assertException("resultReused", "Db"); - foreach ($result as $row) { - $rows[] = $row['col']; - } - } - - /** @dataProvider provideResults */ - public function testGetSingleValues(bool $driverTestable, bool $stringCoersion, string $class, \Closure $func) { - if (!$driverTestable) { - $this->markTestSkipped(); - } - $exp = [1867, 1970, 2112]; - $exp = $stringCoersion ? $this->stringify($exp) : $exp; - $test = new $class(...$func("SELECT 1867 as year union select 1970 as year union select 2112 as year")); - $this->assertSame($exp[0], $test->getValue()); - $this->assertSame($exp[1], $test->getValue()); - $this->assertSame($exp[2], $test->getValue()); - $this->assertSame(null, $test->getValue()); - } - - /** @dataProvider provideResults */ - public function testGetFirstValuesOnly(bool $driverTestable, bool $stringCoersion, string $class, \Closure $func) { - if (!$driverTestable) { - $this->markTestSkipped(); - } - $exp = [1867, 1970, 2112]; - $exp = $stringCoersion ? $this->stringify($exp) : $exp; - $test = new $class(...$func("SELECT 1867 as year, 19 as century union select 1970 as year, 20 as century union select 2112 as year, 22 as century")); - $this->assertSame($exp[0], $test->getValue()); - $this->assertSame($exp[1], $test->getValue()); - $this->assertSame($exp[2], $test->getValue()); - $this->assertSame(null, $test->getValue()); - } - - /** @dataProvider provideResults */ - public function testGetRows(bool $driverTestable, bool $stringCoersion, string $class, \Closure $func) { - if (!$driverTestable) { - $this->markTestSkipped(); - } - $exp = [ - ['album' => '2112', 'track' => '2112'], - ['album' => 'Clockwork Angels', 'track' => 'The Wreckers'], - ]; - $test = new $class(...$func("SELECT '2112' as album, '2112' as track union select 'Clockwork Angels' as album, 'The Wreckers' as track")); - $this->assertSame($exp[0], $test->getRow()); - $this->assertSame($exp[1], $test->getRow()); - $this->assertSame(null, $test->getRow()); - } - - /** @dataProvider provideResults */ - public function testGetAllRows(bool $driverTestable, bool $stringCoersion, string $class, \Closure $func) { - if (!$driverTestable) { - $this->markTestSkipped(); - } - $exp = [ - ['album' => '2112', 'track' => '2112'], - ['album' => 'Clockwork Angels', 'track' => 'The Wreckers'], - ]; - $test = new $class(...$func("SELECT '2112' as album, '2112' as track union select 'Clockwork Angels' as album, 'The Wreckers' as track")); - $this->assertEquals($exp, $test->getAll()); - } -} diff --git a/tests/cases/Db/TestResultPDO.php b/tests/cases/Db/TestResultPDO.php new file mode 100644 index 00000000..f4d2eec7 --- /dev/null +++ b/tests/cases/Db/TestResultPDO.php @@ -0,0 +1,52 @@ + + */ +class TestResultPDO extends \JKingWeb\Arsse\TestCase\Db\BaseResult { + protected static $firstAvailableDriver; + + public static function setUpBeforeClass() { + self::setConf(); + // we only need to test one PDO implementation (they all use the same result class), so we find the first usable one + $drivers = DatabaseInformation::listPDO(); + self::$firstAvailableDriver = $drivers[0]; + foreach ($drivers as $driver) { + $info = new DatabaseInformation($driver); + $interface = ($info->interfaceConstructor)(); + if ($interface) { + self::$firstAvailableDriver = $driver; + break; + } + } + } + + public function setUp() { + $this->implementation = self::$firstAvailableDriver; + parent::setUp(); + } + + public function tearDown() { + parent::tearDown(); + unset($this->interface); + } + + protected function exec(string $q) { + $this->interface->exec($q); + } + + protected function makeResult(string $q): array { + $set = $this->interface->query($q); + $rows = $set->rowCount(); + $id = $this->interface->lastInsertID(); + return [$set, [$rows, $id]]; + } +} diff --git a/tests/cases/Db/TestStatement.php b/tests/cases/Db/TestStatement.php index 838ef678..d6a3cb81 100644 --- a/tests/cases/Db/TestStatement.php +++ b/tests/cases/Db/TestStatement.php @@ -38,18 +38,14 @@ class TestStatement extends \JKingWeb\Arsse\Test\AbstractTest { } /** @dataProvider provideStatements */ - public function testConstructStatement(bool $driverTestable, bool $stringCoersion, string $class, \Closure $func) { - if (!$driverTestable) { - $this->markTestSkipped(); - } + public function testConstructStatement() { + $class = $this->statementClass; $this->assertInstanceOf(Statement::class, new $class(...$func("SELECT ? as value"))); } /** @dataProvider provideBindings */ public function testBindATypedValue(bool $driverTestable, string $class, \Closure $func, $value, string $type, string $exp) { - if (!$driverTestable) { - $this->markTestSkipped(); - } + $class = $this->statementClass; if ($exp=="null") { $query = "SELECT (cast(? as text) is null) as pass"; } else { @@ -63,10 +59,8 @@ class TestStatement extends \JKingWeb\Arsse\Test\AbstractTest { } /** @dataProvider provideBinaryBindings */ - public function testHandleBinaryData(bool $driverTestable, string $class, \Closure $func, $value, string $type, string $exp) { - if (!$driverTestable) { - $this->markTestSkipped(); - } + public function testHandleBinaryData($value, string $type, string $exp) { + $class = $this->statementClass; if ($exp=="null") { $query = "SELECT (cast(? as text) is null) as pass"; } else { @@ -80,20 +74,16 @@ class TestStatement extends \JKingWeb\Arsse\Test\AbstractTest { } /** @dataProvider provideStatements */ - public function testBindMissingValue(bool $driverTestable, bool $stringCoersion, string $class, \Closure $func) { - if (!$driverTestable) { - $this->markTestSkipped(); - } + public function testBindMissingValue() { + $class = $this->statementClass; $s = new $class(...$func("SELECT ? as value", ["int"])); $val = $s->runArray()->getRow()['value']; $this->assertSame(null, $val); } /** @dataProvider provideStatements */ - public function testBindMultipleValues(bool $driverTestable, bool $stringCoersion, string $class, \Closure $func) { - if (!$driverTestable) { - $this->markTestSkipped(); - } + public function testBindMultipleValues() { + $class = $this->statementClass; $exp = [ 'one' => 1, 'two' => 2, @@ -105,10 +95,8 @@ class TestStatement extends \JKingWeb\Arsse\Test\AbstractTest { } /** @dataProvider provideStatements */ - public function testBindRecursively(bool $driverTestable, bool $stringCoersion, string $class, \Closure $func) { - if (!$driverTestable) { - $this->markTestSkipped(); - } + public function testBindRecursively() { + $class = $this->statementClass; $exp = [ 'one' => 1, 'two' => 2, @@ -122,20 +110,16 @@ class TestStatement extends \JKingWeb\Arsse\Test\AbstractTest { } /** @dataProvider provideStatements */ - public function testBindWithoutType(bool $driverTestable, bool $stringCoersion, string $class, \Closure $func) { - if (!$driverTestable) { - $this->markTestSkipped(); - } + public function testBindWithoutType() { + $class = $this->statementClass; $this->assertException("paramTypeMissing", "Db"); $s = new $class(...$func("SELECT ? as value", [])); $s->runArray([1]); } /** @dataProvider provideStatements */ - public function testViolateConstraint(bool $driverTestable, bool $stringCoersion, string $class, \Closure $func) { - if (!$driverTestable) { - $this->markTestSkipped(); - } + public function testViolateConstraint() { + $class = $this->statementClass; (new $class(...$func("CREATE TABLE if not exists arsse_meta(key varchar(255) primary key not null, value text)")))->run(); $s = new $class(...$func("INSERT INTO arsse_meta(key) values(?)", ["str"])); $this->assertException("constraintViolation", "Db", "ExceptionInput"); @@ -143,10 +127,8 @@ class TestStatement extends \JKingWeb\Arsse\Test\AbstractTest { } /** @dataProvider provideStatements */ - public function testMismatchTypes(bool $driverTestable, bool $stringCoersion, string $class, \Closure $func) { - if (!$driverTestable) { - $this->markTestSkipped(); - } + public function testMismatchTypes() { + $class = $this->statementClass; (new $class(...$func("CREATE TABLE if not exists arsse_feeds(id integer primary key not null, url text not null)")))->run(); $s = new $class(...$func("INSERT INTO arsse_feeds(id,url) values(?,?)", ["str", "str"])); $this->assertException("typeViolation", "Db", "ExceptionInput"); diff --git a/tests/cases/Feed/TestFeed.php b/tests/cases/Feed/TestFeed.php index a1ca84bd..01e9022d 100644 --- a/tests/cases/Feed/TestFeed.php +++ b/tests/cases/Feed/TestFeed.php @@ -96,7 +96,7 @@ class TestFeed extends \JKingWeb\Arsse\Test\AbstractTest { } $this->base = self::$host."Feed/"; $this->clearData(); - $this->setConf(); + self::setConf(); Arsse::$db = Phake::mock(Database::class); } diff --git a/tests/cases/Feed/TestFetching.php b/tests/cases/Feed/TestFetching.php index 25d4d7c4..64102b9d 100644 --- a/tests/cases/Feed/TestFetching.php +++ b/tests/cases/Feed/TestFetching.php @@ -26,7 +26,7 @@ class TestFetching extends \JKingWeb\Arsse\Test\AbstractTest { } $this->base = self::$host."Feed/"; $this->clearData(); - $this->setConf(); + self::setConf(); } public function testHandle400() { diff --git a/tests/cases/REST/NextCloudNews/TestV1_2.php b/tests/cases/REST/NextCloudNews/TestV1_2.php index 90375b70..22f3ab6a 100644 --- a/tests/cases/REST/NextCloudNews/TestV1_2.php +++ b/tests/cases/REST/NextCloudNews/TestV1_2.php @@ -340,7 +340,7 @@ class TestV1_2 extends \JKingWeb\Arsse\Test\AbstractTest { public function setUp() { $this->clearData(); - $this->setConf(); + self::setConf(); // create a mock user manager Arsse::$user = Phake::mock(User::class); Phake::when(Arsse::$user)->auth->thenReturn(true); diff --git a/tests/cases/REST/TestREST.php b/tests/cases/REST/TestREST.php index fcc4965a..19e119b0 100644 --- a/tests/cases/REST/TestREST.php +++ b/tests/cases/REST/TestREST.php @@ -95,7 +95,7 @@ class TestREST extends \JKingWeb\Arsse\Test\AbstractTest { } public function testSendAuthenticationChallenges() { - $this->setConf(); + self::setConf(); $r = new REST(); $in = new EmptyResponse(401); $exp = $in->withHeader("WWW-Authenticate", 'Basic realm="OOK"'); @@ -151,7 +151,7 @@ class TestREST extends \JKingWeb\Arsse\Test\AbstractTest { /** @dataProvider provideCorsNegotiations */ public function testNegotiateCors($origin, bool $exp, string $allowed = null, string $denied = null) { - $this->setConf(); + self::setConf(); $r = Phake::partialMock(REST::class); Phake::when($r)->corsNormalizeOrigin->thenReturnCallback(function ($origin) { return $origin; diff --git a/tests/cases/REST/TinyTinyRSS/TestAPI.php b/tests/cases/REST/TinyTinyRSS/TestAPI.php index b6bfb4f2..eb6ead75 100644 --- a/tests/cases/REST/TinyTinyRSS/TestAPI.php +++ b/tests/cases/REST/TinyTinyRSS/TestAPI.php @@ -177,7 +177,7 @@ LONG_STRING; public function setUp() { $this->clearData(); - $this->setConf(); + self::setConf(); // create a mock user manager Arsse::$user = Phake::mock(User::class); Phake::when(Arsse::$user)->auth->thenReturn(true); @@ -225,7 +225,7 @@ LONG_STRING; /** @dataProvider provideLoginRequests */ public function testLogIn(array $conf, $httpUser, array $data, $sessions) { Arsse::$user->id = null; - $this->setConf($conf); + self::setConf($conf); Phake::when(Arsse::$user)->auth->thenReturn(false); Phake::when(Arsse::$user)->auth("john.doe@example.com", "secret")->thenReturn(true); Phake::when(Arsse::$user)->auth("jane.doe@example.com", "superman")->thenReturn(true); @@ -259,7 +259,7 @@ LONG_STRING; /** @dataProvider provideResumeRequests */ public function testValidateASession(array $conf, $httpUser, string $data, $result) { Arsse::$user->id = null; - $this->setConf($conf); + self::setConf($conf); Phake::when(Arsse::$db)->sessionResume("PriestsOfSyrinx")->thenReturn([ 'id' => "PriestsOfSyrinx", 'created' => "2000-01-01 00:00:00", diff --git a/tests/cases/REST/TinyTinyRSS/TestIcon.php b/tests/cases/REST/TinyTinyRSS/TestIcon.php index 53db57c6..e25c6712 100644 --- a/tests/cases/REST/TinyTinyRSS/TestIcon.php +++ b/tests/cases/REST/TinyTinyRSS/TestIcon.php @@ -24,7 +24,7 @@ class TestIcon extends \JKingWeb\Arsse\Test\AbstractTest { public function setUp() { $this->clearData(); - $this->setConf(); + self::setConf(); // create a mock user manager Arsse::$user = Phake::mock(User::class); // create a mock database interface @@ -108,7 +108,7 @@ class TestIcon extends \JKingWeb\Arsse\Test\AbstractTest { $this->assertMessage($exp, $this->reqAuthFailed("42.ico")); $this->assertMessage($exp, $this->reqAuthFailed("1337.ico")); // with HTTP auth required, only authenticated requests should succeed - $this->setConf(['userHTTPAuthRequired' => true]); + self::setConf(['userHTTPAuthRequired' => true]); $exp = new Response(301, ['Location' => "http://example.org/icon.gif"]); $this->assertMessage($exp, $this->reqAuth("42.ico")); $this->assertMessage($exp, $this->reqAuth("1337.ico")); diff --git a/tests/cases/Service/TestService.php b/tests/cases/Service/TestService.php index 3ba18e02..69eec5f0 100644 --- a/tests/cases/Service/TestService.php +++ b/tests/cases/Service/TestService.php @@ -19,7 +19,7 @@ class TestService extends \JKingWeb\Arsse\Test\AbstractTest { public function setUp() { $this->clearData(); - $this->setConf(); + self::setConf(); Arsse::$db = Phake::mock(Database::class); $this->srv = new Service(); } diff --git a/tests/cases/User/TestInternal.php b/tests/cases/User/TestInternal.php index 68b597d4..a1f95dea 100644 --- a/tests/cases/User/TestInternal.php +++ b/tests/cases/User/TestInternal.php @@ -20,7 +20,7 @@ class TestInternal extends \JKingWeb\Arsse\Test\AbstractTest { public function setUp() { $this->clearData(); - $this->setConf(); + self::setConf(); // create a mock database interface Arsse::$db = Phake::mock(Database::class); Phake::when(Arsse::$db)->begin->thenReturn(Phake::mock(\JKingWeb\Arsse\Db\Transaction::class)); diff --git a/tests/cases/User/TestUser.php b/tests/cases/User/TestUser.php index 806bfff2..c576245f 100644 --- a/tests/cases/User/TestUser.php +++ b/tests/cases/User/TestUser.php @@ -20,7 +20,7 @@ class TestUser extends \JKingWeb\Arsse\Test\AbstractTest { public function setUp() { $this->clearData(); - $this->setConf(); + self::setConf(); // create a mock database interface Arsse::$db = Phake::mock(Database::class); Phake::when(Arsse::$db)->begin->thenReturn(Phake::mock(\JKingWeb\Arsse\Db\Transaction::class)); diff --git a/tests/lib/AbstractTest.php b/tests/lib/AbstractTest.php index e4930f04..1b244dbd 100644 --- a/tests/lib/AbstractTest.php +++ b/tests/lib/AbstractTest.php @@ -40,7 +40,7 @@ abstract class AbstractTest extends \PHPUnit\Framework\TestCase { } } - public function setConf(array $conf = []) { + public static function setConf(array $conf = []) { $defaults = [ 'dbSQLite3File' => ":memory:", 'dbSQLite3Timeout' => 0, @@ -126,165 +126,4 @@ abstract class AbstractTest extends \PHPUnit\Framework\TestCase { } return $value; } - - public function provideDbDrivers(array $conf = []): array { - $this->setConf($conf); - return [ - 'SQLite 3' => (function() { - try { - return new \JKingWeb\Arsse\Db\SQLite3\Driver; - } catch (\Exception $e) { - return; - } - })(), - 'PDO SQLite 3' => (function() { - try { - return new \JKingWeb\Arsse\Db\SQLite3\PDODriver; - } catch (\Exception $e) { - return; - } - })(), - 'PDO PostgreSQL' => (function() { - try { - return new \JKingWeb\Arsse\Db\PostgreSQL\PDODriver; - } catch (\Exception $e) { - return; - } - })(), - ]; - } - - public function provideDbInterfaces(array $conf = []): array { - $this->setConf($conf); - return [ - 'SQLite 3' => [ - 'interface' => (function() { - if (\JKingWeb\Arsse\Db\SQLite3\Driver::requirementsMet()) { - try { - $d = new \SQLite3(Arsse::$conf->dbSQLite3File); - } catch (\Exception $e) { - return; - } - $d->enableExceptions(true); - return $d; - } - })(), - 'statement' => \JKingWeb\Arsse\Db\SQLite3\Statement::class, - 'result' => \JKingWeb\Arsse\Db\SQLite3\Result::class, - 'stringOutput' => false, - ], - 'PDO SQLite 3' => [ - 'interface' => (function() { - if (\JKingWeb\Arsse\Db\SQLite3\PDODriver::requirementsMet()) { - try { - return new \PDO("sqlite:".Arsse::$conf->dbSQLite3File, "", "", [\PDO::ATTR_ERRMODE => \PDO::ERRMODE_EXCEPTION]); - } catch (\PDOException $e) { - return; - } - } - })(), - 'statement' => \JKingWeb\Arsse\Db\PDOStatement::class, - 'result' => \JKingWeb\Arsse\Db\PDOResult::class, - 'stringOutput' => true, - ], - 'PDO PostgreSQL' => [ - 'interface' => (function() { - if (\JKingWeb\Arsse\Db\PostgreSQL\PDODriver::requirementsMet()) { - $connString = \JKingWeb\Arsse\Db\PostgreSQL\Driver::makeConnectionString(true, Arsse::$conf->dbPostgreSQLUser, Arsse::$conf->dbPostgreSQLPass, Arsse::$conf->dbPostgreSQLDb, Arsse::$conf->dbPostgreSQLHost, Arsse::$conf->dbPostgreSQLPort, ""); - try { - $c = new \PDO("pgsql:".$connString, Arsse::$conf->dbPostgreSQLUser, Arsse::$conf->dbPostgreSQLPass, [\PDO::ATTR_ERRMODE => \PDO::ERRMODE_EXCEPTION]); - } catch (\PDOException $e) { - return; - } - foreach (\JKingWeb\Arsse\Db\PostgreSQL\PDODriver::makeSetupQueries(Arsse::$conf->dbPostgreSQLSchema) as $q) { - $c->exec($q); - } - return $c; - } - })(), - 'statement' => \JKingWeb\Arsse\Db\PDOStatement::class, - 'result' => \JKingWeb\Arsse\Db\PDOResult::class, - 'stringOutput' => true, - ], - ]; - } - - public function getDbDriver(string $name, array $conf = []) { - $this->setConf($conf); - switch ($name) { - case 'SQLite 3': - return (function() { - try { - return new \JKingWeb\Arsse\Db\SQLite3\Driver; - } catch (\Exception $e) { - return; - } - })(); - case 'PDO SQLite 3': - return (function() { - try { - return new \JKingWeb\Arsse\Db\SQLite3\PDODriver; - } catch (\Exception $e) { - return; - } - })(); - case 'PDO PostgreSQL': - return (function() { - try { - return new \JKingWeb\Arsse\Db\PostgreSQL\PDODriver; - } catch (\Exception $e) { - return; - } - })(); - default: - throw new \Exception("Invalid database driver name"); - } - } - - public function getDbInterface(string $name, array $conf = []) { - $this->setConf($conf); - switch ($name) { - case 'SQLite 3': - return (function() { - if (\JKingWeb\Arsse\Db\SQLite3\Driver::requirementsMet()) { - try { - $d = new \SQLite3(Arsse::$conf->dbSQLite3File); - } catch (\Exception $e) { - return; - } - $d->enableExceptions(true); - return $d; - } - })(); - case 'PDO SQLite 3': - return (function() { - if (\JKingWeb\Arsse\Db\SQLite3\PDODriver::requirementsMet()) { - try { - $d = new \PDO("sqlite:".Arsse::$conf->dbSQLite3File, "", "", [\PDO::ATTR_ERRMODE => \PDO::ERRMODE_EXCEPTION]); - $d->exec("PRAGMA busy_timeout=0"); - return $d; - } catch (\PDOException $e) { - return; - } - } - })(); - case 'PDO PostgreSQL': - return (function() { - if (\JKingWeb\Arsse\Db\PostgreSQL\PDODriver::requirementsMet()) { - $connString = \JKingWeb\Arsse\Db\PostgreSQL\Driver::makeConnectionString(true, Arsse::$conf->dbPostgreSQLUser, Arsse::$conf->dbPostgreSQLPass, Arsse::$conf->dbPostgreSQLDb, Arsse::$conf->dbPostgreSQLHost, Arsse::$conf->dbPostgreSQLPort, ""); - try { - $c = new \PDO("pgsql:".$connString, Arsse::$conf->dbPostgreSQLUser, Arsse::$conf->dbPostgreSQLPass, [\PDO::ATTR_ERRMODE => \PDO::ERRMODE_EXCEPTION]); - } catch (\PDOException $e) { - return; - } - foreach (\JKingWeb\Arsse\Db\PostgreSQL\PDODriver::makeSetupQueries(Arsse::$conf->dbPostgreSQLSchema) as $q) { - $c->exec($q); - } - return $c; - } - })(); - default: - throw new \Exception("Invalid database driver name"); - } - } } diff --git a/tests/lib/Database/Setup.php b/tests/lib/Database/Setup.php index 0a98edf0..88a01d11 100644 --- a/tests/lib/Database/Setup.php +++ b/tests/lib/Database/Setup.php @@ -22,7 +22,7 @@ trait Setup { public function setUp() { // establish a clean baseline $this->clearData(); - $this->setConf(); + self::setConf(); // configure and create the relevant database driver $this->setUpDriver(); // create the database interface with the suitable driver diff --git a/tests/lib/DatabaseInformation.php b/tests/lib/DatabaseInformation.php new file mode 100644 index 00000000..d22a6185 --- /dev/null +++ b/tests/lib/DatabaseInformation.php @@ -0,0 +1,111 @@ +name = $name; + foreach (self::$data[$name] as $key => $value) { + $this->$key = $value; + } + } + + public static function list(): array { + if (!isset(self::$data)) { + self::$data = self::getData(); + } + return array_keys(self::$data); + } + + public static function listPDO(): array { + if (!isset(self::$data)) { + self::$data = self::getData(); + } + return array_values(array_filter(array_keys(self::$data), function($k) { + return self::$data[$k]['pdo']; + })); + } + + protected static function getData() { + return [ + 'SQLite 3' => [ + 'pdo' => false, + 'backend' => "SQLite 3", + 'statementClass' => \JKingWeb\Arsse\Db\SQLite3\Statement::class, + 'resultClass' => \JKingWeb\Arsse\Db\SQLite3\Result::class, + 'driverClass' => \JKingWeb\Arsse\Db\SQLite3\Driver::class, + 'stringOutput' => false, + 'interfaceConstructor' => function() { + try { + $d = new \SQLite3(Arsse::$conf->dbSQLite3File); + } catch (\Throwable $e) { + return; + } + $d->enableExceptions(true); + return $d; + }, + + ], + 'PDO SQLite 3' => [ + 'pdo' => true, + 'backend' => "SQLite 3", + 'statementClass' => \JKingWeb\Arsse\Db\PDOStatement::class, + 'resultClass' => \JKingWeb\Arsse\Db\PDOResult::class, + 'driverClass' => \JKingWeb\Arsse\Db\SQLite3\PDODriver::class, + 'stringOutput' => true, + 'interfaceConstructor' => function() { + try { + $d = new \PDO("sqlite:".Arsse::$conf->dbSQLite3File, "", "", [\PDO::ATTR_ERRMODE => \PDO::ERRMODE_EXCEPTION]); + $d->exec("PRAGMA busy_timeout=0"); + return $d; + } catch (\Throwable $e) { + return; + } + }, + ], + 'PDO PostgreSQL' => [ + 'pdo' => true, + 'backend' => "PostgreSQL", + 'statementClass' => \JKingWeb\Arsse\Db\PDOStatement::class, + 'resultClass' => \JKingWeb\Arsse\Db\PDOResult::class, + 'driverClass' => \JKingWeb\Arsse\Db\PostgreSQL\PDODriver::class, + 'stringOutput' => true, + 'interfaceConstructor' => function() { + $connString = \JKingWeb\Arsse\Db\PostgreSQL\Driver::makeConnectionString(true, Arsse::$conf->dbPostgreSQLUser, Arsse::$conf->dbPostgreSQLPass, Arsse::$conf->dbPostgreSQLDb, Arsse::$conf->dbPostgreSQLHost, Arsse::$conf->dbPostgreSQLPort, ""); + try { + $d = new \PDO("pgsql:".$connString, Arsse::$conf->dbPostgreSQLUser, Arsse::$conf->dbPostgreSQLPass, [\PDO::ATTR_ERRMODE => \PDO::ERRMODE_EXCEPTION]); + } catch (\Throwable $e) { + return; + } + foreach (\JKingWeb\Arsse\Db\PostgreSQL\PDODriver::makeSetupQueries(Arsse::$conf->dbPostgreSQLSchema) as $q) { + $d->exec($q); + } + return $d; + }, + ], + ]; + } +} diff --git a/tests/phpunit.xml b/tests/phpunit.xml index faf634e7..e863737d 100644 --- a/tests/phpunit.xml +++ b/tests/phpunit.xml @@ -45,19 +45,23 @@ cases/Db/TestTransaction.php cases/Db/TestResultAggregate.php cases/Db/TestResultEmpty.php - cases/Db/TestResult.php - cases/Db/TestStatement.php + cases/Db/TestResultPDO.php + cases/Db/SQLite3/TestResult.php + cases/Db/SQLite3/TestStatement.php cases/Db/SQLite3/TestCreation.php cases/Db/SQLite3/TestDriver.php cases/Db/SQLite3/TestUpdate.php + cases/Db/SQLite3PDO/TestStatement.php cases/Db/SQLite3PDO/TestCreation.php cases/Db/SQLite3PDO/TestDriver.php cases/Db/SQLite3PDO/TestUpdate.php + cases/Db/PostgreSQL/TestStatement.php cases/Db/PostgreSQL/TestCreation.php - cases/Db/PostgreSQL/TestDriver.php + + cases/Db/SQLite3/Database/TestMiscellany.php