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

/**
 * @category   Core
 * @package    Core_Application
 * @subpackage UnitTests
 * @copyright  Copyright (c) 2013. Burza d.o.o. (http://web.burza.hr/en/)
 * @license    proprietary
 * @group      Core_Application
 * @group      Core_Application_Plugin
 */
class Core_Application_Plugin_EventHandler_RequestValidatorTest extends CoreTest_Container_TestCase
{
    /**
     * @var Core_Application_Plugin_EventHandler_RequestValidator
     */
    protected $_object;

    protected function setUp()
    {
        $this->_object = new Core_Application_Plugin_EventHandler_RequestValidator('reqValidator');
    }

    protected function tearDown()
    {
        Core_Application::resetInstance();
    }

    /**
     * @covers Core_Application_Plugin_EventHandler_RequestValidator::setRequest
     * @covers Core_Application_Plugin_EventHandler_RequestValidator::getRequest
     */
    public function testCanSetAndGetRequest()
    {
        $request = $this->getMock('Core_Request');
        $this->_object->setRequest($request);

        $this->assertEquals($request, $this->_object->getRequest());
    }

    /**
     * @covers Core_Application_Plugin_EventHandler_RequestValidator::getRequest
     */
    public function testIfRequestNotSetItWillFetchItFromApplicationAsRequest()
    {
        $request   = $this->getMock('Core_Request');
        $container = $this->_mockContainer('Request', $request);
        Core_Application::getInstance()->setContainer($container);

        $this->assertEquals($request, $this->_object->getRequest());
    }

    /**
     * @covers Core_Application_Plugin_EventHandler_RequestValidator::setResponse
     * @covers Core_Application_Plugin_EventHandler_RequestValidator::getResponse
     */
    public function testCanSetAndGetResponse()
    {
        $response = $this->getMock('Core_Response');
        $this->_object->setResponse($response);

        $this->assertEquals($response, $this->_object->getResponse());
    }

    /**
     * @covers Core_Application_Plugin_EventHandler_RequestValidator::getResponse
     */
    public function testIfResponseNotSetItWillFetchItFromApplicationAsResponse()
    {
        $response  = $this->getMock('Core_Response');
        $container = $this->_mockContainer('Response', $response);
        Core_Application::getInstance()->setContainer($container);

        $this->assertEquals($response, $this->_object->getResponse());
    }

    /**
     * @covers Core_Application_Plugin_EventHandler_RequestValidator::setSupportedMethods
     * @covers Core_Application_Plugin_EventHandler_RequestValidator::getSupportedMethods
     */
    public function testCanSetAndGetSupportedMethods()
    {
        $methods = array('POST', 'OPTIONS');
        $this->_object->setSupportedMethods($methods);

        $this->assertEquals($methods, $this->_object->getSupportedMethods());
    }

    /**
     * @covers Core_Application_Plugin_EventHandler_RequestValidator::setSupportedMethods
     */
    public function testWillAlwaysSupportOptionsMethod()
    {
        $methods = array('POST');
        $this->_object->setSupportedMethods($methods);

        $this->assertContains('OPTIONS', $this->_object->getSupportedMethods());
    }

    /**
     * @covers Core_Application_Plugin_EventHandler_RequestValidator::setSupportedHeaders
     * @covers Core_Application_Plugin_EventHandler_RequestValidator::getSupportedHeaders
     */
    public function testCanSetAndGetSupportedHeaders()
    {
        $headers = array('Content-Type', 'Accept');
        $this->_object->setSupportedHeaders($headers);

        $this->assertEquals($headers, $this->_object->getSupportedHeaders());
    }

    /**
     * @covers Core_Application_Plugin_EventHandler_RequestValidator::payloadValidatorHandler
     */
    public function testWillThrowAInvalidInputExceptionIfRequestIsInvalid()
    {
        $this->setExpectedException('Core_Application_InvalidInputException');

        $request = $this->getMock('Core_Request');
        $request
            ->expects($this->once())
            ->method('isValid')
            ->will($this->returnValue(false));
        $this->_object->setRequest($request);

        $this->_object->payloadValidatorHandler();
    }

