<?php

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

require_once dirname(__FILE__) . '/../../../Registry.php';
require_once dirname(__FILE__) . '/../../../Config.php';
require_once dirname(__FILE__) . '/../../../exception/GeneralException.php';
require_once dirname(__FILE__) . '/../../../util/FirePHPCore-0.3.2/lib/FirePHPCore/fb.php';
require_once dirname(__FILE__) . '/../../../util/profiler/Profiler.php';

/**
 * @TODO: Profiler->getJson() hardly depends on FB library
 */
class ProfilerTest extends PHPUnit_Framework_TestCase
{

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

    public function setUp()
    {
        set_new_overload(array($this, 'newCallback'));
    }

    /**
     * @runInSeparateProcess
     */
    public function testGetInstaceNoDebug()
    {
        Config::set('PROFILER', false);
        $this->setExpectedException('GeneralException', 'Need turn PROFILER before use.');
        Profiler::getInstance();
    }

    /**
     * @runInSeparateProcess
     */
    public function testGetInstance()
    {
        Config::set('PROFILER', true);
        $profiler = Profiler::getInstance();
        $this->assertInstanceOf('Profiler', $profiler);
        $this->assertSame($profiler, Profiler::getInstance());
    }

    /**
     * @runInSeparateProcess
     */
    public function testProfilerCommand()
    {
        Config::set('PROFILER', true);
        $this->getMock('CommandProfiler', array('getType', 'getCommand', 'getElapsed'), array(), 'CommandProfilerMock', false);
        $profiler = Profiler::getInstance();
        $cmdProfiler = $profiler->profilerCommand('command', 'type');
        $this->assertInstanceOf('CommandProfiler', $cmdProfiler);
    }

    /**
     * @runInSeparateProcess
     */
    public function testStartEndNoCommandProfiler()
    {
        Config::set('PROFILER', true);
        Config::set('PROFILER_DETAILS', true);
        $profiler = Profiler::getInstance();
        $profiler->start();
        $result = $profiler->end('<body></body>');
        $this->assertNotEquals('<body></body>', $result);
        $this->assertStringStartsWith('<body>', $result);
        $this->assertStringEndsWith(']<br/></div></body>', $result);
        $this->assertContains('<div style="clear:both; font:12px monospace; margin: 5px; white-space: pre;">', $result);


        $this->assertSame('html', $profiler->end('html'));
    }

    /**
     * @runInSeparateProcess
     */
    public function testStartEndWithCommandProfiler()
    {
        Config::set('PROFILER', true);
        Config::set('PROFILER_DETAILS', true);
        
        $this->getMock('CommandProfiler', array('getType', 'getCommand', 'getElapsed'), array(), 'CommandProfilerMock', false);
        $profiler = Profiler::getInstance();

        $profiler->start();
        $cmdProfiler = $profiler->profilerCommand('command', 'type');
        $this->assertNotNull($cmdProfiler);
        $result = $profiler->end('<body></body>');
        $this->assertNotEquals('<body></body>', $result);
        $this->assertStringEndsNotWith(']<br/></div></body>', $result);
        $this->assertContains('Queries: 1 [0 ms]<br/>() [0ms] <br/>', $result);
    }

    /**
     * @runInSeparateProcess
     */
    public function testStartEndWithCommandProfilerWithNonDetails()
    {
        Config::set('PROFILER', true);
        Config::set('PROFILER_DETAILS', false);

        $this->getMock('CommandProfiler', array('getType', 'getCommand', 'getElapsed'), array(), 'CommandProfilerMock', false);
        $profiler = Profiler::getInstance();
        $profiler->start();
        $result = $profiler->end('<body></body>');
        $this->assertNotEquals('<body></body>', $result);
        $this->assertContains('Queries not counted.', $result);
    }

    /**
     * @runInSeparateProcess
     */
    public function testStartEndWithCommandProfilerWithNonDetailsButExistingQueries()
    {
        Config::set('PROFILER', true);
        Config::set('PROFILER_DETAILS', false);

        $this->getMock('CommandProfiler', array('getType', 'getCommand', 'getElapsed'), array(), 'CommandProfilerMock', false);
        $profiler = Profiler::getInstance();
        $profiler->start();
        $cmdProfiler = $profiler->profilerCommand('command', 'type');
        $result = $profiler->end('<body></body>');
        $this->assertNotEquals('<body></body>', $result);
        $this->assertStringEndsNotWith(']<br/></div></body>', $result);
        $this->assertContains('Queries: 1', $result);
    }

