<?php
/**
 * core.framework
 *
 * @category   Core
 * @package    Core_Embed
 * @subpackage UnitTests
 * @copyright  Copyright (c) 2011. Burza d.o.o. (http://web.burza.hr/en/)
 * @license    proprietary
 */

/**
 * @category   Core
 * @package    Core_Embed
 * @subpackage UnitTests
 * @copyright  Copyright (c) 2011. Burza d.o.o. (http://web.burza.hr/en/)
 * @license    proprietary
 * @group      Core_Embed
 */
class Core_Embed_ResponseTest extends PHPUnit_Framework_TestCase
{
    /**
     * @var Core_Embed_Response
     */
    protected $_object;

    /**
     * Sets up the fixture, for example, opens a network connection.
     * This method is called before a test is executed.
     */
    protected function setUp()
    {
        $this->_object = new Core_Embed_Response(null);
    }

    /**
     * @covers Core_Embed_Response::__construct
     * @covers Core_Embed_Response::<protected>
     */
    public function testCanPassDataAsArrayViaConstructor()
    {
        $object   = new Core_Embed_Response(array('type' => 'link'));
        $this->assertEquals("link", $object->get('type'));
    }

    /**
     * @covers Core_Embed_Response::__construct
     * @covers Core_Embed_Response::<protected>
     */
    public function testCanPassDataAsZend_Http_ResponseViaConstructorInJsonFormat()
    {
        $response = $this->_mockResponse('{"type": "link"}');
        $object   = new Core_Embed_Response($response);
        $this->assertEquals("link", $object->get('type'));
    }

    /**
     * @covers Core_Embed_Response::__construct
     * @covers Core_Embed_Response::<protected>
     */
    public function testCanPassDataAsZend_Http_ResponseViaConstructorInXMLFormat()
    {
        $response = $this->_mockResponse(
            '<?xml version="1.0" encoding="utf-8" standalone="yes"?><oembed><type>link</type></oembed>',
            'text/xml'
        );
        $object   = new Core_Embed_Response($response);
        $this->assertEquals("link", $object->get('type'));
    }

    /**
     * @covers Core_Embed_Response::__construct
     * @covers Core_Embed_Response::<protected>
     *
     * @depends testCanPassDataAsZend_Http_ResponseViaConstructorInJsonFormat
     */
    public function testIfContentTypeInZend_Http_ResponseContainsEncodingItWillBeStripped()
    {
        $response = $this->_mockResponse('{"type": "link"}', 'application/json; encoding=UTF8');
        $object   = new Core_Embed_Response($response);
        $this->assertEquals("link", $object->get('type'));
    }

    /**
     * @covers Core_Embed_Response::setData
     */
    public function testCanSetDataAsAnArray()
    {
        $this->_object->setData(array('type' => 'video'));

        $this->assertEquals('video', $this->_object->get('type'));
    }

    /**
     * @covers Core_Embed_Response::set
     * @covers Core_Embed_Response::get
     */
    public function testCanSetAndGetProperty()
    {
        $this->_object->set('type', 'video');

        $this->assertEquals('video', $this->_object->get('type'));
    }

    /**
     * @covers Core_Embed_Response::set
     * @covers Core_Embed_Response::get
     */
    public function testGettingAnUnknownPropertyReturnsNull()
    {
        $this->assertEquals(null, $this->_object->get('type'));
    }

    /**
     * @covers Core_Embed_Response::__set
     * @covers Core_Embed_Response::__get
     */
    public function testCanSetAndGetPropertyViaOverloading()
    {
        $this->_object->type = 'video';
        $this->assertEquals('video', $this->_object->type);
    }

    /**
     * @covers Core_Embed_Response::set
     * @covers Core_Embed_Response::__get
     */
    public function testCanSetAndGetPropertyViaOverloadingAndMethodsInterchangeably()
    {
        $this->_object->set('type', 'video');
        $this->assertEquals('video', $this->_object->type);
    }

    /**
     * @covers Core_Embed_Response::setFormat
     * @covers Core_Embed_Response::getFormat
     */
    public function testCanSetAndGetFormat()
    {
        $this->_object->setFormat('xml');
        $this->assertEquals('xml', $this->_object->getFormat());
    }

    /**
     * @covers Core_Embed_Response::getFormat
     */
    public function testDefaultFormatIsJson()
    {
        $this->assertEquals('json', $this->_object->getFormat());
    }

