GitHub Access Token became invalid

It seems like the GitHub access token used for retrieving details about this repository from GitHub became invalid. This might prevent certain types of inspections from being run (in particular, everything related to pull requests).
Please ask an admin of your repository to re-new the access token on this website.

CheckAnnotations::checkLarge()   A
last analyzed

Complexity

Conditions 2
Paths 2

Size

Total Lines 6
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 4
CRAP Score 2

Importance

Changes 0
Metric Value
cc 2
eloc 3
nc 2
nop 0
dl 0
loc 6
ccs 4
cts 4
cp 1
crap 2
rs 10
c 0
b 0
f 0
1
<?php
2
3
declare(strict_types=1);
4
5
namespace EdmondsCommerce\PHPQA\PHPUnit;
6
7
use Generator;
8
use InvalidArgumentException;
9
use RecursiveDirectoryIterator;
10
use RecursiveIteratorIterator;
11
use SplFileInfo;
12
13
/**
14
 * Class CheckForLargeAndMediumAnnotations.
15
 *
16
 * This class checks a test directory structure and if it is using the Edmonds Commerce recommended style of a
17
 * `Large`,`Medium` and `Large` sub directory structure, then we will also ensure that the large and medium tests are
18
 * correctly annotated
19
 */
20
final class CheckAnnotations
21
{
22
    /**
23
     * @var string
24
     */
25
    private $largePath;
26
    /**
27
     * @var string
28
     */
29
    private $mediumPath;
30
31
    /**
32
     * @var string
33
     */
34
    private $smallPath;
35
36
    /**
37
     * @var array[]
38
     */
39
    private $errors = [];
40
41
    /**
42
     * Check the Large and Medium directories, if they exist,
43
     * and then assert that all tests have the correct annotation.
44
     *
45
     * @return array[] of errors
46
     */
47 6
    public function main(string $pathToTestsDirectory): array
48
    {
49 6
        if (!is_dir($pathToTestsDirectory)) {
50 1
            throw new InvalidArgumentException(
51 1
                '$pathToTestsDirectory "' . $pathToTestsDirectory . '" does not exist"'
52
            );
53
        }
54 5
        $this->largePath  = $pathToTestsDirectory . '/Large';
55 5
        $this->mediumPath = $pathToTestsDirectory . '/Medium';
56 5
        $this->smallPath  = $pathToTestsDirectory . '/Small';
57 5
        $this->checkLarge();
58 5
        $this->checkMedium();
59 5
        $this->checkSmall();
60
61 5
        return $this->errors;
62
    }
63
64 5
    private function checkLarge(): void
65
    {
66 5
        if (!is_dir($this->largePath)) {
67 3
            return;
68
        }
69 2
        $this->checkDirectory($this->largePath, 'large');
70 2
    }
71
72 4
    private function checkDirectory(string $path, string $annotation): void
73
    {
74 4
        foreach ($this->yieldTestFilesInPath($path) as $fileInfo) {
75 4
            if (strpos($fileInfo->getFilename(), 'Test.php') === false) {
76 4
                continue;
77
            }
78 4
            $this->checkFile($fileInfo, $annotation);
79
        }
80 4
    }
81
82
    /**
83
     * @return Generator|SplFileInfo[]
84
     */
85 4
    private function yieldTestFilesInPath(string $path): Generator
86
    {
87 4
        $recursiveDirectoryIterator = new RecursiveDirectoryIterator($path);
88 4
        $iterator                   = new RecursiveIteratorIterator($recursiveDirectoryIterator);
89 4
        foreach ($iterator as $fileInfo) {
90 4
            yield $fileInfo;
91
        }
92 4
    }
93
94 4
    private function checkFile(SplFileInfo $fileInfo, string $annotation): void
95
    {
96 4
        $contents = (string)file_get_contents($fileInfo->getPathname());
97 4
        if ($this->isAnnotationInClassDocBlock($contents, $annotation) === true) {
98 2
            return;
99
        }
100
101 4
        $matches = [];
102 4
        preg_match_all(
103
            <<<REGEXP
104
%(?<docblock>/\\*(?:[^*]|\n|(?:\\*(?:[^/]|\n)))*\\*/|\n)\\s+?public\\s+?function\\s+?(?<method>.+?)\\(%
105
REGEXP
106 4
            . 'si',
107 4
            $contents,
108 4
            $matches
109
        );
110 4
        if ($matches[0] === '') {
111
            $this->errors[$fileInfo->getFilename()][] = 'Failed finding any doc blocks';
112
113
            return;
114
        }
115 4
        foreach ($matches['method'] as $key => $method) {
116 4
            $docblock = $matches['docblock'][$key];
117
            /* Found the annotation - continue */
118 4
            if (\strpos($docblock, '@' . $annotation) !== false) {
119 3
                continue;
120
            }
121
            /* No @test annotation found & method not beginning test =  not a test, so continue */
122 3
            if (\strpos($docblock, '@test') === false && \strpos($method, 'test') === false) {
123
                continue;
124
            }
125 3
            $this->errors[$fileInfo->getFilename()][] =
126 3
                'Failed finding @' . $annotation . ' for method: ' . $method;
127
        }
128 4
    }
129
130
    /**
131
     * It is possible to put the annotation in the class doc, and have it apply to all tests in the file. This checks
132
     * the class docblock and if the annotation is found there returns true. If not it returns false and the rest of the
133
     * self::checkFile method runs looking for it in the method docblocks.
134
     */
135 4
    private function isAnnotationInClassDocBlock(string $fileContent, string $annotation): bool
136
    {
137 4
        $matches = [];
138 4
        preg_match_all(
139
            <<<REGEXP
140
%(?<docblock>/\\*(?:[^*]|\n|(?:\\*(?:[^/]|\n)))*\\*/)\\s+?(final |)class\\s+?(?<classname>.+?)\\s+?extends%
141
REGEXP
142 4
            . 'si',
143 4
            $fileContent,
144 4
            $matches
145
        );
146 4
        if (count($matches['docblock']) !== 1) {
147
            return false;
148
        }
149 4
        $docBlock = array_shift($matches['docblock']);
150
151 4
        return strpos($docBlock, '@' . $annotation) !== false;
152
    }
153
154 5
    private function checkMedium(): void
155
    {
156 5
        if (!is_dir($this->mediumPath)) {
157 1
            return;
158
        }
159 4
        $this->checkDirectory($this->mediumPath, 'medium');
160 4
    }
161
162 5
    private function checkSmall(): void
163
    {
164 5
        if (!is_dir($this->smallPath)) {
165 2
            return;
166
        }
167 3
        $this->checkDirectory($this->smallPath, 'small');
168 3
    }
169
}
170