• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

PHP-CS-Fixer / PHP-CS-Fixer / 16080300047

04 Jul 2025 08:06PM UTC coverage: 94.842% (-0.004%) from 94.846%
16080300047

push

github

web-flow
feat: support anonymous classes extending `TestCase` in PHPUnit fixers (#8707)

28190 of 29723 relevant lines covered (94.84%)

45.36 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

95.45
/src/Tokenizer/Analyzer/PhpUnitTestCaseAnalyzer.php
1
<?php
2

3
declare(strict_types=1);
4

5
/*
6
 * This file is part of PHP CS Fixer.
7
 *
8
 * (c) Fabien Potencier <fabien@symfony.com>
9
 *     Dariusz RumiƄski <dariusz.ruminski@gmail.com>
10
 *
11
 * This source file is subject to the MIT license that is bundled
12
 * with this source code in the file LICENSE.
13
 */
14

15
namespace PhpCsFixer\Tokenizer\Analyzer;
16

17
use PhpCsFixer\Preg;
18
use PhpCsFixer\Tokenizer\Tokens;
19

20
/**
21
 * @internal
22
 */
23
final class PhpUnitTestCaseAnalyzer
24
{
25
    /**
26
     * Returns an indices of PHPUnit classes in reverse appearance order.
27
     * Order is important - it's reverted, so if we inject tokens into collection,
28
     * we do it for bottom of file first, and then to the top of the file, so we
29
     * mitigate risk of not visiting whole collections (final indices).
30
     *
31
     * @return iterable<array{0: int, 1: int}> array of [int start, int end] indices from later to earlier classes
32
     */
33
    public function findPhpUnitClasses(Tokens $tokens): iterable
34
    {
35
        for ($index = $tokens->count() - 1; $index > 0; --$index) {
19✔
36
            if (!$this->isPhpUnitClass($tokens, $index)) {
17✔
37
                continue;
17✔
38
            }
39

40
            $startIndex = $tokens->getNextTokenOfKind($index, ['{']);
12✔
41
            \assert(\is_int($startIndex));
12✔
42

43
            $endIndex = $tokens->findBlockEnd(Tokens::BLOCK_TYPE_CURLY_BRACE, $startIndex);
12✔
44

45
            yield [$startIndex, $endIndex];
12✔
46
        }
47
    }
48

49
    private function isPhpUnitClass(Tokens $tokens, int $index): bool
50
    {
51
        if (!$tokens[$index]->isGivenKind(T_CLASS)) {
17✔
52
            return false;
17✔
53
        }
54

55
        $extendsIndex = $tokens->getNextTokenOfKind($index, ['{', [T_EXTENDS]]);
17✔
56

57
        if (!$tokens[$extendsIndex]->isGivenKind(T_EXTENDS)) {
17✔
58
            return false;
6✔
59
        }
60

61
        if (Preg::match('/(?:Test|TestCase)$/', $tokens[$index]->getContent())) {
12✔
62
            return true;
×
63
        }
64

65
        while (null !== $index = $tokens->getNextMeaningfulToken($index)) {
12✔
66
            if ($tokens[$index]->equals('{')) {
12✔
67
                break; // end of class signature
1✔
68
            }
69

70
            if (!$tokens[$index]->isGivenKind(T_STRING)) {
12✔
71
                continue; // not part of extends nor part of implements; so continue
8✔
72
            }
73

74
            if (Preg::match('/(?:Test|TestCase)(?:Interface)?$/', $tokens[$index]->getContent())) {
12✔
75
                return true;
12✔
76
            }
77
        }
78

79
        return false;
1✔
80
    }
81
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc