Actualización

This commit is contained in:
Xes
2025-04-10 12:24:57 +02:00
parent 8969cc929d
commit 45420b6f0d
39760 changed files with 4303286 additions and 0 deletions

View File

@@ -0,0 +1,279 @@
<?php
namespace Symfony\Bridge\Twig\Tests;
use PHPUnit\Framework\TestCase;
use Symfony\Bridge\Twig\AppVariable;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Session\Flash\FlashBag;
use Symfony\Component\HttpFoundation\Session\Session;
class AppVariableTest extends TestCase
{
/**
* @var AppVariable
*/
protected $appVariable;
protected function setUp()
{
$this->appVariable = new AppVariable();
}
/**
* @dataProvider debugDataProvider
*/
public function testDebug($debugFlag)
{
$this->appVariable->setDebug($debugFlag);
$this->assertEquals($debugFlag, $this->appVariable->getDebug());
}
public function debugDataProvider()
{
return array(
'debug on' => array(true),
'debug off' => array(false),
);
}
public function testEnvironment()
{
$this->appVariable->setEnvironment('dev');
$this->assertEquals('dev', $this->appVariable->getEnvironment());
}
/**
* @runInSeparateProcess
*/
public function testGetSession()
{
$request = $this->getMockBuilder('Symfony\Component\HttpFoundation\Request')->getMock();
$request->method('getSession')->willReturn($session = new Session());
$this->setRequestStack($request);
$this->assertEquals($session, $this->appVariable->getSession());
}
public function testGetSessionWithNoRequest()
{
$this->setRequestStack(null);
$this->assertNull($this->appVariable->getSession());
}
public function testGetRequest()
{
$this->setRequestStack($request = new Request());
$this->assertEquals($request, $this->appVariable->getRequest());
}
public function testGetToken()
{
$tokenStorage = $this->getMockBuilder('Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorageInterface')->getMock();
$this->appVariable->setTokenStorage($tokenStorage);
$token = $this->getMockBuilder('Symfony\Component\Security\Core\Authentication\Token\TokenInterface')->getMock();
$tokenStorage->method('getToken')->willReturn($token);
$this->assertEquals($token, $this->appVariable->getToken());
}
public function testGetUser()
{
$this->setTokenStorage($user = $this->getMockBuilder('Symfony\Component\Security\Core\User\UserInterface')->getMock());
$this->assertEquals($user, $this->appVariable->getUser());
}
public function testGetUserWithUsernameAsTokenUser()
{
$this->setTokenStorage($user = 'username');
$this->assertNull($this->appVariable->getUser());
}
public function testGetTokenWithNoToken()
{
$tokenStorage = $this->getMockBuilder('Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorageInterface')->getMock();
$this->appVariable->setTokenStorage($tokenStorage);
$this->assertNull($this->appVariable->getToken());
}
public function testGetUserWithNoToken()
{
$tokenStorage = $this->getMockBuilder('Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorageInterface')->getMock();
$this->appVariable->setTokenStorage($tokenStorage);
$this->assertNull($this->appVariable->getUser());
}
/**
* @expectedException \RuntimeException
*/
public function testEnvironmentNotSet()
{
$this->appVariable->getEnvironment();
}
/**
* @expectedException \RuntimeException
*/
public function testDebugNotSet()
{
$this->appVariable->getDebug();
}
/**
* @expectedException \RuntimeException
*/
public function testGetTokenWithTokenStorageNotSet()
{
$this->appVariable->getToken();
}
/**
* @expectedException \RuntimeException
*/
public function testGetUserWithTokenStorageNotSet()
{
$this->appVariable->getUser();
}
/**
* @expectedException \RuntimeException
*/
public function testGetRequestWithRequestStackNotSet()
{
$this->appVariable->getRequest();
}
/**
* @expectedException \RuntimeException
*/
public function testGetSessionWithRequestStackNotSet()
{
$this->appVariable->getSession();
}
public function testGetFlashesWithNoRequest()
{
$this->setRequestStack(null);
$this->assertEquals(array(), $this->appVariable->getFlashes());
}
/**
* @runInSeparateProcess
*/
public function testGetFlashesWithNoSessionStarted()
{
$request = $this->getMockBuilder('Symfony\Component\HttpFoundation\Request')->getMock();
$request->method('getSession')->willReturn(new Session());
$this->setRequestStack($request);
$this->assertEquals(array(), $this->appVariable->getFlashes());
}
/**
* @runInSeparateProcess
*/
public function testGetFlashes()
{
$flashMessages = $this->setFlashMessages();
$this->assertEquals($flashMessages, $this->appVariable->getFlashes(null));
$flashMessages = $this->setFlashMessages();
$this->assertEquals($flashMessages, $this->appVariable->getFlashes(''));
$flashMessages = $this->setFlashMessages();
$this->assertEquals($flashMessages, $this->appVariable->getFlashes(array()));
$flashMessages = $this->setFlashMessages();
$this->assertEquals(array(), $this->appVariable->getFlashes('this-does-not-exist'));
$flashMessages = $this->setFlashMessages();
$this->assertEquals(
array('this-does-not-exist' => array()),
$this->appVariable->getFlashes(array('this-does-not-exist'))
);
$flashMessages = $this->setFlashMessages();
$this->assertEquals($flashMessages['notice'], $this->appVariable->getFlashes('notice'));
$flashMessages = $this->setFlashMessages();
$this->assertEquals(
array('notice' => $flashMessages['notice']),
$this->appVariable->getFlashes(array('notice'))
);
$flashMessages = $this->setFlashMessages();
$this->assertEquals(
array('notice' => $flashMessages['notice'], 'this-does-not-exist' => array()),
$this->appVariable->getFlashes(array('notice', 'this-does-not-exist'))
);
$flashMessages = $this->setFlashMessages();
$this->assertEquals(
array('notice' => $flashMessages['notice'], 'error' => $flashMessages['error']),
$this->appVariable->getFlashes(array('notice', 'error'))
);
$this->assertEquals(
array('warning' => $flashMessages['warning']),
$this->appVariable->getFlashes(array('warning')),
'After getting some flash types (e.g. "notice" and "error"), the rest of flash messages must remain (e.g. "warning").'
);
$this->assertEquals(
array('this-does-not-exist' => array()),
$this->appVariable->getFlashes(array('this-does-not-exist'))
);
}
protected function setRequestStack($request)
{
$requestStackMock = $this->getMockBuilder('Symfony\Component\HttpFoundation\RequestStack')->getMock();
$requestStackMock->method('getCurrentRequest')->willReturn($request);
$this->appVariable->setRequestStack($requestStackMock);
}
protected function setTokenStorage($user)
{
$tokenStorage = $this->getMockBuilder('Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorageInterface')->getMock();
$this->appVariable->setTokenStorage($tokenStorage);
$token = $this->getMockBuilder('Symfony\Component\Security\Core\Authentication\Token\TokenInterface')->getMock();
$tokenStorage->method('getToken')->willReturn($token);
$token->method('getUser')->willReturn($user);
}
private function setFlashMessages()
{
$flashMessages = array(
'notice' => array('Notice #1 message'),
'warning' => array('Warning #1 message'),
'error' => array('Error #1 message', 'Error #2 message'),
);
$flashBag = new FlashBag();
$flashBag->initialize($flashMessages);
$session = $this->getMockBuilder('Symfony\Component\HttpFoundation\Session\Session')->getMock();
$session->method('isStarted')->willReturn(true);
$session->method('getFlashBag')->willReturn($flashBag);
$request = $this->getMockBuilder('Symfony\Component\HttpFoundation\Request')->getMock();
$request->method('getSession')->willReturn($session);
$this->setRequestStack($request);
return $flashMessages;
}
}

View File

@@ -0,0 +1,114 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Bridge\Twig\Tests\Command;
use PHPUnit\Framework\TestCase;
use Symfony\Bridge\Twig\Command\LintCommand;
use Symfony\Component\Console\Application;
use Symfony\Component\Console\Output\OutputInterface;
use Symfony\Component\Console\Tester\CommandTester;
use Twig\Loader\FilesystemLoader;
use Twig\Environment;
class LintCommandTest extends TestCase
{
private $files;
public function testLintCorrectFile()
{
$tester = $this->createCommandTester();
$filename = $this->createFile('{{ foo }}');
$ret = $tester->execute(array('filename' => array($filename)), array('verbosity' => OutputInterface::VERBOSITY_VERBOSE, 'decorated' => false));
$this->assertEquals(0, $ret, 'Returns 0 in case of success');
$this->assertContains('OK in', trim($tester->getDisplay()));
}
public function testLintIncorrectFile()
{
$tester = $this->createCommandTester();
$filename = $this->createFile('{{ foo');
$ret = $tester->execute(array('filename' => array($filename)), array('decorated' => false));
$this->assertEquals(1, $ret, 'Returns 1 in case of error');
$this->assertRegExp('/ERROR in \S+ \(line /', trim($tester->getDisplay()));
}
/**
* @expectedException \RuntimeException
*/
public function testLintFileNotReadable()
{
$tester = $this->createCommandTester();
$filename = $this->createFile('');
unlink($filename);
$ret = $tester->execute(array('filename' => array($filename)), array('decorated' => false));
}
public function testLintFileCompileTimeException()
{
$tester = $this->createCommandTester();
$filename = $this->createFile("{{ 2|number_format(2, decimal_point='.', ',') }}");
$ret = $tester->execute(array('filename' => array($filename)), array('decorated' => false));
$this->assertEquals(1, $ret, 'Returns 1 in case of error');
$this->assertRegExp('/ERROR in \S+ \(line /', trim($tester->getDisplay()));
}
/**
* @return CommandTester
*/
private function createCommandTester()
{
$twig = new Environment(new FilesystemLoader());
$command = new LintCommand();
$command->setTwigEnvironment($twig);
$application = new Application();
$application->add($command);
$command = $application->find('lint:twig');
return new CommandTester($command);
}
/**
* @return string Path to the new file
*/
private function createFile($content)
{
$filename = tempnam(sys_get_temp_dir(), 'sf-');
file_put_contents($filename, $content);
$this->files[] = $filename;
return $filename;
}
protected function setUp()
{
$this->files = array();
}
protected function tearDown()
{
foreach ($this->files as $file) {
if (file_exists($file)) {
unlink($file);
}
}
}
}

View File

@@ -0,0 +1,69 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Bridge\Twig\Tests\Extension;
use PHPUnit\Framework\TestCase;
use Symfony\Bridge\Twig\Extension\CodeExtension;
use Symfony\Component\HttpKernel\Debug\FileLinkFormatter;
class CodeExtensionTest extends TestCase
{
public function testFormatFile()
{
$expected = sprintf('<a href="proto://foobar%s#&amp;line=25" title="Click to open this file" class="file_link">%s at line 25</a>', substr(__FILE__, 5), __FILE__);
$this->assertEquals($expected, $this->getExtension()->formatFile(__FILE__, 25));
}
/**
* @dataProvider getClassNameProvider
*/
public function testGettingClassAbbreviation($class, $abbr)
{
$this->assertEquals($this->getExtension()->abbrClass($class), $abbr);
}
/**
* @dataProvider getMethodNameProvider
*/
public function testGettingMethodAbbreviation($method, $abbr)
{
$this->assertEquals($this->getExtension()->abbrMethod($method), $abbr);
}
public function getClassNameProvider()
{
return array(
array('F\Q\N\Foo', '<abbr title="F\Q\N\Foo">Foo</abbr>'),
array('Bare', '<abbr title="Bare">Bare</abbr>'),
);
}
public function getMethodNameProvider()
{
return array(
array('F\Q\N\Foo::Method', '<abbr title="F\Q\N\Foo">Foo</abbr>::Method()'),
array('Bare::Method', '<abbr title="Bare">Bare</abbr>::Method()'),
array('Closure', '<abbr title="Closure">Closure</abbr>'),
array('Method', '<abbr title="Method">Method</abbr>()'),
);
}
public function testGetName()
{
$this->assertEquals('code', $this->getExtension()->getName());
}
protected function getExtension()
{
return new CodeExtension(new FileLinkFormatter('proto://%f#&line=%l&'.substr(__FILE__, 0, 5).'>foobar'), '/root', 'UTF-8');
}
}

View File

