<commit_before><?php

declare(strict_types=1);

namespace Codeception\Task\Filter;

use Codeception\Lib\GroupManager;
use Codeception\Test\Descriptor as TestDescriptor;
use Codeception\Util\Annotation;
use InvalidArgumentException;
use PHPUnit\Framework\SelfDescribing;

/**
 * Class GroupFilter - allows to filter tests by the @group Annotation
 *
 * @see \Tests\Codeception\Task\Filter\GroupFilterTest
 */
class GroupFilter implements Filter
{
    /** @var string[] $includedGroups */
    private array $includedGroups = [];

    private array $excludedGroups = [];

    /** @var SelfDescribing[] */
    private array $tests = [];

    public function reset(): void
    {
        $this->resetIncludedGroups();
        $this->resetExcludedGroups();
    }

    public function resetIncludedGroups(): void
    {
        $this->includedGroups = [];
    }

    public function resetExcludedGroups(): void
    {
        $this->excludedGroups = [];
    }

    /**
     * @return SelfDescribing[]
     */
    public function getTests(): array
    {
        return $this->tests;
    }

    /**
     * Adds a group name to the excluded array
     */
    public function groupExcluded(string $group): self
    {
        if (in_array($group, $this->getIncludedGroups(), true)) {
            throw new InvalidArgumentException(
                sprintf(
                    'You can mark group "%s" only as included OR excluded.',
                    $group
                )
            );
        }

        if (!in_array($group, $this->getExcludedGroups(), true)) {
            $this->excludedGroups[] = $group;
        }

        return $this;
    }

    /**
     * Adds a group name to the included array
     */
    public function groupIncluded(string $group): self
    {
        if (in_array($group, $this->getExcludedGroups(), true)) {
            throw new InvalidArgumentException(
                sprintf(
                    'You can mark group "%s" only as included OR excluded.',
                    $group
                )
            );
        }

        if (!in_array($group, $this->getIncludedGroups(), true)) {
            $this->includedGroups[] = $group;
        }

        return $this;
    }

    public function getExcludedGroups(): array
    {
        return $this->excludedGroups;
    }

    /**
     * @return string[]
     */
    public function getIncludedGroups(): array
    {
        return $this->includedGroups;
    }

    /**
     * @param SelfDescribing[] $tests
     */
    public function setTests(array $tests): void
    {
        $this->tests = $tests;
    }

    /**
     * Filter the tests by the given included and excluded @group annotations
     *
     * @return \PHPUnit\Framework\SelfDescribing[]
     */
    public function filter(): array
    {
        $groupManager = new GroupManager([]);

        $testsByGroups = [];
        foreach ($this->getTests() as $test) {
            if (!($test instanceof SelfDescribing)) {
                throw new InvalidArgumentException(
                    'Tests must be an instance of ' . SelfDescribing::class
                );
            }

            $groups = $groupManager->groupsForTest($test);

            if (
                !empty($this->getExcludedGroups())
                && [] === array_diff($this->getExcludedGroups(), $groups)
            ) {
                continue;
            }

            if (
                !empty($this->getIncludedGroups())
                && [] !== array_diff($this->getIncludedGroups(), $groups)
            ) {
                continue;
            }

            $testsByGroups[] = $test;
        }

        return $testsByGroups;
    }
}
<commit_msg>Fix detection of @groups for dataprovider tests (#108)<commit_after><?php

declare(strict_types=1);

namespace Codeception\Task\Filter;

use Codeception\Lib\GroupManager;
use Codeception\Test\Descriptor as TestDescriptor;
use Codeception\Util\Annotation;
use InvalidArgumentException;
use PHPUnit\Framework\SelfDescribing;

/**
 * Class GroupFilter - allows to filter tests by the @group Annotation
 *
 * @see \Tests\Codeception\Task\Filter\GroupFilterTest
 */
class GroupFilter implements Filter
{
    /** @var string[] $includedGroups */
    private array $includedGroups = [];

    private array $excludedGroups = [];

    /** @var SelfDescribing[] */
    private array $tests = [];

    public function reset(): void
    {
        $this->resetIncludedGroups();
        $this->resetExcludedGroups();
    }

    public function resetIncludedGroups(): void
    {
        $this->includedGroups = [];
    }

    public function resetExcludedGroups(): void
    {
        $this->excludedGroups = [];
    }

    /**
     * @return SelfDescribing[]
     */
    public function getTests(): array
    {
        return $this->tests;
    }

    /**
     * Adds a group name to the excluded array
     */
    public function groupExcluded(string $group): self
    {
        if (in_array($group, $this->getIncludedGroups(), true)) {
            throw new InvalidArgumentException(
                sprintf(
                    'You can mark group "%s" only as included OR excluded.',
                    $group
                )
            );
        }

        if (!in_array($group, $this->getExcludedGroups(), true)) {
            $this->excludedGroups[] = $group;
        }

        return $this;
    }

    /**
     * Adds a group name to the included array
     */
    public function groupIncluded(string $group): self
    {
        if (in_array($group, $this->getExcludedGroups(), true)) {
            throw new InvalidArgumentException(
                sprintf(
                    'You can mark group "%s" only as included OR excluded.',
                    $group
                )
            );
        }

        if (!in_array($group, $this->getIncludedGroups(), true)) {
            $this->includedGroups[] = $group;
        }

        return $this;
    }

    public function getExcludedGroups(): array
    {
        return $this->excludedGroups;
    }

    /**
     * @return string[]
     */
    public function getIncludedGroups(): array
    {
        return $this->includedGroups;
    }

    /**
     * @param SelfDescribing[] $tests
     */
    public function setTests(array $tests): void
    {
        $this->tests = $tests;
    }

    /**
     * Filter the tests by the given included and excluded @group annotations
     *
     * @return \PHPUnit\Framework\SelfDescribing[]
     */
    public function filter(): array
    {
        $groupManager = new GroupManager([]);

        $testsByGroups = [];
        foreach ($this->getTests() as $test) {
            if (!($test instanceof SelfDescribing)) {
                throw new InvalidArgumentException(
                    'Tests must be an instance of ' . SelfDescribing::class
                );
            }

            $groups = $groupManager->groupsForTest($test);

            if (!$groups && $test instanceof \PHPUnit\Framework\DataProviderTestSuite) {
              /** @var \PHPUnit\Framework\DataProviderTestSuite $dataProviderTestSuite */
              $dataProviderTestSuite = $test;
              // By definition (a) all tests of dataprovider test suite are the same test case definition, and (b) there is at least one test case
              $firstDataProviderTest = $dataProviderTestSuite->tests()[0];
              $groups = $groupManager->groupsForTest($firstDataProviderTest);
            }

            if (
                !empty($this->getExcludedGroups())
                && [] === array_diff($this->getExcludedGroups(), $groups)
            ) {
                continue;
            }

            if (
                !empty($this->getIncludedGroups())
                && [] !== array_diff($this->getIncludedGroups(), $groups)
            ) {
                continue;
            }

            $testsByGroups[] = $test;
        }

        return $testsByGroups;
    }
}

{'fraction_non_alphanumeric': 0.11884678333123505, 'fraction_numerical': 0.0007553820974442906, 'mean_word_length': 1.8270462633451958, 'pattern_counts': {'":': 0, '<': 5, '<?xml version=': 0, '>': 45, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '5801298', 'n_tokens_mistral': 2143, 'n_tokens_neox': 2030, 'n_words': 503}