From 23ead95798782c07ad06e20f8cad92027d21ed1a Mon Sep 17 00:00:00 2001 From: "hubert.lenoir" Date: Wed, 12 Mar 2025 09:31:18 +0100 Subject: [PATCH] Rework PhpAstExtractor tests organization --- .../Extractor/Visitor/AbstractVisitor.php | 3 +- .../Tests/Extractor/PhpAstExtractorTest.php | 207 ++---------------- .../Extractor/Visitor/AbstractVisitorTest.php | 27 +++ .../Visitor/ConstraintVisitorTest.php | 47 ++++ .../Visitor/TransMethodVisitorTest.php | 115 ++++++++++ .../TranslatableMessageVisitorTest.php | 81 +++++++ .../validator-constraints.php | 40 ++++ .../extract-files/resource.format.engine | 0 .../this.is.a.template.format.engine | 0 .../extract-files/translation.html.php | 1 + .../form-type-visitor/form-type.php | 72 ++++++ .../translatable-short-fqn.html.php | 47 ++++ .../translatable-short.html.php | 47 ++++ .../translation-73.html.php | 13 ++ .../trans-method-visitor/translation.html.php | 70 ++++++ .../translatable-fqn.html.php | 47 ++++ .../translatable.html.php | 47 ++++ 17 files changed, 669 insertions(+), 195 deletions(-) create mode 100644 src/Symfony/Component/Translation/Tests/Extractor/Visitor/AbstractVisitorTest.php create mode 100644 src/Symfony/Component/Translation/Tests/Extractor/Visitor/ConstraintVisitorTest.php create mode 100644 src/Symfony/Component/Translation/Tests/Extractor/Visitor/TransMethodVisitorTest.php create mode 100644 src/Symfony/Component/Translation/Tests/Extractor/Visitor/TranslatableMessageVisitorTest.php create mode 100644 src/Symfony/Component/Translation/Tests/Fixtures/extractor-php-ast/constraint-visitor/validator-constraints.php create mode 100644 src/Symfony/Component/Translation/Tests/Fixtures/extractor-php-ast/extract-files/resource.format.engine create mode 100644 src/Symfony/Component/Translation/Tests/Fixtures/extractor-php-ast/extract-files/this.is.a.template.format.engine create mode 100644 src/Symfony/Component/Translation/Tests/Fixtures/extractor-php-ast/extract-files/translation.html.php create mode 100644 src/Symfony/Component/Translation/Tests/Fixtures/extractor-php-ast/form-type-visitor/form-type.php create mode 100644 src/Symfony/Component/Translation/Tests/Fixtures/extractor-php-ast/trans-method-visitor/translatable-short-fqn.html.php create mode 100644 src/Symfony/Component/Translation/Tests/Fixtures/extractor-php-ast/trans-method-visitor/translatable-short.html.php create mode 100644 src/Symfony/Component/Translation/Tests/Fixtures/extractor-php-ast/trans-method-visitor/translation-73.html.php create mode 100644 src/Symfony/Component/Translation/Tests/Fixtures/extractor-php-ast/trans-method-visitor/translation.html.php create mode 100644 src/Symfony/Component/Translation/Tests/Fixtures/extractor-php-ast/translatable-message-visitor/translatable-fqn.html.php create mode 100644 src/Symfony/Component/Translation/Tests/Fixtures/extractor-php-ast/translatable-message-visitor/translatable.html.php diff --git a/src/Symfony/Component/Translation/Extractor/Visitor/AbstractVisitor.php b/src/Symfony/Component/Translation/Extractor/Visitor/AbstractVisitor.php index c336896169a8b..4fc514ba19c7f 100644 --- a/src/Symfony/Component/Translation/Extractor/Visitor/AbstractVisitor.php +++ b/src/Symfony/Component/Translation/Extractor/Visitor/AbstractVisitor.php @@ -35,8 +35,7 @@ protected function addMessageToCatalogue(string $message, ?string $domain, int $ $domain ??= 'messages'; $this->catalogue->set($message, $this->messagePrefix.$message, $domain); $metadata = $this->catalogue->getMetadata($message, $domain) ?? []; - $normalizedFilename = preg_replace('{[\\\\/]+}', '/', $this->file); - $metadata['sources'][] = $normalizedFilename.':'.$line; + $metadata['sources'][] = $this->file->getPathname().':'.$line; $this->catalogue->setMetadata($message, $metadata, $domain); } diff --git a/src/Symfony/Component/Translation/Tests/Extractor/PhpAstExtractorTest.php b/src/Symfony/Component/Translation/Tests/Extractor/PhpAstExtractorTest.php index 658164a37150d..13e02f87aad73 100644 --- a/src/Symfony/Component/Translation/Tests/Extractor/PhpAstExtractorTest.php +++ b/src/Symfony/Component/Translation/Tests/Extractor/PhpAstExtractorTest.php @@ -13,225 +13,46 @@ use PHPUnit\Framework\TestCase; use Symfony\Component\Translation\Extractor\PhpAstExtractor; -use Symfony\Component\Translation\Extractor\Visitor\ConstraintVisitor; -use Symfony\Component\Translation\Extractor\Visitor\TranslatableMessageVisitor; use Symfony\Component\Translation\Extractor\Visitor\TransMethodVisitor; use Symfony\Component\Translation\MessageCatalogue; final class PhpAstExtractorTest extends TestCase { - public const OTHER_DOMAIN = 'not_messages'; + private const FIXTURES_FOLDER = __DIR__ . '/../Fixtures/extractor-php-ast/extract-files/'; /** * @dataProvider resourcesProvider */ - public function testExtraction(iterable|string $resource) + public function testExtractFiles(iterable|string $resource) { - $extractor = new PhpAstExtractor([ - new TransMethodVisitor(), - new TranslatableMessageVisitor(), - new ConstraintVisitor([ - 'NotBlank', - 'Isbn', - 'Length', - ], new TranslatableMessageVisitor()), - ]); - $extractor->setPrefix('prefix'); + $extractor = new PhpAstExtractor([new TransMethodVisitor()]); $catalogue = new MessageCatalogue('en'); $extractor->extract($resource, $catalogue); - $expectedHeredoc = << [ - 'translatable single-quoted key' => 'prefixtranslatable single-quoted key', - 'translatable double-quoted key' => 'prefixtranslatable double-quoted key', - 'translatable heredoc key' => 'prefixtranslatable heredoc key', - 'translatable nowdoc key' => 'prefixtranslatable nowdoc key', - "translatable double-quoted key with whitespace and escaped \$\n\" sequences" => "prefixtranslatable double-quoted key with whitespace and escaped \$\n\" sequences", - 'translatable single-quoted key with whitespace and nonescaped \$\n\' sequences' => 'prefixtranslatable single-quoted key with whitespace and nonescaped \$\n\' sequences', - 'translatable single-quoted key with "quote mark at the end"' => 'prefixtranslatable single-quoted key with "quote mark at the end"', - 'translatable '.$expectedHeredoc => 'prefixtranslatable '.$expectedHeredoc, - 'translatable '.$expectedNowdoc => 'prefixtranslatable '.$expectedNowdoc, - 'translatable concatenated message with heredoc and nowdoc' => 'prefixtranslatable concatenated message with heredoc and nowdoc', - 'translatable default domain' => 'prefixtranslatable default domain', - 'translatable-fqn single-quoted key' => 'prefixtranslatable-fqn single-quoted key', - 'translatable-fqn double-quoted key' => 'prefixtranslatable-fqn double-quoted key', - 'translatable-fqn heredoc key' => 'prefixtranslatable-fqn heredoc key', - 'translatable-fqn nowdoc key' => 'prefixtranslatable-fqn nowdoc key', - "translatable-fqn double-quoted key with whitespace and escaped \$\n\" sequences" => "prefixtranslatable-fqn double-quoted key with whitespace and escaped \$\n\" sequences", - 'translatable-fqn single-quoted key with whitespace and nonescaped \$\n\' sequences' => 'prefixtranslatable-fqn single-quoted key with whitespace and nonescaped \$\n\' sequences', - 'translatable-fqn single-quoted key with "quote mark at the end"' => 'prefixtranslatable-fqn single-quoted key with "quote mark at the end"', - 'translatable-fqn '.$expectedHeredoc => 'prefixtranslatable-fqn '.$expectedHeredoc, - 'translatable-fqn '.$expectedNowdoc => 'prefixtranslatable-fqn '.$expectedNowdoc, - 'translatable-fqn concatenated message with heredoc and nowdoc' => 'prefixtranslatable-fqn concatenated message with heredoc and nowdoc', - 'translatable-fqn default domain' => 'prefixtranslatable-fqn default domain', - 'translatable-short single-quoted key' => 'prefixtranslatable-short single-quoted key', - 'translatable-short double-quoted key' => 'prefixtranslatable-short double-quoted key', - 'translatable-short heredoc key' => 'prefixtranslatable-short heredoc key', - 'translatable-short nowdoc key' => 'prefixtranslatable-short nowdoc key', - "translatable-short double-quoted key with whitespace and escaped \$\n\" sequences" => "prefixtranslatable-short double-quoted key with whitespace and escaped \$\n\" sequences", - 'translatable-short single-quoted key with whitespace and nonescaped \$\n\' sequences' => 'prefixtranslatable-short single-quoted key with whitespace and nonescaped \$\n\' sequences', - 'translatable-short single-quoted key with "quote mark at the end"' => 'prefixtranslatable-short single-quoted key with "quote mark at the end"', - 'translatable-short '.$expectedHeredoc => 'prefixtranslatable-short '.$expectedHeredoc, - 'translatable-short '.$expectedNowdoc => 'prefixtranslatable-short '.$expectedNowdoc, - 'translatable-short concatenated message with heredoc and nowdoc' => 'prefixtranslatable-short concatenated message with heredoc and nowdoc', - 'translatable-short default domain' => 'prefixtranslatable-short default domain', - 'translatable-short-fqn single-quoted key' => 'prefixtranslatable-short-fqn single-quoted key', - 'translatable-short-fqn double-quoted key' => 'prefixtranslatable-short-fqn double-quoted key', - 'translatable-short-fqn heredoc key' => 'prefixtranslatable-short-fqn heredoc key', - 'translatable-short-fqn nowdoc key' => 'prefixtranslatable-short-fqn nowdoc key', - "translatable-short-fqn double-quoted key with whitespace and escaped \$\n\" sequences" => "prefixtranslatable-short-fqn double-quoted key with whitespace and escaped \$\n\" sequences", - 'translatable-short-fqn single-quoted key with whitespace and nonescaped \$\n\' sequences' => 'prefixtranslatable-short-fqn single-quoted key with whitespace and nonescaped \$\n\' sequences', - 'translatable-short-fqn single-quoted key with "quote mark at the end"' => 'prefixtranslatable-short-fqn single-quoted key with "quote mark at the end"', - 'translatable-short-fqn '.$expectedHeredoc => 'prefixtranslatable-short-fqn '.$expectedHeredoc, - 'translatable-short-fqn '.$expectedNowdoc => 'prefixtranslatable-short-fqn '.$expectedNowdoc, - 'translatable-short-fqn concatenated message with heredoc and nowdoc' => 'prefixtranslatable-short-fqn concatenated message with heredoc and nowdoc', - 'translatable-short-fqn default domain' => 'prefixtranslatable-short-fqn default domain', - 'single-quoted key' => 'prefixsingle-quoted key', - 'double-quoted key' => 'prefixdouble-quoted key', - 'heredoc key' => 'prefixheredoc key', - 'nowdoc key' => 'prefixnowdoc key', - "double-quoted key with whitespace and escaped \$\n\" sequences" => "prefixdouble-quoted key with whitespace and escaped \$\n\" sequences", - 'single-quoted key with whitespace and nonescaped \$\n\' sequences' => 'prefixsingle-quoted key with whitespace and nonescaped \$\n\' sequences', - 'single-quoted key with "quote mark at the end"' => 'prefixsingle-quoted key with "quote mark at the end"', - $expectedHeredoc => 'prefix'.$expectedHeredoc, - $expectedNowdoc => 'prefix'.$expectedNowdoc, - 'concatenated message with heredoc and nowdoc' => 'prefixconcatenated message with heredoc and nowdoc', - 'default domain' => 'prefixdefault domain', - 'mix-named-arguments' => 'prefixmix-named-arguments', - 'mix-named-arguments-locale' => 'prefixmix-named-arguments-locale', - 'mix-named-arguments-without-domain' => 'prefixmix-named-arguments-without-domain', - ], - 'not_messages' => [ - 'translatable other-domain-test-no-params-short-array' => 'prefixtranslatable other-domain-test-no-params-short-array', - 'translatable other-domain-test-no-params-long-array' => 'prefixtranslatable other-domain-test-no-params-long-array', - 'translatable other-domain-test-params-short-array' => 'prefixtranslatable other-domain-test-params-short-array', - 'translatable other-domain-test-params-long-array' => 'prefixtranslatable other-domain-test-params-long-array', - 'translatable typecast' => 'prefixtranslatable typecast', - 'translatable-fqn other-domain-test-no-params-short-array' => 'prefixtranslatable-fqn other-domain-test-no-params-short-array', - 'translatable-fqn other-domain-test-no-params-long-array' => 'prefixtranslatable-fqn other-domain-test-no-params-long-array', - 'translatable-fqn other-domain-test-params-short-array' => 'prefixtranslatable-fqn other-domain-test-params-short-array', - 'translatable-fqn other-domain-test-params-long-array' => 'prefixtranslatable-fqn other-domain-test-params-long-array', - 'translatable-fqn typecast' => 'prefixtranslatable-fqn typecast', - 'translatable-short other-domain-test-no-params-short-array' => 'prefixtranslatable-short other-domain-test-no-params-short-array', - 'translatable-short other-domain-test-no-params-long-array' => 'prefixtranslatable-short other-domain-test-no-params-long-array', - 'translatable-short other-domain-test-params-short-array' => 'prefixtranslatable-short other-domain-test-params-short-array', - 'translatable-short other-domain-test-params-long-array' => 'prefixtranslatable-short other-domain-test-params-long-array', - 'translatable-short typecast' => 'prefixtranslatable-short typecast', - 'translatable-short-fqn other-domain-test-no-params-short-array' => 'prefixtranslatable-short-fqn other-domain-test-no-params-short-array', - 'translatable-short-fqn other-domain-test-no-params-long-array' => 'prefixtranslatable-short-fqn other-domain-test-no-params-long-array', - 'translatable-short-fqn other-domain-test-params-short-array' => 'prefixtranslatable-short-fqn other-domain-test-params-short-array', - 'translatable-short-fqn other-domain-test-params-long-array' => 'prefixtranslatable-short-fqn other-domain-test-params-long-array', - 'translatable-short-fqn typecast' => 'prefixtranslatable-short-fqn typecast', - 'other-domain-test-no-params-short-array' => 'prefixother-domain-test-no-params-short-array', - 'other-domain-test-no-params-long-array' => 'prefixother-domain-test-no-params-long-array', - 'other-domain-test-params-short-array' => 'prefixother-domain-test-params-short-array', - 'other-domain-test-params-long-array' => 'prefixother-domain-test-params-long-array', - 'typecast' => 'prefixtypecast', - 'ordered-named-arguments-in-trans-method' => 'prefixordered-named-arguments-in-trans-method', - 'disordered-named-arguments-in-trans-method' => 'prefixdisordered-named-arguments-in-trans-method', - 'variable-assignation-inlined-in-trans-method-call1' => 'prefixvariable-assignation-inlined-in-trans-method-call1', - 'variable-assignation-inlined-in-trans-method-call2' => 'prefixvariable-assignation-inlined-in-trans-method-call2', - 'variable-assignation-inlined-in-trans-method-call3' => 'prefixvariable-assignation-inlined-in-trans-method-call3', - 'variable-assignation-inlined-with-named-arguments-in-trans-method' => 'prefixvariable-assignation-inlined-with-named-arguments-in-trans-method', - 'mix-named-arguments-without-parameters' => 'prefixmix-named-arguments-without-parameters', - 'mix-named-arguments-disordered' => 'prefixmix-named-arguments-disordered', - 'const-domain' => 'prefixconst-domain', - ], - 'validators' => [ - 'message-in-constraint-attribute' => 'prefixmessage-in-constraint-attribute', - // 'custom Isbn message from attribute' => 'prefixcustom Isbn message from attribute', - 'custom Isbn message from attribute with options as array' => 'prefixcustom Isbn message from attribute with options as array', - 'custom Length exact message from attribute from named argument' => 'prefixcustom Length exact message from attribute from named argument', - 'custom Length exact message from attribute from named argument 1/2' => 'prefixcustom Length exact message from attribute from named argument 1/2', - 'custom Length min message from attribute from named argument 2/2' => 'prefixcustom Length min message from attribute from named argument 2/2', - // 'custom Isbn message' => 'prefixcustom Isbn message', - 'custom Isbn message with options as array' => 'prefixcustom Isbn message with options as array', - 'custom Isbn message from named argument' => 'prefixcustom Isbn message from named argument', - 'custom Length exact message from named argument' => 'prefixcustom Length exact message from named argument', - 'custom Length exact message from named argument 1/2' => 'prefixcustom Length exact message from named argument 1/2', - 'custom Length min message from named argument 2/2' => 'prefixcustom Length min message from named argument 2/2', - ], - ]; - $actualCatalogue = $catalogue->all(); - - $this->assertEquals($expectedCatalogue, $actualCatalogue); - - $filename = str_replace(\DIRECTORY_SEPARATOR, '/', __DIR__).'/../Fixtures/extractor-ast/translatable.html.php'; - $this->assertEquals(['sources' => [$filename.':2']], $catalogue->getMetadata('translatable single-quoted key')); - $this->assertEquals(['sources' => [$filename.':37']], $catalogue->getMetadata('translatable other-domain-test-no-params-short-array', 'not_messages')); - - $filename = str_replace(\DIRECTORY_SEPARATOR, '/', __DIR__).'/../Fixtures/extractor-ast/translatable-fqn.html.php'; - $this->assertEquals(['sources' => [$filename.':2']], $catalogue->getMetadata('translatable-fqn single-quoted key')); - $this->assertEquals(['sources' => [$filename.':37']], $catalogue->getMetadata('translatable-fqn other-domain-test-no-params-short-array', 'not_messages')); - - $filename = str_replace(\DIRECTORY_SEPARATOR, '/', __DIR__).'/../Fixtures/extractor-ast/translatable-short.html.php'; - $this->assertEquals(['sources' => [$filename.':2']], $catalogue->getMetadata('translatable-short single-quoted key')); - $this->assertEquals(['sources' => [$filename.':37']], $catalogue->getMetadata('translatable-short other-domain-test-no-params-short-array', 'not_messages')); - - $filename = str_replace(\DIRECTORY_SEPARATOR, '/', __DIR__).'/../Fixtures/extractor-ast/translatable-short-fqn.html.php'; - $this->assertEquals(['sources' => [$filename.':2']], $catalogue->getMetadata('translatable-short-fqn single-quoted key')); - $this->assertEquals(['sources' => [$filename.':37']], $catalogue->getMetadata('translatable-short-fqn other-domain-test-no-params-short-array', 'not_messages')); - - $filename = str_replace(\DIRECTORY_SEPARATOR, '/', __DIR__).'/../Fixtures/extractor-ast/translation.html.php'; - $this->assertEquals(['sources' => [$filename.':2']], $catalogue->getMetadata('single-quoted key')); - $this->assertEquals(['sources' => [$filename.':37']], $catalogue->getMetadata('other-domain-test-no-params-short-array', 'not_messages')); - } - - public function testExtractionFromIndentedHeredocNowdoc() - { - $catalogue = new MessageCatalogue('en'); - - $extractor = new PhpAstExtractor([ - new TransMethodVisitor(), - new TranslatableMessageVisitor(), - new ConstraintVisitor([ - 'NotBlank', - 'Isbn', - 'Length', - ], new TranslatableMessageVisitor()), - ]); - $extractor->setPrefix('prefix'); - $extractor->extract(__DIR__.'/../Fixtures/extractor-7.3/translation.html.php', $catalogue); - - $expectedCatalogue = [ - 'messages' => [ - "heredoc\nindented\n further" => "prefixheredoc\nindented\n further", - "nowdoc\nindented\n further" => "prefixnowdoc\nindented\n further", - ], - ]; - - $this->assertEquals($expectedCatalogue, $catalogue->all()); + $this->assertEquals(['messages' => ['example' => 'example']], $catalogue->all()); + $this->assertEquals(['sources' => [self::FIXTURES_FOLDER.'translation.html.php:1']], $catalogue->getMetadata('example')); } - public static function resourcesProvider(): array + public static function resourcesProvider(): \Generator { - $directory = __DIR__.'/../Fixtures/extractor-ast/'; $phpFiles = []; $splFiles = []; - foreach (new \DirectoryIterator($directory) as $fileInfo) { + foreach (new \DirectoryIterator(self::FIXTURES_FOLDER) as $fileInfo) { if ($fileInfo->isDot()) { continue; } - if (\in_array($fileInfo->getBasename(), ['translatable.html.php', 'translatable-fqn.html.php', 'translatable-short.html.php', 'translatable-short-fqn.html.php', 'translation.html.php', 'validator-constraints.php'], true)) { + if ('php' === $fileInfo->getExtension()) { $phpFiles[] = $fileInfo->getPathname(); } $splFiles[] = $fileInfo->getFileInfo(); } - return [ - [$directory], - [$phpFiles], - [glob($directory.'*')], - [$splFiles], - [new \ArrayObject(glob($directory.'*'))], - [new \ArrayObject($splFiles)], - ]; + yield 'directory' => [self::FIXTURES_FOLDER]; + yield 'phpFiles' => [$phpFiles]; + yield 'glob' => [glob(self::FIXTURES_FOLDER.'*')]; + yield 'splFiles' => [$splFiles]; + yield 'ArrayObject_glob' => [new \ArrayObject(glob(self::FIXTURES_FOLDER.'*'))]; + yield 'ArrayObject_splFiles' => [new \ArrayObject($splFiles)]; } } diff --git a/src/Symfony/Component/Translation/Tests/Extractor/Visitor/AbstractVisitorTest.php b/src/Symfony/Component/Translation/Tests/Extractor/Visitor/AbstractVisitorTest.php new file mode 100644 index 0000000000000..664ef5b1fcc56 --- /dev/null +++ b/src/Symfony/Component/Translation/Tests/Extractor/Visitor/AbstractVisitorTest.php @@ -0,0 +1,27 @@ +getVisitor()]); + $extractor->setPrefix('prefix'); + $catalogue = new MessageCatalogue('en'); + + $extractor->extract($this->getResource(), $catalogue); + + $this->assertCatalogue($catalogue); + + } +} diff --git a/src/Symfony/Component/Translation/Tests/Extractor/Visitor/ConstraintVisitorTest.php b/src/Symfony/Component/Translation/Tests/Extractor/Visitor/ConstraintVisitorTest.php new file mode 100644 index 0000000000000..b3a5e9f7f22ec --- /dev/null +++ b/src/Symfony/Component/Translation/Tests/Extractor/Visitor/ConstraintVisitorTest.php @@ -0,0 +1,47 @@ +assertEquals( + [ + 'validators' => [ + 'message-in-constraint-attribute' => 'prefixmessage-in-constraint-attribute', + // 'custom Isbn message from attribute' => 'prefixcustom Isbn message from attribute', + 'custom Isbn message from attribute with options as array' => 'prefixcustom Isbn message from attribute with options as array', + 'custom Length exact message from attribute from named argument' => 'prefixcustom Length exact message from attribute from named argument', + 'custom Length exact message from attribute from named argument 1/2' => 'prefixcustom Length exact message from attribute from named argument 1/2', + 'custom Length min message from attribute from named argument 2/2' => 'prefixcustom Length min message from attribute from named argument 2/2', + // 'custom Isbn message' => 'prefixcustom Isbn message', + 'custom Isbn message with options as array' => 'prefixcustom Isbn message with options as array', + 'custom Isbn message from named argument' => 'prefixcustom Isbn message from named argument', + 'custom Length exact message from named argument' => 'prefixcustom Length exact message from named argument', + 'custom Length exact message from named argument 1/2' => 'prefixcustom Length exact message from named argument 1/2', + 'custom Length min message from named argument 2/2' => 'prefixcustom Length min message from named argument 2/2', + ], + ], + $catalogue->all(), + ); + + $this->assertEquals(['sources' => [self::FIXTURES_FOLDER . 'validator-constraints.php:8']], $catalogue->getMetadata('message-in-constraint-attribute', 'validators')); + } +} diff --git a/src/Symfony/Component/Translation/Tests/Extractor/Visitor/TransMethodVisitorTest.php b/src/Symfony/Component/Translation/Tests/Extractor/Visitor/TransMethodVisitorTest.php new file mode 100644 index 0000000000000..2b0ffda00f5c3 --- /dev/null +++ b/src/Symfony/Component/Translation/Tests/Extractor/Visitor/TransMethodVisitorTest.php @@ -0,0 +1,115 @@ +assertEquals( + [ + 'messages' => [ + 'single-quoted key' => 'prefixsingle-quoted key', + 'double-quoted key' => 'prefixdouble-quoted key', + 'heredoc key' => 'prefixheredoc key', + 'nowdoc key' => 'prefixnowdoc key', + "double-quoted key with whitespace and escaped \$\n\" sequences" => "prefixdouble-quoted key with whitespace and escaped \$\n\" sequences", + 'single-quoted key with whitespace and nonescaped \\$\\n\' sequences' => 'prefixsingle-quoted key with whitespace and nonescaped \\$\\n\' sequences', + $expectedHeredoc => 'prefix'.$expectedHeredoc, + $expectedNowdoc => 'prefix'.$expectedNowdoc, + 'single-quoted key with "quote mark at the end"' => 'prefixsingle-quoted key with "quote mark at the end"', + 'concatenated message with heredoc and nowdoc' => 'prefixconcatenated message with heredoc and nowdoc', + 'default domain' => 'prefixdefault domain', + 'mix-named-arguments' => 'prefixmix-named-arguments', + 'mix-named-arguments-locale' => 'prefixmix-named-arguments-locale', + 'mix-named-arguments-without-domain' => 'prefixmix-named-arguments-without-domain', + "heredoc\nindented\n further" => "prefixheredoc\nindented\n further", + "nowdoc\nindented\n further" => "prefixnowdoc\nindented\n further", + 'translatable-short single-quoted key' => 'prefixtranslatable-short single-quoted key', + 'translatable-short double-quoted key' => 'prefixtranslatable-short double-quoted key', + 'translatable-short heredoc key' => 'prefixtranslatable-short heredoc key', + 'translatable-short nowdoc key' => 'prefixtranslatable-short nowdoc key', + "translatable-short double-quoted key with whitespace and escaped \$\n\" sequences" => "prefixtranslatable-short double-quoted key with whitespace and escaped \$\n\" sequences", + 'translatable-short single-quoted key with whitespace and nonescaped \$\n\' sequences' => 'prefixtranslatable-short single-quoted key with whitespace and nonescaped \$\n\' sequences', + 'translatable-short single-quoted key with "quote mark at the end"' => 'prefixtranslatable-short single-quoted key with "quote mark at the end"', + 'translatable-short '.$expectedHeredoc => 'prefixtranslatable-short '.$expectedHeredoc, + 'translatable-short '.$expectedNowdoc => 'prefixtranslatable-short '.$expectedNowdoc, + 'translatable-short concatenated message with heredoc and nowdoc' => 'prefixtranslatable-short concatenated message with heredoc and nowdoc', + 'translatable-short default domain' => 'prefixtranslatable-short default domain', + 'translatable-short-fqn single-quoted key' => 'prefixtranslatable-short-fqn single-quoted key', + 'translatable-short-fqn double-quoted key' => 'prefixtranslatable-short-fqn double-quoted key', + 'translatable-short-fqn heredoc key' => 'prefixtranslatable-short-fqn heredoc key', + 'translatable-short-fqn nowdoc key' => 'prefixtranslatable-short-fqn nowdoc key', + "translatable-short-fqn double-quoted key with whitespace and escaped \$\n\" sequences" => "prefixtranslatable-short-fqn double-quoted key with whitespace and escaped \$\n\" sequences", + 'translatable-short-fqn single-quoted key with whitespace and nonescaped \$\n\' sequences' => 'prefixtranslatable-short-fqn single-quoted key with whitespace and nonescaped \$\n\' sequences', + 'translatable-short-fqn single-quoted key with "quote mark at the end"' => 'prefixtranslatable-short-fqn single-quoted key with "quote mark at the end"', + 'translatable-short-fqn '.$expectedHeredoc => 'prefixtranslatable-short-fqn '.$expectedHeredoc, + 'translatable-short-fqn '.$expectedNowdoc => 'prefixtranslatable-short-fqn '.$expectedNowdoc, + 'translatable-short-fqn concatenated message with heredoc and nowdoc' => 'prefixtranslatable-short-fqn concatenated message with heredoc and nowdoc', + 'translatable-short-fqn default domain' => 'prefixtranslatable-short-fqn default domain', + ], + 'not_messages' => [ + 'other-domain-test-no-params-short-array' => 'prefixother-domain-test-no-params-short-array', + 'other-domain-test-no-params-long-array' => 'prefixother-domain-test-no-params-long-array', + 'other-domain-test-params-short-array' => 'prefixother-domain-test-params-short-array', + 'other-domain-test-params-long-array' => 'prefixother-domain-test-params-long-array', + 'typecast' => 'prefixtypecast', + 'ordered-named-arguments-in-trans-method' => 'prefixordered-named-arguments-in-trans-method', + 'disordered-named-arguments-in-trans-method' => 'prefixdisordered-named-arguments-in-trans-method', + 'variable-assignation-inlined-in-trans-method-call1' => 'prefixvariable-assignation-inlined-in-trans-method-call1', + 'variable-assignation-inlined-in-trans-method-call2' => 'prefixvariable-assignation-inlined-in-trans-method-call2', + 'variable-assignation-inlined-in-trans-method-call3' => 'prefixvariable-assignation-inlined-in-trans-method-call3', + 'variable-assignation-inlined-with-named-arguments-in-trans-method' => 'prefixvariable-assignation-inlined-with-named-arguments-in-trans-method', + 'mix-named-arguments-without-parameters' => 'prefixmix-named-arguments-without-parameters', + 'mix-named-arguments-disordered' => 'prefixmix-named-arguments-disordered', + 'const-domain' => 'prefixconst-domain', + 'translatable-short other-domain-test-no-params-short-array' => 'prefixtranslatable-short other-domain-test-no-params-short-array', + 'translatable-short other-domain-test-no-params-long-array' => 'prefixtranslatable-short other-domain-test-no-params-long-array', + 'translatable-short other-domain-test-params-short-array' => 'prefixtranslatable-short other-domain-test-params-short-array', + 'translatable-short other-domain-test-params-long-array' => 'prefixtranslatable-short other-domain-test-params-long-array', + 'translatable-short typecast' => 'prefixtranslatable-short typecast', + 'translatable-short-fqn other-domain-test-no-params-short-array' => 'prefixtranslatable-short-fqn other-domain-test-no-params-short-array', + 'translatable-short-fqn other-domain-test-no-params-long-array' => 'prefixtranslatable-short-fqn other-domain-test-no-params-long-array', + 'translatable-short-fqn other-domain-test-params-short-array' => 'prefixtranslatable-short-fqn other-domain-test-params-short-array', + 'translatable-short-fqn other-domain-test-params-long-array' => 'prefixtranslatable-short-fqn other-domain-test-params-long-array', + 'translatable-short-fqn typecast' => 'prefixtranslatable-short-fqn typecast', + ], + ], + $catalogue->all(), + ); + + $this->assertEquals(['sources' => [self::FIXTURES_FOLDER . 'translation.html.php:2']], $catalogue->getMetadata('single-quoted key')); + $this->assertEquals(['sources' => [self::FIXTURES_FOLDER . 'translation.html.php:37']], $catalogue->getMetadata('other-domain-test-no-params-short-array', 'not_messages')); + $this->assertEquals(['sources' => [self::FIXTURES_FOLDER . 'translation-73.html.php:8']], $catalogue->getMetadata("nowdoc\nindented\n further")); + + $this->assertEquals(['sources' => [self::FIXTURES_FOLDER . 'translatable-short.html.php:2']], $catalogue->getMetadata('translatable-short single-quoted key')); + $this->assertEquals(['sources' => [self::FIXTURES_FOLDER . 'translatable-short.html.php:37']], $catalogue->getMetadata('translatable-short other-domain-test-no-params-short-array', 'not_messages')); + + $this->assertEquals(['sources' => [self::FIXTURES_FOLDER . 'translatable-short-fqn.html.php:2']], $catalogue->getMetadata('translatable-short-fqn single-quoted key')); + $this->assertEquals(['sources' => [self::FIXTURES_FOLDER . 'translatable-short-fqn.html.php:37']], $catalogue->getMetadata('translatable-short-fqn other-domain-test-no-params-short-array', 'not_messages')); + } +} diff --git a/src/Symfony/Component/Translation/Tests/Extractor/Visitor/TranslatableMessageVisitorTest.php b/src/Symfony/Component/Translation/Tests/Extractor/Visitor/TranslatableMessageVisitorTest.php new file mode 100644 index 0000000000000..ad9c2e191701d --- /dev/null +++ b/src/Symfony/Component/Translation/Tests/Extractor/Visitor/TranslatableMessageVisitorTest.php @@ -0,0 +1,81 @@ +assertEquals( + [ + 'messages' => [ + 'translatable single-quoted key' => 'prefixtranslatable single-quoted key', + 'translatable double-quoted key' => 'prefixtranslatable double-quoted key', + 'translatable heredoc key' => 'prefixtranslatable heredoc key', + 'translatable nowdoc key' => 'prefixtranslatable nowdoc key', + "translatable double-quoted key with whitespace and escaped \$\n\" sequences" => "prefixtranslatable double-quoted key with whitespace and escaped \$\n\" sequences", + 'translatable single-quoted key with whitespace and nonescaped \$\n\' sequences' => 'prefixtranslatable single-quoted key with whitespace and nonescaped \$\n\' sequences', + 'translatable single-quoted key with "quote mark at the end"' => 'prefixtranslatable single-quoted key with "quote mark at the end"', + 'translatable '.$expectedHeredoc => 'prefixtranslatable '.$expectedHeredoc, + 'translatable '.$expectedNowdoc => 'prefixtranslatable '.$expectedNowdoc, + 'translatable concatenated message with heredoc and nowdoc' => 'prefixtranslatable concatenated message with heredoc and nowdoc', + 'translatable default domain' => 'prefixtranslatable default domain', + 'translatable-fqn single-quoted key' => 'prefixtranslatable-fqn single-quoted key', + 'translatable-fqn double-quoted key' => 'prefixtranslatable-fqn double-quoted key', + 'translatable-fqn heredoc key' => 'prefixtranslatable-fqn heredoc key', + 'translatable-fqn nowdoc key' => 'prefixtranslatable-fqn nowdoc key', + "translatable-fqn double-quoted key with whitespace and escaped \$\n\" sequences" => "prefixtranslatable-fqn double-quoted key with whitespace and escaped \$\n\" sequences", + 'translatable-fqn single-quoted key with whitespace and nonescaped \$\n\' sequences' => 'prefixtranslatable-fqn single-quoted key with whitespace and nonescaped \$\n\' sequences', + 'translatable-fqn single-quoted key with "quote mark at the end"' => 'prefixtranslatable-fqn single-quoted key with "quote mark at the end"', + 'translatable-fqn '.$expectedHeredoc => 'prefixtranslatable-fqn '.$expectedHeredoc, + 'translatable-fqn '.$expectedNowdoc => 'prefixtranslatable-fqn '.$expectedNowdoc, + 'translatable-fqn concatenated message with heredoc and nowdoc' => 'prefixtranslatable-fqn concatenated message with heredoc and nowdoc', + 'translatable-fqn default domain' => 'prefixtranslatable-fqn default domain', + ], + 'not_messages' => [ + 'translatable other-domain-test-no-params-short-array' => 'prefixtranslatable other-domain-test-no-params-short-array', + 'translatable other-domain-test-no-params-long-array' => 'prefixtranslatable other-domain-test-no-params-long-array', + 'translatable other-domain-test-params-short-array' => 'prefixtranslatable other-domain-test-params-short-array', + 'translatable other-domain-test-params-long-array' => 'prefixtranslatable other-domain-test-params-long-array', + 'translatable typecast' => 'prefixtranslatable typecast', + 'translatable-fqn other-domain-test-no-params-short-array' => 'prefixtranslatable-fqn other-domain-test-no-params-short-array', + 'translatable-fqn other-domain-test-no-params-long-array' => 'prefixtranslatable-fqn other-domain-test-no-params-long-array', + 'translatable-fqn other-domain-test-params-short-array' => 'prefixtranslatable-fqn other-domain-test-params-short-array', + 'translatable-fqn other-domain-test-params-long-array' => 'prefixtranslatable-fqn other-domain-test-params-long-array', + 'translatable-fqn typecast' => 'prefixtranslatable-fqn typecast', + ], + ], + $catalogue->all(), + ); + + $this->assertEquals(['sources' => [self::FIXTURES_FOLDER . 'translatable.html.php:2']], $catalogue->getMetadata('translatable single-quoted key')); + $this->assertEquals(['sources' => [self::FIXTURES_FOLDER . 'translatable.html.php:37']], $catalogue->getMetadata('translatable other-domain-test-no-params-short-array', 'not_messages')); + + $this->assertEquals(['sources' => [self::FIXTURES_FOLDER . 'translatable-fqn.html.php:2']], $catalogue->getMetadata('translatable-fqn single-quoted key')); + $this->assertEquals(['sources' => [self::FIXTURES_FOLDER . 'translatable-fqn.html.php:37']], $catalogue->getMetadata('translatable-fqn other-domain-test-no-params-short-array', 'not_messages')); + } +} diff --git a/src/Symfony/Component/Translation/Tests/Fixtures/extractor-php-ast/constraint-visitor/validator-constraints.php b/src/Symfony/Component/Translation/Tests/Fixtures/extractor-php-ast/constraint-visitor/validator-constraints.php new file mode 100644 index 0000000000000..091d251b63a0d --- /dev/null +++ b/src/Symfony/Component/Translation/Tests/Fixtures/extractor-php-ast/constraint-visitor/validator-constraints.php @@ -0,0 +1,40 @@ +This template is used for translation message extraction tests + 'isbn10', + 'message' => 'custom Isbn message from attribute with options as array', + ])] + public string $isbn2; +} + +class Foo2 +{ + public function index() + { + $constraint1 = new Assert\Isbn('isbn10', 'custom Isbn message'); // no way to handle those arguments (not named, not in associative array). + $constraint2 = new Assert\Isbn([ + 'type' => 'isbn10', + 'message' => 'custom Isbn message with options as array', + ]); + $constraint3 = new Assert\Isbn(message: 'custom Isbn message from named argument'); + $constraint4 = new Assert\Length(exactMessage: 'custom Length exact message from named argument'); + $constraint5 = new Assert\Length(exactMessage: 'custom Length exact message from named argument 1/2', minMessage: 'custom Length min message from named argument 2/2'); + } +} diff --git a/src/Symfony/Component/Translation/Tests/Fixtures/extractor-php-ast/extract-files/resource.format.engine b/src/Symfony/Component/Translation/Tests/Fixtures/extractor-php-ast/extract-files/resource.format.engine new file mode 100644 index 0000000000000..e69de29bb2d1d diff --git a/src/Symfony/Component/Translation/Tests/Fixtures/extractor-php-ast/extract-files/this.is.a.template.format.engine b/src/Symfony/Component/Translation/Tests/Fixtures/extractor-php-ast/extract-files/this.is.a.template.format.engine new file mode 100644 index 0000000000000..e69de29bb2d1d diff --git a/src/Symfony/Component/Translation/Tests/Fixtures/extractor-php-ast/extract-files/translation.html.php b/src/Symfony/Component/Translation/Tests/Fixtures/extractor-php-ast/extract-files/translation.html.php new file mode 100644 index 0000000000000..97cb0f024ac3c --- /dev/null +++ b/src/Symfony/Component/Translation/Tests/Fixtures/extractor-php-ast/extract-files/translation.html.php @@ -0,0 +1 @@ +trans('example'); ?> diff --git a/src/Symfony/Component/Translation/Tests/Fixtures/extractor-php-ast/form-type-visitor/form-type.php b/src/Symfony/Component/Translation/Tests/Fixtures/extractor-php-ast/form-type-visitor/form-type.php new file mode 100644 index 0000000000000..8c1b87b24a48c --- /dev/null +++ b/src/Symfony/Component/Translation/Tests/Fixtures/extractor-php-ast/form-type-visitor/form-type.php @@ -0,0 +1,72 @@ +This template is used for translation message extraction tests +add('foo1', null, [ + 'label' => 'label.foo1' + ]); + } +} + +class ExplicitLabelType extends AbstractType +{ + public function buildForm(FormBuilderInterface $builder, array $options) + { + $var = "something"; + $builder->add('find1', null, [ + 'label' => 'label.find1' + ]); + $builder + ->add('find2', null, array( + 'label' => 'find2' + )) + ->add('field_longer_name3', null, [ + 'label' => 'FOUND3' + ]) + ->add('skip1', null, [ + 'label' => $var, // shouldn't be picked up + 'somethingelse' => 'skipthis', + ]) + ->add('skip2', null, [ + 'label' => PHP_OS, // constant shouldn't work + ]) + ->add('skip3', null, [ + 'label' // value label, shouldn't be picked up + ]) + ->add('skip4', null, [ + 'label' => 'something '.$var // string+var concatenation, shouldn't be picked up + ]) + ; + + // add label in variable should be found + $opts = ['label'=>'label.find4']; + $builder->add('find4', null, $opts); + + // empty label should be skipped + $builder->add('skip5', null, ['label'=>'']); + + // collection test + $builder->add('find5', CollectionType::class, [ + 'options' => [ + 'label' => 'label.find5', + ], + ]); + + // implicit labels should be found + $builder->add('find6'); + $builder->add('bigger_find7'); + $builder->add('camelFind8'); + $builder->add('skip6'.$var); + $builder->add('skip7', null, ['label'=>'label.find9']); + } +} diff --git a/src/Symfony/Component/Translation/Tests/Fixtures/extractor-php-ast/trans-method-visitor/translatable-short-fqn.html.php b/src/Symfony/Component/Translation/Tests/Fixtures/extractor-php-ast/trans-method-visitor/translatable-short-fqn.html.php new file mode 100644 index 0000000000000..c02e0b51be028 --- /dev/null +++ b/src/Symfony/Component/Translation/Tests/Fixtures/extractor-php-ast/trans-method-visitor/translatable-short-fqn.html.php @@ -0,0 +1,47 @@ +This template is used for translation message extraction tests + + + + + + + + + + + + + + + + + + 'bar'], 'not_messages'); ?> + + 'bar'], 'not_messages'); ?> + + (int) '123'], 'not_messages'); ?> + + diff --git a/src/Symfony/Component/Translation/Tests/Fixtures/extractor-php-ast/trans-method-visitor/translatable-short.html.php b/src/Symfony/Component/Translation/Tests/Fixtures/extractor-php-ast/trans-method-visitor/translatable-short.html.php new file mode 100644 index 0000000000000..d8842b97f1ada --- /dev/null +++ b/src/Symfony/Component/Translation/Tests/Fixtures/extractor-php-ast/trans-method-visitor/translatable-short.html.php @@ -0,0 +1,47 @@ +This template is used for translation message extraction tests + + + + + + + + + + + + + + + + + + 'bar'], 'not_messages'); ?> + + 'bar'], 'not_messages'); ?> + + (int) '123'], 'not_messages'); ?> + + diff --git a/src/Symfony/Component/Translation/Tests/Fixtures/extractor-php-ast/trans-method-visitor/translation-73.html.php b/src/Symfony/Component/Translation/Tests/Fixtures/extractor-php-ast/trans-method-visitor/translation-73.html.php new file mode 100644 index 0000000000000..35ffe8812ed66 --- /dev/null +++ b/src/Symfony/Component/Translation/Tests/Fixtures/extractor-php-ast/trans-method-visitor/translation-73.html.php @@ -0,0 +1,13 @@ +This template is used for translation message extraction tests +trans(<< +trans(<<<'EOF' + nowdoc + indented + further + EOF +); ?> diff --git a/src/Symfony/Component/Translation/Tests/Fixtures/extractor-php-ast/trans-method-visitor/translation.html.php b/src/Symfony/Component/Translation/Tests/Fixtures/extractor-php-ast/trans-method-visitor/translation.html.php new file mode 100644 index 0000000000000..1bba72115e235 --- /dev/null +++ b/src/Symfony/Component/Translation/Tests/Fixtures/extractor-php-ast/trans-method-visitor/translation.html.php @@ -0,0 +1,70 @@ +This template is used for translation message extraction tests +trans('single-quoted key'); ?> +trans('double-quoted key'); ?> +trans(<< +trans(<<<'EOF' +nowdoc key +EOF +); ?> +trans( + "double-quoted key with whitespace and escaped \$\n\" sequences" +); ?> +trans( + 'single-quoted key with whitespace and nonescaped \$\n\' sequences' +); ?> +trans(<< +trans(<<<'EOF' +nowdoc key with whitespace and nonescaped \$\n sequences +EOF +); ?> + +trans('single-quoted key with "quote mark at the end"'); ?> + +trans('concatenated'.' message'.<< + +trans('other-domain-test-no-params-short-array', [], 'not_messages'); ?> + +trans('other-domain-test-no-params-long-array', [], 'not_messages'); ?> + +trans('other-domain-test-params-short-array', ['foo' => 'bar'], 'not_messages'); ?> + +trans('other-domain-test-params-long-array', ['foo' => 'bar'], 'not_messages'); ?> + +trans('typecast', ['a' => (int) '123'], 'not_messages'); ?> + +trans('default domain', [], null); ?> + +trans(id: 'ordered-named-arguments-in-trans-method', parameters: [], domain: 'not_messages'); ?> +trans(domain: 'not_messages', id: 'disordered-named-arguments-in-trans-method', parameters: []); ?> + +trans($key = 'variable-assignation-inlined-in-trans-method-call1', $parameters = [], $domain = 'not_messages'); ?> +trans('variable-assignation-inlined-in-trans-method-call2', $parameters = [], $domain = 'not_messages'); ?> +trans('variable-assignation-inlined-in-trans-method-call3', [], $domain = 'not_messages'); ?> + +trans(domain: $domain = 'not_messages', id: $key = 'variable-assignation-inlined-with-named-arguments-in-trans-method', parameters: $parameters = []); ?> + +trans('mix-named-arguments', parameters: ['foo' => 'bar']); ?> +trans('mix-named-arguments-locale', parameters: ['foo' => 'bar'], locale: 'de'); ?> +trans('mix-named-arguments-without-domain', parameters: ['foo' => 'bar']); ?> +trans('mix-named-arguments-without-parameters', domain: 'not_messages'); ?> +trans('mix-named-arguments-disordered', domain: 'not_messages', parameters: []); ?> + +trans(...); // should not fail ?> + +trans('const-domain', [], TransMethodVisitorTest::OTHER_DOMAIN); +?> + diff --git a/src/Symfony/Component/Translation/Tests/Fixtures/extractor-php-ast/translatable-message-visitor/translatable-fqn.html.php b/src/Symfony/Component/Translation/Tests/Fixtures/extractor-php-ast/translatable-message-visitor/translatable-fqn.html.php new file mode 100644 index 0000000000000..87a64c42f1eec --- /dev/null +++ b/src/Symfony/Component/Translation/Tests/Fixtures/extractor-php-ast/translatable-message-visitor/translatable-fqn.html.php @@ -0,0 +1,47 @@ +This template is used for translation message extraction tests + + + + + + + + + + + + + + + + + + 'bar'], 'not_messages'); ?> + + 'bar'], 'not_messages'); ?> + + (int) '123'], 'not_messages'); ?> + + diff --git a/src/Symfony/Component/Translation/Tests/Fixtures/extractor-php-ast/translatable-message-visitor/translatable.html.php b/src/Symfony/Component/Translation/Tests/Fixtures/extractor-php-ast/translatable-message-visitor/translatable.html.php new file mode 100644 index 0000000000000..828707e26ed02 --- /dev/null +++ b/src/Symfony/Component/Translation/Tests/Fixtures/extractor-php-ast/translatable-message-visitor/translatable.html.php @@ -0,0 +1,47 @@ +This template is used for translation message extraction tests + + + + + + + + + + + + + + + + + + 'bar'], 'not_messages'); ?> + + 'bar'], 'not_messages'); ?> + + (int) '123'], 'not_messages'); ?> + +