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

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

    protected function setUp()
    {
        $this->_object      = new Core_Loader_PluginLoader;
        $this->_includePath = get_include_path();

        set_include_path(TESTS_ROOT .'/resources/fixtures/Core/Loader' .PATH_SEPARATOR. get_include_path());
    }

    public function tearDown()
    {
        set_include_path($this->_includePath);
    }

    /**
     * @covers Core_Loader_PluginLoader::setPrefixes
     * @covers Core_Loader_PluginLoader::getPrefixes
     */
    public function testCanSetAndGetPrefixes()
    {
        $prefixes = array('Pre', 'Fix');
        $this->_object->setPrefixes($prefixes);
        $this->assertEquals($prefixes, $this->_object->getPrefixes());
    }

    /**
     * @covers Core_Loader_PluginLoader::setOptions
     */
    public function testCanSetOptions()
    {
        $prefixes = array('a', 'b');
        $options  = array('prefixes' => $prefixes);
        $this->_object->setOptions($options);
        $this->assertEquals($prefixes, $this->_object->getPrefixes());
    }

    /**
     * @covers Core_Loader_PluginLoader::__construct
     */
    public function testCanSetOptionsViaConstructor()
    {
        $prefixes = array('a', 'b');
        $options  = array('prefixes' => $prefixes);
        $object   = new Core_Loader_PluginLoader($options);
        $this->assertEquals($prefixes, $object->getPrefixes());
    }

    /**
     * @covers Core_Loader_PluginLoader::setOptions
     */
    public function testSettingAnInvalidOptionWillThrowAnInvalidArgumentException()
    {
        $this->setExpectedException('InvalidArgumentException');
        $options  = array('nonExistant' => null);
        $this->_object->setOptions($options);
    }

    /**
     * @covers Core_Loader_PluginLoader::loadPlugin
     * @covers Core_Loader_PluginLoader::<protected>
     */
    public function testCanLoadAPluginByShortName()
    {
        $this->_object->setPrefixes(array('Invalid'));
        $this->_object->loadPlugin('TestPlugin');
        $this->assertTrue(class_exists('Invalid_Test_Plugin', false));
    }

    /**
     * @covers Core_Loader_PluginLoader::loadPlugin
     */
    public function testTryingToLoadAnUnavailablePluginWillThrowAnUnexpectedValueException()
    {
        $this->setExpectedException('UnexpectedValueException');
        $this->_object->setPrefixes(array('Invalid'));
        $this->_object->loadPlugin('NonExistant');
    }

    /**
     * @covers Core_Loader_PluginLoader::loadPlugin
     */
    public function testLoadingAPluginByShortNameWillLoadPluginAndReturnFullName()
    {
        $this->_object->setPrefixes(array('Invalid'));
        $plugin = $this->_object->loadPlugin('TestPlugin');
        $this->assertEquals($plugin, 'Invalid_Test_Plugin');
    }

    /**
     * @covers Core_Loader_PluginLoader::loadPlugin
     */
    public function testLoadingAPluginWillReturnTheSameOneUtilPrefixesChange()
    {
        $this->_object->setPrefixes(array('Invalid'));
        $plugin1 = $this->_object->loadPlugin('TestPlugin');
        $plugin2 = $this->_object->loadPlugin('TestPlugin');
        $this->assertEquals($plugin1, $plugin2);
    }

    /**
     * @covers Core_Loader_PluginLoader::initializePlugin
     */
    public function testCanInitializePluginByShortName()
    {
        $this->_object->setPrefixes(array('Invalid'));
        $plugin = $this->_object->initializePlugin('TestPlugin');
        $this->assertEquals(get_class($plugin), 'Invalid_Test_Plugin');
    }

    /**
     * @covers Core_Loader_PluginLoader::initializePlugin
     */
    public function testAllInitializeParamsExceptTypeWillBeProxiedToPlugin()
    {
        $this->_object->setPrefixes(array('Invalid'));
        $plugin = $this->_object->initializePlugin('MySoCalledPlugin', 1, '2', array(3));
        $this->assertEquals(1, $plugin->a);
        $this->assertEquals('2', $plugin->b);
        $this->assertEquals(array(3), $plugin->c);
    }

    /**
     * @covers Core_Loader_PluginLoader::loadPlugin
     * @covers Core_Loader_PluginLoader::__call
     */
    public function testCanLoadPluginWithOverloadedMethodLoadPlugin()
    {
        $this->_object->setPrefixes(array('Invalid'));
        $plugin = $this->_object->loadTestPluginPlugin();
        $this->assertEquals($plugin, 'Invalid_Test_Plugin');
    }

    /**
     * @covers Core_Loader_PluginLoader::initializePlugin
     * @covers Core_Loader_PluginLoader::__call
     */
    public function testCanInitializePluginWithOverloadedMethodInitializePlugin()
    {
        $this->_object->setPrefixes(array('Invalid'));
        $plugin = $this->_object->initializeTestPlugin('Plugin');
        $this->assertEquals(get_class($plugin), 'Invalid_Test_Plugin');
    }

    /**
     * @covers Core_Loader_PluginLoader::initializePlugin
     * @covers Core_Loader_PluginLoader::__call
     */
    public function testCanPassParamsToPluginWhenInitializingWithOverloadedMethodInitializePlugin()
    {
        $this->_object->setPrefixes(array('Invalid'));
        $plugin = $this->_object->initializeMySoCalledPlugin('Plugin', 1, '2', array(3));
        $this->assertEquals(1, $plugin->a);
        $this->assertEquals('2', $plugin->b);
        $this->assertEquals(array(3), $plugin->c);
    }

    /**
     * @covers Core_Loader_PluginLoader::__call
     */
    public function testCallingAnInvalidMethodThrowsAnInvalidArgumentException()
    {
        $this->setExpectedException('InvalidArgumentException');
        $this->_object->thisMethodIsNonExistant();
    }
}

// mock object for plugin params testing
class Invalid_My_So_Called_Plugin
{
    public $a;
    public $b;
    public $c;

    public function __construct($a, $b, $c)
    {
        $this->a = $a;
        $this->b = $b;
        $this->c = $c;
    }
}
