Version 5.1 - All the GraphQL #32

Closed
timw4mail wants to merge 1160 commits from develop into master
17 changed files with 0 additions and 1494 deletions
Showing only changes of commit 276c492355 - Show all commits

169
build.xml
View File

@ -1,169 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<project default="full-build" name="animeclient" basedir=".">
<autoloader autoloaderpath="${project.basedir}/vendor/autoload.php" />
<!-- By default, we assume all tools to be on the $PATH -->
<property name="pdepend" value="pdepend" />
<property name="phpcpd" value="phpcpd" />
<property name="phpdox" value="phpdox" />
<property name="phploc" value="phploc" />
<property name="phpmd" value="phpmd" />
<property name="phpunit" value="phpunit" />
<property name="sonar" value="sonar-runner" />
<target name="full-build"
depends="prepare,static-analysis,phpunit,phpdox"
description="Performs static analysis, runs the tests, and generates project documentation"
/>
<target name="quick-build"
depends="prepare,lint,phpunit-no-coverage"
description="Performs a lint check and runs the tests (without generating code coverage reports)"
/>
<target name="static-analysis"
depends="lint,phploc-ci,pdepend,phpcpd-ci"
description="Performs static analysis"
/>
<target name="clean" unless="clean.done" description="Cleanup build artifacts">
<delete dir="build/api" />
<delete dir="build/coverage" />
<delete dir="build/logs" />
<delete dir="build/pdepend" />
<delete dir="build/phpdox" />
<property name="clean.done" value="true" />
</target>
<target name="prepare" depends="clean" unless="prepare.done" description="Prepare for build">
<mkdir dir="build/api" />
<mkdir dir="build/coverage" />
<mkdir dir="build/logs" />
<mkdir dir="build/pdepend" />
<mkdir dir="build/phpdox" />
<property name="prepare.done" value="true" />
</target>
<target name="lint" unless="lint.done" description="Perform syntax check of sourcecode files">
<parallel threadcount="6">
<apply executable="php" passthru="true" taskname="lint">
<arg value="-l" />
<fileset dir=".">
<include name="src/Aviat/AnimeClient/**/*.php" />
</fileset>
</apply>
<apply executable="php" passthru="true" taskname="lint">
<arg value="-l" />
<fileset dir=".">
<include name="src/Aviat/Ion/**/*.php" />
</fileset>
</apply>
<apply executable="php" passthru="true" taskname="lint">
<arg value="-l" />
<fileset dir=".">
<include name="tests/AnimeClient/**/*.php" />
</fileset>
</apply>
<apply executable="php" passthru="true" taskname="lint">
<arg value="-l" />
<fileset dir=".">
<include name="tests/Ion/**/*.php" />
</fileset>
</apply>
</parallel>
<property name="lint.done" value="true" />
</target>
<target name="phploc" unless="phploc.done" description="Measure project size using PHPLOC and print human readable output. Intended for usage on the command line.">
<exec executable="${phploc}" passthru="true" taskname="phploc">
<arg value="--count-tests" />
<arg path="src" />
<arg path="tests" />
</exec>
<property name="phploc.done" value="true" />
</target>
<target name="phploc-ci" depends="prepare" unless="phploc.done" description="Measure project size using PHPLOC and log result in CSV and XML format. Intended for usage within a continuous integration environment.">
<parallel threadcount="2">
<phploc countTests="true" reportType="csv" reportDirectory="build/logs" reportName="phploc" taskname="csv report">
<fileset dir=".">
<include name="src/**/*.php" />
<include name="tests/**/*.php" />
</fileset>
</phploc>
<phploc countTests="true" reportType="xml" reportDirectory="build/logs" reportName="phploc" taskname="xml report">
<fileset dir=".">
<include name="src/**/*.php" />
<include name="tests/**/*.php" />
</fileset>
</phploc>
</parallel>
<property name="phploc.done" value="true" />
</target>
<target name="pdepend" depends="prepare" unless="pdepend.done" description="Calculate software metrics using PHP_Depend and log result in XML format. Intended for usage within a continuous integration environment.">
<phpdepend>
<fileset dir=".">
<include name="src/**/*.php" />
</fileset>
<logger type="jdepend-xml" outfile="build/logs/jdepend.xml" />
<logger type="jdepend-chart" outfile="build/pdepend/dependencies.svg" />
<logger type="overview-pyramid" outfile="build/pdepend/overview-pyramid.svg" />
</phpdepend>
<property name="pdepend.done" value="true" />
</target>
<target name="phpcpd" unless="phpcpd.done" description="Find duplicate code using PHPCPD and print human readable output. Intended for usage on the command line before committing.">
<phpcpd>
<formatter type="default" usefile="false" />
<fileset dir=".">
<include name="src/**/*.php" />
</fileset>
</phpcpd>
<property name="phpcpd.done" value="true" />
</target>
<target name="phpcpd-ci" depends="prepare" unless="phpcpd.done" description="Find duplicate code using PHPCPD and log result in XML format. Intended for usage within a continuous integration environment.">
<phpcpd>
<formatter type="pmd" outfile="build/logs/pmd-cpd.xml" />
<fileset dir=".">
<include name="src/**/*.php" />
</fileset>
</phpcpd>
<property name="phpcpd.done" value="true" />
</target>
<target name="phpunit" unless="phpunit.done" depends="prepare" description="Run unit tests with PHPUnit">
<exec executable="${phpunit}" logoutput="true" passthru="true" checkreturn="true" taskname="phpunit">
<arg value="--configuration" />
<arg path="build/phpunit.xml" />
</exec>
<property name="phpunit.done" value="true" />
</target>
<target name="phpunit-no-coverage" depends="prepare" unless="phpunit.done" description="Run unit tests with PHPUnit (without generating code coverage reports)">
<exec executable="${phpunit}" passthru="true" taskname="phpunit">
<arg value="--configuration" />
<arg path="build/phpunit.xml" />
<arg value="--no-coverage" />
</exec>
<property name="phpunit.done" value="true" />
</target>
<target name="phpdox" depends="phploc-ci,phpunit" unless="phpdox.done" description="Generate project documentation using phpDox">
<exec dir="build" executable="${phpdox}" passthru="true" taskname="phpdox" />
<property name="phpdox.done" value="true" />
</target>
<target name="sonar" depends="phpunit" unless="sonar.done" description="Generate code analysis with sonarqube">
<exec executable="${sonar}" passthru="true" taskname="sonar" />
<property name="sonar.done" value="true" />
</target>
</project>

