<?php



namespace DataSift\Storyplayer\ConfigLib;

use stdClass;
use PHPUnit_Framework_TestCase;
use Mockery;
use DataSift\Stone\ObjectLib\BaseObject;
use DataSift\Storyplayer\Injectables;

class ConfigListTest extends PHPUnit_Framework_TestCase
{
	/**
	 * @covers DataSift\Storyplayer\ConfigLib\ConfigList::__construct()
	 */
	public function testCanInstantiate()
	{
	    // ----------------------------------------------------------------
	    // perform the change

	    $obj = new ConfigList("DataSift\Storyplayer\ConfigLib\WrappedConfig", __DIR__ . '/ConfigListTestData1');

	    // ----------------------------------------------------------------
	    // test the results

	    $this->assertTrue($obj instanceof ConfigList);
	}

	/**
	 * @covers DataSift\Storyplayer\ConfigLib\ConfigList::__construct
	 * @covers DataSift\Storyplayer\ConfigLib\ConfigList::getEntries
	 */
	public function testStartsWithEmptyConfig()
	{
		// ----------------------------------------------------------------
		// setup the test

		$expected = [];

	    // ----------------------------------------------------------------
	    // perform the change

	    $obj = new ConfigList("DataSift\Storyplayer\ConfigLib\WrappedConfig", __DIR__ . '/ConfigListTestData1');

	    // ----------------------------------------------------------------
	    // test the results

	    $actual = $obj->getEntries();
	    $this->assertEquals($expected, $actual);
	}

	/**
	 * @covers DataSift\Storyplayer\ConfigLib\ConfigList::__construct
	 * @covers DataSift\Storyplayer\ConfigLib\ConfigList::getConfigType
	 * @covers DataSift\Storyplayer\ConfigLib\ConfigList::setConfigType
	 */
	public function testCanGetListedConfigType()
	{
		// ----------------------------------------------------------------
		// setup the test

		$expected = "DataSift\Storyplayer\ConfigLib\WrappedConfig";

	    // ----------------------------------------------------------------
	    // perform the change

	    $obj = new ConfigList($expected, __DIR__ . '/ConfigListTestData1');

	    // ----------------------------------------------------------------
	    // test the results

	    $actual = $obj->getConfigType();
	    $this->assertEquals($expected, $actual);
	}

	/**
	 * @covers DataSift\Storyplayer\ConfigLib\ConfigList::__construct
	 * @covers DataSift\Storyplayer\ConfigLib\ConfigList::getConfigType
	 * @covers DataSift\Storyplayer\ConfigLib\ConfigList::setConfigType
	 * @covers DataSift\Storyplayer\ConfigLib\ConfigList::getWrappedConfigClassname
	 * @covers DataSift\Storyplayer\ConfigLib\ConfigList::newWrappedConfigObject
	 */
	public function testCanGetNewListedConfigObject()
	{
		// ----------------------------------------------------------------
		// setup the test

		$expectedClassname = "DataSift\Storyplayer\ConfigLib\WrappedConfig";

	    // ----------------------------------------------------------------
	    // perform the change

	    $obj = new ConfigList($expectedClassname, __DIR__ . '/ConfigListTestData1');

	    // ----------------------------------------------------------------
	    // test the results

	    $actualClassname = $obj->getWrappedConfigClassname();
	    $this->assertEquals($expectedClassname, $actualClassname);

	    $actualConfigObj = $obj->newWrappedConfigObject();
	    $this->assertTrue($actualConfigObj instanceof WrappedConfig);
	}

	/**
	 * @covers DataSift\Storyplayer\ConfigLib\ConfigList::__construct
	 * @covers DataSift\Storyplayer\ConfigLib\ConfigList::setConfigType
	 * @expectedException DataSift\Storyplayer\ConfigLib\E4xx_NoSuchConfigClass
	 */
	public function testConfigTypeMustBeAConfigLibClass()
	{
	    // ----------------------------------------------------------------
	    // perform the change

	    $obj = new ConfigList("NonExistentConfig", __DIR__ . '/ConfigListTestData1');
	}

	/**
	 * @covers DataSift\Storyplayer\ConfigLib\ConfigList::__construct
	 * @covers DataSift\Storyplayer\ConfigLib\ConfigList::getSearchFolder
	 * @covers DataSift\Storyplayer\ConfigLib\ConfigList::setSearchFolder
	 */
	public function testStartsWithGivenSearchFolder()
	{
	    // ----------------------------------------------------------------
	    // setup your test

		$expected = __DIR__ . '/ConfigListTestData1';

	    // ----------------------------------------------------------------
	    // perform the change

	    $obj = new ConfigList("DataSift\Storyplayer\ConfigLib\StoryplayerConfig", $expected);

	    // ----------------------------------------------------------------
	    // test the results

	    $actual = $obj->getSearchFolder();
	    $this->assertEquals($expected, $actual);
	}

