J. King
6 years ago
12 changed files with 1138 additions and 1 deletions
@ -0,0 +1,47 @@ |
|||
<?php |
|||
/** @license MIT |
|||
* Copyright 2017 J. King, Dustin Wilson et al. |
|||
* See LICENSE and AUTHORS files for details */ |
|||
|
|||
declare(strict_types=1); |
|||
namespace JKingWeb\Arsse\Db; |
|||
|
|||
trait PDODriver { |
|||
use PDOError; |
|||
|
|||
public function exec(string $query): bool { |
|||
try { |
|||
$this->db->exec($query); |
|||
return true; |
|||
} catch (\PDOException $e) { |
|||
list($excClass, $excMsg, $excData) = $this->exceptionBuild(); |
|||
throw new $excClass($excMsg, $excData); |
|||
} |
|||
} |
|||
|
|||
public function query(string $query): Result { |
|||
try { |
|||
$r = $this->db->query($query); |
|||
} catch (\PDOException $e) { |
|||
list($excClass, $excMsg, $excData) = $this->exceptionBuild(); |
|||
throw new $excClass($excMsg, $excData); |
|||
} |
|||
$changes = $r->rowCount(); |
|||
try { |
|||
$lastId = 0; |
|||
$lastId = $this->db->lastInsertId(); |
|||
} catch (\PDOException $e) { // @codeCoverageIgnore |
|||
} |
|||
return new PDOResult($r, [$changes, $lastId]); |
|||
} |
|||
|
|||
public function prepareArray(string $query, array $paramTypes): Statement { |
|||
try { |
|||
$s = $this->db->prepare($query); |
|||
} catch (\PDOException $e) { |
|||
list($excClass, $excMsg, $excData) = $this->exceptionBuild(); |
|||
throw new $excClass($excMsg, $excData); |
|||
} |
|||
return new PDOStatement($this->db, $s, $paramTypes); |
|||
} |
|||
} |
@ -0,0 +1,42 @@ |
|||
<?php |
|||
/** @license MIT |
|||
* Copyright 2017 J. King, Dustin Wilson et al. |
|||
* See LICENSE and AUTHORS files for details */ |
|||
|
|||
declare(strict_types=1); |
|||
namespace JKingWeb\Arsse\Db; |
|||
|
|||
trait PDOError { |
|||
public function exceptionBuild() { |
|||
if ($this instanceof Statement) { |
|||
$err = $this->st->errorInfo(); |
|||
} else { |
|||
$err = $this->db->errorInfo(); |
|||
} |
|||
switch ($err[0]) { |
|||
case "23000": |
|||
return [ExceptionInput::class, "constraintViolation", $err[2]]; |
|||
case "HY000": |
|||
// engine-specific errors |
|||
switch ($this->db->getAttribute(\PDO::ATTR_DRIVER_NAME)) { |
|||
case "sqlite": |
|||
switch ($err[1]) { |
|||
case \JKingWeb\Arsse\Db\SQLite3\Driver::SQLITE_BUSY: |
|||
return [ExceptionTimeout::class, 'general', $err[2]]; |
|||
case \JKingWeb\Arsse\Db\SQLite3\Driver::SQLITE_MISMATCH: |
|||
return [ExceptionInput::class, 'engineTypeViolation', $err[2]]; |
|||
default: |
|||
return [Exception::class, "engineErrorGeneral", $err[1]." - ".$err[2]]; |
|||
} |
|||
default: |
|||
return [Exception::class, "engineErrorGeneral", $err[2]]; // @codeCoverageIgnore |
|||
} |
|||
default: |
|||
return [Exception::class, "engineErrorGeneral", $err[0].": ".$err[2]]; // @codeCoverageIgnore |
|||
} |
|||
} |
|||
|
|||
public function getError(): string { |
|||
return (string) $this->db->errorInfo()[2]; |
|||
} |
|||
} |
@ -0,0 +1,49 @@ |
|||
<?php |
|||
/** @license MIT |
|||
* Copyright 2017 J. King, Dustin Wilson et al. |
|||
* See LICENSE and AUTHORS files for details */ |
|||
|
|||
declare(strict_types=1); |
|||
namespace JKingWeb\Arsse\Db; |
|||
|
|||
use JKingWeb\Arsse\Db\Exception; |
|||
|
|||
class PDOResult extends AbstractResult { |
|||
protected $set; |
|||
protected $cur = null; |
|||
protected $rows = 0; |
|||
protected $id = 0; |
|||
|
|||
// actual public methods |
|||
|
|||
public function changes() { |
|||
return $this->rows; |
|||
} |
|||
|
|||
public function lastId() { |
|||
return $this->id; |
|||
} |
|||
|
|||
// constructor/destructor |
|||
|
|||
public function __construct(\PDOStatement $result, array $changes = [0,0]) { |
|||
$this->set = $result; |
|||
$this->rows = (int) $changes[0]; |
|||
$this->id = (int) $changes[1]; |
|||
} |
|||
|
|||
public function __destruct() { |
|||
try { |
|||
$this->set->closeCursor(); |
|||
} catch (\PDOException $e) { // @codeCoverageIgnore |
|||
} |
|||
unset($this->set); |
|||
} |
|||
|
|||
// PHP iterator methods |
|||
|
|||
public function valid() { |
|||
$this->cur = $this->set->fetch(\PDO::FETCH_ASSOC); |
|||
return ($this->cur !== false); |
|||
} |
|||
} |
@ -0,0 +1,85 @@ |
|||
<?php |
|||
/** @license MIT |
|||
* Copyright 2017 J. King, Dustin Wilson et al. |
|||
* See LICENSE and AUTHORS files for details */ |
|||
|
|||
declare(strict_types=1); |
|||
namespace JKingWeb\Arsse\Db; |
|||
|
|||
class PDOStatement extends AbstractStatement { |
|||
use PDOError; |
|||
|
|||
const BINDINGS = [ |
|||
"null" => \PDO::PARAM_NULL, |
|||
"integer" => \PDO::PARAM_INT, |
|||
"float" => \PDO::PARAM_STR, |
|||
"date" => \PDO::PARAM_STR, |
|||
"time" => \PDO::PARAM_STR, |
|||
"datetime" => \PDO::PARAM_STR, |
|||
"binary" => \PDO::PARAM_LOB, |
|||
"string" => \PDO::PARAM_STR, |
|||
"boolean" => \PDO::PARAM_BOOL, |
|||
]; |
|||
|
|||
protected $st; |
|||
protected $db; |
|||
|
|||
public function __construct(\PDO $db, \PDOStatement $st, array $bindings = []) { |
|||
$this->db = $db; |
|||
$this->st = $st; |
|||
$this->rebindArray($bindings); |
|||
} |
|||
|
|||
public function __destruct() { |
|||
unset($this->st); |
|||
} |
|||
|
|||
public function runArray(array $values = []): \JKingWeb\Arsse\Db\Result { |
|||
$this->st->closeCursor(); |
|||
$this->bindValues($values); |
|||
try { |
|||
$this->st->execute(); |
|||
} catch (\PDOException $e) { |
|||
list($excClass, $excMsg, $excData) = $this->exceptionBuild(); |
|||
throw new $excClass($excMsg, $excData); |
|||
} |
|||
$changes = $this->st->rowCount(); |
|||
try { |
|||
$lastId = 0; |
|||
$lastId = $this->db->lastInsertId(); |
|||
} catch (\PDOException $e) { // @codeCoverageIgnore |
|||
} |
|||
return new PDOResult($this->st, [$changes, $lastId]); |
|||
} |
|||
|
|||
protected function bindValues(array $values, int $offset = 0): int { |
|||
$a = $offset; |
|||
foreach ($values as $value) { |
|||
if (is_array($value)) { |
|||
// recursively flatten any arrays, which may be provided for SET or IN() clauses |
|||
$a += $this->bindValues($value, $a); |
|||
} elseif (array_key_exists($a, $this->types)) { |
|||
// if the parameter type is something other than the known values, this is an error |
|||
assert(array_key_exists($this->types[$a], self::BINDINGS), new Exception("paramTypeUnknown", $this->types[$a])); |
|||
// if the parameter type is null or the value is null (and the type is nullable), just bind null |
|||
if ($this->types[$a]=="null" || ($this->isNullable[$a] && is_null($value))) { |
|||
$this->st->bindValue($a+1, null, \PDO::PARAM_NULL); |
|||
} else { |
|||
// otherwise cast the value to the right type and bind the result |
|||
$type = self::BINDINGS[$this->types[$a]]; |
|||
$value = $this->cast($value, $this->types[$a], $this->isNullable[$a]); |
|||
// re-adjust for null casts |
|||
if ($value===null) { |
|||
$type = \PDO::PARAM_NULL; |
|||
} |
|||
// perform binding |
|||
$this->st->bindValue($a+1, $value, $type); |
|||
} |
|||
$a++; |
|||
} else { |
|||
throw new Exception("paramTypeMissing", $a+1); |
|||
} |
|||
} |
|||
return $a - $offset; |
|||
} |
|||
} |
@ -0,0 +1,46 @@ |
|||
<?php |
|||
/** @license MIT |
|||
* Copyright 2017 J. King, Dustin Wilson et al. |
|||
* See LICENSE and AUTHORS files for details */ |
|||
|
|||
declare(strict_types=1); |
|||
namespace JKingWeb\Arsse\Db\SQLite3; |
|||
|
|||
use JKingWeb\Arsse\Arsse; |
|||
use JKingWeb\Arsse\Db\Exception; |
|||
use JKingWeb\Arsse\Db\ExceptionInput; |
|||
use JKingWeb\Arsse\Db\ExceptionTimeout; |
|||
|
|||
class PDODriver extends Driver { |
|||
use \JKingWeb\Arsse\Db\PDODriver; |
|||
|
|||
protected $db; |
|||
|
|||
public static function requirementsMet(): bool { |
|||
return class_exists("PDO") && in_array("sqlite", \PDO::getAvailableDrivers()); |
|||
} |
|||
|
|||
protected function makeConnection(string $file, string $key) { |
|||
$this->db = new \PDO("sqlite:".$file, "", "", [\PDO::ATTR_ERRMODE => \PDO::ERRMODE_EXCEPTION]); |
|||
} |
|||
|
|||
public function __destruct() { |
|||
unset($this->db); |
|||
} |
|||
|
|||
/** @codeCoverageIgnore */ |
|||
public static function create(): \JKingWeb\Arsse\Db\Driver { |
|||
if (self::requirementsMet()) { |
|||
return new self; |
|||
} elseif (Driver::requirementsMet()) { |
|||
return new Driver; |
|||
} else { |
|||
throw new Exception("extMissing", self::driverName()); |
|||
} |
|||
} |
|||
|
|||
|
|||
public static function driverName(): string { |
|||
return Arsse::$lang->msg("Driver.Db.SQLite3PDO.Name"); |
|||
} |
|||
} |
@ -0,0 +1,195 @@ |
|||
<?php |
|||
/** @license MIT |
|||
* Copyright 2017 J. King, Dustin Wilson et al. |
|||
* See LICENSE and AUTHORS files for details */ |
|||
|
|||
declare(strict_types=1); |
|||
namespace JKingWeb\Arsse; |
|||
|
|||
use JKingWeb\Arsse\Arsse; |
|||
use JKingWeb\Arsse\Db\SQLite3\PDODriver as Driver; |
|||
use org\bovigo\vfs\vfsStream; |
|||
use Phake; |
|||
|
|||
/** |
|||
* @covers \JKingWeb\Arsse\Db\SQLite3\PDODriver<extended> |
|||
* @covers \JKingWeb\Arsse\Db\PDODriver |
|||
* @covers \JKingWeb\Arsse\Db\PDOError */ |
|||
class TestDbDriverCreationSQLite3PDO extends Test\AbstractTest { |
|||
protected $data; |
|||
protected $drv; |
|||
protected $ch; |
|||
|
|||
public function setUp() { |
|||
if (!Driver::requirementsMet()) { |
|||
$this->markTestSkipped("PDO-SQLite extension not loaded"); |
|||
} |
|||
$this->clearData(); |
|||
// test files |
|||
$this->files = [ |
|||
// cannot create files |
|||
'Cmain' => [], |
|||
'Cshm' => [ |
|||
'arsse.db' => "", |
|||
'arsse.db-wal' => "", |
|||
], |
|||
'Cwal' => [ |
|||
'arsse.db' => "", |
|||
], |
|||
// cannot write to files |
|||
'Wmain' => [ |
|||
'arsse.db' => "", |
|||
'arsse.db-wal' => "", |
|||
'arsse.db-shm' => "", |
|||
], |
|||
'Wwal' => [ |
|||
'arsse.db' => "", |
|||
'arsse.db-wal' => "", |
|||
'arsse.db-shm' => "", |
|||
], |
|||
'Wshm' => [ |
|||
'arsse.db' => "", |
|||
'arsse.db-wal' => "", |
|||
'arsse.db-shm' => "", |
|||
], |
|||
// cannot read from files |
|||
'Rmain' => [ |
|||
'arsse.db' => "", |
|||
'arsse.db-wal' => "", |
|||
'arsse.db-shm' => "", |
|||
], |
|||
'Rwal' => [ |
|||
'arsse.db' => "", |
|||
'arsse.db-wal' => "", |
|||
'arsse.db-shm' => "", |
|||
], |
|||
'Rshm' => [ |
|||
'arsse.db' => "", |
|||
'arsse.db-wal' => "", |
|||
'arsse.db-shm' => "", |
|||
], |
|||
// can neither read from or write to files |
|||
'Amain' => [ |
|||
'arsse.db' => "", |
|||
'arsse.db-wal' => "", |
|||
'arsse.db-shm' => "", |
|||
], |
|||
'Awal' => [ |
|||
'arsse.db' => "", |
|||
'arsse.db-wal' => "", |
|||
'arsse.db-shm' => "", |
|||
], |
|||
'Ashm' => [ |
|||
'arsse.db' => "", |
|||
'arsse.db-wal' => "", |
|||
'arsse.db-shm' => "", |
|||
], |
|||
// non-filesystem errors |
|||
'corrupt' => [ |
|||
'arsse.db' => "", |
|||
'arsse.db-wal' => "", |
|||
'arsse.db-shm' => "", |
|||
], |
|||
]; |
|||
$vfs = vfsStream::setup("dbtest", 0777, $this->files); |
|||
$this->path = $path = $vfs->url()."/"; |
|||
// set up access blocks |
|||
chmod($path."Cmain", 0555); |
|||
chmod($path."Cwal", 0555); |
|||
chmod($path."Cshm", 0555); |
|||
chmod($path."Rmain/arsse.db", 0333); |
|||
chmod($path."Rwal/arsse.db-wal", 0333); |
|||
chmod($path."Rshm/arsse.db-shm", 0333); |
|||
chmod($path."Wmain/arsse.db", 0555); |
|||
chmod($path."Wwal/arsse.db-wal", 0555); |
|||
chmod($path."Wshm/arsse.db-shm", 0555); |
|||
chmod($path."Amain/arsse.db", 0111); |
|||
chmod($path."Awal/arsse.db-wal", 0111); |
|||
chmod($path."Ashm/arsse.db-shm", 0111); |
|||
// set up configuration |
|||
Arsse::$conf = new Conf(); |
|||
Arsse::$conf->dbSQLite3File = ":memory:"; |
|||
} |
|||
|
|||
public function tearDown() { |
|||
$this->clearData(); |
|||
} |
|||
|
|||
public function testFailToCreateDatabase() { |
|||
Arsse::$conf->dbSQLite3File = $this->path."Cmain/arsse.db"; |
|||
$this->assertException("fileUncreatable", "Db"); |
|||
new Driver; |
|||
} |
|||
|
|||
public function testFailToCreateJournal() { |
|||
Arsse::$conf->dbSQLite3File = $this->path."Cwal/arsse.db"; |
|||
$this->assertException("fileUncreatable", "Db"); |
|||
new Driver; |
|||
} |
|||
|
|||
public function testFailToCreateSharedMmeory() { |
|||
Arsse::$conf->dbSQLite3File = $this->path."Cshm/arsse.db"; |
|||
$this->assertException("fileUncreatable", "Db"); |
|||
new Driver; |
|||
} |
|||
|
|||
public function testFailToReadDatabase() { |
|||
Arsse::$conf->dbSQLite3File = $this->path."Rmain/arsse.db"; |
|||
$this->assertException("fileUnreadable", "Db"); |
|||
new Driver; |
|||
} |
|||
|
|||
public function testFailToReadJournal() { |
|||
Arsse::$conf->dbSQLite3File = $this->path."Rwal/arsse.db"; |
|||
$this->assertException("fileUnreadable", "Db"); |
|||
new Driver; |
|||
} |
|||
|
|||
public function testFailToReadSharedMmeory() { |
|||
Arsse::$conf->dbSQLite3File = $this->path."Rshm/arsse.db"; |
|||
$this->assertException("fileUnreadable", "Db"); |
|||
new Driver; |
|||
} |
|||
|
|||
public function testFailToWriteToDatabase() { |
|||
Arsse::$conf->dbSQLite3File = $this->path."Wmain/arsse.db"; |
|||
$this->assertException("fileUnwritable", "Db"); |
|||
new Driver; |
|||
} |
|||
|
|||
public function testFailToWriteToJournal() { |
|||
Arsse::$conf->dbSQLite3File = $this->path."Wwal/arsse.db"; |
|||
$this->assertException("fileUnwritable", "Db"); |
|||
new Driver; |
|||
} |
|||
|
|||
public function testFailToWriteToSharedMmeory() { |
|||
Arsse::$conf->dbSQLite3File = $this->path."Wshm/arsse.db"; |
|||
$this->assertException("fileUnwritable", "Db"); |
|||
new Driver; |
|||
} |
|||
|
|||
public function testFailToAccessDatabase() { |
|||
Arsse::$conf->dbSQLite3File = $this->path."Amain/arsse.db"; |
|||
$this->assertException("fileUnusable", "Db"); |
|||
new Driver; |
|||
} |
|||
|
|||
public function testFailToAccessJournal() { |
|||
Arsse::$conf->dbSQLite3File = $this->path."Awal/arsse.db"; |
|||
$this->assertException("fileUnusable", "Db"); |
|||
new Driver; |
|||
} |
|||
|
|||
public function testFailToAccessSharedMmeory() { |
|||
Arsse::$conf->dbSQLite3File = $this->path."Ashm/arsse.db"; |
|||
$this->assertException("fileUnusable", "Db"); |
|||
new Driver; |
|||
} |
|||
|
|||
public function testAssumeDatabaseCorruption() { |
|||
Arsse::$conf->dbSQLite3File = $this->path."corrupt/arsse.db"; |
|||
$this->assertException("fileCorrupt", "Db"); |
|||
new Driver; |
|||
} |
|||
} |
@ -0,0 +1,337 @@ |
|||
<?php |
|||
/** @license MIT |
|||
* Copyright 2017 J. King, Dustin Wilson et al. |
|||
* See LICENSE and AUTHORS files for details */ |
|||
|
|||
declare(strict_types=1); |
|||
namespace JKingWeb\Arsse; |
|||
|
|||
/** |
|||
* @covers \JKingWeb\Arsse\Db\SQLite3\PDODriver<extended> |
|||
* @covers \JKingWeb\Arsse\Db\PDODriver |
|||
* @covers \JKingWeb\Arsse\Db\PDOError */ |
|||
class TestDbDriverSQLite3PDO extends Test\AbstractTest { |
|||
protected $data; |
|||
protected $drv; |
|||
protected $ch; |
|||
|
|||
public function setUp() { |
|||
if (!Db\SQLite3\PDODriver::requirementsMet()) { |
|||
$this->markTestSkipped("PDO-SQLite extension not loaded"); |
|||
} |
|||
$this->clearData(); |
|||
$conf = new Conf(); |
|||
Arsse::$conf = $conf; |
|||
$conf->dbDriver = Db\SQLite3\PDODriver::class; |
|||
$conf->dbSQLite3Timeout = 0; |
|||
$conf->dbSQLite3File = tempnam(sys_get_temp_dir(), 'ook'); |
|||
$this->drv = new Db\SQLite3\PDODriver(); |
|||
$this->ch = new \PDO("sqlite:".Arsse::$conf->dbSQLite3File, "", "", [\PDO::ATTR_ERRMODE => \PDO::ERRMODE_EXCEPTION]); |
|||
} |
|||
|
|||
public function tearDown() { |
|||
unset($this->drv); |
|||
unset($this->ch); |
|||
if (isset(Arsse::$conf)) { |
|||
unlink(Arsse::$conf->dbSQLite3File); |
|||
} |
|||
$this->clearData(); |
|||
} |
|||
|
|||
public function testFetchDriverName() { |
|||
$class = Arsse::$conf->dbDriver; |
|||
$this->assertTrue(strlen($class::driverName()) > 0); |
|||
} |
|||
|
|||
public function testCheckCharacterSetAcceptability() { |
|||
$this->assertTrue($this->drv->charsetAcceptable()); |
|||
} |
|||
|
|||
public function testExecAValidStatement() { |
|||
$this->assertTrue($this->drv->exec("CREATE TABLE test(id integer primary key)")); |
|||
} |
|||
|
|||
public function testExecAnInvalidStatement() { |
|||
$this->assertException("engineErrorGeneral", "Db"); |
|||
$this->drv->exec("And the meek shall inherit the earth..."); |
|||
} |
|||
|
|||
public function testExecMultipleStatements() { |
|||
$this->assertTrue($this->drv->exec("CREATE TABLE test(id integer primary key); INSERT INTO test(id) values(2112)")); |
|||
$this->assertEquals(2112, $this->ch->query("SELECT id from test")->fetchColumn()); |
|||
} |
|||
|
|||
public function testExecTimeout() { |
|||
$this->ch->exec("BEGIN EXCLUSIVE TRANSACTION"); |
|||
$this->assertException("general", "Db", "ExceptionTimeout"); |
|||
$this->drv->exec("CREATE TABLE test(id integer primary key)"); |
|||
} |
|||
|
|||
public function testExecConstraintViolation() { |
|||
$this->drv->exec("CREATE TABLE test(id integer not null)"); |
|||
$this->assertException("constraintViolation", "Db", "ExceptionInput"); |
|||
$this->drv->exec("INSERT INTO test(id) values(null)"); |
|||
} |
|||
|
|||
public function testExecTypeViolation() { |
|||
$this->drv->exec("CREATE TABLE test(id integer primary key)"); |
|||
$this->assertException("typeViolation", "Db", "ExceptionInput"); |
|||
$this->drv->exec("INSERT INTO test(id) values('ook')"); |
|||
} |
|||
|
|||
public function testMakeAValidQuery() { |
|||
$this->assertInstanceOf(Db\Result::class, $this->drv->query("SELECT 1")); |
|||
} |
|||
|
|||
public function testMakeAnInvalidQuery() { |
|||
$this->assertException("engineErrorGeneral", "Db"); |
|||
$this->drv->query("Apollo was astonished; Dionysus thought me mad"); |
|||
} |
|||
|
|||
public function testQueryTimeout() { |
|||
$this->ch->exec("BEGIN EXCLUSIVE TRANSACTION"); |
|||
$this->assertException("general", "Db", "ExceptionTimeout"); |
|||
$this->drv->query("CREATE TABLE test(id integer primary key)"); |
|||
} |
|||
|
|||
public function testQueryConstraintViolation() { |
|||
$this->drv->exec("CREATE TABLE test(id integer not null)"); |
|||
$this->assertException("constraintViolation", "Db", "ExceptionInput"); |
|||
$this->drv->query("INSERT INTO test(id) values(null)"); |
|||
} |
|||
|
|||
public function testQueryTypeViolation() { |
|||
$this->drv->exec("CREATE TABLE test(id integer primary key)"); |
|||
$this->assertException("typeViolation", "Db", "ExceptionInput"); |
|||
$this->drv->query("INSERT INTO test(id) values('ook')"); |
|||
} |
|||
|
|||
public function testPrepareAValidQuery() { |
|||
$s = $this->drv->prepare("SELECT ?, ?", "int", "int"); |
|||
$this->assertInstanceOf(Db\Statement::class, $s); |
|||
} |
|||
|
|||
public function testPrepareAnInvalidQuery() { |
|||
$this->assertException("engineErrorGeneral", "Db"); |
|||
$s = $this->drv->prepare("This is an invalid query", "int", "int"); |
|||
} |
|||
|
|||
public function testCreateASavepoint() { |
|||
$this->assertEquals(1, $this->drv->savepointCreate()); |
|||
$this->assertEquals(2, $this->drv->savepointCreate()); |
|||
$this->assertEquals(3, $this->drv->savepointCreate()); |
|||
} |
|||
|
|||
public function testReleaseASavepoint() { |
|||
$this->assertEquals(1, $this->drv->savepointCreate()); |
|||
$this->assertEquals(true, $this->drv->savepointRelease()); |
|||
$this->assertException("savepointInvalid", "Db"); |
|||
$this->drv->savepointRelease(); |
|||
} |
|||
|
|||
public function testUndoASavepoint() { |
|||
$this->assertEquals(1, $this->drv->savepointCreate()); |
|||
$this->assertEquals(true, $this->drv->savepointUndo()); |
|||
$this->assertException("savepointInvalid", "Db"); |
|||
$this->drv->savepointUndo(); |
|||
} |
|||
|
|||
public function testManipulateSavepoints() { |
|||
$this->assertEquals(1, $this->drv->savepointCreate()); |
|||
$this->assertEquals(2, $this->drv->savepointCreate()); |
|||
$this->assertEquals(3, $this->drv->savepointCreate()); |
|||
$this->assertEquals(4, $this->drv->savepointCreate()); |
|||
$this->assertEquals(5, $this->drv->savepointCreate()); |
|||
$this->assertTrue($this->drv->savepointUndo(3)); |
|||
$this->assertFalse($this->drv->savepointRelease(4)); |
|||
$this->assertEquals(6, $this->drv->savepointCreate()); |
|||
$this->assertFalse($this->drv->savepointRelease(5)); |
|||
$this->assertTrue($this->drv->savepointRelease(6)); |
|||
$this->assertEquals(3, $this->drv->savepointCreate()); |
|||
$this->assertTrue($this->drv->savepointRelease(2)); |
|||
$this->assertException("savepointStale", "Db"); |
|||
$this->drv->savepointRelease(2); |
|||
} |
|||
|
|||
public function testManipulateSavepointsSomeMore() { |
|||
$this->assertEquals(1, $this->drv->savepointCreate()); |
|||
$this->assertEquals(2, $this->drv->savepointCreate()); |
|||
$this->assertEquals(3, $this->drv->savepointCreate()); |
|||
$this->assertEquals(4, $this->drv->savepointCreate()); |
|||
$this->assertTrue($this->drv->savepointRelease(2)); |
|||
$this->assertFalse($this->drv->savepointUndo(3)); |
|||
$this->assertException("savepointStale", "Db"); |
|||
$this->drv->savepointUndo(2); |
|||
} |
|||
|
|||
public function testBeginATransaction() { |
|||
$select = "SELECT count(*) FROM test"; |
|||
$insert = "INSERT INTO test(id) values(null)"; |
|||
$this->drv->exec("CREATE TABLE test(id integer primary key)"); |
|||
$tr = $this->drv->begin(); |
|||
$this->drv->query($insert); |
|||
$this->assertEquals(1, $this->drv->query($select)->getValue()); |
|||
$this->assertEquals(0, $this->ch->query($select)->fetchColumn()); |
|||
$this->drv->query($insert); |
|||
$this->assertEquals(2, $this->drv->query($select)->getValue()); |
|||
$this->assertEquals(0, $this->ch->query($select)->fetchColumn()); |
|||
} |
|||
|
|||
public function testCommitATransaction() { |
|||
$select = "SELECT count(*) FROM test"; |
|||
$insert = "INSERT INTO test(id) values(null)"; |
|||
$this->drv->exec("CREATE TABLE test(id integer primary key)"); |
|||
$tr = $this->drv->begin(); |
|||
$this->drv->query($insert); |
|||
$this->assertEquals(1, $this->drv->query($select)->getValue()); |
|||
$this->assertEquals(0, $this->ch->query($select)->fetchColumn()); |
|||
$tr->commit(); |
|||
$this->assertEquals(1, $this->drv->query($select)->getValue()); |
|||
$this->assertEquals(1, $this->ch->query($select)->fetchColumn()); |
|||
} |
|||
|
|||
public function testRollbackATransaction() { |
|||
$select = "SELECT count(*) FROM test"; |
|||
$insert = "INSERT INTO test(id) values(null)"; |
|||
$this->drv->exec("CREATE TABLE test(id integer primary key)"); |
|||
$tr = $this->drv->begin(); |
|||
$this->drv->query($insert); |
|||
$this->assertEquals(1, $this->drv->query($select)->getValue()); |
|||
$this->assertEquals(0, $this->ch->query($select)->fetchColumn()); |
|||
$tr->rollback(); |
|||
$this->assertEquals(0, $this->drv->query($select)->getValue()); |
|||
$this->assertEquals(0, $this->ch->query($select)->fetchColumn()); |
|||
} |
|||
|
|||
public function testBeginChainedTransactions() { |
|||
$select = "SELECT count(*) FROM test"; |
|||
$insert = "INSERT INTO test(id) values(null)"; |
|||
$this->drv->exec("CREATE TABLE test(id integer primary key)"); |
|||
$tr1 = $this->drv->begin(); |
|||
$this->drv->query($insert); |
|||
$this->assertEquals(1, $this->drv->query($select)->getValue()); |
|||
$this->assertEquals(0, $this->ch->query($select)->fetchColumn()); |
|||
$tr2 = $this->drv->begin(); |
|||
$this->drv->query($insert); |
|||
$this->assertEquals(2, $this->drv->query($select)->getValue()); |
|||
$this->assertEquals(0, $this->ch->query($select)->fetchColumn()); |
|||
} |
|||
|
|||
public function testCommitChainedTransactions() { |
|||
$select = "SELECT count(*) FROM test"; |
|||
$insert = "INSERT INTO test(id) values(null)"; |
|||
$this->drv->exec("CREATE TABLE test(id integer primary key)"); |
|||
$tr1 = $this->drv->begin(); |
|||
$this->drv->query($insert); |
|||
$this->assertEquals(1, $this->drv->query($select)->getValue()); |
|||
$this->assertEquals(0, $this->ch->query($select)->fetchColumn()); |
|||
$tr2 = $this->drv->begin(); |
|||
$this->drv->query($insert); |
|||
$this->assertEquals(2, $this->drv->query($select)->getValue()); |
|||
$this->assertEquals(0, $this->ch->query($select)->fetchColumn()); |
|||
$tr2->commit(); |
|||
$this->assertEquals(0, $this->ch->query($select)->fetchColumn()); |
|||
$tr1->commit(); |
|||
$this->assertEquals(2, $this->ch->query($select)->fetchColumn()); |
|||
} |
|||
|
|||
public function testCommitChainedTransactionsOutOfOrder() { |
|||
$select = "SELECT count(*) FROM test"; |
|||
$insert = "INSERT INTO test(id) values(null)"; |
|||
$this->drv->exec("CREATE TABLE test(id integer primary key)"); |
|||
$tr1 = $this->drv->begin(); |
|||
$this->drv->query($insert); |
|||
$this->assertEquals(1, $this->drv->query($select)->getValue()); |
|||
$this->assertEquals(0, $this->ch->query($select)->fetchColumn()); |
|||
$tr2 = $this->drv->begin(); |
|||
$this->drv->query($insert); |
|||
$this->assertEquals(2, $this->drv->query($select)->getValue()); |
|||
$this->assertEquals(0, $this->ch->query($select)->fetchColumn()); |
|||
$tr1->commit(); |
|||
$this->assertEquals(2, $this->ch->query($select)->fetchColumn()); |
|||
$tr2->commit(); |
|||
} |
|||
|
|||
public function testRollbackChainedTransactions() { |
|||
$select = "SELECT count(*) FROM test"; |
|||
$insert = "INSERT INTO test(id) values(null)"; |
|||
$this->drv->exec("CREATE TABLE test(id integer primary key)"); |
|||
$tr1 = $this->drv->begin(); |
|||
$this->drv->query($insert); |
|||
$this->assertEquals(1, $this->drv->query($select)->getValue()); |
|||
$this->assertEquals(0, $this->ch->query($select)->fetchColumn()); |
|||
$tr2 = $this->drv->begin(); |
|||
$this->drv->query($insert); |
|||
$this->assertEquals(2, $this->drv->query($select)->getValue()); |
|||
$this->assertEquals(0, $this->ch->query($select)->fetchColumn()); |
|||
$tr2->rollback(); |
|||
$this->assertEquals(1, $this->drv->query($select)->getValue()); |
|||
$this->assertEquals(0, $this->ch->query($select)->fetchColumn()); |
|||
$tr1->rollback(); |
|||
$this->assertEquals(0, $this->drv->query($select)->getValue()); |
|||
$this->assertEquals(0, $this->ch->query($select)->fetchColumn()); |
|||
} |
|||
|
|||
public function testRollbackChainedTransactionsOutOfOrder() { |
|||
$select = "SELECT count(*) FROM test"; |
|||
$insert = "INSERT INTO test(id) values(null)"; |
|||
$this->drv->exec("CREATE TABLE test(id integer primary key)"); |
|||
$tr1 = $this->drv->begin(); |
|||
$this->drv->query($insert); |
|||
$this->assertEquals(1, $this->drv->query($select)->getValue()); |
|||
$this->assertEquals(0, $this->ch->query($select)->fetchColumn()); |
|||
$tr2 = $this->drv->begin(); |
|||
$this->drv->query($insert); |
|||
$this->assertEquals(2, $this->drv->query($select)->getValue()); |
|||
$this->assertEquals(0, $this->ch->query($select)->fetchColumn()); |
|||
$tr1->rollback(); |
|||
$this->assertEquals(0, $this->drv->query($select)->getValue()); |
|||
$this->assertEquals(0, $this->ch->query($select)->fetchColumn()); |
|||
$tr2->rollback(); |
|||
$this->assertEquals(0, $this->drv->query($select)->getValue()); |
|||
$this->assertEquals(0, $this->ch->query($select)->fetchColumn()); |
|||
} |
|||
|
|||
public function testPartiallyRollbackChainedTransactions() { |
|||
$select = "SELECT count(*) FROM test"; |
|||
$insert = "INSERT INTO test(id) values(null)"; |
|||
$this->drv->exec("CREATE TABLE test(id integer primary key)"); |
|||
$tr1 = $this->drv->begin(); |
|||
$this->drv->query($insert); |
|||
$this->assertEquals(1, $this->drv->query($select)->getValue()); |
|||
$this->assertEquals(0, $this->ch->query($select)->fetchColumn()); |
|||
$tr2 = $this->drv->begin(); |
|||
$this->drv->query($insert); |
|||
$this->assertEquals(2, $this->drv->query($select)->getValue()); |
|||
$this->assertEquals(0, $this->ch->query($select)->fetchColumn()); |
|||
$tr2->rollback(); |
|||
$this->assertEquals(1, $this->drv->query($select)->getValue()); |
|||
$this->assertEquals(0, $this->ch->query($select)->fetchColumn()); |
|||
$tr1->commit(); |
|||
$this->assertEquals(1, $this->drv->query($select)->getValue()); |
|||
$this->assertEquals(1, $this->ch->query($select)->fetchColumn()); |
|||
} |
|||
|
|||
public function testFetchSchemaVersion() { |
|||
$this->assertSame(0, $this->drv->schemaVersion()); |
|||
$this->drv->exec("PRAGMA user_version=1"); |
|||
$this->assertSame(1, $this->drv->schemaVersion()); |
|||
$this->drv->exec("PRAGMA user_version=2"); |
|||
$this->assertSame(2, $this->drv->schemaVersion()); |
|||
} |
|||
|
|||
public function testLockTheDatabase() { |
|||
$this->drv->savepointCreate(true); |
|||
$this->ch->exec("PRAGMA busy_timeout = 0"); |
|||
$this->assertException(); |
|||
$this->ch->exec("CREATE TABLE test(id integer primary key)"); |
|||
} |
|||
|
|||
public function testUnlockTheDatabase() { |
|||
$this->drv->savepointCreate(true); |
|||
$this->drv->savepointRelease(); |
|||
$this->drv->savepointCreate(true); |
|||
$this->drv->savepointUndo(); |
|||
$this->assertSame(0, $this->ch->exec("CREATE TABLE test(id integer primary key)")); |
|||
} |
|||
} |
@ -0,0 +1,104 @@ |
|||
<?php |
|||
/** @license MIT |
|||
* Copyright 2017 J. King, Dustin Wilson et al. |
|||
* See LICENSE and AUTHORS files for details */ |
|||
|
|||
declare(strict_types=1); |
|||
namespace JKingWeb\Arsse; |
|||
|
|||
/** @covers \JKingWeb\Arsse\Db\PDOResult<extended> */ |
|||
class TestDbResultSQLite3PDO extends Test\AbstractTest { |
|||
protected $c; |
|||
|
|||
public function setUp() { |
|||
$this->clearData(); |
|||
if (!Db\SQLite3\PDODriver::requirementsMet()) { |
|||
$this->markTestSkipped("PDO-SQLite extension not loaded"); |
|||
} |
|||
$c = new \PDO("sqlite::memory:", "", "", [\PDO::ATTR_ERRMODE => \PDO::ERRMODE_EXCEPTION]); |
|||
$this->c = $c; |
|||
} |
|||
|
|||
public function tearDown() { |
|||
unset($this->c); |
|||
$this->clearData(); |
|||
} |
|||
|
|||
public function testConstructResult() { |
|||
$set = $this->c->query("SELECT 1"); |
|||
$this->assertInstanceOf(Db\Result::class, new Db\PDOResult($set)); |
|||
} |
|||
|
|||
public function testGetChangeCountAndLastInsertId() { |
|||
$this->c->query("CREATE TABLE test(col)"); |
|||
$set = $this->c->query("INSERT INTO test(col) values(1)"); |
|||
$rows = $set->rowCount(); |
|||
$id = $this->c->lastInsertID(); |
|||
$r = new Db\PDOResult($set, [$rows,$id]); |
|||
$this->assertSame((int) $rows, $r->changes()); |
|||
$this->assertSame((int) $id, $r->lastId()); |
|||
} |
|||
|
|||
public function testIterateOverResults() { |
|||
$set = $this->c->query("SELECT 1 as col union select 2 as col union select 3 as col"); |
|||
$rows = []; |
|||
foreach (new Db\PDOResult($set) as $index => $row) { |
|||
$rows[$index] = $row['col']; |
|||
} |
|||
$this->assertSame([0 => "1", 1 => "2", 2 => "3"], $rows); |
|||
} |
|||
|
|||
public function testIterateOverResultsTwice() { |
|||
$set = $this->c->query("SELECT 1 as col union select 2 as col union select 3 as col"); |
|||
$rows = []; |
|||
$test = new Db\PDOResult($set); |
|||
foreach ($test as $row) { |
|||
$rows[] = $row['col']; |
|||
} |
|||
$this->assertSame(["1","2","3"], $rows); |
|||
$this->assertException("resultReused", "Db"); |
|||
foreach ($test as $row) { |
|||
$rows[] = $row['col']; |
|||
} |
|||
} |
|||
|
|||
public function testGetSingleValues() { |
|||
$set = $this->c->query("SELECT 1867 as year union select 1970 as year union select 2112 as year"); |
|||
$test = new Db\PDOResult($set); |
|||
$this->assertEquals(1867, $test->getValue()); |
|||
$this->assertEquals(1970, $test->getValue()); |
|||
$this->assertEquals(2112, $test->getValue()); |
|||
$this->assertSame(null, $test->getValue()); |
|||
} |
|||
|
|||
public function testGetFirstValuesOnly() { |
|||
$set = $this->c->query("SELECT 1867 as year, 19 as century union select 1970 as year, 20 as century union select 2112 as year, 22 as century"); |
|||
$test = new Db\PDOResult($set); |
|||
$this->assertEquals(1867, $test->getValue()); |
|||
$this->assertEquals(1970, $test->getValue()); |
|||
$this->assertEquals(2112, $test->getValue()); |
|||
$this->assertSame(null, $test->getValue()); |
|||
} |
|||
|
|||
public function testGetRows() { |
|||
$set = $this->c->query("SELECT '2112' as album, '2112' as track union select 'Clockwork Angels' as album, 'The Wreckers' as track"); |
|||
$rows = [ |
|||
['album' => '2112', 'track' => '2112'], |
|||
['album' => 'Clockwork Angels', 'track' => 'The Wreckers'], |
|||
]; |
|||
$test = new Db\PDOResult($set); |
|||
$this->assertEquals($rows[0], $test->getRow()); |
|||
$this->assertEquals($rows[1], $test->getRow()); |
|||
$this->assertSame(null, $test->getRow()); |
|||
} |
|||
|
|||
public function testGetAllRows() { |
|||
$set = $this->c->query("SELECT '2112' as album, '2112' as track union select 'Clockwork Angels' as album, 'The Wreckers' as track"); |
|||
$rows = [ |
|||
['album' => '2112', 'track' => '2112'], |
|||
['album' => 'Clockwork Angels', 'track' => 'The Wreckers'], |
|||
]; |
|||
$test = new Db\PDOResult($set); |
|||
$this->assertEquals($rows, $test->getAll()); |
|||
} |
|||
} |
@ -0,0 +1,105 @@ |
|||
<?php |
|||
/** @license MIT |
|||
* Copyright 2017 J. King, Dustin Wilson et al. |
|||
* See LICENSE and AUTHORS files for details */ |
|||
|
|||
declare(strict_types=1); |
|||
namespace JKingWeb\Arsse; |
|||
|
|||
use JKingWeb\Arsse\Db\Statement; |
|||
|
|||
/** |
|||
* @covers \JKingWeb\Arsse\Db\PDOStatement<extended> |
|||
* @covers \JKingWeb\Arsse\Db\PDOError */ |
|||
class TestDbStatementSQLite3PDO extends Test\AbstractTest { |
|||
|
|||
protected $c; |
|||
protected static $imp = Db\PDOStatement::class; |
|||
|
|||
public function setUp() { |
|||
$this->clearData(); |
|||
if (!Db\SQLite3\PDODriver::requirementsMet()) { |
|||
$this->markTestSkipped("PDO-SQLite extension not loaded"); |
|||
} |
|||
$c = new \PDO("sqlite::memory:", "", "", [\PDO::ATTR_ERRMODE => \PDO::ERRMODE_EXCEPTION]); |
|||
$this->c = $c; |
|||
} |
|||
|
|||
public function tearDown() { |
|||
unset($this->c); |
|||
$this->clearData(); |
|||
} |
|||
|
|||
protected function checkBinding($input, array $expectations, bool $strict = false) { |
|||
$nativeStatement = $this->c->prepare("SELECT ? as value"); |
|||
$s = new self::$imp($this->c, $nativeStatement); |
|||
$types = array_unique(Statement::TYPES); |
|||
foreach ($types as $type) { |
|||
$s->rebindArray([$strict ? "strict $type" : $type]); |
|||
$val = $s->runArray([$input])->getRow()['value']; |
|||
$this->assertSame($expectations[$type], $val, "Binding from type $type failed comparison."); |
|||
$s->rebind(...[$strict ? "strict $type" : $type]); |
|||
$val = $s->run(...[$input])->getRow()['value']; |
|||
$this->assertSame($expectations[$type], $val, "Binding from type $type failed comparison."); |
|||
} |
|||
} |
|||
|
|||
public function testConstructStatement() { |
|||
$nativeStatement = $this->c->prepare("SELECT ? as value"); |
|||
$this->assertInstanceOf(Statement::class, new Db\PDOStatement($this->c, $nativeStatement)); |
|||
} |
|||
|
|||
public function testBindMissingValue() { |
|||
$nativeStatement = $this->c->prepare("SELECT ? as value"); |
|||
$s = new self::$imp($this->c, $nativeStatement); |
|||
$val = $s->runArray()->getRow()['value']; |
|||
$this->assertSame(null, $val); |
|||
} |
|||
|
|||
public function testBindMultipleValues() { |
|||
$exp = [ |
|||
'one' => "1", |
|||
'two' => "2", |
|||
]; |
|||
$nativeStatement = $this->c->prepare("SELECT ? as one, ? as two"); |
|||
$s = new self::$imp($this->c, $nativeStatement, ["int", "int"]); |
|||
$val = $s->runArray([1,2])->getRow(); |
|||
$this->assertSame($exp, $val); |
|||
} |
|||
|
|||
public function testBindRecursively() { |
|||
$exp = [ |
|||
'one' => "1", |
|||
'two' => "2", |
|||
'three' => "3", |
|||
'four' => "4", |
|||
]; |
|||
$nativeStatement = $this->c->prepare("SELECT ? as one, ? as two, ? as three, ? as four"); |
|||
$s = new self::$imp($this->c, $nativeStatement, ["int", ["int", "int"], "int"]); |
|||
$val = $s->runArray([1, [2, 3], 4])->getRow(); |
|||
$this->assertSame($exp, $val); |
|||
} |
|||
|
|||
public function testBindWithoutType() { |
|||
$nativeStatement = $this->c->prepare("SELECT ? as value"); |
|||
$this->assertException("paramTypeMissing", "Db"); |
|||
$s = new self::$imp($this->c, $nativeStatement, []); |
|||
$s->runArray([1]); |
|||
} |
|||
|
|||
public function testViolateConstraint() { |
|||
$this->c->exec("CREATE TABLE test(id integer not null)"); |
|||
$nativeStatement = $this->c->prepare("INSERT INTO test(id) values(?)"); |
|||
$s = new self::$imp($this->c, $nativeStatement, ["int"]); |
|||
$this->assertException("constraintViolation", "Db", "ExceptionInput"); |
|||
$s->runArray([null]); |
|||
} |
|||
|
|||
public function testMismatchTypes() { |
|||
$this->c->exec("CREATE TABLE test(id integer primary key)"); |
|||
$nativeStatement = $this->c->prepare("INSERT INTO test(id) values(?)"); |
|||
$s = new self::$imp($this->c, $nativeStatement, ["str"]); |
|||
$this->assertException("typeViolation", "Db", "ExceptionInput"); |
|||
$s->runArray(['ook']); |
|||
} |
|||
} |
@ -0,0 +1,120 @@ |
|||
<?php |
|||
/** @license MIT |
|||
* Copyright 2017 J. King, Dustin Wilson et al. |
|||
* See LICENSE and AUTHORS files for details */ |
|||
|
|||
declare(strict_types=1); |
|||
namespace JKingWeb\Arsse; |
|||
|
|||
use org\bovigo\vfs\vfsStream; |
|||
|
|||
/** |
|||
* @covers \JKingWeb\Arsse\Db\SQLite3\PDODriver<extended> |
|||
* @covers \JKingWeb\Arsse\Db\PDOError */ |
|||
class TestDbUpdateSQLite3PDO extends Test\AbstractTest { |
|||
protected $data; |
|||
protected $drv; |
|||
protected $vfs; |
|||
protected $base; |
|||
|
|||
const MINIMAL1 = "create table arsse_meta(key text primary key not null, value text); pragma user_version=1"; |
|||
const MINIMAL2 = "pragma user_version=2"; |
|||
|
|||
public function setUp(Conf $conf = null) { |
|||
if (!Db\SQLite3\PDODriver::requirementsMet()) { |
|||
$this->markTestSkipped("PDO-SQLite extension not loaded"); |
|||
} |
|||
$this->clearData(); |
|||
$this->vfs = vfsStream::setup("schemata", null, ['SQLite3' => []]); |
|||
if (!$conf) { |
|||
$conf = new Conf(); |
|||
} |
|||
$conf->dbDriver = Db\SQLite3\PDODriver::class; |
|||
$conf->dbSQLite3File = ":memory:"; |
|||
Arsse::$conf = $conf; |
|||
$this->base = $this->vfs->url(); |
|||
$this->path = $this->base."/SQLite3/"; |
|||
$this->drv = new Db\SQLite3\PDODriver(); |
|||
} |
|||
|
|||
public function tearDown() { |
|||
unset($this->drv); |
|||
unset($this->data); |
|||
unset($this->vfs); |
|||
$this->clearData(); |
|||
} |
|||
|
|||
public function testLoadMissingFile() { |
|||
$this->assertException("updateFileMissing", "Db"); |
|||
$this->drv->schemaUpdate(1, $this->base); |
|||
} |
|||
|
|||
public function testLoadUnreadableFile() { |
|||
touch($this->path."0.sql"); |
|||
chmod($this->path."0.sql", 0000); |
|||
$this->assertException("updateFileUnreadable", "Db"); |
|||
$this->drv->schemaUpdate(1, $this->base); |
|||
} |
|||
|
|||
public function testLoadCorruptFile() { |
|||
file_put_contents($this->path."0.sql", "This is a corrupt file"); |
|||
$this->assertException("updateFileError", "Db"); |
|||
$this->drv->schemaUpdate(1, $this->base); |
|||
} |
|||
|
|||
public function testLoadIncompleteFile() { |
|||
file_put_contents($this->path."0.sql", "create table arsse_meta(key text primary key not null, value text);"); |
|||
$this->assertException("updateFileIncomplete", "Db"); |
|||
$this->drv->schemaUpdate(1, $this->base); |
|||
} |
|||
|
|||
public function testLoadEmptyFile() { |
|||
file_put_contents($this->path."0.sql", ""); |
|||
$this->assertException("updateFileIncomplete", "Db"); |
|||
$this->drv->schemaUpdate(1, $this->base); |
|||
} |
|||
|
|||
public function testLoadCorrectFile() { |
|||
file_put_contents($this->path."0.sql", self::MINIMAL1); |
|||
$this->drv->schemaUpdate(1, $this->base); |
|||
$this->assertEquals(1, $this->drv->schemaVersion()); |
|||
} |
|||
|
|||
public function testPerformPartialUpdate() { |
|||
file_put_contents($this->path."0.sql", self::MINIMAL1); |
|||
file_put_contents($this->path."1.sql", " "); |
|||
$this->assertException("updateFileIncomplete", "Db"); |
|||
try { |
|||
$this->drv->schemaUpdate(2, $this->base); |
|||
} catch (Exception $e) { |
|||
$this->assertEquals(1, $this->drv->schemaVersion()); |
|||
throw $e; |
|||
} |
|||
} |
|||
|
|||
public function testPerformSequentialUpdate() { |
|||
file_put_contents($this->path."0.sql", self::MINIMAL1); |
|||
file_put_contents($this->path."1.sql", self::MINIMAL2); |
|||
$this->drv->schemaUpdate(2, $this->base); |
|||
$this->assertEquals(2, $this->drv->schemaVersion()); |
|||
} |
|||
|
|||
public function testPerformActualUpdate() { |
|||
$this->drv->schemaUpdate(Database::SCHEMA_VERSION); |
|||
$this->assertEquals(Database::SCHEMA_VERSION, $this->drv->schemaVersion()); |
|||
} |
|||
|
|||
public function testDeclineManualUpdate() { |
|||
// turn auto-updating off |
|||
$conf = new Conf(); |
|||
$conf->dbAutoUpdate = false; |
|||
$this->setUp($conf); |
|||
$this->assertException("updateManual", "Db"); |
|||
$this->drv->schemaUpdate(Database::SCHEMA_VERSION); |
|||
} |
|||
|
|||
public function testDeclineDowngrade() { |
|||
$this->assertException("updateTooNew", "Db"); |
|||
$this->drv->schemaUpdate(-1, $this->base); |
|||
} |
|||
} |
Loading…
Reference in new issue