View File

@ -1,108 +0,0 @@
<?php declare(strict_types=1);
/**
* Hummingbird Anime Client
*
* An API client for Hummingbird to manage anime and manga watch lists
*
* PHP version 7
*
* @package HummingbirdAnimeClient
* @author Timothy J. Warren <tim@timshomepage.net>
* @copyright 2015 - 2016 Timothy J. Warren
* @license http://www.opensource.org/licenses/mit-license.html MIT License
* @version 3.1
* @link https://github.com/timw4mail/HummingBirdAnimeClient
*/
namespace Aviat\AnimeClient\Auth;
use Aviat\AnimeClient\AnimeClient;
use Aviat\Ion\Di\ContainerInterface;
/**
* Hummingbird API Authentication
*/
class HummingbirdAuth {
use \Aviat\Ion\Di\ContainerAware;
/**
* Anime API Model
*
* @var \Aviat\AnimeClient\Model\API
*/
protected $model;
/**
* Session object
*
* @var Aura\Session\Segment
*/
protected $segment;
/**
* Constructor
*
* @param ContainerInterface $container
*/
public function __construct(ContainerInterface $container)
{
$this->setContainer($container);
$this->segment = $container->get('session')
->getSegment(AnimeClient::SESSION_SEGMENT);
$this->model = $container->get('api-model');
}
/**
* Make the appropriate authentication call,
* and save the resulting auth token if successful
*
* @param string $password
* @return boolean
*/
public function authenticate($password)
{
$username = $this->container->get('config')
->get('hummingbird_username');
$auth_token = $this->model->authenticate($username, $password);
if (FALSE !== $auth_token)
{
$this->segment->set('auth_token', $auth_token);
return TRUE;
}
return FALSE;
}
/**
* Check whether the current user is authenticated
*
* @return boolean
*/
public function is_authenticated()
{
return ($this->get_auth_token() !== FALSE);
}
/**
* Clear authentication values
*
* @return void
*/
public function logout()
{
$this->segment->clear();
}
/**
* Retrieve the authentication token from the session
*
* @return string|false
*/
public function get_auth_token()
{
return $this->segment->get('auth_token', FALSE);
}
}
// End of HummingbirdAuth.php

View File

@ -1,29 +0,0 @@
<?php declare(strict_types=1);
/**
* Hummingbird Anime Client
*
* An API client for Hummingbird to manage anime and manga watch lists
*
* PHP version 7
*
* @package HummingbirdAnimeClient
* @author Timothy J. Warren <tim@timshomepage.net>
* @copyright 2015 - 2016 Timothy J. Warren
* @license http://www.opensource.org/licenses/mit-license.html MIT License
* @version 3.1
* @link https://github.com/timw4mail/HummingBirdAnimeClient
*/
namespace Aviat\AnimeClient\Hummingbird\Enum;
use Aviat\Ion\Enum as BaseEnum;
/**
* Status of when anime is being/was/will be aired
*/
class AnimeAiringStatus extends BaseEnum {
const NOT_YET_AIRED = 'Not Yet Aired';
const AIRING = 'Currently Airing';
const FINISHED_AIRING = 'Finished Airing';
}
// End of AnimeAiringStatus.php

View File

