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

NexusPHP / tachycardia / 13396103169

18 Feb 2025 05:04PM UTC coverage: 98.694%. First build
13396103169

push

github

paulbalandan
Allow phpunit ^12

25 of 27 new or added lines in 1 file covered. (92.59%)

529 of 536 relevant lines covered (98.69%)

39.22 hits per line

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

95.45
/src/Metadata/Parser/AnnotationParser.php
1
<?php
2

3
declare(strict_types=1);
4

5
/**
6
 * This file is part of Nexus Tachycardia.
7
 *
8
 * (c) 2021 John Paul E. Balandan, CPA <paulbalandan@gmail.com>
9
 *
10
 * For the full copyright and license information, please view
11
 * the LICENSE file that was distributed with this source code.
12
 */
13

14
namespace Nexus\PHPUnit\Tachycardia\Metadata\Parser;
15

16
use Nexus\PHPUnit\Tachycardia\Metadata\LimitCollection;
17
use Nexus\PHPUnit\Tachycardia\Metadata\NoTimeLimitForClass;
18
use Nexus\PHPUnit\Tachycardia\Metadata\NoTimeLimitForMethod;
19
use Nexus\PHPUnit\Tachycardia\Metadata\TimeLimitForClass;
20
use Nexus\PHPUnit\Tachycardia\Metadata\TimeLimitForMethod;
21

22
/**
23
 * @internal
24
 */
25
final class AnnotationParser implements Parser
26
{
27
    /**
28
     * @var array<class-string, array<non-empty-string, non-empty-list<string>>>
29
     */
30
    private array $classDocblocks = [];
31

32
    /**
33
     * @var array<class-string, array<non-empty-string, array<non-empty-string, non-empty-list<string>>>>
34
     */
35
    private array $methodDocblocks = [];
36

37
    public function forClass(string $className): LimitCollection
38
    {
39
        $limits = [];
63✔
40

41
        foreach ($this->parseClassName($className) as $annotation => $values) {
63✔
42
            switch ($annotation) {
43
                case 'noTimeLimit':
63✔
44
                    $limits[] = new NoTimeLimitForClass();
18✔
45
                    break;
18✔
46

47
                case 'timeLimit':
63✔
48
                    $limits[] = new TimeLimitForClass((float) $values[0]);
36✔
49
                    break;
36✔
50
            }
51
        }
52

53
        return LimitCollection::fromArray($limits);
63✔
54
    }
55

56
    public function forMethod(string $className, string $methodName): LimitCollection
57
    {
58
        $limits = [];
72✔
59

60
        foreach ($this->parseMethodName($className, $methodName) as $annotation => $values) {
72✔
61
            switch ($annotation) {
62
                case 'noTimeLimit':
54✔
63
                    $limits[] = new NoTimeLimitForMethod();
27✔
64
                    break;
27✔
65

66
                case 'timeLimit':
27✔
67
                    $limits[] = new TimeLimitForMethod((float) $values[0]);
27✔
68
                    break;
27✔
69
            }
70
        }
71

72
        return LimitCollection::fromArray($limits);
72✔
73
    }
74

75
    public function forClassAndMethod(string $className, string $methodName): LimitCollection
76
    {
77
        return $this->forClass($className)->mergeWith($this->forMethod($className, $methodName));
18✔
78
    }
79

80
    /**
81
     * @param class-string $class
82
     *
83
     * @return array<non-empty-string, non-empty-list<string>>
84
     */
85
    private function parseClassName(string $class): array
86
    {
87
        if (\array_key_exists($class, $this->classDocblocks)) {
63✔
NEW
88
            return $this->classDocblocks[$class];
×
89
        }
90

91
        $reflection = new \ReflectionClass($class);
63✔
92
        $annotations = array_merge(
63✔
93
            $this->parseDocComment((string) $reflection->getDocComment()),
63✔
94
            ...array_map(
63✔
95
                fn(\ReflectionClass $trait): array => $this->parseDocComment((string) $trait->getDocComment()),
63✔
96
                $reflection->getTraits(),
63✔
97
            ),
63✔
98
        );
63✔
99

100
        $this->classDocblocks[$class] = $annotations;
63✔
101

102
        return $annotations;
63✔
103
    }
104

105
    /**
106
     * @param class-string     $class
107
     * @param non-empty-string $method
108
     *
109
     * @return array<non-empty-string, non-empty-list<string>>
110
     */
111
    private function parseMethodName(string $class, string $method): array
112
    {
113
        if (isset($this->methodDocblocks[$class][$method])) {
72✔
NEW
114
            return $this->methodDocblocks[$class][$method];
×
115
        }
116

117
        $reflection = new \ReflectionMethod($class, $method);
72✔
118
        $annotations = $this->parseDocComment((string) $reflection->getDocComment());
72✔
119

120
        $this->methodDocblocks[$class][$method] = $annotations;
72✔
121

122
        return $annotations;
72✔
123
    }
124

125
    /**
126
     * @return array<non-empty-string, non-empty-list<string>>
127
     */
128
    private function parseDocComment(string $docComment): array
129
    {
130
        $docComment = substr($docComment, 3, -2);
90✔
131
        $annotations = [];
90✔
132

133
        if (preg_match_all('/@(?P<name>[A-Za-z_-]+)(?:[ \t]+(?P<value>.*?))?[ \t]*\r?$/m', $docComment, $matches) > 0) {
90✔
134
            $numMatches = \count($matches[0]);
81✔
135

136
            for ($i = 0; $i < $numMatches; ++$i) {
81✔
137
                $annotations[$matches['name'][$i]][] = $matches['value'][$i];
81✔
138
            }
139
        }
140

141
        return $annotations;
90✔
142
    }
143
}
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