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

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

    protected function setUp()
    {
        $this->_object = $this->getMockForAbstractClass('Core_Controller_Abstract');
    }

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

    /**
     * @covers Core_Controller_Abstract::setResourceFinder
     * @covers Core_Controller_Abstract::getResourceFinder
     */
    public function testCanSetAndGetResourceFinder()
    {
        $finder = $this->_mockResourceFinder();
        $this->_object->setResourceFinder($finder);

        $this->assertEquals($finder, $this->_object->getResourceFinder());
    }

    /**
     * @covers Core_Controller_Abstract::getResourceFinder
     */
    public function testIfNoResourceFinderIsSpecifiedItWillPullAnInstanceFromApplicationAsResourceFinder()
    {
        $finder    = $this->_mockResourceFinder();
        $container = $this->_mockContainer('ResourceFinder', $finder);
        Core_Application::getInstance()->setContainer($container);

        $this->assertEquals($finder, $this->_object->getResourceFinder());
    }

    /**
     * @covers Core_Controller_Abstract::invoke
     */
    public function testCanInvokeActionMethod()
    {
        $object   = new Invalid_ProperController;
        $location = $this->getMock('Core_Dispatcher_Location_Interface');
        $expected = array(
            'findControllerAction' => 'someAction',
        );
        $object->setResourceFinder($this->_mockResourceFinder($expected));

        $this->assertEquals('someActionReturnValue', $object->invoke($location));
    }

    /**
     * @covers Core_Controller_Abstract::getLocation
     */
    public function testActionInvocationWillStoreLocation()
    {
        $object   = new Invalid_ProperController;
        $location = $this->getMock('Core_Dispatcher_Location_Interface');
        $expected = array(
            'findControllerAction' => 'someAction',
        );
        $object->setResourceFinder($this->_mockResourceFinder($expected));

        $object->invoke($location);

        $this->assertEquals($location, $object->getLocation());
    }

    /**
     * @covers Core_Controller_Abstract::invoke
     *
     * @depends testCanInvokeActionMethod
     */
    public function testIfActionToInvokeDoesNotExistWillThrowAnInvalidArgumentException()
    {
        $this->setExpectedException('InvalidArgumentException');
        $object   = new Invalid_InvalidActionController;
        $location = $this->getMock('Core_Dispatcher_Location_Interface');
        $expected = array(
            'findControllerAction' => 'noSuchAction',
        );
        $object->setResourceFinder($this->_mockResourceFinder($expected));

        $this->assertEquals('someActionReturnValue', $object->invoke($location));
    }

    /**
     * @covers Core_Controller_Abstract::__get
     */
    public function testAccessingPublicPropertiesWillProxyToApplication()
    {
        $object    = new Invalid_InvalidActionController;
        $component = new stdClass;
        $container = $this->getMock('Core_Yadif_Container', array('getComponent'));
        $container
            ->expects($this->once())
            ->method('getComponent')
            ->with($this->equalTo('foo'))
            ->will($this->returnValue($component));
        Core_Application::getInstance()->setContainer($container);

        $this->assertEquals($component, $object->foo);
    }

    /**
     * @covers Core_Controller_Abstract::getSecurityResource
     */
    public function testCanAccessControllerSecurityResource()
    {
        $object = new Invalid_SecurityResourceController;
        $this->assertEquals('my:security:resource', $object->getSecurityResource());
    }

    protected function _mockResourceFinder(array $expected = array())
    {
        $resourceFinder = $this->getMock('Core_Module_ResourceFinder', array_keys($expected));
        if ($expected) {
            foreach ($expected as $method => $return) {
                $resourceFinder
                    ->expects($this->once())
                    ->method($method)
                    ->will($this->returnValue($return));
            }
        }
        return $resourceFinder;
    }
}

class Invalid_ProperController extends Core_Controller_Abstract
{
    public function someAction()
    {
        return 'someActionReturnValue';
    }
}

class Invalid_InvalidActionController extends Core_Controller_Abstract
{
}

class Invalid_SecurityResourceController extends Core_Controller_Abstract
{
    protected $_securityResource = 'my:security:resource';
}