@ -1,32 +0,0 @@
<?php declare(strict_types=1);
/**
* Hummingbird Anime Client
*
* An API client for Hummingbird to manage anime and manga watch lists
*
* PHP version 7
*
* @package HummingbirdAnimeClient
* @author Timothy J. Warren <tim@timshomepage.net>
* @copyright 2015 - 2016 Timothy J. Warren
* @license http://www.opensource.org/licenses/mit-license.html MIT License
* @version 3.1
* @link https://github.com/timw4mail/HummingBirdAnimeClient
*/
namespace Aviat\AnimeClient\Hummingbird\Enum;
use Aviat\Ion\Enum as BaseEnum;
/**
* Type of Anime
*/
class AnimeShowType extends BaseEnum {
const TV = 'TV';
const MOVIE = 'Movie';
const OVA = 'OVA';
const ONA = 'ONA';
const SPECIAL = 'Special';
const MUSIC = 'Music';
}
// End of AnimeShowType.php

View File

@ -1,31 +0,0 @@
<?php declare(strict_types=1);
/**
* Hummingbird Anime Client
*
* An API client for Hummingbird to manage anime and manga watch lists
*
* PHP version 7
*
* @package HummingbirdAnimeClient
* @author Timothy J. Warren <tim@timshomepage.net>
* @copyright 2015 - 2016 Timothy J. Warren
* @license http://www.opensource.org/licenses/mit-license.html MIT License
* @version 3.1
* @link https://github.com/timw4mail/HummingBirdAnimeClient
*/
namespace Aviat\AnimeClient\Hummingbird\Enum;
use Aviat\Ion\Enum as BaseEnum;
/**
* Possible values for watching status for the current anime
*/
class AnimeWatchingStatus extends BaseEnum {
const WATCHING = 'currently-watching';
const PLAN_TO_WATCH = 'plan-to-watch';
const COMPLETED = 'completed';
const ON_HOLD = 'on-hold';
const DROPPED = 'dropped';
}
// End of AnimeWatchingStatus.php

View File

@ -1,31 +0,0 @@
<?php declare(strict_types=1);
/**
* Hummingbird Anime Client
*
* An API client for Hummingbird to manage anime and manga watch lists
*
* PHP version 7
*
* @package HummingbirdAnimeClient
* @author Timothy J. Warren <tim@timshomepage.net>
* @copyright 2015 - 2016 Timothy J. Warren
* @license http://www.opensource.org/licenses/mit-license.html MIT License
* @version 3.1
* @link https://github.com/timw4mail/HummingBirdAnimeClient
*/
namespace Aviat\AnimeClient\Hummingbird\Enum;
use Aviat\Ion\Enum as BaseEnum;
/**
* Possible values for current reading status of manga
*/
class MangaReadingStatus extends BaseEnum {
const READING = 'Currently Reading';
const PLAN_TO_READ = 'Plan to Read';
const DROPPED = 'Dropped';
const ON_HOLD = 'On Hold';
const COMPLETED = 'Completed';
}
// End of MangaReadingStatus.php

View File

@ -1,147 +0,0 @@
<?php declare(strict_types=1);
/**
* Hummingbird Anime Client
*
* An API client for Hummingbird to manage anime and manga watch lists
*
* PHP version 7
*
* @package HummingbirdAnimeClient
* @author Timothy J. Warren <tim@timshomepage.net>
* @copyright 2015 - 2016 Timothy J. Warren
* @license http://www.opensource.org/licenses/mit-license.html MIT License
* @version 3.1
* @link https://github.com/timw4mail/HummingBirdAnimeClient
*/
namespace Aviat\AnimeClient\Hummingbird\Transformer;
use Aviat\Ion\Transformer\AbstractTransformer;
/**
* Transformer for anime list
*/
class AnimeListTransformer extends AbstractTransformer {
/**
* Convert raw api response to a more
* logical and workable structure
*
* @param array $item API library item
* @return array
*/
public function transform($item)
{
$anime =& $item['anime'];
$genres = $this->linearizeGenres($item['anime']['genres']);
$rating = NULL;
if ($item['rating']['type'] === 'advanced')
{
$rating = is_numeric($item['rating']['value'])
? (int) 2 * $item['rating']['value']
: '-';
}
$total_episodes = is_numeric($anime['episode_count'])
? $anime['episode_count']
: '-';
$alternate_title = NULL;
if (array_key_exists('alternate_title', $anime))
{
// If the alternate title is very similar, or
// a subset of the main title, don't list the
// alternate title
$not_subset = stripos($anime['title'], $anime['alternate_title']) === FALSE;
$diff = levenshtein($anime['title'], $anime['alternate_title'] ?? '');
if ($not_subset && $diff >= 5)
{
$alternate_title = $anime['alternate_title'];
}
}
return [
'id' => $item['id'],
'episodes' => [
'watched' => $item['episodes_watched'],
'total' => $total_episodes,
'length' => $anime['episode_length'],
],
'airing' => [
'status' => $anime['status'],
'started' => $anime['started_airing'],
'ended' => $anime['finished_airing']
],
'anime' => [
'age_rating' => $anime['age_rating'],
'title' => $anime['title'],
'alternate_title' => $alternate_title,
'slug' => $anime['slug'],
'url' => $anime['url'],
'type' => $anime['show_type'],
'image' => $anime['cover_image'],
'genres' => $genres,
],
'watching_status' => $item['status'],
'notes' => $item['notes'],
'rewatching' => (bool) $item['rewatching'],
'rewatched' => $item['rewatched_times'],
'user_rating' => $rating,
'private' => (bool) $item['private'],
];
}
/**
* Convert transformed data to
* api response format
*
* @param array $item Transformed library item
* @return array API library item
*/
public function untransform($item)
{
// Messy mapping of boolean values to their API string equivalents
$privacy = 'public';
if (array_key_exists('private', $item) && $item['private'])
{
$privacy = 'private';
}
$rewatching = 'false';
if (array_key_exists('rewatching', $item) && $item['rewatching'])
{
$rewatching = 'true';
}
return [
'id' => $item['id'],
'status' => $item['watching_status'],
'sane_rating_update' => $item['user_rating'] / 2,
'rewatching' => $rewatching,
'rewatched_times' => $item['rewatched'],
'notes' => $item['notes'],
'episodes_watched' => $item['episodes_watched'],
'privacy' => $privacy
];
}
/**
* Simplify structure of genre list
*
* @param array $rawGenres
* @return array
*/
protected function linearizeGenres(array $rawGenres): array
{
$genres = [];
foreach ($rawGenres as $genre)
{
$genres[] = $genre['name'];
}
return $genres;
}
}
// End of AnimeListTransformer.php