@@ -0,0 +1,145 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Bridge\Twig\Tests\Extension;
use PHPUnit\Framework\TestCase;
use Symfony\Bridge\Twig\Extension\DumpExtension;
use Symfony\Component\VarDumper\Dumper\HtmlDumper;
use Symfony\Component\VarDumper\VarDumper;
use Symfony\Component\VarDumper\Cloner\VarCloner;
use Twig\Environment;
use Twig\Loader\ArrayLoader;
class DumpExtensionTest extends TestCase
{
/**
* @dataProvider getDumpTags
*/
public function testDumpTag($template, $debug, $expectedOutput, $expectedDumped)
{
$extension = new DumpExtension(new VarCloner());
$twig = new Environment(new ArrayLoader(array('template' => $template)), array(
'debug' => $debug,
'cache' => false,
'optimizations' => 0,
));
$twig->addExtension($extension);
$dumped = null;
$exception = null;
$prevDumper = VarDumper::setHandler(function ($var) use (&$dumped) { $dumped = $var; });
try {
$this->assertEquals($expectedOutput, $twig->render('template'));
} catch (\Exception $exception) {
}
VarDumper::setHandler($prevDumper);
if (null !== $exception) {
throw $exception;
}
$this->assertSame($expectedDumped, $dumped);
}
public function getDumpTags()
{
return array(
array('A{% dump %}B', true, 'AB', array()),
array('A{% set foo="bar"%}B{% dump %}C', true, 'ABC', array('foo' => 'bar')),
array('A{% dump %}B', false, 'AB', null),
);
}
/**
* @dataProvider getDumpArgs
*/
public function testDump($context, $args, $expectedOutput, $debug = true)
{
$extension = new DumpExtension(new VarCloner());
$twig = new Environment($this->getMockBuilder('Twig\Loader\LoaderInterface')->getMock(), array(
'debug' => $debug,
'cache' => false,
'optimizations' => 0,
));
array_unshift($args, $context);
array_unshift($args, $twig);
$dump = call_user_func_array(array($extension, 'dump'), $args);
if ($debug) {
$this->assertStringStartsWith('<script>', $dump);
$dump = preg_replace('/^.*?<pre/', '<pre', $dump);
$dump = preg_replace('/sf-dump-\d+/', 'sf-dump', $dump);
}
$this->assertEquals($expectedOutput, $dump);
}
public function getDumpArgs()
{
return array(
array(array(), array(), '', false),
array(array(), array(), "<pre class=sf-dump id=sf-dump data-indent-pad=\" \">[]\n</pre><script>Sfdump(\"sf-dump\")</script>\n"),
array(
array(),
array(123, 456),
"<pre class=sf-dump id=sf-dump data-indent-pad=\" \"><span class=sf-dump-num>123</span>\n</pre><script>Sfdump(\"sf-dump\")</script>\n"
."<pre class=sf-dump id=sf-dump data-indent-pad=\" \"><span class=sf-dump-num>456</span>\n</pre><script>Sfdump(\"sf-dump\")</script>\n",
),
array(
array('foo' => 'bar'),
array(),
"<pre class=sf-dump id=sf-dump data-indent-pad=\" \"><span class=sf-dump-note>array:1</span> [<samp>\n"
." \"<span class=sf-dump-key>foo</span>\" => \"<span class=sf-dump-str title=\"3 characters\">bar</span>\"\n"
."</samp>]\n"
."</pre><script>Sfdump(\"sf-dump\")</script>\n",
),
);
}
public function testCustomDumper()
{
$output = '';
$lineDumper = function ($line) use (&$output) {
$output .= $line;
};
$dumper = new HtmlDumper($lineDumper);
$dumper->setDumpHeader('');
$dumper->setDumpBoundaries(
'<pre class=sf-dump-test id=%s data-indent-pad="%s">',
'</pre><script>Sfdump("%s")</script>'
);
$extension = new DumpExtension(new VarCloner(), $dumper);
$twig = new Environment($this->getMockBuilder('Twig\Loader\LoaderInterface')->getMock(), array(
'debug' => true,
'cache' => false,
'optimizations' => 0,
));
$dump = $extension->dump($twig, array(), 'foo');
$dump = preg_replace('/sf-dump-\d+/', 'sf-dump', $dump);
$this->assertEquals(
'<pre class=sf-dump-test id=sf-dump data-indent-pad=" ">"'.
"<span class=sf-dump-str title=\"3 characters\">foo</span>\"\n".
"</pre><script>Sfdump(\"sf-dump\")</script>\n",
$dump,
'Custom dumper should be used to dump data.'
);
$this->assertEmpty($output, 'Dumper output should be ignored.');
}
}

View File

@@ -0,0 +1,30 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Bridge\Twig\Tests\Extension;
use PHPUnit\Framework\TestCase;
use Symfony\Bridge\Twig\Extension\ExpressionExtension;
use Twig\Environment;
use Twig\Loader\ArrayLoader;
class ExpressionExtensionTest extends TestCase
{
public function testExpressionCreation()
{
$template = "{{ expression('1 == 1') }}";
$twig = new Environment(new ArrayLoader(array('template' => $template)), array('debug' => true, 'cache' => false, 'autoescape' => 'html', 'optimizations' => 0));
$twig->addExtension(new ExpressionExtension());
$output = $twig->render('template');
$this->assertEquals('1 == 1', $output);
}
}

View File

@@ -0,0 +1,25 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Bridge\Twig\Tests\Extension\Fixtures;
use Twig\Loader\FilesystemLoader;
class StubFilesystemLoader extends FilesystemLoader
{
protected function findTemplate($name, $throw = true)
{
// strip away bundle name
$parts = explode(':', $name);
return parent::findTemplate(end($parts), $throw);
}
}

View File

@@ -0,0 +1,35 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Bridge\Twig\Tests\Extension\Fixtures;
use Symfony\Component\Translation\TranslatorInterface;
class StubTranslator implements TranslatorInterface
{
public function trans($id, array $parameters = array(), $domain = null, $locale = null)
{
return '[trans]'.$id.'[/trans]';
}
public function transChoice($id, $number, array $parameters = array(), $domain = null, $locale = null)
{
return '[trans]'.$id.'[/trans]';
}
public function setLocale($locale)
{
}
public function getLocale()
{
}
}

View File

@@ -0,0 +1,3 @@
{% block form_label %}
<label>{{ global }}child</label>
{% endblock form_label %}

View File

@@ -0,0 +1,25 @@
{% block _text_id_widget %}
{% spaceless %}
<div id="container">
{{ form_widget(form) }}
</div>
{% endspaceless %}
{% endblock _text_id_widget %}
{% block _names_entry_label %}
{% spaceless %}
{% if label is empty %}
{% set label = name|humanize %}
{% endif %}
<label>Custom label: {{ label|trans({}, translation_domain) }}</label>
{% endspaceless %}
{% endblock _names_entry_label %}
{% block _name_c_entry_label %}
{% spaceless %}
{% if label is empty %}
{% set label = name|humanize %}
{% endif %}
<label>Custom name label: {{ label|trans({}, translation_domain) }}</label>
{% endspaceless %}
{% endblock _name_c_entry_label %}

View File

@@ -0,0 +1 @@
{% extends dynamic_template_name ~ '.html.twig' %}

View File

@@ -0,0 +1,3 @@
{% block form_label %}
<label>parent</label>
{% endblock form_label %}

View File

@@ -0,0 +1,6 @@
{% block form_widget_simple %}
{% spaceless %}
{% set type = type|default('text') %}
<input type="{{ type }}" {{ block('widget_attributes') }} value="{{ value }}" rel="theme" />
{% endspaceless %}
{% endblock form_widget_simple %}

View File

@@ -0,0 +1,8 @@
{% extends 'form_div_layout.html.twig' %}
{% block form_widget_simple %}
{% spaceless %}
{% set type = type|default('text') %}
<input type="{{ type }}" {{ block('widget_attributes') }} value="{{ value }}" rel="theme" />
{% endspaceless %}
{% endblock form_widget_simple %}

View File

@@ -0,0 +1,8 @@
{% use 'form_div_layout.html.twig' %}
{% block form_widget_simple %}
{% spaceless %}
{% set type = type|default('text') %}
<input type="{{ type }}" {{ block('widget_attributes') }} value="{{ value }}" rel="theme" />
{% endspaceless %}
{% endblock form_widget_simple %}

View File

@@ -0,0 +1,103 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Bridge\Twig\Tests\Extension;
use Symfony\Bridge\Twig\Extension\FormExtension;
use Symfony\Bridge\Twig\Form\TwigRenderer;
use Symfony\Bridge\Twig\Form\TwigRendererEngine;
use Symfony\Bridge\Twig\Extension\TranslationExtension;
use Symfony\Bridge\Twig\Tests\Extension\Fixtures\StubTranslator;
use Symfony\Bridge\Twig\Tests\Extension\Fixtures\StubFilesystemLoader;
use Symfony\Component\Form\FormView;
use Symfony\Component\Form\Tests\AbstractBootstrap3HorizontalLayoutTest;
use Twig\Environment;
class FormExtensionBootstrap3HorizontalLayoutTest extends AbstractBootstrap3HorizontalLayoutTest
{
use RuntimeLoaderProvider;
protected $testableFeatures = array(
'choice_attr',
);
private $renderer;
protected function setUp()
{
parent::setUp();
$loader = new StubFilesystemLoader(array(
__DIR__.'/../../Resources/views/Form',
__DIR__.'/Fixtures/templates/form',
));
$environment = new Environment($loader, array('strict_variables' => true));
$environment->addExtension(new TranslationExtension(new StubTranslator()));
$environment->addExtension(new FormExtension());
$rendererEngine = new TwigRendererEngine(array(
'bootstrap_3_horizontal_layout.html.twig',
'custom_widgets.html.twig',
), $environment);
$this->renderer = new TwigRenderer($rendererEngine, $this->getMockBuilder('Symfony\Component\Security\Csrf\CsrfTokenManagerInterface')->getMock());
$this->registerTwigRuntimeLoader($environment, $this->renderer);
}
protected function renderForm(FormView $view, array $vars = array())
{
return (string) $this->renderer->renderBlock($view, 'form', $vars);
}
protected function renderLabel(FormView $view, $label = null, array $vars = array())
{
if (null !== $label) {
$vars += array('label' => $label);
}
return (string) $this->renderer->searchAndRenderBlock($view, 'label', $vars);
}
protected function renderErrors(FormView $view)
{
return (string) $this->renderer->searchAndRenderBlock($view, 'errors');
}
protected function renderWidget(FormView $view, array $vars = array())
{
return (string) $this->renderer->searchAndRenderBlock($view, 'widget', $vars);
}
protected function renderRow(FormView $view, array $vars = array())
{
return (string) $this->renderer->searchAndRenderBlock($view, 'row', $vars);
}
protected function renderRest(FormView $view, array $vars = array())
{
return (string) $this->renderer->searchAndRenderBlock($view, 'rest', $vars);
}
protected function renderStart(FormView $view, array $vars = array())
{
return (string) $this->renderer->renderBlock($view, 'form_start', $vars);
}
protected function renderEnd(FormView $view, array $vars = array())
{
return (string) $this->renderer->renderBlock($view, 'form_end', $vars);
}
protected function setTheme(FormView $view, array $themes)
{
$this->renderer->setTheme($view, $themes);
}
}

View File

