<commit_before><?php

namespace Phug\Test;

use Phug\Renderer;
use Phug\Renderer\Profiler\ProfilerException;
use Phug\Renderer\Profiler\ProfilerModule;
use Phug\RendererException;

/**
 * @coversDefaultClass Phug\Renderer\Profiler\ProfilerModule
 */
class ProfilerModuleTest extends \PHPUnit_Framework_TestCase
{
    /**
     * @group profiler
     * @covers ::record
     * @covers ::renderProfile
     * @covers ::cleanupProfilerNodes
     * @covers ::appendParam
     * @covers ::appendNode
     * @covers ::<public>
     * @covers \Phug\Renderer\Profiler\TokenDump::<public>
     * @covers \Phug\Renderer\Profiler\LinkDump::<public>
     * @covers \Phug\Renderer\Profiler\LinkDump::initProperties
     * @covers \Phug\Renderer\Profiler\Profile::<public>
     * @covers \Phug\Renderer\Profiler\Profile::calculateIndex
     * @covers \Phug\Renderer\Profiler\Profile::getProcesses
     * @covers \Phug\Renderer\Profiler\Profile::getDuration
     * @covers \Phug\Renderer\Profiler\LinkedProcesses::<public>
     * @covers \Phug\Renderer\Profiler\LinkedProcesses::getEventLink
     * @covers \Phug\Renderer\Profiler\LinkedProcesses::getProfilerEvent
     * @covers \Phug\Renderer::__construct
     * @covers \Phug\Renderer\Partial\Debug\DebuggerTrait::initDebugOptions
     */
    public function testRenderProfiler()
    {
        $renderer = new Renderer([
            'enable_profiler' => true,
        ]);
        $render = $renderer->render('div');

        self::assertRegExp('/div lexing\s*<br>\s*[\.\d]+[µm]?s/', $render);
        self::assertContains('title="div lexing:', $render);
        self::assertRegExp('/div parsing\s*<br>\s*[\.\d]+[µm]?s/', $render);
        self::assertContains('title="div parsing:', $render);
        self::assertRegExp('/div compiling\s*<br>\s*[\.\d]+[µm]?s/', $render);
        self::assertContains('title="div compiling:', $render);
        self::assertRegExp('/div formatting\s*<br>\s*[\.\d]+[µm]?s/', $render);
        self::assertContains('title="div formatting:', $render);
        self::assertRegExp('/div rendering\s*<br>\s*[\.\d]+[µm]?s/', $render);
        self::assertContains('title="div rendering:', $render);

        $renderer = new Renderer([
            'enable_profiler' => true,
            'profiler'        => [
                'time_precision' => 7,
                'dump_event'     => function () {
                    return '-void-dump-';
                },
            ],
        ]);
        $render = $renderer->render("mixin foo\n  | Hello\n+foo");

        self::assertRegExp('/\+foo\s+parsing\s*<br>\s*[\.\d]+µs/', $render);
        self::assertRegExp('/text\s+parsing\s*<br>\s*[\.\d]+µs/', $render);
        self::assertRegExp('/mixin\s+foo\s+parsing\s*<br>\s*[\.\d]+µs/', $render);
    }

    /**
     * @group profiler
     * @covers ::record
     * @covers ::renderProfile
     * @covers ::recordDisplayEvent
     */
    public function testLogProfiler()
    {
        $log = sys_get_temp_dir().DIRECTORY_SEPARATOR.'profiler'.mt_rand(0, 9999999).'.log';
        $renderer = new Renderer([
            'enable_profiler' => true,
            'profiler'        => [
                'log'     => $log,
                'display' => false,
            ],
        ]);
        $renderer->render('div');
        $render = file_get_contents($log);
        /* @var ProfilerModule $profiler */
        $profiler = array_filter($renderer->getModules(), function ($module) {
            return $module instanceof ProfilerModule;
        })[0];
        $count = count($profiler->getEvents());
        $profiler->recordDisplayEvent(1);

        self::assertCount($count, $profiler->getEvents());

        self::assertRegExp('/div lexing\s*<br>\s*[\.\d]+[µm]?s/', $render);
        self::assertContains('title="div lexing:', $render);
        self::assertRegExp('/div parsing\s*<br>\s*[\.\d]+[µm]?s/', $render);
        self::assertContains('title="div parsing:', $render);
        self::assertRegExp('/div compiling\s*<br>\s*[\.\d]+[µm]?s/', $render);
        self::assertContains('title="div compiling:', $render);
        self::assertRegExp('/div formatting\s*<br>\s*[\.\d]+[µm]?s/', $render);
        self::assertContains('title="div formatting:', $render);
        self::assertRegExp('/div rendering\s*<br>\s*[\.\d]+[µm]?s/', $render);
        self::assertContains('title="div rendering:', $render);
    }

