ILIAS  release_5-2 Revision v5.2.25-18-g3f80b828510
NormalizerFormatterTest.php
Go to the documentation of this file.
1 <?php
2 
3 /*
4  * This file is part of the Monolog package.
5  *
6  * (c) Jordi Boggiano <j.boggiano@seld.be>
7  *
8  * For the full copyright and license information, please view the LICENSE
9  * file that was distributed with this source code.
10  */
11 
12 namespace Monolog\Formatter;
13 
18 {
19  public function tearDown()
20  {
21  \PHPUnit_Framework_Error_Warning::$enabled = true;
22 
23  return parent::tearDown();
24  }
25 
26  public function testFormat()
27  {
28  $formatter = new NormalizerFormatter('Y-m-d');
29  $formatted = $formatter->format(array(
30  'level_name' => 'ERROR',
31  'channel' => 'meh',
32  'message' => 'foo',
33  'datetime' => new \DateTime,
34  'extra' => array('foo' => new TestFooNorm, 'bar' => new TestBarNorm, 'baz' => array(), 'res' => fopen('php://memory', 'rb')),
35  'context' => array(
36  'foo' => 'bar',
37  'baz' => 'qux',
38  'inf' => INF,
39  '-inf' => -INF,
40  'nan' => acos(4),
41  ),
42  ));
43 
44  $this->assertEquals(array(
45  'level_name' => 'ERROR',
46  'channel' => 'meh',
47  'message' => 'foo',
48  'datetime' => date('Y-m-d'),
49  'extra' => array(
50  'foo' => '[object] (Monolog\\Formatter\\TestFooNorm: {"foo":"foo"})',
51  'bar' => '[object] (Monolog\\Formatter\\TestBarNorm: bar)',
52  'baz' => array(),
53  'res' => '[resource] (stream)',
54  ),
55  'context' => array(
56  'foo' => 'bar',
57  'baz' => 'qux',
58  'inf' => 'INF',
59  '-inf' => '-INF',
60  'nan' => 'NaN',
61  ),
62  ), $formatted);
63  }
64 
65  public function testFormatExceptions()
66  {
67  $formatter = new NormalizerFormatter('Y-m-d');
68  $e = new \LogicException('bar');
69  $e2 = new \RuntimeException('foo', 0, $e);
70  $formatted = $formatter->format(array(
71  'exception' => $e2,
72  ));
73 
74  $this->assertGreaterThan(5, count($formatted['exception']['trace']));
75  $this->assertTrue(isset($formatted['exception']['previous']));
76  unset($formatted['exception']['trace'], $formatted['exception']['previous']);
77 
78  $this->assertEquals(array(
79  'exception' => array(
80  'class' => get_class($e2),
81  'message' => $e2->getMessage(),
82  'code' => $e2->getCode(),
83  'file' => $e2->getFile().':'.$e2->getLine(),
84  ),
85  ), $formatted);
86  }
87 
88  public function testFormatSoapFaultException()
89  {
90  if (!class_exists('SoapFault')) {
91  $this->markTestSkipped('Requires the soap extension');
92  }
93 
94  $formatter = new NormalizerFormatter('Y-m-d');
95  $e = new \SoapFault('foo', 'bar', 'hello', 'world');
96  $formatted = $formatter->format(array(
97  'exception' => $e,
98  ));
99 
100  unset($formatted['exception']['trace']);
101 
102  $this->assertEquals(array(
103  'exception' => array(
104  'class' => 'SoapFault',
105  'message' => 'bar',
106  'code' => 0,
107  'file' => $e->getFile().':'.$e->getLine(),
108  'faultcode' => 'foo',
109  'faultactor' => 'hello',
110  'detail' => 'world',
111  ),
112  ), $formatted);
113  }
114 
116  {
117  $formatter = new NormalizerFormatter('Y-m-d');
118  $this->setExpectedException('RuntimeException', 'Could not convert to string');
119  $formatter->format(array(
120  'myObject' => new TestToStringError(),
121  ));
122  }
123 
124  public function testBatchFormat()
125  {
126  $formatter = new NormalizerFormatter('Y-m-d');
127  $formatted = $formatter->formatBatch(array(
128  array(
129  'level_name' => 'CRITICAL',
130  'channel' => 'test',
131  'message' => 'bar',
132  'context' => array(),
133  'datetime' => new \DateTime,
134  'extra' => array(),
135  ),
136  array(
137  'level_name' => 'WARNING',
138  'channel' => 'log',
139  'message' => 'foo',
140  'context' => array(),
141  'datetime' => new \DateTime,
142  'extra' => array(),
143  ),
144  ));
145  $this->assertEquals(array(
146  array(
147  'level_name' => 'CRITICAL',
148  'channel' => 'test',
149  'message' => 'bar',
150  'context' => array(),
151  'datetime' => date('Y-m-d'),
152  'extra' => array(),
153  ),
154  array(
155  'level_name' => 'WARNING',
156  'channel' => 'log',
157  'message' => 'foo',
158  'context' => array(),
159  'datetime' => date('Y-m-d'),
160  'extra' => array(),
161  ),
162  ), $formatted);
163  }
164 
169  {
170  // set up the recursion
171  $foo = new \stdClass();
172  $bar = new \stdClass();
173 
174  $foo->bar = $bar;
175  $bar->foo = $foo;
176 
177  // set an error handler to assert that the error is not raised anymore
178  $that = $this;
179  set_error_handler(function ($level, $message, $file, $line, $context) use ($that) {
180  if (error_reporting() & $level) {
181  restore_error_handler();
182  $that->fail("$message should not be raised");
183  }
184  });
185 
186  $formatter = new NormalizerFormatter();
187  $reflMethod = new \ReflectionMethod($formatter, 'toJson');
188  $reflMethod->setAccessible(true);
189  $res = $reflMethod->invoke($formatter, array($foo, $bar), true);
190 
191  restore_error_handler();
192 
193  $this->assertEquals(@json_encode(array($foo, $bar)), $res);
194  }
195 
196  public function testIgnoresInvalidTypes()
197  {
198  // set up the recursion
199  $resource = fopen(__FILE__, 'r');
200 
201  // set an error handler to assert that the error is not raised anymore
202  $that = $this;
203  set_error_handler(function ($level, $message, $file, $line, $context) use ($that) {
204  if (error_reporting() & $level) {
205  restore_error_handler();
206  $that->fail("$message should not be raised");
207  }
208  });
209 
210  $formatter = new NormalizerFormatter();
211  $reflMethod = new \ReflectionMethod($formatter, 'toJson');
212  $reflMethod->setAccessible(true);
213  $res = $reflMethod->invoke($formatter, array($resource), true);
214 
215  restore_error_handler();
216 
217  $this->assertEquals(@json_encode(array($resource)), $res);
218  }
219 
223  public function testThrowsOnInvalidEncoding()
224  {
225  if (version_compare(PHP_VERSION, '5.5.0', '<')) {
226  // Ignore the warning that will be emitted by PHP <5.5.0
227  \PHPUnit_Framework_Error_Warning::$enabled = false;
228  }
229  $formatter = new NormalizerFormatter();
230  $reflMethod = new \ReflectionMethod($formatter, 'toJson');
231  $reflMethod->setAccessible(true);
232 
233  // send an invalid unicode sequence as a object that can't be cleaned
234  $record = new \stdClass;
235  $record->message = "\xB1\x31";
236  $res = $reflMethod->invoke($formatter, $record);
237  if (PHP_VERSION_ID < 50500 && $res === '{"message":null}') {
238  throw new \RuntimeException('PHP 5.3/5.4 throw a warning and null the value instead of returning false entirely');
239  }
240  }
241 
243  {
244  if (version_compare(PHP_VERSION, '5.5.0', '<')) {
245  // Ignore the warning that will be emitted by PHP <5.5.0
246  \PHPUnit_Framework_Error_Warning::$enabled = false;
247  }
248  $formatter = new NormalizerFormatter();
249  $reflMethod = new \ReflectionMethod($formatter, 'toJson');
250  $reflMethod->setAccessible(true);
251 
252  $res = $reflMethod->invoke($formatter, array('message' => "\xA4\xA6\xA8\xB4\xB8\xBC\xBD\xBE"));
253 
254  if (version_compare(PHP_VERSION, '5.5.0', '>=')) {
255  $this->assertSame('{"message":"€ŠšŽžŒœŸ"}', $res);
256  } else {
257  // PHP <5.5 does not return false for an element encoding failure,
258  // instead it emits a warning (possibly) and nulls the value.
259  $this->assertSame('{"message":null}', $res);
260  }
261  }
262 
269  public function testDetectAndCleanUtf8($in, $expect)
270  {
271  $formatter = new NormalizerFormatter();
272  $formatter->detectAndCleanUtf8($in);
273  $this->assertSame($expect, $in);
274  }
275 
276  public function providesDetectAndCleanUtf8()
277  {
278  $obj = new \stdClass;
279 
280  return array(
281  'null' => array(null, null),
282  'int' => array(123, 123),
283  'float' => array(123.45, 123.45),
284  'bool false' => array(false, false),
285  'bool true' => array(true, true),
286  'ascii string' => array('abcdef', 'abcdef'),
287  'latin9 string' => array("\xB1\x31\xA4\xA6\xA8\xB4\xB8\xBC\xBD\xBE\xFF", '±1€ŠšŽžŒœŸÿ'),
288  'unicode string' => array('¤¦¨´¸¼½¾€ŠšŽžŒœŸ', '¤¦¨´¸¼½¾€ŠšŽžŒœŸ'),
289  'empty array' => array(array(), array()),
290  'array' => array(array('abcdef'), array('abcdef')),
291  'object' => array($obj, $obj),
292  );
293  }
294 
300  public function testHandleJsonErrorFailure($code, $msg)
301  {
302  $formatter = new NormalizerFormatter();
303  $reflMethod = new \ReflectionMethod($formatter, 'handleJsonError');
304  $reflMethod->setAccessible(true);
305 
306  $this->setExpectedException('RuntimeException', $msg);
307  $reflMethod->invoke($formatter, $code, 'faked');
308  }
309 
311  {
312  return array(
313  'depth' => array(JSON_ERROR_DEPTH, 'Maximum stack depth exceeded'),
314  'state' => array(JSON_ERROR_STATE_MISMATCH, 'Underflow or the modes mismatch'),
315  'ctrl' => array(JSON_ERROR_CTRL_CHAR, 'Unexpected control character found'),
316  'default' => array(-1, 'Unknown error'),
317  );
318  }
319 
320  public function testExceptionTraceWithArgs()
321  {
322  if (defined('HHVM_VERSION')) {
323  $this->markTestSkipped('Not supported in HHVM since it detects errors differently');
324  }
325 
326  // This happens i.e. in React promises or Guzzle streams where stream wrappers are registered
327  // and no file or line are included in the trace because it's treated as internal function
328  set_error_handler(function ($errno, $errstr, $errfile, $errline) {
329  throw new \ErrorException($errstr, 0, $errno, $errfile, $errline);
330  });
331 
332  try {
333  // This will contain $resource and $wrappedResource as arguments in the trace item
334  $resource = fopen('php://memory', 'rw+');
335  fwrite($resource, 'test_resource');
336  $wrappedResource = new TestFooNorm;
337  $wrappedResource->foo = $resource;
338  // Just do something stupid with a resource/wrapped resource as argument
339  array_keys($wrappedResource);
340  } catch (\Exception $e) {
341  restore_error_handler();
342  }
343 
344  $formatter = new NormalizerFormatter();
345  $record = array('context' => array('exception' => $e));
346  $result = $formatter->format($record);
347 
348  $this->assertRegExp(
349  '%"resource":"\[resource\] \(stream\)"%',
350  $result['context']['exception']['trace'][0]
351  );
352 
353  if (version_compare(PHP_VERSION, '5.5.0', '>=')) {
354  $pattern = '%"wrappedResource":"\[object\] \(Monolog\\\\\\\\Formatter\\\\\\\\TestFooNorm: \)"%';
355  } else {
356  $pattern = '%\\\\"foo\\\\":null%';
357  }
358 
359  // Tests that the wrapped resource is ignored while encoding, only works for PHP <= 5.4
360  $this->assertRegExp(
361  $pattern,
362  $result['context']['exception']['trace'][0]
363  );
364  }
365 }
366 
368 {
369  public $foo = 'foo';
370 }
371 
373 {
374  public function __toString()
375  {
376  return 'bar';
377  }
378 }
379 
381 {
382  public $foo;
383  public $resource;
384 
385  public function __construct($resource)
386  {
387  $this->resource = $resource;
388  $this->foo = 'BAR';
389  }
390 
391  public function __toString()
392  {
393  fseek($this->resource, 0);
394 
395  return $this->foo . ' - ' . (string) stream_get_contents($this->resource);
396  }
397 }
398 
400 {
401  public function __toString()
402  {
403  throw new \RuntimeException('Could not convert to string');
404  }
405 }
$result
$code
Definition: example_050.php:99
Add rich text string
The name of the decorator.
date( 'd-M-Y', $objPHPExcel->getProperties() ->getCreated())
Normalizes incoming records to remove objects/resources so it&#39;s easier to dump to various targets...
Create styles array
The data for the language used.
if(php_sapi_name() !='cli') $in
Definition: Utf8Test.php:37
if(!file_exists("$old.txt")) if($old===$new) if(file_exists("$new.txt")) $file
defined( 'APPLICATION_ENV')||define( 'APPLICATION_ENV'
Definition: bootstrap.php:27