<?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_SecurityValidatorTest extends CoreTest_Container_TestCase
{
    /**
     * @var Core_Application_Plugin_EventHandler_SecurityValidator
     */
    protected $_object;

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

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

    /**
     * @covers Core_Application_Plugin_EventHandler_SecurityValidator::setUser
     * @covers Core_Application_Plugin_EventHandler_SecurityValidator::getUser
     */
    public function testCanSetAndGetUser()
    {
        $user = $this->getMock('Core_User');
        $this->_object->setUser($user);

        $this->assertEquals($user, $this->_object->getUser());
    }

    /**
     * @covers Core_Application_Plugin_EventHandler_SecurityValidator::getUser
     */
    public function testIfUserNotSetItWillFetchItFromApplicationAsUser()
    {
        $user      = $this->getMock('Core_User');
        $container = $this->_mockContainer('User', $user);
        Core_Application::getInstance()->setContainer($container);

        $this->assertEquals($user, $this->_object->getUser());
    }

    /**
     * @covers Core_Application_Plugin_EventHandler_SecurityValidator::setSecurity
     * @covers Core_Application_Plugin_EventHandler_SecurityValidator::getSecurity
     */
    public function testCanSetAndGetSecurity()
    {
        $security = $this->getMock('Core_Security');
        $this->_object->setSecurity($security);

        $this->assertEquals($security, $this->_object->getSecurity());
    }

    /**
     * @covers Core_Application_Plugin_EventHandler_SecurityValidator::getSecurity
     */
    public function testIfSecurityNotSetItWillFetchItFromApplicationAsSecurity()
    {
        $security  = $this->getMock('Core_Security');
        $container = $this->_mockContainer('Security', $security);
        Core_Application::getInstance()->setContainer($container);

        $this->assertEquals($security, $this->_object->getSecurity());
    }

    /**
     * @covers Core_Application_Plugin_EventHandler_SecurityValidator::securityHandler
     */
    public function testWillThrowUnauthorizedExceptionIfAccessIsNotAllowedAndUserIdentityIsNotAvailable()
    {
        $this->setExpectedException('Core_Application_UnauthorizedException');
        $event = $this->_mock($this->_object, false, false);

        $this->_object->securityHandler($event);
    }

    /**
     * @covers Core_Application_Plugin_EventHandler_SecurityValidator::securityHandler
     */
    public function testWillThrowForbiddenExceptionIfAccessIsNotAllowedAndUserIdentityIsAvailable()
    {
        $this->setExpectedException('Core_Application_ForbiddenException');
        $event = $this->_mock($this->_object, false, true);

        $this->_object->securityHandler($event);
    }


    /**
     * @covers Core_Application_Plugin_EventHandler_SecurityValidator::securityHandler
     */
    public function testWillIgnoreAllowedRequests()
    {
        $event = $this->_mock($this->_object, true);

        $this->_object->securityHandler($event);

        $this->assertTrue(!$event->getIsProcessed());
    }

    protected function _mock($object, $isAllowed, $hasIdentity = null)
    {
        $location   = $this->getMock('Core_Dispatcher_Location_Interface');
        $location
            ->expects($this->once())
            ->method('getAction')
            ->will($this->returnValue('someAction'));
        $controller = $this->getMock('Core_Controller_Interface', array('getSecurityResource', 'invoke'));
        $user       = $this->getMock('Core_User', array('hasIdentity'));
        $security   = $this->getMock('Core_Security');
        $security
            ->expects($this->once())
            ->method('isAllowed')
            ->with($this->equalTo($user), $this->equalTo($controller), $this->equalTo('someAction'))
            ->will($this->returnValue($isAllowed));
        $event      = $this->getMock(
            'Core_Event',
            array('getParam', 'setIsProcessed', 'getIsProcessed'),
            array($this, 'someName')
        );
        $event
            ->expects($this->at(0))
            ->method('getParam')
            ->with($this->equalTo('location'))
            ->will($this->returnValue($location));
        $event
            ->expects($this->at(1))
            ->method('getParam')
            ->with($this->equalTo('controller'))
            ->will($this->returnValue($controller));

        if (!$isAllowed) {
            $controller
                ->expects($this->once())
                ->method('getSecurityResource')
                ->will($this->returnValue('someAction'));

            $user
                ->expects($this->once())
                ->method('hasIdentity')
                ->will($this->returnValue($hasIdentity));
            $event
                ->expects($this->once())
                ->method('setIsProcessed')
                ->with($this->equalTo(true));
        }
        $object
            ->setUser($user)
            ->setSecurity($security);

        return $event;
    }
}