Browse Source

Merge master

microsub
J. King 5 years ago
parent
commit
0513b606c2
  1. 6
      CHANGELOG
  2. 2
      lib/Arsse.php
  3. 10
      lib/Db/SQLite3/Driver.php
  4. 10
      tests/cases/CLI/TestCLI.php
  5. 2
      tests/cases/Database/Base.php
  6. 24
      tests/cases/Misc/TestValueInfo.php
  7. 2
      tests/cases/REST/NextCloudNews/TestV1_2.php
  8. 22
      tests/cases/REST/TinyTinyRSS/TestAPI.php
  9. 4
      tests/lib/AbstractTest.php
  10. 1
      tests/phpunit.xml

6
CHANGELOG

@ -1,3 +1,9 @@
Version 0.5.1 (2018-11-10)
==========================
Bug fixes:
- Correctly initialize PDO database driver
Version 0.5.0 (2018-11-07)
==========================

2
lib/Arsse.php

@ -7,7 +7,7 @@ declare(strict_types=1);
namespace JKingWeb\Arsse;
class Arsse {
const VERSION = "0.5.0";
const VERSION = "0.5.1";
/** @var Lang */
public static $lang;

10
lib/Db/SQLite3/Driver.php

@ -20,15 +20,17 @@ class Driver extends \JKingWeb\Arsse\Db\AbstractDriver {
protected $db;
public function __construct(string $dbFile = null) {
public function __construct(string $dbFile = null, string $dbKey = null) {
// check to make sure required extension is loaded
if (!self::requirementsMet()) {
throw new Exception("extMissing", self::driverName()); // @codeCoverageIgnore
if (!static::requirementsMet()) {
throw new Exception("extMissing", static::driverName()); // @codeCoverageIgnore
}
// if no database file is specified in the configuration, use a suitable default
$dbFile = $dbFile ?? Arsse::$conf->dbSQLite3File ?? \JKingWeb\Arsse\BASE."arsse.db";
$dbKey = $dbKey ?? Arsse::$conf->dbSQLite3Key;
$timeout = Arsse::$conf->dbSQLite3Timeout * 1000;
try {
$this->makeConnection($dbFile, Arsse::$conf->dbSQLite3Key);
$this->makeConnection($dbFile, $dbKey);
} catch (\Throwable $e) {
// if opening the database doesn't work, check various pre-conditions to find out what the problem might be
$files = [

10
tests/cases/CLI/TestCLI.php

@ -114,7 +114,7 @@ class TestCLI extends \JKingWeb\Arsse\Test\AbstractTest {
/** @dataProvider provideUserList */
public function testListUsers(string $cmd, array $list, int $exitStatus, string $output) {
// Phake is somehow unable to mock the User class correctly, so we use PHPUnit's mocks instead
// FIXME: Phake is somehow unable to mock the User class correctly, so we use PHPUnit's mocks instead
Arsse::$user = $this->createMock(User::class);
Arsse::$user->method("list")->willReturn($list);
$this->assertConsole(new CLI, $cmd, $exitStatus, $output);
@ -133,7 +133,7 @@ class TestCLI extends \JKingWeb\Arsse\Test\AbstractTest {
/** @dataProvider provideUserAdditions */
public function testAddAUser(string $cmd, int $exitStatus, string $output) {
// Phake is somehow unable to mock the User class correctly, so we use PHPUnit's mocks instead
// FIXME: Phake is somehow unable to mock the User class correctly, so we use PHPUnit's mocks instead
Arsse::$user = $this->createMock(User::class);
Arsse::$user->method("add")->will($this->returnCallback(function($user, $pass = null) {
switch ($user) {
@ -156,7 +156,7 @@ class TestCLI extends \JKingWeb\Arsse\Test\AbstractTest {
/** @dataProvider provideUserAuthentication */
public function testAuthenticateAUser(string $cmd, int $exitStatus, string $output) {
// Phake is somehow unable to mock the User class correctly, so we use PHPUnit's mocks instead
// FIXME: Phake is somehow unable to mock the User class correctly, so we use PHPUnit's mocks instead
Arsse::$user = $this->createMock(User::class);
Arsse::$user->method("auth")->will($this->returnCallback(function($user, $pass) {
return (
@ -179,7 +179,7 @@ class TestCLI extends \JKingWeb\Arsse\Test\AbstractTest {
/** @dataProvider provideUserRemovals */
public function testRemoveAUser(string $cmd, int $exitStatus, string $output) {
// Phake is somehow unable to mock the User class correctly, so we use PHPUnit's mocks instead
// FIXME: Phake is somehow unable to mock the User class correctly, so we use PHPUnit's mocks instead
Arsse::$user = $this->createMock(User::class);
Arsse::$user->method("remove")->will($this->returnCallback(function($user) {
if ($user == "john.doe@example.com") {
@ -199,7 +199,7 @@ class TestCLI extends \JKingWeb\Arsse\Test\AbstractTest {
/** @dataProvider provideUserPasswordChanges */
public function testChangeAUserPassword(string $cmd, int $exitStatus, string $output) {
// Phake is somehow unable to mock the User class correctly, so we use PHPUnit's mocks instead
// FIXME: Phake is somehow unable to mock the User class correctly, so we use PHPUnit's mocks instead
Arsse::$user = $this->createMock(User::class);
Arsse::$user->method("passwordSet")->will($this->returnCallback(function($user, $pass = null) {
switch ($user) {

2
tests/cases/Database/Base.php

@ -225,7 +225,7 @@ abstract class Base extends \JKingWeb\Arsse\Test\AbstractTest {
$found = array_search($row, $expected);
unset($expected[$found]);
}
$this->assertArraySubset($expected, [], "Expectations not in result set.");
$this->assertArraySubset($expected, [], false, "Expectations not in result set.");
}
}
}

24
tests/cases/Misc/TestValueInfo.php

@ -411,26 +411,36 @@ class TestValueInfo extends \JKingWeb\Arsse\Test\AbstractTest {
[I::T_STRING, "String", ],
[I::T_ARRAY, "Array", ],
];
$assert = function($exp, $act, string $msg) {
if (is_null($exp)) {
$this->assertNull($act, $msg);
} elseif (is_float($exp) && is_nan($exp)) {
$this->assertNan($act, $msg);
} elseif (is_scalar($exp)) {
$this->assertSame($exp, $act, $msg);
} else {
$this->assertEquals($exp, $act, $msg);
}
};
foreach ($params as $index => $param) {
list($type, $name) = $param;
$this->assertNull(I::normalize(null, $type | I::M_STRICT | I::M_NULL), $name." null-passthrough test failed");
$assert(null, I::normalize(null, $type | I::M_STRICT | I::M_NULL), $name." null-passthrough test failed");
foreach ($tests as $test) {
list($exp, $pass) = $index ? $test[$index] : [$test[$index], true];
$value = $test[0];
$assert = (is_float($exp) && is_nan($exp) ? "assertNan" : (is_scalar($exp) ? "assertSame" : "assertEquals"));
$this->$assert($exp, I::normalize($value, $type), $name." test failed for value: ".var_export($value, true));
$assert($exp, I::normalize($value, $type), $name." test failed for value: ".var_export($value, true));
if ($pass) {
$this->$assert($exp, I::normalize($value, $type | I::M_DROP), $name." drop test failed for value: ".var_export($value, true));
$this->$assert($exp, I::normalize($value, $type | I::M_STRICT), $name." error test failed for value: ".var_export($value, true));
$assert($exp, I::normalize($value, $type | I::M_DROP), $name." drop test failed for value: ".var_export($value, true));
$assert($exp, I::normalize($value, $type | I::M_STRICT), $name." error test failed for value: ".var_export($value, true));
} else {
$this->assertNull(I::normalize($value, $type | I::M_DROP), $name." drop test failed for value: ".var_export($value, true));
$assert(null, I::normalize($value, $type | I::M_DROP), $name." drop test failed for value: ".var_export($value, true));
$exc = new ExceptionType("strictFailure", $type);
try {
$act = I::normalize($value, $type | I::M_STRICT);
} catch (ExceptionType $e) {
$act = $e;
} finally {
$this->assertEquals($exc, $act, $name." error test failed for value: ".var_export($value, true));
$assert($exc, $act, $name." error test failed for value: ".var_export($value, true));
}
}
}

2
tests/cases/REST/NextCloudNews/TestV1_2.php

@ -768,7 +768,7 @@ class TestV1_2 extends \JKingWeb\Arsse\Test\AbstractTest {
Phake::verify(Arsse::$db)->articleList(Arsse::$user->id, (new Context)->reverse(false)->limit(10)->oldestEdition(6), $this->anything()); // offset is one more than specified
Phake::verify(Arsse::$db)->articleList(Arsse::$user->id, (new Context)->reverse(true)->limit(5)->latestEdition(4), $this->anything()); // offset is one less than specified
Phake::verify(Arsse::$db)->articleList(Arsse::$user->id, (new Context)->reverse(true)->unread(true), $this->anything());
Phake::verify(Arsse::$db)->articleList(Arsse::$user->id, (new Context)->reverse(true)->markedSince($t), $this->anything());
Phake::verify(Arsse::$db)->articleList(Arsse::$user->id, $this->equalTo((new Context)->reverse(true)->markedSince($t), 2), $this->anything());
Phake::verify(Arsse::$db)->articleList(Arsse::$user->id, (new Context)->reverse(true)->limit(5), $this->anything());
}

22
tests/cases/REST/TinyTinyRSS/TestAPI.php

@ -1133,7 +1133,7 @@ LONG_STRING;
Phake::when(Arsse::$db)->folderList($this->anything(), null, false)->thenReturn(new Result($this->v($this->topFolders)));
Phake::when(Arsse::$db)->subscriptionList($this->anything())->thenReturn(new Result($this->v($this->subscriptions)));
Phake::when(Arsse::$db)->labelList($this->anything())->thenReturn(new Result($this->v($this->labels)));
Phake::when(Arsse::$db)->articleCount($this->anything(), $this->anything())->thenReturn(7); // FIXME: this should check an unread+modifiedSince context
Phake::when(Arsse::$db)->articleCount($this->anything(), $this->equalTo((new Context)->unread(true)->modifiedSince(Date::sub("PT24H")), 2))->thenReturn(7);
Phake::when(Arsse::$db)->articleStarred($this->anything())->thenReturn($this->v($this->starred));
$exp = [
[
@ -1197,7 +1197,7 @@ LONG_STRING;
Phake::when(Arsse::$db)->folderList($this->anything())->thenReturn(new Result($this->v($this->folders)));
Phake::when(Arsse::$db)->subscriptionList($this->anything())->thenReturn(new Result($this->v($this->subscriptions)));
Phake::when(Arsse::$db)->labelList($this->anything(), false)->thenReturn(new Result($this->v($this->usedLabels)));
Phake::when(Arsse::$db)->articleCount($this->anything(), $this->anything())->thenReturn(7); // FIXME: this should check an unread+modifiedSince context
Phake::when(Arsse::$db)->articleCount($this->anything(), $this->equalTo((new Context)->unread(true)->modifiedSince(Date::sub("PT24H")), 2))->thenReturn(7);
Phake::when(Arsse::$db)->articleStarred($this->anything())->thenReturn($this->v($this->starred));
$exp = [
['id' => "global-unread", 'counter' => 35],
@ -1318,7 +1318,7 @@ LONG_STRING;
Phake::when(Arsse::$db)->folderList($this->anything(), null, true)->thenReturn(new Result($this->v($this->folders)));
Phake::when(Arsse::$db)->subscriptionList($this->anything())->thenReturn(new Result($this->v($this->subscriptions)));
Phake::when(Arsse::$db)->labelList($this->anything(), true)->thenReturn(new Result($this->v($this->labels)));
Phake::when(Arsse::$db)->articleCount($this->anything(), $this->anything())->thenReturn(7); // FIXME: this should check an unread+modifiedSince context
Phake::when(Arsse::$db)->articleCount($this->anything(), $this->equalTo((new Context)->unread(true)->modifiedSince(Date::sub("PT24H")), 2))->thenReturn(7);
Phake::when(Arsse::$db)->articleStarred($this->anything())->thenReturn($this->v($this->starred));
// the expectations are packed tightly since they're very verbose; one can use var_export() (or convert to JSON) to pretty-print them
$exp = ['categories'=>['identifier'=>'id','label'=>'name','items'=>[['name'=>'Special','id'=>'CAT:-1','bare_id'=>-1,'type'=>'category','unread'=>0,'items'=>[['name'=>'All articles','id'=>'FEED:-4','bare_id'=>-4,'icon'=>'images/folder.png','unread'=>35,'type'=>'feed','auxcounter'=>0,'error'=>'','updated'=>'',],['name'=>'Fresh articles','id'=>'FEED:-3','bare_id'=>-3,'icon'=>'images/fresh.png','unread'=>7,'type'=>'feed','auxcounter'=>0,'error'=>'','updated'=>'',],['name'=>'Starred articles','id'=>'FEED:-1','bare_id'=>-1,'icon'=>'images/star.png','unread'=>4,'type'=>'feed','auxcounter'=>0,'error'=>'','updated'=>'',],['name'=>'Published articles','id'=>'FEED:-2','bare_id'=>-2,'icon'=>'images/feed.png','unread'=>0,'type'=>'feed','auxcounter'=>0,'error'=>'','updated'=>'',],['name'=>'Archived articles','id'=>'FEED:0','bare_id'=>0,'icon'=>'images/archive.png','unread'=>0,'type'=>'feed','auxcounter'=>0,'error'=>'','updated'=>'',],['name'=>'Recently read','id'=>'FEED:-6','bare_id'=>-6,'icon'=>'images/time.png','unread'=>0,'type'=>'feed','auxcounter'=>0,'error'=>'','updated'=>'',],],],['name'=>'Labels','id'=>'CAT:-2','bare_id'=>-2,'type'=>'category','unread'=>6,'items'=>[['name'=>'Fascinating','id'=>'FEED:-1027','bare_id'=>-1027,'unread'=>0,'icon'=>'images/label.png','type'=>'feed','auxcounter'=>0,'error'=>'','updated'=>'','fg_color'=>'','bg_color'=>'',],['name'=>'Interesting','id'=>'FEED:-1029','bare_id'=>-1029,'unread'=>0,'icon'=>'images/label.png','type'=>'feed','auxcounter'=>0,'error'=>'','updated'=>'','fg_color'=>'','bg_color'=>'',],['name'=>'Logical','id'=>'FEED:-1025','bare_id'=>-1025,'unread'=>0,'icon'=>'images/label.png','type'=>'feed','auxcounter'=>0,'error'=>'','updated'=>'','fg_color'=>'','bg_color'=>'',],],],['name'=>'Photography','id'=>'CAT:4','bare_id'=>4,'parent_id'=>null,'type'=>'category','auxcounter'=>0,'unread'=>0,'child_unread'=>0,'checkbox'=>false,'param'=>'(0 feeds)','items'=>[],],['name'=>'Politics','id'=>'CAT:3','bare_id'=>3,'parent_id'=>null,'type'=>'category','auxcounter'=>0,'unread'=>0,'child_unread'=>0,'checkbox'=>false,'param'=>'(3 feeds)','items'=>[['name'=>'Local','id'=>'CAT:5','bare_id'=>5,'parent_id'=>3,'type'=>'category','auxcounter'=>0,'unread'=>0,'child_unread'=>0,'checkbox'=>false,'param'=>'(1 feed)','items'=>[['name'=>'Toronto Star','id'=>'FEED:2','bare_id'=>2,'icon'=>'feed-icons/2.ico','error'=>'oops','param'=>'2011-11-11T11:11:11Z','unread'=>0,'auxcounter'=>0,'checkbox'=>false,],],],['name'=>'National','id'=>'CAT:6','bare_id'=>6,'parent_id'=>3,'type'=>'category','auxcounter'=>0,'unread'=>0,'child_unread'=>0,'checkbox'=>false,'param'=>'(2 feeds)','items'=>[['name'=>'CBC News','id'=>'FEED:4','bare_id'=>4,'icon'=>'feed-icons/4.ico','error'=>'','param'=>'2017-10-09T15:58:34Z','unread'=>0,'auxcounter'=>0,'checkbox'=>false,],['name'=>'Ottawa Citizen','id'=>'FEED:5','bare_id'=>5,'icon'=>false,'error'=>'','param'=>'2017-07-07T17:07:17Z','unread'=>0,'auxcounter'=>0,'checkbox'=>false,],],],],],['name'=>'Science','id'=>'CAT:1','bare_id'=>1,'parent_id'=>null,'type'=>'category','auxcounter'=>0,'unread'=>0,'child_unread'=>0,'checkbox'=>false,'param'=>'(2 feeds)','items'=>[['name'=>'Rocketry','id'=>'CAT:2','bare_id'=>2,'parent_id'=>1,'type'=>'category','auxcounter'=>0,'unread'=>0,'child_unread'=>0,'checkbox'=>false,'param'=>'(1 feed)','items'=>[['name'=>'NASA JPL','id'=>'FEED:1','bare_id'=>1,'icon'=>false,'error'=>'','param'=>'2017-09-15T22:54:16Z','unread'=>0,'auxcounter'=>0,'checkbox'=>false,],],],['name'=>'Ars Technica','id'=>'FEED:3','bare_id'=>3,'icon'=>'feed-icons/3.ico','error'=>'argh','param'=>'2016-05-23T06:40:02Z','unread'=>0,'auxcounter'=>0,'checkbox'=>false,],],],['name'=>'Uncategorized','id'=>'CAT:0','bare_id'=>0,'type'=>'category','auxcounter'=>0,'unread'=>0,'child_unread'=>0,'checkbox'=>false,'parent_id'=>null,'param'=>'(1 feed)','items'=>[['name'=>'Eurogamer','id'=>'FEED:6','bare_id'=>6,'icon'=>'feed-icons/6.ico','error'=>'','param'=>'2010-02-12T20:08:47Z','unread'=>0,'auxcounter'=>0,'checkbox'=>false,],],],],],];
@ -1375,7 +1375,7 @@ LONG_STRING;
for ($a = 0; $a < sizeof($in3); $a++) {
$this->assertMessage($exp, $this->req($in3[$a]), "Test $a failed");
}
Phake::verify(Arsse::$db)->articleMark($this->anything(), ['read' => true], (new Context)->modifiedSince($t));
Phake::verify(Arsse::$db)->articleMark($this->anything(), ['read' => true], $this->equalTo((new Context)->modifiedSince($t), 2)); // within two seconds
}
public function testRetrieveFeedList() {
@ -1405,7 +1405,7 @@ LONG_STRING;
];
// statistical mocks
Phake::when(Arsse::$db)->articleStarred($this->anything())->thenReturn($this->v($this->starred));
Phake::when(Arsse::$db)->articleCount->thenReturn(7); // FIXME: this should check an unread+modifiedSince context
Phake::when(Arsse::$db)->articleCount($this->anything(), $this->equalTo((new Context)->unread(true)->modifiedSince(Date::sub("PT24H")), 2))->thenReturn(7);
Phake::when(Arsse::$db)->articleCount($this->anything(), (new Context)->unread(true))->thenReturn(35);
// label mocks
Phake::when(Arsse::$db)->labelList($this->anything())->thenReturn(new Result($this->v($this->labels)));
@ -1793,9 +1793,9 @@ LONG_STRING;
$this->assertMessage($out1[$a], $this->req($in1[$a]), "Test $a failed");
}
for ($a = 0; $a < sizeof($in2); $a++) {
Phake::when(Arsse::$db)->articleList($this->anything(), (clone $c)->unread(false)->markedSince(Date::sub("PT24H")), ["id"])->thenReturn(new Result($this->v([['id' => 1001]])));
Phake::when(Arsse::$db)->articleList($this->anything(), (clone $c)->unread(true)->modifiedSince(Date::sub("PT24H")), ["id"])->thenReturn(new Result($this->v([['id' => 1002]])));
Phake::when(Arsse::$db)->articleList($this->anything(), (clone $c)->unread(true)->modifiedSince(Date::sub("PT24H"))->starred(true), ["id"])->thenReturn(new Result($this->v([['id' => 1003]])));
Phake::when(Arsse::$db)->articleList($this->anything(), $this->equalTo((clone $c)->unread(false)->markedSince(Date::sub("PT24H")), 2), ["id"])->thenReturn(new Result($this->v([['id' => 1001]])));
Phake::when(Arsse::$db)->articleList($this->anything(), $this->equalTo((clone $c)->unread(true)->modifiedSince(Date::sub("PT24H")), 2), ["id"])->thenReturn(new Result($this->v([['id' => 1002]])));
Phake::when(Arsse::$db)->articleList($this->anything(), $this->equalTo((clone $c)->unread(true)->modifiedSince(Date::sub("PT24H"))->starred(true), 2), ["id"])->thenReturn(new Result($this->v([['id' => 1003]])));
$this->assertMessage($out2[$a], $this->req($in2[$a]), "Test $a failed");
}
}
@ -1904,9 +1904,9 @@ LONG_STRING;
$this->assertMessage($out2[$a], $this->req($in2[$a]), "Test $a failed");
}
for ($a = 0; $a < sizeof($in3); $a++) {
Phake::when(Arsse::$db)->articleList($this->anything(), (clone $c)->unread(false)->markedSince(Date::sub("PT24H")), $this->anything())->thenReturn($this->generateHeadlines(1001));
Phake::when(Arsse::$db)->articleList($this->anything(), (clone $c)->unread(true)->modifiedSince(Date::sub("PT24H")), $this->anything())->thenReturn($this->generateHeadlines(1002));
Phake::when(Arsse::$db)->articleList($this->anything(), (clone $c)->unread(true)->modifiedSince(Date::sub("PT24H"))->starred(true), $this->anything())->thenReturn($this->generateHeadlines(1003));
Phake::when(Arsse::$db)->articleList($this->anything(), $this->equalTo((clone $c)->unread(false)->markedSince(Date::sub("PT24H")), 2), $this->anything())->thenReturn($this->generateHeadlines(1001));
Phake::when(Arsse::$db)->articleList($this->anything(), $this->equalTo((clone $c)->unread(true)->modifiedSince(Date::sub("PT24H")), 2), $this->anything())->thenReturn($this->generateHeadlines(1002));
Phake::when(Arsse::$db)->articleList($this->anything(), $this->equalTo((clone $c)->unread(true)->modifiedSince(Date::sub("PT24H"))->starred(true), 2), $this->anything())->thenReturn($this->generateHeadlines(1003));
$this->assertMessage($out3[$a], $this->req($in3[$a]), "Test $a failed");
}
}

4
tests/lib/AbstractTest.php

@ -69,7 +69,7 @@ abstract class AbstractTest extends \PHPUnit\Framework\TestCase {
}
}
protected function assertMessage(MessageInterface $exp, MessageInterface $act, string $text = null) {
protected function assertMessage(MessageInterface $exp, MessageInterface $act, string $text = '') {
if ($exp instanceof ResponseInterface) {
$this->assertInstanceOf(ResponseInterface::class, $act, $text);
$this->assertEquals($exp->getStatusCode(), $act->getStatusCode(), $text);
@ -91,7 +91,7 @@ abstract class AbstractTest extends \PHPUnit\Framework\TestCase {
$this->assertEquals($exp->getHeaders(), $act->getHeaders(), $text);
}
public function assertTime($exp, $test, string $msg = null) {
public function assertTime($exp, $test, string $msg = '') {
$test = $this->approximateTime($exp, $test);
$exp = Date::transform($exp, "iso8601");
$test = Date::transform($test, "iso8601");

1
tests/phpunit.xml

@ -7,7 +7,6 @@
convertWarningsToExceptions="false"
beStrictAboutTestsThatDoNotTestAnything="true"
beStrictAboutOutputDuringTests="true"
beStrictAboutTestSize="true"
stopOnError="true">
<filter>

Loading…
Cancel
Save