Skip to content

Commit d96c7d6

Browse files
committed
Tokenizers/Comment: add tests
The `Tokenizers\Comment` class did not have any tests associated with it. This commit fixes that and documents the existing behaviour. Note: code coverage is as high as it can go, but not 100%. The reason for this, is the tokenizer debug statements, which are conditional on a verbosity flag, which is turned off for the tests. Loosely related to 484.
1 parent 4866ee3 commit d96c7d6

15 files changed

+1880
-0
lines changed
Lines changed: 117 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,117 @@
1+
<?php
2+
/**
3+
* Base class for testing DocBlock comment tokenization.
4+
*
5+
* @author Juliette Reinders Folmer <[email protected]>
6+
* @copyright 2024 PHPCSStandards and contributors
7+
* @license https://github.com/PHPCSStandards/PHP_CodeSniffer/blob/master/licence.txt BSD Licence
8+
*/
9+
10+
namespace PHP_CodeSniffer\Tests\Core\Tokenizer\Comment;
11+
12+
use PHP_CodeSniffer\Tests\Core\Tokenizer\AbstractTokenizerTestCase;
13+
use PHP_CodeSniffer\Util\Tokens;
14+
15+
/**
16+
* Base class for testing DocBlock comment tokenization.
17+
*
18+
* @covers PHP_CodeSniffer\Tokenizers\Comment
19+
*/
20+
abstract class CommentTestCase extends AbstractTokenizerTestCase
21+
{
22+
23+
24+
/**
25+
* Test whether the docblock opener and closer have the expected extra keys.
26+
*
27+
* @param string $marker The comment prefacing the target token.
28+
* @param int $closerOffset The offset of the closer from the opener.
29+
* @param array<int> $expectedTags The expected tags offsets array.
30+
*
31+
* @dataProvider dataDocblockOpenerCloser
32+
*
33+
* @return void
34+
*/
35+
public function testDocblockOpenerCloser($marker, $closerOffset, $expectedTags)
36+
{
37+
$tokens = $this->phpcsFile->getTokens();
38+
$target = $this->getTargetToken($marker, [T_DOC_COMMENT_OPEN_TAG]);
39+
40+
$opener = $tokens[$target];
41+
42+
$this->assertArrayHasKey('comment_closer', $opener, 'Comment opener: comment_closer index is not set');
43+
$this->assertArrayHasKey('comment_tags', $opener, 'Comment opener: comment_tags index is not set');
44+
45+
$expectedCloser = ($target + $closerOffset);
46+
$this->assertSame($expectedCloser, $opener['comment_closer'], 'Comment opener: comment_closer not set to the expected stack pointer');
47+
48+
// Update the tags expectations.
49+
foreach ($expectedTags as $i => $ptr) {
50+
$expectedTags[$i] += $target;
51+
}
52+
53+
$this->assertSame($expectedTags, $opener['comment_tags'], 'Comment opener: recorded tags do not match expected tags');
54+
55+
$closer = $tokens[$opener['comment_closer']];
56+
57+
$this->assertArrayHasKey('comment_opener', $closer, 'Comment closer: comment_opener index is not set');
58+
$this->assertSame($target, $closer['comment_opener'], 'Comment closer: comment_opener not set to the expected stack pointer');
59+
60+
}//end testDocblockOpenerCloser()
61+
62+
63+
/**
64+
* Data provider.
65+
*
66+
* @see testDocblockOpenerCloser()
67+
*
68+
* @return array<string, array<string, string|int|array<int>>>
69+
*/
70+
abstract public static function dataDocblockOpenerCloser();
71+
72+
73+
/**
74+
* Test helper. Check a token sequence complies with an expected token sequence.
75+
*
76+
* @param int $startPtr The position in the file to start checking from.
77+
* @param array<array<int|string, string>> $expectedSequence The consecutive token constants and their contents to expect.
78+
*
79+
* @return void
80+
*/
81+
protected function checkTokenSequence($startPtr, array $expectedSequence)
82+
{
83+
$tokens = $this->phpcsFile->getTokens();
84+
85+
$sequenceKey = 0;
86+
$sequenceCount = count($expectedSequence);
87+
88+
for ($i = $startPtr; $sequenceKey < $sequenceCount; $i++, $sequenceKey++) {
89+
$currentItem = $expectedSequence[$sequenceKey];
90+
$expectedCode = key($currentItem);
91+
$expectedType = Tokens::tokenName($expectedCode);
92+
$expectedContent = current($currentItem);
93+
$errorMsgSuffix = PHP_EOL.'(StackPtr: '.$i.' | Position in sequence: '.$sequenceKey.' | Expected: '.$expectedType.')';
94+
95+
$this->assertSame(
96+
$expectedCode,
97+
$tokens[$i]['code'],
98+
'Token tokenized as '.Tokens::tokenName($tokens[$i]['code']).', not '.$expectedType.' (code)'.$errorMsgSuffix
99+
);
100+
101+
$this->assertSame(
102+
$expectedType,
103+
$tokens[$i]['type'],
104+
'Token tokenized as '.$tokens[$i]['type'].', not '.$expectedType.' (type)'.$errorMsgSuffix
105+
);
106+
107+
$this->assertSame(
108+
$expectedContent,
109+
$tokens[$i]['content'],
110+
'Token content did not match expectations'.$errorMsgSuffix
111+
);
112+
}//end for
113+
114+
}//end checkTokenSequence()
115+
116+
117+
}//end class
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
<?php
2+
3+
/* testLiveCoding */
4+
/**
5+
* Unclosed docblock, live coding.... with no blank line at end of file.
6+
*
Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
<?php
2+
/**
3+
* Tests that unclosed docblocks during live coding are handled correctly.
4+
*
5+
* @author Juliette Reinders Folmer <[email protected]>
6+
* @copyright 2024 PHPCSStandards and contributors
7+
* @license https://github.com/PHPCSStandards/PHP_CodeSniffer/blob/master/licence.txt BSD Licence
8+
*/
9+
10+
namespace PHP_CodeSniffer\Tests\Core\Tokenizer\Comment;
11+
12+
/**
13+
* Tests that unclosed docblocks during live coding are handled correctly.
14+
*
15+
* @covers PHP_CodeSniffer\Tokenizers\Comment
16+
*/
17+
final class LiveCoding1Test extends CommentTestCase
18+
{
19+
20+
21+
/**
22+
* Data provider.
23+
*
24+
* @see testDocblockOpenerCloser()
25+
*
26+
* @return array<string, array<string, string|int|array<int>>>
27+
*/
28+
public static function dataDocblockOpenerCloser()
29+
{
30+
return [
31+
'live coding: unclosed docblock, no blank line at end of file' => [
32+
'marker' => '/* testLiveCoding */',
33+
'closerOffset' => 8,
34+
'expectedTags' => [],
35+
],
36+
];
37+
38+
}//end dataDocblockOpenerCloser()
39+
40+
41+
/**
42+
* Verify tokenization of the DocBlock.
43+
*
44+
* @phpcs:disable Squiz.Arrays.ArrayDeclaration.SpaceBeforeDoubleArrow -- Readability is better with alignment.
45+
*
46+
* @return void
47+
*/
48+
public function testLiveCoding()
49+
{
50+
$expectedSequence = [
51+
[T_DOC_COMMENT_OPEN_TAG => '/**'],
52+
[T_DOC_COMMENT_WHITESPACE => "\n"],
53+
[T_DOC_COMMENT_WHITESPACE => ' '],
54+
[T_DOC_COMMENT_STAR => '*'],
55+
[T_DOC_COMMENT_WHITESPACE => ' '],
56+
[T_DOC_COMMENT_STRING => 'Unclosed docblock, live coding.... with no blank line at end of file.'],
57+
[T_DOC_COMMENT_WHITESPACE => "\n"],
58+
[T_DOC_COMMENT_WHITESPACE => ' '],
59+
[T_DOC_COMMENT_CLOSE_TAG => '*'],
60+
];
61+
62+
$target = $this->getTargetToken('/* '.__FUNCTION__.' */', T_DOC_COMMENT_OPEN_TAG);
63+
64+
$this->checkTokenSequence($target, $expectedSequence);
65+
66+
}//end testLiveCoding()
67+
68+
69+
}//end class
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
<?php
2+
3+
/* testLiveCoding */
4+
/**
5+
* Unclosed docblock, live coding.... with a blank line at end of file.
Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
<?php
2+
/**
3+
* Tests that unclosed docblocks during live coding are handled correctly.
4+
*
5+
* @author Juliette Reinders Folmer <[email protected]>
6+
* @copyright 2024 PHPCSStandards and contributors
7+
* @license https://github.com/PHPCSStandards/PHP_CodeSniffer/blob/master/licence.txt BSD Licence
8+
*/
9+
10+
namespace PHP_CodeSniffer\Tests\Core\Tokenizer\Comment;
11+
12+
/**
13+
* Tests that unclosed docblocks during live coding are handled correctly.
14+
*
15+
* @covers PHP_CodeSniffer\Tokenizers\Comment
16+
*/
17+
final class LiveCoding2Test extends CommentTestCase
18+
{
19+
20+
21+
/**
22+
* Data provider.
23+
*
24+
* @see testDocblockOpenerCloser()
25+
*
26+
* @return array<string, array<string, string|int|array<int>>>
27+
*/
28+
public static function dataDocblockOpenerCloser()
29+
{
30+
return [
31+
'live coding: unclosed docblock with blank line at end of file' => [
32+
'marker' => '/* testLiveCoding */',
33+
'closerOffset' => 7,
34+
'expectedTags' => [],
35+
],
36+
];
37+
38+
}//end dataDocblockOpenerCloser()
39+
40+
41+
/**
42+
* Verify tokenization of the DocBlock.
43+
*
44+
* @phpcs:disable Squiz.Arrays.ArrayDeclaration.SpaceBeforeDoubleArrow -- Readability is better with alignment.
45+
*
46+
* @return void
47+
*/
48+
public function testLiveCoding()
49+
{
50+
$expectedSequence = [
51+
[T_DOC_COMMENT_OPEN_TAG => '/**'],
52+
[T_DOC_COMMENT_WHITESPACE => "\n"],
53+
[T_DOC_COMMENT_WHITESPACE => ' '],
54+
[T_DOC_COMMENT_STAR => '*'],
55+
[T_DOC_COMMENT_WHITESPACE => ' '],
56+
[T_DOC_COMMENT_STRING => 'Unclosed docblock, live coding.... with a blank line at end of file.'],
57+
[T_DOC_COMMENT_WHITESPACE => "\n"],
58+
[T_DOC_COMMENT_CLOSE_TAG => ''],
59+
];
60+
61+
$target = $this->getTargetToken('/* '.__FUNCTION__.' */', T_DOC_COMMENT_OPEN_TAG);
62+
63+
$this->checkTokenSequence($target, $expectedSequence);
64+
65+
}//end testLiveCoding()
66+
67+
68+
}//end class
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
<?php
2+
3+
/* testLiveCoding */
4+
/**
Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
<?php
2+
/**
3+
* Tests that unclosed docblocks during live coding are handled correctly.
4+
*
5+
* @author Juliette Reinders Folmer <[email protected]>
6+
* @copyright 2024 PHPCSStandards and contributors
7+
* @license https://github.com/PHPCSStandards/PHP_CodeSniffer/blob/master/licence.txt BSD Licence
8+
*/
9+
10+
namespace PHP_CodeSniffer\Tests\Core\Tokenizer\Comment;
11+
12+
/**
13+
* Tests that unclosed docblocks during live coding are handled correctly.
14+
*
15+
* @covers PHP_CodeSniffer\Tokenizers\Comment
16+
*/
17+
final class LiveCoding3Test extends CommentTestCase
18+
{
19+
20+
21+
/**
22+
* Data provider.
23+
*
24+
* @see testDocblockOpenerCloser()
25+
*
26+
* @return array<string, array<string, string|int|array<int>>>
27+
*/
28+
public static function dataDocblockOpenerCloser()
29+
{
30+
return [
31+
'live coding: unclosed docblock, no contents, no blank line at end of file' => [
32+
'marker' => '/* testLiveCoding */',
33+
'closerOffset' => 1,
34+
'expectedTags' => [],
35+
],
36+
];
37+
38+
}//end dataDocblockOpenerCloser()
39+
40+
41+
/**
42+
* Verify tokenization of the DocBlock.
43+
*
44+
* @phpcs:disable Squiz.Arrays.ArrayDeclaration.SpaceBeforeDoubleArrow -- Readability is better with alignment.
45+
*
46+
* @return void
47+
*/
48+
public function testLiveCoding()
49+
{
50+
$expectedSequence = [
51+
[T_DOC_COMMENT_OPEN_TAG => '/**'],
52+
[T_DOC_COMMENT_CLOSE_TAG => ''],
53+
];
54+
55+
$target = $this->getTargetToken('/* '.__FUNCTION__.' */', T_DOC_COMMENT_OPEN_TAG);
56+
57+
$this->checkTokenSequence($target, $expectedSequence);
58+
59+
}//end testLiveCoding()
60+
61+
62+
}//end class
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
<?php
2+
3+
/* testLiveCoding */
4+
/**
5+
* The last line of this test must have trailing whitespace.
6+
* So, be careful when saving this file!
7+
*

0 commit comments

Comments
 (0)