Refactor, increase test coverage

This commit is contained in:
Timothy Warren 2020-12-10 15:59:37 -05:00
parent 0029dd2fb8
commit 292d9bbaaf
44 changed files with 194 additions and 409 deletions

View File

@ -30,7 +30,7 @@ class RoboFile extends Tasks {
* *
* @var array * @var array
*/ */
protected $taskDirs = [ protected array $taskDirs = [
'build/logs', 'build/logs',
'build/pdepend', 'build/pdepend',
'build/phpdox', 'build/phpdox',
@ -41,7 +41,7 @@ class RoboFile extends Tasks {
* *
* @var array * @var array
*/ */
protected $cleanDirs = [ protected array $cleanDirs = [
'coverage', 'coverage',
'docs', 'docs',
'phpdoc', 'phpdoc',

View File

@ -255,6 +255,13 @@ $routes = [
'path' => '/logout', 'path' => '/logout',
'action' => 'logout', 'action' => 'logout',
], ],
'history' => [
'controller' => 'history',
'path' => '/history/{type}',
'tokens' => [
'type' => SLUG_PATTERN
]
],
'increment' => [ 'increment' => [
'path' => '/{controller}/increment', 'path' => '/{controller}/increment',
'action' => 'increment', 'action' => 'increment',
@ -288,19 +295,12 @@ $routes = [
], ],
], ],
'list' => [ 'list' => [
'path' => '/{controller}/{type}{/view}', 'path' => '/{controller}/{status}{/view}',
'tokens' => [ 'tokens' => [
'type' => ALPHA_SLUG_PATTERN, 'status' => ALPHA_SLUG_PATTERN,
'view' => ALPHA_SLUG_PATTERN, 'view' => ALPHA_SLUG_PATTERN,
], ],
], ],
'history' => [
'controller' => 'history',
'path' => '/history/{type}',
'tokens' => [
'type' => SLUG_PATTERN
]
],
'index_redirect' => [ 'index_redirect' => [
'path' => '/', 'path' => '/',
'action' => 'redirectToDefaultRoute', 'action' => 'redirectToDefaultRoute',

View File

@ -21,7 +21,7 @@ use function Amp\Promise\wait;
use InvalidArgumentException; use InvalidArgumentException;
use Amp\Http\Client\Request; use Amp\Http\Client\Request;
use Aviat\AnimeClient\API\Anilist; use Aviat\AnimeClient\Anilist;
use Aviat\AnimeClient\API\Mapping\{AnimeWatchingStatus, MangaReadingStatus}; use Aviat\AnimeClient\API\Mapping\{AnimeWatchingStatus, MangaReadingStatus};
use Aviat\AnimeClient\Types\FormItem; use Aviat\AnimeClient\Types\FormItem;
use Aviat\Ion\Json; use Aviat\Ion\Json;

View File

@ -18,7 +18,7 @@ namespace Aviat\AnimeClient\API\Anilist;
use Amp\Http\Client\Request; use Amp\Http\Client\Request;
use Amp\Http\Client\Response; use Amp\Http\Client\Response;
use Aviat\AnimeClient\API\Anilist; use Aviat\AnimeClient\Anilist;
use Aviat\Ion\Di\ContainerAware; use Aviat\Ion\Di\ContainerAware;
use Aviat\Ion\Di\ContainerInterface; use Aviat\Ion\Di\ContainerInterface;
use Aviat\Ion\Json; use Aviat\Ion\Json;

View File

@ -23,7 +23,6 @@ trait RequestBuilderTrait {
/** /**
* The request builder for the Anilist API * The request builder for the Anilist API
* @var RequestBuilder
*/ */
protected RequestBuilder $requestBuilder; protected RequestBuilder $requestBuilder;
@ -33,7 +32,7 @@ trait RequestBuilderTrait {
* @param RequestBuilder $requestBuilder * @param RequestBuilder $requestBuilder
* @return self * @return self
*/ */
public function setRequestBuilder($requestBuilder): self public function setRequestBuilder(RequestBuilder $requestBuilder): self
{ {
$this->requestBuilder = $requestBuilder; $this->requestBuilder = $requestBuilder;
return $this; return $this;

View File

@ -24,33 +24,15 @@ class MediaListEntry extends AbstractType {
*/ */
public $id; public $id;
/**
* @var string|null
*/
public ?string $notes; public ?string $notes;
/**
* @var bool
*/
public ?bool $private; public ?bool $private;
/**
* @var int
*/
public int $progress; public int $progress;
/**
* @var int
*/
public ?int $repeat; public ?int $repeat;
/**
* @var string
*/
public string $status; public string $status;
/**
* @var int
*/
public ?int $score; public ?int $score;
} }

View File

@ -33,7 +33,7 @@ use Aviat\AnimeClient\API\Kitsu\Transformer\{
MangaListTransformer, MangaListTransformer,
MangaTransformer MangaTransformer
}; };
use Aviat\AnimeClient\Enum\ListType; use Aviat\AnimeClient\Enum\MediaType;
use Aviat\AnimeClient\Kitsu as K; use Aviat\AnimeClient\Kitsu as K;
use Aviat\AnimeClient\Types\Anime; use Aviat\AnimeClient\Types\Anime;
use Aviat\AnimeClient\Types\MangaPage; use Aviat\AnimeClient\Types\MangaPage;
@ -319,7 +319,7 @@ final class Model {
if ($list === NULL) if ($list === NULL)
{ {
$data = $this->getList(ListType::ANIME, $status) ?? []; $data = $this->getList(MediaType::ANIME, $status) ?? [];
// Bail out on no data // Bail out on no data
if (empty($data)) if (empty($data))
@ -352,7 +352,7 @@ final class Model {
*/ */
public function getAnimeListCount(string $status = '') : int public function getAnimeListCount(string $status = '') : int
{ {
return $this->getListCount(ListType::ANIME, $status); return $this->getListCount(MediaType::ANIME, $status);
} }
/** /**
@ -462,7 +462,7 @@ final class Model {
if ($list === NULL) if ($list === NULL)
{ {
$data = $this->getList(ListType::MANGA, $status) ?? []; $data = $this->getList(MediaType::MANGA, $status) ?? [];
// Bail out on no data // Bail out on no data
if (empty($data)) if (empty($data))
@ -495,7 +495,7 @@ final class Model {
*/ */
public function getMangaListCount(string $status = '') : int public function getMangaListCount(string $status = '') : int
{ {
return $this->getListCount(ListType::MANGA, $status); return $this->getListCount(MediaType::MANGA, $status);
} }
/** /**

View File

@ -14,7 +14,7 @@
* @link https://git.timshomepage.net/timw4mail/HummingBirdAnimeClient * @link https://git.timshomepage.net/timw4mail/HummingBirdAnimeClient
*/ */
namespace Aviat\AnimeClient\API; namespace Aviat\AnimeClient;
use Aviat\AnimeClient\API\Enum\{ use Aviat\AnimeClient\API\Enum\{
AnimeWatchingStatus\Kitsu as KAWS, AnimeWatchingStatus\Kitsu as KAWS,

View File

@ -250,7 +250,7 @@ function getResponse ($request): Response
* @param bool $webp * @param bool $webp
* @return string * @return string
*/ */
function getLocalImg ($kitsuUrl, $webp = TRUE): string function getLocalImg (string $kitsuUrl, $webp = TRUE): string
{ {
if (empty($kitsuUrl) || ( ! is_string($kitsuUrl))) if (empty($kitsuUrl) || ( ! is_string($kitsuUrl)))
{ {
@ -360,7 +360,7 @@ function clearCache(CacheInterface $cache): bool
Kitsu::AUTH_TOKEN_REFRESH_CACHE_KEY, Kitsu::AUTH_TOKEN_REFRESH_CACHE_KEY,
], NULL); ], NULL);
$userData = array_filter((array)$userData, fn ($value) => $value !== NULL); $userData = array_filter((array)$userData, static fn ($value) => $value !== NULL);
$cleared = $cache->clear(); $cleared = $cache->clear();
$saved = ( ! empty($userData)) $saved = ( ! empty($userData))

View File

@ -25,7 +25,8 @@ use Aviat\AnimeClient\API\{
use Aviat\AnimeClient\API; use Aviat\AnimeClient\API;
use Aviat\AnimeClient\API\Anilist; use Aviat\AnimeClient\API\Anilist;
use Aviat\AnimeClient\API\Mapping\{AnimeWatchingStatus, MangaReadingStatus}; use Aviat\AnimeClient\API\Mapping\{AnimeWatchingStatus, MangaReadingStatus};
use Aviat\AnimeClient\Enum\{ListType, SyncAction}; use Aviat\AnimeClient\Enum;
use Aviat\AnimeClient\Enum\{MediaType, SyncAction};
use Aviat\AnimeClient\Types\FormItem; use Aviat\AnimeClient\Types\FormItem;
use Aviat\Ion\Di\Exception\ContainerException; use Aviat\Ion\Di\Exception\ContainerException;
use Aviat\Ion\Di\Exception\NotFoundException; use Aviat\Ion\Di\Exception\NotFoundException;
@ -73,7 +74,7 @@ final class SyncLists extends BaseCommand {
{ {
$this->init(); $this->init();
foreach ([ListType::ANIME, ListType::MANGA] as $type) foreach ([MediaType::ANIME, MediaType::MANGA] as $type)
{ {
// Main Sync flow // Main Sync flow
$this->fetchCount($type); $this->fetchCount($type);
@ -100,7 +101,7 @@ final class SyncLists extends BaseCommand {
$this->setCache($this->container->get('cache')); $this->setCache($this->container->get('cache'));
$config = $this->container->get('config'); $config = $this->container->get('config');
$anilistEnabled = $config->get([API::ANILIST, 'enabled']); $anilistEnabled = $config->get([Enum\API::ANILIST, 'enabled']);
// We can't sync kitsu against itself! // We can't sync kitsu against itself!
if ( ! $anilistEnabled) if ( ! $anilistEnabled)
@ -165,8 +166,8 @@ final class SyncLists extends BaseCommand {
$this->clearLine(); $this->clearLine();
return [ return [
API::ANILIST => $anilist, Enum\API::ANILIST => $anilist,
API::KITSU => $kitsu, Enum\API::KITSU => $kitsu,
]; ];
} }
@ -182,17 +183,17 @@ final class SyncLists extends BaseCommand {
$this->echo('Normalizing List Data'); $this->echo('Normalizing List Data');
$progress = new Widgets\ProgressBar($this->getConsole(), 2, 50, FALSE); $progress = new Widgets\ProgressBar($this->getConsole(), 2, 50, FALSE);
$kitsu = $this->transformKitsu($type, $data[API::KITSU]); $kitsu = $this->transformKitsu($type, $data[Enum\API::KITSU]);
$progress->incr(); $progress->incr();
$anilist = $this->transformAnilist($type, $data[API::ANILIST]); $anilist = $this->transformAnilist($type, $data[Enum\API::ANILIST]);
$progress->incr(); $progress->incr();
$this->clearLine(); $this->clearLine();
return [ return [
API::ANILIST => $anilist, Enum\API::ANILIST => $anilist,
API::KITSU => $kitsu, Enum\API::KITSU => $kitsu,
]; ];
} }
@ -207,7 +208,7 @@ final class SyncLists extends BaseCommand {
{ {
$this->echo('Comparing List Items'); $this->echo('Comparing List Items');
return $this->compareLists($type, $data[API::ANILIST], $data[API::KITSU]); return $this->compareLists($type, $data[Enum\API::ANILIST], $data[Enum\API::KITSU]);
} }
/** /**
@ -280,8 +281,8 @@ final class SyncLists extends BaseCommand {
private function fetchAnilist(string $type): array private function fetchAnilist(string $type): array
{ {
static $list = [ static $list = [
ListType::ANIME => NULL, MediaType::ANIME => NULL,
ListType::MANGA => NULL, MediaType::MANGA => NULL,
]; ];
// This uses a static so I don't have to fetch this list twice for a count // This uses a static so I don't have to fetch this list twice for a count
@ -435,12 +436,12 @@ final class SyncLists extends BaseCommand {
continue; continue;
} }
if (in_array(API::KITSU, $item['updateType'], TRUE)) if (in_array(Enum\API::KITSU, $item['updateType'], TRUE))
{ {
$kitsuUpdateItems[] = $item['data']; $kitsuUpdateItems[] = $item['data'];
} }
if (in_array(API::ANILIST, $item['updateType'], TRUE)) if (in_array(Enum\API::ANILIST, $item['updateType'], TRUE))
{ {
$anilistUpdateItems[] = $item['data']; $anilistUpdateItems[] = $item['data'];
} }
@ -448,7 +449,7 @@ final class SyncLists extends BaseCommand {
continue; continue;
} }
$statusMap = ($type === ListType::ANIME) ? AnimeWatchingStatus::class : MangaReadingStatus::class; $statusMap = ($type === MediaType::ANIME) ? AnimeWatchingStatus::class : MangaReadingStatus::class;
// Looks like this item only exists on Kitsu // Looks like this item only exists on Kitsu
$kItem = $kitsuItem['data']; $kItem = $kitsuItem['data'];
@ -528,7 +529,7 @@ final class SyncLists extends BaseCommand {
if ($kitsuItem['data']['status'] === 'completed' && $kitsuItem['data']['reconsuming'] === TRUE) if ($kitsuItem['data']['status'] === 'completed' && $kitsuItem['data']['reconsuming'] === TRUE)
{ {
$update['data']['reconsuming'] = FALSE; $update['data']['reconsuming'] = FALSE;
$return['updateType'][] = API::KITSU; $return['updateType'][] = Enum\API::KITSU;
} }
// If status is the same, and progress count is different, use greater progress // If status is the same, and progress count is different, use greater progress
@ -537,12 +538,12 @@ final class SyncLists extends BaseCommand {
if ($diff['progress'] === self::KITSU_GREATER) if ($diff['progress'] === self::KITSU_GREATER)
{ {
$update['data']['progress'] = $kitsuItem['data']['progress']; $update['data']['progress'] = $kitsuItem['data']['progress'];
$return['updateType'][] = API::ANILIST; $return['updateType'][] = Enum\API::ANILIST;
} }
else if($diff['progress'] === self::ANILIST_GREATER) else if($diff['progress'] === self::ANILIST_GREATER)
{ {
$update['data']['progress'] = $anilistItem['data']['progress']; $update['data']['progress'] = $anilistItem['data']['progress'];
$return['updateType'][] = API::KITSU; $return['updateType'][] = Enum\API::KITSU;
} }
} }
@ -552,12 +553,12 @@ final class SyncLists extends BaseCommand {
if ($dateDiff === self::KITSU_GREATER) if ($dateDiff === self::KITSU_GREATER)
{ {
$update['data']['status'] = $kitsuItem['data']['status']; $update['data']['status'] = $kitsuItem['data']['status'];
$return['updateType'][] = API::ANILIST; $return['updateType'][] = Enum\API::ANILIST;
} }
else if ($dateDiff === self::ANILIST_GREATER) else if ($dateDiff === self::ANILIST_GREATER)
{ {
$update['data']['status'] = $anilistItem['data']['status']; $update['data']['status'] = $anilistItem['data']['status'];
$return['updateType'][] = API::KITSU; $return['updateType'][] = Enum\API::KITSU;
} }
} }
@ -574,7 +575,7 @@ final class SyncLists extends BaseCommand {
$update['data']['progress'] = $kitsuItem['data']['progress']; $update['data']['progress'] = $kitsuItem['data']['progress'];
} }
$return['updateType'][] = API::ANILIST; $return['updateType'][] = Enum\API::ANILIST;
} }
else if($dateDiff === self::ANILIST_GREATER) else if($dateDiff === self::ANILIST_GREATER)
{ {
@ -585,7 +586,7 @@ final class SyncLists extends BaseCommand {
$update['data']['progress'] = $kitsuItem['data']['progress']; $update['data']['progress'] = $kitsuItem['data']['progress'];
} }
$return['updateType'][] = API::KITSU; $return['updateType'][] = Enum\API::KITSU;
} }
} }
@ -599,12 +600,12 @@ final class SyncLists extends BaseCommand {
) )
{ {
$update['data']['ratingTwenty'] = $kitsuItem['data']['ratingTwenty']; $update['data']['ratingTwenty'] = $kitsuItem['data']['ratingTwenty'];
$return['updateType'][] = API::ANILIST; $return['updateType'][] = Enum\API::ANILIST;
} }
else if($dateDiff === self::ANILIST_GREATER && $anilistItem['data']['rating'] !== 0) else if($dateDiff === self::ANILIST_GREATER && $anilistItem['data']['rating'] !== 0)
{ {
$update['data']['ratingTwenty'] = $anilistItem['data']['rating'] * 2; $update['data']['ratingTwenty'] = $anilistItem['data']['rating'] * 2;
$return['updateType'][] = API::KITSU; $return['updateType'][] = Enum\API::KITSU;
} }
} }
@ -614,12 +615,12 @@ final class SyncLists extends BaseCommand {
if ( ! empty($kitsuItem['data']['notes'])) if ( ! empty($kitsuItem['data']['notes']))
{ {
$update['data']['notes'] = $kitsuItem['data']['notes']; $update['data']['notes'] = $kitsuItem['data']['notes'];
$return['updateType'][] = API::ANILIST; $return['updateType'][] = Enum\API::ANILIST;
} }
else else
{ {
$update['data']['notes'] = $anilistItem['data']['notes']; $update['data']['notes'] = $anilistItem['data']['notes'];
$return['updateType'][] = API::KITSU; $return['updateType'][] = Enum\API::KITSU;
} }
} }
@ -629,12 +630,12 @@ final class SyncLists extends BaseCommand {
if ($diff['reconsumeCount'] === self::KITSU_GREATER) if ($diff['reconsumeCount'] === self::KITSU_GREATER)
{ {
$update['data']['reconsumeCount'] = $kitsuItem['data']['reconsumeCount']; $update['data']['reconsumeCount'] = $kitsuItem['data']['reconsumeCount'];
$return['updateType'][] = API::ANILIST; $return['updateType'][] = Enum\API::ANILIST;
} }
else if ($diff['reconsumeCount'] === self::ANILIST_GREATER) else if ($diff['reconsumeCount'] === self::ANILIST_GREATER)
{ {
$update['data']['reconsumeCount'] = $anilistItem['data']['reconsumeCount']; $update['data']['reconsumeCount'] = $anilistItem['data']['reconsumeCount'];
$return['updateType'][] = API::KITSU; $return['updateType'][] = Enum\API::KITSU;
} }
} }
@ -645,8 +646,8 @@ final class SyncLists extends BaseCommand {
} }
$return['meta'] = [ $return['meta'] = [
API::KITSU => $kitsuItem['data'], Enum\API::KITSU => $kitsuItem['data'],
API::ANILIST => $anilistItem['data'], Enum\API::ANILIST => $anilistItem['data'],
'dateDiff' => $dateDiff, 'dateDiff' => $dateDiff,
'diff' => $diff, 'diff' => $diff,
]; ];
@ -656,7 +657,7 @@ final class SyncLists extends BaseCommand {
// Fill in missing data values for update // Fill in missing data values for update
// so I don't have to create a really complex graphql query // so I don't have to create a really complex graphql query
// to handle each combination of fields // to handle each combination of fields
if ($return['updateType'][0] === API::ANILIST) if ($return['updateType'][0] === Enum\API::ANILIST)
{ {
// Anilist GraphQL expects a rating from 1-100 // Anilist GraphQL expects a rating from 1-100
$prevData = [ $prevData = [
@ -673,7 +674,7 @@ final class SyncLists extends BaseCommand {
$return['data']['data'] = array_merge($prevData, $return['data']['data']); $return['data']['data'] = array_merge($prevData, $return['data']['data']);
} }
else if ($return['updateType'][0] === API::KITSU) else if ($return['updateType'][0] === Enum\API::KITSU)
{ {
$prevData = [ $prevData = [
'notes' => $anilistItem['data']['notes'], 'notes' => $anilistItem['data']['notes'],
@ -707,7 +708,7 @@ final class SyncLists extends BaseCommand {
* @param string $type * @param string $type
* @throws Throwable * @throws Throwable
*/ */
private function updateKitsuListItems(array $itemsToUpdate, string $action = SyncAction::UPDATE, string $type = ListType::ANIME): void private function updateKitsuListItems(array $itemsToUpdate, string $action = SyncAction::UPDATE, string $type = MediaType::ANIME): void
{ {
$requester = new ParallelAPIRequest(); $requester = new ParallelAPIRequest();
foreach($itemsToUpdate as $item) foreach($itemsToUpdate as $item)
@ -776,7 +777,7 @@ final class SyncLists extends BaseCommand {
* @param string $type * @param string $type
* @throws Throwable * @throws Throwable
*/ */
private function updateAnilistListItems(array $itemsToUpdate, string $action = SyncAction::UPDATE, string $type = ListType::ANIME): void private function updateAnilistListItems(array $itemsToUpdate, string $action = SyncAction::UPDATE, string $type = MediaType::ANIME): void
{ {
$requester = new ParallelAPIRequest(); $requester = new ParallelAPIRequest();

View File

@ -69,11 +69,11 @@ final class UpdateThumbnails extends ClearThumbnails {
public function getImageList(): array public function getImageList(): array
{ {
$animeIds = array_map( $animeIds = array_map(
fn ($item) => $item['media']['id'], static fn ($item) => $item['media']['id'],
$this->kitsuModel->getThumbList('ANIME') $this->kitsuModel->getThumbList('ANIME')
); );
$mangaIds = array_map( $mangaIds = array_map(
fn ($item) => $item['media']['id'], static fn ($item) => $item['media']['id'],
$this->kitsuModel->getThumbList('MANGA') $this->kitsuModel->getThumbList('MANGA')
); );

View File

@ -26,6 +26,7 @@ final class VerticalTabs {
* also used to generate id attributes * also used to generate id attributes
* @param array $tabData The data used to create the tab content, indexed by the tab label * @param array $tabData The data used to create the tab content, indexed by the tab label
* @param callable $cb The function to generate the tab content * @param callable $cb The function to generate the tab content
* @param string $className
* @return string * @return string
*/ */
public function __invoke( public function __invoke(

View File

@ -46,49 +46,41 @@ class Controller {
/** /**
* The authentication object * The authentication object
* @var Auth $auth ;
*/ */
protected Auth $auth; protected Auth $auth;
/** /**
* Cache manager * Cache manager
* @var CacheInterface
*/ */
protected CacheInterface $cache; protected CacheInterface $cache;
/** /**
* The global configuration object * The global configuration object
* @var ConfigInterface $config
*/ */
public ConfigInterface $config; public ConfigInterface $config;
/** /**
* Request object * Request object
* @var ServerRequestInterface $request
*/ */
protected ServerRequestInterface $request; protected ServerRequestInterface $request;
/** /**
* Url generation class * Url generation class
* @var UrlGenerator
*/ */
protected UrlGenerator $urlGenerator; protected UrlGenerator $urlGenerator;
/** /**
* Aura url generator * Aura url generator
* @var Generator
*/ */
protected Generator $url; protected Generator $url;
/** /**
* Session segment * Session segment
* @var Segment
*/ */
protected Segment $session; protected Segment $session;
/** /**
* Common data to be sent to views * Common data to be sent to views
* @var array
*/ */
protected array $baseData = []; protected array $baseData = [];

View File

@ -66,17 +66,17 @@ final class Anime extends BaseController {
/** /**
* Show a portion, or all of the anime list * Show a portion, or all of the anime list
* *
* @param string|int $type - The section of the list * @param string|int $status - The section of the list
* @param string $view - List or cover view * @param string|null $view - List or cover view
* @throws ContainerException * @throws ContainerException
* @throws NotFoundException * @throws NotFoundException
* @throws InvalidArgumentException * @throws InvalidArgumentException
* @throws Throwable * @throws Throwable
* @return void * @return void
*/ */
public function index($type = KitsuWatchingStatus::WATCHING, string $view = NULL): void public function index($status = KitsuWatchingStatus::WATCHING, ?string $view = NULL): void
{ {
if ( ! in_array($type, [ if ( ! in_array($status, [
'all', 'all',
'watching', 'watching',
'plan_to_watch', 'plan_to_watch',
@ -88,10 +88,10 @@ final class Anime extends BaseController {
$this->errorPage(404, 'Not Found', 'Page not found'); $this->errorPage(404, 'Not Found', 'Page not found');
} }
$title = array_key_exists($type, AnimeWatchingStatus::ROUTE_TO_TITLE) $title = array_key_exists($status, AnimeWatchingStatus::ROUTE_TO_TITLE)
? $this->formatTitle( ? $this->formatTitle(
$this->config->get('whose_list') . "'s Anime List", $this->config->get('whose_list') . "'s Anime List",
AnimeWatchingStatus::ROUTE_TO_TITLE[$type] AnimeWatchingStatus::ROUTE_TO_TITLE[$status]
) )
: ''; : '';
@ -100,8 +100,8 @@ final class Anime extends BaseController {
'list' => 'list' 'list' => 'list'
]; ];
$data = ($type !== 'all') $data = ($status !== 'all')
? $this->model->getList(AnimeWatchingStatus::ROUTE_TO_KITSU[$type]) ? $this->model->getList(AnimeWatchingStatus::ROUTE_TO_KITSU[$status])
: $this->model->getAllLists(); : $this->model->getAllLists();
$this->outputHTML('anime/' . $viewMap[$view], [ $this->outputHTML('anime/' . $viewMap[$view], [
@ -305,17 +305,17 @@ final class Anime extends BaseController {
/** /**
* View details of an anime * View details of an anime
* *
* @param string $animeId * @param string $id
* @throws ContainerException * @throws ContainerException
* @throws NotFoundException * @throws NotFoundException
* @throws InvalidArgumentException * @throws InvalidArgumentException
* @return void * @return void
*/ */
public function details(string $animeId): void public function details(string $id): void
{ {
try try
{ {
$data = $this->model->getAnime($animeId); $data = $this->model->getAnime($id);
if ($data->isEmpty()) if ($data->isEmpty())
{ {
@ -349,7 +349,7 @@ final class Anime extends BaseController {
} }
} }
public function random() public function random(): void
{ {
try try
{ {

View File

@ -94,7 +94,7 @@ final class AnimeCollection extends BaseController {
* @throws InvalidArgumentException * @throws InvalidArgumentException
* @return void * @return void
*/ */
public function view($view): void public function view(string $view = ''): void
{ {
$viewMap = [ $viewMap = [
'' => 'cover', '' => 'cover',

View File

@ -303,19 +303,16 @@ final class Manga extends Controller {
/** /**
* View details of an manga * View details of an manga
* *
* @param string $manga_id * @param string $id
* @throws ContainerException * @throws ContainerException
* @throws NotFoundException * @throws NotFoundException
* @throws InvalidArgumentException * @throws InvalidArgumentException
* @throws Throwable * @throws Throwable
* @return void * @return void
*/ */
public function details($manga_id): void public function details(string $id): void
{ {
$data = $this->model->getManga($manga_id); $data = $this->model->getManga($id);
$staff = [];
$characters = [];
if ($data->isEmpty()) if ($data->isEmpty())
{ {
$this->notFound( $this->notFound(
@ -333,9 +330,7 @@ final class Manga extends Controller {
'Manga', 'Manga',
$data['title'] $data['title']
), ),
'characters' => $characters,
'data' => $data, 'data' => $data,
'staff' => $staff,
]); ]);
} }
@ -351,9 +346,6 @@ final class Manga extends Controller {
public function random(): void public function random(): void
{ {
$data = $this->model->getRandomManga(); $data = $this->model->getRandomManga();
$staff = [];
$characters = [];
if ($data->isEmpty()) if ($data->isEmpty())
{ {
$this->notFound( $this->notFound(
@ -371,9 +363,7 @@ final class Manga extends Controller {
'Manga', 'Manga',
$data['title'] $data['title']
), ),
'characters' => $characters,
'data' => $data, 'data' => $data,
'staff' => $staff,
]); ]);
} }
} }

View File

@ -14,9 +14,11 @@
* @link https://git.timshomepage.net/timw4mail/HummingBirdAnimeClient * @link https://git.timshomepage.net/timw4mail/HummingBirdAnimeClient
*/ */
namespace Aviat\AnimeClient; namespace Aviat\AnimeClient\Enum;
class API { use Aviat\Ion\Enum;
final class API extends Enum {
public const ANILIST = 'anilist'; public const ANILIST = 'anilist';
public const KITSU = 'kitsu'; public const KITSU = 'kitsu';
} }

View File

@ -19,9 +19,9 @@ namespace Aviat\AnimeClient\Enum;
use Aviat\Ion\Enum as BaseEnum; use Aviat\Ion\Enum as BaseEnum;
/** /**
* Types of lists * Types of media
*/ */
final class ListType extends BaseEnum { final class MediaType extends BaseEnum {
public const ANIME = 'anime'; public const ANIME = 'anime';
public const DRAMA = 'drama'; public const DRAMA = 'drama';
public const MANGA = 'manga'; public const MANGA = 'manga';

View File

@ -49,7 +49,8 @@ final class Picture {
]; ];
/** /**
* Create the html for an html picture element * Create the html for an html picture element.
* Uses .webp images with fallback
* *
* @param string $uri * @param string $uri
* @param string $fallbackExt * @param string $fallbackExt

View File

@ -187,14 +187,14 @@ final class Kitsu {
$host = parse_url($url, \PHP_URL_HOST); $host = parse_url($url, \PHP_URL_HOST);
$links[] = [ $links[] = [
'meta' => static::getServiceMetaData($host), 'meta' => self::getServiceMetaData($host),
'link' => $streamingLink['url'], 'link' => $streamingLink['url'],
'subs' => $streamingLink['subs'], 'subs' => $streamingLink['subs'],
'dubs' => $streamingLink['dubs'] 'dubs' => $streamingLink['dubs']
]; ];
} }
usort($links, fn ($a, $b) => $a['meta']['name'] <=> $b['meta']['name']); usort($links, static fn ($a, $b) => $a['meta']['name'] <=> $b['meta']['name']);
return $links; return $links;
} }
@ -282,7 +282,7 @@ final class Kitsu {
*/ */
protected static function getServiceMetaData(string $hostname = NULL): array protected static function getServiceMetaData(string $hostname = NULL): array
{ {
$hostname = str_replace('www.', '', $hostname); $hostname = str_replace('www.', '', $hostname ?? '');
$serviceMap = [ $serviceMap = [
'animelab.com' => [ 'animelab.com' => [
@ -412,11 +412,11 @@ final class Kitsu {
/** /**
* Determine if an alternate title is unique enough to list * Determine if an alternate title is unique enough to list
* *
* @param string $title * @param string|null $title
* @param array $existingTitles * @param array $existingTitles
* @return bool * @return bool
*/ */
private static function titleIsUnique(string $title = NULL, array $existingTitles = []): bool private static function titleIsUnique(?string $title = NULL, array $existingTitles = []): bool
{ {
if (empty($title)) if (empty($title))
{ {

View File

@ -134,6 +134,7 @@ final class AnimeCollection extends Collection {
} }
// Organize the media types into groups // Organize the media types into groups
// @TODO: make this more database-driven, rather than hardcoded
return [ return [
'Common' => [ 'Common' => [
2 => $flatList[2], // Blu-ray 2 => $flatList[2], // Blu-ray

View File

@ -28,7 +28,7 @@ abstract class DB {
* The database connection information array * The database connection information array
* @var array $dbConfig * @var array $dbConfig
*/ */
protected $dbConfig = []; protected array $dbConfig = [];
/** /**
* Constructor * Constructor

View File

@ -22,34 +22,16 @@ use Aviat\AnimeClient\API\Kitsu\Enum\AnimeAiringStatus;
* Type representing an anime within a watch list * Type representing an anime within a watch list
*/ */
class Anime extends AbstractType { class Anime extends AbstractType {
/**
* @var string
*/
public ?string $age_rating; public ?string $age_rating;
/**
* @var string
*/
public ?string $age_rating_guide; public ?string $age_rating_guide;
/**
* @var string
*/
public ?string $cover_image; public ?string $cover_image;
/**
* @var string|int
*/
public ?int $episode_count; public ?int $episode_count;
/**
* @var string|int
*/
public ?int $episode_length; public ?int $episode_length;
/**
* @var array
*/
public array $genres = []; public array $genres = [];
/** /**
@ -57,67 +39,33 @@ class Anime extends AbstractType {
*/ */
public $id = ''; public $id = '';
/**
* @var array
*/
public array $included = []; public array $included = [];
/**
* @var string
*/
public ?string $show_type; public ?string $show_type;
/**
* @var string
*/
public ?string $slug; public ?string $slug;
/**
* @var AnimeAiringStatus
*/
public string $status = AnimeAiringStatus::FINISHED_AIRING; public string $status = AnimeAiringStatus::FINISHED_AIRING;
/**
* @var array
*/
public ?array $streaming_links = []; public ?array $streaming_links = [];
/**
* @var string
*/
public ?string $synopsis; public ?string $synopsis;
/**
* @var string
*/
public ?string $title; public ?string $title;
/**
* @var array
*/
public array $titles = []; public array $titles = [];
/**
* @var array
*/
public array $titles_more = []; public array $titles_more = [];
/**
* @var string
*/
public ?string $trailer_id; public ?string $trailer_id;
/** /**
* Length of the entire series in seconds * Length of the entire series in seconds
*
* @var int|null
*/ */
public ?int $total_length; public ?int $total_length;
/** /**
* Kitsu detail page url * Kitsu detail page url
*
* @var string
*/ */
public ?string $url; public ?string $url;
} }

View File

@ -20,14 +20,8 @@ namespace Aviat\AnimeClient\Types;
* Type representing an anime watch list item * Type representing an anime watch list item
*/ */
final class AnimeListItem extends AbstractType { final class AnimeListItem extends AbstractType {
/**
* @var string
*/
public ?string $id; public ?string $id;
/**
* @var string
*/
public ?string $mal_id; public ?string $mal_id;
/** /**
@ -35,47 +29,26 @@ final class AnimeListItem extends AbstractType {
*/ */
public $anilist_item_id; public $anilist_item_id;
/**
* @var array
*/
public array $episodes = [ public array $episodes = [
'length' => 0, 'length' => 0,
'total' => 0, 'total' => 0,
'watched' => '', 'watched' => '',
]; ];
/**
* @var array
*/
public array $airing = [ public array $airing = [
'status' => '', 'status' => '',
'started' => '', 'started' => '',
'ended' => '', 'ended' => '',
]; ];
/**
* @var Anime
*/
public ?Anime $anime; public ?Anime $anime;
/**
* @var string
*/
public ?string $notes; public ?string $notes;
/**
* @var bool
*/
public bool $private = FALSE; public bool $private = FALSE;
/**
* @var bool
*/
public bool $rewatching = FALSE; public bool $rewatching = FALSE;
/**
* @var int
*/
public int $rewatched = 0; public int $rewatched = 0;
/** /**
@ -85,10 +58,8 @@ final class AnimeListItem extends AbstractType {
/** /**
* One of Aviat\AnimeClient\API\Enum\AnimeWatchingStatus * One of Aviat\AnimeClient\API\Enum\AnimeWatchingStatus
*
* @var string
*/ */
public $watching_status; public string $watching_status;
public function setAnime($anime): void public function setAnime($anime): void
{ {

View File

@ -20,18 +20,9 @@ namespace Aviat\AnimeClient\Types;
* Type representing an Anime object for a detail page * Type representing an Anime object for a detail page
*/ */
final class AnimePage extends Anime { final class AnimePage extends Anime {
/**
* @var array
*/
public array $characters = []; public array $characters = [];
/**
* @var array
*/
public array $links = []; public array $links = [];
/**
* @var array
*/
public array $staff = []; public array $staff = [];
} }

View File

@ -20,14 +20,8 @@ namespace Aviat\AnimeClient\Types;
* Type representing a character for display * Type representing a character for display
*/ */
final class Character extends AbstractType { final class Character extends AbstractType {
/**
* @var array
*/
public array $castings = []; public array $castings = [];
/**
* @var string
*/
public ?string $description; public ?string $description;
/** /**
@ -35,29 +29,14 @@ final class Character extends AbstractType {
*/ */
public $id; public $id;
/**
* @var array
*/
public array $included = []; public array $included = [];
/**
* @var Media
*/
public ?Media $media; public ?Media $media;
/**
* @var string
*/
public ?string $name; public ?string $name;
/**
* @var array
*/
public array $names = []; public array $names = [];
/**
* @var array
*/
public array $otherNames = []; public array $otherNames = [];
public function setMedia ($media): void public function setMedia ($media): void

View File

@ -17,13 +17,7 @@
namespace Aviat\AnimeClient\Types; namespace Aviat\AnimeClient\Types;
final class Characters extends AbstractType { final class Characters extends AbstractType {
/**
* @var array
*/
public array $main = []; public array $main = [];
/**
* @var array
*/
public array $supporting = []; public array $supporting = [];
} }

View File

@ -22,28 +22,16 @@ class Config extends AbstractType {
// Config files/namespaces // Config files/namespaces
// ------------------------------------------------------------------------ // ------------------------------------------------------------------------
/**
* @var Config\Anilist
*/
public ?Config\Anilist $anilist; public ?Config\Anilist $anilist;
/**
* @var Config\Cache
*/
public ?Config\Cache $cache; public ?Config\Cache $cache;
/**
* @var Config\Database
*/
public ?Config\Database $database; public ?Config\Database $database;
// ------------------------------------------------------------------------ // ------------------------------------------------------------------------
// Settings in config.toml // Settings in config.toml
// ------------------------------------------------------------------------ // ------------------------------------------------------------------------
/**
* @var string
*/
public ?string $asset_path; // Path to public folder for urls public ?string $asset_path; // Path to public folder for urls
/** /**
@ -60,8 +48,6 @@ class Config extends AbstractType {
/** /**
* Default Anime list status page, values are listed in * Default Anime list status page, values are listed in
* Aviat\AnimeClient\API\Enum\AnimeWatchingStatus\Title * Aviat\AnimeClient\API\Enum\AnimeWatchingStatus\Title
*
* @var string
*/ */
public ?string $default_anime_list_path; public ?string $default_anime_list_path;
@ -75,8 +61,6 @@ class Config extends AbstractType {
/** /**
* Default Manga list status page, values are listed in * Default Manga list status page, values are listed in
* Aviat\AnimeClient\API\Enum\MangaReadingStatus\Title * Aviat\AnimeClient\API\Enum\MangaReadingStatus\Title
*
* @var string
*/ */
public ?string $default_manga_list_path; public ?string $default_manga_list_path;
@ -85,25 +69,13 @@ class Config extends AbstractType {
*/ */
public ?string $default_view_type; public ?string $default_view_type;
/**
* @var string
*/
public ?string $kitsu_username; public ?string $kitsu_username;
/**
* @var bool
*/
public bool $secure_urls = TRUE; public bool $secure_urls = TRUE;
/** public bool $show_anime_collection = FALSE;
* @var bool
*/
public $show_anime_collection = FALSE;
/** public bool $show_manga_collection = FALSE;
* @var bool
*/
public $show_manga_collection = FALSE;
/** /**
* CSS theme: light, dark, or auto-switching * CSS theme: light, dark, or auto-switching
@ -112,9 +84,6 @@ class Config extends AbstractType {
*/ */
public ?string $theme; public ?string $theme;
/**
* @var string
*/
public ?string $whose_list; public ?string $whose_list;
// ------------------------------------------------------------------------ // ------------------------------------------------------------------------
@ -135,34 +104,16 @@ class Config extends AbstractType {
// Generated config values // Generated config values
// ------------------------------------------------------------------------ // ------------------------------------------------------------------------
/**
* @var string
*/
public ?string $asset_dir; // Path to public folder for local files public ?string $asset_dir; // Path to public folder for local files
/**
* @var string
*/
public ?string $base_config_dir; public ?string $base_config_dir;
/**
* @var string
*/
public ?string $config_dir; public ?string $config_dir;
/**
* @var string
*/
public ?string $data_cache_path; public ?string $data_cache_path;
/**
* @var string
*/
public ?string $img_cache_path; public ?string $img_cache_path;
/**
* @var string
*/
public ?string $view_path; public ?string $view_path;
public function setAnilist ($data): void public function setAnilist ($data): void

View File

@ -19,38 +19,17 @@ namespace Aviat\AnimeClient\Types\Config;
use Aviat\AnimeClient\Types\AbstractType; use Aviat\AnimeClient\Types\AbstractType;
class Anilist extends AbstractType { class Anilist extends AbstractType {
/** public bool $enabled = FALSE;
* @var bool
*/
public $enabled = FALSE;
/** public ?string $client_id;
* @var string
*/
public $client_id;
/** public ?string $client_secret;
* @var string
*/
public $client_secret;
/** public ?string $access_token;
* @var string
*/
public $access_token;
/** public ?int $access_token_expires;
* @var string
*/
public $access_token_expires;
/** public ?string $refresh_token;
* @var string
*/
public $refresh_token;
/** public ?string $username;
* @var string
*/
public $username;
} }

View File

@ -22,21 +22,24 @@ class Cache extends AbstractType {
/** /**
* @var string * @var string
*/ */
public $driver; public string $driver = 'null';
public $host; public ?string $host;
/**
* @var string|int|null
*/
public $port; public $port;
public $database; public ?string $database;
/** /**
* @var array * @var array
*/ */
public $connection = []; public array $connection = [];
/** /**
* @var array * @var array
*/ */
public $options = []; public array $options = [];
} }

View File

@ -22,35 +22,35 @@ class Database extends AbstractType {
/** /**
* @var string * @var string
*/ */
public $type; public string $type = 'sqlite';
/** /**
* @var string * @var string|null
*/ */
public $host; public ?string $host;
/** /**
* @var string * @var string|null
*/ */
public $user; public ?string $user;
/** /**
* @var string * @var string|null
*/ */
public $pass; public ?string $pass;
/** /**
* @var string|int * @var string|int|null
*/ */
public $port; public $port;
/** /**
* @var string * @var string|null
*/ */
public $database; public ?string $database;
/** /**
* @var string * @var string|null
*/ */
public $file; public ?string $file;
} }

View File

@ -25,9 +25,6 @@ class FormItem extends AbstractType {
*/ */
public $id; public $id;
/**
* @var string
*/
public ?string $anilist_item_id; public ?string $anilist_item_id;
/** /**
@ -35,9 +32,6 @@ class FormItem extends AbstractType {
*/ */
public $mal_id; public $mal_id;
/**
* @var FormItemData
*/
public ?FormItemData $data; public ?FormItemData $data;
public function setData($value): void public function setData($value): void

View File

@ -20,14 +20,8 @@ namespace Aviat\AnimeClient\Types;
* Type representing a Media object for editing/syncing * Type representing a Media object for editing/syncing
*/ */
class FormItemData extends AbstractType { class FormItemData extends AbstractType {
/**
* @var string
*/
public ?string $notes; public ?string $notes;
/**
* @var bool
*/
public ?bool $private = FALSE; public ?bool $private = FALSE;
/** /**
@ -50,9 +44,6 @@ class FormItemData extends AbstractType {
*/ */
public $reconsumeCount; public $reconsumeCount;
/**
* @var bool
*/
public bool $reconsuming = FALSE; public bool $reconsuming = FALSE;
/** /**
@ -62,8 +53,6 @@ class FormItemData extends AbstractType {
/** /**
* W3C Format Date string * W3C Format Date string
*
* @var string
*/ */
public ?string $updatedAt; public ?string $updatedAt;
} }

View File

@ -20,47 +20,47 @@ use DateTimeImmutable;
class HistoryItem extends AbstractType { class HistoryItem extends AbstractType {
/** /**
* @var string Title of the anime/manga * Title of the anime/manga
*/ */
public string $title = ''; public string $title = '';
/** /**
* @var string The url of the cover image * The url of the cover image
*/ */
public string $coverImg = ''; public string $coverImg = '';
/** /**
* @var string The type of action done * The type of action done
*/ */
public string $action = ''; public string $action = '';
/** /**
* @var bool Is this item a combination of items? * Is this item a combination of items?
*/ */
public bool $isAggregate = FALSE; public bool $isAggregate = FALSE;
/** /**
* @var string The kind of history event * The kind of history event
*/ */
public string $kind = ''; public string $kind = '';
/** /**
* @var DateTimeImmutable When the item was last updated * When the item was last updated
*/ */
public ?DateTimeImmutable $updated = NULL; public ?DateTimeImmutable $updated = NULL;
/** /**
* @var array Range of updated times for the aggregated item * Range of updated times for the aggregated item
*/ */
public array $dateRange = []; public array $dateRange = [];
/** /**
* @var string Url to details page * Url to details page
*/ */
public string $url = ''; public string $url = '';
/** /**
* @var array The item before transformation * The item before transformation
*/ */
public array $original = []; public array $original = [];
} }

View File

@ -17,13 +17,7 @@
namespace Aviat\AnimeClient\Types; namespace Aviat\AnimeClient\Types;
final class Media extends AbstractType { final class Media extends AbstractType {
/**
* @var array
*/
public array $anime = []; public array $anime = [];
/**
* @var array
*/
public array $manga = []; public array $manga = [];
} }

View File

@ -20,48 +20,21 @@ namespace Aviat\AnimeClient\Types;
* Type representing a Kitsu user for display * Type representing a Kitsu user for display
*/ */
final class User extends AbstractType { final class User extends AbstractType {
/**
* @var string
*/
public ?string $about; public ?string $about;
/**
* @var string
*/
public ?string $avatar; public ?string $avatar;
/**
* @var array
*/
public ?array $favorites; public ?array $favorites;
/**
* @var string
*/
public ?string $location; public ?string $location;
/**
* @var string
*/
public ?string $name; public ?string $name;
/**
* @var string
*/
public ?string $slug; public ?string $slug;
/**
* @var array
*/
public ?array $stats; public ?array $stats;
/**
* @var array
*/
public ?array $waifu; public ?array $waifu;
/**
* @var string
*/
public ?string $website; public ?string $website;
} }

View File

@ -49,7 +49,7 @@ class Event {
// Call each subscriber with the provided arguments // Call each subscriber with the provided arguments
if (array_key_exists($eventName, static::$eventMap)) if (array_key_exists($eventName, static::$eventMap))
{ {
array_walk(static::$eventMap[$eventName], fn ($fn) => $fn(...$args)); array_walk(static::$eventMap[$eventName], static fn ($fn) => $fn(...$args));
} }
} }
} }

View File

@ -37,7 +37,7 @@ class Friend {
* Reflection class of the object * Reflection class of the object
* @var ReflectionClass * @var ReflectionClass
*/ */
private $_reflect_; private ReflectionClass $_reflect_;
/** /**
* Create a friend object * Create a friend object

View File

@ -180,6 +180,7 @@ class HttpView implements ViewInterface{
/** /**
* Send the appropriate response * Send the appropriate response
* *
* @codeCoverageIgnore
* @throws DoubleRenderException * @throws DoubleRenderException
* @throws \InvalidArgumentException * @throws \InvalidArgumentException
* @return void * @return void

View File

@ -92,4 +92,10 @@ class UtilTest extends AnimeClientTestCase {
]); ]);
$this->assertEquals(!$expected, $this->util->isFormPage()); $this->assertEquals(!$expected, $this->util->isFormPage());
} }
public function testAriaCurrent(): void
{
$this->assertEquals('true', Util::ariaCurrent(true));
$this->assertEquals('false', Util::ariaCurrent(false));
}
} }

29
tests/Ion/EventTest.php Normal file
View File

@ -0,0 +1,29 @@
<?php declare(strict_types=1);
/**
* Hummingbird Anime List Client
*
* An API client for Kitsu to manage anime and manga watch lists
*
* PHP version 7.4
*
* @package HummingbirdAnimeClient
* @author Timothy J. Warren <tim@timshomepage.net>
* @copyright 2015 - 2020 Timothy J. Warren
* @license http://www.opensource.org/licenses/mit-license.html MIT License
* @version 5.1
* @link https://git.timshomepage.net/timw4mail/HummingBirdAnimeClient
*/
namespace Aviat\Ion\Tests;
use Aviat\Ion\Event;
use PHPUnit\Framework\TestCase;
class EventTest extends TestCase {
public function testEmit(): void
{
Event::on('test-event', fn ($fired) => $this->assertTrue($fired));
Event::emit('test-event', [true]);
}
}

View File

@ -29,7 +29,7 @@ class HtmlViewTest extends HttpViewTest {
$this->view = new TestHtmlView($this->container); $this->view = new TestHtmlView($this->container);
} }
public function testRenderTemplate() public function testRenderTemplate(): void
{ {
$path = _dir(self::TEST_VIEW_DIR, 'test_view.php'); $path = _dir(self::TEST_VIEW_DIR, 'test_view.php');
$expected = '<tag>foo</tag>'; $expected = '<tag>foo</tag>';

View File

@ -32,7 +32,7 @@ class HttpViewTest extends IonTestCase {
$this->friend = new Friend($this->view); $this->friend = new Friend($this->view);
} }
public function testGetOutput() public function testGetOutput():void
{ {
$this->friend->setOutput('foo'); $this->friend->setOutput('foo');
$this->assertEquals('foo', $this->friend->getOutput()); $this->assertEquals('foo', $this->friend->getOutput());
@ -42,34 +42,34 @@ class HttpViewTest extends IonTestCase {
$this->assertTrue($this->friend->hasRendered); $this->assertTrue($this->friend->hasRendered);
} }
public function testSetOutput() public function testSetOutput():void
{ {
$same = $this->view->setOutput('<h1></h1>'); $same = $this->view->setOutput('<h1></h1>');
$this->assertEquals($same, $this->view); $this->assertEquals($same, $this->view);
$this->assertEquals('<h1></h1>', $this->view->getOutput()); $this->assertEquals('<h1></h1>', $this->view->getOutput());
} }
public function testAppendOutput() public function testAppendOutput():void
{ {
$this->view->setOutput('<h1>'); $this->view->setOutput('<h1>');
$this->view->appendOutput('</h1>'); $this->view->appendOutput('</h1>');
$this->assertEquals('<h1></h1>', $this->view->getOutput()); $this->assertEquals('<h1></h1>', $this->view->getOutput());
} }
public function testSetStatusCode() public function testSetStatusCode():void
{ {
$view = $this->view->setStatusCode(404); $view = $this->view->setStatusCode(404);
$this->assertEquals(404, $view->response->getStatusCode()); $this->assertEquals(404, $view->response->getStatusCode());
} }
public function testAddHeader() public function testAddHeader():void
{ {
$view = $this->view->addHeader('foo', 'bar'); $view = $this->view->addHeader('foo', 'bar');
$this->assertTrue($view->response->hasHeader('foo')); $this->assertTrue($view->response->hasHeader('foo'));
$this->assertEquals(['bar'], $view->response->getHeader('foo')); $this->assertEquals(['bar'], $view->response->getHeader('foo'));
} }
public function testSendDoubleRenderException() public function testSendDoubleRenderException():void
{ {
$this->expectException(DoubleRenderException::class); $this->expectException(DoubleRenderException::class);
$this->expectExceptionMessage('A view can only be rendered once, because headers can only be sent once.'); $this->expectExceptionMessage('A view can only be rendered once, because headers can only be sent once.');
@ -81,7 +81,7 @@ class HttpViewTest extends IonTestCase {
$this->view->send(); $this->view->send();
} }
public function test__toStringDoubleRenderException() public function test__toStringDoubleRenderException():void
{ {
$this->expectException(DoubleRenderException::class); $this->expectException(DoubleRenderException::class);
$this->expectExceptionMessage('A view can only be rendered once, because headers can only be sent once.'); $this->expectExceptionMessage('A view can only be rendered once, because headers can only be sent once.');
@ -92,4 +92,18 @@ class HttpViewTest extends IonTestCase {
// Second render // Second render
$this->view->__toString(); $this->view->__toString();
} }
public function testRedirect(): void
{
$this->friend->redirect('http://example.com');
$this->assertInstanceOf(\Laminas\Diactoros\Response\RedirectResponse::class, $this->friend->response);
}
public function testOutput(): void
{
$this->friend->setOutput('<h1></h1>');
$this->friend->send();
$this->assertTrue($this->friend->hasRendered);
}
} }

View File

@ -28,7 +28,7 @@ class JsonViewTest extends HttpViewTest {
$this->friend = new Friend($this->view); $this->friend = new Friend($this->view);
} }
public function testSetOutputJSON() public function testSetOutputJSON():void
{ {
// Extend view class to remove destructor which does output // Extend view class to remove destructor which does output
$view = new TestJsonView(); $view = new TestJsonView();
@ -40,7 +40,7 @@ class JsonViewTest extends HttpViewTest {
$this->assertEquals($expected, $view->getOutput()); $this->assertEquals($expected, $view->getOutput());
} }
public function testSetOutput() public function testSetOutput():void
{ {
// Directly set string // Directly set string
$view = new TestJsonView(); $view = new TestJsonView();
@ -50,7 +50,7 @@ class JsonViewTest extends HttpViewTest {
$this->assertEquals($expected, $view->getOutput()); $this->assertEquals($expected, $view->getOutput());
} }
public function testOutput() public function testOutputType():void
{ {
$this->assertEquals('application/json', $this->friend->contentType); $this->assertEquals('application/json', $this->friend->contentType);
} }