@@ -0,0 +1,123 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Bridge\Twig\Tests\Extension;
use Symfony\Bridge\Twig\Extension\FormExtension;
use Symfony\Bridge\Twig\Form\TwigRenderer;
use Symfony\Bridge\Twig\Form\TwigRendererEngine;
use Symfony\Bridge\Twig\Extension\TranslationExtension;
use Symfony\Bridge\Twig\Tests\Extension\Fixtures\StubTranslator;
use Symfony\Bridge\Twig\Tests\Extension\Fixtures\StubFilesystemLoader;
use Symfony\Component\Form\FormView;
use Symfony\Component\Form\Tests\AbstractBootstrap3LayoutTest;
use Twig\Environment;
class FormExtensionBootstrap3LayoutTest extends AbstractBootstrap3LayoutTest
{
use RuntimeLoaderProvider;
private $renderer;
protected function setUp()
{
parent::setUp();
$loader = new StubFilesystemLoader(array(
__DIR__.'/../../Resources/views/Form',
__DIR__.'/Fixtures/templates/form',
));
$environment = new Environment($loader, array('strict_variables' => true));
$environment->addExtension(new TranslationExtension(new StubTranslator()));
$environment->addExtension(new FormExtension());
$rendererEngine = new TwigRendererEngine(array(
'bootstrap_3_layout.html.twig',
'custom_widgets.html.twig',
), $environment);
$this->renderer = new TwigRenderer($rendererEngine, $this->getMockBuilder('Symfony\Component\Security\Csrf\CsrfTokenManagerInterface')->getMock());
$this->registerTwigRuntimeLoader($environment, $this->renderer);
}
public function testStartTagHasNoActionAttributeWhenActionIsEmpty()
{
$form = $this->factory->create('Symfony\Component\Form\Extension\Core\Type\FormType', null, array(
'method' => 'get',
'action' => '',
));
$html = $this->renderStart($form->createView());
$this->assertSame('<form name="form" method="get">', $html);
}
public function testStartTagHasActionAttributeWhenActionIsZero()
{
$form = $this->factory->create('Symfony\Component\Form\Extension\Core\Type\FormType', null, array(
'method' => 'get',
'action' => '0',
));
$html = $this->renderStart($form->createView());
$this->assertSame('<form name="form" method="get" action="0">', $html);
}
protected function renderForm(FormView $view, array $vars = array())
{
return (string) $this->renderer->renderBlock($view, 'form', $vars);
}
protected function renderLabel(FormView $view, $label = null, array $vars = array())
{
if (null !== $label) {
$vars += array('label' => $label);
}
return (string) $this->renderer->searchAndRenderBlock($view, 'label', $vars);
}
protected function renderErrors(FormView $view)
{
return (string) $this->renderer->searchAndRenderBlock($view, 'errors');
}
protected function renderWidget(FormView $view, array $vars = array())
{
return (string) $this->renderer->searchAndRenderBlock($view, 'widget', $vars);
}
protected function renderRow(FormView $view, array $vars = array())
{
return (string) $this->renderer->searchAndRenderBlock($view, 'row', $vars);
}
protected function renderRest(FormView $view, array $vars = array())
{
return (string) $this->renderer->searchAndRenderBlock($view, 'rest', $vars);
}
protected function renderStart(FormView $view, array $vars = array())
{
return (string) $this->renderer->renderBlock($view, 'form_start', $vars);
}
protected function renderEnd(FormView $view, array $vars = array())
{
return (string) $this->renderer->renderBlock($view, 'form_end', $vars);
}
protected function setTheme(FormView $view, array $themes)
{
$this->renderer->setTheme($view, $themes);
}
}

View File

@@ -0,0 +1,227 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Bridge\Twig\Tests\Extension;
use Symfony\Bridge\Twig\Extension\FormExtension;
use Symfony\Bridge\Twig\Form\TwigRenderer;
use Symfony\Bridge\Twig\Form\TwigRendererEngine;
use Symfony\Bridge\Twig\Extension\TranslationExtension;
use Symfony\Bridge\Twig\Tests\Extension\Fixtures\StubTranslator;
use Symfony\Bridge\Twig\Tests\Extension\Fixtures\StubFilesystemLoader;
use Symfony\Component\Form\ChoiceList\View\ChoiceView;
use Symfony\Component\Form\FormView;
use Symfony\Component\Form\Tests\AbstractDivLayoutTest;
use Twig\Environment;
class FormExtensionDivLayoutTest extends AbstractDivLayoutTest
{
use RuntimeLoaderProvider;
private $renderer;
protected function setUp()
{
parent::setUp();
$loader = new StubFilesystemLoader(array(
__DIR__.'/../../Resources/views/Form',
__DIR__.'/Fixtures/templates/form',
));
$environment = new Environment($loader, array('strict_variables' => true));
$environment->addExtension(new TranslationExtension(new StubTranslator()));
$environment->addGlobal('global', '');
// the value can be any template that exists
$environment->addGlobal('dynamic_template_name', 'child_label');
$environment->addExtension(new FormExtension());
$rendererEngine = new TwigRendererEngine(array(
'form_div_layout.html.twig',
'custom_widgets.html.twig',
), $environment);
$this->renderer = new TwigRenderer($rendererEngine, $this->getMockBuilder('Symfony\Component\Security\Csrf\CsrfTokenManagerInterface')->getMock());
$this->registerTwigRuntimeLoader($environment, $this->renderer);
}
public function testThemeBlockInheritanceUsingUse()
{
$view = $this->factory
->createNamed('name', 'Symfony\Component\Form\Extension\Core\Type\EmailType')
->createView()
;
$this->setTheme($view, array('theme_use.html.twig'));
$this->assertMatchesXpath(
$this->renderWidget($view),
'/input[@type="email"][@rel="theme"]'
);
}
public function testThemeBlockInheritanceUsingExtend()
{
$view = $this->factory
->createNamed('name', 'Symfony\Component\Form\Extension\Core\Type\EmailType')
->createView()
;
$this->setTheme($view, array('theme_extends.html.twig'));
$this->assertMatchesXpath(
$this->renderWidget($view),
'/input[@type="email"][@rel="theme"]'
);
}
public function testThemeBlockInheritanceUsingDynamicExtend()
{
$view = $this->factory
->createNamed('name', 'Symfony\Component\Form\Extension\Core\Type\EmailType')
->createView()
;
$this->renderer->setTheme($view, array('page_dynamic_extends.html.twig'));
$this->assertMatchesXpath(
$this->renderer->searchAndRenderBlock($view, 'row'),
'/div/label[text()="child"]'
);
}
public function isSelectedChoiceProvider()
{
return array(
array(true, '0', '0'),
array(true, '1', '1'),
array(true, '', ''),
array(true, '1.23', '1.23'),
array(true, 'foo', 'foo'),
array(true, 'foo10', 'foo10'),
array(true, 'foo', array(1, 'foo', 'foo10')),
array(false, 10, array(1, 'foo', 'foo10')),
array(false, 0, array(1, 'foo', 'foo10')),
);
}
/**
* @dataProvider isSelectedChoiceProvider
*/
public function testIsChoiceSelected($expected, $choice, $value)
{
$choice = new ChoiceView($choice, $choice, $choice.' label');
$this->assertSame($expected, \Symfony\Bridge\Twig\Extension\twig_is_selected_choice($choice, $value));
}
public function testStartTagHasNoActionAttributeWhenActionIsEmpty()
{
$form = $this->factory->create('Symfony\Component\Form\Extension\Core\Type\FormType', null, array(
'method' => 'get',
'action' => '',
));
$html = $this->renderStart($form->createView());
$this->assertSame('<form name="form" method="get">', $html);
}
public function testStartTagHasActionAttributeWhenActionIsZero()
{
$form = $this->factory->create('Symfony\Component\Form\Extension\Core\Type\FormType', null, array(
'method' => 'get',
'action' => '0',
));
$html = $this->renderStart($form->createView());
$this->assertSame('<form name="form" method="get" action="0">', $html);
}
public function isRootFormProvider()
{
return array(
array(true, new FormView()),
array(false, new FormView(new FormView())),
);
}
/**
* @dataProvider isRootFormProvider
*/
public function testIsRootForm($expected, FormView $formView)
{
$this->assertSame($expected, \Symfony\Bridge\Twig\Extension\twig_is_root_form($formView));
}
protected function renderForm(FormView $view, array $vars = array())
{
return (string) $this->renderer->renderBlock($view, 'form', $vars);
}
protected function renderLabel(FormView $view, $label = null, array $vars = array())
{
if (null !== $label) {
$vars += array('label' => $label);
}
return (string) $this->renderer->searchAndRenderBlock($view, 'label', $vars);
}
protected function renderErrors(FormView $view)
{
return (string) $this->renderer->searchAndRenderBlock($view, 'errors');
}
protected function renderWidget(FormView $view, array $vars = array())
{
return (string) $this->renderer->searchAndRenderBlock($view, 'widget', $vars);
}
protected function renderRow(FormView $view, array $vars = array())
{
return (string) $this->renderer->searchAndRenderBlock($view, 'row', $vars);
}
protected function renderRest(FormView $view, array $vars = array())
{
return (string) $this->renderer->searchAndRenderBlock($view, 'rest', $vars);
}
protected function renderStart(FormView $view, array $vars = array())
{
return (string) $this->renderer->renderBlock($view, 'form_start', $vars);
}
protected function renderEnd(FormView $view, array $vars = array())
{
return (string) $this->renderer->renderBlock($view, 'form_end', $vars);
}
protected function setTheme(FormView $view, array $themes)
{
$this->renderer->setTheme($view, $themes);
}
public static function themeBlockInheritanceProvider()
{
return array(
array(array('theme.html.twig')),
);
}
public static function themeInheritanceProvider()
{
return array(
array(array('parent_label.html.twig'), array('child_label.html.twig')),
);
}
}

View File

@@ -0,0 +1,124 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Bridge\Twig\Tests\Extension;
use Symfony\Component\Form\FormView;
use Symfony\Bridge\Twig\Form\TwigRenderer;
use Symfony\Bridge\Twig\Form\TwigRendererEngine;
use Symfony\Bridge\Twig\Extension\FormExtension;
use Symfony\Bridge\Twig\Extension\TranslationExtension;
use Symfony\Component\Form\Tests\AbstractTableLayoutTest;
use Symfony\Bridge\Twig\Tests\Extension\Fixtures\StubTranslator;
use Symfony\Bridge\Twig\Tests\Extension\Fixtures\StubFilesystemLoader;
use Twig\Environment;
class FormExtensionTableLayoutTest extends AbstractTableLayoutTest
{
use RuntimeLoaderProvider;
private $renderer;
protected function setUp()
{
parent::setUp();
$loader = new StubFilesystemLoader(array(
__DIR__.'/../../Resources/views/Form',
__DIR__.'/Fixtures/templates/form',
));
$environment = new Environment($loader, array('strict_variables' => true));
$environment->addExtension(new TranslationExtension(new StubTranslator()));
$environment->addGlobal('global', '');
$environment->addExtension(new FormExtension());
$rendererEngine = new TwigRendererEngine(array(
'form_table_layout.html.twig',
'custom_widgets.html.twig',
), $environment);
$this->renderer = new TwigRenderer($rendererEngine, $this->getMockBuilder('Symfony\Component\Security\Csrf\CsrfTokenManagerInterface')->getMock());
$this->registerTwigRuntimeLoader($environment, $this->renderer);
}
public function testStartTagHasNoActionAttributeWhenActionIsEmpty()
{
$form = $this->factory->create('Symfony\Component\Form\Extension\Core\Type\FormType', null, array(
'method' => 'get',
'action' => '',
));
$html = $this->renderStart($form->createView());
$this->assertSame('<form name="form" method="get">', $html);
}
public function testStartTagHasActionAttributeWhenActionIsZero()
{
$form = $this->factory->create('Symfony\Component\Form\Extension\Core\Type\FormType', null, array(
'method' => 'get',
'action' => '0',
));
$html = $this->renderStart($form->createView());
$this->assertSame('<form name="form" method="get" action="0">', $html);
}
protected function renderForm(FormView $view, array $vars = array())
{
return (string) $this->renderer->renderBlock($view, 'form', $vars);
}
protected function renderLabel(FormView $view, $label = null, array $vars = array())
{
if (null !== $label) {
$vars += array('label' => $label);
}
return (string) $this->renderer->searchAndRenderBlock($view, 'label', $vars);
}
protected function renderErrors(FormView $view)
{
return (string) $this->renderer->searchAndRenderBlock($view, 'errors');
}
protected function renderWidget(FormView $view, array $vars = array())
{
return (string) $this->renderer->searchAndRenderBlock($view, 'widget', $vars);
}
protected function renderRow(FormView $view, array $vars = array())
{
return (string) $this->renderer->searchAndRenderBlock($view, 'row', $vars);
}
protected function renderRest(FormView $view, array $vars = array())
{
return (string) $this->renderer->searchAndRenderBlock($view, 'rest', $vars);
}
protected function renderStart(FormView $view, array $vars = array())
{
return (string) $this->renderer->renderBlock($view, 'form_start', $vars);
}
protected function renderEnd(FormView $view, array $vars = array())
{
return (string) $this->renderer->renderBlock($view, 'form_end', $vars);
}
protected function setTheme(FormView $view, array $themes)
{
$this->renderer->setTheme($view, $themes);
}
}

View File

