Browse Source

Make database test helpers generic

microsub
J. King 5 years ago
parent
commit
2628ff7bf4
  1. 123
      tests/cases/Database/Base.php
  2. 58
      tests/cases/Database/SeriesArticle.php
  3. 16
      tests/cases/Database/SeriesCleanup.php
  4. 8
      tests/cases/Database/SeriesFeed.php
  5. 12
      tests/cases/Database/SeriesFolder.php
  6. 26
      tests/cases/Database/SeriesLabel.php
  7. 10
      tests/cases/Database/SeriesMeta.php
  8. 6
      tests/cases/Database/SeriesSession.php
  9. 16
      tests/cases/Database/SeriesSubscription.php
  10. 26
      tests/cases/Database/SeriesTag.php
  11. 12
      tests/cases/Database/SeriesToken.php
  12. 6
      tests/cases/Database/SeriesUser.php
  13. 121
      tests/lib/AbstractTest.php

123
tests/cases/Database/Base.php

@ -8,11 +8,7 @@ namespace JKingWeb\Arsse\TestCase\Database;
use JKingWeb\Arsse\Test\Database; use JKingWeb\Arsse\Test\Database;
use JKingWeb\Arsse\Arsse; use JKingWeb\Arsse\Arsse;
use JKingWeb\Arsse\Conf;
use JKingWeb\Arsse\User; use JKingWeb\Arsse\User;
use JKingWeb\Arsse\Misc\ValueInfo;
use JKingWeb\Arsse\Db\Result;
use JKingWeb\Arsse\Test\DatabaseInformation;
use Phake; use Phake;
abstract class Base extends \JKingWeb\Arsse\Test\AbstractTest { abstract class Base extends \JKingWeb\Arsse\Test\AbstractTest {
@ -84,7 +80,7 @@ abstract class Base extends \JKingWeb\Arsse\Test\AbstractTest {
$this->$setUp(); $this->$setUp();
// prime the database with series data if it hasn't already been done // prime the database with series data if it hasn't already been done
if (!$this->primed && isset($this->data)) { if (!$this->primed && isset($this->data)) {
$this->primeDatabase($this->data); $this->primeDatabase(static::$drv, $this->data);
} }
} }
@ -111,121 +107,4 @@ abstract class Base extends \JKingWeb\Arsse\Test\AbstractTest {
static::$failureReason = ""; static::$failureReason = "";
static::clearData(); static::clearData();
} }
public function primeDatabase(array $data): bool {
$drv = static::$drv;
$tr = $drv->begin();
foreach ($data as $table => $info) {
$cols = array_map(function($v) {
return '"'.str_replace('"', '""', $v).'"';
}, array_keys($info['columns']));
$cols = implode(",", $cols);
$bindings = array_values($info['columns']);
$params = implode(",", array_fill(0, sizeof($info['columns']), "?"));
$s = $drv->prepareArray("INSERT INTO $table($cols) values($params)", $bindings);
foreach ($info['rows'] as $row) {
$s->runArray($row);
}
}
$tr->commit();
$this->primed = true;
return true;
}
public function compareExpectations(array $expected): bool {
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 = static::$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 values for array index $index does not match the number of fields");
$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;
}
}
if ($row===$test) {
$data[$index] = $test;
break;
}
}
$this->assertContains($row, $data, "Table $table does not contain record at array index $index.");
$found = array_search($row, $data, true);
unset($data[$found]);
}
$this->assertSame([], $data);
}
return true;
}
public function primeExpectations(array $source, array $tableSpecs = null): array {
$out = [];
foreach ($tableSpecs as $table => $columns) {
// make sure the source has the table we want
$this->assertArrayHasKey($table, $source, "Source for expectations does not contain requested table $table.");
$out[$table] = [
'columns' => [],
'rows' => array_fill(0, sizeof($source[$table]['rows']), []),
];
// make sure the source has all the columns we want for the table
$cols = array_flip($columns);
$cols = array_intersect_key($cols, $source[$table]['columns']);
$this->assertSame(array_keys($cols), $columns, "Source for table $table does not contain all requested columns");
// get a map of source value offsets and keys
$targets = array_flip(array_keys($source[$table]['columns']));
foreach ($cols as $key => $order) {
// fill the column-spec
$out[$table]['columns'][$key] = $source[$table]['columns'][$key];
foreach ($source[$table]['rows'] as $index => $row) {
// fill each row column-wise with re-ordered values
$out[$table]['rows'][$index][$order] = $row[$targets[$key]];
}
}
}
return $out;
}
public function assertResult(array $expected, Result $data) {
$data = $data->getAll();
$this->assertCount(sizeof($expected), $data, "Number of result rows (".sizeof($data).") differs from number of expected rows (".sizeof($expected).")");
if (sizeof($expected)) {
// make sure the expectations are consistent
foreach ($expected as $exp) {
if (!isset($keys)) {
$keys = $exp;
continue;
}
$this->assertSame(array_keys($keys), array_keys($exp), "Result set expectations are irregular");
}
// filter the result set to contain just the desired keys (we don't care if the result has extra keys)
$rows = [];
foreach ($data as $row) {
$rows[] = array_intersect_key($row, $keys);
}
// compare the result set to the expectations
foreach ($rows as $row) {
$this->assertContains($row, $expected, "Result set contains unexpected record.");
$found = array_search($row, $expected);
unset($expected[$found]);
}
$this->assertArraySubset($expected, [], false, "Expectations not in result set.");
}
}
} }

58
tests/cases/Database/SeriesArticle.php

@ -581,7 +581,7 @@ trait SeriesArticle {
$state['arsse_marks']['rows'][9][4] = $now; $state['arsse_marks']['rows'][9][4] = $now;
$state['arsse_marks']['rows'][11][2] = 0; $state['arsse_marks']['rows'][11][2] = 0;
$state['arsse_marks']['rows'][11][4] = $now; $state['arsse_marks']['rows'][11][4] = $now;
$this->compareExpectations($state); $this->compareExpectations(static::$drv, $state);
} }
public function testMarkAllArticlesRead() { public function testMarkAllArticlesRead() {
@ -596,7 +596,7 @@ trait SeriesArticle {
$state['arsse_marks']['rows'][] = [13,6,1,0,$now,'']; $state['arsse_marks']['rows'][] = [13,6,1,0,$now,''];
$state['arsse_marks']['rows'][] = [14,7,1,0,$now,'']; $state['arsse_marks']['rows'][] = [14,7,1,0,$now,''];
$state['arsse_marks']['rows'][] = [14,8,1,0,$now,'']; $state['arsse_marks']['rows'][] = [14,8,1,0,$now,''];
$this->compareExpectations($state); $this->compareExpectations(static::$drv, $state);
} }
public function testMarkAllArticlesUnstarred() { public function testMarkAllArticlesUnstarred() {
@ -607,7 +607,7 @@ trait SeriesArticle {
$state['arsse_marks']['rows'][10][4] = $now; $state['arsse_marks']['rows'][10][4] = $now;
$state['arsse_marks']['rows'][11][3] = 0; $state['arsse_marks']['rows'][11][3] = 0;
$state['arsse_marks']['rows'][11][4] = $now; $state['arsse_marks']['rows'][11][4] = $now;
$this->compareExpectations($state); $this->compareExpectations(static::$drv, $state);
} }
public function testMarkAllArticlesStarred() { public function testMarkAllArticlesStarred() {
@ -622,7 +622,7 @@ trait SeriesArticle {
$state['arsse_marks']['rows'][] = [13,6,0,1,$now,'']; $state['arsse_marks']['rows'][] = [13,6,0,1,$now,''];
$state['arsse_marks']['rows'][] = [14,7,0,1,$now,'']; $state['arsse_marks']['rows'][] = [14,7,0,1,$now,''];
$state['arsse_marks']['rows'][] = [14,8,0,1,$now,'']; $state['arsse_marks']['rows'][] = [14,8,0,1,$now,''];
$this->compareExpectations($state); $this->compareExpectations(static::$drv, $state);
} }
public function testMarkAllArticlesUnreadAndUnstarred() { public function testMarkAllArticlesUnreadAndUnstarred() {
@ -636,7 +636,7 @@ trait SeriesArticle {
$state['arsse_marks']['rows'][11][2] = 0; $state['arsse_marks']['rows'][11][2] = 0;
$state['arsse_marks']['rows'][11][3] = 0; $state['arsse_marks']['rows'][11][3] = 0;
$state['arsse_marks']['rows'][11][4] = $now; $state['arsse_marks']['rows'][11][4] = $now;
$this->compareExpectations($state); $this->compareExpectations(static::$drv, $state);
} }
public function testMarkAllArticlesReadAndStarred() { public function testMarkAllArticlesReadAndStarred() {
@ -654,7 +654,7 @@ trait SeriesArticle {
$state['arsse_marks']['rows'][] = [13,6,1,1,$now,'']; $state['arsse_marks']['rows'][] = [13,6,1,1,$now,''];
$state['arsse_marks']['rows'][] = [14,7,1,1,$now,'']; $state['arsse_marks']['rows'][] = [14,7,1,1,$now,''];
$state['arsse_marks']['rows'][] = [14,8,1,1,$now,'']; $state['arsse_marks']['rows'][] = [14,8,1,1,$now,''];
$this->compareExpectations($state); $this->compareExpectations(static::$drv, $state);
} }
public function testMarkAllArticlesUnreadAndStarred() { public function testMarkAllArticlesUnreadAndStarred() {
@ -672,7 +672,7 @@ trait SeriesArticle {
$state['arsse_marks']['rows'][] = [13,6,0,1,$now,'']; $state['arsse_marks']['rows'][] = [13,6,0,1,$now,''];
$state['arsse_marks']['rows'][] = [14,7,0,1,$now,'']; $state['arsse_marks']['rows'][] = [14,7,0,1,$now,''];
$state['arsse_marks']['rows'][] = [14,8,0,1,$now,'']; $state['arsse_marks']['rows'][] = [14,8,0,1,$now,''];
$this->compareExpectations($state); $this->compareExpectations(static::$drv, $state);
} }
public function testMarkAllArticlesReadAndUnstarred() { public function testMarkAllArticlesReadAndUnstarred() {
@ -690,7 +690,7 @@ trait SeriesArticle {
$state['arsse_marks']['rows'][] = [13,6,1,0,$now,'']; $state['arsse_marks']['rows'][] = [13,6,1,0,$now,''];
$state['arsse_marks']['rows'][] = [14,7,1,0,$now,'']; $state['arsse_marks']['rows'][] = [14,7,1,0,$now,''];
$state['arsse_marks']['rows'][] = [14,8,1,0,$now,'']; $state['arsse_marks']['rows'][] = [14,8,1,0,$now,''];
$this->compareExpectations($state); $this->compareExpectations(static::$drv, $state);
} }
public function testSetNoteForAllArticles() { public function testSetNoteForAllArticles() {
@ -709,7 +709,7 @@ trait SeriesArticle {
$state['arsse_marks']['rows'][] = [13,6,0,0,$now,'New note']; $state['arsse_marks']['rows'][] = [13,6,0,0,$now,'New note'];
$state['arsse_marks']['rows'][] = [14,7,0,0,$now,'New note']; $state['arsse_marks']['rows'][] = [14,7,0,0,$now,'New note'];
$state['arsse_marks']['rows'][] = [14,8,0,0,$now,'New note']; $state['arsse_marks']['rows'][] = [14,8,0,0,$now,'New note'];
$this->compareExpectations($state); $this->compareExpectations(static::$drv, $state);
} }
public function testMarkATreeFolder() { public function testMarkATreeFolder() {
@ -720,7 +720,7 @@ trait SeriesArticle {
$state['arsse_marks']['rows'][] = [13,6,1,0,$now,'']; $state['arsse_marks']['rows'][] = [13,6,1,0,$now,''];
$state['arsse_marks']['rows'][] = [14,7,1,0,$now,'']; $state['arsse_marks']['rows'][] = [14,7,1,0,$now,''];
$state['arsse_marks']['rows'][] = [14,8,1,0,$now,'']; $state['arsse_marks']['rows'][] = [14,8,1,0,$now,''];
$this->compareExpectations($state); $this->compareExpectations(static::$drv, $state);
} }
public function testMarkALeafFolder() { public function testMarkALeafFolder() {
@ -729,7 +729,7 @@ trait SeriesArticle {
$state = $this->primeExpectations($this->data, $this->checkTables); $state = $this->primeExpectations($this->data, $this->checkTables);
$state['arsse_marks']['rows'][] = [13,5,1,0,$now,'']; $state['arsse_marks']['rows'][] = [13,5,1,0,$now,''];
$state['arsse_marks']['rows'][] = [13,6,1,0,$now,'']; $state['arsse_marks']['rows'][] = [13,6,1,0,$now,''];
$this->compareExpectations($state); $this->compareExpectations(static::$drv, $state);
} }
public function testMarkAMissingFolder() { public function testMarkAMissingFolder() {
@ -743,7 +743,7 @@ trait SeriesArticle {
$state = $this->primeExpectations($this->data, $this->checkTables); $state = $this->primeExpectations($this->data, $this->checkTables);
$state['arsse_marks']['rows'][] = [13,5,1,0,$now,'']; $state['arsse_marks']['rows'][] = [13,5,1,0,$now,''];
$state['arsse_marks']['rows'][] = [13,6,1,0,$now,'']; $state['arsse_marks']['rows'][] = [13,6,1,0,$now,''];
$this->compareExpectations($state); $this->compareExpectations(static::$drv, $state);
} }
public function testMarkAMissingSubscription() { public function testMarkAMissingSubscription() {
@ -757,7 +757,7 @@ trait SeriesArticle {
$state = $this->primeExpectations($this->data, $this->checkTables); $state = $this->primeExpectations($this->data, $this->checkTables);
$state['arsse_marks']['rows'][9][3] = 1; $state['arsse_marks']['rows'][9][3] = 1;
$state['arsse_marks']['rows'][9][4] = $now; $state['arsse_marks']['rows'][9][4] = $now;
$this->compareExpectations($state); $this->compareExpectations(static::$drv, $state);
} }
public function testMarkMultipleArticles() { public function testMarkMultipleArticles() {
@ -767,7 +767,7 @@ trait SeriesArticle {
$state['arsse_marks']['rows'][9][3] = 1; $state['arsse_marks']['rows'][9][3] = 1;
$state['arsse_marks']['rows'][9][4] = $now; $state['arsse_marks']['rows'][9][4] = $now;
$state['arsse_marks']['rows'][] = [14,7,0,1,$now,'']; $state['arsse_marks']['rows'][] = [14,7,0,1,$now,''];
$this->compareExpectations($state); $this->compareExpectations(static::$drv, $state);
} }
public function testMarkMultipleArticlessUnreadAndStarred() { public function testMarkMultipleArticlessUnreadAndStarred() {
@ -780,7 +780,7 @@ trait SeriesArticle {
$state['arsse_marks']['rows'][11][2] = 0; $state['arsse_marks']['rows'][11][2] = 0;
$state['arsse_marks']['rows'][11][4] = $now; $state['arsse_marks']['rows'][11][4] = $now;
$state['arsse_marks']['rows'][] = [14,7,0,1,$now,'']; $state['arsse_marks']['rows'][] = [14,7,0,1,$now,''];
$this->compareExpectations($state); $this->compareExpectations(static::$drv, $state);
} }
public function testMarkTooFewMultipleArticles() { public function testMarkTooFewMultipleArticles() {
@ -803,7 +803,7 @@ trait SeriesArticle {
$state = $this->primeExpectations($this->data, $this->checkTables); $state = $this->primeExpectations($this->data, $this->checkTables);
$state['arsse_marks']['rows'][9][3] = 1; $state['arsse_marks']['rows'][9][3] = 1;
$state['arsse_marks']['rows'][9][4] = $now; $state['arsse_marks']['rows'][9][4] = $now;
$this->compareExpectations($state); $this->compareExpectations(static::$drv, $state);
} }
public function testMarkMultipleEditions() { public function testMarkMultipleEditions() {
@ -813,13 +813,13 @@ trait SeriesArticle {
$state['arsse_marks']['rows'][9][3] = 1; $state['arsse_marks']['rows'][9][3] = 1;
$state['arsse_marks']['rows'][9][4] = $now; $state['arsse_marks']['rows'][9][4] = $now;
$state['arsse_marks']['rows'][] = [14,7,0,1,$now,'']; $state['arsse_marks']['rows'][] = [14,7,0,1,$now,''];
$this->compareExpectations($state); $this->compareExpectations(static::$drv, $state);
} }
public function testMarkMultipleMissingEditions() { public function testMarkMultipleMissingEditions() {
$this->assertSame(0, Arsse::$db->articleMark($this->user, ['starred'=>true], (new Context)->editions([500,501]))); $this->assertSame(0, Arsse::$db->articleMark($this->user, ['starred'=>true], (new Context)->editions([500,501])));
$state = $this->primeExpectations($this->data, $this->checkTables); $state = $this->primeExpectations($this->data, $this->checkTables);
$this->compareExpectations($state); $this->compareExpectations(static::$drv, $state);
} }
public function testMarkMultipleEditionsUnread() { public function testMarkMultipleEditionsUnread() {
@ -830,7 +830,7 @@ trait SeriesArticle {
$state['arsse_marks']['rows'][9][4] = $now; $state['arsse_marks']['rows'][9][4] = $now;
$state['arsse_marks']['rows'][11][2] = 0; $state['arsse_marks']['rows'][11][2] = 0;
$state['arsse_marks']['rows'][11][4] = $now; $state['arsse_marks']['rows'][11][4] = $now;
$this->compareExpectations($state); $this->compareExpectations(static::$drv, $state);
} }
public function testMarkMultipleEditionsUnreadWithStale() { public function testMarkMultipleEditionsUnreadWithStale() {
@ -839,7 +839,7 @@ trait SeriesArticle {
$state = $this->primeExpectations($this->data, $this->checkTables); $state = $this->primeExpectations($this->data, $this->checkTables);
$state['arsse_marks']['rows'][11][2] = 0; $state['arsse_marks']['rows'][11][2] = 0;
$state['arsse_marks']['rows'][11][4] = $now; $state['arsse_marks']['rows'][11][4] = $now;
$this->compareExpectations($state); $this->compareExpectations(static::$drv, $state);
} }
public function testMarkMultipleEditionsUnreadAndStarredWithStale() { public function testMarkMultipleEditionsUnreadAndStarredWithStale() {
@ -851,7 +851,7 @@ trait SeriesArticle {
$state['arsse_marks']['rows'][11][2] = 0; $state['arsse_marks']['rows'][11][2] = 0;
$state['arsse_marks']['rows'][11][4] = $now; $state['arsse_marks']['rows'][11][4] = $now;
$state['arsse_marks']['rows'][] = [14,7,0,1,$now,'']; $state['arsse_marks']['rows'][] = [14,7,0,1,$now,''];
$this->compareExpectations($state); $this->compareExpectations(static::$drv, $state);
} }
public function testMarkTooFewMultipleEditions() { public function testMarkTooFewMultipleEditions() {
@ -866,7 +866,7 @@ trait SeriesArticle {
public function testMarkAStaleEditionUnread() { public function testMarkAStaleEditionUnread() {
Arsse::$db->articleMark($this->user, ['read'=>false], (new Context)->edition(20)); // no changes occur Arsse::$db->articleMark($this->user, ['read'=>false], (new Context)->edition(20)); // no changes occur
$state = $this->primeExpectations($this->data, $this->checkTables); $state = $this->primeExpectations($this->data, $this->checkTables);
$this->compareExpectations($state); $this->compareExpectations(static::$drv, $state);
} }
public function testMarkAStaleEditionStarred() { public function testMarkAStaleEditionStarred() {
@ -875,7 +875,7 @@ trait SeriesArticle {
$state = $this->primeExpectations($this->data, $this->checkTables); $state = $this->primeExpectations($this->data, $this->checkTables);
$state['arsse_marks']['rows'][9][3] = 1; $state['arsse_marks']['rows'][9][3] = 1;
$state['arsse_marks']['rows'][9][4] = $now; $state['arsse_marks']['rows'][9][4] = $now;
$this->compareExpectations($state); $this->compareExpectations(static::$drv, $state);
} }
public function testMarkAStaleEditionUnreadAndStarred() { public function testMarkAStaleEditionUnreadAndStarred() {
@ -884,13 +884,13 @@ trait SeriesArticle {
$state = $this->primeExpectations($this->data, $this->checkTables); $state = $this->primeExpectations($this->data, $this->checkTables);
$state['arsse_marks']['rows'][9][3] = 1; $state['arsse_marks']['rows'][9][3] = 1;
$state['arsse_marks']['rows'][9][4] = $now; $state['arsse_marks']['rows'][9][4] = $now;
$this->compareExpectations($state); $this->compareExpectations(static::$drv, $state);
} }
public function testMarkAStaleEditionUnreadAndUnstarred() { public function testMarkAStaleEditionUnreadAndUnstarred() {
Arsse::$db->articleMark($this->user, ['read'=>false,'starred'=>false], (new Context)->edition(20)); // no changes occur Arsse::$db->articleMark($this->user, ['read'=>false,'starred'=>false], (new Context)->edition(20)); // no changes occur
$state = $this->primeExpectations($this->data, $this->checkTables); $state = $this->primeExpectations($this->data, $this->checkTables);
$this->compareExpectations($state); $this->compareExpectations(static::$drv, $state);
} }
public function testMarkAMissingEdition() { public function testMarkAMissingEdition() {
@ -906,7 +906,7 @@ trait SeriesArticle {
$state['arsse_marks']['rows'][8][4] = $now; $state['arsse_marks']['rows'][8][4] = $now;
$state['arsse_marks']['rows'][9][3] = 1; $state['arsse_marks']['rows'][9][3] = 1;
$state['arsse_marks']['rows'][9][4] = $now; $state['arsse_marks']['rows'][9][4] = $now;
$this->compareExpectations($state); $this->compareExpectations(static::$drv, $state);
} }
public function testMarkByLatestEdition() { public function testMarkByLatestEdition() {
@ -919,7 +919,7 @@ trait SeriesArticle {
$state['arsse_marks']['rows'][] = [13,6,0,1,$now,'']; $state['arsse_marks']['rows'][] = [13,6,0,1,$now,''];
$state['arsse_marks']['rows'][] = [14,7,0,1,$now,'']; $state['arsse_marks']['rows'][] = [14,7,0,1,$now,''];
$state['arsse_marks']['rows'][] = [14,8,0,1,$now,'']; $state['arsse_marks']['rows'][] = [14,8,0,1,$now,''];
$this->compareExpectations($state); $this->compareExpectations(static::$drv, $state);
} }
public function testMarkByLastMarked() { public function testMarkByLastMarked() {
@ -930,7 +930,7 @@ trait SeriesArticle {
$state['arsse_marks']['rows'][8][4] = $now; $state['arsse_marks']['rows'][8][4] = $now;
$state['arsse_marks']['rows'][9][3] = 1; $state['arsse_marks']['rows'][9][3] = 1;
$state['arsse_marks']['rows'][9][4] = $now; $state['arsse_marks']['rows'][9][4] = $now;
$this->compareExpectations($state); $this->compareExpectations(static::$drv, $state);
} }
public function testMarkByNotLastMarked() { public function testMarkByNotLastMarked() {
@ -939,7 +939,7 @@ trait SeriesArticle {
$state = $this->primeExpectations($this->data, $this->checkTables); $state = $this->primeExpectations($this->data, $this->checkTables);
$state['arsse_marks']['rows'][] = [13,5,0,1,$now,'']; $state['arsse_marks']['rows'][] = [13,5,0,1,$now,''];
$state['arsse_marks']['rows'][] = [14,7,0,1,$now,'']; $state['arsse_marks']['rows'][] = [14,7,0,1,$now,''];
$this->compareExpectations($state); $this->compareExpectations(static::$drv, $state);
} }
public function testMarkArticlesWithoutAuthority() { public function testMarkArticlesWithoutAuthority() {

16
tests/cases/Database/SeriesCleanup.php

@ -161,7 +161,7 @@ trait SeriesCleanup {
$state['arsse_feeds']['rows'][0][1] = null; $state['arsse_feeds']['rows'][0][1] = null;
unset($state['arsse_feeds']['rows'][1]); unset($state['arsse_feeds']['rows'][1]);
$state['arsse_feeds']['rows'][2][1] = $now; $state['arsse_feeds']['rows'][2][1] = $now;
$this->compareExpectations($state); $this->compareExpectations(static::$drv, $state);
} }
public function testCleanUpOrphanedFeedsWithUnlimitedRetention() { public function testCleanUpOrphanedFeedsWithUnlimitedRetention() {
@ -175,7 +175,7 @@ trait SeriesCleanup {
]); ]);
$state['arsse_feeds']['rows'][0][1] = null; $state['arsse_feeds']['rows'][0][1] = null;
$state['arsse_feeds']['rows'][2][1] = $now; $state['arsse_feeds']['rows'][2][1] = $now;
$this->compareExpectations($state); $this->compareExpectations(static::$drv, $state);
} }
public function testCleanUpOldArticlesWithStandardRetention() { public function testCleanUpOldArticlesWithStandardRetention() {
@ -186,7 +186,7 @@ trait SeriesCleanup {
foreach ([7,8,9] as $id) { foreach ([7,8,9] as $id) {
unset($state['arsse_articles']['rows'][$id - 1]); unset($state['arsse_articles']['rows'][$id - 1]);
} }
$this->compareExpectations($state); $this->compareExpectations(static::$drv, $state);
} }
public function testCleanUpOldArticlesWithUnlimitedReadRetention() { public function testCleanUpOldArticlesWithUnlimitedReadRetention() {
@ -200,7 +200,7 @@ trait SeriesCleanup {
foreach ([7,8] as $id) { foreach ([7,8] as $id) {
unset($state['arsse_articles']['rows'][$id - 1]); unset($state['arsse_articles']['rows'][$id - 1]);
} }
$this->compareExpectations($state); $this->compareExpectations(static::$drv, $state);
} }
public function testCleanUpOldArticlesWithUnlimitedUnreadRetention() { public function testCleanUpOldArticlesWithUnlimitedUnreadRetention() {
@ -214,7 +214,7 @@ trait SeriesCleanup {
foreach ([9] as $id) { foreach ([9] as $id) {
unset($state['arsse_articles']['rows'][$id - 1]); unset($state['arsse_articles']['rows'][$id - 1]);
} }
$this->compareExpectations($state); $this->compareExpectations(static::$drv, $state);
} }
public function testCleanUpOldArticlesWithUnlimitedRetention() { public function testCleanUpOldArticlesWithUnlimitedRetention() {
@ -226,7 +226,7 @@ trait SeriesCleanup {
$state = $this->primeExpectations($this->data, [ $state = $this->primeExpectations($this->data, [
'arsse_articles' => ["id"] 'arsse_articles' => ["id"]
]); ]);
$this->compareExpectations($state); $this->compareExpectations(static::$drv, $state);
} }
public function testCleanUpExpiredSessions() { public function testCleanUpExpiredSessions() {
@ -237,7 +237,7 @@ trait SeriesCleanup {
foreach ([3,4,5] as $id) { foreach ([3,4,5] as $id) {
unset($state['arsse_sessions']['rows'][$id - 1]); unset($state['arsse_sessions']['rows'][$id - 1]);
} }
$this->compareExpectations($state); $this->compareExpectations(static::$drv, $state);
} }
public function testCleanUpExpiredTokens() { public function testCleanUpExpiredTokens() {
@ -248,6 +248,6 @@ trait SeriesCleanup {
foreach ([2] as $id) { foreach ([2] as $id) {
unset($state['arsse_tokens']['rows'][$id - 1]); unset($state['arsse_tokens']['rows'][$id - 1]);
} }
$this->compareExpectations($state); $this->compareExpectations(static::$drv, $state);
} }
} }

8
tests/cases/Database/SeriesFeed.php

@ -204,7 +204,7 @@ trait SeriesFeed {
$state['arsse_marks']['rows'][3] = [6,4,0,0,$now]; $state['arsse_marks']['rows'][3] = [6,4,0,0,$now];
$state['arsse_marks']['rows'][6] = [1,3,0,0,$now]; $state['arsse_marks']['rows'][6] = [1,3,0,0,$now];
$state['arsse_feeds']['rows'][0] = [1,6]; $state['arsse_feeds']['rows'][0] = [1,6];
$this->compareExpectations($state); $this->compareExpectations(static::$drv, $state);
// update a valid feed which previously had an error // update a valid feed which previously had an error
Arsse::$db->feedUpdate(2); Arsse::$db->feedUpdate(2);
// update an erroneous feed which previously had no errors // update an erroneous feed which previously had no errors
@ -214,12 +214,12 @@ trait SeriesFeed {
]); ]);
$state['arsse_feeds']['rows'][1] = [2,0,""]; $state['arsse_feeds']['rows'][1] = [2,0,""];
$state['arsse_feeds']['rows'][2] = [3,1,'Feed URL "http://localhost:8000/Feed/Fetching/Error?code=404" is invalid']; $state['arsse_feeds']['rows'][2] = [3,1,'Feed URL "http://localhost:8000/Feed/Fetching/Error?code=404" is invalid'];
$this->compareExpectations($state); $this->compareExpectations(static::$drv, $state);
// update the bad feed again, twice // update the bad feed again, twice
Arsse::$db->feedUpdate(3); Arsse::$db->feedUpdate(3);
Arsse::$db->feedUpdate(3); Arsse::$db->feedUpdate(3);
$state['arsse_feeds']['rows'][2] = [3,3,'Feed URL "http://localhost:8000/Feed/Fetching/Error?code=404" is invalid']; $state['arsse_feeds']['rows'][2] = [3,3,'Feed URL "http://localhost:8000/Feed/Fetching/Error?code=404" is invalid'];
$this->compareExpectations($state); $this->compareExpectations(static::$drv, $state);
} }
public function testUpdateAMissingFeed() { public function testUpdateAMissingFeed() {
@ -254,7 +254,7 @@ trait SeriesFeed {
["Bodybuilders"], ["Bodybuilders"],
["Men"], ["Men"],
]; ];
$this->compareExpectations($state); $this->compareExpectations(static::$drv, $state);
} }
public function testListStaleFeeds() { public function testListStaleFeeds() {

12
tests/cases/Database/SeriesFolder.php

@ -105,7 +105,7 @@ trait SeriesFolder {
Phake::verify(Arsse::$user)->authorize($user, "folderAdd"); Phake::verify(Arsse::$user)->authorize($user, "folderAdd");
$state = $this->primeExpectations($this->data, ['arsse_folders' => ['id','owner', 'parent', 'name']]); $state = $this->primeExpectations($this->data, ['arsse_folders' => ['id','owner', 'parent', 'name']]);
$state['arsse_folders']['rows'][] = [$folderID, $user, null, "Entertainment"]; $state['arsse_folders']['rows'][] = [$folderID, $user, null, "Entertainment"];
$this->compareExpectations($state); $this->compareExpectations(static::$drv, $state);
} }
public function testAddADuplicateRootFolder() { public function testAddADuplicateRootFolder() {
@ -120,7 +120,7 @@ trait SeriesFolder {
Phake::verify(Arsse::$user)->authorize($user, "folderAdd"); Phake::verify(Arsse::$user)->authorize($user, "folderAdd");
$state = $this->primeExpectations($this->data, ['arsse_folders' => ['id','owner', 'parent', 'name']]); $state = $this->primeExpectations($this->data, ['arsse_folders' => ['id','owner', 'parent', 'name']]);
$state['arsse_folders']['rows'][] = [$folderID, $user, 2, "GNOME"]; $state['arsse_folders']['rows'][] = [$folderID, $user, 2, "GNOME"];
$this->compareExpectations($state); $this->compareExpectations(static::$drv, $state);
} }
public function testAddANestedFolderToAMissingParent() { public function testAddANestedFolderToAMissingParent() {
@ -218,7 +218,7 @@ trait SeriesFolder {
Phake::verify(Arsse::$user)->authorize("john.doe@example.com", "folderRemove"); Phake::verify(Arsse::$user)->authorize("john.doe@example.com", "folderRemove");
$state = $this->primeExpectations($this->data, ['arsse_folders' => ['id','owner', 'parent', 'name']]); $state = $this->primeExpectations($this->data, ['arsse_folders' => ['id','owner', 'parent', 'name']]);
array_pop($state['arsse_folders']['rows']); array_pop($state['arsse_folders']['rows']);
$this->compareExpectations($state); $this->compareExpectations(static::$drv, $state);
} }
public function testRemoveAFolderTree() { public function testRemoveAFolderTree() {
@ -228,7 +228,7 @@ trait SeriesFolder {
foreach ([0,1,2,5] as $index) { foreach ([0,1,2,5] as $index) {
unset($state['arsse_folders']['rows'][$index]); unset($state['arsse_folders']['rows'][$index]);
} }
$this->compareExpectations($state); $this->compareExpectations(static::$drv, $state);
} }
public function testRemoveAMissingFolder() { public function testRemoveAMissingFolder() {
@ -292,7 +292,7 @@ trait SeriesFolder {
Phake::verify(Arsse::$user)->authorize("john.doe@example.com", "folderPropertiesSet"); Phake::verify(Arsse::$user)->authorize("john.doe@example.com", "folderPropertiesSet");
$state = $this->primeExpectations($this->data, ['arsse_folders' => ['id','owner', 'parent', 'name']]); $state = $this->primeExpectations($this->data, ['arsse_folders' => ['id','owner', 'parent', 'name']]);
$state['arsse_folders']['rows'][5][3] = "Opinion"; $state['arsse_folders']['rows'][5][3] = "Opinion";
$this->compareExpectations($state); $this->compareExpectations(static::$drv, $state);
} }
public function testRenameTheRootFolder() { public function testRenameTheRootFolder() {
@ -319,7 +319,7 @@ trait SeriesFolder {
Phake::verify(Arsse::$user)->authorize("john.doe@example.com", "folderPropertiesSet"); Phake::verify(Arsse::$user)->authorize("john.doe@example.com", "folderPropertiesSet");
$state = $this->primeExpectations($this->data, ['arsse_folders' => ['id','owner', 'parent', 'name']]); $state = $this->primeExpectations($this->data, ['arsse_folders' => ['id','owner', 'parent', 'name']]);
$state['arsse_folders']['rows'][5][2] = 5; // parent should have changed $state['arsse_folders']['rows'][5][2] = 5; // parent should have changed
$this->compareExpectations($state); $this->compareExpectations(static::$drv, $state);
} }
public function testMoveTheRootFolder() { public function testMoveTheRootFolder() {

26
tests/cases/Database/SeriesLabel.php

@ -257,7 +257,7 @@ trait SeriesLabel {
Phake::verify(Arsse::$user)->authorize($user, "labelAdd"); Phake::verify(Arsse::$user)->authorize($user, "labelAdd");
$state = $this->primeExpectations($this->data, $this->checkLabels); $state = $this->primeExpectations($this->data, $this->checkLabels);
$state['arsse_labels']['rows'][] = [$labelID, $user, "Entertaining"]; $state['arsse_labels']['rows'][] = [$labelID, $user, "Entertaining"];
$this->compareExpectations($state); $this->compareExpectations(static::$drv, $state);
} }
public function testAddADuplicateLabel() { public function testAddADuplicateLabel() {
@ -313,7 +313,7 @@ trait SeriesLabel {
Phake::verify(Arsse::$user)->authorize("john.doe@example.com", "labelRemove"); Phake::verify(Arsse::$user)->authorize("john.doe@example.com", "labelRemove");
$state = $this->primeExpectations($this->data, $this->checkLabels); $state = $this->primeExpectations($this->data, $this->checkLabels);
array_shift($state['arsse_labels']['rows']); array_shift($state['arsse_labels']['rows']);
$this->compareExpectations($state); $this->compareExpectations(static::$drv, $state);
} }
public function testRemoveALabelByName() { public function testRemoveALabelByName() {
@ -321,7 +321,7 @@ trait SeriesLabel {
Phake::verify(Arsse::$user)->authorize("john.doe@example.com", "labelRemove"); Phake::verify(Arsse::$user)->authorize("john.doe@example.com", "labelRemove");
$state = $this->primeExpectations($this->data, $this->checkLabels); $state = $this->primeExpectations($this->data, $this->checkLabels);
array_shift($state['arsse_labels']['rows']); array_shift($state['arsse_labels']['rows']);
$this->compareExpectations($state); $this->compareExpectations(static::$drv, $state);
} }
public function testRemoveAMissingLabel() { public function testRemoveAMissingLabel() {
@ -397,7 +397,7 @@ trait SeriesLabel {
Phake::verify(Arsse::$user)->authorize("john.doe@example.com", "labelPropertiesSet"); Phake::verify(Arsse::$user)->authorize("john.doe@example.com", "labelPropertiesSet");
$state = $this->primeExpectations($this->data, $this->checkLabels); $state = $this->primeExpectations($this->data, $this->checkLabels);
$state['arsse_labels']['rows'][0][2] = "Curious"; $state['arsse_labels']['rows'][0][2] = "Curious";
$this->compareExpectations($state); $this->compareExpectations(static::$drv, $state);
} }
public function testRenameALabelByName() { public function testRenameALabelByName() {
@ -405,7 +405,7 @@ trait SeriesLabel {
Phake::verify(Arsse::$user)->authorize("john.doe@example.com", "labelPropertiesSet"); Phake::verify(Arsse::$user)->authorize("john.doe@example.com", "labelPropertiesSet");
$state = $this->primeExpectations($this->data, $this->checkLabels); $state = $this->primeExpectations($this->data, $this->checkLabels);
$state['arsse_labels']['rows'][0][2] = "Curious"; $state['arsse_labels']['rows'][0][2] = "Curious";
$this->compareExpectations($state); $this->compareExpectations(static::$drv, $state);
} }
public function testRenameALabelToTheEmptyString() { public function testRenameALabelToTheEmptyString() {
@ -487,14 +487,14 @@ trait SeriesLabel {
$state = $this->primeExpectations($this->data, $this->checkMembers); $state = $this->primeExpectations($this->data, $this->checkMembers);
$state['arsse_label_members']['rows'][4][3] = 1; $state['arsse_label_members']['rows'][4][3] = 1;
$state['arsse_label_members']['rows'][] = [1,2,1,1]; $state['arsse_label_members']['rows'][] = [1,2,1,1];
$this->compareExpectations($state); $this->compareExpectations(static::$drv, $state);
} }
public function testClearALabelFromArticles() { public function testClearALabelFromArticles() {
Arsse::$db->labelArticlesSet("john.doe@example.com", 1, (new Context)->articles([1,5]), Database::ASSOC_REMOVE); Arsse::$db->labelArticlesSet("john.doe@example.com", 1, (new Context)->articles([1,5]), Database::ASSOC_REMOVE);
$state = $this->primeExpectations($this->data, $this->checkMembers); $state = $this->primeExpectations($this->data, $this->checkMembers);
$state['arsse_label_members']['rows'][0][3] = 0; $state['arsse_label_members']['rows'][0][3] = 0;
$this->compareExpectations($state); $this->compareExpectations(static::$drv, $state);
} }
public function testApplyALabelToArticlesByName() { public function testApplyALabelToArticlesByName() {
@ -502,26 +502,26 @@ trait SeriesLabel {
$state = $this->primeExpectations($this->data, $this->checkMembers); $state = $this->primeExpectations($this->data, $this->checkMembers);
$state['arsse_label_members']['rows'][4][3] = 1; $state['arsse_label_members']['rows'][4][3] = 1;
$state['arsse_label_members']['rows'][] = [1,2,1,1]; $state['arsse_label_members']['rows'][] = [1,2,1,1];
$this->compareExpectations($state); $this->compareExpectations(static::$drv, $state);
} }
public function testClearALabelFromArticlesByName() { public function testClearALabelFromArticlesByName() {
Arsse::$db->labelArticlesSet("john.doe@example.com", "Interesting", (new Context)->articles([1,5]), Database::ASSOC_REMOVE, true); Arsse::$db->labelArticlesSet("john.doe@example.com", "Interesting", (new Context)->articles([1,5]), Database::ASSOC_REMOVE, true);
$state = $this->primeExpectations($this->data, $this->checkMembers); $state = $this->primeExpectations($this->data, $this->checkMembers);
$state['arsse_label_members']['rows'][0][3] = 0; $state['arsse_label_members']['rows'][0][3] = 0;
$this->compareExpectations($state); $this->compareExpectations(static::$drv, $state);
} }
public function testApplyALabelToNoArticles() { public function testApplyALabelToNoArticles() {
Arsse::$db->labelArticlesSet("john.doe@example.com", 1, (new Context)->articles([10000])); Arsse::$db->labelArticlesSet("john.doe@example.com", 1, (new Context)->articles([10000]));
$state = $this->primeExpectations($this->data, $this->checkMembers); $state = $this->primeExpectations($this->data, $this->checkMembers);
$this->compareExpectations($state); $this->compareExpectations(static::$drv, $state);
} }
public function testClearALabelFromNoArticles() { public function testClearALabelFromNoArticles() {
Arsse::$db->labelArticlesSet("john.doe@example.com", 1, (new Context)->articles([10000]), Database::ASSOC_REMOVE); Arsse::$db->labelArticlesSet("john.doe@example.com", 1, (new Context)->articles([10000]), Database::ASSOC_REMOVE);
$state = $this->primeExpectations($this->data, $this->checkMembers); $state = $this->primeExpectations($this->data, $this->checkMembers);
$this->compareExpectations($state); $this->compareExpectations(static::$drv, $state);
} }
public function testReplaceArticlesOfALabel() { public function testReplaceArticlesOfALabel() {
@ -531,7 +531,7 @@ trait SeriesLabel {
$state['arsse_label_members']['rows'][2][3] = 0; $state['arsse_label_members']['rows'][2][3] = 0;
$state['arsse_label_members']['rows'][4][3] = 1; $state['arsse_label_members']['rows'][4][3] = 1;
$state['arsse_label_members']['rows'][] = [1,2,1,1]; $state['arsse_label_members']['rows'][] = [1,2,1,1];
$this->compareExpectations($state); $this->compareExpectations(static::$drv, $state);
} }
public function testPurgeArticlesOfALabel() { public function testPurgeArticlesOfALabel() {
@ -539,7 +539,7 @@ trait SeriesLabel {
$state = $this->primeExpectations($this->data, $this->checkMembers); $state = $this->primeExpectations($this->data, $this->checkMembers);
$state['arsse_label_members']['rows'][0][3] = 0; $state['arsse_label_members']['rows'][0][3] = 0;
$state['arsse_label_members']['rows'][2][3] = 0; $state['arsse_label_members']['rows'][2][3] = 0;
$this->compareExpectations($state); $this->compareExpectations(static::$drv, $state);
} }
public function testApplyALabelToArticlesWithoutAuthority() { public function testApplyALabelToArticlesWithoutAuthority() {

10
tests/cases/Database/SeriesMeta.php

@ -28,7 +28,7 @@ trait SeriesMeta {
// as far as tests are concerned the schema version is part of the expectations primed into the database // as far as tests are concerned the schema version is part of the expectations primed into the database
array_unshift($this->data['arsse_meta']['rows'], ['schema_version', "".Database::SCHEMA_VERSION]); array_unshift($this->data['arsse_meta']['rows'], ['schema_version', "".Database::SCHEMA_VERSION]);
// but it's already been inserted by the driver, so we prime without it // but it's already been inserted by the driver, so we prime without it
$this->primeDatabase($dataBare); $this->primeDatabase(static::$drv, $dataBare);
} }
protected function tearDownSeriesMeta() { protected function tearDownSeriesMeta() {
@ -39,7 +39,7 @@ trait SeriesMeta {
$this->assertTrue(Arsse::$db->metaSet("favourite", "Cygnus X-1")); $this->assertTrue(Arsse::$db->metaSet("favourite", "Cygnus X-1"));
$state = $this->primeExpectations($this->data, ['arsse_meta' => ['key','value']]); $state = $this->primeExpectations($this->data, ['arsse_meta' => ['key','value']]);
$state['arsse_meta']['rows'][] = ["favourite","Cygnus X-1"]; $state['arsse_meta']['rows'][] = ["favourite","Cygnus X-1"];
$this->compareExpectations($state); $this->compareExpectations(static::$drv, $state);
} }
public function testAddANewTypedValue() { public function testAddANewTypedValue() {
@ -52,14 +52,14 @@ trait SeriesMeta {
$state['arsse_meta']['rows'][] = ["true","1"]; $state['arsse_meta']['rows'][] = ["true","1"];
$state['arsse_meta']['rows'][] = ["false","0"]; $state['arsse_meta']['rows'][] = ["false","0"];
$state['arsse_meta']['rows'][] = ["millennium","2000-01-01 00:00:00"]; $state['arsse_meta']['rows'][] = ["millennium","2000-01-01 00:00:00"];
$this->compareExpectations($state); $this->compareExpectations(static::$drv, $state);
} }
public function testChangeAnExistingValue() { public function testChangeAnExistingValue() {
$this->assertTrue(Arsse::$db->metaSet("album", "Hemispheres")); $this->assertTrue(Arsse::$db->metaSet("album", "Hemispheres"));
$state = $this->primeExpectations($this->data, ['arsse_meta' => ['key','value']]); $state = $this->primeExpectations($this->data, ['arsse_meta' => ['key','value']]);
$state['arsse_meta']['rows'][1][1] = "Hemispheres"; $state['arsse_meta']['rows'][1][1] = "Hemispheres";
$this->compareExpectations($state); $this->compareExpectations(static::$drv, $state);
} }
public function testRemoveAValue() { public function testRemoveAValue() {
@ -67,7 +67,7 @@ trait SeriesMeta {
$this->assertFalse(Arsse::$db->metaRemove("album")); $this->assertFalse(Arsse::$db->metaRemove("album"));
$state = $this->primeExpectations($this->data, ['arsse_meta' => ['key','value']]); $state = $this->primeExpectations($this->data, ['arsse_meta' => ['key','value']]);
unset($state['arsse_meta']['rows'][1]); unset($state['arsse_meta']['rows'][1]);
$this->compareExpectations($state); $this->compareExpectations(static::$drv, $state);
} }
public function testRetrieveAValue() { public function testRetrieveAValue() {

6
tests/cases/Database/SeriesSession.php

@ -69,7 +69,7 @@ trait SeriesSession {
// sessions near timeout should be refreshed automatically // sessions near timeout should be refreshed automatically
$state = $this->primeExpectations($this->data, ['arsse_sessions' => ["id", "created", "expires", "user"]]); $state = $this->primeExpectations($this->data, ['arsse_sessions' => ["id", "created", "expires", "user"]]);
$state['arsse_sessions']['rows'][3][2] = Date::transform(Date::add(Arsse::$conf->userSessionTimeout, $now), "sql"); $state['arsse_sessions']['rows'][3][2] = Date::transform(Date::add(Arsse::$conf->userSessionTimeout, $now), "sql");
$this->compareExpectations($state); $this->compareExpectations(static::$drv, $state);
// session resumption should not check authorization // session resumption should not check authorization
Phake::when(Arsse::$user)->authorize->thenReturn(false); Phake::when(Arsse::$user)->authorize->thenReturn(false);
$this->assertArraySubset($exp1, Arsse::$db->sessionResume("80fa94c1a11f11e78667001e673b2560")); $this->assertArraySubset($exp1, Arsse::$db->sessionResume("80fa94c1a11f11e78667001e673b2560"));
@ -96,7 +96,7 @@ trait SeriesSession {
$now = time(); $now = time();
$state = $this->primeExpectations($this->data, ['arsse_sessions' => ["id", "created", "expires", "user"]]); $state = $this->primeExpectations($this->data, ['arsse_sessions' => ["id", "created", "expires", "user"]]);
$state['arsse_sessions']['rows'][] = [$id, Date::transform($now, "sql"), Date::transform(Date::add(Arsse::$conf->userSessionTimeout, $now), "sql"), $user]; $state['arsse_sessions']['rows'][] = [$id, Date::transform($now, "sql"), Date::transform(Date::add(Arsse::$conf->userSessionTimeout, $now), "sql"), $user];
$this->compareExpectations($state); $this->compareExpectations(static::$drv, $state);
} }
public function testCreateASessionWithoutAuthority() { public function testCreateASessionWithoutAuthority() {
@ -111,7 +111,7 @@ trait SeriesSession {
$this->assertTrue(Arsse::$db->sessionDestroy($user, $id)); $this->assertTrue(Arsse::$db->sessionDestroy($user, $id));
$state = $this->primeExpectations($this->data, ['arsse_sessions' => ["id", "created", "expires", "user"]]); $state = $this->primeExpectations($this->data, ['arsse_sessions' => ["id", "created", "expires", "user"]]);
unset($state['arsse_sessions']['rows'][0]); unset($state['arsse_sessions']['rows'][0]);
$this->compareExpectations($state); $this->compareExpectations(static::$drv, $state);
// destroying a session which does not exist is not an error // destroying a session which does not exist is not an error
$this->assertFalse(Arsse::$db->sessionDestroy($user, $id)); $this->assertFalse(Arsse::$db->sessionDestroy($user, $id));
} }

16
tests/cases/Database/SeriesSubscription.php

@ -160,7 +160,7 @@ trait SeriesSubscription {
'arsse_subscriptions' => ['id','owner','feed'], 'arsse_subscriptions' => ['id','owner','feed'],
]); ]);
$state['arsse_subscriptions']['rows'][] = [$subID,$this->user,1]; $state['arsse_subscriptions']['rows'][] = [$subID,$this->user,1];
$this->compareExpectations($state); $this->compareExpectations(static::$drv, $state);
} }
public function testAddASubscriptionToANewFeed() { public function testAddASubscriptionToANewFeed() {
@ -177,7 +177,7 @@ trait SeriesSubscription {
]); ]);
$state['arsse_feeds']['rows'][] = [$feedID,$url,"",""]; $state['arsse_feeds']['rows'][] = [$feedID,$url,"",""];
$state['arsse_subscriptions']['rows'][] = [$subID,$this->user,$feedID]; $state['arsse_subscriptions']['rows'][] = [$subID,$this->user,$feedID];
$this->compareExpectations($state); $this->compareExpectations(static::$drv, $state);
} }
public function testAddASubscriptionToANewFeedViaDiscovery() { public function testAddASubscriptionToANewFeedViaDiscovery() {
@ -195,7 +195,7 @@ trait SeriesSubscription {
]); ]);
$state['arsse_feeds']['rows'][] = [$feedID,$discovered,"",""]; $state['arsse_feeds']['rows'][] = [$feedID,$discovered,"",""];
$state['arsse_subscriptions']['rows'][] = [$subID,$this->user,$feedID]; $state['arsse_subscriptions']['rows'][] = [$subID,$this->user,$feedID];
$this->compareExpectations($state); $this->compareExpectations(static::$drv, $state);
} }
public function testAddASubscriptionToAnInvalidFeed() { public function testAddASubscriptionToAnInvalidFeed() {
@ -211,7 +211,7 @@ trait SeriesSubscription {
'arsse_feeds' => ['id','url','username','password'], 'arsse_feeds' => ['id','url','username','password'],
'arsse_subscriptions' => ['id','owner','feed'], 'arsse_subscriptions' => ['id','owner','feed'],
]); ]);
$this->compareExpectations($state); $this->compareExpectations(static::$drv, $state);
$this->assertException("invalidUrl", "Feed"); $this->assertException("invalidUrl", "Feed");
throw $e; throw $e;
} }
@ -238,7 +238,7 @@ trait SeriesSubscription {
'arsse_subscriptions' => ['id','owner','feed'], 'arsse_subscriptions' => ['id','owner','feed'],
]); ]);
array_shift($state['arsse_subscriptions']['rows']); array_shift($state['arsse_subscriptions']['rows']);
$this->compareExpectations($state); $this->compareExpectations(static::$drv, $state);
} }
public function testRemoveAMissingSubscription() { public function testRemoveAMissingSubscription() {
@ -377,15 +377,15 @@ trait SeriesSubscription {
'arsse_subscriptions' => ['id','owner','feed','title','folder','pinned','order_type'], 'arsse_subscriptions' => ['id','owner','feed','title','folder','pinned','order_type'],
]); ]);
$state['arsse_subscriptions']['rows'][0] = [1,"john.doe@example.com",2,"Ook Ook",3,0,0]; $state['arsse_subscriptions']['rows'][0] = [1,"john.doe@example.com",2,"Ook Ook",3,0,0];
$this->compareExpectations($state); $this->compareExpectations(static::$drv, $state);
Arsse::$db->subscriptionPropertiesSet($this->user, 1, [ Arsse::$db->subscriptionPropertiesSet($this->user, 1, [
'title' => null, 'title' => null,
]); ]);
$state['arsse_subscriptions']['rows'][0] = [1,"john.doe@example.com",2,null,3,0,0]; $state['arsse_subscriptions']['rows'][0] = [1,"john.doe@example.com",2,null,3,0,0];
$this->compareExpectations($state); $this->compareExpectations(static::$drv, $state);
// making no changes is a valid result // making no changes is a valid result
Arsse::$db->subscriptionPropertiesSet($this->user, 1, ['unhinged' => true]); Arsse::$db->subscriptionPropertiesSet($this->user, 1, ['unhinged' => true]);
$this->compareExpectations($state); $this->compareExpectations(static::$drv, $state);
} }
public function testMoveASubscriptionToAMissingFolder() { public function testMoveASubscriptionToAMissingFolder() {

26
tests/cases/Database/SeriesTag.php

@ -117,7 +117,7 @@ trait SeriesTag {
Phake::verify(Arsse::$user)->authorize($user, "tagAdd"); Phake::verify(Arsse::$user)->authorize($user, "tagAdd");
$state = $this->primeExpectations($this->data, $this->checkTags); $state = $this->primeExpectations($this->data, $this->checkTags);
$state['arsse_tags']['rows'][] = [$tagID, $user, "Entertaining"]; $state['arsse_tags']['rows'][] = [$tagID, $user, "Entertaining"];
$this->compareExpectations($state); $this->compareExpectations(static::$drv, $state);
} }
public function testAddADuplicateTag() { public function testAddADuplicateTag() {
@ -173,7 +173,7 @@ trait SeriesTag {
Phake::verify(Arsse::$user)->authorize("john.doe@example.com", "tagRemove"); Phake::verify(Arsse::$user)->authorize("john.doe@example.com", "tagRemove");
$state = $this->primeExpectations($this->data, $this->checkTags); $state = $this->primeExpectations($this->data, $this->checkTags);
array_shift($state['arsse_tags']['rows']); array_shift($state['arsse_tags']['rows']);
$this->compareExpectations($state); $this->compareExpectations(static::$drv, $state);
} }
public function testRemoveATagByName() { public function testRemoveATagByName() {
@ -181,7 +181,7 @@ trait SeriesTag {
Phake::verify(Arsse::$user)->authorize("john.doe@example.com", "tagRemove"); Phake::verify(Arsse::$user)->authorize("john.doe@example.com", "tagRemove");
$state = $this->primeExpectations($this->data, $this->checkTags); $state = $this->primeExpectations($this->data, $this->checkTags);
array_shift($state['arsse_tags']['rows']); array_shift($state['arsse_tags']['rows']);
$this->compareExpectations($state); $this->compareExpectations(static::$drv, $state);
} }
public function testRemoveAMissingTag() { public function testRemoveAMissingTag() {
@ -255,7 +255,7 @@ trait SeriesTag {
Phake::verify(Arsse::$user)->authorize("john.doe@example.com", "tagPropertiesSet"); Phake::verify(Arsse::$user)->authorize("john.doe@example.com", "tagPropertiesSet");
$state = $this->primeExpectations($this->data, $this->checkTags); $state = $this->primeExpectations($this->data, $this->checkTags);
$state['arsse_tags']['rows'][0][2] = "Curious"; $state['arsse_tags']['rows'][0][2] = "Curious";
$this->compareExpectations($state); $this->compareExpectations(static::$drv, $state);
} }
public function testRenameATagByName() { public function testRenameATagByName() {
@ -263,7 +263,7 @@ trait SeriesTag {
Phake::verify(Arsse::$user)->authorize("john.doe@example.com", "tagPropertiesSet"); Phake::verify(Arsse::$user)->authorize("john.doe@example.com", "tagPropertiesSet");
$state = $this->primeExpectations($this->data, $this->checkTags); $state = $this->primeExpectations($this->data, $this->checkTags);
$state['arsse_tags']['rows'][0][2] = "Curious"; $state['arsse_tags']['rows'][0][2] = "Curious";
$this->compareExpectations($state); $this->compareExpectations(static::$drv, $state);
} }
public function testRenameATagToTheEmptyString() { public function testRenameATagToTheEmptyString() {
@ -345,14 +345,14 @@ trait SeriesTag {
$state = $this->primeExpectations($this->data, $this->checkMembers); $state = $this->primeExpectations($this->data, $this->checkMembers);
$state['arsse_tag_members']['rows'][1][2] = 1; $state['arsse_tag_members']['rows'][1][2] = 1;
$state['arsse_tag_members']['rows'][] = [1,4,1]; $state['arsse_tag_members']['rows'][] = [1,4,1];
$this->compareExpectations($state); $this->compareExpectations(static::$drv, $state);
} }
public function testClearATagFromSubscriptions() { public function testClearATagFromSubscriptions() {
Arsse::$db->tagSubscriptionsSet("john.doe@example.com", 1, [1,3], Database::ASSOC_REMOVE); Arsse::$db->tagSubscriptionsSet("john.doe@example.com", 1, [1,3], Database::ASSOC_REMOVE);
$state = $this->primeExpectations($this->data, $this->checkMembers); $state = $this->primeExpectations($this->data, $this->checkMembers);
$state['arsse_tag_members']['rows'][0][2] = 0; $state['arsse_tag_members']['rows'][0][2] = 0;
$this->compareExpectations($state); $this->compareExpectations(static::$drv, $state);
} }
public function testApplyATagToSubscriptionsByName() { public function testApplyATagToSubscriptionsByName() {
@ -360,26 +360,26 @@ trait SeriesTag {
$state = $this->primeExpectations($this->data, $this->checkMembers); $state = $this->primeExpectations($this->data, $this->checkMembers);
$state['arsse_tag_members']['rows'][1][2] = 1; $state['arsse_tag_members']['rows'][1][2] = 1;
$state['arsse_tag_members']['rows'][] = [1,4,1]; $state['arsse_tag_members']['rows'][] = [1,4,1];
$this->compareExpectations($state); $this->compareExpectations(static::$drv, $state);
} }
public function testClearATagFromSubscriptionsByName() { public function testClearATagFromSubscriptionsByName() {
Arsse::$db->tagSubscriptionsSet("john.doe@example.com", "Interesting", [1,3], Database::ASSOC_REMOVE, true); Arsse::$db->tagSubscriptionsSet("john.doe@example.com", "Interesting", [1,3], Database::ASSOC_REMOVE, true);
$state = $this->primeExpectations($this->data, $this->checkMembers); $state = $this->primeExpectations($this->data, $this->checkMembers);
$state['arsse_tag_members']['rows'][0][2] = 0; $state['arsse_tag_members']['rows'][0][2] = 0;
$this->compareExpectations($state); $this->compareExpectations(static::$drv, $state);
} }
public function testApplyATagToNoSubscriptionsByName() { public function testApplyATagToNoSubscriptionsByName() {
Arsse::$db->tagSubscriptionsSet("john.doe@example.com", "Interesting", [], Database::ASSOC_ADD, true); Arsse::$db->tagSubscriptionsSet("john.doe@example.com", "Interesting", [], Database::ASSOC_ADD, true);
$state = $this->primeExpectations($this->data, $this->checkMembers); $state = $this->primeExpectations($this->data, $this->checkMembers);
$this->compareExpectations($state); $this->compareExpectations(static::$drv, $state);
} }
public function testClearATagFromNoSubscriptionsByName() { public function testClearATagFromNoSubscriptionsByName() {
Arsse::$db->tagSubscriptionsSet("john.doe@example.com", "Interesting", [], Database::ASSOC_REMOVE, true); Arsse::$db->tagSubscriptionsSet("john.doe@example.com", "Interesting", [], Database::ASSOC_REMOVE, true);
$state = $this->primeExpectations($this->data, $this->checkMembers); $state = $this->primeExpectations($this->data, $this->checkMembers);
$this->compareExpectations($state); $this->compareExpectations(static::$drv, $state);
} }
public function testReplaceSubscriptionsOfATag() { public function testReplaceSubscriptionsOfATag() {
@ -389,7 +389,7 @@ trait SeriesTag {
$state['arsse_tag_members']['rows'][1][2] = 1; $state['arsse_tag_members']['rows'][1][2] = 1;
$state['arsse_tag_members']['rows'][2][2] = 0; $state['arsse_tag_members']['rows'][2][2] = 0;
$state['arsse_tag_members']['rows'][] = [1,4,1]; $state['arsse_tag_members']['rows'][] = [1,4,1];
$this->compareExpectations($state); $this->compareExpectations(static::$drv, $state);
} }
public function testPurgeSubscriptionsOfATag() { public function testPurgeSubscriptionsOfATag() {
@ -397,7 +397,7 @@ trait SeriesTag {
$state = $this->primeExpectations($this->data, $this->checkMembers); $state = $this->primeExpectations($this->data, $this->checkMembers);
$state['arsse_tag_members']['rows'][0][2] = 0; $state['arsse_tag_members']['rows'][0][2] = 0;
$state['arsse_tag_members']['rows'][2][2] = 0; $state['arsse_tag_members']['rows'][2][2] = 0;
$this->compareExpectations($state); $this->compareExpectations(static::$drv, $state);
} }
public function testApplyATagToSubscriptionsWithoutAuthority() { public function testApplyATagToSubscriptionsWithoutAuthority() {

12
tests/cases/Database/SeriesToken.php

@ -87,13 +87,13 @@ trait SeriesToken {
$state = $this->primeExpectations($this->data, ['arsse_tokens' => ["id", "class", "expires", "user"]]); $state = $this->primeExpectations($this->data, ['arsse_tokens' => ["id", "class", "expires", "user"]]);
$id = Arsse::$db->tokenCreate($user, "fever.login"); $id = Arsse::$db->tokenCreate($user, "fever.login");
$state['arsse_tokens']['rows'][] = [$id, "fever.login", null, $user]; $state['arsse_tokens']['rows'][] = [$id, "fever.login", null, $user];
$this->compareExpectations($state); $this->compareExpectations(static::$drv, $state);
$id = Arsse::$db->tokenCreate($user, "fever.login", null, new \DateTime("2020-01-01T00:00:00Z")); $id = Arsse::$db->tokenCreate($user, "fever.login", null, new \DateTime("2020-01-01T00:00:00Z"));
$state['arsse_tokens']['rows'][] = [$id, "fever.login", "2020-01-01 00:00:00", $user]; $state['arsse_tokens']['rows'][] = [$id, "fever.login", "2020-01-01 00:00:00", $user];
$this->compareExpectations($state); $this->compareExpectations(static::$drv, $state);
Arsse::$db->tokenCreate($user, "fever.login", "token!", new \DateTime("2021-01-01T00:00:00Z")); Arsse::$db->tokenCreate($user, "fever.login", "token!", new \DateTime("2021-01-01T00:00:00Z"));
$state['arsse_tokens']['rows'][] = ["token!", "fever.login", "2021-01-01 00:00:00", $user]; $state['arsse_tokens']['rows'][] = ["token!", "fever.login", "2021-01-01 00:00:00", $user];
$this->compareExpectations($state); $this->compareExpectations(static::$drv, $state);
} }
public function testCreateATokenForAMissingUser() { public function testCreateATokenForAMissingUser() {
@ -113,7 +113,7 @@ trait SeriesToken {
$this->assertTrue(Arsse::$db->tokenRevoke($user, "fever.login", $id)); $this->assertTrue(Arsse::$db->tokenRevoke($user, "fever.login", $id));
$state = $this->primeExpectations($this->data, ['arsse_tokens' => ["id", "expires", "user"]]); $state = $this->primeExpectations($this->data, ['arsse_tokens' => ["id", "expires", "user"]]);
unset($state['arsse_tokens']['rows'][0]); unset($state['arsse_tokens']['rows'][0]);
$this->compareExpectations($state); $this->compareExpectations(static::$drv, $state);
// revoking a token which does not exist is not an error // revoking a token which does not exist is not an error
$this->assertFalse(Arsse::$db->tokenRevoke($user, "fever.login", $id)); $this->assertFalse(Arsse::$db->tokenRevoke($user, "fever.login", $id));
} }
@ -124,10 +124,10 @@ trait SeriesToken {
$this->assertTrue(Arsse::$db->tokenRevoke($user, "fever.login")); $this->assertTrue(Arsse::$db->tokenRevoke($user, "fever.login"));
unset($state['arsse_tokens']['rows'][0]); unset($state['arsse_tokens']['rows'][0]);
unset($state['arsse_tokens']['rows'][1]); unset($state['arsse_tokens']['rows'][1]);
$this->compareExpectations($state); $this->compareExpectations(static::$drv, $state);
$this->assertTrue(Arsse::$db->tokenRevoke($user, "class.class")); $this->assertTrue(Arsse::$db->tokenRevoke($user, "class.class"));
unset($state['arsse_tokens']['rows'][2]); unset($state['arsse_tokens']['rows'][2]);
$this->compareExpectations($state); $this->compareExpectations(static::$drv, $state);
// revoking tokens which do not exist is not an error // revoking tokens which do not exist is not an error
$this->assertFalse(Arsse::$db->tokenRevoke($user, "unknown.class")); $this->assertFalse(Arsse::$db->tokenRevoke($user, "unknown.class"));
} }

6
tests/cases/Database/SeriesUser.php

@ -36,7 +36,7 @@ trait SeriesUser {
$this->assertFalse(Arsse::$db->userExists("jane.doe@example.org")); $this->assertFalse(Arsse::$db->userExists("jane.doe@example.org"));
Phake::verify(Arsse::$user)->authorize("jane.doe@example.com", "userExists"); Phake::verify(Arsse::$user)->authorize("jane.doe@example.com", "userExists");
Phake::verify(Arsse::$user)->authorize("jane.doe@example.org", "userExists"); Phake::verify(Arsse::$user)->authorize("jane.doe@example.org", "userExists");
$this->compareExpectations($this->data); $this->compareExpectations(static::$drv, $this->data);
} }
public function testCheckThatAUserExistsWithoutAuthority() { public function testCheckThatAUserExistsWithoutAuthority() {
@ -68,7 +68,7 @@ trait SeriesUser {
Phake::verify(Arsse::$user)->authorize("john.doe@example.org", "userAdd"); Phake::verify(Arsse::$user)->authorize("john.doe@example.org", "userAdd");
$state = $this->primeExpectations($this->data, ['arsse_users' => ['id']]); $state = $this->primeExpectations($this->data, ['arsse_users' => ['id']]);
$state['arsse_users']['rows'][] = ["john.doe@example.org"]; $state['arsse_users']['rows'][] = ["john.doe@example.org"];
$this->compareExpectations($state); $this->compareExpectations(static::$drv, $state);
} }
public function testAddAnExistingUser() { public function testAddAnExistingUser() {
@ -87,7 +87,7 @@ trait SeriesUser {
Phake::verify(Arsse::$user)->authorize("admin@example.net", "userRemove"); Phake::verify(Arsse::$user)->authorize("admin@example.net", "userRemove");
$state = $this->primeExpectations($this->data, ['arsse_users' => ['id']]); $state = $this->primeExpectations($this->data, ['arsse_users' => ['id']]);
array_shift($state['arsse_users']['rows']); array_shift($state['arsse_users']['rows']);
$this->compareExpectations($state); $this->compareExpectations(static::$drv, $state);
} }
public function testRemoveAMissingUser() { public function testRemoveAMissingUser() {

121
tests/lib/AbstractTest.php

@ -9,14 +9,15 @@ namespace JKingWeb\Arsse\Test;
use JKingWeb\Arsse\Exception; use JKingWeb\Arsse\Exception;
use JKingWeb\Arsse\Arsse; use JKingWeb\Arsse\Arsse;
use JKingWeb\Arsse\Conf; use JKingWeb\Arsse\Conf;
use JKingWeb\Arsse\CLI; use JKingWeb\Arsse\Db\Driver;
use JKingWeb\Arsse\Db\Result;
use JKingWeb\Arsse\Misc\Date; use JKingWeb\Arsse\Misc\Date;
use JKingWeb\Arsse\Misc\ValueInfo;
use Psr\Http\Message\MessageInterface; use Psr\Http\Message\MessageInterface;
use Psr\Http\Message\RequestInterface; use Psr\Http\Message\RequestInterface;
use Psr\Http\Message\ServerRequestInterface; use Psr\Http\Message\ServerRequestInterface;
use Psr\Http\Message\ResponseInterface; use Psr\Http\Message\ResponseInterface;
use Zend\Diactoros\Response\JsonResponse; use Zend\Diactoros\Response\JsonResponse;
use Zend\Diactoros\Response\EmptyResponse;
/** @coversNothing */ /** @coversNothing */
abstract class AbstractTest extends \PHPUnit\Framework\TestCase { abstract class AbstractTest extends \PHPUnit\Framework\TestCase {
@ -135,4 +136,120 @@ abstract class AbstractTest extends \PHPUnit\Framework\TestCase {
} }
return $value; return $value;
} }
public function primeDatabase(Driver $drv, array $data): bool {
$tr = $drv->begin();
foreach ($data as $table => $info) {
$cols = array_map(function($v) {
return '"'.str_replace('"', '""', $v).'"';
}, array_keys($info['columns']));
$cols = implode(",", $cols);
$bindings = array_values($info['columns']);
$params = implode(",", array_fill(0, sizeof($info['columns']), "?"));
$s = $drv->prepareArray("INSERT INTO $table($cols) values($params)", $bindings);
foreach ($info['rows'] as $row) {
$s->runArray($row);
}
}
$tr->commit();
$this->primed = true;
return true;
}
public function compareExpectations(Driver $drv, array $expected): bool {
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 values for array index $index does not match the number of fields");
$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;
}
}
if ($row===$test) {
$data[$index] = $test;
break;
}
}
$this->assertContains($row, $data, "Table $table does not contain record at array index $index.");
$found = array_search($row, $data, true);
unset($data[$found]);
}
$this->assertSame([], $data);
}
return true;
}
public function primeExpectations(array $source, array $tableSpecs = null): array {
$out = [];
foreach ($tableSpecs as $table => $columns) {
// make sure the source has the table we want
$this->assertArrayHasKey($table, $source, "Source for expectations does not contain requested table $table.");
$out[$table] = [
'columns' => [],
'rows' => array_fill(0, sizeof($source[$table]['rows']), []),
];
// make sure the source has all the columns we want for the table
$cols = array_flip($columns);
$cols = array_intersect_key($cols, $source[$table]['columns']);
$this->assertSame(array_keys($cols), $columns, "Source for table $table does not contain all requested columns");
// get a map of source value offsets and keys
$targets = array_flip(array_keys($source[$table]['columns']));
foreach ($cols as $key => $order) {
// fill the column-spec
$out[$table]['columns'][$key] = $source[$table]['columns'][$key];
foreach ($source[$table]['rows'] as $index => $row) {
// fill each row column-wise with re-ordered values
$out[$table]['rows'][$index][$order] = $row[$targets[$key]];
}
}
}
return $out;
}
public function assertResult(array $expected, Result $data) {
$data = $data->getAll();
$this->assertCount(sizeof($expected), $data, "Number of result rows (".sizeof($data).") differs from number of expected rows (".sizeof($expected).")");
if (sizeof($expected)) {
// make sure the expectations are consistent
foreach ($expected as $exp) {
if (!isset($keys)) {
$keys = $exp;
continue;
}
$this->assertSame(array_keys($keys), array_keys($exp), "Result set expectations are irregular");
}
// filter the result set to contain just the desired keys (we don't care if the result has extra keys)
$rows = [];
foreach ($data as $row) {
$rows[] = array_intersect_key($row, $keys);
}
// compare the result set to the expectations
foreach ($rows as $row) {
$this->assertContains($row, $expected, "Result set contains unexpected record.");
$found = array_search($row, $expected);
unset($expected[$found]);
}
$this->assertArraySubset($expected, [], false, "Expectations not in result set.");
}
}
} }

Loading…
Cancel
Save