    /**
     * @runInSeparateProcess
     */
    public function testStartEndWithCommandProfilerWithDetailsButNonQueries()
    {
        Config::set('PROFILER', true);
        Config::set('PROFILER_DETAILS', true);

        $this->getMock('CommandProfiler', array('getType', 'getCommand', 'getElapsed'), array(), 'CommandProfilerMock', false);
        $profiler = Profiler::getInstance();
        $profiler->start();
        $result = $profiler->end('<body></body>');
        $this->assertNotEquals('<body></body>', $result);
        $this->assertStringEndsWith(']<br/></div></body>', $result);
        $this->assertContains('Queries: 0', $result);
    }

    /**
     * @runInSeparateProcess
     */
    public function testGetJSON()
    {
        Config::set('PROFILER', true);
        Config::set('PROFILER_DETAILS', true);

        $this->getMock('CommandProfiler', array('getType', 'getCommand', 'getElapsed'), array(), 'CommandProfilerMock', false);
        $profiler = Profiler::getInstance();
        $cmdProfiler = $profiler->profilerCommand('command', 'type');
        $fire_php_mock = $this->getMockBuilder('FirePHP')
                ->disableOriginalConstructor()
                ->setMethods(array('__construct', 'fb'))
                ->getMock();
        $fire_php_mock->expects($this->exactly(2))
            ->method('fb')
            ->with($this->anything(), $this->logicalAnd($this->logicalXor($this->anything(), $this->stringContains('Queries not'))), $this->logicalXor($this->anything(), $this->stringContains('Queries: 0'))); // Expected "Queries: 1"
        $reflection_property = new ReflectionProperty('FirePHP', 'instance');
        $reflection_property->setAccessible(true);
        $reflection_property->setValue($fire_php_mock);
        $this->assertNull($profiler->getJson());
    }

    /**
     * @runInSeparateProcess
     */
    public function testGetJSONWithNonDetails()
    {
        Config::set('PROFILER', true);
        Config::set('PROFILER_DETAILS', false);

        $this->getMock('CommandProfiler', array('getType', 'getCommand', 'getElapsed'), array(), 'CommandProfilerMock', false);
        $profiler = Profiler::getInstance();
        $fire_php_mock = $this->getMockBuilder('FirePHP')
                ->disableOriginalConstructor()
                ->setMethods(array('__construct', 'fb'))
                ->getMock();
        $fire_php_mock->expects($this->exactly(2))
            ->method('fb')
            ->with($this->anything(), $this->logicalAnd($this->logicalXor($this->anything(), $this->stringContains('Queries: 1'))), $this->logicalXor($this->anything(), $this->stringContains('Queries: 0'))); // expected "Queries not counted"
        $reflection_property = new ReflectionProperty('FirePHP', 'instance');
        $reflection_property->setAccessible(true);
        $reflection_property->setValue($fire_php_mock);
        $this->assertNull($profiler->getJson());
    }

    /**
     * @runInSeparateProcess
     */
    public function testGetJSONWithNonDetailsButExistingQueries()
    {
        Config::set('PROFILER', true);
        Config::set('PROFILER_DETAILS', false);

        $this->getMock('CommandProfiler', array('getType', 'getCommand', 'getElapsed'), array(), 'CommandProfilerMock', false);
        $profiler = Profiler::getInstance();
        $cmdProfiler = $profiler->profilerCommand('command', 'type');
        $fire_php_mock = $this->getMockBuilder('FirePHP')
                ->disableOriginalConstructor()
                ->setMethods(array('__construct', 'fb'))
                ->getMock();
        $fire_php_mock->expects($this->exactly(2))
            ->method('fb')
            ->with($this->anything(), $this->logicalAnd($this->logicalXor($this->anything(), $this->stringContains('Queries not counted'))), $this->logicalXor($this->anything(), $this->stringContains('Queries: 0'))); // expected "Queries: 1"
        $reflection_property = new ReflectionProperty('FirePHP', 'instance');
        $reflection_property->setAccessible(true);
        $reflection_property->setValue($fire_php_mock);
        $this->assertNull($profiler->getJson());
    }