View File

@ -1,121 +0,0 @@
<?php declare(strict_types=1);
/**
* Hummingbird Anime Client
*
* An API client for Hummingbird to manage anime and manga watch lists
*
* PHP version 7
*
* @package HummingbirdAnimeClient
* @author Timothy J. Warren <tim@timshomepage.net>
* @copyright 2015 - 2016 Timothy J. Warren
* @license http://www.opensource.org/licenses/mit-license.html MIT License
* @version 3.1
* @link https://github.com/timw4mail/HummingBirdAnimeClient
*/
namespace Aviat\AnimeClient\Hummingbird\Transformer;
use Aviat\Ion\Transformer\AbstractTransformer;
/**
* Data transformation class for zippered Hummingbird manga
*/
class MangaListTransformer extends AbstractTransformer {
use \Aviat\Ion\StringWrapper;
/**
* Remap zipped anime data to a more logical form
*
* @param array $item manga entry item
* @return array
*/
public function transform($item)
{
$manga =& $item['manga'];
$rating = (is_numeric($item['rating']))
? intval(2 * $item['rating'])
: '-';
$total_chapters = ($manga['chapter_count'] > 0)
? $manga['chapter_count']
: '-';
$total_volumes = ($manga['volume_count'] > 0)
? $manga['volume_count']
: '-';
$map = [
'id' => $item['id'],
'chapters' => [
'read' => $item['chapters_read'],
'total' => $total_chapters
],
'volumes' => [
'read' => $item['volumes_read'],
'total' => $total_volumes
],
'manga' => [
'title' => $manga['romaji_title'],
'alternate_title' => NULL,
'slug' => $manga['id'],
'url' => 'https://hummingbird.me/manga/' . $manga['id'],
'type' => $manga['manga_type'],
'image' => $manga['poster_image_thumb'],
'genres' => $manga['genres'],
],
'reading_status' => $item['status'],
'notes' => $item['notes'],
'rereading' => (bool)$item['rereading'],
'reread' => $item['reread_count'],
'user_rating' => $rating,
];
if (array_key_exists('english_title', $manga))
{
$diff = levenshtein($manga['romaji_title'], $manga['english_title']);
// If the titles are REALLY similar, don't bother showing both
if ($diff >= 5)
{
$map['manga']['alternate_title'] = $manga['english_title'];
}
}
return $map;
}
/**
* Untransform data to update the api
*
* @param array $item
* @return array
*/
public function untransform($item)
{
$rereading = (array_key_exists('rereading', $item)) && (bool)$item['rereading'];
$map = [
'id' => $item['id'],
'manga_id' => $item['manga_id'],
'status' => $item['status'],
'chapters_read' => (int)$item['chapters_read'],
'volumes_read' => (int)$item['volumes_read'],
'rereading' => $rereading,
'reread_count' => (int)$item['reread_count'],
'notes' => $item['notes'],
];
if ($item['new_rating'] !== $item['old_rating'] && $item['new_rating'] !== "")
{
$map['rating'] = ($item['new_rating'] > 0)
? $item['new_rating'] / 2
: $item['old_rating'] / 2;
}
return $map;
}
}
// End of MangaListTransformer.php

View File