    /**
     * @group profiler
     * @covers ::record
     * @covers ::renderProfile
     * @covers ::recordDisplayEvent
     * @covers ::throwException
     */
    public function testExecutionMaxTime()
    {
        $renderer = new Renderer([
            'execution_max_time' => 3,
        ]);
        $message = null;
        try {
            $renderer->render('div');
        } catch (ProfilerException $exception) {
            // Short time should imply not located exception
            $message = $exception->getMessage();
        }

        self::assertContains('execution_max_time of 3ms exceeded.', $message);
    }

    /**
     * @group profiler
     * @covers ::record
     * @covers ::renderProfile
     * @covers ::recordDisplayEvent
     * @covers ::throwException
     */
    public function testMemoryLimit()
    {
        $GLOBALS['LAkjdJHSmlakSJHGdjAJGdjGAHgsjHDAD'] = null;
        $limit = 500000;
        $renderer = new Renderer([
            'memory_limit' => $limit,
            'filters'      => [
                'verbatim' => function ($string) use ($limit) {
                    // Pollute memory
                    $GLOBALS['LAkjdJHSmlakSJHGdjAJGdjGAHgsjHDAD'] = str_repeat('a', $limit * 1.3);

                    return $string;
                },
            ],
        ]);
        $message = null;
        try {
            $renderer->renderFile(__DIR__.'/../cases/includes.pug');
        } catch (RendererException $exception) {
            // 500000B should only be exceeded on verbatim call
            $message = $exception->getMessage();
        }
        unset($GLOBALS['LAkjdJHSmlakSJHGdjAJGdjGAHgsjHDAD']);

        self::assertContains('memory_limit of '.$limit.'B exceeded.', $message);
    }

