<?php

/*
 * @copyright NetMonsters <team@netmonsters.ru>
 * @link http://netmonsters.ru
 * @package Majestic
 * @subpackage UnitTests
 * @since 2011-10-..
 *
 * Unit tests for Load class
 */

require_once dirname(__FILE__) . '/../Registry.php';
require_once dirname(__FILE__) . '/../Config.php';
require_once dirname(__FILE__) . '/../Load.php';
require_once 'vfsStream/vfsStream.php';

class LoadTest extends PHPUnit_Framework_TestCase
{

    private static $inc_dirs = array();

    private static $file;

    private $root;

    public static $file_contents;
    public static $autoload_array;


    public function run(PHPUnit_Framework_TestResult $result = NULL)
    {
        $this->setPreserveGlobalState(false);
        return parent::run($result);
    }

    /**
     * @TODO: Load->buildAutoload() should recieve AutoloadBuilder as a parameter
     */
    public function setUp()
    {
        self::$file_contents = '<?php return array("Db" => "/lib/core/model/Db.php", "DbDriver" => "/lib/core/model/DbDriver.php"); ?>';
        self::$autoload_array = array('Db' => '/lib/core/model/Db.php', 'DbDriver' => '/lib/core/model/DbDriver.php');

        vfsStreamWrapper::register();
        vfsStream::setup();
        $this->root = vfsStream::create(
            array(
                 'lib' => array(
                     'core' =>
                     array(
                         'util' => array(
                             'AutoloadBuilder.php' => ''
                         ),
                         'model' => array(
                             'Db.php' => '',
                             'DbDriver.php' => ''
                         ),
                         'Registry.php' => '',
                         'Load.php' => '',
                         'devel.config' => ' development config file'
                     )
                 ),
                 'autoload.php' => self::$file_contents
            )
        );

        if (!class_exists('AutoloadBuilder')) {
            $this->getMock('AutoloadBuilder');
        }

        vfsStreamWrapper::setRoot($this->root);

        self::$file = vfsStream::url('root/autoload.php');

        set_new_overload(array($this, 'newCallback'));
    }

    /**
     * @runInSeparateProcess
     */
    public function testSetAutoLoadFromExistingFile()
    {
        $this->setConstants();
        $this->assertFileExists(self::$file);
        Load::setAutoloadFrom(self::$file);

        $autoload = require(self::$file);
        $this->assertSame(self::$autoload_array, $autoload);
        Load::autoload('Db');
    }

    /**
     * @runInSeparateProcess
     */
    public function testAutoloadFromNonExistingFile()
    {
        $this->setConstants();
        $this->assertTrue($this->root->removeChild('autoload.php'));
        $this->assertFileNotExists(self::$file);

        Load::setAutoloadFrom(self::$file);
        $autoload = require(self::$file);

        $this->assertSame(self::$autoload_array, $autoload);
    }

    public function testAutoloadArrayExists()
    {
        $this->assertFileExists(self::$file);
    }

    /**
     * @runInSeparateProcess
     */
    public function testFileForArray()
    {
        $autoload = require(self::$file);
        $this->assertInternalType('array', $autoload);
    }

    /**
     * @runInSeparateProcess
     */
    public function testAutoloadArrayNotEmpty()
    {
        $autoload = require(self::$file);
        $this->assertNotEmpty($autoload);
        $this->assertArrayHasKey('Db', $autoload);
    }

    /**
     * @runInSeparateProcess
     */
    public function testAutoloadGetFilePath()
    {
        $this->setConstants();
        Load::setAutoloadFrom(self::$file);
        $this->assertNotEmpty(Load::getFilePath('DbDriver'));
    }

    /**
     * @runInSeparateProcess
     */
    public function testAutoloadGetFilePathNullIndex()
    {
        $this->setConstants();
        Load::setAutoloadFrom(self::$file);
        $autoload = require(self::$file);
        $this->setExpectedException('PHPUnit_Framework_Error', 'Undefined index');
        $this->assertNotEmpty(Load::getFilePath('ClassDontExist'));
    }

    /**
     * @runInSeparateProcess
     */
    public function testDebugAutoload()
    {
        $this->setConstants();
        unlink(self::$file);
        Load::setAutoloadFrom(self::$file);

        $autoload = require(self::$file);
        $this->assertNotEmpty($autoload);

        Config::set('DEBUG', true);
        Load::autoload('Some');
        Load::autoload('DbDriver');
    }

    /**
     * @runInSeparateProcess
     */
    public function testSetExclude()
    {
        $reflection_prop = new ReflectionProperty('Load', 'exclude');
        $reflection_prop->setAccessible(true);
        $this->assertCount(0, $reflection_prop->getValue('Load'));
        Load::setExclude('dir1');
        $this->assertCount(1, $reflection_prop->getValue('Load'));
        Load::setExclude(array('dir2'));
        $this->assertCount(2, $reflection_prop->getValue('Load'));

        $this->assertSame(array('dir1', 'dir2'), $reflection_prop->getValue('Load'));

    }


    protected function newCallback($className)
    {
        switch ($className) {
            case 'AutoloadBuilder':
                return 'AutoloadBuilderMock';
            default:
                return $className;
        }
    }

    private function setConstants()
    {
        if (!defined('PATH')) {
            define('PATH', vfsStream::url('root'));
        }
        if (!defined('APP')) {
            define('APP', 'lib/core/tests/face');
        }
    }

    public function tearDown()
    {
//        if (defined('PATH')) {
//            echo PHP_EOL . __CLASS__ . '   ' . PATH . PHP_EOL;
//        } else {
//            echo PHP_EOL . __CLASS__ . '   ' . 'PATH NOT DEFINED' . PHP_EOL;
//        }
        unset_new_overload();
    }
}

class AutoloadBuilderMock
{
    public function build()
    {
        $file = new vfsStreamFile('autoload.php');
        $file->setContent(LoadTest::$file_contents);
        vfsStreamWrapper::getRoot()->addChild($file);
    }
}