@@ -0,0 +1,143 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Bridge\Twig\Tests\Extension;
use PHPUnit\Framework\TestCase;
use Symfony\Bridge\Twig\Extension\HttpFoundationExtension;
use Symfony\Component\HttpFoundation\RequestStack;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\Routing\RequestContext;
class HttpFoundationExtensionTest extends TestCase
{
/**
* @dataProvider getGenerateAbsoluteUrlData()
*/
public function testGenerateAbsoluteUrl($expected, $path, $pathinfo)
{
$stack = new RequestStack();
$stack->push(Request::create($pathinfo));
$extension = new HttpFoundationExtension($stack);
$this->assertEquals($expected, $extension->generateAbsoluteUrl($path));
}
public function getGenerateAbsoluteUrlData()
{
return array(
array('http://localhost/foo.png', '/foo.png', '/foo/bar.html'),
array('http://localhost/foo/foo.png', 'foo.png', '/foo/bar.html'),
array('http://localhost/foo/foo.png', 'foo.png', '/foo/bar'),
array('http://localhost/foo/bar/foo.png', 'foo.png', '/foo/bar/'),
array('http://example.com/baz', 'http://example.com/baz', '/'),
array('https://example.com/baz', 'https://example.com/baz', '/'),
array('//example.com/baz', '//example.com/baz', '/'),
array('http://localhost/foo/bar?baz', '?baz', '/foo/bar'),
array('http://localhost/foo/bar?baz=1', '?baz=1', '/foo/bar?foo=1'),
array('http://localhost/foo/baz?baz=1', 'baz?baz=1', '/foo/bar?foo=1'),
array('http://localhost/foo/bar#baz', '#baz', '/foo/bar'),
array('http://localhost/foo/bar?0#baz', '#baz', '/foo/bar?0'),
array('http://localhost/foo/bar?baz=1#baz', '?baz=1#baz', '/foo/bar?foo=1'),
array('http://localhost/foo/baz?baz=1#baz', 'baz?baz=1#baz', '/foo/bar?foo=1'),
);
}
/**
* @dataProvider getGenerateAbsoluteUrlRequestContextData
*/
public function testGenerateAbsoluteUrlWithRequestContext($path, $baseUrl, $host, $scheme, $httpPort, $httpsPort, $expected)
{
if (!class_exists('Symfony\Component\Routing\RequestContext')) {
$this->markTestSkipped('The Routing component is needed to run tests that depend on its request context.');
}
$requestContext = new RequestContext($baseUrl, 'GET', $host, $scheme, $httpPort, $httpsPort, $path);
$extension = new HttpFoundationExtension(new RequestStack(), $requestContext);
$this->assertEquals($expected, $extension->generateAbsoluteUrl($path));
}
/**
* @dataProvider getGenerateAbsoluteUrlRequestContextData
*/
public function testGenerateAbsoluteUrlWithoutRequestAndRequestContext($path)
{
if (!class_exists('Symfony\Component\Routing\RequestContext')) {
$this->markTestSkipped('The Routing component is needed to run tests that depend on its request context.');
}
$extension = new HttpFoundationExtension(new RequestStack());
$this->assertEquals($path, $extension->generateAbsoluteUrl($path));
}
public function getGenerateAbsoluteUrlRequestContextData()
{
return array(
array('/foo.png', '/foo', 'localhost', 'http', 80, 443, 'http://localhost/foo.png'),
array('foo.png', '/foo', 'localhost', 'http', 80, 443, 'http://localhost/foo/foo.png'),
array('foo.png', '/foo/bar/', 'localhost', 'http', 80, 443, 'http://localhost/foo/bar/foo.png'),
array('/foo.png', '/foo', 'localhost', 'https', 80, 443, 'https://localhost/foo.png'),
array('foo.png', '/foo', 'localhost', 'https', 80, 443, 'https://localhost/foo/foo.png'),
array('foo.png', '/foo/bar/', 'localhost', 'https', 80, 443, 'https://localhost/foo/bar/foo.png'),
array('/foo.png', '/foo', 'localhost', 'http', 443, 80, 'http://localhost:443/foo.png'),
array('/foo.png', '/foo', 'localhost', 'https', 443, 80, 'https://localhost:80/foo.png'),
);
}
public function testGenerateAbsoluteUrlWithScriptFileName()
{
$request = Request::create('http://localhost/app/web/app_dev.php');
$request->server->set('SCRIPT_FILENAME', '/var/www/app/web/app_dev.php');
$stack = new RequestStack();
$stack->push($request);
$extension = new HttpFoundationExtension($stack);
$this->assertEquals(
'http://localhost/app/web/bundles/framework/css/structure.css',
$extension->generateAbsoluteUrl('/app/web/bundles/framework/css/structure.css')
);
}
/**
* @dataProvider getGenerateRelativePathData()
*/
public function testGenerateRelativePath($expected, $path, $pathinfo)
{
if (!method_exists('Symfony\Component\HttpFoundation\Request', 'getRelativeUriForPath')) {
$this->markTestSkipped('Your version of Symfony HttpFoundation is too old.');
}
$stack = new RequestStack();
$stack->push(Request::create($pathinfo));
$extension = new HttpFoundationExtension($stack);
$this->assertEquals($expected, $extension->generateRelativePath($path));
}
public function getGenerateRelativePathData()
{
return array(
array('../foo.png', '/foo.png', '/foo/bar.html'),
array('../baz/foo.png', '/baz/foo.png', '/foo/bar.html'),
array('baz/foo.png', 'baz/foo.png', '/foo/bar.html'),
array('http://example.com/baz', 'http://example.com/baz', '/'),
array('https://example.com/baz', 'https://example.com/baz', '/'),
array('//example.com/baz', '//example.com/baz', '/'),
);
}
}

View File

@@ -0,0 +1,92 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Bridge\Twig\Tests\Extension;
use PHPUnit\Framework\TestCase;
use Symfony\Bridge\Twig\Extension\HttpKernelExtension;
use Symfony\Bridge\Twig\Extension\HttpKernelRuntime;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpKernel\Fragment\FragmentHandler;
use Twig\Environment;
use Twig\Loader\ArrayLoader;
class HttpKernelExtensionTest extends TestCase
{
/**
* @expectedException \Twig\Error\RuntimeError
*/
public function testFragmentWithError()
{
$renderer = $this->getFragmentHandler($this->throwException(new \Exception('foo')));
$this->renderTemplate($renderer);
}
public function testRenderFragment()
{
$renderer = $this->getFragmentHandler($this->returnValue(new Response('html')));
$response = $this->renderTemplate($renderer);
$this->assertEquals('html', $response);
}
public function testUnknownFragmentRenderer()
{
$context = $this->getMockBuilder('Symfony\\Component\\HttpFoundation\\RequestStack')
->disableOriginalConstructor()
->getMock()
;
$renderer = new FragmentHandler($context);
if (method_exists($this, 'expectException')) {
$this->expectException('InvalidArgumentException');
$this->expectExceptionMessage('The "inline" renderer does not exist.');
} else {
$this->setExpectedException('InvalidArgumentException', 'The "inline" renderer does not exist.');
}
$renderer->render('/foo');
}
protected function getFragmentHandler($return)
{
$strategy = $this->getMockBuilder('Symfony\\Component\\HttpKernel\\Fragment\\FragmentRendererInterface')->getMock();
$strategy->expects($this->once())->method('getName')->will($this->returnValue('inline'));
$strategy->expects($this->once())->method('render')->will($return);
$context = $this->getMockBuilder('Symfony\\Component\\HttpFoundation\\RequestStack')
->disableOriginalConstructor()
->getMock()
;
$context->expects($this->any())->method('getCurrentRequest')->will($this->returnValue(Request::create('/')));
return new FragmentHandler($context, array($strategy), false);
}
protected function renderTemplate(FragmentHandler $renderer, $template = '{{ render("foo") }}')
{
$loader = new ArrayLoader(array('index' => $template));
$twig = new Environment($loader, array('debug' => true, 'cache' => false));
$twig->addExtension(new HttpKernelExtension());
$loader = $this->getMockBuilder('Twig\RuntimeLoader\RuntimeLoaderInterface')->getMock();
$loader->expects($this->any())->method('load')->will($this->returnValueMap(array(
array('Symfony\Bridge\Twig\Extension\HttpKernelRuntime', new HttpKernelRuntime($renderer)),
)));
$twig->addRuntimeLoader($loader);
return $twig->render('index');
}
}

View File

@@ -0,0 +1,54 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Bridge\Twig\Tests\Extension;
use PHPUnit\Framework\TestCase;
use Symfony\Bridge\Twig\Extension\RoutingExtension;
use Twig\Environment;
use Twig\Node\Expression\FilterExpression;
use Twig\Source;
class RoutingExtensionTest extends TestCase
{
/**
* @dataProvider getEscapingTemplates
*/
public function testEscaping($template, $mustBeEscaped)
{
$twig = new Environment($this->getMockBuilder('Twig\Loader\LoaderInterface')->getMock(), array('debug' => true, 'cache' => false, 'autoescape' => 'html', 'optimizations' => 0));
$twig->addExtension(new RoutingExtension($this->getMockBuilder('Symfony\Component\Routing\Generator\UrlGeneratorInterface')->getMock()));
$nodes = $twig->parse($twig->tokenize(new Source($template, '')));
$this->assertSame($mustBeEscaped, $nodes->getNode('body')->getNode(0)->getNode('expr') instanceof FilterExpression);
}
public function getEscapingTemplates()
{
return array(
array('{{ path("foo") }}', false),
array('{{ path("foo", {}) }}', false),
array('{{ path("foo", { foo: "foo" }) }}', false),
array('{{ path("foo", foo) }}', true),
array('{{ path("foo", { foo: foo }) }}', true),
array('{{ path("foo", { foo: ["foo", "bar"] }) }}', true),
array('{{ path("foo", { foo: "foo", bar: "bar" }) }}', true),
array('{{ path(name = "foo", parameters = {}) }}', false),
array('{{ path(name = "foo", parameters = { foo: "foo" }) }}', false),
array('{{ path(name = "foo", parameters = foo) }}', true),
array('{{ path(name = "foo", parameters = { foo: ["foo", "bar"] }) }}', true),
array('{{ path(name = "foo", parameters = { foo: foo }) }}', true),
array('{{ path(name = "foo", parameters = { foo: "foo", bar: "bar" }) }}', true),
);
}
}

View File

@@ -0,0 +1,27 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Bridge\Twig\Tests\Extension;
use Symfony\Bridge\Twig\Form\TwigRenderer;
use Twig\Environment;
trait RuntimeLoaderProvider
{
protected function registerTwigRuntimeLoader(Environment $environment, TwigRenderer $renderer)
{
$loader = $this->getMockBuilder('Twig\RuntimeLoader\RuntimeLoaderInterface')->getMock();
$loader->expects($this->any())->method('load')->will($this->returnValueMap(array(
array('Symfony\Bridge\Twig\Form\TwigRenderer', $renderer),
)));
$environment->addRuntimeLoader($loader);
}
}

View File

@@ -0,0 +1,76 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Bridge\Twig\Tests\Extension;
use PHPUnit\Framework\TestCase;
use Symfony\Bridge\Twig\Extension\StopwatchExtension;
use Twig\Environment;
use Twig\Error\RuntimeError;
use Twig\Loader\ArrayLoader;
class StopwatchExtensionTest extends TestCase
{
/**
* @expectedException \Twig\Error\SyntaxError
*/
public function testFailIfStoppingWrongEvent()
{
$this->testTiming('{% stopwatch "foo" %}{% endstopwatch "bar" %}', array());
}
/**
* @dataProvider getTimingTemplates
*/
public function testTiming($template, $events)
{
$twig = new Environment(new ArrayLoader(array('template' => $template)), array('debug' => true, 'cache' => false, 'autoescape' => 'html', 'optimizations' => 0));
$twig->addExtension(new StopwatchExtension($this->getStopwatch($events)));
try {
$nodes = $twig->render('template');
} catch (RuntimeError $e) {
throw $e->getPrevious();
}
}
public function getTimingTemplates()
{
return array(
array('{% stopwatch "foo" %}something{% endstopwatch %}', 'foo'),
array('{% stopwatch "foo" %}symfony is fun{% endstopwatch %}{% stopwatch "bar" %}something{% endstopwatch %}', array('foo', 'bar')),
array('{% set foo = "foo" %}{% stopwatch foo %}something{% endstopwatch %}', 'foo'),
array('{% set foo = "foo" %}{% stopwatch foo %}something {% set foo = "bar" %}{% endstopwatch %}', 'foo'),
array('{% stopwatch "foo.bar" %}something{% endstopwatch %}', 'foo.bar'),
array('{% stopwatch "foo" %}something{% endstopwatch %}{% stopwatch "foo" %}something else{% endstopwatch %}', array('foo', 'foo')),
);
}
protected function getStopwatch($events = array())
{
$events = is_array($events) ? $events : array($events);
$stopwatch = $this->getMockBuilder('Symfony\Component\Stopwatch\Stopwatch')->getMock();
$i = -1;
foreach ($events as $eventName) {
$stopwatch->expects($this->at(++$i))
->method('start')
->with($this->equalTo($eventName), 'template')
;
$stopwatch->expects($this->at(++$i))
->method('stop')
->with($this->equalTo($eventName))
;
}
return $stopwatch;
}
}

