55namespace Cdn77 \TestUtils \TestCheck ;
66
77use Cdn77 \EntityFqnExtractor \ClassExtractor ;
8+ use InvalidArgumentException ;
89use PHPUnit \Framework \Attributes \Group ;
910use PHPUnit \Framework \TestCase ;
1011use ReflectionClass ;
1112
12- use function Safe \preg_match ;
13+ use function array_intersect ;
14+ use function array_map ;
15+ use function in_array ;
16+ use function Safe \preg_match_all ;
1317use function sprintf ;
1418
1519final class EveryTestHasGroup implements TestCheck
1620{
1721 /**
1822 * @param iterable<string> $filePathNames
19- * @param list<string> $allowedGroups
23+ * @param non-empty-list<string>|null $requiredGroups
24+ * @param list<string> $supportedGroups
2025 */
21- public function __construct (private iterable $ filePathNames , private array $ allowedGroups )
22- {
26+ public function __construct (
27+ private iterable $ filePathNames ,
28+ private array |null $ requiredGroups = null ,
29+ private array |null $ supportedGroups = null ,
30+ ) {
31+ if (
32+ $ requiredGroups !== null
33+ && $ supportedGroups !== null
34+ && array_intersect ($ requiredGroups , $ supportedGroups ) !== []
35+ ) {
36+ throw new InvalidArgumentException ('Required groups must not be in supported groups ' );
37+ }
2338 }
2439
2540 public function run (TestCase $ testCaseContext ): void
@@ -31,48 +46,63 @@ public function run(TestCase $testCaseContext): void
3146 }
3247
3348 $ groupAttributes = $ classReflection ->getAttributes (Group::class);
34- foreach ($ groupAttributes as $ groupAttribute ) {
49+ if ($ groupAttributes !== []) {
50+ $ groups = array_map (
51+ static fn ($ groupAttribute ) => $ groupAttribute ->getArguments ()[0 ],
52+ $ groupAttributes ,
53+ );
54+ } else {
55+ $ docComment = $ classReflection ->getDocComment ();
56+ if ($ docComment === false ) {
57+ $ testCaseContext ::fail (sprintf ('Test "%s" is missing phpdoc comment ' , $ classReflection ->getName ()));
58+ }
59+
60+ if (preg_match_all ('~\* @group +(?<group>\w+)(\n| \*/)~ ' , $ docComment , $ matches ) === 0 ) {
61+ $ testCaseContext ::fail (
62+ sprintf ('Test "%s" is missing @group annotation ' , $ classReflection ->getName ()),
63+ );
64+ }
65+
66+ $ groups = $ matches ['group ' ];
67+ }
68+
69+ $ hasRequiredGroup = false ;
70+ foreach ($ groups as $ group ) {
71+ if (
72+ $ this ->requiredGroups !== null
73+ && in_array ($ group , $ this ->requiredGroups , true )
74+ ) {
75+ $ hasRequiredGroup = true ;
76+
77+ continue ;
78+ }
79+
80+ if ($ this ->supportedGroups === null ) {
81+ continue ;
82+ }
83+
3584 $ testCaseContext ::assertContains (
36- $ groupAttribute -> getArguments ()[ 0 ] ,
37- $ this ->allowedGroups ,
85+ $ group ,
86+ $ this ->supportedGroups ,
3887 sprintf (
39- 'Test "%s" has invalid @group annotation "%s" ' ,
88+ 'Test "%s" has invalid Group attribute "%s" ' ,
4089 $ classReflection ->getName (),
41- $ groupAttribute -> getArguments ()[ 0 ] ,
90+ $ group ,
4291 ),
4392 );
4493 }
4594
46- if ($ groupAttributes !== []) {
47- continue ;
95+ if ($ this ->requiredGroups !== null ) {
96+ $ testCaseContext ::assertTrue (
97+ $ hasRequiredGroup ,
98+ sprintf (
99+ 'Test "%s" does not have required Group attribute ' ,
100+ $ classReflection ->getName (),
101+ ),
102+ );
103+ } else {
104+ $ testCaseContext ::assertTrue (true );
48105 }
49-
50- $ this ->validateDocComment ($ testCaseContext , $ classReflection );
51- }
52- }
53-
54- /** @param ReflectionClass<object> $reflectionClass */
55- private function validateDocComment (TestCase $ testCaseContext , ReflectionClass $ reflectionClass ): void
56- {
57- $ docComment = $ reflectionClass ->getDocComment ();
58- if ($ docComment === false ) {
59- $ testCaseContext ::fail (sprintf ('Test "%s" is missing phpdoc comment ' , $ reflectionClass ->getName ()));
60106 }
61-
62- if (preg_match ('~\* @group +(?<group>\w+)(\n| \*/)~ ' , $ docComment , $ matches ) !== 1 ) {
63- $ testCaseContext ::fail (
64- sprintf ('Test "%s" is missing @group annotation ' , $ reflectionClass ->getName ()),
65- );
66- }
67-
68- $ testCaseContext ::assertContains (
69- $ matches ['group ' ],
70- $ this ->allowedGroups ,
71- sprintf (
72- 'Test "%s" has invalid @group annotation "%s" ' ,
73- $ reflectionClass ->getName (),
74- $ matches ['group ' ],
75- ),
76- );
77107 }
78108}
0 commit comments