    /**
     * @covers Core_Application_Plugin_EventHandler_RequestValidator::payloadValidatorHandler
     */
    public function testWillIgnoreValidRequest()
    {
        $request = $this->getMock('Core_Request');
        $request
            ->expects($this->once())
            ->method('isValid')
            ->will($this->returnValue(true));
        $this->_object->setRequest($request);

        $this->_object->payloadValidatorHandler();
    }

    /**
     * @covers Core_Application_Plugin_EventHandler_RequestValidator::methodValidatorHandler
     */
    public function testWillInterceptInvalidMethod()
    {
        $request = $this->getMock('Core_Request');
        $request
            ->expects($this->once())
            ->method('getMethod')
            ->will($this->returnValue('INVALID'));

        $response = $this->getMock('Core_Response', array('setCode', 'setHeader'));
        $response
            ->expects($this->at(0))
            ->method('setCode')
            ->with($this->equalTo(405))
            ->will($this->returnValue($response));
        $response
            ->expects($this->at(1))
            ->method('setHeader')
            ->with($this->equalTo('Allow'), $this->equalTo('GET, POST, OPTIONS'))
            ->will($this->returnValue($response));
        $this->_object
            ->setSupportedMethods(array('GET', 'POST'))
            ->setRequest($request)
            ->setResponse($response);

        $event   = $this->getMock('Core_Event', array('setIsProcessed'), array($this, 'someName'));
        $event
            ->expects($this->once())
            ->method('setIsProcessed')
            ->with($this->equalTo(true));

        $this->assertEquals($response, $this->_object->methodValidatorHandler($event));
    }

    /**
     * @covers Core_Application_Plugin_EventHandler_RequestValidator::methodValidatorHandler
     */
    public function testWillHandleOptionsMethod()
    {
        $request = $this->getMock('Core_Request');
        $request
            ->expects($this->once())
            ->method('getMethod')
            ->will($this->returnValue('OPTIONS'));
        $request
            ->expects($this->once())
            ->method('isMethod')
            ->with($this->equalTo('OPTIONS'))
            ->will($this->returnValue(true));

        $response = $this->getMock('Core_Response', array('setCode', 'setHeader'));
        $response
            ->expects($this->at(0))
            ->method('setHeader')
            ->with($this->equalTo('Allow'), $this->equalTo('GET, POST, OPTIONS'))
            ->will($this->returnValue($response));
        $response
            ->expects($this->at(1))
            ->method('setHeader')
            ->with($this->equalTo('Access-Control-Allow-Methods'), $this->equalTo('GET, POST, OPTIONS'))
            ->will($this->returnValue($response));
        $response
            ->expects($this->at(2))
            ->method('setHeader')
            ->with($this->equalTo('Access-Control-Allow-Headers'), $this->equalTo('Accept, Content-Type'))
            ->will($this->returnValue($response));
        $response
            ->expects($this->at(3))
            ->method('setHeader')
            ->with($this->equalTo('Access-Control-Max-Age'), $this->equalTo(360))
            ->will($this->returnValue($response));

        $this->_object
            ->setSupportedMethods(array('GET', 'POST'))
            ->setSupportedHeaders(array('Accept', 'Content-Type'))
            ->setRequest($request)
            ->setResponse($response);

        $event   = $this->getMock('Core_Event', array('setIsProcessed'), array($this, 'someName'));
        $event
            ->expects($this->once())
            ->method('setIsProcessed')
            ->with($this->equalTo(true));

        $this->assertEquals($response, $this->_object->methodValidatorHandler($event));
    }

    /**
     * @covers Core_Application_Plugin_EventHandler_RequestValidator::methodValidatorHandler
     */
    public function testWillIgnoreValidRequests()
    {
        $request = $this->getMock('Core_Request');
        $request
            ->expects($this->once())
            ->method('getMethod')
            ->will($this->returnValue('GET'));
        $request
            ->expects($this->once())
            ->method('isMethod')
            ->with($this->equalTo('OPTIONS'))
            ->will($this->returnValue(false));
        $this->_object->setRequest($request);

        $event   = $this->getMock('Core_Event_Interface');

        $this->assertNull($this->_object->methodValidatorHandler($event));
    }
}