View File

@@ -0,0 +1,220 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Bridge\Twig\Tests\Extension;
use PHPUnit\Framework\TestCase;
use Symfony\Bridge\Twig\Extension\TranslationExtension;
use Symfony\Component\Translation\Translator;
use Symfony\Component\Translation\MessageSelector;
use Symfony\Component\Translation\Loader\ArrayLoader;
use Twig\Environment;
use Twig\Loader\ArrayLoader as TwigArrayLoader;
class TranslationExtensionTest extends TestCase
{
public function testEscaping()
{
$output = $this->getTemplate('{% trans %}Percent: %value%%% (%msg%){% endtrans %}')->render(array('value' => 12, 'msg' => 'approx.'));
$this->assertEquals('Percent: 12% (approx.)', $output);
}
/**
* @dataProvider getTransTests
*/
public function testTrans($template, $expected, array $variables = array())
{
if ($expected != $this->getTemplate($template)->render($variables)) {
echo $template."\n";
$loader = new TwigArrayLoader(array('index' => $template));
$twig = new Environment($loader, array('debug' => true, 'cache' => false));
$twig->addExtension(new TranslationExtension(new Translator('en', new MessageSelector())));
echo $twig->compile($twig->parse($twig->tokenize($twig->getLoader()->getSourceContext('index'))))."\n\n";
$this->assertEquals($expected, $this->getTemplate($template)->render($variables));
}
$this->assertEquals($expected, $this->getTemplate($template)->render($variables));
}
/**
* @expectedException \Twig\Error\SyntaxError
* @expectedExceptionMessage Unexpected token. Twig was looking for the "with", "from", or "into" keyword in "index" at line 3.
*/
public function testTransUnknownKeyword()
{
$output = $this->getTemplate("{% trans \n\nfoo %}{% endtrans %}")->render();
}
/**
* @expectedException \Twig\Error\SyntaxError
* @expectedExceptionMessage A message inside a trans tag must be a simple text in "index" at line 2.
*/
public function testTransComplexBody()
{
$output = $this->getTemplate("{% trans %}\n{{ 1 + 2 }}{% endtrans %}")->render();
}
/**
* @expectedException \Twig\Error\SyntaxError
* @expectedExceptionMessage A message inside a transchoice tag must be a simple text in "index" at line 2.
*/
public function testTransChoiceComplexBody()
{
$output = $this->getTemplate("{% transchoice count %}\n{{ 1 + 2 }}{% endtranschoice %}")->render();
}
public function getTransTests()
{
return array(
// trans tag
array('{% trans %}Hello{% endtrans %}', 'Hello'),
array('{% trans %}%name%{% endtrans %}', 'Symfony', array('name' => 'Symfony')),
array('{% trans from elsewhere %}Hello{% endtrans %}', 'Hello'),
array('{% trans %}Hello %name%{% endtrans %}', 'Hello Symfony', array('name' => 'Symfony')),
array('{% trans with { \'%name%\': \'Symfony\' } %}Hello %name%{% endtrans %}', 'Hello Symfony'),
array('{% set vars = { \'%name%\': \'Symfony\' } %}{% trans with vars %}Hello %name%{% endtrans %}', 'Hello Symfony'),
array('{% trans into "fr"%}Hello{% endtrans %}', 'Hello'),
// transchoice
array(
'{% transchoice count from "messages" %}{0} There is no apples|{1} There is one apple|]1,Inf] There is %count% apples{% endtranschoice %}',
'There is no apples',
array('count' => 0),
),
array(
'{% transchoice count %}{0} There is no apples|{1} There is one apple|]1,Inf] There is %count% apples{% endtranschoice %}',
'There is 5 apples',
array('count' => 5),
),
array(
'{% transchoice count %}{0} There is no apples|{1} There is one apple|]1,Inf] There is %count% apples (%name%){% endtranschoice %}',
'There is 5 apples (Symfony)',
array('count' => 5, 'name' => 'Symfony'),
),
array(
'{% transchoice count with { \'%name%\': \'Symfony\' } %}{0} There is no apples|{1} There is one apple|]1,Inf] There is %count% apples (%name%){% endtranschoice %}',
'There is 5 apples (Symfony)',
array('count' => 5),
),
array(
'{% transchoice count into "fr"%}{0} There is no apples|{1} There is one apple|]1,Inf] There is %count% apples{% endtranschoice %}',
'There is no apples',
array('count' => 0),
),
array(
'{% transchoice 5 into "fr"%}{0} There is no apples|{1} There is one apple|]1,Inf] There is %count% apples{% endtranschoice %}',
'There is 5 apples',
),
// trans filter
array('{{ "Hello"|trans }}', 'Hello'),
array('{{ name|trans }}', 'Symfony', array('name' => 'Symfony')),
array('{{ hello|trans({ \'%name%\': \'Symfony\' }) }}', 'Hello Symfony', array('hello' => 'Hello %name%')),
array('{% set vars = { \'%name%\': \'Symfony\' } %}{{ hello|trans(vars) }}', 'Hello Symfony', array('hello' => 'Hello %name%')),
array('{{ "Hello"|trans({}, "messages", "fr") }}', 'Hello'),
// transchoice filter
array('{{ "{0} There is no apples|{1} There is one apple|]1,Inf] There is %count% apples"|transchoice(count) }}', 'There is 5 apples', array('count' => 5)),
array('{{ text|transchoice(5, {\'%name%\': \'Symfony\'}) }}', 'There is 5 apples (Symfony)', array('text' => '{0} There is no apples|{1} There is one apple|]1,Inf] There is %count% apples (%name%)')),
array('{{ "{0} There is no apples|{1} There is one apple|]1,Inf] There is %count% apples"|transchoice(count, {}, "messages", "fr") }}', 'There is 5 apples', array('count' => 5)),
);
}
public function testDefaultTranslationDomain()
{
$templates = array(
'index' => '
{%- extends "base" %}
{%- trans_default_domain "foo" %}
{%- block content %}
{%- trans %}foo{% endtrans %}
{%- trans from "custom" %}foo{% endtrans %}
{{- "foo"|trans }}
{{- "foo"|trans({}, "custom") }}
{{- "foo"|transchoice(1) }}
{{- "foo"|transchoice(1, {}, "custom") }}
{% endblock %}
',
'base' => '
{%- block content "" %}
',
);
$translator = new Translator('en', new MessageSelector());
$translator->addLoader('array', new ArrayLoader());
$translator->addResource('array', array('foo' => 'foo (messages)'), 'en');
$translator->addResource('array', array('foo' => 'foo (custom)'), 'en', 'custom');
$translator->addResource('array', array('foo' => 'foo (foo)'), 'en', 'foo');
$template = $this->getTemplate($templates, $translator);
$this->assertEquals('foo (foo)foo (custom)foo (foo)foo (custom)foo (foo)foo (custom)', trim($template->render(array())));
}
public function testDefaultTranslationDomainWithNamedArguments()
{
$templates = array(
'index' => '
{%- trans_default_domain "foo" %}
{%- block content %}
{{- "foo"|trans(arguments = {}, domain = "custom") }}
{{- "foo"|transchoice(count = 1) }}
{{- "foo"|transchoice(count = 1, arguments = {}, domain = "custom") }}
{{- "foo"|trans({}, domain = "custom") }}
{{- "foo"|trans({}, "custom", locale = "fr") }}
{{- "foo"|transchoice(1, arguments = {}, domain = "custom") }}
{{- "foo"|transchoice(1, {}, "custom", locale = "fr") }}
{% endblock %}
',
'base' => '
{%- block content "" %}
',
);
$translator = new Translator('en', new MessageSelector());
$translator->addLoader('array', new ArrayLoader());
$translator->addResource('array', array('foo' => 'foo (messages)'), 'en');
$translator->addResource('array', array('foo' => 'foo (custom)'), 'en', 'custom');
$translator->addResource('array', array('foo' => 'foo (foo)'), 'en', 'foo');
$translator->addResource('array', array('foo' => 'foo (fr)'), 'fr', 'custom');
$template = $this->getTemplate($templates, $translator);
$this->assertEquals('foo (custom)foo (foo)foo (custom)foo (custom)foo (fr)foo (custom)foo (fr)', trim($template->render(array())));
}
protected function getTemplate($template, $translator = null)
{
if (null === $translator) {
$translator = new Translator('en', new MessageSelector());
}
if (is_array($template)) {
$loader = new TwigArrayLoader($template);
} else {
$loader = new TwigArrayLoader(array('index' => $template));
}
$twig = new Environment($loader, array('debug' => true, 'cache' => false));
$twig->addExtension(new TranslationExtension($translator));
return $twig->loadTemplate('index');
}
}

View File

@@ -0,0 +1,92 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Bridge\Twig\Tests\Extension;
use Fig\Link\Link;
use PHPUnit\Framework\TestCase;
use Symfony\Bridge\Twig\Extension\WebLinkExtension;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\RequestStack;
/**
* @author Kévin Dunglas <dunglas@gmail.com>
*/
class WebLinkExtensionTest extends TestCase
{
/**
* @var Request
*/
private $request;
/**
* @var WebLinkExtension
*/
private $extension;
protected function setUp()
{
$this->request = new Request();
$requestStack = new RequestStack();
$requestStack->push($this->request);
$this->extension = new WebLinkExtension($requestStack);
}
public function testLink()
{
$this->assertEquals('/foo.css', $this->extension->link('/foo.css', 'preload', array('as' => 'style', 'nopush' => true)));
$link = (new Link('preload', '/foo.css'))->withAttribute('as', 'style')->withAttribute('nopush', true);
$this->assertEquals(array($link), array_values($this->request->attributes->get('_links')->getLinks()));
}
public function testPreload()
{
$this->assertEquals('/foo.css', $this->extension->preload('/foo.css', array('as' => 'style', 'crossorigin' => true)));
$link = (new Link('preload', '/foo.css'))->withAttribute('as', 'style')->withAttribute('crossorigin', true);
$this->assertEquals(array($link), array_values($this->request->attributes->get('_links')->getLinks()));
}
public function testDnsPrefetch()
{
$this->assertEquals('/foo.css', $this->extension->dnsPrefetch('/foo.css', array('as' => 'style', 'crossorigin' => true)));
$link = (new Link('dns-prefetch', '/foo.css'))->withAttribute('as', 'style')->withAttribute('crossorigin', true);
$this->assertEquals(array($link), array_values($this->request->attributes->get('_links')->getLinks()));
}
public function testPreconnect()
{
$this->assertEquals('/foo.css', $this->extension->preconnect('/foo.css', array('as' => 'style', 'crossorigin' => true)));
$link = (new Link('preconnect', '/foo.css'))->withAttribute('as', 'style')->withAttribute('crossorigin', true);
$this->assertEquals(array($link), array_values($this->request->attributes->get('_links')->getLinks()));
}
public function testPrefetch()
{
$this->assertEquals('/foo.css', $this->extension->prefetch('/foo.css', array('as' => 'style', 'crossorigin' => true)));
$link = (new Link('prefetch', '/foo.css'))->withAttribute('as', 'style')->withAttribute('crossorigin', true);
$this->assertEquals(array($link), array_values($this->request->attributes->get('_links')->getLinks()));
}
public function testPrerender()
{
$this->assertEquals('/foo.css', $this->extension->prerender('/foo.css', array('as' => 'style', 'crossorigin' => true)));
$link = (new Link('prerender', '/foo.css'))->withAttribute('as', 'style')->withAttribute('crossorigin', true);
$this->assertEquals(array($link), array_values($this->request->attributes->get('_links')->getLinks()));
}
}

