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

/**
 * @category   Core
 * @package    Core_Application
 * @subpackage UnitTests
 * @copyright  Copyright (c) 2013. Burza d.o.o. (http://web.burza.hr/en/)
 * @license    proprietary
 * @group      Core_Application
 * @group      Core_Application_Plugin
 * @group      xhprof
 * @group      pecl
 */
class Core_Application_Plugin_EventHandler_ProfilerTest extends CoreTest_Container_TestCase
{
    /**
     * @var Core_Application_Plugin_EventHandler_Profiler
     */
    protected $_object;

    protected function setUp()
    {
        if (!extension_loaded('xhprof')) {
            $this->markTestSkipped('Core_Application_Plugin_EventHandler_Profiler requires "xhprof" PECL loaded');
        }

        $this->_object = new Core_Application_Plugin_EventHandler_Profiler('profiler');
    }

    protected function tearDown()
    {
        Core_Application::resetInstance();
    }

    /**
     * @covers Core_Application_Plugin_EventHandler_Profiler::setRate
     * @covers Core_Application_Plugin_EventHandler_Profiler::getRate
     */
    public function testCanSetAndGetRate()
    {
        $this->_object->setRate(10);
        $this->assertEquals(10, $this->_object->getRate());
    }

    /**
     * @covers Core_Application_Plugin_EventHandler_Profiler::getRate
     */
    public function testDefaultRateIs100()
    {
        $this->assertEquals(100, $this->_object->getRate());
    }

    /**
     * @covers Core_Application_Plugin_EventHandler_Profiler::setThreshold
     * @covers Core_Application_Plugin_EventHandler_Profiler::getThreshold
     */
    public function testCanSetAndGetThreshold()
    {
        $this->_object->setThreshold(501);
        $this->assertEquals(501, $this->_object->getThreshold());
    }

    /**
     * @covers Core_Application_Plugin_EventHandler_Profiler::getThreshold
     */
    public function testDefaultThresholdIs150000()
    {
        $this->assertEquals(150000, $this->_object->getThreshold());
    }

    /**
     * @covers Core_Application_Plugin_EventHandler_Profiler::setComponent
     * @covers Core_Application_Plugin_EventHandler_Profiler::getComponent
     */
    public function testCanGetAndSetComponent()
    {
        $this->_object->setComponent('foo');

        $this->assertEquals('foo', $this->_object->getComponent());
    }

    /**
     * @covers Core_Application_Plugin_EventHandler_Profiler::getComponent
     */
    public function testIfComponentNotSetWillThrowAnInvalidArgumentException()
    {
        $this->setExpectedException('InvalidArgumentException');

        $this->_object->getComponent();
    }

    /**
     * @covers Core_Application_Plugin_EventHandler_Profiler::setModel
     * @covers Core_Application_Plugin_EventHandler_Profiler::getModel
     */
    public function testCanGetAndSetModel()
    {
        $model = $this->getMock('Core_Application_Plugin_EventHandler_Profiler_Interface');
        $this->_object->setModel($model);

        $this->assertEquals($model, $this->_object->getModel());
    }

    /**
     * @covers Core_Application_Plugin_EventHandler_Profiler::getModel
     */
    public function testIfModelNotSetItWillFetchNamedComponentInstanceFromContainer()
    {
        $model  = $this->getMock('Core_Application_Plugin_EventHandler_Profiler_Interface');
        $this->_setupMockedModel($model);

        $this->assertEquals($model, $this->_object->getModel());
    }

    /**
     * @covers Core_Application_Plugin_EventHandler_Profiler::getModel
     */
    public function testComponentMustBeCore_Application_Plugin_EventHandler_Profiler_Interface()
    {
        $this->_setupMockedModel($this->getMock('stdClass'));
        $this->setExpectedException('InvalidArgumentException');

        $this->_object->getModel();
    }

    /**
     * @covers Core_Application_Plugin_EventHandler_Profiler::init
     */
    public function testInitWillEnableXhprof()
    {
        global $running, $flags;

        $running = false;

        if (!function_exists('runkit_function_add')) {
            $this->markTestSkipped('Requires the runkit_function_add() provided by "runkit" PECL');
        } else if (!ini_get('runkit.internal_override')) {
            $this->markTestSkipped('Requires PHP INI setting runkit.internal_override = true');
        }
        runkit_function_rename('xhprof_enable', 'xhprof_enable_old');
        runkit_function_add('xhprof_enable', '$mflags', 'global $running, $flags; $running = true; $flags = $mflags;');

        $this->_object
            ->setEventDispatcher($this->getMock('Core_Event_Dispatcher_Interface'))
            ->setRate(1);
        $this->_object->init();

        runkit_function_remove('xhprof_enable');
        runkit_function_rename('xhprof_enable_old', 'xhprof_enable');

        $this->assertTrue($running);
        $this->assertEquals(XHPROF_FLAGS_CPU | XHPROF_FLAGS_MEMORY, $flags);
    }

    /**
     * @covers Core_Application_Plugin_EventHandler_Profiler::eventHandler
     */
    public function testEventHandlerWillPersistXhprofDataViaModelIfWalltimeHigherThanThreshold()
    {
        $data  = array('main()' => array(
            // complete wall time = 100msec, threshold = 50msec
            'wt' => 100000,
        ));

        if (!function_exists('runkit_function_add')) {
            $this->markTestSkipped('Requires the runkit_function_add() provided by "runkit" PECL');
        } else if (!ini_get('runkit.internal_override')) {
            $this->markTestSkipped('Requires PHP INI setting runkit.internal_override = true');
        }
        runkit_function_rename('xhprof_disable', 'xhprof_disable_old');
        runkit_function_add('xhprof_disable', '', 'return '. var_export($data, true) .';');

        $model = $this->getMock('Core_Application_Plugin_EventHandler_Profiler_Interface');
        $model
            ->expects($this->once())
            ->method('persistProfile')
            ->with($this->isInstanceOf('Core_Xhprof_Profile'), $this->equalTo(50000));
        $this->_object
            ->setThreshold(50000)
            ->setModel($model);

        $this->_object->eventHandler($this->getMock('Core_Event_Interface'));

        runkit_function_remove('xhprof_disable');
        runkit_function_rename('xhprof_disable_old', 'xhprof_disable');
    }

    protected function _setupMockedModel($model, $name = 'lookupModel')
    {
        $container = $this->_mockContainer($name, $model);
        Core_Application::getInstance()->setContainer($container);
        $this->_object->setComponent($name);
    }
}