<?php

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

require_once dirname(__FILE__) . '/../../classes/Env.class.php';
require_once dirname(__FILE__) . '/../../session/Session.php';
require_once dirname(__FILE__) . '/../../exception/ErrorHandler.php';

class ErrorHandlerTest extends PHPUnit_Framework_TestCase
{
    public $old_eh = array('PHPUnit_Util_ErrorHandler', 'handleError');

    protected $log_file_name = 'error_log_file';

    public function setUp()
    {
        set_error_handler(array('ErrorHandler', 'error_handler'));
        ob_start();
    }

    public function testErrorHandlerInit()
    {
        $my_eh = array('ErrorHandler', 'error_handler');
        ErrorHandler::init();
        $eh = set_error_handler($my_eh);
        $this->assertInternalType('array', $eh);
        $this->assertSame($eh, $my_eh);
    }

    public function testHandleError()
    {
        $this->setExpectedException('ErrorException', 'test error');
        trigger_error("test error", E_USER_ERROR);
    }

    public function testHandleAt()
    {
        $my_eh = array('ErrorHandler', 'error_handler');
        ErrorHandler::init();
        set_error_handler($my_eh);
        $var = '';
        $ok = @$var['some'];
        $this->assertSame('', $var);
        ob_start();
        $this->setExpectedException('ErrorException');
        $ex = $var['some'];
    }

    /**
     * @TODO: ErrorHandler->wrapTrace() not used
     */
    public function testShowDebug()
    {
        try {
            throw new ErrorException("test error", E_USER_ERROR);
        }
        catch (ErrorException $e) {
            $_SESSION['some'] = 'value';
            $result = ErrorHandler::showDebug($e);
            $this->assertNotEmpty($result);
            $this->assertStringStartsWith('<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">', $result);
            $this->assertStringEndsWith('</html>', $result);
        }
    }

    /**
     * @TODO: ErrorHandler::wrapTrace not used
     * @TODO: nl2br() adds html <br /> but leaves original linebreak line \n
     */
    public function testWrapTrace()
    {
        $class = new ReflectionClass('ErrorHandler');
        $method = $class->getMethod('WrapTrace');
        $method->setAccessible(true);
        $result = $method->invoke(null, "first line\nsecond line");
        $this->assertSame("<code>first line<br />\nsecond line</code>", $result);
        $result = $method->invoke(null, "first line\r\nsecond line");
        $this->assertSame("<code>first line<br />\r\nsecond line</code>", $result);
        $result = $method->invoke(null, "first line\r\n\r\nsecond line");
        $this->assertSame("<code>first line<br />\r\n<br />\r\nsecond line</code>", $result);
    }

    /**
     * @runInSeparateProcess
     */
    public function testLogErrorDefaultException()
    {
        $ex = new Exception('message', 123);
        ini_set('error_log', $this->log_file_name);
        ErrorHandler::logError($ex);
        $log = file_get_contents($this->log_file_name);
        $this->assertContains('PHP Unknown Error:  Exception: message in ', $log);
    }

    /**
     * @runInSeparateProcess
     */
    public function testLogErrorDefaultExceptionWithHTTP()
    {
        $_SERVER['REQUEST_METHOD'] = 'GET';
        $_SERVER['REQUEST_URI'] = '/somelongurl';
        $_SERVER['HTTP_REFERER'] = 'http://referrer/url';
        $this->assertEquals('GET', ENV::Server('REQUEST_METHOD'));
        $this->assertEquals('/somelongurl', ENV::Server('REQUEST_URI'));
        $this->assertEquals('http://referrer/url', ENV::Server('HTTP_REFERER'));

        $ex = new Exception('message', 123);
        ini_set('error_log', $this->log_file_name);
        ErrorHandler::logError($ex);
        $log = file_get_contents($this->log_file_name);
        $this->assertContains('PHP Unknown Error:  Exception: message in ', $log);
        $this->assertContains('URL: GET /somelongurl, referrer: http://referrer/url', $log);
    }

    /**
     * @runInSeparateProcess
     */
    public function testLogErrorCustomException()
    {
        $ex = new LogicException('Logic', 333);
        ini_set('error_log', $this->log_file_name);
        ErrorHandler::logError($ex);
        $log = file_get_contents($this->log_file_name);
        $this->assertContains('PHP Unknown Error:  LogicException: Logic in ', $log);
    }

    /**
     * @runInSeparateProcess
     */
    public function testLogErrorErrorExceptionNotice()
    {
        $ex = new ErrorException('message', 321, E_NOTICE);
        ini_set('error_log', $this->log_file_name);
        ErrorHandler::logError($ex);
        $log = file_get_contents($this->log_file_name);
        $this->assertContains('PHP Notice:  message in ', $log);
    }

    /**
     * @runInSeparateProcess
     */
    public function testLogErrorErrorExceptionWarning()
    {
        $ex = new ErrorException('message', 321, E_WARNING);
        ini_set('error_log', $this->log_file_name);
        ErrorHandler::logError($ex);
        $log = file_get_contents($this->log_file_name);
        $this->assertContains('PHP Warning:  message in ', $log);
    }

    /**
     * @runInSeparateProcess
     */
    public function testLogErrorErrorExceptionFatal()
    {
        $ex = new ErrorException('message', 321, E_ERROR);
        ini_set('error_log', $this->log_file_name);
        ErrorHandler::logError($ex);
        $log = file_get_contents($this->log_file_name);
        $this->assertContains('PHP Fatal Error:  message in ', $log);
    }

    public function tearDown()
    {
        if (file_exists($this->log_file_name) && is_writable($this->log_file_name)) {
            unlink($this->log_file_name);
        }
        ini_set('error_log', 'php://stderr');
        set_error_handler($this->old_eh);
    }
}