Skip to content

Commit

Permalink
bug #30660 [Bridge][Twig] DebugCommand - fix escaping and filter (Spa…
Browse files Browse the repository at this point in the history
…cePossum)

This PR was squashed before being merged into the 3.4 branch (closes #30660).

Discussion
----------

[Bridge][Twig] DebugCommand - fix escaping and filter

| Q             | A
| ------------- | ---
| Branch?       | 3.4
| Bug fix?      | yes
| New feature?  | no
| BC breaks?    | no
| Deprecations? | no
| Tests pass?   | yes
| License       | MIT

The PR fixes:
- output escaping was not done for decorated consoles
- filter was not applied when using format json

+ added some tests for paths currently not tested

Commits
-------

7bdb066 [Bridge][Twig] DebugCommand - fix escaping and filter
  • Loading branch information
fabpot committed Mar 31, 2019
2 parents e3bbf8d + 7bdb066 commit 6f08630
Show file tree
Hide file tree
Showing 3 changed files with 69 additions and 11 deletions.
28 changes: 19 additions & 9 deletions src/Symfony/Bridge/Twig/Command/DebugCommand.php
Expand Up @@ -12,6 +12,7 @@
namespace Symfony\Bridge\Twig\Command;

use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Formatter\OutputFormatter;
use Symfony\Component\Console\Input\InputArgument;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Input\InputOption;
Expand Down Expand Up @@ -100,6 +101,7 @@ protected function configure()
protected function execute(InputInterface $input, OutputInterface $output)
{
$io = new SymfonyStyle($input, $output);
$decorated = $io->isDecorated();

// BC to be removed in 4.0
if (__CLASS__ !== \get_class($this)) {
Expand All @@ -114,29 +116,35 @@ protected function execute(InputInterface $input, OutputInterface $output)
throw new \RuntimeException('The Twig environment needs to be set.');
}

$filter = $input->getArgument('filter');
$types = ['functions', 'filters', 'tests', 'globals'];

if ('json' === $input->getOption('format')) {
$data = [];
foreach ($types as $type) {
foreach ($this->twig->{'get'.ucfirst($type)}() as $name => $entity) {
$data[$type][$name] = $this->getMetadata($type, $entity);
if (!$filter || false !== strpos($name, $filter)) {
$data[$type][$name] = $this->getMetadata($type, $entity);
}
}
}
$data['tests'] = array_keys($data['tests']);

if (isset($data['tests'])) {
$data['tests'] = array_keys($data['tests']);
}

$data['loader_paths'] = $this->getLoaderPaths();
$io->writeln(json_encode($data));
$data = json_encode($data, JSON_PRETTY_PRINT);
$io->writeln($decorated ? OutputFormatter::escape($data) : $data);

return 0;
}

$filter = $input->getArgument('filter');

foreach ($types as $index => $type) {
$items = [];
foreach ($this->twig->{'get'.ucfirst($type)}() as $name => $entity) {
if (!$filter || false !== strpos($name, $filter)) {
$items[$name] = $name.$this->getPrettyMetadata($type, $entity);
$items[$name] = $name.$this->getPrettyMetadata($type, $entity, $decorated);
}
}

Expand Down Expand Up @@ -262,7 +270,7 @@ private function getMetadata($type, $entity)
}
}

private function getPrettyMetadata($type, $entity)
private function getPrettyMetadata($type, $entity, $decorated)
{
if ('tests' === $type) {
return '';
Expand All @@ -274,15 +282,17 @@ private function getPrettyMetadata($type, $entity)
return '(unknown?)';
}
} catch (\UnexpectedValueException $e) {
return ' <error>'.$e->getMessage().'</error>';
return sprintf(' <error>%s</error>', $decorated ? OutputFormatter::escape($e->getMessage()) : $e->getMessage());
}

if ('globals' === $type) {
if (\is_object($meta)) {
return ' = object('.\get_class($meta).')';
}

return ' = '.substr(@json_encode($meta), 0, 50);
$description = substr(@json_encode($meta), 0, 50);

return sprintf(' = %s', $decorated ? OutputFormatter::escape($description) : $description);
}

if ('functions' === $type) {
Expand Down
48 changes: 46 additions & 2 deletions src/Symfony/Bridge/Twig/Tests/Command/DebugCommandTest.php
Expand Up @@ -62,15 +62,59 @@ public function testLineSeparatorInLoaderPaths()
$this->assertContains($loaderPaths, trim($tester->getDisplay(true)));
}

private function createCommandTester(array $paths = [])
public function testWithGlobals()
{
$message = '<error>foo</error>';
$tester = $this->createCommandTester([], ['message' => $message]);
$tester->execute([], ['decorated' => true]);

$display = $tester->getDisplay();

$this->assertContains(\json_encode($message), $display);
}

public function testWithGlobalsJson()
{
$globals = ['message' => '<error>foo</error>'];

$tester = $this->createCommandTester([], $globals);
$tester->execute(['--format' => 'json'], ['decorated' => true]);

$display = $tester->getDisplay();
$display = \json_decode($display, true);

$this->assertSame($globals, $display['globals']);
}

public function testWithFilter()
{
$tester = $this->createCommandTester([]);
$tester->execute(['--format' => 'json'], ['decorated' => false]);
$display = $tester->getDisplay();
$display1 = \json_decode($display, true);

$tester->execute(['filter' => 'date', '--format' => 'json'], ['decorated' => false]);
$display = $tester->getDisplay();
$display2 = \json_decode($display, true);

$this->assertNotSame($display1, $display2);
}

private function createCommandTester(array $paths = [], array $globals = [])
{
$filesystemLoader = new FilesystemLoader([], \dirname(__DIR__).'/Fixtures');
foreach ($paths as $namespace => $relDirs) {
foreach ($relDirs as $relDir) {
$filesystemLoader->addPath($relDir, $namespace);
}
}
$command = new DebugCommand(new Environment($filesystemLoader));

$environment = new Environment($filesystemLoader);
foreach ($globals as $name => $value) {
$environment->addGlobal($name, $value);
}

$command = new DebugCommand($environment);

$application = new Application();
$application->add($command);
Expand Down
4 changes: 4 additions & 0 deletions src/Symfony/Component/Console/Tester/CommandTester.php
Expand Up @@ -87,6 +87,10 @@ public function execute(array $input, array $options = [])
*/
public function getDisplay($normalize = false)
{
if (null === $this->output) {
throw new \RuntimeException('Output not initialized, did you execute the command before requesting the display?');
}

rewind($this->output->getStream());

$display = stream_get_contents($this->output->getStream());
Expand Down

0 comments on commit 6f08630

Please sign in to comment.