<?php
/**
 * Whoops - php errors for cool kids
 * @author Filipe Dobreira <http://github.com/filp>
 */

namespace Whoops\Exception;

use Whoops\TestCase;

class FrameTest extends TestCase
{
    /**
     * @return array
     */
    private function getFrameData()
    {
        return [
            'file'     => __DIR__ . '/../../fixtures/frame.lines-test.php',
            'line'     => 0,
            'function' => 'test',
            'class'    => 'MyClass',
            'args'     => [true, 'hello'],
        ];
    }

    /**
     * @param  array $data
     * @return Frame
     */
    private function getFrameInstance($data = null)
    {
        if ($data === null) {
            $data = $this->getFrameData();
        }

        return new Frame($data);
    }

    /**
     * @covers Whoops\Exception\Frame::getFile
     */
    public function testGetFile()
    {
        $data  = $this->getFrameData();
        $frame = $this->getFrameInstance($data);

        $this->assertEquals($frame->getFile(), $data['file']);
    }

    /**
     * @covers Whoops\Exception\Frame::getLine
     */
    public function testGetLine()
    {
        $data  = $this->getFrameData();
        $frame = $this->getFrameInstance($data);

        $this->assertEquals($frame->getLine(), $data['line']);
    }

    /**
     * @covers Whoops\Exception\Frame::getClass
     */
    public function testGetClass()
    {
        $data  = $this->getFrameData();
        $frame = $this->getFrameInstance($data);

        $this->assertEquals($frame->getClass(), $data['class']);
    }

    /**
     * @covers Whoops\Exception\Frame::getFunction
     */
    public function testGetFunction()
    {
        $data  = $this->getFrameData();
        $frame = $this->getFrameInstance($data);

        $this->assertEquals($frame->getFunction(), $data['function']);
    }

    /**
     * @covers Whoops\Exception\Frame::getArgs
     */
    public function testGetArgs()
    {
        $data  = $this->getFrameData();
        $frame = $this->getFrameInstance($data);

        $this->assertEquals($frame->getArgs(), $data['args']);
    }

    /**
     * @covers Whoops\Exception\Frame::getFileContents
     */
    public function testGetFileContents()
    {
        $data  = $this->getFrameData();
        $frame = $this->getFrameInstance($data);

        $this->assertStringEqualsFile($data['file'], $frame->getFileContents());
    }

    /**
     * @covers Whoops\Exception\Frame::getFileContents
     * @testWith ["[internal]"]
     *           ["Unknown"]
     * @see https://github.com/filp/whoops/pull/599
     */
    public function testGetFileContentsWhenFrameIsNotRelatedToSpecificFile($fakeFilename)
    {
        $data  = array_merge($this->getFrameData(), ['file' => $fakeFilename]);
        $frame = $this->getFrameInstance($data);

        $this->assertNull($frame->getFileContents());
    }

    /**
     * @covers Whoops\Exception\Frame::getFileLines
     */
    public function testGetFileLines()
    {
        $data  = $this->getFrameData();
        $frame = $this->getFrameInstance($data);

        $lines = explode("\n", $frame->getFileContents());
        $this->assertEquals($frame->getFileLines(), $lines);
    }

    /**
     * @covers Whoops\Exception\Frame::getFileLines
     */
    public function testGetFileLinesRange()
    {
        $data  = $this->getFrameData();
        $frame = $this->getFrameInstance($data);

        $lines = $frame->getFileLines(0, 3);

        $this->assertEquals($lines[0], '<?php');
        $this->assertEquals($lines[1], '// Line 2');
        $this->assertEquals($lines[2], '// Line 3');
    }

    /**
     * @covers Whoops\Exception\Frame::addComment
     * @covers Whoops\Exception\Frame::getComments
     */
    public function testGetComments()
    {
        $frame    = $this->getFrameInstance();
        $testComments = [
            'Dang, yo!',
            'Errthangs broken!',
            'Dayumm!',
        ];

        $frame->addComment($testComments[0]);
        $frame->addComment($testComments[1]);
        $frame->addComment($testComments[2]);

        $comments = $frame->getComments();

        $this->assertCount(3, $comments);

        $this->assertEquals($comments[0]['comment'], $testComments[0]);
        $this->assertEquals($comments[1]['comment'], $testComments[1]);
        $this->assertEquals($comments[2]['comment'], $testComments[2]);
    }

    /**
     * @covers Whoops\Exception\Frame::addComment
     * @covers Whoops\Exception\Frame::getComments
     */
    public function testGetFilteredComments()
    {
        $frame    = $this->getFrameInstance();
        $testComments = [
            ['Dang, yo!', 'test'],
            ['Errthangs broken!', 'test'],
            'Dayumm!',
        ];

        $frame->addComment($testComments[0][0], $testComments[0][1]);
        $frame->addComment($testComments[1][0], $testComments[1][1]);
        $frame->addComment($testComments[2][0], $testComments[2][1]);

        $comments = $frame->getComments('test');

        $this->assertCount(2, $comments);
        $this->assertEquals($comments[0]['comment'], $testComments[0][0]);
        $this->assertEquals($comments[1]['comment'], $testComments[1][0]);
    }

    /**
     * @covers Whoops\Exception\Frame::serialize
     * @covers Whoops\Exception\Frame::unserialize
     */
    public function testFrameIsSerializable()
    {
        $data            = $this->getFrameData();
        $frame           = $this->getFrameInstance();
        $commentText     = "Gee I hope this works";
        $commentContext  = "test";

        $frame->addComment($commentText, $commentContext);

        $serializedFrame = serialize($frame);
        $newFrame        = unserialize($serializedFrame);

        $this->assertInstanceOf('Whoops\\Exception\\Frame', $newFrame);
        $this->assertEquals($newFrame->getFile(), $data['file']);
        $this->assertEquals($newFrame->getLine(), $data['line']);

        $comments = $newFrame->getComments();
        $this->assertCount(1, $comments);
        $this->assertEquals($comments[0]["comment"], $commentText);
        $this->assertEquals($comments[0]["context"], $commentContext);
    }

    /**
     * @covers Whoops\Exception\Frame::equals
     */
    public function testEquals()
    {
        $frame1 = $this->getFrameInstance(['line' => 1, 'file' => 'test-file.php']);
        $frame2 = $this->getFrameInstance(['line' => 1, 'file' => 'test-file.php']);
        $this->assertTrue ($frame1->equals($frame2));
    }
}
