Skip to content

Commit 9dcb6f7

Browse files
committed
feat: Enhance group filtering logic and update help documentation to support AND logic for group combinations
1 parent a9fe626 commit 9dcb6f7

9 files changed

Lines changed: 328 additions & 3 deletions

File tree

src/Runner/Filter/GroupFilterIterator.php

Lines changed: 37 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,9 +9,13 @@
99
*/
1010
namespace PHPUnit\Runner\Filter;
1111

12+
use function array_intersect;
1213
use function array_merge;
1314
use function array_push;
15+
use function array_values;
16+
use function explode;
1417
use function in_array;
18+
use function str_contains;
1519
use PHPUnit\Framework\Test;
1620
use PHPUnit\Framework\TestCase;
1721
use PHPUnit\Framework\TestSuite;
@@ -39,16 +43,46 @@ public function __construct(RecursiveIterator $iterator, array $groups, TestSuit
3943
{
4044
parent::__construct($iterator);
4145

42-
$groupTests = [];
46+
$groupTests = [];
47+
$suiteGroups = $suite->groups();
4348

44-
foreach ($suite->groups() as $group => $tests) {
45-
if (in_array($group, $groups, true)) {
49+
$simpleGroups = [];
50+
$compoundGroups = [];
51+
52+
foreach ($groups as $group) {
53+
if (str_contains($group, '+')) {
54+
$compoundGroups[] = explode('+', $group);
55+
} else {
56+
$simpleGroups[] = $group;
57+
}
58+
}
59+
60+
foreach ($suiteGroups as $group => $tests) {
61+
if (in_array($group, $simpleGroups, true)) {
4662
$groupTests = array_merge($groupTests, $tests);
4763

4864
array_push($groupTests, ...$groupTests);
4965
}
5066
}
5167

68+
foreach ($compoundGroups as $constituents) {
69+
$testsInAllGroups = null;
70+
71+
foreach ($constituents as $part) {
72+
$testsInGroup = $suiteGroups[$part] ?? [];
73+
74+
if ($testsInAllGroups === null) {
75+
$testsInAllGroups = $testsInGroup;
76+
} else {
77+
$testsInAllGroups = array_values(array_intersect($testsInAllGroups, $testsInGroup));
78+
}
79+
}
80+
81+
if ($testsInAllGroups !== null && $testsInAllGroups !== []) {
82+
$groupTests = array_merge($groupTests, $testsInAllGroups);
83+
}
84+
}
85+
5286
$this->groupTests = $groupTests;
5387
}
5488

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
<?xml version="1.0" encoding="UTF-8"?>
2+
<phpunit xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
3+
xsi:noNamespaceSchemaLocation="../../../../phpunit.xsd"
4+
>
5+
<testsuites>
6+
<testsuite name="default">
7+
<directory>tests</directory>
8+
</testsuite>
9+
</testsuites>
10+
</phpunit>
Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
<?php declare(strict_types=1);
2+
/*
3+
* This file is part of PHPUnit.
4+
*
5+
* (c) Sebastian Bergmann <sebastian@phpunit.de>
6+
*
7+
* For the full copyright and license information, please view the LICENSE
8+
* file that was distributed with this source code.
9+
*/
10+
namespace PHPUnit\TestFixture\GroupsWithAndLogic;
11+
12+
use PHPUnit\Framework\Attributes\Group;
13+
use PHPUnit\Framework\TestCase;
14+
15+
final class MultiGroupTest extends TestCase
16+
{
17+
#[Group('X')]
18+
public function testX(): void
19+
{
20+
$this->assertTrue(true);
21+
}
22+
23+
#[Group('Y')]
24+
public function testY(): void
25+
{
26+
$this->assertTrue(true);
27+
}
28+
29+
#[Group('X')]
30+
#[Group('Y')]
31+
public function testXY(): void
32+
{
33+
$this->assertTrue(true);
34+
}
35+
36+
#[Group('X')]
37+
#[Group('Y')]
38+
#[Group('Z')]
39+
public function testXYZ(): void
40+
{
41+
$this->assertTrue(true);
42+
}
43+
44+
#[Group('Z')]
45+
public function testZ(): void
46+
{
47+
$this->assertTrue(true);
48+
}
49+
}
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
--TEST--
2+
phpunit --exclude-group X+Y tests/MultiGroupTest.php (AND exclude group filter)
3+
--FILE--
4+
<?php declare(strict_types=1);
5+
$_SERVER['argv'][] = '--do-not-cache-result';
6+
$_SERVER['argv'][] = '--no-configuration';
7+
$_SERVER['argv'][] = '--debug';
8+
$_SERVER['argv'][] = '--exclude-group';
9+
$_SERVER['argv'][] = 'X+Y';
10+
$_SERVER['argv'][] = __DIR__ . '/../../_files/groups-with-and-logic/tests/MultiGroupTest.php';
11+
12+
require_once __DIR__ . '/../../../bootstrap.php';
13+
14+
(new PHPUnit\TextUI\Application)->run($_SERVER['argv']);
15+
--EXPECTF--
16+
PHPUnit Started (PHPUnit %s using %s)
17+
Test Runner Configured
18+
Event Facade Sealed
19+
Test Suite Loaded (5 tests)
20+
Test Runner Started
21+
Test Suite Sorted
22+
Test Suite Filtered (3 tests)
23+
Test Runner Execution Started (3 tests)
24+
Test Suite Started (PHPUnit\TestFixture\GroupsWithAndLogic\MultiGroupTest, 3 tests)
25+
Test Preparation Started (PHPUnit\TestFixture\GroupsWithAndLogic\MultiGroupTest::testX)
26+
Test Prepared (PHPUnit\TestFixture\GroupsWithAndLogic\MultiGroupTest::testX)
27+
Test Passed (PHPUnit\TestFixture\GroupsWithAndLogic\MultiGroupTest::testX)
28+
Test Finished (PHPUnit\TestFixture\GroupsWithAndLogic\MultiGroupTest::testX)
29+
Test Preparation Started (PHPUnit\TestFixture\GroupsWithAndLogic\MultiGroupTest::testY)
30+
Test Prepared (PHPUnit\TestFixture\GroupsWithAndLogic\MultiGroupTest::testY)
31+
Test Passed (PHPUnit\TestFixture\GroupsWithAndLogic\MultiGroupTest::testY)
32+
Test Finished (PHPUnit\TestFixture\GroupsWithAndLogic\MultiGroupTest::testY)
33+
Test Preparation Started (PHPUnit\TestFixture\GroupsWithAndLogic\MultiGroupTest::testZ)
34+
Test Prepared (PHPUnit\TestFixture\GroupsWithAndLogic\MultiGroupTest::testZ)
35+
Test Passed (PHPUnit\TestFixture\GroupsWithAndLogic\MultiGroupTest::testZ)
36+
Test Finished (PHPUnit\TestFixture\GroupsWithAndLogic\MultiGroupTest::testZ)
37+
Test Suite Finished (PHPUnit\TestFixture\GroupsWithAndLogic\MultiGroupTest, 3 tests)
38+
Test Runner Execution Finished
39+
Test Runner Finished
40+
PHPUnit Finished (Shell Exit Code: 0)
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
--TEST--
2+
phpunit --exclude-group X+Y --exclude-group Z tests/MultiGroupTest.php (AND combined with OR exclude group filter)
3+
--FILE--
4+
<?php declare(strict_types=1);
5+
$_SERVER['argv'][] = '--do-not-cache-result';
6+
$_SERVER['argv'][] = '--no-configuration';
7+
$_SERVER['argv'][] = '--debug';
8+
$_SERVER['argv'][] = '--exclude-group';
9+
$_SERVER['argv'][] = 'X+Y';
10+
$_SERVER['argv'][] = '--exclude-group';
11+
$_SERVER['argv'][] = 'Z';
12+
$_SERVER['argv'][] = __DIR__ . '/../../_files/groups-with-and-logic/tests/MultiGroupTest.php';
13+
14+
require_once __DIR__ . '/../../../bootstrap.php';
15+
16+
(new PHPUnit\TextUI\Application)->run($_SERVER['argv']);
17+
--EXPECTF--
18+
PHPUnit Started (PHPUnit %s using %s)
19+
Test Runner Configured
20+
Event Facade Sealed
21+
Test Suite Loaded (5 tests)
22+
Test Runner Started
23+
Test Suite Sorted
24+
Test Suite Filtered (2 tests)
25+
Test Runner Execution Started (2 tests)
26+
Test Suite Started (PHPUnit\TestFixture\GroupsWithAndLogic\MultiGroupTest, 2 tests)
27+
Test Preparation Started (PHPUnit\TestFixture\GroupsWithAndLogic\MultiGroupTest::testX)
28+
Test Prepared (PHPUnit\TestFixture\GroupsWithAndLogic\MultiGroupTest::testX)
29+
Test Passed (PHPUnit\TestFixture\GroupsWithAndLogic\MultiGroupTest::testX)
30+
Test Finished (PHPUnit\TestFixture\GroupsWithAndLogic\MultiGroupTest::testX)
31+
Test Preparation Started (PHPUnit\TestFixture\GroupsWithAndLogic\MultiGroupTest::testY)
32+
Test Prepared (PHPUnit\TestFixture\GroupsWithAndLogic\MultiGroupTest::testY)
33+
Test Passed (PHPUnit\TestFixture\GroupsWithAndLogic\MultiGroupTest::testY)
34+
Test Finished (PHPUnit\TestFixture\GroupsWithAndLogic\MultiGroupTest::testY)
35+
Test Suite Finished (PHPUnit\TestFixture\GroupsWithAndLogic\MultiGroupTest, 2 tests)
36+
Test Runner Execution Finished
37+
Test Runner Finished
38+
PHPUnit Finished (Shell Exit Code: 0)
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
--TEST--
2+
phpunit --exclude-group X+Y+Z tests/MultiGroupTest.php (AND exclude group filter with three groups)
3+
--FILE--
4+
<?php declare(strict_types=1);
5+
$_SERVER['argv'][] = '--do-not-cache-result';
6+
$_SERVER['argv'][] = '--no-configuration';
7+
$_SERVER['argv'][] = '--debug';
8+
$_SERVER['argv'][] = '--exclude-group';
9+
$_SERVER['argv'][] = 'X+Y+Z';
10+
$_SERVER['argv'][] = __DIR__ . '/../../_files/groups-with-and-logic/tests/MultiGroupTest.php';
11+
12+
require_once __DIR__ . '/../../../bootstrap.php';
13+
14+
(new PHPUnit\TextUI\Application)->run($_SERVER['argv']);
15+
--EXPECTF--
16+
PHPUnit Started (PHPUnit %s using %s)
17+
Test Runner Configured
18+
Event Facade Sealed
19+
Test Suite Loaded (5 tests)
20+
Test Runner Started
21+
Test Suite Sorted
22+
Test Suite Filtered (4 tests)
23+
Test Runner Execution Started (4 tests)
24+
Test Suite Started (PHPUnit\TestFixture\GroupsWithAndLogic\MultiGroupTest, 4 tests)
25+
Test Preparation Started (PHPUnit\TestFixture\GroupsWithAndLogic\MultiGroupTest::testX)
26+
Test Prepared (PHPUnit\TestFixture\GroupsWithAndLogic\MultiGroupTest::testX)
27+
Test Passed (PHPUnit\TestFixture\GroupsWithAndLogic\MultiGroupTest::testX)
28+
Test Finished (PHPUnit\TestFixture\GroupsWithAndLogic\MultiGroupTest::testX)
29+
Test Preparation Started (PHPUnit\TestFixture\GroupsWithAndLogic\MultiGroupTest::testY)
30+
Test Prepared (PHPUnit\TestFixture\GroupsWithAndLogic\MultiGroupTest::testY)
31+
Test Passed (PHPUnit\TestFixture\GroupsWithAndLogic\MultiGroupTest::testY)
32+
Test Finished (PHPUnit\TestFixture\GroupsWithAndLogic\MultiGroupTest::testY)
33+
Test Preparation Started (PHPUnit\TestFixture\GroupsWithAndLogic\MultiGroupTest::testXY)
34+
Test Prepared (PHPUnit\TestFixture\GroupsWithAndLogic\MultiGroupTest::testXY)
35+
Test Passed (PHPUnit\TestFixture\GroupsWithAndLogic\MultiGroupTest::testXY)
36+
Test Finished (PHPUnit\TestFixture\GroupsWithAndLogic\MultiGroupTest::testXY)
37+
Test Preparation Started (PHPUnit\TestFixture\GroupsWithAndLogic\MultiGroupTest::testZ)
38+
Test Prepared (PHPUnit\TestFixture\GroupsWithAndLogic\MultiGroupTest::testZ)
39+
Test Passed (PHPUnit\TestFixture\GroupsWithAndLogic\MultiGroupTest::testZ)
40+
Test Finished (PHPUnit\TestFixture\GroupsWithAndLogic\MultiGroupTest::testZ)
41+
Test Suite Finished (PHPUnit\TestFixture\GroupsWithAndLogic\MultiGroupTest, 4 tests)
42+
Test Runner Execution Finished
43+
Test Runner Finished
44+
PHPUnit Finished (Shell Exit Code: 0)
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
--TEST--
2+
phpunit --group X+Y tests/MultiGroupTest.php (AND group filter)
3+
--FILE--
4+
<?php declare(strict_types=1);
5+
$_SERVER['argv'][] = '--do-not-cache-result';
6+
$_SERVER['argv'][] = '--no-configuration';
7+
$_SERVER['argv'][] = '--debug';
8+
$_SERVER['argv'][] = '--group';
9+
$_SERVER['argv'][] = 'X+Y';
10+
$_SERVER['argv'][] = __DIR__ . '/../../_files/groups-with-and-logic/tests/MultiGroupTest.php';
11+
12+
require_once __DIR__ . '/../../../bootstrap.php';
13+
14+
(new PHPUnit\TextUI\Application)->run($_SERVER['argv']);
15+
--EXPECTF--
16+
PHPUnit Started (PHPUnit %s using %s)
17+
Test Runner Configured
18+
Event Facade Sealed
19+
Test Suite Loaded (5 tests)
20+
Test Runner Started
21+
Test Suite Sorted
22+
Test Suite Filtered (2 tests)
23+
Test Runner Execution Started (2 tests)
24+
Test Suite Started (PHPUnit\TestFixture\GroupsWithAndLogic\MultiGroupTest, 2 tests)
25+
Test Preparation Started (PHPUnit\TestFixture\GroupsWithAndLogic\MultiGroupTest::testXY)
26+
Test Prepared (PHPUnit\TestFixture\GroupsWithAndLogic\MultiGroupTest::testXY)
27+
Test Passed (PHPUnit\TestFixture\GroupsWithAndLogic\MultiGroupTest::testXY)
28+
Test Finished (PHPUnit\TestFixture\GroupsWithAndLogic\MultiGroupTest::testXY)
29+
Test Preparation Started (PHPUnit\TestFixture\GroupsWithAndLogic\MultiGroupTest::testXYZ)
30+
Test Prepared (PHPUnit\TestFixture\GroupsWithAndLogic\MultiGroupTest::testXYZ)
31+
Test Passed (PHPUnit\TestFixture\GroupsWithAndLogic\MultiGroupTest::testXYZ)
32+
Test Finished (PHPUnit\TestFixture\GroupsWithAndLogic\MultiGroupTest::testXYZ)
33+
Test Suite Finished (PHPUnit\TestFixture\GroupsWithAndLogic\MultiGroupTest, 2 tests)
34+
Test Runner Execution Finished
35+
Test Runner Finished
36+
PHPUnit Finished (Shell Exit Code: 0)
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
--TEST--
2+
phpunit --group X+Y --group Z tests/MultiGroupTest.php (AND combined with OR)
3+
--FILE--
4+
<?php declare(strict_types=1);
5+
$_SERVER['argv'][] = '--do-not-cache-result';
6+
$_SERVER['argv'][] = '--no-configuration';
7+
$_SERVER['argv'][] = '--debug';
8+
$_SERVER['argv'][] = '--group';
9+
$_SERVER['argv'][] = 'X+Y';
10+
$_SERVER['argv'][] = '--group';
11+
$_SERVER['argv'][] = 'Z';
12+
$_SERVER['argv'][] = __DIR__ . '/../../_files/groups-with-and-logic/tests/MultiGroupTest.php';
13+
14+
require_once __DIR__ . '/../../../bootstrap.php';
15+
16+
(new PHPUnit\TextUI\Application)->run($_SERVER['argv']);
17+
--EXPECTF--
18+
PHPUnit Started (PHPUnit %s using %s)
19+
Test Runner Configured
20+
Event Facade Sealed
21+
Test Suite Loaded (5 tests)
22+
Test Runner Started
23+
Test Suite Sorted
24+
Test Suite Filtered (3 tests)
25+
Test Runner Execution Started (3 tests)
26+
Test Suite Started (PHPUnit\TestFixture\GroupsWithAndLogic\MultiGroupTest, 3 tests)
27+
Test Preparation Started (PHPUnit\TestFixture\GroupsWithAndLogic\MultiGroupTest::testXY)
28+
Test Prepared (PHPUnit\TestFixture\GroupsWithAndLogic\MultiGroupTest::testXY)
29+
Test Passed (PHPUnit\TestFixture\GroupsWithAndLogic\MultiGroupTest::testXY)
30+
Test Finished (PHPUnit\TestFixture\GroupsWithAndLogic\MultiGroupTest::testXY)
31+
Test Preparation Started (PHPUnit\TestFixture\GroupsWithAndLogic\MultiGroupTest::testXYZ)
32+
Test Prepared (PHPUnit\TestFixture\GroupsWithAndLogic\MultiGroupTest::testXYZ)
33+
Test Passed (PHPUnit\TestFixture\GroupsWithAndLogic\MultiGroupTest::testXYZ)
34+
Test Finished (PHPUnit\TestFixture\GroupsWithAndLogic\MultiGroupTest::testXYZ)
35+
Test Preparation Started (PHPUnit\TestFixture\GroupsWithAndLogic\MultiGroupTest::testZ)
36+
Test Prepared (PHPUnit\TestFixture\GroupsWithAndLogic\MultiGroupTest::testZ)
37+
Test Passed (PHPUnit\TestFixture\GroupsWithAndLogic\MultiGroupTest::testZ)
38+
Test Finished (PHPUnit\TestFixture\GroupsWithAndLogic\MultiGroupTest::testZ)
39+
Test Suite Finished (PHPUnit\TestFixture\GroupsWithAndLogic\MultiGroupTest, 3 tests)
40+
Test Runner Execution Finished
41+
Test Runner Finished
42+
PHPUnit Finished (Shell Exit Code: 0)
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
--TEST--
2+
phpunit --group X+Y+Z tests/MultiGroupTest.php (AND group filter with three groups)
3+
--FILE--
4+
<?php declare(strict_types=1);
5+
$_SERVER['argv'][] = '--do-not-cache-result';
6+
$_SERVER['argv'][] = '--no-configuration';
7+
$_SERVER['argv'][] = '--debug';
8+
$_SERVER['argv'][] = '--group';
9+
$_SERVER['argv'][] = 'X+Y+Z';
10+
$_SERVER['argv'][] = __DIR__ . '/../../_files/groups-with-and-logic/tests/MultiGroupTest.php';
11+
12+
require_once __DIR__ . '/../../../bootstrap.php';
13+
14+
(new PHPUnit\TextUI\Application)->run($_SERVER['argv']);
15+
--EXPECTF--
16+
PHPUnit Started (PHPUnit %s using %s)
17+
Test Runner Configured
18+
Event Facade Sealed
19+
Test Suite Loaded (5 tests)
20+
Test Runner Started
21+
Test Suite Sorted
22+
Test Suite Filtered (1 test)
23+
Test Runner Execution Started (1 test)
24+
Test Suite Started (PHPUnit\TestFixture\GroupsWithAndLogic\MultiGroupTest, 1 test)
25+
Test Preparation Started (PHPUnit\TestFixture\GroupsWithAndLogic\MultiGroupTest::testXYZ)
26+
Test Prepared (PHPUnit\TestFixture\GroupsWithAndLogic\MultiGroupTest::testXYZ)
27+
Test Passed (PHPUnit\TestFixture\GroupsWithAndLogic\MultiGroupTest::testXYZ)
28+
Test Finished (PHPUnit\TestFixture\GroupsWithAndLogic\MultiGroupTest::testXYZ)
29+
Test Suite Finished (PHPUnit\TestFixture\GroupsWithAndLogic\MultiGroupTest, 1 test)
30+
Test Runner Execution Finished
31+
Test Runner Finished
32+
PHPUnit Finished (Shell Exit Code: 0)

0 commit comments

Comments
 (0)