Вход Регистрация
Файл: gapps/vendor/monolog/monolog/tests/Monolog/Formatter/NormalizerFormatterTest.php
Строк: 398
<?php

/*
 * This file is part of the Monolog package.
 *
 * (c) Jordi Boggiano <j.boggiano@seld.be>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace MonologFormatter;

/**
 * @covers MonologFormatterNormalizerFormatter
 */
class NormalizerFormatterTest extends PHPUnit_Framework_TestCase
{
    public function 
tearDown()
    {
        
PHPUnit_Framework_Error_Warning::$enabled = true;

        return 
parent::tearDown();
    }

    public function 
testFormat()
    {
        
$formatter = new NormalizerFormatter('Y-m-d');
        
$formatted = $formatter->format(array(
            
'level_name' => 'ERROR',
            
'channel' => 'meh',
            
'message' => 'foo',
            
'datetime' => new DateTime,
            
'extra' => array('foo' => new TestFooNorm, 'bar' => new TestBarNorm, 'baz' => array(), 'res' => fopen('php://memory', 'rb')),
            
'context' => array(
                
'foo' => 'bar',
                
'baz' => 'qux',
                
'inf' => INF,
                
'-inf' => -INF,
                
'nan' => acos(4),
            ),
        ));

        
$this->assertEquals(array(
            
'level_name' => 'ERROR',
            
'channel' => 'meh',
            
'message' => 'foo',
            
'datetime' => date('Y-m-d'),
            
'extra' => array(
                
'foo' => '[object] (Monolog\Formatter\TestFooNorm: {"foo":"foo"})',
                
'bar' => '[object] (Monolog\Formatter\TestBarNorm: bar)',
                
'baz' => array(),
                
'res' => '[resource] (stream)',
            ),
            
'context' => array(
                
'foo' => 'bar',
                
'baz' => 'qux',
                
'inf' => 'INF',
                
'-inf' => '-INF',
                
'nan' => 'NaN',
            ),
        ), 
$formatted);
    }

    public function 
testFormatExceptions()
    {
        
$formatter = new NormalizerFormatter('Y-m-d');
        
$e = new LogicException('bar');
        
$e2 = new RuntimeException('foo', 0, $e);
        
$formatted = $formatter->format(array(
            
'exception' => $e2,
        ));

        
$this->assertGreaterThan(5, count($formatted['exception']['trace']));
        
$this->assertTrue(isset($formatted['exception']['previous']));
        unset(
$formatted['exception']['trace'], $formatted['exception']['previous']);

        
$this->assertEquals(array(
            
'exception' => array(
                
'class'   => get_class($e2),
                
'message' => $e2->getMessage(),
                
'code'    => $e2->getCode(),
                
'file'    => $e2->getFile().':'.$e2->getLine(),
            ),
        ), 
$formatted);
    }

    public function 
testFormatSoapFaultException()
    {
        if (!
class_exists('SoapFault')) {
            
$this->markTestSkipped('Requires the soap extension');
        }

        
$formatter = new NormalizerFormatter('Y-m-d');
        
$e = new SoapFault('foo', 'bar', 'hello', 'world');
        
$formatted = $formatter->format(array(
            
'exception' => $e,
        ));

        unset(
$formatted['exception']['trace']);

        
$this->assertEquals(array(
            
'exception' => array(
                
'class' => 'SoapFault',
                
'message' => 'bar',
                
'code' => 0,
                
'file' => $e->getFile().':'.$e->getLine(),
                
'faultcode' => 'foo',
                
'faultactor' => 'hello',
                
'detail' => 'world',
            ),
        ), 
$formatted);
    }

    public function 
testFormatToStringExceptionHandle()
    {
        
$formatter = new NormalizerFormatter('Y-m-d');
        
$this->setExpectedException('RuntimeException', 'Could not convert to string');
        
$formatter->format(array(
            
'myObject' => new TestToStringError(),
        ));
    }