    /**
     * @runInSeparateProcess
     */
    public function testGetJSONWithDetailsButNonQueries()
    {
        Config::set('PROFILER', true);
        Config::set('PROFILER_DETAILS', true);

        $this->getMock('CommandProfiler', array('getType', 'getCommand', 'getElapsed'), array(), 'CommandProfilerMock', false);
        $profiler = Profiler::getInstance();
        $fire_php_mock = $this->getMockBuilder('FirePHP')
                ->disableOriginalConstructor()
                ->setMethods(array('__construct', 'fb'))
                ->getMock();
        $fire_php_mock->expects($this->exactly(2))
            ->method('fb')
            ->with($this->anything(), $this->logicalAnd($this->logicalXor($this->anything(), $this->stringContains('Queries not counted'))), $this->logicalXor($this->anything(), $this->stringContains('Queries: 1'))); // expected "Queries: 0"
        $reflection_property = new ReflectionProperty('FirePHP', 'instance');
        $reflection_property->setAccessible(true);
        $reflection_property->setValue($fire_php_mock);
        $this->assertNull($profiler->getJson());
    }

    /**
     * @runInSeparateProcess
     */
    public function testGetCLI()
    {
        Config::set('PROFILER', true);
        Config::set('PROFILER_DETAILS', true);

        $this->getMock('CommandProfiler', array('getType', 'getCommand', 'getElapsed'), array(), 'CommandProfilerMock', false);
        $profiler = Profiler::getInstance();
        $cmdProfiler = $profiler->profilerCommand('command', 'type');
        $result = $profiler->getCli();
        $this->assertNotNull($result);
        $this->assertContains('Queries: 1', Profiler::getInstance()->getCli());
    }

    /**
     * @runInSeparateProcess
     */
    public function testGetCLIWithNonDetails()
    {
        Config::set('PROFILER', true);
        Config::set('PROFILER_DETAILS', false);

        $this->getMock('CommandProfiler', array('getType', 'getCommand', 'getElapsed'), array(), 'CommandProfilerMock', false);
        $profiler = Profiler::getInstance();
        $result = $profiler->getCli();
        $this->assertNotNull($result);
        $this->assertContains('Queries not counted', Profiler::getInstance()->getCli());
    }

    /**
     * @runInSeparateProcess
     */
    public function testGetCLIWithNonDetailsButExistingQueries()
    {
        Config::set('PROFILER', true);
        Config::set('PROFILER_DETAILS', false);

        $this->getMock('CommandProfiler', array('getType', 'getCommand', 'getElapsed'), array(), 'CommandProfilerMock', false);
        $profiler = Profiler::getInstance();
        $cmdProfiler = $profiler->profilerCommand('command', 'type');
        $result = $profiler->getCli();
        $this->assertNotNull($result);
        $this->assertContains('Queries: 1', Profiler::getInstance()->getCli());
    }

    /**
     * @runInSeparateProcess
     */
    public function testGetCLIWithDetailsButNonQueries()
    {
        Config::set('PROFILER', true);
        Config::set('PROFILER_DETAILS', true);

        $this->getMock('CommandProfiler', array('getType', 'getCommand', 'getElapsed'), array(), 'CommandProfilerMock', false);
        $profiler = Profiler::getInstance();
        $result = $profiler->getCli();
        $this->assertNotNull($result);
        $this->assertContains('Queries: 0', Profiler::getInstance()->getCli());
    }

    public function tearDown()
    {
//        if (!is_null(Config::get('DEBUG'))) {
//            $debug = Config::get('DEBUG') ? 'TRUE' : 'FALSE';
//            echo PHP_EOL . __CLASS__ . '   ' . $debug . PHP_EOL;
//        } else {
//            echo PHP_EOL . __CLASS__ . '   ' . 'DEBUG NOT DEFINED' . PHP_EOL;
//        }
        unset_new_overload();
    }

    protected function newCallback($className)
    {
        switch ($className) {
            case 'CommandProfiler':
                return 'CommandProfilerMock';
            default:
                return $className;
        }
    }
}
//
//
//class CommandProfilerMock
//{
//
//    public function __construct($type, $command)
//    {
//    }
//
//    public function getCommand()
//    {
//        return 'command';
//    }
//
//    public function getType()
//    {
//        return 'type';
//    }
//
//    public function getElapsed()
//    {
//        return 10;
//    }
//}