File: ReplaceTabsInTokenTestCase.php

package info (click to toggle)
php-codesniffer 3.11.2-2
  • links: PTS, VCS
  • area: main
  • in suites: sid
  • size: 13,772 kB
  • sloc: php: 84,771; pascal: 10,061; xml: 6,832; javascript: 2,096; sh: 11; makefile: 4
file content (274 lines) | stat: -rw-r--r-- 10,651 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
<?php
/**
 * Base class to test the tab replacement logic.
 *
 * @author    Juliette Reinders Folmer <phpcs_nospam@adviesenzo.nl>
 * @copyright 2024 PHPCSStandards and contributors
 * @license   https://github.com/PHPCSStandards/PHP_CodeSniffer/blob/master/licence.txt BSD Licence
 */

namespace PHP_CodeSniffer\Tests\Core\Tokenizers\Tokenizer;

use Exception;
use PHP_CodeSniffer\Tests\Core\Tokenizers\AbstractTokenizerTestCase;

/**
 * Tab replacement test case.
 *
 * @covers PHP_CodeSniffer\Tokenizers\Tokenizer::replaceTabsInToken
 */
abstract class ReplaceTabsInTokenTestCase extends AbstractTokenizerTestCase
{

    /**
     * The name of the test case file used by this test.
     *
     * @var string
     */
    private static $caseFileName;


    /**
     * Make a copy the test case file we want to use for this test (as the file will be used by multiple tests).
     *
     * @beforeClass
     *
     * @return void
     *
     * @throws \Exception In case the base test case file would not be available.
     */
    public static function copyCaseFile()
    {
        $relativeCN         = str_replace(__NAMESPACE__.'\\', '', get_called_class());
        self::$caseFileName = __DIR__.DIRECTORY_SEPARATOR.$relativeCN.'.inc';

        $baseFileName = realpath(__DIR__.'/ReplaceTabsInTokenTest.inc');
        if (is_string($baseFileName) === false) {
            throw new Exception('Base test case file "ReplaceTabsInTokenTest.inc" not found');
        }

        if (copy($baseFileName, self::$caseFileName) === false) {
            throw new Exception(sprintf('Failed to copy test case file "ReplaceTabsInTokenTest.inc" to %s', self::$caseFileName));
        }

    }//end copyCaseFile()


    /**
     * Delete the copied test case file after use.
     *
     * @afterClass
     *
     * @return void
     */
    public static function deleteCaseFile()
    {
        @unlink(self::$caseFileName);

    }//end deleteCaseFile()


    /**
     * Verify that if a token not containing tabs would be passed to the replaceTabsInToken() method,
     * yes, the `orig_content` key is added, but no changes are made to the token `content` or `length` values.
     *
     * @param string                         $testMarker The comment prefacing the target token.
     * @param int|string                     $testTarget Token code to look for.
     * @param array<string, int|string|null> $expected   Expectations for the token array.
     * @param int                            $offset     Optional. Offset from the target token to get to the _real_ target.
     *                                                   This is specifically needed to target indentation whitespace.
     *
     * @dataProvider dataNoReplacementsAreMadeWhenNoTabsAreFound
     *
     * @return void
     */
    public function testNoReplacementsAreMadeWhenNoTabsAreFound($testMarker, $testTarget, $expected, $offset=0)
    {
        $tokens  = $this->phpcsFile->getTokens();
        $target  = $this->getTargetToken($testMarker, $testTarget);
        $target += $offset;

        foreach ($expected as $key => $value) {
            if ($key === 'orig_content' && $value === null) {
                $this->assertArrayNotHasKey($key, $tokens[$target], "Unexpected 'orig_content' key found in the token array.");
                continue;
            }

            $this->assertArrayHasKey($key, $tokens[$target], "Key $key not found in the token array.");
            $this->assertSame($value, $tokens[$target][$key], "Value for key $key does not match expectation.");
        }

    }//end testNoReplacementsAreMadeWhenNoTabsAreFound()


    /**
     * Data provider.
     *
     * @see testNoReplacementsAreMadeWhenNoTabsAreFound()
     *
     * @return array<string, array<string, int|string|array<string, int|string|null>>>
     */
    public static function dataNoReplacementsAreMadeWhenNoTabsAreFound()
    {
        return [
            'Indentation whitespace, only spaces'      => [
                'testMarker' => '/* testNoReplacementNeeded */',
                'testTarget' => T_WHITESPACE,
                'expected'   => [
                    'length'       => 4,
                    'content'      => '    ',
                    'orig_content' => null,
                ],
                'offset'     => 1,
            ],
            'Trailing comment not containing any tabs' => [
                'testMarker' => '/* testNoReplacementNeeded */',
                'testTarget' => T_COMMENT,
                'expected'   => [
                    'length'       => 35,
                    'content'      => '// Comment not containing any tabs.
',
                    'orig_content' => null,
                ],
            ],
        ];

    }//end dataNoReplacementsAreMadeWhenNoTabsAreFound()