    /**
     * @covers Core_Embed_Response::render
     *
     * @depends testCanSetDataAsAnArray
     */
    public function testCanRenderAsJSON()
    {
        $this->_object->setData(array('title' => 'foo'));
        $json = $this->_object->render(Core_Embed::FORMAT_JSON);

        $this->assertEquals('{"title":"foo"}', $json);
    }

    /**
     * @covers Core_Embed_Response::render
     *
     * @depends testCanRenderAsJSON
     */
    public function testDefaultRenderTargetIsJSON()
    {
        $this->_object->setData(array('title' => 'foo'));
        $json = $this->_object->render();

        $this->assertEquals('{"title":"foo"}', $json);
    }

    /**
     * @covers Core_Embed_Response::__toString
     *
     * @depends testCanRenderAsJSON
     * @runInSeparateProcess
     */
    public function testWillRenderWhenCastingObjectToString()
    {
        $this->_object->setData(array('title' => 'foo'));

        $this->assertEquals('{"title":"foo"}', $this->_object .'');
    }

    /**
     * @covers Core_Embed_Response::render
     *
     * @depends testCanSetDataAsAnArray
     */
    public function testCanRenderAsXML()
    {
        $this->_object->setData(array('title' => 'foo'));
        $xml  = $this->_object->render(Core_Embed::FORMAT_XML);
        $dom1 = new DOMDocument;
        $dom1->loadXML($xml);

        $dom2 = new DOMDocument;
        $dom2->loadXML('<embed><title>foo</title></embed>');

        $this->assertEqualXMLStructure($dom1->documentElement, $dom2->documentElement);
    }

    /**
     * @covers Core_Embed_Response::toArray
     *
     * @depends testCanSetDataAsAnArray
     */
    public function testCanFetchResponseAsAnArray()
    {
        $response = $this->_mockResponse('{"title": "foo"}', 'application/json; encoding=UTF8');
        $object   = new Core_Embed_Response($response);

        $this->assertEquals(array('title' => 'foo'), $object->toArray());
    }

    /**
     * @covers Core_Embed_Response::set
     * @covers Core_Embed_Response::get
     */
    public function testWillLowercasePropertyName()
    {
        $this->_object->set('TITLE', 'STOP YELLING');
        $this->assertEquals('STOP YELLING', $this->_object->get('title'));
        $this->assertEquals('STOP YELLING', $this->_object->get('TiTlE'));
    }

    /**
     * @param string $type       Original type
     * @param string $normalized Normalized type
     *
     * @covers Core_Embed_Response::get
     * @covers Core_Embed_Response::set
     * @covers Core_Embed_Response::<protected>
     * @dataProvider typeToNormalizedType
     */
    public function testWillNormalizeType($type, $normalized)
    {
        $this->_object->set(Core_Embed_Response::PROPERTY_TYPE, $type);
        $this->assertEquals($normalized, $this->_object->get(Core_Embed_Response::PROPERTY_TYPE));
    }

    /**
     * @return array
     */
    public function typeToNormalizedType()
    {
        return array(
            array('link',                'link'),
            array('article',             'link'),
            array('website',             'link'),
            array('activity',            'link'),
            array('domain',              'link'),
            array('other',               'link'),
            array('product',             'link'),
            array('tv_show',             'link'),
            array('sports_league',       'link'),
            array('game',                'link'),
            array('company',             'link'),
            array('blog',                'link'),
            array('athlete',             'link'),
            array('cause',               'link'),
            array('quickmemeapp:meme',   'link'),
            array('og_vimeo:group',      'link'),

            array('image',               'image'),
            array('photo',               'image'),
            array('flickr_photos:photo', 'image'),
            array('pbphotos:photo',      'image'),

            array('video',               'video'),
            array('video.other',         'video'),
            array('media',               'video'),

            array('audio',               'audio'),
            array('soundcloud:sound',    'audio'),
        );
    }

    protected function _mockResponse($body, $type = 'application/json', $isSuccessful = true)
    {
        $response = $this->getMock(
            'Zend_Http_Response',
            array('isSuccessful', 'getHeader', 'getBody'),
            array(null, array())
        );
        $response
            ->expects($this->once())
            ->method('isSuccessful')
            ->will($this->returnValue($isSuccessful));
        $response
            ->expects($this->once())
            ->method('getHeader')
            ->with($this->equalTo('Content-Type'))
            ->will($this->returnValue($type));
        $response
            ->expects($this->once())
            ->method('getBody')
            ->will($this->returnValue($body));

        return $response;
    }
}