View File

@@ -0,0 +1,83 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Bridge\Twig\Tests\Extension;
use PHPUnit\Framework\TestCase;
use Symfony\Bridge\Twig\Extension\WorkflowExtension;
use Symfony\Component\Workflow\Definition;
use Symfony\Component\Workflow\Registry;
use Symfony\Component\Workflow\SupportStrategy\ClassInstanceSupportStrategy;
use Symfony\Component\Workflow\Transition;
use Symfony\Component\Workflow\Workflow;
class WorkflowExtensionTest extends TestCase
{
private $extension;
protected function setUp()
{
$places = array('ordered', 'waiting_for_payment', 'processed');
$transitions = array(
new Transition('t1', 'ordered', 'waiting_for_payment'),
new Transition('t2', 'waiting_for_payment', 'processed'),
);
$definition = new Definition($places, $transitions);
$workflow = new Workflow($definition);
$registry = new Registry();
$registry->add($workflow, new ClassInstanceSupportStrategy(\stdClass::class));
$this->extension = new WorkflowExtension($registry);
}
public function testCanTransition()
{
$subject = new \stdClass();
$subject->marking = array();
$this->assertTrue($this->extension->canTransition($subject, 't1'));
$this->assertFalse($this->extension->canTransition($subject, 't2'));
}
public function testGetEnabledTransitions()
{
$subject = new \stdClass();
$subject->marking = array();
$transitions = $this->extension->getEnabledTransitions($subject);
$this->assertCount(1, $transitions);
$this->assertInstanceOf(Transition::class, $transitions[0]);
$this->assertSame('t1', $transitions[0]->getName());
}
public function testHasMarkedPlace()
{
$subject = new \stdClass();
$subject->marking = array();
$subject->marking = array('ordered' => 1, 'waiting_for_payment' => 1);
$this->assertTrue($this->extension->hasMarkedPlace($subject, 'ordered'));
$this->assertTrue($this->extension->hasMarkedPlace($subject, 'waiting_for_payment'));
$this->assertFalse($this->extension->hasMarkedPlace($subject, 'processed'));
}
public function testGetMarkedPlaces()
{
$subject = new \stdClass();
$subject->marking = array();
$subject->marking = array('ordered' => 1, 'waiting_for_payment' => 1);
$this->assertSame(array('ordered', 'waiting_for_payment'), $this->extension->getMarkedPlaces($subject));
$this->assertSame($subject->marking, $this->extension->getMarkedPlaces($subject, false));
}
}

View File

