Chris@0: Chris@0: * Chris@0: * For the full copyright and license information, please view the LICENSE Chris@0: * file that was distributed with this source code. Chris@0: */ Chris@0: Chris@0: namespace Symfony\Component\VarDumper\Tests\Dumper; Chris@0: Chris@0: use PHPUnit\Framework\TestCase; Chris@0: use Symfony\Component\VarDumper\Cloner\VarCloner; Chris@0: use Symfony\Component\VarDumper\Dumper\CliDumper; Chris@0: use Symfony\Component\VarDumper\Test\VarDumperTestTrait; Chris@0: use Twig\Environment; Chris@0: use Twig\Loader\FilesystemLoader; Chris@0: Chris@0: /** Chris@0: * @author Nicolas Grekas Chris@0: */ Chris@0: class CliDumperTest extends TestCase Chris@0: { Chris@0: use VarDumperTestTrait; Chris@0: Chris@0: public function testGet() Chris@0: { Chris@0: require __DIR__.'/../Fixtures/dumb-var.php'; Chris@0: Chris@0: $dumper = new CliDumper('php://output'); Chris@0: $dumper->setColors(false); Chris@0: $cloner = new VarCloner(); Chris@17: $cloner->addCasters([ Chris@0: ':stream' => function ($res, $a) { Chris@0: unset($a['uri'], $a['wrapper_data']); Chris@0: Chris@0: return $a; Chris@0: }, Chris@17: ]); Chris@0: $data = $cloner->cloneVar($var); Chris@0: Chris@0: ob_start(); Chris@0: $dumper->dump($data); Chris@0: $out = ob_get_clean(); Chris@0: $out = preg_replace('/[ \t]+$/m', '', $out); Chris@0: $intMax = PHP_INT_MAX; Chris@0: $res = (int) $var['res']; Chris@0: Chris@17: $r = \defined('HHVM_VERSION') ? '' : '#%d'; Chris@0: $this->assertStringMatchesFormat( Chris@0: << 1 Chris@0: 0 => &1 null Chris@0: "const" => 1.1 Chris@0: 1 => true Chris@0: 2 => false Chris@0: 3 => NAN Chris@0: 4 => INF Chris@0: 5 => -INF Chris@0: 6 => {$intMax} Chris@0: "str" => "déjà\\n" Chris@0: 7 => b"é\\x00" Chris@0: "[]" => [] Chris@0: "res" => stream resource {@{$res} Chris@0: %A wrapper_type: "plainfile" Chris@0: stream_type: "STDIO" Chris@0: mode: "r" Chris@0: unread_bytes: 0 Chris@0: seekable: true Chris@0: %A options: [] Chris@0: } Chris@0: "obj" => Symfony\Component\VarDumper\Tests\Fixture\DumbFoo {#%d Chris@0: +foo: "foo" Chris@0: +"bar": "bar" Chris@0: } Chris@0: "closure" => Closure {{$r} Chris@0: class: "Symfony\Component\VarDumper\Tests\Dumper\CliDumperTest" Chris@0: this: Symfony\Component\VarDumper\Tests\Dumper\CliDumperTest {{$r} …} Chris@0: parameters: { Chris@0: \$a: {} Chris@0: &\$b: { Chris@0: typeHint: "PDO" Chris@0: default: null Chris@0: } Chris@0: } Chris@12: file: "%s%eTests%eFixtures%edumb-var.php" Chris@0: line: "{$var['line']} to {$var['line']}" Chris@0: } Chris@0: "line" => {$var['line']} Chris@0: "nobj" => array:1 [ Chris@0: 0 => &3 {#%d} Chris@0: ] Chris@0: "recurs" => &4 array:1 [ Chris@0: 0 => &4 array:1 [&4] Chris@0: ] Chris@0: 8 => &1 null Chris@0: "sobj" => Symfony\Component\VarDumper\Tests\Fixture\DumbFoo {#%d} Chris@0: "snobj" => &3 {#%d} Chris@0: "snobj2" => {#%d} Chris@0: "file" => "{$var['file']}" Chris@0: b"bin-key-é" => "" Chris@0: ] Chris@0: Chris@0: EOTXT Chris@0: , Chris@0: $out Chris@0: ); Chris@0: } Chris@0: Chris@0: /** Chris@0: * @dataProvider provideDumpWithCommaFlagTests Chris@0: */ Chris@0: public function testDumpWithCommaFlag($expected, $flags) Chris@0: { Chris@0: $dumper = new CliDumper(null, null, $flags); Chris@0: $dumper->setColors(false); Chris@0: $cloner = new VarCloner(); Chris@0: Chris@17: $var = [ Chris@17: 'array' => ['a', 'b'], Chris@0: 'string' => 'hello', Chris@0: 'multiline string' => "this\nis\na\multiline\nstring", Chris@17: ]; Chris@0: Chris@0: $dump = $dumper->dump($cloner->cloneVar($var), true); Chris@0: Chris@0: $this->assertSame($expected, $dump); Chris@0: } Chris@0: Chris@0: public function testDumpWithCommaFlagsAndExceptionCodeExcerpt() Chris@0: { Chris@0: $dumper = new CliDumper(null, null, CliDumper::DUMP_TRAILING_COMMA); Chris@0: $dumper->setColors(false); Chris@0: $cloner = new VarCloner(); Chris@0: Chris@0: $ex = new \RuntimeException('foo'); Chris@0: Chris@0: $dump = $dumper->dump($cloner->cloneVar($ex)->withRefHandles(false), true); Chris@0: Chris@0: $this->assertStringMatchesFormat(<<<'EOTXT' Chris@0: RuntimeException { Chris@0: #message: "foo" Chris@0: #code: 0 Chris@0: #file: "%ACliDumperTest.php" Chris@0: #line: %d Chris@0: trace: { Chris@12: %ACliDumperTest.php:%d { Chris@12: › Chris@12: › $ex = new \RuntimeException('foo'); Chris@12: › Chris@0: } Chris@0: %A Chris@0: } Chris@0: } Chris@0: Chris@0: EOTXT Chris@0: , $dump); Chris@0: } Chris@0: Chris@0: public function provideDumpWithCommaFlagTests() Chris@0: { Chris@0: $expected = <<<'EOTXT' Chris@0: array:3 [ Chris@0: "array" => array:2 [ Chris@0: 0 => "a", Chris@0: 1 => "b" Chris@0: ], Chris@0: "string" => "hello", Chris@0: "multiline string" => """ Chris@0: this\n Chris@0: is\n Chris@0: a\multiline\n Chris@0: string Chris@0: """ Chris@0: ] Chris@0: Chris@0: EOTXT; Chris@0: Chris@17: yield [$expected, CliDumper::DUMP_COMMA_SEPARATOR]; Chris@0: Chris@0: $expected = <<<'EOTXT' Chris@0: array:3 [ Chris@0: "array" => array:2 [ Chris@0: 0 => "a", Chris@0: 1 => "b", Chris@0: ], Chris@0: "string" => "hello", Chris@0: "multiline string" => """ Chris@0: this\n Chris@0: is\n Chris@0: a\multiline\n Chris@0: string Chris@0: """, Chris@0: ] Chris@0: Chris@0: EOTXT; Chris@0: Chris@17: yield [$expected, CliDumper::DUMP_TRAILING_COMMA]; Chris@0: } Chris@0: Chris@0: /** Chris@0: * @requires extension xml Chris@0: */ Chris@0: public function testXmlResource() Chris@0: { Chris@0: $var = xml_parser_create(); Chris@0: Chris@0: $this->assertDumpMatchesFormat( Chris@0: <<<'EOTXT' Chris@0: xml resource { Chris@0: current_byte_index: %i Chris@0: current_column_number: %i Chris@0: current_line_number: 1 Chris@0: error_code: XML_ERROR_NONE Chris@0: } Chris@0: EOTXT Chris@0: , Chris@0: $var Chris@0: ); Chris@0: } Chris@0: Chris@0: public function testJsonCast() Chris@0: { Chris@0: $var = (array) json_decode('{"0":{},"1":null}'); Chris@0: foreach ($var as &$v) { Chris@0: } Chris@0: $var[] = &$v; Chris@0: $var[''] = 2; Chris@0: Chris@0: if (\PHP_VERSION_ID >= 70200) { Chris@0: $this->assertDumpMatchesFormat( Chris@0: <<<'EOTXT' Chris@0: array:4 [ Chris@0: 0 => {} Chris@0: 1 => &1 null Chris@0: 2 => &1 null Chris@0: "" => 2 Chris@0: ] Chris@0: EOTXT Chris@0: , Chris@0: $var Chris@0: ); Chris@0: } else { Chris@0: $this->assertDumpMatchesFormat( Chris@0: <<<'EOTXT' Chris@0: array:4 [ Chris@0: "0" => {} Chris@0: "1" => &1 null Chris@0: 0 => &1 null Chris@0: "" => 2 Chris@0: ] Chris@0: EOTXT Chris@0: , Chris@0: $var Chris@0: ); Chris@0: } Chris@0: } Chris@0: Chris@0: public function testObjectCast() Chris@0: { Chris@17: $var = (object) [1 => 1]; Chris@0: $var->{1} = 2; Chris@0: Chris@0: if (\PHP_VERSION_ID >= 70200) { Chris@0: $this->assertDumpMatchesFormat( Chris@0: <<<'EOTXT' Chris@0: { Chris@0: +"1": 2 Chris@0: } Chris@0: EOTXT Chris@0: , Chris@0: $var Chris@0: ); Chris@0: } else { Chris@0: $this->assertDumpMatchesFormat( Chris@0: <<<'EOTXT' Chris@0: { Chris@0: +1: 1 Chris@0: +"1": 2 Chris@0: } Chris@0: EOTXT Chris@0: , Chris@0: $var Chris@0: ); Chris@0: } Chris@0: } Chris@0: Chris@0: public function testClosedResource() Chris@0: { Chris@17: if (\defined('HHVM_VERSION') && HHVM_VERSION_ID < 30600) { Chris@0: $this->markTestSkipped(); Chris@0: } Chris@0: Chris@0: $var = fopen(__FILE__, 'r'); Chris@0: fclose($var); Chris@0: Chris@0: $dumper = new CliDumper('php://output'); Chris@0: $dumper->setColors(false); Chris@0: $cloner = new VarCloner(); Chris@0: $data = $cloner->cloneVar($var); Chris@0: Chris@0: ob_start(); Chris@0: $dumper->dump($data); Chris@0: $out = ob_get_clean(); Chris@0: $res = (int) $var; Chris@0: Chris@0: $this->assertStringMatchesFormat( Chris@0: << 'bar'], Chris@17: ]; Chris@0: Chris@0: $this->assertDumpEquals( Chris@0: << (3) "foo" Chris@0: 2 => (3) "bar" Chris@0: ] Chris@0: ] Chris@0: EOTXT Chris@0: , Chris@0: $var Chris@0: ); Chris@0: Chris@0: putenv('DUMP_LIGHT_ARRAY='); Chris@0: putenv('DUMP_STRING_LENGTH='); Chris@0: } Chris@0: Chris@0: /** Chris@0: * @requires function Twig\Template::getSourceContext Chris@0: */ Chris@0: public function testThrowingCaster() Chris@0: { Chris@0: $out = fopen('php://memory', 'r+b'); Chris@0: Chris@0: require_once __DIR__.'/../Fixtures/Twig.php'; Chris@0: $twig = new \__TwigTemplate_VarDumperFixture_u75a09(new Environment(new FilesystemLoader())); Chris@0: Chris@0: $dumper = new CliDumper(); Chris@0: $dumper->setColors(false); Chris@0: $cloner = new VarCloner(); Chris@17: $cloner->addCasters([ Chris@0: ':stream' => function ($res, $a) { Chris@0: unset($a['wrapper_data']); Chris@0: Chris@0: return $a; Chris@0: }, Chris@17: ]); Chris@17: $cloner->addCasters([ Chris@0: ':stream' => eval('return function () use ($twig) { Chris@0: try { Chris@17: $twig->render([]); Chris@0: } catch (\Twig\Error\RuntimeError $e) { Chris@0: throw $e->getPrevious(); Chris@0: } Chris@0: };'), Chris@17: ]); Chris@0: $ref = (int) $out; Chris@0: Chris@0: $data = $cloner->cloneVar($out); Chris@0: $dumper->dump($data, $out); Chris@0: $out = stream_get_contents($out, -1, 0); Chris@0: Chris@17: $r = \defined('HHVM_VERSION') ? '' : '#%d'; Chris@0: $this->assertStringMatchesFormat( Chris@0: << 'foo']; Chris@0: $var->bar = &$var->foo; Chris@0: Chris@0: $dumper = new CliDumper(); Chris@0: $dumper->setColors(false); Chris@0: $cloner = new VarCloner(); Chris@0: Chris@0: $data = $cloner->cloneVar($var); Chris@0: $out = $dumper->dump($data, true); Chris@0: Chris@17: $r = \defined('HHVM_VERSION') ? '' : '#%d'; Chris@0: $this->assertStringMatchesFormat( Chris@0: <<getSpecialVars(); Chris@0: Chris@0: $this->assertDumpEquals( Chris@0: <<<'EOTXT' Chris@0: array:3 [ Chris@0: 0 => array:1 [ Chris@0: 0 => &1 array:1 [ Chris@0: 0 => &1 array:1 [&1] Chris@0: ] Chris@0: ] Chris@0: 1 => array:1 [ Chris@0: "GLOBALS" => &2 array:1 [ Chris@0: "GLOBALS" => &2 array:1 [&2] Chris@0: ] Chris@0: ] Chris@0: 2 => &2 array:1 [&2] Chris@0: ] Chris@0: EOTXT Chris@0: , Chris@0: $var Chris@0: ); Chris@0: } Chris@0: Chris@0: /** Chris@0: * @runInSeparateProcess Chris@0: * @preserveGlobalState disabled Chris@0: */ Chris@0: public function testGlobalsNoExt() Chris@0: { Chris@0: $var = $this->getSpecialVars(); Chris@0: unset($var[0]); Chris@0: $out = ''; Chris@0: Chris@0: $dumper = new CliDumper(function ($line, $depth) use (&$out) { Chris@0: if ($depth >= 0) { Chris@0: $out .= str_repeat(' ', $depth).$line."\n"; Chris@0: } Chris@0: }); Chris@0: $dumper->setColors(false); Chris@0: $cloner = new VarCloner(); Chris@0: Chris@0: $refl = new \ReflectionProperty($cloner, 'useExt'); Chris@0: $refl->setAccessible(true); Chris@0: $refl->setValue($cloner, false); Chris@0: Chris@0: $data = $cloner->cloneVar($var); Chris@0: $dumper->dump($data); Chris@0: Chris@0: $this->assertSame( Chris@0: <<<'EOTXT' Chris@0: array:2 [ Chris@0: 1 => array:1 [ Chris@0: "GLOBALS" => &1 array:1 [ Chris@0: "GLOBALS" => &1 array:1 [&1] Chris@0: ] Chris@0: ] Chris@0: 2 => &1 array:1 [&1] Chris@0: ] Chris@0: Chris@0: EOTXT Chris@0: , Chris@0: $out Chris@0: ); Chris@0: } Chris@0: Chris@0: /** Chris@0: * @runInSeparateProcess Chris@0: * @preserveGlobalState disabled Chris@0: */ Chris@0: public function testBuggyRefs() Chris@0: { Chris@0: if (\PHP_VERSION_ID >= 50600) { Chris@0: $this->markTestSkipped('PHP 5.6 fixed refs counting'); Chris@0: } Chris@0: Chris@0: $var = $this->getSpecialVars(); Chris@0: $var = $var[0]; Chris@0: Chris@0: $dumper = new CliDumper(); Chris@0: $dumper->setColors(false); Chris@0: $cloner = new VarCloner(); Chris@0: Chris@0: $data = $cloner->cloneVar($var)->withMaxDepth(3); Chris@0: $out = ''; Chris@0: $dumper->dump($data, function ($line, $depth) use (&$out) { Chris@0: if ($depth >= 0) { Chris@0: $out .= str_repeat(' ', $depth).$line."\n"; Chris@0: } Chris@0: }); Chris@0: Chris@0: $this->assertSame( Chris@0: <<<'EOTXT' Chris@0: array:1 [ Chris@0: 0 => array:1 [ Chris@0: 0 => array:1 [ Chris@0: 0 => array:1 [ …1] Chris@0: ] Chris@0: ] Chris@0: ] Chris@0: Chris@0: EOTXT Chris@0: , Chris@0: $out Chris@0: ); Chris@0: } Chris@0: Chris@0: public function testIncompleteClass() Chris@0: { Chris@0: $unserializeCallbackHandler = ini_set('unserialize_callback_func', null); Chris@0: $var = unserialize('O:8:"Foo\Buzz":0:{}'); Chris@0: ini_set('unserialize_callback_func', $unserializeCallbackHandler); Chris@0: Chris@0: $this->assertDumpMatchesFormat( Chris@0: <<