diff --git a/src/Rule/Rules/File/Psr1PhpTagsRule.php b/src/Rule/Rules/File/Psr1PhpTagsRule.php index 8b83bea..deac0a1 100644 --- a/src/Rule/Rules/File/Psr1PhpTagsRule.php +++ b/src/Rule/Rules/File/Psr1PhpTagsRule.php @@ -113,9 +113,12 @@ private function fixInvalidTagOnLine(string $code, int $line): ?string $replacement = $this->replacementForInvalidTag($token[0], $text, $token[2], $line); if ($replacement !== null) { - return substr($code, 0, $offset + $replacement['offset']) - . $replacement['text'] - . substr($code, $offset + $replacement['offset'] + $replacement['length']); + $replaceAt = $offset + $replacement['offset']; + $afterOffset = $replaceAt + $replacement['length']; + + return substr($code, 0, $replaceAt) + . $this->normalizedTagReplacement($replacement['text'], substr($code, $afterOffset, 1)) + . substr($code, $afterOffset); } } @@ -125,6 +128,23 @@ private function fixInvalidTagOnLine(string $code, int $line): ?string return null; } + /** + * Ensures the replaced ` $tagOffset, 'length' => 2, - 'text' => preg_match('/^\s/', substr($text, $tagOffset + 2)) === 1 ? ' 'makeTempDir(); + + try { + mkdir($basePath . '/src'); + file_put_contents($basePath . '/src/Foo.php', 'fixWithShortOpenTagEnabled($basePath); + + // A bare `assertSame('assertSame(0, $exitCode); + $this->assertSame(['hi'], $output); + } finally { + unlink($basePath . '/src/Foo.php'); + rmdir($basePath . '/src'); + rmdir($basePath); + } + } + + public function testFixesShortOpenTagFollowedByVariableWhenShortOpenTagEnabled(): void + { + $basePath = $this->makeTempDir(); + + try { + mkdir($basePath . '/src'); + file_put_contents($basePath . '/src/Foo.php', 'fixWithShortOpenTagEnabled($basePath); + + $this->assertSame('assertSame(0, $exitCode); + } finally { + unlink($basePath . '/src/Foo.php'); + rmdir($basePath . '/src'); + rmdir($basePath); + } + } + public function testViolatesAssignmentUsingShortOpenTag(): void { $basePath = $this->makeTempDir(); @@ -587,4 +643,45 @@ private function makeTempDir(): string return $path; } + + /** + * Runs the fixer in a subprocess with short_open_tag=On so that bare `exported($autoload)}; + + use Boundwize\\StructArmed\\Architecture; + use Boundwize\\StructArmed\\Rule\\Rules\\File\\Psr1PhpTagsRule; + + \$rule = new Psr1PhpTagsRule(['src/']); + \$violations = \$rule->evaluateProjectAll({$this->exported($basePath)}, Architecture::define()); + \$rule->fix(\$violations[0]); + PHP); + + $command = escapeshellarg(PHP_BINARY) + . ' -d short_open_tag=1 ' + . escapeshellarg($runner); + exec($command, $output, $exitCode); + + $fixedContent = (string) file_get_contents($basePath . '/src/Foo.php'); + unlink($runner); + + $this->assertSame(0, $exitCode, 'Fixer runner failed: ' . implode("\n", $output)); + + return $fixedContent; + } + + private function exported(string $value): string + { + return var_export($value, true); + } }