mirror of
https://code.mensbeam.com/MensBeam/Arsse.git
synced 2024-12-22 13:12:41 +00:00
Partial rewrite of database table comparison
Contents still need to be sorted for tests to pass.
This commit is contained in:
parent
9ac615e4a4
commit
51ce4ae92b
2 changed files with 195 additions and 181 deletions
|
@ -10,152 +10,6 @@ use JKingWeb\Arsse\Database;
|
|||
|
||||
/** @covers \JKingWeb\Arsse\Database */
|
||||
class TestDatabase extends \JKingWeb\Arsse\Test\AbstractTest {
|
||||
protected const COL_DEFS = [
|
||||
'arsse_meta' => [
|
||||
'key' => "strict str",
|
||||
'value' => "str",
|
||||
],
|
||||
'arsse_users' => [
|
||||
'id' => "strict str",
|
||||
'password' => "str",
|
||||
'num' => "strict int",
|
||||
'admin' => "strict bool",
|
||||
],
|
||||
'arsse_user_meta' => [
|
||||
'owner' => "strict str",
|
||||
'key' => "strict str",
|
||||
'modified' => "strict datetime",
|
||||
'value' => "str",
|
||||
],
|
||||
'arsse_sessions' => [
|
||||
'id' => "strict str",
|
||||
'created' => "strict datetime",
|
||||
'expires' => "strict datetime",
|
||||
'user' => "strict str",
|
||||
],
|
||||
'arsse_tokens' => [
|
||||
'id' => "strict str",
|
||||
'class' => "strict str",
|
||||
'user' => "strict str",
|
||||
'created' => "strict datetime",
|
||||
'expires' => "datetime",
|
||||
'data' => "str",
|
||||
],
|
||||
'arsse_feeds' => [
|
||||
'id' => "int",
|
||||
'url' => "strict str",
|
||||
'title' => "str",
|
||||
'source' => "str",
|
||||
'updated' => "datetime",
|
||||
'modified' => "datetime",
|
||||
'next_fetch' => "datetime",
|
||||
'orphaned' => "datetime",
|
||||
'etag' => "strict str",
|
||||
'err_count' => "strict int",
|
||||
'err_msg' => "str",
|
||||
'username' => "strict str",
|
||||
'password' => "strict str",
|
||||
'size' => "strict int",
|
||||
'icon' => "int",
|
||||
],
|
||||
'arsse_icons' => [
|
||||
'id' => "int",
|
||||
'url' => "strict str",
|
||||
'modified' => "datetime",
|
||||
'etag' => "strict str",
|
||||
'next_fetch' => "datetime",
|
||||
'orphaned' => "datetime",
|
||||
'type' => "str",
|
||||
'data' => "blob",
|
||||
],
|
||||
'arsse_articles' => [
|
||||
'id' => "int",
|
||||
'feed' => "strict int",
|
||||
'url' => "str",
|
||||
'title' => "str",
|
||||
'author' => "str",
|
||||
'published' => "datetime",
|
||||
'edited' => "datetime",
|
||||
'modified' => "strict datetime",
|
||||
'guid' => "str",
|
||||
'url_title_hash' => "strict str",
|
||||
'url_content_hash' => "strict str",
|
||||
'title_content_hash' => "strict str",
|
||||
'content_scraped' => "str",
|
||||
'content' => "str",
|
||||
],
|
||||
'arsse_editions' => [
|
||||
'id' => "int",
|
||||
'article' => "strict int",
|
||||
'modified' => "strict datetime",
|
||||
],
|
||||
'arsse_enclosures' => [
|
||||
'article' => "strict int",
|
||||
'url' => "str",
|
||||
'type' => "str",
|
||||
],
|
||||
'arsse_categories' => [
|
||||
'article' => "strict int",
|
||||
'name' => "str",
|
||||
],
|
||||
'arsse_marks' => [
|
||||
'article' => "strict int",
|
||||
'subscription' => "strict int",
|
||||
'read' => "strict bool",
|
||||
'starred' => "strict bool",
|
||||
'modified' => "datetime",
|
||||
'note' => "strict str",
|
||||
'touched' => "strict bool",
|
||||
'hidden' => "strict bool",
|
||||
],
|
||||
'arsse_subscriptions' => [
|
||||
'id' => "int",
|
||||
'owner' => "strict str",
|
||||
'feed' => "strict int",
|
||||
'added' => "strict datetime",
|
||||
'modified' => "strict datetime",
|
||||
'title' => "str",
|
||||
'order_type' => "strict int",
|
||||
'pinned' => "strict bool",
|
||||
'folder' => "int",
|
||||
'keep_rule' => "str",
|
||||
'block_rule' => "str",
|
||||
'scrape' => "strict bool",
|
||||
],
|
||||
'arsse_folders' => [
|
||||
'id' => "int",
|
||||
'owner' => "strict str",
|
||||
'parent' => "int",
|
||||
'name' => "strict str",
|
||||
'modified' => "strict datetime",
|
||||
],
|
||||
'arsse_tags' => [
|
||||
'id' => "int",
|
||||
'owner' => "strict str",
|
||||
'name' => "strict str",
|
||||
'modified' => "strict datetime",
|
||||
],
|
||||
'arsse_tag_members' => [
|
||||
'tag' => "strict int",
|
||||
'subscription' => "strict int",
|
||||
'assigned' => "strict bool",
|
||||
'modified' => "strict datetime",
|
||||
],
|
||||
'arsse_labels' => [
|
||||
'id' => "int",
|
||||
'owner' => "strict str",
|
||||
'name' => "strict str",
|
||||
'modified' => "strict datetime",
|
||||
],
|
||||
'arsse_label_members' => [
|
||||
'label' => "strict int",
|
||||
'article' => "strict int",
|
||||
'subscription' => "strict int",
|
||||
'assigned' => "strict bool",
|
||||
'modified' => "strict datetime",
|
||||
],
|
||||
];
|
||||
|
||||
protected $db = null;
|
||||
|
||||
public function setUp(): void {
|
||||
|
|
|
@ -31,6 +31,152 @@ use Laminas\Diactoros\Response\XmlResponse;
|
|||
abstract class AbstractTest extends \PHPUnit\Framework\TestCase {
|
||||
use \DMS\PHPUnitExtensions\ArraySubset\ArraySubsetAsserts;
|
||||
|
||||
protected const COL_DEFS = [
|
||||
'arsse_meta' => [
|
||||
'key' => "str",
|
||||
'value' => "str",
|
||||
],
|
||||
'arsse_users' => [
|
||||
'id' => "str",
|
||||
'password' => "str",
|
||||
'num' => "int",
|
||||
'admin' => "bool",
|
||||
],
|
||||
'arsse_user_meta' => [
|
||||
'owner' => "str",
|
||||
'key' => "str",
|
||||
'modified' => "datetime",
|
||||
'value' => "str",
|
||||
],
|
||||
'arsse_sessions' => [
|
||||
'id' => "str",
|
||||
'created' => "datetime",
|
||||
'expires' => "datetime",
|
||||
'user' => "str",
|
||||
],
|
||||
'arsse_tokens' => [
|
||||
'id' => "str",
|
||||
'class' => "str",
|
||||
'user' => "str",
|
||||
'created' => "datetime",
|
||||
'expires' => "datetime",
|
||||
'data' => "str",
|
||||
],
|
||||
'arsse_feeds' => [
|
||||
'id' => "int",
|
||||
'url' => "str",
|
||||
'title' => "str",
|
||||
'source' => "str",
|
||||
'updated' => "datetime",
|
||||
'modified' => "datetime",
|
||||
'next_fetch' => "datetime",
|
||||
'orphaned' => "datetime",
|
||||
'etag' => "str",
|
||||
'err_count' => "int",
|
||||
'err_msg' => "str",
|
||||
'username' => "str",
|
||||
'password' => "str",
|
||||
'size' => "int",
|
||||
'icon' => "int",
|
||||
],
|
||||
'arsse_icons' => [
|
||||
'id' => "int",
|
||||
'url' => "str",
|
||||
'modified' => "datetime",
|
||||
'etag' => "str",
|
||||
'next_fetch' => "datetime",
|
||||
'orphaned' => "datetime",
|
||||
'type' => "str",
|
||||
'data' => "blob",
|
||||
],
|
||||
'arsse_articles' => [
|
||||
'id' => "int",
|
||||
'feed' => "int",
|
||||
'url' => "str",
|
||||
'title' => "str",
|
||||
'author' => "str",
|
||||
'published' => "datetime",
|
||||
'edited' => "datetime",
|
||||
'modified' => "datetime",
|
||||
'guid' => "str",
|
||||
'url_title_hash' => "str",
|
||||
'url_content_hash' => "str",
|
||||
'title_content_hash' => "str",
|
||||
'content_scraped' => "str",
|
||||
'content' => "str",
|
||||
],
|
||||
'arsse_editions' => [
|
||||
'id' => "int",
|
||||
'article' => "int",
|
||||
'modified' => "datetime",
|
||||
],
|
||||
'arsse_enclosures' => [
|
||||
'article' => "int",
|
||||
'url' => "str",
|
||||
'type' => "str",
|
||||
],
|
||||
'arsse_categories' => [
|
||||
'article' => "int",
|
||||
'name' => "str",
|
||||
],
|
||||
'arsse_marks' => [
|
||||
'article' => "int",
|
||||
'subscription' => "int",
|
||||
'read' => "bool",
|
||||
'starred' => "bool",
|
||||
'modified' => "datetime",
|
||||
'note' => "str",
|
||||
'touched' => "bool",
|
||||
'hidden' => "bool",
|
||||
],
|
||||
'arsse_subscriptions' => [
|
||||
'id' => "int",
|
||||
'owner' => "str",
|
||||
'feed' => "int",
|
||||
'added' => "datetime",
|
||||
'modified' => "datetime",
|
||||
'title' => "str",
|
||||
'order_type' => "int",
|
||||
'pinned' => "bool",
|
||||
'folder' => "int",
|
||||
'keep_rule' => "str",
|
||||
'block_rule' => "str",
|
||||
'scrape' => "bool",
|
||||
],
|
||||
'arsse_folders' => [
|
||||
'id' => "int",
|
||||
'owner' => "str",
|
||||
'parent' => "int",
|
||||
'name' => "str",
|
||||
'modified' => "datetime",
|
||||
],
|
||||
'arsse_tags' => [
|
||||
'id' => "int",
|
||||
'owner' => "str",
|
||||
'name' => "str",
|
||||
'modified' => "datetime",
|
||||
],
|
||||
'arsse_tag_members' => [
|
||||
'tag' => "int",
|
||||
'subscription' => "int",
|
||||
'assigned' => "bool",
|
||||
'modified' => "datetime",
|
||||
],
|
||||
'arsse_labels' => [
|
||||
'id' => "int",
|
||||
'owner' => "str",
|
||||
'name' => "str",
|
||||
'modified' => "datetime",
|
||||
],
|
||||
'arsse_label_members' => [
|
||||
'label' => "int",
|
||||
'article' => "int",
|
||||
'subscription' => "int",
|
||||
'assigned' => "bool",
|
||||
'modified' => "datetime",
|
||||
],
|
||||
];
|
||||
|
||||
protected $objMock;
|
||||
protected $confMock;
|
||||
protected $langMock;
|
||||
|
@ -260,47 +406,61 @@ abstract class AbstractTest extends \PHPUnit\Framework\TestCase {
|
|||
return true;
|
||||
}
|
||||
|
||||
public function compareExpectations(Driver $drv, array $expected): bool {
|
||||
public function compareExpectations(Driver $drv, array $expected): void {
|
||||
foreach ($expected as $table => $info) {
|
||||
$cols = array_map(function($v) {
|
||||
return '"'.str_replace('"', '""', $v).'"';
|
||||
}, array_keys($info['columns']));
|
||||
$cols = implode(",", $cols);
|
||||
$types = $info['columns'];
|
||||
$data = $drv->prepare("SELECT $cols from $table")->run()->getAll();
|
||||
$cols = array_keys($info['columns']);
|
||||
foreach ($info['rows'] as $index => $row) {
|
||||
$this->assertCount(sizeof($cols), $row, "The number of columns in array index $index of expectations for table $table does not match its definition");
|
||||
$row = array_combine($cols, $row);
|
||||
foreach ($data as $index => $test) {
|
||||
foreach ($test as $col => $value) {
|
||||
switch ($types[$col]) {
|
||||
case "datetime":
|
||||
$test[$col] = $this->approximateTime($row[$col], $value);
|
||||
break;
|
||||
case "int":
|
||||
$test[$col] = ValueInfo::normalize($value, ValueInfo::T_INT | ValueInfo::M_DROP | valueInfo::M_NULL);
|
||||
break;
|
||||
case "float":
|
||||
$test[$col] = ValueInfo::normalize($value, ValueInfo::T_FLOAT | ValueInfo::M_DROP | valueInfo::M_NULL);
|
||||
break;
|
||||
case "bool":
|
||||
$test[$col] = (int) ValueInfo::normalize($value, ValueInfo::T_BOOL | ValueInfo::M_DROP | valueInfo::M_NULL);
|
||||
break;
|
||||
}
|
||||
// serialize the rows of the expected output
|
||||
$types = array_values($info['columns']);
|
||||
$exp = [];
|
||||
$dates = [];
|
||||
foreach ($info['rows'] as $r) {
|
||||
$row = [];
|
||||
foreach ($r as $c => $v) {
|
||||
if ($types[$c] === "datetime") {
|
||||
$dates[] = $v;
|
||||
}
|
||||
if ($row === $test) {
|
||||
$data[$index] = $test;
|
||||
break;
|
||||
if ($v === null) {
|
||||
$row[] = "";
|
||||
} elseif (static::$stringOutput || is_string($v)) {
|
||||
$row[] = '"'.str_replace('"', '""', (string) $v).'"';
|
||||
} else {
|
||||
$row[] = (string) $v;
|
||||
}
|
||||
}
|
||||
$this->assertContains($row, $data, "Actual Table $table does not contain record at expected array index $index");
|
||||
$found = array_search($row, $data, true);
|
||||
unset($data[$found]);
|
||||
$exp[] = implode(",", $row);
|
||||
}
|
||||
$this->assertSame([], $data, "Actual table $table contains extra rows not in expectations");
|
||||
// serialize the rows of the actual output
|
||||
$cols = implode(",", array_map(function($v) {
|
||||
return '"'.str_replace('"', '""', $v).'"';
|
||||
}, array_keys($info['columns'])));
|
||||
$data = $drv->prepare("SELECT $cols from $table")->run()->getAll();
|
||||
$types = $info['columns'];
|
||||
$act = [];
|
||||
foreach ($data as $r) {
|
||||
$row = [];
|
||||
foreach ($r as $c => $v) {
|
||||
if ($types[$c] === "datetime") {
|
||||
if (array_search($v, $dates, true) === false) {
|
||||
$v = Date::transform(Date::sub("PT1S", $v), "sql");
|
||||
if (array_search($v, $dates, true) === false) {
|
||||
$v = Date::transform(Date::add("PT2S", $v), "sql");
|
||||
if (array_search($v, $dates, true) === false) {
|
||||
$v = Date::transform(Date::sub("PT1S", $v), "sql");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if ($v === null) {
|
||||
$row[] = "";
|
||||
} elseif (is_string($v)) {
|
||||
$row[] = '"'.str_replace('"', '""', (string) $v).'"';
|
||||
} else {
|
||||
$row[] = (string) $v;
|
||||
}
|
||||
}
|
||||
$act[] = implode(",", $row);
|
||||
}
|
||||
$this->assertSame($exp, $act, "Actual table $table does not match expectations");
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
public function primeExpectations(array $source, array $tableSpecs): array {
|
||||
|
|
Loading…
Reference in a new issue