Version 5.1 - All the GraphQL #32
@ -10,6 +10,7 @@ use Aura\Web\WebFactory;
|
||||
use Aura\Router\RouterFactory;
|
||||
use Aura\Session\SessionFactory;
|
||||
use Aviat\Ion\Di\Container;
|
||||
use Aviat\AnimeClient\Auth\HummingbirdAuth;
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// Setup DI container
|
||||
@ -54,6 +55,7 @@ return function(array $config_array = []) {
|
||||
$container->set('session', $session);
|
||||
|
||||
$container->set('url-generator', new UrlGenerator($container));
|
||||
$container->set('auth', new HummingbirdAuth($container));
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
// Dispatcher
|
||||
|
@ -10,6 +10,8 @@ namespace Aviat\AnimeClient;
|
||||
*/
|
||||
class Config {
|
||||
|
||||
use \Aviat\Ion\ArrayWrapper;
|
||||
|
||||
/**
|
||||
* Config object
|
||||
*
|
||||
@ -30,11 +32,16 @@ class Config {
|
||||
/**
|
||||
* Get a config value
|
||||
*
|
||||
* @param string $key
|
||||
* @param array|string $key
|
||||
* @return mixed
|
||||
*/
|
||||
public function get($key)
|
||||
{
|
||||
if (is_array($key))
|
||||
{
|
||||
return $this->get_deep_key($key, FALSE);
|
||||
}
|
||||
|
||||
if (array_key_exists($key, $this->map))
|
||||
{
|
||||
return $this->map[$key];
|
||||
@ -43,16 +50,84 @@ class Config {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a reference to an arbitrary key on the config map
|
||||
* @param array $key
|
||||
* @param bool $create Whether to create the missing array keys
|
||||
* @return mixed
|
||||
*/
|
||||
protected function &get_deep_key(array $key, $create = TRUE)
|
||||
{
|
||||
$pos =& $this->map;
|
||||
|
||||
// Create the start of the array if it doesn't exist
|
||||
if ($create && ! is_array($pos))
|
||||
{
|
||||
$pos = [];
|
||||
}
|
||||
elseif ( ! is_array($pos))
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// Iterate through the levels of the array,
|
||||
// create the levels if they don't exist
|
||||
foreach($key as $level)
|
||||
{
|
||||
if ($create && empty($pos) && ! is_array($pos))
|
||||
{
|
||||
$pos = [];
|
||||
$pos[$level] = [];
|
||||
}
|
||||
$pos =& $pos[$level];
|
||||
}
|
||||
|
||||
return $pos;
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove a config value
|
||||
*
|
||||
* @param string|array $key
|
||||
* @return void
|
||||
*/
|
||||
public function delete($key)
|
||||
{
|
||||
$pos =& $this->map;
|
||||
|
||||
if (is_array($key))
|
||||
{
|
||||
$pos =& $this->arr($this->map)->get_deep_key($key);
|
||||
}
|
||||
else
|
||||
{
|
||||
$pos =& $this->map[$key];
|
||||
}
|
||||
|
||||
unset($pos);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set a config value
|
||||
*
|
||||
* @param string $key
|
||||
* @param string|array $key
|
||||
* @param mixed $value
|
||||
* @return Config
|
||||
*/
|
||||
public function set($key, $value)
|
||||
{
|
||||
$this->map[$key] = $value;
|
||||
$pos =& $this->map;
|
||||
|
||||
if (is_array($key))
|
||||
{
|
||||
$pos =& $this->get_deep_key($key);
|
||||
$pos = $value;
|
||||
}
|
||||
else
|
||||
{
|
||||
$pos[$key] = $value;
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
}
|
||||
|
@ -43,11 +43,6 @@ class Anime extends BaseController {
|
||||
{
|
||||
parent::__construct($container);
|
||||
|
||||
if ($this->config->get('show_anime_collection') === FALSE)
|
||||
{
|
||||
unset($this->nav_routes['Collection']);
|
||||
}
|
||||
|
||||
$this->model = new AnimeModel($container);
|
||||
$this->collection_model = new AnimeCollectionModel($container);
|
||||
$this->base_data = array_merge($this->base_data, [
|
||||
@ -109,7 +104,8 @@ class Anime extends BaseController {
|
||||
'completed' => AnimeWatchingStatus::COMPLETED
|
||||
];
|
||||
|
||||
$title = $this->config->get('whose_list') . "'s Anime List · {$type_title_map[$type]}";
|
||||
$title = $this->config->get('whose_list') .
|
||||
"'s Anime List · {$type_title_map[$type]}";
|
||||
|
||||
$view_map = [
|
||||
'' => 'cover',
|
||||
|
@ -19,13 +19,6 @@ class MenuGenerator extends UrlGenerator {
|
||||
*/
|
||||
protected $helper;
|
||||
|
||||
/**
|
||||
* Menu config array
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $menus;
|
||||
|
||||
/**
|
||||
* Request object
|
||||
*
|
||||
@ -41,7 +34,6 @@ class MenuGenerator extends UrlGenerator {
|
||||
public function __construct(ContainerInterface $container)
|
||||
{
|
||||
parent::__construct($container);
|
||||
$this->menus = $this->config->get('menus');
|
||||
$this->helper = $container->get('html-helper');
|
||||
$this->request = $container->get('request');
|
||||
}
|
||||
@ -51,11 +43,11 @@ class MenuGenerator extends UrlGenerator {
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
protected function parse_config()
|
||||
protected function parse_config(array $menus)
|
||||
{
|
||||
$parsed = [];
|
||||
|
||||
foreach ($this->menus as $name => $menu)
|
||||
foreach ($menus as $name => $menu)
|
||||
{
|
||||
$parsed[$name] = [];
|
||||
foreach ($menu['items'] as $path_name => $partial_path)
|
||||
@ -76,7 +68,8 @@ class MenuGenerator extends UrlGenerator {
|
||||
*/
|
||||
public function generate($menu)
|
||||
{
|
||||
$parsed_config = $this->parse_config();
|
||||
$menus = $this->config->get('menus');
|
||||
$parsed_config = $this->parse_config($menus);
|
||||
|
||||
// Bail out early on invalid menu
|
||||
if ( ! $this->arr($parsed_config)->has_key($menu))
|
||||
|
@ -7,12 +7,21 @@ namespace Aviat\AnimeClient\Model;
|
||||
use GuzzleHttp\Client;
|
||||
use GuzzleHttp\Cookie\CookieJar;
|
||||
use GuzzleHttp\Psr7\Request;
|
||||
use GuzzleHttp\Psr7\ResponseInterface;
|
||||
|
||||
use Aviat\Ion\Di\ContainerInterface;
|
||||
use Aviat\AnimeClient\Model as BaseModel;
|
||||
|
||||
/**
|
||||
* Base model for api interaction
|
||||
*
|
||||
* @method ResponseInterface get(string $uri, array $options);
|
||||
* @method ResponseInterface delete(string $uri, array $options);
|
||||
* @method ResponseInterface head(string $uri, array $options);
|
||||
* @method ResponseInterface options(string $uri, array $options);
|
||||
* @method ResponseInterface patch(string $uri, array $options);
|
||||
* @method ResponseInterface post(string $uri, array $options);
|
||||
* @method ResponseInterface put(string $uri, array $options);
|
||||
*/
|
||||
class API extends BaseModel {
|
||||
|
||||
@ -58,6 +67,35 @@ class API extends BaseModel {
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Magic methods to call guzzle api client
|
||||
*
|
||||
* @param string $method
|
||||
* @param array $args
|
||||
* @return ResponseInterface|null
|
||||
*/
|
||||
public function __call($method, $args)
|
||||
{
|
||||
$valid_methods = [
|
||||
'get',
|
||||
'delete',
|
||||
'head',
|
||||
'options',
|
||||
'patch',
|
||||
'post',
|
||||
'put'
|
||||
];
|
||||
|
||||
if ( ! in_array($method, $valid_methods))
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
array_unshift($args, strtoupper($method));
|
||||
$response = call_user_func_array([$this->client, 'request'], $args);
|
||||
return $response;
|
||||
}
|
||||
|
||||
/**
|
||||
* Attempt login via the api
|
||||
*
|
||||
@ -68,7 +106,7 @@ class API extends BaseModel {
|
||||
*/
|
||||
public function authenticate($username, $password)
|
||||
{
|
||||
$result = $this->client->post('https://hummingbird.me/api/v1/users/authenticate', [
|
||||
$result = $this->post('https://hummingbird.me/api/v1/users/authenticate', [
|
||||
'body' => [
|
||||
'username' => $username,
|
||||
'password' => $password
|
||||
|
@ -5,7 +5,6 @@
|
||||
|
||||
namespace Aviat\AnimeClient\Model;
|
||||
|
||||
use Aviat\AnimeClient\Model\API;
|
||||
use Aviat\AnimeClient\Hummingbird\Enum\AnimeWatchingStatus;
|
||||
use Aviat\AnimeClient\Hummingbird\Transformer\AnimeListTransformer;
|
||||
|
||||
@ -50,11 +49,11 @@ class Anime extends API {
|
||||
// @TODO use Hummingbird Auth class
|
||||
$data['auth_token'] = '';
|
||||
|
||||
$result = $this->client->post("libraries/{$data['id']}", [
|
||||
$response = $this->client->post("libraries/{$data['id']}", [
|
||||
'body' => $data
|
||||
]);
|
||||
|
||||
return $result->json();
|
||||
return json_decode($result->getBody(), TRUE);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -140,7 +139,7 @@ class Anime extends API {
|
||||
]
|
||||
];
|
||||
|
||||
$response = $this->client->get('search/anime', $config);
|
||||
$response = $this->get('search/anime', $config);
|
||||
$errorHandler->addDataTable('anime_search_response', (array)$response);
|
||||
|
||||
if ($response->getStatusCode() != 200)
|
||||
@ -148,7 +147,7 @@ class Anime extends API {
|
||||
throw new RuntimeException($response->getEffectiveUrl());
|
||||
}
|
||||
|
||||
return $response->json();
|
||||
return json_decode($response->getBody(), TRUE);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -170,7 +169,7 @@ class Anime extends API {
|
||||
}
|
||||
|
||||
$username = $this->config->get('hummingbird_username');
|
||||
$response = $this->client->get("users/{$username}/library", $config);
|
||||
$response = $this->get("users/{$username}/library", $config);
|
||||
$output = $this->_check_cache($status, $response);
|
||||
|
||||
foreach ($output as &$row)
|
||||
|
@ -6,7 +6,6 @@
|
||||
namespace Aviat\AnimeClient\Model;
|
||||
|
||||
use Aviat\Ion\Di\ContainerInterface;
|
||||
use Aviat\AnimeClient\Model\DB;
|
||||
use Aviat\AnimeClient\Model\Anime as AnimeModel;
|
||||
|
||||
/**
|
||||
@ -43,8 +42,15 @@ class AnimeCollection extends DB {
|
||||
$db_file_name = $this->db_config['collection']['file'];
|
||||
if ($db_file_name !== ':memory:')
|
||||
{
|
||||
$db_file = file_get_contents($db_file_name);
|
||||
$this->valid_database = (strpos($db_file, 'SQLite format 3') === 0);
|
||||
if ( ! file_exists($db_file_name))
|
||||
{
|
||||
$this->valid_data = FALSE;
|
||||
}
|
||||
else
|
||||
{
|
||||
$db_file = file_get_contents($db_file_name);
|
||||
$this->valid_database = (strpos($db_file, 'SQLite format 3') === 0);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -49,12 +49,12 @@ class Manga extends API {
|
||||
unset($data['id']);
|
||||
|
||||
// @TODO update with auth key from auth class
|
||||
$result = $this->client->put("manga_library_entries/{$id}", [
|
||||
$result = $this->put("manga_library_entries/{$id}", [
|
||||
'cookies' => ['token' => ''],
|
||||
'json' => ['manga_library_entry' => $data]
|
||||
]);
|
||||
|
||||
return $result->json();
|
||||
return json_decode($result->getBody(), TRUE);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -90,7 +90,7 @@ class Manga extends API {
|
||||
|
||||
/**
|
||||
* Retrieve the list from the hummingbird api
|
||||
*
|
||||
*
|
||||
* @param string $status
|
||||
* @return array
|
||||
*/
|
||||
@ -104,7 +104,7 @@ class Manga extends API {
|
||||
'allow_redirects' => FALSE
|
||||
];
|
||||
|
||||
$response = $this->client->get('manga_library_entries', $config);
|
||||
$response = $this->get('manga_library_entries', $config);
|
||||
$data = $this->_check_cache($response);
|
||||
$output = $this->map_by_status($data);
|
||||
|
||||
|
@ -61,7 +61,7 @@ class ArrayType {
|
||||
*
|
||||
* @param array $arr
|
||||
*/
|
||||
public function __construct(array $arr)
|
||||
public function __construct(array &$arr)
|
||||
{
|
||||
$this->arr =& $arr;
|
||||
}
|
||||
@ -154,5 +154,41 @@ class ArrayType {
|
||||
{
|
||||
return in_array($value, $this->arr, $strict);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the array
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function get()
|
||||
{
|
||||
return $this->arr;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a reference to the value of an arbitrary key on the array
|
||||
*
|
||||
* @param array $key
|
||||
* @return mixed
|
||||
*/
|
||||
public function &get_deep_key(array $key)
|
||||
{
|
||||
$pos =& $this->arr;
|
||||
|
||||
// Create the start of the array if it doesn't exist
|
||||
if ( ! is_array($pos))
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// Iterate through the levels of the array,
|
||||
// create the levels if they don't exist
|
||||
foreach($key as $level)
|
||||
{
|
||||
$pos =& $pos[$level];
|
||||
}
|
||||
|
||||
return $pos;
|
||||
}
|
||||
}
|
||||
// End of ArrayType.php
|
@ -26,6 +26,7 @@ class HttpView extends BaseView {
|
||||
/**
|
||||
* Send the appropriate response
|
||||
*
|
||||
* @codeCoverageIgnore
|
||||
* @return void
|
||||
*/
|
||||
protected function output()
|
||||
|
@ -20,6 +20,83 @@ class ConfigTest extends AnimeClient_TestCase {
|
||||
$this->assertNull($this->config->get('baz'));
|
||||
}
|
||||
|
||||
public function testConfigSet()
|
||||
{
|
||||
$this->config->set('foo', 'foobar');
|
||||
$this->assertEquals('foobar', $this->config->get('foo'));
|
||||
|
||||
$this->config->set(['apple', 'sauce', 'is'], 'great');
|
||||
$this->assertEquals('great', $this->config->get(['apple', 'sauce', 'is']));
|
||||
}
|
||||
|
||||
public function dataConfigDelete()
|
||||
{
|
||||
return [
|
||||
'top level delete' => [
|
||||
'key' => 'apple',
|
||||
'assertKeys' => [
|
||||
[
|
||||
'path' => ['apple', 'sauce', 'is'],
|
||||
'expected' => NULL
|
||||
],
|
||||
[
|
||||
'path' => ['apple', 'sauce'],
|
||||
'expected' => NULL
|
||||
],
|
||||
[
|
||||
'path' => 'apple',
|
||||
'expected' => NULL
|
||||
]
|
||||
]
|
||||
],
|
||||
'mid level delete' => [
|
||||
'key' => ['apple', 'sauce'],
|
||||
'assertKeys' => [
|
||||
[
|
||||
'path' => ['apple', 'sauce', 'is'],
|
||||
'expected' => NULL
|
||||
],
|
||||
[
|
||||
'path' => ['apple', 'sauce'],
|
||||
'expected' => NULL
|
||||
],
|
||||
[
|
||||
'path' => 'apple',
|
||||
'expected' => []
|
||||
]
|
||||
]
|
||||
],
|
||||
'deep delete' => [
|
||||
'key' => ['apple', 'sauce', 'is'],
|
||||
'assertKeys' => [
|
||||
[
|
||||
'path' => ['apple', 'sauce', 'is'],
|
||||
'expected' => NULL
|
||||
],
|
||||
[
|
||||
'path' => ['apple', 'sauce'],
|
||||
'expected' => NULL
|
||||
]
|
||||
]
|
||||
]
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* @dataProvider dataConfigDelete
|
||||
*/
|
||||
public function testConfigDelete($key, $assertKeys)
|
||||
{
|
||||
$this->markTestIncomplete();
|
||||
$this->config->set(['apple', 'sauce', 'is'], 'great');
|
||||
$this->config->delete($key);
|
||||
|
||||
foreach($assertKeys as $pair)
|
||||
{
|
||||
$this->assertEquals($pair['expected'], $this->config->get($pair['path']));
|
||||
}
|
||||
}
|
||||
|
||||
public function testGetNonExistentConfigItem()
|
||||
{
|
||||
$this->assertNull($this->config->get('foobar'));
|
||||
|
@ -1,5 +1,8 @@
|
||||
<?php
|
||||
use \Aviat\AnimeClient\Controller;
|
||||
use Aviat\AnimeClient\Controller\Anime as AnimeController;
|
||||
use Aviat\AnimeClient\Controller\Manga as MangaController;
|
||||
use Aviat\AnimeClient\Controller\Collection as CollectionController;
|
||||
use \Aura\Web\WebFactory;
|
||||
use \Aura\Router\RouterFactory;
|
||||
|
||||
@ -20,9 +23,34 @@ class ControllerTest extends AnimeClient_TestCase {
|
||||
$this->container->set('request', $web_factory->newRequest());
|
||||
$this->container->set('response', $web_factory->newResponse());
|
||||
|
||||
|
||||
$this->BaseController = new Controller($this->container);
|
||||
}
|
||||
|
||||
public function testControllersSanity()
|
||||
{
|
||||
$config = $this->container->get('config');
|
||||
$config->set(['database', 'collection'], [
|
||||
'type' => 'sqlite',
|
||||
'database' => '',
|
||||
'file' => ":memory:"
|
||||
]);
|
||||
$this->container->set('config', $config);
|
||||
|
||||
$this->assertInstanceOf(
|
||||
'Aviat\AnimeClient\Controller',
|
||||
new AnimeController($this->container)
|
||||
);
|
||||
$this->assertInstanceOf(
|
||||
'Aviat\AnimeClient\Controller',
|
||||
new MangaController($this->container)
|
||||
);
|
||||
$this->assertInstanceOf(
|
||||
'Aviat\AnimeClient\Controller',
|
||||
new CollectionController($this->container)
|
||||
);
|
||||
}
|
||||
|
||||
public function testBaseControllerSanity()
|
||||
{
|
||||
$this->assertTrue(is_object($this->BaseController));
|
||||
|
@ -16,23 +16,7 @@ class MenuGeneratorTest extends AnimeClient_TestCase {
|
||||
public function setUp()
|
||||
{
|
||||
parent::setUp();
|
||||
$config = $this->container->get('config');
|
||||
$config->set('menus', [
|
||||
'anime_list' => [
|
||||
'route_prefix' => '/anime',
|
||||
'items' => [
|
||||
'watching' => '/watching',
|
||||
'plan_to_watch' => '/plan_to_watch',
|
||||
'on_hold' => '/on_hold',
|
||||
'dropped' => '/dropped',
|
||||
'completed' => '/completed',
|
||||
'all' => '/all'
|
||||
]
|
||||
],
|
||||
]);
|
||||
|
||||
$this->generator = new MenuGenerator($this->container);
|
||||
|
||||
}
|
||||
|
||||
public function testSanity()
|
||||
@ -44,6 +28,19 @@ class MenuGeneratorTest extends AnimeClient_TestCase {
|
||||
public function testParseConfig()
|
||||
{
|
||||
$friend = new Friend($this->generator);
|
||||
$menus = [
|
||||
'anime_list' => [
|
||||
'route_prefix' => '/anime',
|
||||
'items' => [
|
||||
'watching' => '/watching',
|
||||
'plan_to_watch' => '/plan_to_watch',
|
||||
'on_hold' => '/on_hold',
|
||||
'dropped' => '/dropped',
|
||||
'completed' => '/completed',
|
||||
'all' => '/all'
|
||||
]
|
||||
],
|
||||
];
|
||||
$expected = [
|
||||
'anime_list' => [
|
||||
'Watching' => '/anime/watching',
|
||||
@ -54,6 +51,6 @@ class MenuGeneratorTest extends AnimeClient_TestCase {
|
||||
'All' => '/anime/all'
|
||||
]
|
||||
];
|
||||
$this->assertEquals($expected, $friend->parse_config());
|
||||
$this->assertEquals($expected, $friend->parse_config($menus));
|
||||
}
|
||||
}
|
@ -6,6 +6,8 @@ use Aviat\AnimeClient\Model\API as BaseApiModel;
|
||||
|
||||
class MockBaseApiModel extends BaseApiModel {
|
||||
|
||||
protected $base_url = 'https://httpbin.org/';
|
||||
|
||||
public function __construct(ContainerInterface $container)
|
||||
{
|
||||
parent::__construct($container);
|
||||
@ -19,9 +21,15 @@ class MockBaseApiModel extends BaseApiModel {
|
||||
|
||||
class BaseApiModelTest extends AnimeClient_TestCase {
|
||||
|
||||
public function setUp()
|
||||
{
|
||||
parent::setUp();
|
||||
$this->model = new MockBaseApiModel($this->container);
|
||||
}
|
||||
|
||||
public function testBaseApiModelSanity()
|
||||
{
|
||||
$baseApiModel = new MockBaseApiModel($this->container);
|
||||
$baseApiModel = $this->model;
|
||||
|
||||
// Some basic type checks for class memebers
|
||||
$this->assertInstanceOf('\Aviat\AnimeClient\Model', $baseApiModel);
|
||||
@ -34,4 +42,186 @@ class BaseApiModelTest extends AnimeClient_TestCase {
|
||||
$this->assertTrue(empty($baseApiModel->base_url));
|
||||
}
|
||||
|
||||
public function dataClient()
|
||||
{
|
||||
$host = gethostname();
|
||||
$ip = gethostbyname($host);
|
||||
$user_agent = "Tim's Anime Client/2.0";
|
||||
$headers = [
|
||||
'User-Agent' => $user_agent
|
||||
];
|
||||
|
||||
return [
|
||||
'invalid' => [
|
||||
'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
|
||||
],
|
||||
'origin' => $ip,
|
||||
'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,
|
||||
'origin' => $ip,
|
||||
'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,
|
||||
'origin' => $ip,
|
||||
'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,
|
||||
'origin' => $ip,
|
||||
'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,
|
||||
'origin' => $ip,
|
||||
'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;
|
||||
}
|
||||
|
||||
$actual = ($is_json)
|
||||
? json_decode($result->getBody(), TRUE)
|
||||
: (string) $result->getBody();
|
||||
|
||||
$this->assertEquals($expected, $actual);
|
||||
}
|
||||
|
||||
}
|
52
tests/Ion/View/HtmlViewTest.php
Normal file
52
tests/Ion/View/HtmlViewTest.php
Normal file
@ -0,0 +1,52 @@
|
||||
<?php
|
||||
|
||||
include_once __DIR__ . "/../ViewTest.php";
|
||||
|
||||
use Aviat\Ion\Friend;
|
||||
use Aviat\Ion\View;
|
||||
use Aviat\Ion\View\HtmlView;
|
||||
|
||||
class TestHtmlView extends HtmlView {
|
||||
protected function output() {
|
||||
$reflect = new ReflectionClass($this);
|
||||
$properties = $reflect->getProperties();
|
||||
$props = [];
|
||||
|
||||
foreach($properties as $reflectProp)
|
||||
{
|
||||
$reflectProp->setAccessible(TRUE);
|
||||
$props[$reflectProp->getName()] = $reflectProp->getValue($this);
|
||||
}
|
||||
|
||||
$view = new TestView($this->container);
|
||||
$friend = new Friend($view);
|
||||
foreach($props as $name => $val)
|
||||
{
|
||||
$friend->__set($name, $val);
|
||||
}
|
||||
|
||||
$friend->output();
|
||||
}
|
||||
}
|
||||
|
||||
class HtmlViewTest extends ViewTest {
|
||||
|
||||
protected $template_path = __DIR__ . "/../../test_views/";
|
||||
|
||||
public function setUp()
|
||||
{
|
||||
parent::setUp();
|
||||
$this->view = new TestHtmlView($this->container);
|
||||
}
|
||||
|
||||
public function testRenderTemplate()
|
||||
{
|
||||
$path = $this->template_path . 'test_view.php';
|
||||
$expected = '<tag>foo</tag>';
|
||||
$actual = $this->view->render_template($path, [
|
||||
'var' => 'foo'
|
||||
]);
|
||||
$this->assertEquals($expected, $actual);
|
||||
}
|
||||
|
||||
}
|
46
tests/Ion/View/HttpViewTest.php
Normal file
46
tests/Ion/View/HttpViewTest.php
Normal file
@ -0,0 +1,46 @@
|
||||
<?php
|
||||
|
||||
include_once __DIR__ . "/../ViewTest.php";
|
||||
|
||||
use Aviat\Ion\Friend;
|
||||
use Aviat\Ion\View\HttpView;
|
||||
|
||||
class TestHttpView extends HttpView {
|
||||
protected function output() {
|
||||
$reflect = new ReflectionClass($this);
|
||||
$properties = $reflect->getProperties();
|
||||
$props = [];
|
||||
|
||||
foreach($properties as $reflectProp)
|
||||
{
|
||||
$reflectProp->setAccessible(TRUE);
|
||||
$props[$reflectProp->getName()] = $reflectProp->getValue($this);
|
||||
}
|
||||
|
||||
$view = new TestView($this->container);
|
||||
$friend = new Friend($view);
|
||||
foreach($props as $name => $val)
|
||||
{
|
||||
$friend->__set($name, $val);
|
||||
}
|
||||
|
||||
$friend->output();
|
||||
}
|
||||
}
|
||||
|
||||
class HttpViewTest extends ViewTest {
|
||||
|
||||
public function setUp()
|
||||
{
|
||||
parent::setUp();
|
||||
$this->view = new TestHttpView($this->container);
|
||||
$this->friend = new Friend($this->view);
|
||||
}
|
||||
|
||||
public function testRedirect()
|
||||
{
|
||||
$this->friend->redirect('/foo', 303);
|
||||
$this->assertEquals('/foo', $this->friend->response->headers->get('Location'));
|
||||
$this->assertEquals(303, $this->friend->response->status->getCode());
|
||||
}
|
||||
}
|
44
tests/Ion/View/JsonViewTest.php
Normal file
44
tests/Ion/View/JsonViewTest.php
Normal file
@ -0,0 +1,44 @@
|
||||
<?php
|
||||
|
||||
use Aviat\Ion\Friend;
|
||||
use Aviat\Ion\View\JsonView;
|
||||
|
||||
include_once __DIR__ . "/../ViewTest.php";
|
||||
|
||||
class TestJsonView extends JsonView {
|
||||
public function __destruct() {}
|
||||
}
|
||||
|
||||
class JsonViewTest extends ViewTest {
|
||||
|
||||
public function setUp()
|
||||
{
|
||||
parent::setUp();
|
||||
|
||||
$this->view = new TestJsonView($this->container);
|
||||
$this->friend = new Friend($this->view);
|
||||
}
|
||||
|
||||
public function testSetOutput()
|
||||
{
|
||||
// Extend view class to remove destructor which does output
|
||||
$view = new TestJsonView($this->container);
|
||||
|
||||
// Json encode non-string
|
||||
$content = ['foo' => 'bar'];
|
||||
$expected = json_encode($content);
|
||||
$this->view->setOutput($content);
|
||||
$this->assertEquals($expected, $this->view->getOutput());
|
||||
|
||||
// Directly set string
|
||||
$content = '{}';
|
||||
$expected = '{}';
|
||||
$this->view->setOutput($content);
|
||||
$this->assertEquals($expected, $this->view->getOutput());
|
||||
}
|
||||
|
||||
public function testOutput()
|
||||
{
|
||||
$this->assertEquals('application/json', $this->friend->contentType);
|
||||
}
|
||||
}
|
@ -3,8 +3,6 @@
|
||||
use Aura\Web\WebFactory;
|
||||
use Aviat\Ion\Friend;
|
||||
use Aviat\Ion\View;
|
||||
use Aviat\Ion\Di\Container;
|
||||
|
||||
|
||||
class TestView extends View {
|
||||
|
||||
@ -16,16 +14,6 @@ class ViewTest extends AnimeClient_TestCase {
|
||||
{
|
||||
parent::setUp();
|
||||
|
||||
$web_factory = new WebFactory([
|
||||
'_GET' => $_GET,
|
||||
'_POST' => $_POST,
|
||||
'_COOKIE' => $_COOKIE,
|
||||
'_SERVER' => $_SERVER,
|
||||
'_FILES' => $_FILES
|
||||
]);
|
||||
$this->container->set('request', $web_factory->newRequest());
|
||||
$this->container->set('response', $web_factory->newResponse());
|
||||
|
||||
$this->view = new TestView($this->container);
|
||||
$this->friend = new Friend($this->view);
|
||||
}
|
||||
@ -54,8 +42,9 @@ class ViewTest extends AnimeClient_TestCase {
|
||||
{
|
||||
$this->friend->contentType = 'text/html';
|
||||
$this->friend->__destruct();
|
||||
$this->assertEquals($this->friend->response->content->getType(), $this->friend->contentType);
|
||||
$this->assertEquals($this->friend->response->content->getCharset(), 'utf-8');
|
||||
$this->assertEquals($this->friend->response->content->get(), $this->friend->getOutput());
|
||||
$content =& $this->friend->response->content;
|
||||
$this->assertEquals($content->getType(), $this->friend->contentType);
|
||||
$this->assertEquals($content->getCharset(), 'utf-8');
|
||||
$this->assertEquals($content->get(), $this->friend->getOutput());
|
||||
}
|
||||
}
|
1
tests/test_views/test_view.php
Normal file
1
tests/test_views/test_view.php
Normal file
@ -0,0 +1 @@
|
||||
<tag><?= $var ?></tag>
|
Loading…
Reference in New Issue
Block a user