    public function 
testBatchFormat()
    {
        
$formatter = new NormalizerFormatter('Y-m-d');
        
$formatted = $formatter->formatBatch(array(
            array(
                
'level_name' => 'CRITICAL',
                
'channel' => 'test',
                
'message' => 'bar',
                
'context' => array(),
                
'datetime' => new DateTime,
                
'extra' => array(),
            ),
            array(
                
'level_name' => 'WARNING',
                
'channel' => 'log',
                
'message' => 'foo',
                
'context' => array(),
                
'datetime' => new DateTime,
                
'extra' => array(),
            ),
        ));
        
$this->assertEquals(array(
            array(
                
'level_name' => 'CRITICAL',
                
'channel' => 'test',
                
'message' => 'bar',
                
'context' => array(),
                
'datetime' => date('Y-m-d'),
                
'extra' => array(),
            ),
            array(
                
'level_name' => 'WARNING',
                
'channel' => 'log',
                
'message' => 'foo',
                
'context' => array(),
                
'datetime' => date('Y-m-d'),
                
'extra' => array(),
            ),
        ), 
$formatted);
    }

    
/**
     * Test issue #137
     */
    
public function testIgnoresRecursiveObjectReferences()
    {
        
// set up the recursion
        
$foo = new stdClass();
        
$bar = new stdClass();

        
$foo->bar = $bar;
        
$bar->foo = $foo;

        
// set an error handler to assert that the error is not raised anymore
        
$that = $this;
        
set_error_handler(function ($level, $message, $file, $line, $context) use ($that) {
            if (
error_reporting() & $level) {
                
restore_error_handler();
                
$that->fail("$message should not be raised");
            }
        });

        
$formatter = new NormalizerFormatter();
        
$reflMethod = new ReflectionMethod($formatter, 'toJson');
        
$reflMethod->setAccessible(true);
        
$res = $reflMethod->invoke($formatter, array($foo, $bar), true);

        
restore_error_handler();

        
$this->assertEquals(@json_encode(array($foo, $bar)), $res);
    }

    public function 
testIgnoresInvalidTypes()
    {
        
// set up the recursion
        
$resource = fopen(__FILE__, 'r');

        
// set an error handler to assert that the error is not raised anymore
        
$that = $this;
        
set_error_handler(function ($level, $message, $file, $line, $context) use ($that) {
            if (
error_reporting() & $level) {
                
restore_error_handler();
                
$that->fail("$message should not be raised");
            }
        });

        
$formatter = new NormalizerFormatter();
        
$reflMethod = new ReflectionMethod($formatter, 'toJson');
        
$reflMethod->setAccessible(true);
        
$res = $reflMethod->invoke($formatter, array($resource), true);

        
restore_error_handler();

        
$this->assertEquals(@json_encode(array($resource)), $res);
    }

    public function 
testNormalizeHandleLargeArrays()
    {
        
$formatter = new NormalizerFormatter();
        
$largeArray = range(1, 2000);

        
$res = $formatter->format(array(
            
'level_name' => 'CRITICAL',
            
'channel' => 'test',
            
'message' => 'bar',
            
'context' => array($largeArray),
            
'datetime' => new DateTime,
            
'extra' => array(),
        ));

        
$this->assertCount(1000, $res['context'][0]);
        
$this->assertEquals('Over 1000 items (2000 total), aborting normalization', $res['context'][0]['...']);
    }

    
/**
     * @expectedException RuntimeException
     */
    
public function testThrowsOnInvalidEncoding()
    {
        if (
version_compare(PHP_VERSION, '5.5.0', '<')) {
            
// Ignore the warning that will be emitted by PHP <5.5.0
            
PHPUnit_Framework_Error_Warning::$enabled = false;
        }
        
$formatter = new NormalizerFormatter();
        
$reflMethod = new ReflectionMethod($formatter, 'toJson');
        
$reflMethod->setAccessible(true);

        
// send an invalid unicode sequence as a object that can't be cleaned
        
$record = new stdClass;
        
$record->message = "xB1x31";
        
$res = $reflMethod->invoke($formatter, $record);
        if (
PHP_VERSION_ID < 50500 && $res === '{"message":null}') {
            throw new 
RuntimeException('PHP 5.3/5.4 throw a warning and null the value instead of returning false entirely');
        }
    }

    public function 
testConvertsInvalidEncodingAsLatin9()
    {
        if (
version_compare(PHP_VERSION, '5.5.0', '<')) {
            
// Ignore the warning that will be emitted by PHP <5.5.0
            
PHPUnit_Framework_Error_Warning::$enabled = false;
        }
        
$formatter = new NormalizerFormatter();
        
$reflMethod = new ReflectionMethod($formatter, 'toJson');
        
$reflMethod->setAccessible(true);

        
$res = $reflMethod->invoke($formatter, array('message' => "xA4xA6xA8xB4xB8xBCxBDxBE"));

        if (
version_compare(PHP_VERSION, '5.5.0', '>=')) {
            
$this->assertSame('{"message":"€ŠšŽžŒœŸ"}', $res);
        } else {
            
// PHP <5.5 does not return false for an element encoding failure,
            // instead it emits a warning (possibly) and nulls the value.
            
$this->assertSame('{"message":null}', $res);
        }
    }

    
/**
     * @param mixed $in     Input
     * @param mixed $expect Expected output
     * @covers MonologFormatterNormalizerFormatter::detectAndCleanUtf8
     * @dataProvider providesDetectAndCleanUtf8
     */
    
public function testDetectAndCleanUtf8($in, $expect)
    {
        
$formatter = new NormalizerFormatter();
        
$formatter->detectAndCleanUtf8($in);
        
$this->assertSame($expect, $in);
    }

