2019-03-19 02:49:47 +00:00
< ? php
/** @ license MIT
* Copyright 2017 J . King , Dustin Wilson et al .
* See LICENSE and AUTHORS files for details */
declare ( strict_types = 1 );
namespace JKingWeb\Arsse\TestCase\REST\Fever ;
use JKingWeb\Arsse\Arsse ;
use JKingWeb\Arsse\User ;
use JKingWeb\Arsse\Database ;
use JKingWeb\Arsse\Test\Result ;
use JKingWeb\Arsse\Context\Context ;
use JKingWeb\Arsse\Db\ExceptionInput ;
use JKingWeb\Arsse\Db\Transaction ;
use JKingWeb\Arsse\REST\Fever\API ;
use Psr\Http\Message\ResponseInterface ;
2020-01-20 15:40:05 +00:00
use Laminas\Diactoros\ServerRequest ;
use Laminas\Diactoros\Response\JsonResponse ;
use Laminas\Diactoros\Response\XmlResponse ;
use Laminas\Diactoros\Response\EmptyResponse ;
2019-03-19 02:49:47 +00:00
/** @covers \JKingWeb\Arsse\REST\Fever\API<extended> */
class TestAPI extends \JKingWeb\Arsse\Test\AbstractTest {
2019-07-24 13:10:13 +00:00
/** @var \JKingWeb\Arsse\REST\Fever\API */
protected $h ;
2019-04-08 22:41:56 +00:00
protected $articles = [
'db' => [
[
2020-03-01 20:16:50 +00:00
'id' => 101 ,
'url' => 'http://example.com/1' ,
'title' => 'Article title 1' ,
'author' => '' ,
'content' => '<p>Article content 1</p>' ,
2019-04-08 22:41:56 +00:00
'published_date' => '2000-01-01 00:00:00' ,
2020-03-01 20:16:50 +00:00
'unread' => 1 ,
'starred' => 0 ,
'subscription' => 8 ,
2019-04-08 22:41:56 +00:00
],
[
2020-03-01 20:16:50 +00:00
'id' => 102 ,
'url' => 'http://example.com/2' ,
'title' => 'Article title 2' ,
'author' => '' ,
'content' => '<p>Article content 2</p>' ,
2019-04-08 22:41:56 +00:00
'published_date' => '2000-01-02 00:00:00' ,
2020-03-01 20:16:50 +00:00
'unread' => 0 ,
'starred' => 0 ,
'subscription' => 8 ,
2019-04-08 22:41:56 +00:00
],
[
2020-03-01 20:16:50 +00:00
'id' => 103 ,
'url' => 'http://example.com/3' ,
'title' => 'Article title 3' ,
'author' => '' ,
'content' => '<p>Article content 3</p>' ,
2019-04-08 22:41:56 +00:00
'published_date' => '2000-01-03 00:00:00' ,
2020-03-01 20:16:50 +00:00
'unread' => 1 ,
'starred' => 1 ,
'subscription' => 9 ,
2019-04-08 22:41:56 +00:00
],
[
2020-03-01 20:16:50 +00:00
'id' => 104 ,
'url' => 'http://example.com/4' ,
'title' => 'Article title 4' ,
'author' => '' ,
'content' => '<p>Article content 4</p>' ,
2019-04-08 22:41:56 +00:00
'published_date' => '2000-01-04 00:00:00' ,
2020-03-01 20:16:50 +00:00
'unread' => 0 ,
'starred' => 1 ,
'subscription' => 9 ,
2019-04-08 22:41:56 +00:00
],
[
2020-03-01 20:16:50 +00:00
'id' => 105 ,
'url' => 'http://example.com/5' ,
'title' => 'Article title 5' ,
'author' => '' ,
'content' => '<p>Article content 5</p>' ,
2019-04-08 22:41:56 +00:00
'published_date' => '2000-01-05 00:00:00' ,
2020-03-01 20:16:50 +00:00
'unread' => 1 ,
'starred' => 0 ,
'subscription' => 10 ,
2019-04-08 22:41:56 +00:00
],
],
'rest' => [
[
2020-03-01 20:16:50 +00:00
'id' => 101 ,
'feed_id' => 8 ,
'title' => 'Article title 1' ,
'author' => '' ,
'html' => '<p>Article content 1</p>' ,
'url' => 'http://example.com/1' ,
'is_saved' => 0 ,
'is_read' => 0 ,
2019-04-08 22:41:56 +00:00
'created_on_time' => 946684800 ,
],
[
2020-03-01 20:16:50 +00:00
'id' => 102 ,
'feed_id' => 8 ,
'title' => 'Article title 2' ,
'author' => '' ,
'html' => '<p>Article content 2</p>' ,
'url' => 'http://example.com/2' ,
'is_saved' => 0 ,
'is_read' => 1 ,
2019-04-08 22:41:56 +00:00
'created_on_time' => 946771200 ,
],
[
2020-03-01 20:16:50 +00:00
'id' => 103 ,
'feed_id' => 9 ,
'title' => 'Article title 3' ,
'author' => '' ,
'html' => '<p>Article content 3</p>' ,
'url' => 'http://example.com/3' ,
'is_saved' => 1 ,
'is_read' => 0 ,
2019-04-08 22:41:56 +00:00
'created_on_time' => 946857600 ,
],
[
2020-03-01 20:16:50 +00:00
'id' => 104 ,
'feed_id' => 9 ,
'title' => 'Article title 4' ,
'author' => '' ,
'html' => '<p>Article content 4</p>' ,
'url' => 'http://example.com/4' ,
'is_saved' => 1 ,
'is_read' => 1 ,
2019-04-08 22:41:56 +00:00
'created_on_time' => 946944000 ,
],
[
2020-03-01 20:16:50 +00:00
'id' => 105 ,
'feed_id' => 10 ,
'title' => 'Article title 5' ,
'author' => '' ,
'html' => '<p>Article content 5</p>' ,
'url' => 'http://example.com/5' ,
'is_saved' => 0 ,
'is_read' => 0 ,
2019-04-08 22:41:56 +00:00
'created_on_time' => 947030400 ,
],
],
];
2019-03-19 02:49:47 +00:00
protected function v ( $value ) {
return $value ;
}
2019-09-25 22:30:53 +00:00
protected function req ( $dataGet , $dataPost = " " , string $method = " POST " , string $type = null , string $target = " " , string $user = null ) : ServerRequest {
$prefix = " /fever/ " ;
$url = $prefix . $target ;
2019-04-10 19:07:34 +00:00
$type = $type ? ? " application/x-www-form-urlencoded " ;
2019-09-25 22:30:53 +00:00
return $this -> serverRequest ( $method , $url , $prefix , [], [], $dataPost , $type , $dataGet , $user );
2019-03-19 02:49:47 +00:00
}
2019-10-16 18:42:43 +00:00
public function setUp () : void {
2019-03-19 02:49:47 +00:00
self :: clearData ();
self :: setConf ();
// create a mock user manager
2019-03-27 15:54:47 +00:00
Arsse :: $user = \Phake :: mock ( User :: class );
\Phake :: when ( Arsse :: $user ) -> auth -> thenReturn ( true );
2019-03-19 02:49:47 +00:00
Arsse :: $user -> id = " john.doe@example.com " ;
// create a mock database interface
2019-03-27 15:54:47 +00:00
Arsse :: $db = \Phake :: mock ( Database :: class );
\Phake :: when ( Arsse :: $db ) -> begin -> thenReturn ( \Phake :: mock ( Transaction :: class ));
\Phake :: when ( Arsse :: $db ) -> tokenLookup -> thenReturn ([ 'user' => " john.doe@example.com " ]);
2019-03-27 19:09:04 +00:00
// instantiate the handler as a partial mock to simplify testing
$this -> h = \Phake :: partialMock ( API :: class );
\Phake :: when ( $this -> h ) -> baseResponse -> thenReturn ([]);
2019-03-19 02:49:47 +00:00
}
2019-10-16 18:42:43 +00:00
public function tearDown () : void {
2019-03-19 02:49:47 +00:00
self :: clearData ();
}
2019-03-24 19:05:21 +00:00
/** @dataProvider provideTokenAuthenticationRequests */
2020-01-20 18:52:48 +00:00
public function testAuthenticateAUserToken ( bool $httpRequired , bool $tokenEnforced , string $httpUser = null , array $dataPost , array $dataGet , ResponseInterface $exp ) : void {
2019-03-19 02:49:47 +00:00
self :: setConf ([
'userHTTPAuthRequired' => $httpRequired ,
2020-03-01 20:16:50 +00:00
'userSessionEnforced' => $tokenEnforced ,
2019-03-19 02:49:47 +00:00
], true );
2019-03-20 03:37:08 +00:00
Arsse :: $user -> id = null ;
2019-03-19 02:49:47 +00:00
\Phake :: when ( Arsse :: $db ) -> tokenLookup -> thenThrow ( new ExceptionInput ( " subjectMissing " ));
\Phake :: when ( Arsse :: $db ) -> tokenLookup ( " fever.login " , " validtoken " ) -> thenReturn ([ 'user' => " jane.doe@example.com " ]);
2019-03-27 19:09:04 +00:00
// test only the authentication process
\Phake :: when ( $this -> h ) -> baseResponse -> thenReturnCallback ( function ( bool $authenticated ) {
return [ 'auth' => ( int ) $authenticated ];
});
2019-03-27 15:54:47 +00:00
\Phake :: when ( $this -> h ) -> processRequest -> thenReturnCallback ( function ( $out , $G , $P ) {
return $out ;
});
2019-04-10 19:07:34 +00:00
$act = $this -> h -> dispatch ( $this -> req ( $dataGet , $dataPost , " POST " , null , " " , $httpUser ));
2019-03-19 02:49:47 +00:00
$this -> assertMessage ( $exp , $act );
}
2019-10-16 18:42:43 +00:00
public function provideTokenAuthenticationRequests () : iterable {
2019-03-27 19:09:04 +00:00
$success = new JsonResponse ([ 'auth' => 1 ]);
$failure = new JsonResponse ([ 'auth' => 0 ]);
2019-03-20 03:37:08 +00:00
$denied = new EmptyResponse ( 401 );
2019-03-19 02:49:47 +00:00
return [
2019-03-20 03:37:08 +00:00
[ false , true , null , [], [ 'api' => null ], $failure ],
[ false , false , null , [], [ 'api' => null ], $failure ],
[ true , true , null , [], [ 'api' => null ], $denied ],
[ true , false , null , [], [ 'api' => null ], $denied ],
[ false , true , " " , [], [ 'api' => null ], $denied ],
[ false , false , " " , [], [ 'api' => null ], $denied ],
[ true , true , " " , [], [ 'api' => null ], $denied ],
[ true , false , " " , [], [ 'api' => null ], $denied ],
[ false , true , null , [], [ 'api' => null , 'api_key' => " validToken " ], $failure ],
[ false , false , null , [], [ 'api' => null , 'api_key' => " validToken " ], $failure ],
[ true , true , null , [], [ 'api' => null , 'api_key' => " validToken " ], $denied ],
[ true , false , null , [], [ 'api' => null , 'api_key' => " validToken " ], $denied ],
2019-03-21 17:49:55 +00:00
[ false , true , " " , [], [ 'api' => null , 'api_key' => " validToken " ], $denied ],
[ false , false , " " , [], [ 'api' => null , 'api_key' => " validToken " ], $denied ],
[ true , true , " " , [], [ 'api' => null , 'api_key' => " validToken " ], $denied ],
[ true , false , " " , [], [ 'api' => null , 'api_key' => " validToken " ], $denied ],
[ false , true , " validUser " , [], [ 'api' => null , 'api_key' => " validToken " ], $failure ],
[ false , false , " validUser " , [], [ 'api' => null , 'api_key' => " validToken " ], $success ],
[ true , true , " validUser " , [], [ 'api' => null , 'api_key' => " validToken " ], $failure ],
[ true , false , " validUser " , [], [ 'api' => null , 'api_key' => " validToken " ], $success ],
2019-03-20 03:37:08 +00:00
[ false , true , null , [ 'api_key' => " validToken " ], [ 'api' => null ], $success ],
[ false , false , null , [ 'api_key' => " validToken " ], [ 'api' => null ], $success ],
[ true , true , null , [ 'api_key' => " validToken " ], [ 'api' => null ], $denied ],
[ true , false , null , [ 'api_key' => " validToken " ], [ 'api' => null ], $denied ],
[ false , true , " " , [ 'api_key' => " validToken " ], [ 'api' => null ], $denied ],
[ false , false , " " , [ 'api_key' => " validToken " ], [ 'api' => null ], $denied ],
[ true , true , " " , [ 'api_key' => " validToken " ], [ 'api' => null ], $denied ],
[ true , false , " " , [ 'api_key' => " validToken " ], [ 'api' => null ], $denied ],
[ false , true , " validUser " , [ 'api_key' => " validToken " ], [ 'api' => null ], $success ],
[ false , false , " validUser " , [ 'api_key' => " validToken " ], [ 'api' => null ], $success ],
[ true , true , " validUser " , [ 'api_key' => " validToken " ], [ 'api' => null ], $success ],
[ true , false , " validUser " , [ 'api_key' => " validToken " ], [ 'api' => null ], $success ],
[ false , true , null , [ 'api_key' => " invalidToken " ], [ 'api' => null ], $failure ],
[ false , false , null , [ 'api_key' => " invalidToken " ], [ 'api' => null ], $failure ],
[ true , true , null , [ 'api_key' => " invalidToken " ], [ 'api' => null ], $denied ],
[ true , false , null , [ 'api_key' => " invalidToken " ], [ 'api' => null ], $denied ],
[ false , true , " " , [ 'api_key' => " invalidToken " ], [ 'api' => null ], $denied ],
[ false , false , " " , [ 'api_key' => " invalidToken " ], [ 'api' => null ], $denied ],
[ true , true , " " , [ 'api_key' => " invalidToken " ], [ 'api' => null ], $denied ],
[ true , false , " " , [ 'api_key' => " invalidToken " ], [ 'api' => null ], $denied ],
[ false , true , " validUser " , [ 'api_key' => " invalidToken " ], [ 'api' => null ], $failure ],
[ false , false , " validUser " , [ 'api_key' => " invalidToken " ], [ 'api' => null ], $success ],
[ true , true , " validUser " , [ 'api_key' => " invalidToken " ], [ 'api' => null ], $failure ],
[ true , false , " validUser " , [ 'api_key' => " invalidToken " ], [ 'api' => null ], $success ],
2019-03-19 02:49:47 +00:00
];
}
2019-03-27 19:09:04 +00:00
2020-01-20 18:52:48 +00:00
public function testListGroups () : void {
2019-03-27 19:09:04 +00:00
\Phake :: when ( Arsse :: $db ) -> tagList ( Arsse :: $user -> id ) -> thenReturn ( new Result ([
[ 'id' => 1 , 'name' => " Fascinating " , 'subscriptions' => 2 ],
[ 'id' => 2 , 'name' => " Interesting " , 'subscriptions' => 2 ],
[ 'id' => 3 , 'name' => " Boring " , 'subscriptions' => 0 ],
]));
\Phake :: when ( Arsse :: $db ) -> tagSummarize ( Arsse :: $user -> id ) -> thenReturn ( new Result ([
[ 'id' => 1 , 'name' => " Fascinating " , 'subscription' => 1 ],
[ 'id' => 1 , 'name' => " Fascinating " , 'subscription' => 2 ],
[ 'id' => 2 , 'name' => " Interesting " , 'subscription' => 1 ],
[ 'id' => 2 , 'name' => " Interesting " , 'subscription' => 3 ],
]));
$exp = new JsonResponse ([
'groups' => [
[ 'id' => 1 , 'title' => " Fascinating " ],
[ 'id' => 2 , 'title' => " Interesting " ],
[ 'id' => 3 , 'title' => " Boring " ],
],
'feeds_groups' => [
[ 'group_id' => 1 , 'feed_ids' => " 1,2 " ],
[ 'group_id' => 2 , 'feed_ids' => " 1,3 " ],
],
]);
2019-04-10 19:07:34 +00:00
$act = $this -> h -> dispatch ( $this -> req ( " api&groups " ));
2019-03-27 19:09:04 +00:00
$this -> assertMessage ( $exp , $act );
}
2020-01-20 18:52:48 +00:00
public function testListFeeds () : void {
2019-03-27 19:09:04 +00:00
\Phake :: when ( Arsse :: $db ) -> subscriptionList ( Arsse :: $user -> id ) -> thenReturn ( new Result ([
[ 'id' => 1 , 'feed' => 5 , 'title' => " Ankh-Morpork News " , 'url' => " http://example.com/feed " , 'source' => " http://example.com/ " , 'edited' => " 2019-01-01 21:12:00 " , 'favicon' => " http://example.com/favicon.ico " ],
[ 'id' => 2 , 'feed' => 9 , 'title' => " Ook, Ook Eek Ook! " , 'url' => " http://example.net/feed " , 'source' => " http://example.net/ " , 'edited' => " 1988-06-24 12:21:00 " , 'favicon' => " " ],
[ 'id' => 3 , 'feed' => 1 , 'title' => " The Last Soul " , 'url' => " http://example.org/feed " , 'source' => " http://example.org/ " , 'edited' => " 1991-08-12 03:22:00 " , 'favicon' => " http://example.org/favicon.ico " ],
]));
\Phake :: when ( Arsse :: $db ) -> tagSummarize ( Arsse :: $user -> id ) -> thenReturn ( new Result ([
[ 'id' => 1 , 'name' => " Fascinating " , 'subscription' => 1 ],
[ 'id' => 1 , 'name' => " Fascinating " , 'subscription' => 2 ],
[ 'id' => 2 , 'name' => " Interesting " , 'subscription' => 1 ],
[ 'id' => 2 , 'name' => " Interesting " , 'subscription' => 3 ],
]));
$exp = new JsonResponse ([
'feeds' => [
2019-07-24 16:27:50 +00:00
[ 'id' => 1 , 'favicon_id' => 0 , 'title' => " Ankh-Morpork News " , 'url' => " http://example.com/feed " , 'site_url' => " http://example.com/ " , 'is_spark' => 0 , 'last_updated_on_time' => strtotime ( " 2019-01-01T21:12:00Z " )],
2019-03-27 19:09:04 +00:00
[ 'id' => 2 , 'favicon_id' => 0 , 'title' => " Ook, Ook Eek Ook! " , 'url' => " http://example.net/feed " , 'site_url' => " http://example.net/ " , 'is_spark' => 0 , 'last_updated_on_time' => strtotime ( " 1988-06-24T12:21:00Z " )],
2019-07-24 16:27:50 +00:00
[ 'id' => 3 , 'favicon_id' => 0 , 'title' => " The Last Soul " , 'url' => " http://example.org/feed " , 'site_url' => " http://example.org/ " , 'is_spark' => 0 , 'last_updated_on_time' => strtotime ( " 1991-08-12T03:22:00Z " )],
2019-03-27 19:09:04 +00:00
],
'feeds_groups' => [
[ 'group_id' => 1 , 'feed_ids' => " 1,2 " ],
[ 'group_id' => 2 , 'feed_ids' => " 1,3 " ],
],
]);
2019-04-10 19:07:34 +00:00
$act = $this -> h -> dispatch ( $this -> req ( " api&feeds " ));
2019-03-27 19:09:04 +00:00
$this -> assertMessage ( $exp , $act );
2019-09-05 14:21:36 +00:00
}
2019-04-08 22:41:56 +00:00
/** @dataProvider provideItemListContexts */
2020-01-20 18:52:48 +00:00
public function testListItems ( string $url , Context $c , bool $desc ) : void {
2019-04-08 22:41:56 +00:00
$fields = [ " id " , " subscription " , " title " , " author " , " content " , " url " , " starred " , " unread " , " published_date " ];
$order = [ $desc ? " id desc " : " id " ];
\Phake :: when ( Arsse :: $db ) -> articleList -> thenReturn ( new Result ( $this -> articles [ 'db' ]));
2019-04-10 20:01:58 +00:00
\Phake :: when ( Arsse :: $db ) -> articleCount ( Arsse :: $user -> id ) -> thenReturn ( 1024 );
2019-04-08 22:41:56 +00:00
$exp = new JsonResponse ([
2020-03-01 20:16:50 +00:00
'items' => $this -> articles [ 'rest' ],
2019-04-08 22:41:56 +00:00
'total_items' => 1024 ,
]);
2019-04-10 19:07:34 +00:00
$act = $this -> h -> dispatch ( $this -> req ( " api& $url " ));
2019-04-08 22:41:56 +00:00
$this -> assertMessage ( $exp , $act );
2019-04-10 20:01:58 +00:00
\Phake :: verify ( Arsse :: $db ) -> articleList ( Arsse :: $user -> id , $c , $fields , $order );
2019-04-08 22:41:56 +00:00
}
2019-10-16 18:42:43 +00:00
public function provideItemListContexts () : iterable {
2019-04-08 22:41:56 +00:00
$c = ( new Context ) -> limit ( 50 );
return [
[ " items " , ( clone $c ), false ],
[ " items&group_ids=1,2,3,4 " , ( clone $c ) -> tags ([ 1 , 2 , 3 , 4 ]), false ],
[ " items&feed_ids=1,2,3,4 " , ( clone $c ) -> subscriptions ([ 1 , 2 , 3 , 4 ]), false ],
[ " items&with_ids=1,2,3,4 " , ( clone $c ) -> articles ([ 1 , 2 , 3 , 4 ]), false ],
[ " items&since_id=1 " , ( clone $c ) -> oldestArticle ( 2 ), false ],
[ " items&max_id=2 " , ( clone $c ) -> latestArticle ( 1 ), true ],
[ " items&with_ids=1,2,3,4&max_id=6 " , ( clone $c ) -> articles ([ 1 , 2 , 3 , 4 ]), false ],
[ " items&with_ids=1,2,3,4&since_id=6 " , ( clone $c ) -> articles ([ 1 , 2 , 3 , 4 ]), false ],
[ " items&max_id=3&since_id=6 " , ( clone $c ) -> latestArticle ( 2 ), true ],
[ " items&feed_ids=1,2,3,4&since_id=6 " , ( clone $c ) -> subscriptions ([ 1 , 2 , 3 , 4 ]) -> oldestArticle ( 7 ), false ],
];
}
2019-04-08 23:15:12 +00:00
2020-01-20 18:52:48 +00:00
public function testListItemIds () : void {
2019-04-08 23:15:12 +00:00
$saved = [[ 'id' => 1 ],[ 'id' => 2 ],[ 'id' => 3 ]];
$unread = [[ 'id' => 4 ],[ 'id' => 5 ],[ 'id' => 6 ]];
2019-04-10 20:01:58 +00:00
\Phake :: when ( Arsse :: $db ) -> articleList ( Arsse :: $user -> id , ( new Context ) -> starred ( true )) -> thenReturn ( new Result ( $saved ));
\Phake :: when ( Arsse :: $db ) -> articleList ( Arsse :: $user -> id , ( new Context ) -> unread ( true )) -> thenReturn ( new Result ( $unread ));
2020-03-01 20:16:50 +00:00
$exp = new JsonResponse ([ 'saved_item_ids' => " 1,2,3 " ]);
2019-04-10 19:07:34 +00:00
$this -> assertMessage ( $exp , $this -> h -> dispatch ( $this -> req ( " api&saved_item_ids " )));
2020-03-01 20:16:50 +00:00
$exp = new JsonResponse ([ 'unread_item_ids' => " 4,5,6 " ]);
2019-04-10 19:07:34 +00:00
$this -> assertMessage ( $exp , $this -> h -> dispatch ( $this -> req ( " api&unread_item_ids " )));
2019-04-08 23:15:12 +00:00
}
2019-04-08 23:21:21 +00:00
2020-01-20 18:52:48 +00:00
public function testListHotLinks () : void {
2019-04-08 23:21:21 +00:00
// hot links are not actually implemented, so an empty array should be all we get
2020-03-01 20:16:50 +00:00
$exp = new JsonResponse ([ 'links' => []]);
2019-04-10 19:07:34 +00:00
$this -> assertMessage ( $exp , $this -> h -> dispatch ( $this -> req ( " api&links " )));
2019-04-08 23:21:21 +00:00
}
2019-04-10 13:48:28 +00:00
/** @dataProvider provideMarkingContexts */
2020-01-20 18:52:48 +00:00
public function testSetMarks ( string $post , Context $c , array $data , array $out ) : void {
2019-04-10 13:48:28 +00:00
$saved = [[ 'id' => 1 ],[ 'id' => 2 ],[ 'id' => 3 ]];
$unread = [[ 'id' => 4 ],[ 'id' => 5 ],[ 'id' => 6 ]];
2019-04-10 20:01:58 +00:00
\Phake :: when ( Arsse :: $db ) -> articleList ( Arsse :: $user -> id , ( new Context ) -> starred ( true )) -> thenReturn ( new Result ( $saved ));
\Phake :: when ( Arsse :: $db ) -> articleList ( Arsse :: $user -> id , ( new Context ) -> unread ( true )) -> thenReturn ( new Result ( $unread ));
2019-04-10 13:48:28 +00:00
\Phake :: when ( Arsse :: $db ) -> articleMark -> thenReturn ( 0 );
2019-04-10 20:01:58 +00:00
\Phake :: when ( Arsse :: $db ) -> articleMark ( Arsse :: $user -> id , $this -> anything (), ( new Context ) -> article ( 2112 )) -> thenThrow ( new \JKingWeb\Arsse\Db\ExceptionInput ( " subjectMissing " ));
2019-04-10 13:48:28 +00:00
$exp = new JsonResponse ( $out );
2019-04-10 19:07:34 +00:00
$act = $this -> h -> dispatch ( $this -> req ( " api " , $post ));
2019-04-10 13:48:28 +00:00
$this -> assertMessage ( $exp , $act );
if ( $c && $data ) {
2019-04-10 20:01:58 +00:00
\Phake :: verify ( Arsse :: $db ) -> articleMark ( Arsse :: $user -> id , $data , $c );
2019-04-10 13:48:28 +00:00
} else {
\Phake :: verify ( Arsse :: $db , \Phake :: times ( 0 )) -> articleMark ;
2019-07-27 03:23:22 +00:00
}
}
/** @dataProvider provideMarkingContexts */
2020-01-20 18:52:48 +00:00
public function testSetMarksWithQuery ( string $get , Context $c , array $data , array $out ) : void {
2019-07-27 03:23:22 +00:00
$saved = [[ 'id' => 1 ],[ 'id' => 2 ],[ 'id' => 3 ]];
$unread = [[ 'id' => 4 ],[ 'id' => 5 ],[ 'id' => 6 ]];
\Phake :: when ( Arsse :: $db ) -> articleList ( Arsse :: $user -> id , ( new Context ) -> starred ( true )) -> thenReturn ( new Result ( $saved ));
\Phake :: when ( Arsse :: $db ) -> articleList ( Arsse :: $user -> id , ( new Context ) -> unread ( true )) -> thenReturn ( new Result ( $unread ));
\Phake :: when ( Arsse :: $db ) -> articleMark -> thenReturn ( 0 );
\Phake :: when ( Arsse :: $db ) -> articleMark ( Arsse :: $user -> id , $this -> anything (), ( new Context ) -> article ( 2112 )) -> thenThrow ( new \JKingWeb\Arsse\Db\ExceptionInput ( " subjectMissing " ));
$exp = new JsonResponse ( $out );
$act = $this -> h -> dispatch ( $this -> req ( " api& $get " ));
$this -> assertMessage ( $exp , $act );
if ( $c && $data ) {
\Phake :: verify ( Arsse :: $db ) -> articleMark ( Arsse :: $user -> id , $data , $c );
} else {
\Phake :: verify ( Arsse :: $db , \Phake :: times ( 0 )) -> articleMark ;
2019-04-10 13:48:28 +00:00
}
}
2019-10-16 18:42:43 +00:00
public function provideMarkingContexts () : iterable {
2019-04-10 13:48:28 +00:00
$markRead = [ 'read' => true ];
$markUnread = [ 'read' => false ];
$markSaved = [ 'starred' => true ];
$markUnsaved = [ 'starred' => false ];
$listSaved = [ 'saved_item_ids' => " 1,2,3 " ];
$listUnread = [ 'unread_item_ids' => " 4,5,6 " ];
return [
[ " mark=item&as=read&id=5 " , ( new Context ) -> article ( 5 ), $markRead , $listUnread ],
[ " mark=item&as=unread&id=42 " , ( new Context ) -> article ( 42 ), $markUnread , $listUnread ],
[ " mark=item&as=read&id=2112 " , ( new Context ) -> article ( 2112 ), $markRead , $listUnread ], // article doesn't exist
[ " mark=item&as=saved&id=5 " , ( new Context ) -> article ( 5 ), $markSaved , $listSaved ],
[ " mark=item&as=unsaved&id=42 " , ( new Context ) -> article ( 42 ), $markUnsaved , $listSaved ],
[ " mark=feed&as=read&id=5 " , ( new Context ) -> subscription ( 5 ), $markRead , $listUnread ],
[ " mark=feed&as=unread&id=42 " , ( new Context ) -> subscription ( 42 ), $markUnread , $listUnread ],
[ " mark=feed&as=saved&id=5 " , ( new Context ) -> subscription ( 5 ), $markSaved , $listSaved ],
[ " mark=feed&as=unsaved&id=42 " , ( new Context ) -> subscription ( 42 ), $markUnsaved , $listSaved ],
[ " mark=group&as=read&id=5 " , ( new Context ) -> tag ( 5 ), $markRead , $listUnread ],
[ " mark=group&as=unread&id=42 " , ( new Context ) -> tag ( 42 ), $markUnread , $listUnread ],
[ " mark=group&as=saved&id=5 " , ( new Context ) -> tag ( 5 ), $markSaved , $listSaved ],
[ " mark=group&as=unsaved&id=42 " , ( new Context ) -> tag ( 42 ), $markUnsaved , $listSaved ],
[ " mark=item&as=invalid&id=42 " , new Context , [], []],
[ " mark=invalid&as=unread&id=42 " , new Context , [], []],
[ " mark=group&as=read&id=0 " , ( new Context ), $markRead , $listUnread ],
[ " mark=group&as=unread&id=0 " , ( new Context ), $markUnread , $listUnread ],
[ " mark=group&as=saved&id=0 " , ( new Context ), $markSaved , $listSaved ],
[ " mark=group&as=unsaved&id=0 " , ( new Context ), $markUnsaved , $listSaved ],
[ " mark=group&as=read&id=-1 " , ( new Context ) -> not -> folder ( 0 ), $markRead , $listUnread ],
[ " mark=group&as=unread&id=-1 " , ( new Context ) -> not -> folder ( 0 ), $markUnread , $listUnread ],
[ " mark=group&as=saved&id=-1 " , ( new Context ) -> not -> folder ( 0 ), $markSaved , $listSaved ],
[ " mark=group&as=unsaved&id=-1 " , ( new Context ) -> not -> folder ( 0 ), $markUnsaved , $listSaved ],
2019-04-10 20:01:58 +00:00
[ " mark=group&as=read&id=-1&before=946684800 " , ( new Context ) -> not -> folder ( 0 ) -> notMarkedSince ( " 2000-01-01T00:00:00Z " ), $markRead , $listUnread ],
2019-04-10 13:48:28 +00:00
[ " mark=item&as=unread " , new Context , [], []],
[ " mark=item&id=6 " , new Context , [], []],
[ " as=unread&id=6 " , new Context , [], []],
];
}
2019-04-10 19:07:34 +00:00
/** @dataProvider provideInvalidRequests */
2020-01-20 18:52:48 +00:00
public function testSendInvalidRequests ( ServerRequest $req , ResponseInterface $exp ) : void {
2019-04-10 19:07:34 +00:00
$this -> assertMessage ( $exp , $this -> h -> dispatch ( $req ));
}
2019-10-16 18:42:43 +00:00
public function provideInvalidRequests () : iterable {
2019-04-10 19:07:34 +00:00
return [
2020-10-27 14:49:54 +00:00
'Not an API request' => [ $this -> req ( " " ), new EmptyResponse ( 404 )],
'Wrong method' => [ $this -> req ( " api " , " " , " PUT " ), new EmptyResponse ( 405 , [ 'Allow' => " OPTIONS,POST " ])],
'Non-standard method' => [ $this -> req ( " api " , " " , " GET " ), new JsonResponse ([])],
'Wrong content type' => [ $this -> req ( " api " , '{"api_key":"validToken"}' , " POST " , " application/json " ), new EmptyResponse ( 415 , [ 'Accept' => " application/x-www-form-urlencoded, multipart/form-data " ])],
'Non-standard content type' => [ $this -> req ( " api " , '{"api_key":"validToken"}' , " POST " , " multipart/form-data; boundary=33b68964f0de4c1f-5144aa6caaa6e4a8-18bfaf416a1786c8-5c5053a45f221bc1 " ), new JsonResponse ([])],
2019-04-10 19:07:34 +00:00
];
}
2019-04-10 20:01:58 +00:00
2020-01-20 18:52:48 +00:00
public function testMakeABaseQuery () : void {
2019-04-10 20:01:58 +00:00
$this -> h = \Phake :: partialMock ( API :: class );
\Phake :: when ( $this -> h ) -> logIn -> thenReturn ( true );
\Phake :: when ( Arsse :: $db ) -> subscriptionRefreshed ( Arsse :: $user -> id ) -> thenReturn ( new \DateTimeImmutable ( " 2000-01-01T00:00:00Z " ));
$exp = new JsonResponse ([
2020-03-01 20:16:50 +00:00
'api_version' => API :: LEVEL ,
'auth' => 1 ,
2019-04-10 20:01:58 +00:00
'last_refreshed_on_time' => 946684800 ,
]);
$act = $this -> h -> dispatch ( $this -> req ( " api " ));
$this -> assertMessage ( $exp , $act );
\Phake :: when ( Arsse :: $db ) -> subscriptionRefreshed ( Arsse :: $user -> id ) -> thenReturn ( null ); // no subscriptions
$exp = new JsonResponse ([
2020-03-01 20:16:50 +00:00
'api_version' => API :: LEVEL ,
'auth' => 1 ,
2019-04-10 20:01:58 +00:00
'last_refreshed_on_time' => null ,
]);
$act = $this -> h -> dispatch ( $this -> req ( " api " ));
$this -> assertMessage ( $exp , $act );
\Phake :: when ( $this -> h ) -> logIn -> thenReturn ( false );
$exp = new JsonResponse ([
'api_version' => API :: LEVEL ,
2020-03-01 20:16:50 +00:00
'auth' => 0 ,
2019-04-10 20:01:58 +00:00
]);
$act = $this -> h -> dispatch ( $this -> req ( " api " ));
$this -> assertMessage ( $exp , $act );
}
2019-04-10 22:27:57 +00:00
2020-01-20 18:52:48 +00:00
public function testUndoReadMarks () : void {
2019-04-10 22:27:57 +00:00
$unread = [[ 'id' => 4 ],[ 'id' => 5 ],[ 'id' => 6 ]];
$out = [ 'unread_item_ids' => " 4,5,6 " ];
\Phake :: when ( Arsse :: $db ) -> articleList ( Arsse :: $user -> id , ( new Context ) -> limit ( 1 ), [ " marked_date " ], [ " marked_date desc " ]) -> thenReturn ( new Result ([[ 'marked_date' => " 2000-01-01 00:00:00 " ]]));
\Phake :: when ( Arsse :: $db ) -> articleList ( Arsse :: $user -> id , ( new Context ) -> unread ( true )) -> thenReturn ( new Result ( $unread ));
\Phake :: when ( Arsse :: $db ) -> articleMark -> thenReturn ( 0 );
$exp = new JsonResponse ( $out );
$act = $this -> h -> dispatch ( $this -> req ( " api " , [ 'unread_recently_read' => 1 ]));
$this -> assertMessage ( $exp , $act );
\Phake :: verify ( Arsse :: $db ) -> articleMark ( Arsse :: $user -> id , [ 'read' => false ], ( new Context ) -> unread ( false ) -> markedSince ( " 1999-12-31T23:59:45Z " ));
\Phake :: when ( Arsse :: $db ) -> articleList ( Arsse :: $user -> id , ( new Context ) -> limit ( 1 ), [ " marked_date " ], [ " marked_date desc " ]) -> thenReturn ( new Result ([]));
$act = $this -> h -> dispatch ( $this -> req ( " api " , [ 'unread_recently_read' => 1 ]));
$this -> assertMessage ( $exp , $act );
\Phake :: verify ( Arsse :: $db ) -> articleMark ; // only called one time, above
}
2019-07-24 13:10:13 +00:00
2020-01-20 18:52:48 +00:00
public function testOutputToXml () : void {
2019-07-24 13:10:13 +00:00
\Phake :: when ( $this -> h ) -> processRequest -> thenReturn ([
2020-03-01 20:16:50 +00:00
'items' => $this -> articles [ 'rest' ],
2019-07-24 13:10:13 +00:00
'total_items' => 1024 ,
]);
$exp = new XmlResponse ( " <response><items><item><id>101</id><feed_id>8</feed_id><title>Article title 1</title><author></author><html><p>Article content 1</p></html><url>http://example.com/1</url><is_saved>0</is_saved><is_read>0</is_read><created_on_time>946684800</created_on_time></item><item><id>102</id><feed_id>8</feed_id><title>Article title 2</title><author></author><html><p>Article content 2</p></html><url>http://example.com/2</url><is_saved>0</is_saved><is_read>1</is_read><created_on_time>946771200</created_on_time></item><item><id>103</id><feed_id>9</feed_id><title>Article title 3</title><author></author><html><p>Article content 3</p></html><url>http://example.com/3</url><is_saved>1</is_saved><is_read>0</is_read><created_on_time>946857600</created_on_time></item><item><id>104</id><feed_id>9</feed_id><title>Article title 4</title><author></author><html><p>Article content 4</p></html><url>http://example.com/4</url><is_saved>1</is_saved><is_read>1</is_read><created_on_time>946944000</created_on_time></item><item><id>105</id><feed_id>10</feed_id><title>Article title 5</title><author></author><html><p>Article content 5</p></html><url>http://example.com/5</url><is_saved>0</is_saved><is_read>0</is_read><created_on_time>947030400</created_on_time></item></items><total_items>1024</total_items></response> " );
$act = $this -> h -> dispatch ( $this -> req ( " api=xml " ));
$this -> assertMessage ( $exp , $act );
}
2019-07-24 16:27:50 +00:00
2020-01-20 18:52:48 +00:00
public function testListFeedIcons () : void {
2020-03-01 23:32:01 +00:00
$iconType = ( new \ReflectionClassConstant ( API :: class , " GENERIC_ICON_TYPE " )) -> getValue ();
$iconData = ( new \ReflectionClassConstant ( API :: class , " GENERIC_ICON_DATA " )) -> getValue ();
2019-07-24 16:27:50 +00:00
$act = $this -> h -> dispatch ( $this -> req ( " api&favicons " ));
2020-03-01 23:32:01 +00:00
$exp = new JsonResponse ([ 'favicons' => [[ 'id' => 0 , 'data' => $iconType . " , " . $iconData ]]]);
2019-09-05 14:21:36 +00:00
$this -> assertMessage ( $exp , $act );
2019-07-24 16:27:50 +00:00
}
2019-07-24 16:32:00 +00:00
2020-01-20 18:52:48 +00:00
public function testAnswerOptionsRequest () : void {
2019-07-24 16:32:00 +00:00
$act = $this -> h -> dispatch ( $this -> req ( " api " , " " , " OPTIONS " ));
$exp = new EmptyResponse ( 204 , [
2020-03-01 20:16:50 +00:00
'Allow' => " POST " ,
2020-10-27 14:49:54 +00:00
'Accept' => " application/x-www-form-urlencoded, multipart/form-data " ,
2019-07-24 16:32:00 +00:00
]);
$this -> assertMessage ( $exp , $act );
}
2019-03-19 02:49:47 +00:00
}