    /**
     * @group profiler
     * @covers \Phug\Renderer\Profiler\TokenDump::<public>
     */
    public function testTokenDump()
    {
        $renderer = new Renderer([
            'enable_profiler' => true,
            'profiler'        => [
                'time_precision' => 7,<commit_msg>Skip memory limit test on HHVM<commit_after><?php

namespace Phug\Test;

use Phug\Renderer;
use Phug\Renderer\Profiler\ProfilerException;
use Phug\Renderer\Profiler\ProfilerModule;
use Phug\RendererException;

/**
 * @coversDefaultClass Phug\Renderer\Profiler\ProfilerModule
 */
class ProfilerModuleTest extends \PHPUnit_Framework_TestCase
{
    /**
     * @group profiler
     * @covers ::record
     * @covers ::renderProfile
     * @covers ::cleanupProfilerNodes
     * @covers ::appendParam
     * @covers ::appendNode
     * @covers ::<public>
     * @covers \Phug\Renderer\Profiler\TokenDump::<public>
     * @covers \Phug\Renderer\Profiler\LinkDump::<public>
     * @covers \Phug\Renderer\Profiler\LinkDump::initProperties
     * @covers \Phug\Renderer\Profiler\Profile::<public>
     * @covers \Phug\Renderer\Profiler\Profile::calculateIndex
     * @covers \Phug\Renderer\Profiler\Profile::getProcesses
     * @covers \Phug\Renderer\Profiler\Profile::getDuration
     * @covers \Phug\Renderer\Profiler\LinkedProcesses::<public>
     * @covers \Phug\Renderer\Profiler\LinkedProcesses::getEventLink
     * @covers \Phug\Renderer\Profiler\LinkedProcesses::getProfilerEvent
     * @covers \Phug\Renderer::__construct
     * @covers \Phug\Renderer\Partial\Debug\DebuggerTrait::initDebugOptions
     */
    public function testRenderProfiler()
    {
        $renderer = new Renderer([
            'enable_profiler' => true,
        ]);
        $render = $renderer->render('div');

        self::assertRegExp('/div lexing\s*<br>\s*[\.\d]+[µm]?s/', $render);
        self::assertContains('title="div lexing:', $render);
        self::assertRegExp('/div parsing\s*<br>\s*[\.\d]+[µm]?s/', $render);
        self::assertContains('title="div parsing:', $render);
        self::assertRegExp('/div compiling\s*<br>\s*[\.\d]+[µm]?s/', $render);
        self::assertContains('title="div compiling:', $render);
        self::assertRegExp('/div formatting\s*<br>\s*[\.\d]+[µm]?s/', $render);
        self::assertContains('title="div formatting:', $render);
        self::assertRegExp('/div rendering\s*<br>\s*[\.\d]+[µm]?s/', $render);
        self::assertContains('title="div rendering:', $render);

        $renderer = new Renderer([
            'enable_profiler' => true,
            'profiler'        => [
                'time_precision' => 7,
                'dump_event'     => function () {
                    return '-void-dump-';
                },
            ],
        ]);
        $render = $renderer->render("mixin foo\n  | Hello\n+foo");

        self::assertRegExp('/\+foo\s+parsing\s*<br>\s*[\.\d]+µs/', $render);
        self::assertRegExp('/text\s+parsing\s*<br>\s*[\.\d]+µs/', $render);
        self::assertRegExp('/mixin\s+foo\s+parsing\s*<br>\s*[\.\d]+µs/', $render);
    }

    /**
     * @group profiler
     * @covers ::record
     * @covers ::renderProfile
     * @covers ::recordDisplayEvent
     */
    public function testLogProfiler()
    {
        $log = sys_get_temp_dir().DIRECTORY_SEPARATOR.'profiler'.mt_rand(0, 9999999).'.log';
        $renderer = new Renderer([
            'enable_profiler' => true,
            'profiler'        => [
                'log'     => $log,
                'display' => false,
            ],
        ]);
        $renderer->render('div');
        $render = file_get_contents($log);
        /* @var ProfilerModule $profiler */
        $profiler = array_filter($renderer->getModules(), function ($module) {
            return $module instanceof ProfilerModule;
        })[0];
        $count = count($profiler->getEvents());
        $profiler->recordDisplayEvent(1);

        self::assertCount($count, $profiler->getEvents());

        self::assertRegExp('/div lexing\s*<br>\s*[\.\d]+[µm]?s/', $render);
        self::assertContains('title="div lexing:', $render);
        self::assertRegExp('/div parsing\s*<br>\s*[\.\d]+[µm]?s/', $render);
        self::assertContains('title="div parsing:', $render);
        self::assertRegExp('/div compiling\s*<br>\s*[\.\d]+[µm]?s/', $render);
        self::assertContains('title="div compiling:', $render);
        self::assertRegExp('/div formatting\s*<br>\s*[\.\d]+[µm]?s/', $render);
        self::assertContains('title="div formatting:', $render);
        self::assertRegExp('/div rendering\s*<br>\s*[\.\d]+[µm]?s/', $render);
        self::assertContains('title="div rendering:', $render);
    }

    /**
     * @group profiler
     * @covers ::record
     * @covers ::renderProfile
     * @covers ::recordDisplayEvent
     * @covers ::throwException
     */
    public function testExecutionMaxTime()
    {
        $renderer = new Renderer([
            'execution_max_time' => 3,
        ]);
        $message = '';
        try {
            $renderer->render('div');
        } catch (ProfilerException $exception) {
            // Short time should imply not located exception
            $message = $exception->getMessage();
        } catch (RendererException $exception) {
            // Should not happen (security for HHVM test)
            $message = $exception->getMessage();
        }

        self::assertContains('execution_max_time of 3ms exceeded.', $message);
    }

    /**
     * @group profiler
     * @covers ::record
     * @covers ::renderProfile
     * @covers ::recordDisplayEvent
     * @covers ::throwException
     */
    public function testMemoryLimit()
    {
        if (defined('HHVM_VERSION')) {
            self::markTestSkipped('Memory limit test skipped on HHVM.');

            return;
        }

        $GLOBALS['LAkjdJHSmlakSJHGdjAJGdjGAHgsjHDAD'] = null;
        $limit = 500000;
        $renderer = new Renderer([
            'memory_limit' => $limit,
            'filters'      => [
                'verbatim' => function ($string) use ($limit) {
                    // Pollute memory
                    $GLOBALS['LAkjdJHSmlakSJHGdjAJGdjGAHgsjHDAD'] = str_repeat(
                        'a',
                        $limit
                    );

                    return $string;
                },
            ],
        ]);
        $message = '';
        try {
            $renderer->renderFile(__DIR__.'/../cases/includes.pug');
        } catch (RendererException $exception) {
            // 500000B should only be exceeded on verbatim call
            $message = $exception->getMessage();
        }
        unset($GLOBALS['LAkjdJHSmlakSJHGdjAJGdjGAHgsjHDAD']);

        self::assertContains('memory_limit of '.$limit.'B exceeded.', $message);
    }

    /**
     * @group profiler
     * @covers \Phug\Renderer\Profiler\TokenDump::<public>
     */
    public function testTokenDump()
    {
        $renderer = new Renderer([
            'enable_profiler' => true,
            'profiler'        => [
                'time_precision' => 7,
{'fraction_non_alphanumeric': 0.17036756347101176, 'fraction_numerical': 0.004092459264873058, 'mean_word_length': 2.34753932014206, 'pattern_counts': {'":': 0, '<': 43, '<?xml version=': 0, '>': 96, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 2, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '1191402', 'n_tokens_mistral': 4214, 'n_tokens_neox': 4154, 'n_words': 631}