@@ -0,0 +1 @@
{% syntax error

View File

@@ -0,0 +1 @@
<h1>{{ 'Hi!'|trans }}</h1>

View File

@@ -0,0 +1,128 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Bridge\Twig\Tests\Node;
use PHPUnit\Framework\TestCase;
use Symfony\Bridge\Twig\Node\DumpNode;
use Twig\Compiler;
use Twig\Environment;
use Twig\Node\Expression\NameExpression;
use Twig\Node\Node;
class DumpNodeTest extends TestCase
{
public function testNoVar()
{
$node = new DumpNode('bar', null, 7);
$env = new Environment($this->getMockBuilder('Twig\Loader\LoaderInterface')->getMock());
$compiler = new Compiler($env);
$expected = <<<'EOTXT'
if ($this->env->isDebug()) {
$barvars = array();
foreach ($context as $barkey => $barval) {
if (!$barval instanceof \Twig\Template) {
$barvars[$barkey] = $barval;
}
}
// line 7
\Symfony\Component\VarDumper\VarDumper::dump($barvars);
}
EOTXT;
$this->assertSame($expected, $compiler->compile($node)->getSource());
}
public function testIndented()
{
$node = new DumpNode('bar', null, 7);
$env = new Environment($this->getMockBuilder('Twig\Loader\LoaderInterface')->getMock());
$compiler = new Compiler($env);
$expected = <<<'EOTXT'
if ($this->env->isDebug()) {
$barvars = array();
foreach ($context as $barkey => $barval) {
if (!$barval instanceof \Twig\Template) {
$barvars[$barkey] = $barval;
}
}
// line 7
\Symfony\Component\VarDumper\VarDumper::dump($barvars);
}
EOTXT;
$this->assertSame($expected, $compiler->compile($node, 1)->getSource());
}
public function testOneVar()
{
$vars = new Node(array(
new NameExpression('foo', 7),
));
$node = new DumpNode('bar', $vars, 7);
$env = new Environment($this->getMockBuilder('Twig\Loader\LoaderInterface')->getMock());
$compiler = new Compiler($env);
$expected = <<<'EOTXT'
if ($this->env->isDebug()) {
// line 7
\Symfony\Component\VarDumper\VarDumper::dump(%foo%);
}
EOTXT;
if (\PHP_VERSION_ID >= 70000) {
$expected = preg_replace('/%(.*?)%/', '($context["$1"] ?? null)', $expected);
} else {
$expected = preg_replace('/%(.*?)%/', '(isset($context["$1"]) ? $context["$1"] : null)', $expected);
}
$this->assertSame($expected, $compiler->compile($node)->getSource());
}
public function testMultiVars()
{
$vars = new Node(array(
new NameExpression('foo', 7),
new NameExpression('bar', 7),
));
$node = new DumpNode('bar', $vars, 7);
$env = new Environment($this->getMockBuilder('Twig\Loader\LoaderInterface')->getMock());
$compiler = new Compiler($env);
$expected = <<<'EOTXT'
if ($this->env->isDebug()) {
// line 7
\Symfony\Component\VarDumper\VarDumper::dump(array(
"foo" => %foo%,
"bar" => %bar%,
));
}
EOTXT;
if (\PHP_VERSION_ID >= 70000) {
$expected = preg_replace('/%(.*?)%/', '($context["$1"] ?? null)', $expected);
} else {
$expected = preg_replace('/%(.*?)%/', '(isset($context["$1"]) ? $context["$1"] : null)', $expected);
}
$this->assertSame($expected, $compiler->compile($node)->getSource());
}
}

View File

@@ -0,0 +1,82 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Bridge\Twig\Tests\Node;
use PHPUnit\Framework\TestCase;
use Symfony\Bridge\Twig\Node\FormThemeNode;
use Twig\Compiler;
use Twig\Environment;
use Twig\Node\Expression\ArrayExpression;
use Twig\Node\Expression\ConstantExpression;
use Twig\Node\Expression\NameExpression;
use Twig\Node\Node;
class FormThemeTest extends TestCase
{
public function testConstructor()
{
$form = new NameExpression('form', 0);
$resources = new Node(array(
new ConstantExpression('tpl1', 0),
new ConstantExpression('tpl2', 0),
));
$node = new FormThemeNode($form, $resources, 0);
$this->assertEquals($form, $node->getNode('form'));
$this->assertEquals($resources, $node->getNode('resources'));
}
public function testCompile()
{
$form = new NameExpression('form', 0);
$resources = new ArrayExpression(array(
new ConstantExpression(0, 0),
new ConstantExpression('tpl1', 0),
new ConstantExpression(1, 0),
new ConstantExpression('tpl2', 0),
), 0);
$node = new FormThemeNode($form, $resources, 0);
$compiler = new Compiler(new Environment($this->getMockBuilder('Twig\Loader\LoaderInterface')->getMock()));
$this->assertEquals(
sprintf(
'$this->env->getRuntime(\'Symfony\Bridge\Twig\Form\TwigRenderer\')->setTheme(%s, array(0 => "tpl1", 1 => "tpl2"));',
$this->getVariableGetter('form')
),
trim($compiler->compile($node)->getSource())
);
$resources = new ConstantExpression('tpl1', 0);
$node = new FormThemeNode($form, $resources, 0);
$this->assertEquals(
sprintf(
'$this->env->getRuntime(\'Symfony\Bridge\Twig\Form\TwigRenderer\')->setTheme(%s, "tpl1");',
$this->getVariableGetter('form')
),
trim($compiler->compile($node)->getSource())
);
}
protected function getVariableGetter($name)
{
if (\PHP_VERSION_ID >= 70000) {
return sprintf('($context["%s"] ?? null)', $name);
}
return sprintf('(isset($context["%s"]) ? $context["%1$s"] : null)', $name);
}
}

View File

@@ -0,0 +1,280 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Bridge\Twig\Tests\Node;
use PHPUnit\Framework\TestCase;
use Symfony\Bridge\Twig\Node\SearchAndRenderBlockNode;
use Twig\Compiler;
use Twig\Environment;
use Twig\Node\Expression\ArrayExpression;
use Twig\Node\Expression\ConditionalExpression;
use Twig\Node\Expression\ConstantExpression;
use Twig\Node\Expression\NameExpression;
use Twig\Node\Node;
class SearchAndRenderBlockNodeTest extends TestCase
{
public function testCompileWidget()
{
$arguments = new Node(array(
new NameExpression('form', 0),
));
$node = new SearchAndRenderBlockNode('form_widget', $arguments, 0);
$compiler = new Compiler(new Environment($this->getMockBuilder('Twig\Loader\LoaderInterface')->getMock()));
$this->assertEquals(
sprintf(
'$this->env->getRuntime(\'Symfony\Bridge\Twig\Form\TwigRenderer\')->searchAndRenderBlock(%s, \'widget\')',
$this->getVariableGetter('form')
),
trim($compiler->compile($node)->getSource())
);
}
public function testCompileWidgetWithVariables()
{
$arguments = new Node(array(
new NameExpression('form', 0),
new ArrayExpression(array(
new ConstantExpression('foo', 0),
new ConstantExpression('bar', 0),
), 0),
));
$node = new SearchAndRenderBlockNode('form_widget', $arguments, 0);
$compiler = new Compiler(new Environment($this->getMockBuilder('Twig\Loader\LoaderInterface')->getMock()));
$this->assertEquals(
sprintf(
'$this->env->getRuntime(\'Symfony\Bridge\Twig\Form\TwigRenderer\')->searchAndRenderBlock(%s, \'widget\', array("foo" => "bar"))',
$this->getVariableGetter('form')
),
trim($compiler->compile($node)->getSource())
);
}
public function testCompileLabelWithLabel()
{
$arguments = new Node(array(
new NameExpression('form', 0),
new ConstantExpression('my label', 0),
));
$node = new SearchAndRenderBlockNode('form_label', $arguments, 0);
$compiler = new Compiler(new Environment($this->getMockBuilder('Twig\Loader\LoaderInterface')->getMock()));
$this->assertEquals(
sprintf(
'$this->env->getRuntime(\'Symfony\Bridge\Twig\Form\TwigRenderer\')->searchAndRenderBlock(%s, \'label\', array("label" => "my label"))',
$this->getVariableGetter('form')
),
trim($compiler->compile($node)->getSource())
);
}
public function testCompileLabelWithNullLabel()
{
$arguments = new Node(array(
new NameExpression('form', 0),
new ConstantExpression(null, 0),
));
$node = new SearchAndRenderBlockNode('form_label', $arguments, 0);
$compiler = new Compiler(new Environment($this->getMockBuilder('Twig\Loader\LoaderInterface')->getMock()));
// "label" => null must not be included in the output!
// Otherwise the default label is overwritten with null.
$this->assertEquals(
sprintf(
'$this->env->getRuntime(\'Symfony\Bridge\Twig\Form\TwigRenderer\')->searchAndRenderBlock(%s, \'label\')',
$this->getVariableGetter('form')
),
trim($compiler->compile($node)->getSource())
);
}
public function testCompileLabelWithEmptyStringLabel()
{
$arguments = new Node(array(
new NameExpression('form', 0),
new ConstantExpression('', 0),
));
$node = new SearchAndRenderBlockNode('form_label', $arguments, 0);
$compiler = new Compiler(new Environment($this->getMockBuilder('Twig\Loader\LoaderInterface')->getMock()));
// "label" => null must not be included in the output!
// Otherwise the default label is overwritten with null.
$this->assertEquals(
sprintf(
'$this->env->getRuntime(\'Symfony\Bridge\Twig\Form\TwigRenderer\')->searchAndRenderBlock(%s, \'label\')',
$this->getVariableGetter('form')
),
trim($compiler->compile($node)->getSource())
);
}
public function testCompileLabelWithDefaultLabel()
{
$arguments = new Node(array(
new NameExpression('form', 0),
));
$node = new SearchAndRenderBlockNode('form_label', $arguments, 0);
$compiler = new Compiler(new Environment($this->getMockBuilder('Twig\Loader\LoaderInterface')->getMock()));
$this->assertEquals(
sprintf(
'$this->env->getRuntime(\'Symfony\Bridge\Twig\Form\TwigRenderer\')->searchAndRenderBlock(%s, \'label\')',
$this->getVariableGetter('form')
),
trim($compiler->compile($node)->getSource())
);
}
public function testCompileLabelWithAttributes()
{
$arguments = new Node(array(
new NameExpression('form', 0),
new ConstantExpression(null, 0),
new ArrayExpression(array(
new ConstantExpression('foo', 0),
new ConstantExpression('bar', 0),
), 0),
));
$node = new SearchAndRenderBlockNode('form_label', $arguments, 0);
$compiler = new Compiler(new Environment($this->getMockBuilder('Twig\Loader\LoaderInterface')->getMock()));
// "label" => null must not be included in the output!
// Otherwise the default label is overwritten with null.
// https://github.com/symfony/symfony/issues/5029
$this->assertEquals(
sprintf(
'$this->env->getRuntime(\'Symfony\Bridge\Twig\Form\TwigRenderer\')->searchAndRenderBlock(%s, \'label\', array("foo" => "bar"))',
$this->getVariableGetter('form')
),
trim($compiler->compile($node)->getSource())
);
}
public function testCompileLabelWithLabelAndAttributes()
{
$arguments = new Node(array(
new NameExpression('form', 0),
new ConstantExpression('value in argument', 0),
new ArrayExpression(array(
new ConstantExpression('foo', 0),
new ConstantExpression('bar', 0),
new ConstantExpression('label', 0),
new ConstantExpression('value in attributes', 0),
), 0),
));
$node = new SearchAndRenderBlockNode('form_label', $arguments, 0);
$compiler = new Compiler(new Environment($this->getMockBuilder('Twig\Loader\LoaderInterface')->getMock()));
$this->assertEquals(
sprintf(
'$this->env->getRuntime(\'Symfony\Bridge\Twig\Form\TwigRenderer\')->searchAndRenderBlock(%s, \'label\', array("foo" => "bar", "label" => "value in argument"))',
$this->getVariableGetter('form')
),
trim($compiler->compile($node)->getSource())
);
}
public function testCompileLabelWithLabelThatEvaluatesToNull()
{
$arguments = new Node(array(
new NameExpression('form', 0),
new ConditionalExpression(
// if
new ConstantExpression(true, 0),
// then
new ConstantExpression(null, 0),
// else
new ConstantExpression(null, 0),
0
),
));
$node = new SearchAndRenderBlockNode('form_label', $arguments, 0);
$compiler = new Compiler(new Environment($this->getMockBuilder('Twig\Loader\LoaderInterface')->getMock()));
// "label" => null must not be included in the output!
// Otherwise the default label is overwritten with null.
// https://github.com/symfony/symfony/issues/5029
$this->assertEquals(
sprintf(
'$this->env->getRuntime(\'Symfony\Bridge\Twig\Form\TwigRenderer\')->searchAndRenderBlock(%s, \'label\', (twig_test_empty($_label_ = ((true) ? (null) : (null))) ? array() : array("label" => $_label_)))',
$this->getVariableGetter('form')
),
trim($compiler->compile($node)->getSource())
);
}
public function testCompileLabelWithLabelThatEvaluatesToNullAndAttributes()
{
$arguments = new Node(array(
new NameExpression('form', 0),
new ConditionalExpression(
// if
new ConstantExpression(true, 0),
// then
new ConstantExpression(null, 0),
// else
new ConstantExpression(null, 0),
0
),
new ArrayExpression(array(
new ConstantExpression('foo', 0),
new ConstantExpression('bar', 0),
new ConstantExpression('label', 0),
new ConstantExpression('value in attributes', 0),
), 0),
));
$node = new SearchAndRenderBlockNode('form_label', $arguments, 0);
$compiler = new Compiler(new Environment($this->getMockBuilder('Twig\Loader\LoaderInterface')->getMock()));
// "label" => null must not be included in the output!
// Otherwise the default label is overwritten with null.
// https://github.com/symfony/symfony/issues/5029
$this->assertEquals(
sprintf(
'$this->env->getRuntime(\'Symfony\Bridge\Twig\Form\TwigRenderer\')->searchAndRenderBlock(%s, \'label\', array("foo" => "bar", "label" => "value in attributes") + (twig_test_empty($_label_ = ((true) ? (null) : (null))) ? array() : array("label" => $_label_)))',
$this->getVariableGetter('form')
),
trim($compiler->compile($node)->getSource())
);
}
protected function getVariableGetter($name)
{
if (\PHP_VERSION_ID >= 70000) {
return sprintf('($context["%s"] ?? null)', $name);
}
return sprintf('(isset($context["%s"]) ? $context["%1$s"] : null)', $name);
}
}

View File

@@ -0,0 +1,66 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Bridge\Twig\Tests\Node;
use PHPUnit\Framework\TestCase;
use Symfony\Bridge\Twig\Node\TransNode;
use Twig\Compiler;
use Twig\Environment;
use Twig\Node\Expression\NameExpression;
use Twig\Node\TextNode;
/**
* @author Asmir Mustafic <goetas@gmail.com>
*/
class TransNodeTest extends TestCase
{
public function testCompileStrict()
{
$body = new TextNode('trans %var%', 0);
$vars = new NameExpression('foo', 0);
$node = new TransNode($body, null, null, $vars);
$env = new Environment($this->getMockBuilder('Twig\Loader\LoaderInterface')->getMock(), array('strict_variables' => true));
$compiler = new Compiler($env);
$this->assertEquals(
sprintf(
'echo $this->env->getExtension(\'Symfony\Bridge\Twig\Extension\TranslationExtension\')->getTranslator()->trans("trans %%var%%", array_merge(array("%%var%%" => %s), %s), "messages");',
$this->getVariableGetterWithoutStrictCheck('var'),
$this->getVariableGetterWithStrictCheck('foo')
),
trim($compiler->compile($node)->getSource())
);
}
protected function getVariableGetterWithoutStrictCheck($name)
{
if (\PHP_VERSION_ID >= 70000) {
return sprintf('($context["%s"] ?? null)', $name);
}
return sprintf('(isset($context["%s"]) ? $context["%1$s"] : null)', $name);
}
protected function getVariableGetterWithStrictCheck($name)
{
if (Environment::MAJOR_VERSION >= 2) {
return sprintf('(isset($context["%s"]) || array_key_exists("%1$s", $context) ? $context["%1$s"] : (function () { throw new Twig_Error_Runtime(\'Variable "%1$s" does not exist.\', 0, $this->getSourceContext()); })())', $name);
}
if (\PHP_VERSION_ID >= 70000) {
return sprintf('($context["%s"] ?? $this->getContext($context, "%1$s"))', $name);
}
return sprintf('(isset($context["%s"]) ? $context["%1$s"] : $this->getContext($context, "%1$s"))', $name);
}
}

View File

@@ -0,0 +1,25 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Bridge\Twig\Tests\NodeVisitor;
use PHPUnit\Framework\TestCase;
use Symfony\Bridge\Twig\NodeVisitor\Scope;
class ScopeTest extends TestCase
{
public function testScopeInitiation()
{
$scope = new Scope();
$scope->enter();
$this->assertNull($scope->get('test'));
}
}

View File

@@ -0,0 +1,93 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Bridge\Twig\Tests\NodeVisitor;
use PHPUnit\Framework\TestCase;
use Symfony\Bridge\Twig\NodeVisitor\TranslationDefaultDomainNodeVisitor;
use Symfony\Bridge\Twig\NodeVisitor\TranslationNodeVisitor;
use Twig\Environment;
use Twig\Node\Expression\ArrayExpression;
use Twig\Node\Node;
class TranslationDefaultDomainNodeVisitorTest extends TestCase
{
private static $message = 'message';
private static $domain = 'domain';
/** @dataProvider getDefaultDomainAssignmentTestData */
public function testDefaultDomainAssignment(Node $node)
{
$env = new Environment($this->getMockBuilder('Twig\Loader\LoaderInterface')->getMock(), array('cache' => false, 'autoescape' => false, 'optimizations' => 0));
$visitor = new TranslationDefaultDomainNodeVisitor();
// visit trans_default_domain tag
$defaultDomain = TwigNodeProvider::getTransDefaultDomainTag(self::$domain);
$visitor->enterNode($defaultDomain, $env);
$visitor->leaveNode($defaultDomain, $env);
// visit tested node
$enteredNode = $visitor->enterNode($node, $env);
$leavedNode = $visitor->leaveNode($node, $env);
$this->assertSame($node, $enteredNode);
$this->assertSame($node, $leavedNode);
// extracting tested node messages
$visitor = new TranslationNodeVisitor();
$visitor->enable();
$visitor->enterNode($node, $env);
$visitor->leaveNode($node, $env);
$this->assertEquals(array(array(self::$message, self::$domain)), $visitor->getMessages());
}
/** @dataProvider getDefaultDomainAssignmentTestData */
public function testNewModuleWithoutDefaultDomainTag(Node $node)
{
$env = new Environment($this->getMockBuilder('Twig\Loader\LoaderInterface')->getMock(), array('cache' => false, 'autoescape' => false, 'optimizations' => 0));
$visitor = new TranslationDefaultDomainNodeVisitor();
// visit trans_default_domain tag
$newModule = TwigNodeProvider::getModule('test');
$visitor->enterNode($newModule, $env);
$visitor->leaveNode($newModule, $env);
// visit tested node
$enteredNode = $visitor->enterNode($node, $env);
$leavedNode = $visitor->leaveNode($node, $env);
$this->assertSame($node, $enteredNode);
$this->assertSame($node, $leavedNode);
// extracting tested node messages
$visitor = new TranslationNodeVisitor();
$visitor->enable();
$visitor->enterNode($node, $env);
$visitor->leaveNode($node, $env);
$this->assertEquals(array(array(self::$message, null)), $visitor->getMessages());
}
public function getDefaultDomainAssignmentTestData()
{
return array(
array(TwigNodeProvider::getTransFilter(self::$message)),
array(TwigNodeProvider::getTransChoiceFilter(self::$message)),
array(TwigNodeProvider::getTransTag(self::$message)),
// with named arguments
array(TwigNodeProvider::getTransFilter(self::$message, null, array(
'arguments' => new ArrayExpression(array(), 0),
))),
array(TwigNodeProvider::getTransChoiceFilter(self::$message), null, array(
'arguments' => new ArrayExpression(array(), 0),
)),
);
}
}

View File

@@ -0,0 +1,67 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Bridge\Twig\Tests\NodeVisitor;
use PHPUnit\Framework\TestCase;
use Symfony\Bridge\Twig\NodeVisitor\TranslationNodeVisitor;
use Twig\Environment;
use Twig\Node\Expression\ArrayExpression;
use Twig\Node\Expression\ConstantExpression;
use Twig\Node\Expression\FilterExpression;
use Twig\Node\Expression\NameExpression;
use Twig\Node\Node;
class TranslationNodeVisitorTest extends TestCase
{
/** @dataProvider getMessagesExtractionTestData */
public function testMessagesExtraction(Node $node, array $expectedMessages)
{
$env = new Environment($this->getMockBuilder('Twig\Loader\LoaderInterface')->getMock(), array('cache' => false, 'autoescape' => false, 'optimizations' => 0));
$visitor = new TranslationNodeVisitor();
$visitor->enable();
$visitor->enterNode($node, $env);
$visitor->leaveNode($node, $env);
$this->assertEquals($expectedMessages, $visitor->getMessages());
}
public function testMessageExtractionWithInvalidDomainNode()
{
$message = 'new key';
$node = new FilterExpression(
new ConstantExpression($message, 0),
new ConstantExpression('trans', 0),
new Node(array(
new ArrayExpression(array(), 0),
new NameExpression('variable', 0),
)),
0
);
$this->testMessagesExtraction($node, array(array($message, TranslationNodeVisitor::UNDEFINED_DOMAIN)));
}
public function getMessagesExtractionTestData()
{
$message = 'new key';
$domain = 'domain';
return array(
array(TwigNodeProvider::getTransFilter($message), array(array($message, null))),
array(TwigNodeProvider::getTransChoiceFilter($message), array(array($message, null))),
array(TwigNodeProvider::getTransTag($message), array(array($message, null))),
array(TwigNodeProvider::getTransFilter($message, $domain), array(array($message, $domain))),
array(TwigNodeProvider::getTransChoiceFilter($message, $domain), array(array($message, $domain))),
array(TwigNodeProvider::getTransTag($message, $domain), array(array($message, $domain))),
);
}
}

View File

@@ -0,0 +1,88 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Bridge\Twig\Tests\NodeVisitor;
use Symfony\Bridge\Twig\Node\TransDefaultDomainNode;
use Symfony\Bridge\Twig\Node\TransNode;
use Twig\Node\BodyNode;
use Twig\Node\Expression\ArrayExpression;
use Twig\Node\Expression\ConstantExpression;
use Twig\Node\Expression\FilterExpression;
use Twig\Node\ModuleNode;
use Twig\Node\Node;
use Twig\Source;
class TwigNodeProvider
{
public static function getModule($content)
{
return new ModuleNode(
new ConstantExpression($content, 0),
null,
new ArrayExpression(array(), 0),
new ArrayExpression(array(), 0),
new ArrayExpression(array(), 0),
null,
new Source('', '')
);
}
public static function getTransFilter($message, $domain = null, $arguments = null)
{
if (!$arguments) {
$arguments = $domain ? array(
new ArrayExpression(array(), 0),
new ConstantExpression($domain, 0),
) : array();
}
return new FilterExpression(
new ConstantExpression($message, 0),
new ConstantExpression('trans', 0),
new Node($arguments),
0
);
}
public static function getTransChoiceFilter($message, $domain = null, $arguments = null)
{
if (!$arguments) {
$arguments = $domain ? array(
new ConstantExpression(0, 0),
new ArrayExpression(array(), 0),
new ConstantExpression($domain, 0),
) : array();
}
return new FilterExpression(
new ConstantExpression($message, 0),
new ConstantExpression('transchoice', 0),
new Node($arguments),
0
);
}
public static function getTransTag($message, $domain = null)
{
return new TransNode(
new BodyNode(array(), array('data' => $message)),
$domain ? new ConstantExpression($domain, 0) : null
);
}
public static function getTransDefaultDomainTag($domain)
{
return new TransDefaultDomainNode(
new ConstantExpression($domain, 0)
);
}
}

View File

@@ -0,0 +1,105 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Bridge\Twig\Tests\TokenParser;
use PHPUnit\Framework\TestCase;
use Symfony\Bridge\Twig\TokenParser\FormThemeTokenParser;
use Symfony\Bridge\Twig\Node\FormThemeNode;
use Twig\Environment;
use Twig\Node\Expression\ArrayExpression;
use Twig\Node\Expression\ConstantExpression;
use Twig\Node\Expression\NameExpression;
use Twig\Parser;
use Twig\Source;
class FormThemeTokenParserTest extends TestCase
{
/**
* @dataProvider getTestsForFormTheme
*/
public function testCompile($source, $expected)
{
$env = new Environment($this->getMockBuilder('Twig\Loader\LoaderInterface')->getMock(), array('cache' => false, 'autoescape' => false, 'optimizations' => 0));
$env->addTokenParser(new FormThemeTokenParser());
$stream = $env->tokenize(new Source($source, ''));
$parser = new Parser($env);
$this->assertEquals($expected, $parser->parse($stream)->getNode('body')->getNode(0));
}
public function getTestsForFormTheme()
{
return array(
array(
'{% form_theme form "tpl1" %}',
new FormThemeNode(
new NameExpression('form', 1),
new ArrayExpression(array(
new ConstantExpression(0, 1),
new ConstantExpression('tpl1', 1),
), 1),
1,
'form_theme'
),
),
array(
'{% form_theme form "tpl1" "tpl2" %}',
new FormThemeNode(
new NameExpression('form', 1),
new ArrayExpression(array(
new ConstantExpression(0, 1),
new ConstantExpression('tpl1', 1),
new ConstantExpression(1, 1),
new ConstantExpression('tpl2', 1),
), 1),
1,
'form_theme'
),
),
array(
'{% form_theme form with "tpl1" %}',
new FormThemeNode(
new NameExpression('form', 1),
new ConstantExpression('tpl1', 1),
1,
'form_theme'
),
),
array(
'{% form_theme form with ["tpl1"] %}',
new FormThemeNode(
new NameExpression('form', 1),
new ArrayExpression(array(
new ConstantExpression(0, 1),
new ConstantExpression('tpl1', 1),
), 1),
1,
'form_theme'
),
),
array(
'{% form_theme form with ["tpl1", "tpl2"] %}',
new FormThemeNode(
new NameExpression('form', 1),
new ArrayExpression(array(
new ConstantExpression(0, 1),
new ConstantExpression('tpl1', 1),
new ConstantExpression(1, 1),
new ConstantExpression('tpl2', 1),
), 1),
1,
'form_theme'
),
),
);
}
}

View File

@@ -0,0 +1,152 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Bridge\Twig\Tests\Translation;
use PHPUnit\Framework\TestCase;
use Symfony\Bridge\Twig\Extension\TranslationExtension;
use Symfony\Bridge\Twig\Translation\TwigExtractor;
use Symfony\Component\Translation\MessageCatalogue;
use Twig\Environment;
use Twig\Error\Error;
use Twig\Loader\ArrayLoader;
class TwigExtractorTest extends TestCase
{
/**
* @dataProvider getExtractData
*/
public function testExtract($template, $messages)
{
$loader = $this->getMockBuilder('Twig\Loader\LoaderInterface')->getMock();
$twig = new Environment($loader, array(
'strict_variables' => true,
'debug' => true,
'cache' => false,
'autoescape' => false,
));
$twig->addExtension(new TranslationExtension($this->getMockBuilder('Symfony\Component\Translation\TranslatorInterface')->getMock()));
$extractor = new TwigExtractor($twig);
$extractor->setPrefix('prefix');
$catalogue = new MessageCatalogue('en');
$m = new \ReflectionMethod($extractor, 'extractTemplate');
$m->setAccessible(true);
$m->invoke($extractor, $template, $catalogue);
foreach ($messages as $key => $domain) {
$this->assertTrue($catalogue->has($key, $domain));
$this->assertEquals('prefix'.$key, $catalogue->get($key, $domain));
}
}
public function getExtractData()
{
return array(
array('{{ "new key" | trans() }}', array('new key' => 'messages')),
array('{{ "new key" | trans() | upper }}', array('new key' => 'messages')),
array('{{ "new key" | trans({}, "domain") }}', array('new key' => 'domain')),
array('{{ "new key" | transchoice(1) }}', array('new key' => 'messages')),
array('{{ "new key" | transchoice(1) | upper }}', array('new key' => 'messages')),
array('{{ "new key" | transchoice(1, {}, "domain") }}', array('new key' => 'domain')),
array('{% trans %}new key{% endtrans %}', array('new key' => 'messages')),
array('{% trans %} new key {% endtrans %}', array('new key' => 'messages')),
array('{% trans from "domain" %}new key{% endtrans %}', array('new key' => 'domain')),
array('{% set foo = "new key" | trans %}', array('new key' => 'messages')),
array('{{ 1 ? "new key" | trans : "another key" | trans }}', array('new key' => 'messages', 'another key' => 'messages')),
// make sure 'trans_default_domain' tag is supported
array('{% trans_default_domain "domain" %}{{ "new key"|trans }}', array('new key' => 'domain')),
array('{% trans_default_domain "domain" %}{{ "new key"|transchoice }}', array('new key' => 'domain')),
array('{% trans_default_domain "domain" %}{% trans %}new key{% endtrans %}', array('new key' => 'domain')),
// make sure this works with twig's named arguments
array('{{ "new key" | trans(domain="domain") }}', array('new key' => 'domain')),
array('{{ "new key" | transchoice(domain="domain", count=1) }}', array('new key' => 'domain')),
);
}
/**
* @expectedException \Twig\Error\Error
* @dataProvider resourcesWithSyntaxErrorsProvider
*/
public function testExtractSyntaxError($resources)
{
$twig = new Environment($this->getMockBuilder('Twig\Loader\LoaderInterface')->getMock());
$twig->addExtension(new TranslationExtension($this->getMockBuilder('Symfony\Component\Translation\TranslatorInterface')->getMock()));
$extractor = new TwigExtractor($twig);
try {
$extractor->extract($resources, new MessageCatalogue('en'));
} catch (Error $e) {
if (method_exists($e, 'getSourceContext')) {
$this->assertSame(dirname(__DIR__).strtr('/Fixtures/extractor/syntax_error.twig', '/', DIRECTORY_SEPARATOR), $e->getFile());
$this->assertSame(1, $e->getLine());
$this->assertSame('Unclosed "block".', $e->getMessage());
} else {
$this->expectExceptionMessageRegExp('/Unclosed "block" in ".*extractor(\\/|\\\\)syntax_error\\.twig" at line 1/');
}
throw $e;
}
}
/**
* @return array
*/
public function resourcesWithSyntaxErrorsProvider()
{
return array(
array(__DIR__.'/../Fixtures'),
array(__DIR__.'/../Fixtures/extractor/syntax_error.twig'),
array(new \SplFileInfo(__DIR__.'/../Fixtures/extractor/syntax_error.twig')),
);
}
/**
* @dataProvider resourceProvider
*/
public function testExtractWithFiles($resource)
{
$loader = new ArrayLoader(array());
$twig = new Environment($loader, array(
'strict_variables' => true,
'debug' => true,
'cache' => false,
'autoescape' => false,
));
$twig->addExtension(new TranslationExtension($this->getMockBuilder('Symfony\Component\Translation\TranslatorInterface')->getMock()));
$extractor = new TwigExtractor($twig);
$catalogue = new MessageCatalogue('en');
$extractor->extract($resource, $catalogue);
$this->assertTrue($catalogue->has('Hi!', 'messages'));
$this->assertEquals('Hi!', $catalogue->get('Hi!', 'messages'));
}
/**
* @return array
*/
public function resourceProvider()
{
$directory = __DIR__.'/../Fixtures/extractor/';
return array(
array($directory.'with_translations.html.twig'),
array(array($directory.'with_translations.html.twig')),
array(array(new \SplFileInfo($directory.'with_translations.html.twig'))),
array(new \ArrayObject(array($directory.'with_translations.html.twig'))),
array(new \ArrayObject(array(new \SplFileInfo($directory.'with_translations.html.twig')))),
);
}
}

View File

@@ -0,0 +1,81 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Bridge\Twig\Tests;
use PHPUnit\Framework\TestCase;
use Symfony\Bridge\Twig\TwigEngine;
use Symfony\Component\Templating\TemplateReference;
use Twig\Environment;
use Twig\Loader\ArrayLoader;
class TwigEngineTest extends TestCase
{
public function testExistsWithTemplateInstances()
{
$engine = $this->getTwig();
$this->assertTrue($engine->exists($this->getMockForAbstractClass('Twig\Template', array(), '', false)));
}
public function testExistsWithNonExistentTemplates()
{
$engine = $this->getTwig();
$this->assertFalse($engine->exists('foobar'));
$this->assertFalse($engine->exists(new TemplateReference('foorbar')));
}
public function testExistsWithTemplateWithSyntaxErrors()
{
$engine = $this->getTwig();
$this->assertTrue($engine->exists('error'));
$this->assertTrue($engine->exists(new TemplateReference('error')));
}
public function testExists()
{
$engine = $this->getTwig();
$this->assertTrue($engine->exists('index'));
$this->assertTrue($engine->exists(new TemplateReference('index')));
}
public function testRender()
{
$engine = $this->getTwig();
$this->assertSame('foo', $engine->render('index'));
$this->assertSame('foo', $engine->render(new TemplateReference('index')));
}
/**
* @expectedException \Twig\Error\SyntaxError
*/
public function testRenderWithError()
{
$engine = $this->getTwig();
$engine->render(new TemplateReference('error'));
}
protected function getTwig()
{
$twig = new Environment(new ArrayLoader(array(
'index' => 'foo',
'error' => '{{ foo }',
)));
$parser = $this->getMockBuilder('Symfony\Component\Templating\TemplateNameParserInterface')->getMock();
return new TwigEngine($twig, $parser);
}
}