@ -1,92 +0,0 @@
<?php declare(strict_types=1);
/**
* Hummingbird Anime Client
*
* An API client for Hummingbird to manage anime and manga watch lists
*
* PHP version 7
*
* @package HummingbirdAnimeClient
* @author Timothy J. Warren <tim@timshomepage.net>
* @copyright 2015 - 2016 Timothy J. Warren
* @license http://www.opensource.org/licenses/mit-license.html MIT License
* @version 3.1
* @link https://github.com/timw4mail/HummingBirdAnimeClient
*/
namespace Aviat\AnimeClient\Hummingbird\Transformer;
/**
* Merges the two separate manga lists together
*/
class MangaListsZipper {
/**
* List of manga information
*
* @var array
*/
protected $manga_series_list = [];
/**
* List of manga tracking information
*
* @var array
*/
protected $manga_tracking_list = [];
/**
* Create the transformer
*
* @param array $merge_lists The raw manga data
*/
public function __construct(array $merge_lists)
{
$this->manga_series_list = $merge_lists['manga'];
$this->manga_tracking_list = $merge_lists['manga_library_entries'];
}
/**
* Do the transformation, and return the output
*
* @return array
*/
public function transform()
{
$this->index_manga_entries();
$output = [];
foreach ($this->manga_tracking_list as &$entry)
{
$id = $entry['manga_id'];
$entry['manga'] = $this->manga_series_list[$id];
unset($entry['manga_id']);
$output[] = $entry;
}
return $output;
}
/**
* Index manga series by the id
*
* @return void
*/
protected function index_manga_entries()
{
$orig_list = $this->manga_series_list;
$indexed_list = [];
foreach ($orig_list as $manga)
{
$id = $manga['id'];
$indexed_list[$id] = $manga;
}
$this->manga_series_list = $indexed_list;
}
}
// End of ManagListsZipper.php

View File

@ -1,88 +0,0 @@
<?php
use Aura\Session\SessionFactory;
use Aviat\AnimeClient\Auth\HummingbirdAuth;
use Aviat\Ion\Friend;
use GuzzleHttp\Client;
use GuzzleHttp\Handler\MockHandler;
use GuzzleHttp\HandlerStack;
use GuzzleHttp\Psr7\Response;
class HummingbirdAuthTest extends AnimeClient_TestCase {
static $session;
static $sessionHandler;
public static function setUpBeforeClass()
{
self::$session = (new SessionFactory)->newInstance([]);
}
public function setUp()
{
parent::setUp();
$auth = new HummingbirdAuth($this->container);
$friend = new Friend($auth);
$this->auth = $friend;
$this->container->setInstance('session', self::$session);
}
public function dataAuthenticate()
{
$testToken = 'notReallyAValidTokenButThisIsATest';
return [
'successful auth call' => [
'username' => 'timw4mailtest',
'password' => 'password',
'response_data' => [
'code' => 201,
'body' => json_encode($testToken)
],
'session_value' => $testToken,
'expected' => TRUE,
],
'unsuccessful auth call' => [
'username' => 'foo',
'password' => 'foobarbaz',
'response_data' => [
'code' => 401,
'body' => '{"error":"Invalid credentials"}',
],
'session_value' => FALSE,
'expected' => FALSE,
]
];
}
/**
* @dataProvider dataAuthenticate
*/
public function testAuthenticate($username, $password, $response_data, $session_value, $expected)
{
$this->container->get('config')
->set('hummingbird_username', $username);
$model = new MockBaseApiModel($this->container);
$mock = new MockHandler([
new Response($response_data['code'], [], $response_data['body'])
]);
$handler = HandlerStack::create($mock);
$client = new Client([
'handler' => $handler,
'http_errors' => FALSE // Don't throw an exception for 400/500 class status codes
]);
$model->__set('client', $client);
$this->auth->__set('model', $model);
$actual = $this->auth->authenticate($password);
$this->assertEquals($expected, $actual);
}
public function testIsAuthenticated()
{
$data = $this->dataAuthenticate();
call_user_func_array([$this, 'testAuthenticate'], $data['successful auth call']);
$this->assertTrue($this->auth->is_authenticated());
$this->auth->logout();
$this->assertFalse($this->auth->is_authenticated());
}
}

View File

@ -1,76 +0,0 @@
<?php
use Aviat\AnimeClient\Model\AnimeCollection as AnimeCollectionModel;
use Aviat\Ion\Config;
use Aviat\Ion\Friend;
class AnimeCollectionModelTest extends AnimeClient_TestCase {
public function setUp()
{
parent::setUp();
$this->container->setInstance('config', new Config([
'database' => [
'collection' => [
'type' => 'sqlite',
'host' => '',
'user' => '',
'pass' => '',
'port' => '',
'name' => 'default',
'database' => '',
'file' => ':memory:',
]
]
]));
$this->config = $this->container->get('config');
$this->collectionModel = new AnimeCollectionModel($this->container);
}
public function testSanity()
{
$friend = new Friend($this->collectionModel);
$this->assertInstanceOf('Aviat\Ion\Model\DB', $this->collectionModel);
$this->assertInstanceOf('Aviat\AnimeClient\Model\Anime', $friend->anime_model);
}
public function testInvalidDatabase()
{
$this->container->setInstance('config', new Config([
'database' => [
'collection' => [
'type' => 'sqlite',
'host' => '',
'user' => '',
'pass' => '',
'port' => '',
'name' => 'default',
'database' => '',
'file' => __FILE__,
]
]
]));
$collectionModel = new Friend(new AnimeCollectionModel($this->container));
$this->assertFalse($collectionModel->valid_database);
}
public function testNonExistentDatabase()
{
$this->container->setInstance('config', new Config([
'database' => [
'collection' => [
'type' => 'sqlite',
'host' => '',
'user' => '',
'pass' => '',
'port' => '',
'name' => 'default',
'database' => '',
'file' => '/foo/bar/baz/foobazbar.db',
]
]
]));
$collectionModel = new Friend(new AnimeCollectionModel($this->container));
$this->assertFalse($collectionModel->valid_database);
}
}