	/**
	 * @covers DataSift\Storyplayer\ConfigLib\ConfigList::__construct
	 * @covers DataSift\Storyplayer\ConfigLib\ConfigList::findConfigs
	 * @covers DataSift\Storyplayer\ConfigLib\ConfigList::findConfigFilenames
	 */
	public function testCanLoadConfigFilesFromDisk()
	{
	    // ----------------------------------------------------------------
	    // setup your test

	    $obj = new ConfigList("DataSift\Storyplayer\ConfigLib\StoryplayerConfig", __DIR__ . '/ConfigListTestData1');

	    // ----------------------------------------------------------------
	    // perform the change

	    $obj->findConfigs();

	    // ----------------------------------------------------------------
	    // test the results

	    $configs = $obj->getEntries();

	    $this->assertTrue(is_array($configs));
	    $this->assertTrue(isset($configs['config-1']));
	    $this->assertTrue($configs['config-1'] instanceof StoryplayerConfig);
	    $this->assertTrue(isset($configs['config-2']));
	    $this->assertTrue($configs['config-2'] instanceof StoryplayerConfig);
	}

	/**
	 * @covers DataSift\Storyplayer\ConfigLib\ConfigList::__construct
	 * @covers DataSift\Storyplayer\ConfigLib\ConfigList::findConfigs
	 */
	public function testConfigNamesAreSorted()
	{
	    // ----------------------------------------------------------------
	    // setup your test

		$expectedKeys = [ 'config-1', 'config-2' ];
	    $obj = new ConfigList("DataSift\Storyplayer\ConfigLib\StoryplayerConfig", __DIR__ . '/ConfigListTestData1');

	    // ----------------------------------------------------------------
	    // perform the change

	    $obj->findConfigs();

	    // ----------------------------------------------------------------
	    // test the results

	    $configs = $obj->getEntries();

	    $this->assertEquals($expectedKeys, array_keys($configs));
	}

	/**
	 * @covers DataSift\Storyplayer\ConfigLib\ConfigList::__construct
	 * @covers DataSift\Storyplayer\ConfigLib\ConfigList::findConfigs
	 * @covers DataSift\Storyplayer\ConfigLib\ConfigList::findConfigFilenames
	 */
	public function testIgnoresEmptyFolders()
	{
	    // ----------------------------------------------------------------
	    // setup your test

	    $obj = new ConfigList("DataSift\Storyplayer\ConfigLib\StoryplayerConfig", __DIR__ . '/ConfigListEmptyFolder');

	    // ----------------------------------------------------------------
	    // perform the change

	    $obj->findConfigs();

	    // ----------------------------------------------------------------
	    // test the results

	    $configs = $obj->getEntries();

	    $this->assertTrue(is_array($configs));
	    $this->assertEquals(0, count($configs));
	}

	/**
	 * @covers DataSift\Storyplayer\ConfigLib\ConfigList::__construct
	 * @covers DataSift\Storyplayer\ConfigLib\ConfigList::findConfigs
	 * @covers DataSift\Storyplayer\ConfigLib\ConfigList::findConfigFilenames
	 */
	public function testIgnoresMissingFolders()
	{
	    // ----------------------------------------------------------------
	    // setup your test

	    $obj = new ConfigList("DataSift\Storyplayer\ConfigLib\StoryplayerConfig", __DIR__ . '/ConfigListFolderDoesNotExist');

	    // ----------------------------------------------------------------
	    // perform the change

	    $obj->findConfigs();

	    // ----------------------------------------------------------------
	    // test the results

	    $configs = $obj->getEntries();

	    $this->assertTrue(is_array($configs));
	    $this->assertEquals(0, count($configs));
	}

	/**
	 * @covers DataSift\Storyplayer\ConfigLib\ConfigList::__construct
	 * @covers DataSift\Storyplayer\ConfigLib\ConfigList::addEntry
	 */
	public function testCanAddConfigManually()
	{
	    // ----------------------------------------------------------------
	    // setup your test

	    $obj = new ConfigList("DataSift\Storyplayer\ConfigLib\StoryplayerConfig", __DIR__ . '/ConfigListTestData1');
	    $obj->findConfigs();

	    $expectedName = 'injected-1';
	    $expectedConfig = new StoryplayerConfig();

	    // ----------------------------------------------------------------
	    // perform the change

	    $obj->addEntry($expectedName, $expectedConfig);

	    // ----------------------------------------------------------------
	    // test the results

	    $configs = $obj->getEntries();

	    $this->assertTrue(isset($configs[$expectedName]));
	    $this->assertEquals($expectedConfig, $configs[$expectedName]);
	}

	/**
	 * @covers DataSift\Storyplayer\ConfigLib\ConfigList::__construct
	 * @covers DataSift\Storyplayer\ConfigLib\ConfigList::addEntry
	 * @expectedException DataSift\Storyplayer\ConfigLib\E4xx_IncompatibleConfigClass
	 */
	public function testManuallyAddedConfigsMustBeCompatibleType()
	{
	    // ----------------------------------------------------------------
	    // setup your test

	    $obj = new ConfigList("DataSift\Storyplayer\ConfigLib\StoryplayerConfig", __DIR__ . '/ConfigListTestData1');
	    $obj->findConfigs();

	    $expectedName = 'injected-1';
	    $expectedConfig = new WrappedConfig();

	    // ----------------------------------------------------------------
	    // perform the change

	    $obj->addEntry($expectedName, $expectedConfig);
	}

