<?php

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

require_once dirname(__FILE__) . '/../../util/AutoloadBuilder.php';

/**
 * @TODO: AutoloadBuilder - fix writing to file: construct array first, write to file next - atomic operation
 */
class AutoloadBuilderTest extends PHPUnit_Framework_TestCase
{

    private static $inc_dirs = array();

    private static $file;

    private static $path;

    private static $lib_path;

    private static $app;

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

    /**
     * @TODO: Load->buildAutoload() - uses two paths - PATH . '/' . APP . '/src' and PATH . '/lib' those are not checked. Can couse error.
     */
    public static function setUpBeforeClass()
    {
        self::$path = realpath(dirname(__FILE__) . '/../../../..');
        self::$lib_path = realpath(dirname(__FILE__) . '/../..');
        self::$app = 'lib/core/tests/face';

        self::$file = self::$path . '/' . self::$app . '/cache/autoload.php';

        self::$inc_dirs[self::$path . '/' . self::$app . '/src'] = true;
        self::$inc_dirs[self::$path . '/' . self::$app . '/cache'] = true;
        self::$inc_dirs[self::$lib_path . '/'] = true;

        foreach (self::$inc_dirs as $dir => &$is_exist) {
            if (!file_exists($dir)) {
                $is_exist = false;
                mkdir($dir, 0777, true);
            }
        }
    }

    /**
     * @TODO: AutoloadBuilder - check input params: string for filename, array for dirs
     * @runInSeparateProcess
     */
    public function testBuildParams()
    {
        $this->setConstants();
        $autoload = self::$file;
        $dirs = 'string';
        $builder = new AutoloadBuilder($autoload, $dirs);

        $this->setExpectedException('PHPUnit_Framework_Error');
        $builder->build();
    }

    /**
     * @runInSeparateProcess
     */
    public function testBuild()
    {
        $this->setConstants();
        $builder = new AutoloadBuilder(self::$file, array_keys(self::$inc_dirs));

        $this->assertFileNotExists(self::$file);
        $builder->build();

        $this->assertFileExists(self::$file);

        $array = require self::$file;
        $this->assertFileExists(self::$file);
        $this->assertInternalType('array', $array);
        $this->assertNotEmpty($array);
        $this->assertArrayHasKey('AutoloadBuilder', $array);
        $this->assertArrayHasKey('Load', $array);
    }

    /**
     * @runInSeparateProcess
     */
    public function testBuildWithExcluded()
    {
        $this->setConstants();
        $builder = new AutoloadBuilder(self::$file, array_keys(self::$inc_dirs), array(self::$lib_path . '/app/'));

        $this->assertFileNotExists(self::$file);
        $builder->build();

        $this->assertFileExists(self::$file);

        $array = require self::$file;
        $this->assertInternalType('array', $array);
        $this->assertNotEmpty($array);
        $this->assertArrayHasKey('AutoloadBuilder', $array);
        $this->assertArrayNotHasKey('FrontController', $array);
        $this->assertArrayNotHasKey('AjaxAction', $array);
    }

    /**
     * @runInSeparateProcess
     */
    public function testAccessDenied()
    {
        $this->setConstants();

        $this->assertFileNotExists(self::$file);

        $path = dirname(self::$file);
        chmod($path, 0400);
        $builder = new AutoloadBuilder(self::$file, array(self::$path . '/' . self::$app . '/src', self::$path . '/' . self::$app . '/cache', self::$path . '/lib'));

        $this->setExpectedException('PHPUnit_Framework_Error', 'Permission denied');
        $builder->build();
        chmod(self::$file, 0777);
    }

    public static function tearDownAfterClass()
    {
        if (file_exists(self::$file)) {
            unlink(self::$file);
        }

        foreach (self::$inc_dirs as $dir => $is_exist) {
            if (!$is_exist) {
                self::rrmdir($dir);
            }
        }
        self::rrmdir(self::$path . '/' . self::$app);
    }

    private function setConstants()
    {
        if (!defined('PATH')) {
            define('PATH', realpath(dirname(__FILE__) . '/../../../..'));
        }
        if (!defined('APP')) {
            define('APP', 'lib/core/tests/face');
        }
    }

    public static function rrmdir($dir)
    {
        if (is_dir($dir)) {
            $objects = scandir($dir);
            foreach ($objects as $object) {
                if ($object != "." && $object != "..") {
                    if (filetype($dir . "/" . $object) == "dir") {
                        self::rrmdir($dir . "/" . $object);
                    } else {
                        unlink($dir . "/" . $object);
                    }
                }
            }
            reset($objects);
            rmdir($dir);
        }
    }
}