View File

@ -1,55 +0,0 @@
<?php
use Aviat\Ion\Friend;
class AnimeModelTest extends AnimeClient_TestCase {
public function setUp()
{
parent::setUp();
$this->animeModel = new Friend(new TestAnimeModel($this->container));
$this->mockDir = __DIR__ . '/../test_data/anime_list/search_mocks';
}
public function dataSearch()
{
return [
'nonsense search' => [
'search' => 'foo',
],
'search for common series' => [
'search' => 'Fate',
],
'search for weird series' => [
'search' => 'Twintails',
]
];
}
/**
* @dataProvider dataSearch
*/
public function testSearch($search)
{
// Mock requests
$json = file_get_contents(_dir($this->mockDir, "{$search}.json"));
$client = $this->getMockClient(200, [
'Content-Type' => 'application/json'
], $json);
$this->animeModel->__set('client', $client);
$actual = $this->animeModel->search($search);
$this->assertEquals(json_decode($json, TRUE), $actual);
}
public function testSearchBadResponse()
{
$client = $this->getMockClient(400, [
'Content-Type' => 'application/json'
], "[]");
$this->animeModel->__set('client', $client);
$this->expectException('RuntimeException');
$this->animeModel->search('');
}
}

View File

@ -1,252 +0,0 @@
<?php
use Aviat\AnimeClient\Container;
use GuzzleHttp\Client;
use GuzzleHttp\Handler\MockHandler;
use GuzzleHttp\HandlerStack;
use GuzzleHttp\Psr7\Response;
class BaseApiModelTest extends AnimeClient_TestCase {
public function setUp()
{
parent::setUp();
$this->model = new MockBaseApiModel($this->container);
}
protected function getIp()
{
$response = $this->model->get('/ip');
$json = json_decode($response->getBody(), TRUE);
$ip = $json['origin'];
return $ip;
}
public function dataClient()
{
$user_agent = "Tim's Anime Client/2.0";
$headers = [
'User-Agent' => $user_agent
];
return [
'invalid method' => [
'method' => 'foo',
'uri' => '',
'options' => [],
'expected' => NULL,
'is_json' => FALSE,
],
'get' => [
'method' => 'get',
'uri' => '/get',
'options' => [
'query' => [
'foo' => 'bar'
],
'headers' => $headers
],
'expected' => [
'args' => [
'foo' => 'bar'
],
'headers' => [
'Host' => 'httpbin.org',
'User-Agent' => $user_agent
],
'url' => 'https://httpbin.org/get?foo=bar'
],
'is_json' => TRUE
],
'post' => [
'method' => 'post',
'uri' => '/post',
'options' => [
'form_params' => [
'foo' => 'bar',
'baz' => 'foobar'
],
'headers' => $headers
],
'expected' => [
'args' => [],
'data' => '',
'files' => [],
'form' => [
'foo' => 'bar',
'baz' => 'foobar'
],
'headers' => [
'Host' => 'httpbin.org',
'User-Agent' => $user_agent,
'Content-Length' => '18',
'Content-Type' => 'application/x-www-form-urlencoded'
],
'json' => NULL,
'url' => 'https://httpbin.org/post'
],
'is_json' => TRUE
],
'put' => [
'method' => 'put',
'uri' => '/put',
'options' => [
'form_params' => [
'foo' => 'bar',
'baz' => 'foobar'
],
'headers' => $headers
],
'expected' => [
'args' => [],
'data' => '',
'files' => [],
'form' => [
'foo' => 'bar',
'baz' => 'foobar'
],
'headers' => [
'Host' => 'httpbin.org',
'User-Agent' => $user_agent,
'Content-Length' => '18',
'Content-Type' => 'application/x-www-form-urlencoded'
],
'json' => NULL,
'url' => 'https://httpbin.org/put'
],
'is_json' => TRUE
],
'patch' => [
'method' => 'patch',
'uri' => '/patch',
'options' => [
'form_params' => [
'foo' => 'bar',
'baz' => 'foobar'
],
'headers' => $headers
],
'expected' => [
'args' => [],
'data' => '',
'files' => [],
'form' => [
'foo' => 'bar',
'baz' => 'foobar'
],
'headers' => [
'Host' => 'httpbin.org',
'User-Agent' => $user_agent,
'Content-Length' => '18',
'Content-Type' => 'application/x-www-form-urlencoded'
],
'json' => NULL,
'url' => 'https://httpbin.org/patch'
],
'is_json' => TRUE
],
'delete' => [
'method' => 'delete',
'uri' => '/delete',
'options' => [
'form_params' => [
'foo' => 'bar',
'baz' => 'foobar'
],
'headers' => $headers
],
'expected' => [
'args' => [],
'data' => '',
'files' => [],
'form' => [
'foo' => 'bar',
'baz' => 'foobar'
],
'headers' => [
'Host' => 'httpbin.org',
'User-Agent' => $user_agent,
'Content-Length' => '18',
'Content-Type' => 'application/x-www-form-urlencoded'
],
'json' => NULL,
'url' => 'https://httpbin.org/delete'
],
'is_json' => TRUE
]
];
}
/**
* @dataProvider dataClient
*/
public function testClient($method, $uri, $options, $expected, $is_json)
{
$result = $this->model->$method($uri, $options);
if (is_null($result))
{
$this->assertNull($expected);
return;
}
// Because you have to make another api call to get the origin ip
// address, it needs to be retreived outside of the dataProvider method
$expected['origin'] = $this->getIp();
$actual = ($is_json)
? json_decode($result->getBody(), TRUE)
: (string) $result->getBody();
$this->assertEquals($expected, $actual);
}
public function dataAuthenticate()
{
$test_token = 'eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJqdGkiOiI4YTA5ZDk4Ny1iZWQxLTQyMTktYWVmOS0wMTcxYWVjYTE3ZWUiLCJzY29wZSI6WyJhbGwiXSwic3ViIjoxMDgwMTIsImlzcyI6MTQ0NTAxNzczNSwiZXhwIjoxNDUyOTY2NTM1fQ.fpha1ZDN9dSFAuHeJesfOP9pCk5-ZnZk4uv3zumRMY0';
return [
'successful authentication' => [
'username' => 'timw4mailtest',
'password' => 'password',
'response_data' => [
'code' => 201,
'body' => json_encode($test_token)
],
'expected' => $test_token
],
'failed authentication' => [
'username' => 'foo',
'password' => 'foobarbaz',
'response_data' => [
'code' => 401,
'body' => '{"error":"Invalid credentials"}',
],
'expected' => FALSE
]
];
}
/**
* @dataProvider dataAuthenticate
*/
public function testAuthenticate($username, $password, $response_data, $expected)
{
$mock = new MockHandler([
new Response($response_data['code'], [], $response_data['body'])
]);
$handler = HandlerStack::create($mock);
$client = new Client([
'handler' => $handler,
'http_errors' => FALSE // Don't throw an exception for 400/500 class status codes
]);
// Set the mock client
$this->model->__set('client', $client);
// Check results based on mock data
$actual = $this->model->authenticate($username, $password);
$this->assertEquals($expected, $actual, "Incorrect method return value");
}
}

