Skip to content

Commit f1c9ebc

Browse files
author
Igor Melnikov
committed
Merge branch 'MAGETWO-61240-fix-constantusagesniff' into sprint6-pr-new
2 parents 1cd4dc8 + f0fc16b commit f1c9ebc

File tree

4 files changed

+209
-10
lines changed

4 files changed

+209
-10
lines changed

dev/tests/static/framework/Magento/Sniffs/Translation/ConstantUsageSniff.php

Lines changed: 57 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -5,12 +5,10 @@
55
*/
66
namespace Magento\Sniffs\Translation;
77

8-
use PHP_CodeSniffer_File;
9-
108
/**
119
* Make sure that constants are not used as the first argument of translation function.
1210
*/
13-
class ConstantUsageSniff extends \Generic_Sniffs_Files_LineLengthSniff
11+
class ConstantUsageSniff implements \PHP_CodeSniffer_Sniff
1412
{
1513
/**
1614
* Having previous line content allows to process multi-line declaration.
@@ -20,24 +18,73 @@ class ConstantUsageSniff extends \Generic_Sniffs_Files_LineLengthSniff
2018
protected $previousLineContent = '';
2119

2220
/**
23-
* {@inheritdoc}
21+
* {@inheritDoc}
22+
*/
23+
public function register()
24+
{
25+
return [T_OPEN_TAG];
26+
27+
}
28+
29+
/**
30+
* Copied from \Generic_Sniffs_Files_LineLengthSniff, minor changes made
31+
*
32+
* {@inheritDoc}
2433
*/
25-
protected function checkLineLength(\PHP_CodeSniffer_File $phpcsFile, $stackPtr, $lineContent)
34+
public function process(\PHP_CodeSniffer_File $phpcsFile, $stackPtr)
2635
{
27-
$previousLineRegexp = '~__\($|Phrase\($~';
28-
$currentLineRegexp = '~__\(.+\)|Phrase\(.+\)~';
36+
$tokens = $phpcsFile->getTokens();
37+
38+
// Make sure this is the first open tag
39+
$previousOpenTag = $phpcsFile->findPrevious(T_OPEN_TAG, ($stackPtr - 1));
40+
if ($previousOpenTag !== false) {
41+
return;
42+
}
43+
44+
$tokenCount = 0;
45+
$currentLineContent = '';
46+
$currentLine = 1;
47+
48+
for (; $tokenCount < $phpcsFile->numTokens; $tokenCount++) {
49+
if ($tokens[$tokenCount]['line'] === $currentLine) {
50+
$currentLineContent .= $tokens[$tokenCount]['content'];
51+
} else {
52+
$this->checkIfFirstArgumentConstant($phpcsFile, ($tokenCount - 1), $currentLineContent);
53+
$currentLineContent = $tokens[$tokenCount]['content'];
54+
$currentLine++;
55+
}
56+
}
57+
58+
$this->checkIfFirstArgumentConstant($phpcsFile, ($tokenCount - 1), $currentLineContent);
59+
}
60+
61+
/**
62+
* Checks if first argument of \Magento\Framework\Phrase or translation function is a constant
63+
*
64+
* @param \PHP_CodeSniffer_File $phpcsFile
65+
* @param int $stackPtr
66+
* @param string $lineContent
67+
* @return void
68+
*/
69+
private function checkIfFirstArgumentConstant(
70+
\PHP_CodeSniffer_File $phpcsFile,
71+
$stackPtr,
72+
$lineContent
73+
) {
74+
$previousLineRegexp = '/(__|Phrase)\($/im';
75+
$currentLineRegexp = '/(__|Phrase)\(.+\)/';
2976
$currentLineMatch = preg_match($currentLineRegexp, $lineContent) !== 0;
3077
$previousLineMatch = preg_match($previousLineRegexp, $this->previousLineContent) !== 0;
3178
$this->previousLineContent = $lineContent;
3279
$error = 'Constants are not allowed as the first argument of translation function, use string literal instead';
33-
$constantRegexp = '[^\'"]+::[A-Z_0-9]+.*';
80+
$constantRegexp = '[^\$\'"]+::[A-Z_0-9]+.*';
3481
if ($currentLineMatch) {
35-
$variableRegexp = "~__\({$constantRegexp}\)|Phrase\({$constantRegexp}\)~";
82+
$variableRegexp = "/(__|Phrase)\({$constantRegexp}\)/";
3683
if (preg_match($variableRegexp, $lineContent) !== 0) {
3784
$phpcsFile->addError($error, $stackPtr, 'VariableTranslation');
3885
}
3986
} else if ($previousLineMatch) {
40-
$variableRegexp = "~^\s+{$constantRegexp}~";
87+
$variableRegexp = "/^{$constantRegexp}/";
4188
if (preg_match($variableRegexp, $lineContent) !== 0) {
4289
$phpcsFile->addError($error, $stackPtr, 'VariableTranslation');
4390
}
Lines changed: 96 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,96 @@
1+
<?php
2+
/**
3+
* Copyright © 2016 Magento. All rights reserved.
4+
* See COPYING.txt for license details.
5+
*/
6+
namespace Magento\Sniffs\Translation;
7+
8+
class ConstantUsageSniffTest extends \PHPUnit_Framework_TestCase
9+
{
10+
/**
11+
* @var \PHP_CodeSniffer_File|\PHPUnit_Framework_MockObject_MockObject
12+
*/
13+
private $fileMock;
14+
15+
/**
16+
* @var ConstantUsageSniff
17+
*/
18+
private $constantUsageSniff;
19+
20+
protected function setUp()
21+
{
22+
$this->fileMock = $this->getMock(\PHP_CodeSniffer_File::class, [], [], '', false);
23+
$this->constantUsageSniff = new ConstantUsageSniff();
24+
}
25+
26+
/**
27+
* @param string $file
28+
* @param int $numIncorrectUsages
29+
* @dataProvider processDataProvider
30+
*/
31+
public function testProcessIncorrectArguments($file, $numIncorrectUsages)
32+
{
33+
$stackPtr = 10;
34+
$fileContent = file_get_contents(__DIR__ . '/_files/' . $file);
35+
$tokens = $this->tokenizeString($fileContent);
36+
$this->fileMock->expects($this->once())
37+
->method('findPrevious')
38+
->with(
39+
T_OPEN_TAG,
40+
$stackPtr - 1
41+
)
42+
->willReturn(false);
43+
$this->fileMock->expects($this->once())
44+
->method('getTokens')
45+
->willReturn($tokens);
46+
$this->fileMock->numTokens = count($tokens);
47+
$this->fileMock->expects($this->exactly($numIncorrectUsages))
48+
->method('addError')
49+
->with(
50+
'Constants are not allowed as the first argument of translation function, use string literal instead',
51+
$this->anything(),
52+
'VariableTranslation'
53+
);
54+
$this->constantUsageSniff->process($this->fileMock, $stackPtr);
55+
}
56+
57+
/**
58+
* Get tokens for a string
59+
*
60+
* @param string $fileContent
61+
* @return array
62+
*/
63+
private function tokenizeString($fileContent)
64+
{
65+
$lineNumber = 1;
66+
$tokens = token_get_all($fileContent);
67+
$snifferTokens = [];
68+
for ($i = 0; $i < count($tokens); $i++) {
69+
$content = is_array($tokens[$i]) ? $tokens[$i][1] : $tokens[$i];
70+
$snifferTokens[$i]['line'] = $lineNumber;
71+
$snifferTokens[$i]['content'] = $content;
72+
$trimmedContent = trim($content, ' ');
73+
if ($trimmedContent == PHP_EOL || $trimmedContent == PHP_EOL . PHP_EOL) {
74+
$lineNumber++;
75+
}
76+
}
77+
return $snifferTokens;
78+
}
79+
80+
/**
81+
* @return array
82+
*/
83+
public function processDataProvider()
84+
{
85+
return [
86+
[
87+
'incorrect_arguments.txt',
88+
9
89+
],
90+
[
91+
'correct_arguments.txt',
92+
0
93+
]
94+
];
95+
}
96+
}
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
<?php
2+
/**
3+
* Copyright © 2016 Magento. All rights reserved.
4+
* See COPYING.txt for license details.
5+
*/
6+
7+
$item[ConfigConverter::KEY_TITLE] = __($item)
8+
9+
$item[ConfigConverter::KEY_TITLE] = __($item[Converter::KEY_TITLE])
10+
11+
$item[ConfigConverter::KEY_TITLE] = __($item['\Magento\Support\Model\Report\Config\Converter::KEY_TITLE'])
12+
13+
$item[ConfigConverter::KEY_TITLE] = __($item['value'])
14+
15+
$item[ConfigConverter::KEY_TITLE] = __(
16+
$item
17+
)
18+
19+
Phrase($item)
20+
21+
Phrase($item[Converter::KEY_TITLE])
22+
23+
Phrase($item['\Magento\Support\Model\Report\Config\Converter::KEY_TITLE'])
24+
25+
\Magento\Framework\Phrase($item['value'])
26+
27+
\Magento\Framework\Phrase(
28+
$item[Converter::KEY_TITLE]
29+
)
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
<?php
2+
/**
3+
* Copyright © 2016 Magento. All rights reserved.
4+
* See COPYING.txt for license details.
5+
*/
6+
7+
$item[ConfigConverter::KEY_TITLE] = __(Converter::KEY_TITLE)
8+
9+
$item[ConfigConverter::KEY_TITLE] = __(self::KEY_TITLE)
10+
11+
$item[ConfigConverter::KEY_TITLE] = __(\Magento\Support\Model\Report\Config\Converter::KEY_TITLE)
12+
13+
$item[ConfigConverter::KEY_TITLE] = __(
14+
Converter::KEY_TITLE
15+
)
16+
17+
Phrase(Converter::KEY_TITLE)
18+
19+
Phrase(self::KEY_TITLE)
20+
21+
Phrase(\Magento\Support\Model\Report\Config\Converter::KEY_TITLE)
22+
23+
\Magento\Framework\Phrase(Converter::KEY_TITLE)
24+
25+
\Magento\Framework\Phrase(
26+
Converter::KEY_TITLE
27+
)

0 commit comments

Comments
 (0)