	/**
	 * @covers DataSift\Storyplayer\ConfigLib\ConfigList::__construct
	 * @covers DataSift\Storyplayer\ConfigLib\ConfigList::hasEntry
	 */
	public function testCanCheckForConfigEntry()
	{
	    // ----------------------------------------------------------------
	    // setup your test

	    $obj = new ConfigList("DataSift\Storyplayer\ConfigLib\StoryplayerConfig", __DIR__ . '/ConfigListTestData1');
	    $obj->findConfigs();

	    // ----------------------------------------------------------------
	    // perform the change

	    $actual1 = $obj->hasEntry('config-1');
	    $actual2 = $obj->hasEntry('config-does-not-exist');

	    // ----------------------------------------------------------------
	    // test the results

	    $this->assertTrue($actual1);
	    $this->assertFalse($actual2);
	}


	/**
	 * @covers DataSift\Storyplayer\ConfigLib\ConfigList::__construct
	 * @covers DataSift\Storyplayer\ConfigLib\ConfigList::getEntry
	 */
	public function testCanGetSingleConfigEntry()
	{
	    // ----------------------------------------------------------------
	    // setup your test

	    $obj = new ConfigList("DataSift\Storyplayer\ConfigLib\StoryplayerConfig", __DIR__ . '/ConfigListTestData1');
	    $obj->findConfigs();

	    // ----------------------------------------------------------------
	    // perform the change

	    $actual = $obj->getEntry('config-1');

	    // ----------------------------------------------------------------
	    // test the results

	    $configs = $obj->getEntries();

	    $this->assertSame($configs['config-1'], $actual);
	}

	/**
	 * @covers DataSift\Storyplayer\ConfigLib\ConfigList::__construct
	 * @covers DataSift\Storyplayer\ConfigLib\ConfigList::getEntry
	 * @expectedException DataSift\Storyplayer\ConfigLib\E4xx_NoSuchConfigEntry
	 */
	public function testThrowsExceptionWhenSingleConfigEntryNotFound()
	{
	    // ----------------------------------------------------------------
	    // setup your test

	    $obj = new ConfigList("DataSift\Storyplayer\ConfigLib\StoryplayerConfig", __DIR__ . '/ConfigListTestData1');
	    $obj->findConfigs();

	    // ----------------------------------------------------------------
	    // perform the change

	    $actual = $obj->getEntry('config-does-not-exist');
	}

	/**
	 * @covers DataSift\Storyplayer\ConfigLib\ConfigList::__construct
	 * @covers DataSift\Storyplayer\ConfigLib\ConfigList::getEntryNames
	 */
	public function testCanGetEntryNames()
	{
	    // ----------------------------------------------------------------
	    // setup your test

	    $obj = new ConfigList("DataSift\Storyplayer\ConfigLib\StoryplayerConfig", __DIR__ . '/ConfigListTestData1');
	    $obj->findConfigs();

	    $expected = [ 'config-1', 'config-2' ];

	    // ----------------------------------------------------------------
	    // perform the change

	    $actual = $obj->getEntryNames();

	    // ----------------------------------------------------------------
	    // test the results

	    $this->assertSame($expected, $actual);
	}

	/**
	 * @covers DataSift\Storyplayer\ConfigLib\ConfigList::__construct
	 * @covers DataSift\Storyplayer\ConfigLib\ConfigList::addHardCodedList
	 */
	public function testCanAddEntriesFromAHardCodedList()
	{
	    // ----------------------------------------------------------------
	    // setup your test

	    $obj = new ConfigList("DataSift\Storyplayer\ConfigLib\WrappedConfig", __DIR__ . '/ConfigListTestData1');

	    $hardCodedList = new HardCodedList('DataSift\Storyplayer\ConfigLib\WrappedConfig');
	    $expected1 = $hardCodedList->newConfig('hard-coded-config-1');
	    $expected1->getConfig()->name = 'config-1';
	    $expected2 = $hardCodedList->newConfig('hard-coded-config-2');
	    $expected2->getConfig()->name = 'config-2';

	    // ----------------------------------------------------------------
	    // perform the change

	    $obj->addHardCodedList($hardCodedList);

	    // ----------------------------------------------------------------
	    // test the results

	    $this->assertTrue($obj->hasEntry('hard-coded-config-1'));
	    $this->assertSame($expected1, $obj->getEntry('hard-coded-config-1'));
	    $this->assertTrue($obj->hasEntry('hard-coded-config-2'));
	    $this->assertSame($expected2, $obj->getEntry('hard-coded-config-2'));
	}

}