View File

@ -1,71 +0,0 @@
<?php
use Aviat\Ion\Friend;
use Aviat\Ion\Json;
class MangaModelTest extends AnimeClient_TestCase {
public function setUp()
{
parent::setUp();
$this->container->setInstance('util', new MockUtil($this->container));
$this->model = new Friend(new TestMangaModel($this->container));
$this->mockDir = __DIR__ . '/../test_data/manga_list';
}
public function testZipperLists()
{
$raw_data = Json::decodeFile($this->mockDir . '/manga.json');
$expected = Json::decodeFile($this->mockDir . '/manga-zippered.json');
$this->assertEquals($expected, $this->model->zipperLists($raw_data));
}
public function testMapByStatus()
{
$original = Json::decodeFile($this->mockDir . '/manga-transformed.json');
$expected = Json::decodeFile($this->mockDir . '/manga-mapped.json');
$actual = $this->model->map_by_status($original);
$this->assertEquals($expected, $actual);
}
public function testGetListFromApi()
{
$data = file_get_contents($this->mockDir . '/manga.json');
$client = $this->getMockClient(200, [
'Content-type' => 'application/json'
], $data);
$this->model->__set('client', $client);
$reflect = new ReflectionClass($this->model);
$constants = $reflect->getConstants();
$expected_all = Json::decodeFile($this->mockDir . '/manga-mapped.json');
$this->assertEquals($expected_all, $this->model->_get_list_from_api());
foreach($constants as $name => $value)
{
$key = $reflect->getConstant($name);
$this->assertEquals($expected_all[$key], $this->model->_get_list_from_api($key));
}
}
public function testGetList()
{
if (($var = getenv('CI')))
{
$this->markTestSkipped();
}
$data = file_get_contents($this->mockDir . '/manga.json');
$client = $this->getMockClient(200, [
'Content-type' => 'application/json'
], $data);
$this->model->__set('client', $client);
$expected = Json::decodeFile($this->mockDir . '/get-all-lists.json');
$this->assertEquals($expected['Reading'], $this->model->get_list('Reading'));
}
}

View File