    /**
     * Test tab replacement in tokens.
     *
     * @param string                         $testMarker The comment prefacing the target token.
     * @param int|string                     $testTarget Token code to look for.
     * @param array<string, int|string|null> $expected   Expectations for the token array.
     * @param int                            $offset     Optional. Offset from the target token to get to the _real_ target.
     *                                                   This is specifically needed to target indentation whitespace.
     *
     * @dataProvider dataTabReplacement
     *
     * @return void
     */
    public function testTabReplacement($testMarker, $testTarget, $expected, $offset=0)
    {
        $tokens  = $this->phpcsFile->getTokens();
        $target  = $this->getTargetToken($testMarker, $testTarget);
        $target += $offset;

        foreach ($expected as $key => $value) {
            if ($key === 'orig_content' && $value === null) {
                $this->assertArrayNotHasKey($key, $tokens[$target], "Unexpected 'orig_content' key found in the token array.");
                continue;
            }

            $this->assertArrayHasKey($key, $tokens[$target], "Key $key not found in the token array.");
            $this->assertSame($value, $tokens[$target][$key], "Value for key $key does not match expectation.");
        }

    }//end testTabReplacement()


    /**
     * Data provider.
     *
     * @see testTabReplacement()
     *
     * @return array<string, array<string, int|string|array<string, int|string>>>
     *
     * @throws \Exception When the getTabReplacementExpected() method doesn't provide data in the correct format.
     */
    public static function dataTabReplacement()
    {
        $data = [
            'Tab indentation'                                                      => [
                'testMarker' => '/* testTabIndentation */',
                'testTarget' => T_WHITESPACE,
            ],
            'Mixed tab/space indentation'                                          => [
                'testMarker' => '/* testMixedIndentation */',
                'testTarget' => T_WHITESPACE,
            ],
            'Inline: single tab in text string'                                    => [
                'testMarker' => '/* testInlineSingleTab */',
                'testTarget' => T_CONSTANT_ENCAPSED_STRING,
            ],
            'Inline: single tab between each word in text string'                  => [
                'testMarker' => '/* testInlineSingleTabBetweenEachWord */',
                'testTarget' => T_DOUBLE_QUOTED_STRING,
            ],
            'Inline: multiple tabs in heredoc'                                     => [
                'testMarker' => '/* testInlineMultiTab */',
                'testTarget' => T_HEREDOC,
            ],
            'Inline: multiple tabs between each word in nowdoc'                    => [
                'testMarker' => '/* testInlineMultipleTabsBetweenEachWord */',
                'testTarget' => T_NOWDOC,
            ],
            'Inline: mixed spaces/tabs in text string'                             => [
                'testMarker' => '/* testInlineMixedSpacesTabs */',
                'testTarget' => T_CONSTANT_ENCAPSED_STRING,
            ],
            'Inline: mixed spaces/tabs between each word in text string'           => [
                'testMarker' => '/* testInlineMixedSpacesTabsBetweenEachWord */',
                'testTarget' => T_DOUBLE_QUOTED_STRING,
            ],
            'Inline: tab becomes single space in comment (with tabwidth 4)'        => [
                'testMarker' => '/* testInlineSize1 */',
                'testTarget' => T_COMMENT,
            ],
            'Inline: tab becomes 2 spaces in comment (with tabwidth 4)'            => [
                'testMarker' => '/* testInlineSize2 */',
                'testTarget' => T_COMMENT,
            ],
            'Inline: tab becomes 3 spaces in doc comment string (with tabwidth 4)' => [
                'testMarker' => '/* testInlineSize3 */',
                'testTarget' => T_DOC_COMMENT_STRING,
            ],
            'Inline: tab becomes 4 spaces in comment (with tabwidth 4)'            => [
                'testMarker' => '/* testInlineSize4 */',
                'testTarget' => T_COMMENT,
            ],
        ];

        $expectations = static::getTabReplacementExpected();

        foreach ($data as $key => $value) {
            if (isset($expectations[$key]) === false || is_array($expectations[$key]) === false) {
                throw new Exception(
                    sprintf('Invalid getTabReplacementExpected() method. Missing expectation array for the "%s" test case', $key)
                );
            }

            if (isset($expectations[$key]['length'], $expectations[$key]['content']) === false
                || array_key_exists('orig_content', $expectations[$key]) === false
            ) {
                throw new Exception(
                    sprintf('Invalid expectation array for the "%s" test case. The array must contain the "length", "content" and "orig_content" keys', $key)
                );
            }

            $data[$key]['expected'] = $expectations[$key];
        }

        // Set offset for test cases targetting whitespace.
        $data['Tab indentation']['offset'] = 1;
        $data['Mixed tab/space indentation']['offset'] = 1;

        return $data;

    }//end dataTabReplacement()


    /**
     * Data provider helper.
     *
     * Should be declared in child classes to set the expectations for the token array.
     *
     * @see dataTabReplacement()
     *
     * @return array<string, array<string, int|string|null>>
     */
    abstract public static function getTabReplacementExpected();


}//end class