    public function 
providesDetectAndCleanUtf8()
    {
        
$obj = new stdClass;

        return array(
            
'null' => array(null, null),
            
'int' => array(123, 123),
            
'float' => array(123.45, 123.45),
            
'bool false' => array(false, false),
            
'bool true' => array(true, true),
            
'ascii string' => array('abcdef', 'abcdef'),
            
'latin9 string' => array("xB1x31xA4xA6xA8xB4xB8xBCxBDxBExFF", '±1€ŠšŽžŒœŸÿ'),
            
'unicode string' => array('¤¦¨´¸¼½¾€ŠšŽžŒœŸ', '¤¦¨´¸¼½¾€ŠšŽžŒœŸ'),
            
'empty array' => array(array(), array()),
            
'array' => array(array('abcdef'), array('abcdef')),
            
'object' => array($obj, $obj),
        );
    }

    
/**
     * @param int    $code
     * @param string $msg
     * @dataProvider providesHandleJsonErrorFailure
     */
    
public function testHandleJsonErrorFailure($code, $msg)
    {
        
$formatter = new NormalizerFormatter();
        
$reflMethod = new ReflectionMethod($formatter, 'handleJsonError');
        
$reflMethod->setAccessible(true);

        
$this->setExpectedException('RuntimeException', $msg);
        
$reflMethod->invoke($formatter, $code, 'faked');
    }

    public function 
providesHandleJsonErrorFailure()
    {
        return array(
            
'depth' => array(JSON_ERROR_DEPTH, 'Maximum stack depth exceeded'),
            
'state' => array(JSON_ERROR_STATE_MISMATCH, 'Underflow or the modes mismatch'),
            
'ctrl' => array(JSON_ERROR_CTRL_CHAR, 'Unexpected control character found'),
            
'default' => array(-1, 'Unknown error'),
        );
    }

    public function 
testExceptionTraceWithArgs()
    {
        if (
defined('HHVM_VERSION')) {
            
$this->markTestSkipped('Not supported in HHVM since it detects errors differently');
        }

        
// This happens i.e. in React promises or Guzzle streams where stream wrappers are registered
        // and no file or line are included in the trace because it's treated as internal function
        
set_error_handler(function ($errno, $errstr, $errfile, $errline) {
            throw new 
ErrorException($errstr, 0, $errno, $errfile, $errline);
        });

        try {
            
// This will contain $resource and $wrappedResource as arguments in the trace item
            
$resource = fopen('php://memory', 'rw+');
            
fwrite($resource, 'test_resource');
            
$wrappedResource = new TestFooNorm;
            
$wrappedResource->foo = $resource;
            
// Just do something stupid with a resource/wrapped resource as argument
            
array_keys($wrappedResource);
        } catch (
Exception $e) {
            
restore_error_handler();
        }

        
$formatter = new NormalizerFormatter();
        
$record = array('context' => array('exception' => $e));
        
$result = $formatter->format($record);

        
$this->assertRegExp(
            
'%"resource":"[resource] (stream)"%',
            
$result['context']['exception']['trace'][0]
        );

        if (
version_compare(PHP_VERSION, '5.5.0', '>=')) {
            
$pattern = '%"wrappedResource":"[object] (Monolog\\\\Formatter\\\\TestFooNorm: )"%';
        } else {
            
$pattern = '%\\"foo\\":null%';
        }

        
// Tests that the wrapped resource is ignored while encoding, only works for PHP <= 5.4
        
$this->assertRegExp(
            
$pattern,
            
$result['context']['exception']['trace'][0]
        );
    }
}

class 
TestFooNorm
{
    public 
$foo = 'foo';
}

class 
TestBarNorm
{
    public function 
__toString()
    {
        return 
'bar';
    }
}

class 
TestStreamFoo
{
    public 
$foo;
    public 
$resource;

    public function 
__construct($resource)
    {
        
$this->resource = $resource;
        
$this->foo = 'BAR';
    }

    public function 
__toString()
    {
        
fseek($this->resource, 0);

        return 
$this->foo . ' - ' . (string) stream_get_contents($this->resource);
    }
}

class 
TestToStringError
{
    public function 
__toString()
    {
        throw new 
RuntimeException('Could not convert to string');
    }
}
Онлайн: 0
Реклама