@ -1,50 +0,0 @@
<?php
use Aviat\AnimeClient\Hummingbird\Transformer\AnimeListTransformer;
use Aviat\Ion\Friend;
use Aviat\Ion\Json;
class AnimeListTransformerTest extends AnimeClient_TestCase {
public function setUp()
{
parent::setUp();
$this->start_file = __DIR__ . '/../test_data/anime_list/anime-completed.json';
$this->res_file = __DIR__ . '/../test_data/anime_list/anime-completed-transformed.json';
$this->transformer = new AnimeListTransformer();
$this->transformerFriend = new Friend($this->transformer);
}
public function dataLinearizeGenres()
{
return [
[
'original' => [
['name' => 'Action'],
['name' => 'Comedy'],
['name' => 'Magic'],
['name' => 'Fantasy'],
['name' => 'Mahou Shoujo']
],
'expected' => ['Action', 'Comedy', 'Magic', 'Fantasy', 'Mahou Shoujo']
]
];
}
/**
* @dataProvider dataLinearizeGenres
*/
public function testLinearizeGenres($original, $expected)
{
$actual = $this->transformerFriend->linearizeGenres($original);
$this->assertEquals($expected, $actual);
}
public function testTransform()
{
$json = Json::decodeFile($this->start_file);
$expected = Json::decodeFile($this->res_file);
$actual = $this->transformer->transformCollection($json);
$this->assertEquals($expected, $actual);
}
}

View File

@ -1,114 +0,0 @@
<?php
use Aviat\AnimeClient\Hummingbird\Transformer\MangaListTransformer;
use Aviat\Ion\Json;
class MangaListTransformerTest extends AnimeClient_TestCase {
public function setUp()
{
parent::setUp();
$this->start_file = __DIR__ . '/../test_data/manga_list/manga-zippered.json';
$this->res_file = __DIR__ . '/../test_data/manga_list/manga-transformed.json';
$this->transformer = new MangaListTransformer();
}
public function testTransform()
{
$orig_json = Json::decodeFile($this->start_file);
$expected = Json::decodeFile($this->res_file);
$actual = $this->transformer->transformCollection($orig_json);
$this->assertEquals($expected, $actual);
}
public function dataUntransform()
{
return [
'same_rating' => [
'orig' => [
'id' => 401735,
'manga_id' => "love-hina",
'status' => "Plan to Read",
'chapters_read' => 16,
'volumes_read' => 2,
'rereading' => true,
'reread_count' => 1,
'notes' => "Some text notes",
'old_rating' => 7,
'new_rating' => 7,
],
'expected' => [
'id' => 401735,
'manga_id' => "love-hina",
'status' => "Plan to Read",
'chapters_read' => 16,
'volumes_read' => 2,
'rereading' => true,
'reread_count' => 1,
'notes' => "Some text notes",
]
],
'update_rating' => [
'orig' => [
'id' => 401735,
'manga_id' => "love-hina",
'status' => "Plan to Read",
'chapters_read' => 16,
'volumes_read' => 2,
'rereading' => true,
'reread_count' => 1,
'notes' => "Some text notes",
'old_rating' => 7,
'new_rating' => 8,
],
'expected' => [
'id' => 401735,
'manga_id' => "love-hina",
'status' => "Plan to Read",
'chapters_read' => 16,
'volumes_read' => 2,
'rereading' => true,
'reread_count' => 1,
'notes' => "Some text notes",
'rating' => 4,
]
],
'remove_rating' => [
'orig' => [
'id' => 401735,
'manga_id' => "love-hina",
'status' => "Plan to Read",
'chapters_read' => 16,
'volumes_read' => 2,
'rereading' => true,
'reread_count' => 1,
'notes' => "Some text notes",
'old_rating' => 7,
'new_rating' => 0,
],
'expected' => [
'id' => 401735,
'manga_id' => "love-hina",
'status' => "Plan to Read",
'chapters_read' => 16,
'volumes_read' => 2,
'rereading' => true,
'reread_count' => 1,
'notes' => "Some text notes",
'rating' => 3.5,
]
]
];
}
/**
* @dataProvider dataUntransform
*/
public function testUntransform($orig, $expected)
{
$actual = $this->transformer->untransform($orig);
$this->assertEquals($expected, $actual);
}
}

View File

@ -1,28 +0,0 @@
<?php
use Aviat\AnimeClient\Hummingbird\Transformer\MangaListsZipper;
use Aviat\Ion\Json;
class MangaListsZipperTest extends AnimeClient_TestCase {
protected $start_file = '';
protected $res_file = '';
public function setUp()
{
$this->start_file = __DIR__ . '/../test_data/manga_list/manga.json';
$this->res_file = __DIR__ . '/../test_data/manga_list/manga-zippered.json';
$json = Json::decodeFile($this->start_file);
$this->mangaListsZipper = new MangaListsZipper($json);
}
public function testTransform()
{
$zippered_json = Json::decodeFile($this->res_file);
$transformed = $this->mangaListsZipper->transform();
$this->assertEquals($zippered_json, $transformed);
}
}