diff --git a/.github/workflows/test-autoreview.yml b/.github/workflows/test-autoreview.yml index 3d86065a407d..70cef0e67506 100644 --- a/.github/workflows/test-autoreview.yml +++ b/.github/workflows/test-autoreview.yml @@ -49,4 +49,4 @@ jobs: COMPOSER_AUTH: ${{ secrets.COMPOSER_AUTH }} - name: Run AutoReview Tests - run: vendor/bin/phpunit --color=always --group=auto-review --no-coverage + run: vendor/bin/phpunit --color=always --group=AutoReview --no-coverage diff --git a/.github/workflows/test-phpunit.yml b/.github/workflows/test-phpunit.yml index 7f381ce9b3c4..62865e48cd26 100644 --- a/.github/workflows/test-phpunit.yml +++ b/.github/workflows/test-phpunit.yml @@ -170,7 +170,7 @@ jobs: COVERAGE_NAME: php-v${{ env.COVERAGE_PHP_VERSION }}-${{ matrix.db-platforms }} - name: Test with PHPUnit - run: script -e -c "vendor/bin/phpunit --color=always --exclude-group=auto-review ${{ steps.phpunit-coverage-option.outputs.result }}" + run: script -e -c "vendor/bin/phpunit --color=always --exclude-group=AutoReview ${{ steps.phpunit-coverage-option.outputs.result }}" env: DB: ${{ matrix.db-platforms }} TERM: xterm-256color diff --git a/composer.json b/composer.json index 02215a41ded8..e478fe79d19d 100644 --- a/composer.json +++ b/composer.json @@ -68,7 +68,6 @@ "autoload-dev": { "psr-4": { "CodeIgniter\\": "tests/system/", - "CodeIgniter\\AutoReview\\": "tests/AutoReview/", "Utils\\": "utils/" } }, diff --git a/phpunit.xml.dist b/phpunit.xml.dist index 741cd106e080..251a90b946eb 100644 --- a/phpunit.xml.dist +++ b/phpunit.xml.dist @@ -7,27 +7,30 @@ beStrictAboutTodoAnnotatedTests="true" cacheResultFile="build/.phpunit.cache/test-results" colors="true" + columns="max" failOnRisky="true" failOnWarning="true" verbose="true"> - + - ./system + system - ./system/Commands/Generators/Views - ./system/Debug/Toolbar/Views - ./system/Pager/Views - ./system/ThirdParty - ./system/Validation/Views - ./system/bootstrap.php - ./system/ComposerScripts.php - ./system/Config/Routes.php - ./system/Test/bootstrap.php - ./system/Test/ControllerTester.php - ./system/Test/FeatureTestCase.php + system/Commands/Generators/Views + system/Debug/Toolbar/Views + system/Pager/Views + system/ThirdParty + system/Validation/Views + system/bootstrap.php + system/ComposerScripts.php + system/Config/Routes.php + system/Test/bootstrap.php + system/Test/ControllerTester.php + system/Test/FeatureTestCase.php @@ -36,15 +39,8 @@ - - ./tests/AutoReview - - ./tests/system - ./tests/system/Database - - - ./tests/system/Database + tests/system diff --git a/tests/AutoReview/ComposerJsonTest.php b/tests/system/AutoReview/ComposerJsonTest.php similarity index 96% rename from tests/AutoReview/ComposerJsonTest.php rename to tests/system/AutoReview/ComposerJsonTest.php index 39763b079eca..80ebcaeeb172 100644 --- a/tests/AutoReview/ComposerJsonTest.php +++ b/tests/system/AutoReview/ComposerJsonTest.php @@ -21,7 +21,7 @@ * * @coversNothing * - * @group auto-review + * @group AutoReview */ final class ComposerJsonTest extends TestCase { @@ -32,8 +32,8 @@ protected function setUp(): void { parent::setUp(); - $this->devComposer = $this->getComposerJson(dirname(__DIR__, 2) . '/composer.json'); - $this->frameworkComposer = $this->getComposerJson(dirname(__DIR__, 2) . '/admin/framework/composer.json'); + $this->devComposer = $this->getComposerJson(dirname(__DIR__, 3) . '/composer.json'); + $this->frameworkComposer = $this->getComposerJson(dirname(__DIR__, 3) . '/admin/framework/composer.json'); } public function testFrameworkRequireIsTheSameWithDevRequire(): void diff --git a/tests/system/AutoReview/FrameworkCodeTest.php b/tests/system/AutoReview/FrameworkCodeTest.php new file mode 100644 index 000000000000..f72e7ae9987f --- /dev/null +++ b/tests/system/AutoReview/FrameworkCodeTest.php @@ -0,0 +1,141 @@ + + * + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. + */ + +namespace CodeIgniter\AutoReview; + +use FilesystemIterator; +use PHPUnit\Framework\TestCase; +use RecursiveDirectoryIterator; +use RecursiveIteratorIterator; +use ReflectionClass; +use SplFileInfo; + +/** + * @internal + * + * @group AutoReview + */ +final class FrameworkCodeTest extends TestCase +{ + /** + * Cache of discovered test class names. + */ + private static array $testClasses = []; + + private static array $recognizedGroupAnnotations = [ + 'AutoReview', + 'CacheLive', + 'DatabaseLive', + 'Others', + 'SeparateProcess', + ]; + + /** + * @dataProvider provideTestClassCases + * + * @phpstan-param class-string $class + */ + public function testEachTestClassHasCorrectGroupAnnotation(string $class): void + { + $reflection = new ReflectionClass($class); + + if ($reflection->isAbstract()) { + $this->addToAssertionCount(1); + + return; + } + + $docComment = (string) $reflection->getDocComment(); + $this->assertNotEmpty($docComment, sprintf('[%s] Test class is missing a class-level PHPDoc.', $class)); + + preg_match_all('/@group (\S+)/', $docComment, $matches); + array_shift($matches); + $this->assertNotEmpty($matches[0], sprintf('[%s] Test class is missing a @group annotation.', $class)); + + $unrecognizedGroups = array_diff($matches[0], self::$recognizedGroupAnnotations); + $this->assertEmpty($unrecognizedGroups, sprintf( + "[%s] Unexpected @group annotation%s:\n%s\nExpected annotations to be in \"%s\".", + $class, + count($unrecognizedGroups) > 1 ? 's' : '', + implode("\n", array_map( + static fn (string $group): string => sprintf(' * @group %s', $group), + $unrecognizedGroups + )), + implode(', ', self::$recognizedGroupAnnotations) + )); + } + + public function provideTestClassCases(): iterable + { + foreach ($this->getTestClasses() as $class) { + yield $class => [$class]; + } + } + + private function getTestClasses(): array + { + if (self::$testClasses !== []) { + return self::$testClasses; + } + + helper('filesystem'); + + $directory = set_realpath(dirname(__DIR__), true); + + $iterator = new RecursiveIteratorIterator( + new RecursiveDirectoryIterator( + $directory, + FilesystemIterator::SKIP_DOTS + ), + RecursiveIteratorIterator::CHILD_FIRST + ); + + $testClasses = array_map( + static function (SplFileInfo $file) use ($directory): string { + $relativePath = substr_replace( + $file->getPathname(), + '', + 0, + strlen($directory) + ); + $relativePath = substr_replace( + $relativePath, + '', + strlen($relativePath) - strlen(DIRECTORY_SEPARATOR . $file->getBasename()) + ); + + return sprintf( + 'CodeIgniter\\%s%s%s', + strtr($relativePath, DIRECTORY_SEPARATOR, '\\'), + $relativePath === '' ? '' : '\\', + $file->getBasename('.' . $file->getExtension()) + ); + }, + array_filter( + iterator_to_array($iterator, false), + static fn (SplFileInfo $file): bool => $file->isFile() + && strpos($file->getPathname(), DIRECTORY_SEPARATOR . 'fixtures' . DIRECTORY_SEPARATOR) === false + && strpos($file->getPathname(), DIRECTORY_SEPARATOR . 'Views' . DIRECTORY_SEPARATOR) === false + ) + ); + + $testClasses = array_filter( + $testClasses, + static fn (string $class) => is_subclass_of($class, TestCase::class) + ); + + sort($testClasses); + + self::$testClasses = $testClasses; + + return $testClasses; + } +} diff --git a/tests/system/Database/BaseConnectionTest.php b/tests/system/Database/BaseConnectionTest.php index adf2fd35db97..300e7f7fe5e0 100644 --- a/tests/system/Database/BaseConnectionTest.php +++ b/tests/system/Database/BaseConnectionTest.php @@ -100,9 +100,6 @@ public function testCanConnectAndStoreConnection() $this->assertSame(123, $db->getConnection()); } - /** - * @group single - */ public function testCanConnectToFailoverWhenNoConnectionAvailable() { $options = $this->options; diff --git a/tests/system/Database/BaseQueryTest.php b/tests/system/Database/BaseQueryTest.php index c7eca5f2b9a3..273c52491c15 100644 --- a/tests/system/Database/BaseQueryTest.php +++ b/tests/system/Database/BaseQueryTest.php @@ -305,8 +305,6 @@ public function testSimpleBindsWithNamedBindPlaceholderElsewhere() } /** - * @group single - * * @see https://github.com/codeigniter4/CodeIgniter4/issues/201 */ public function testSimilarNamedBinds() diff --git a/tests/system/Database/Builder/LikeTest.php b/tests/system/Database/Builder/LikeTest.php index 03ba724646bb..23e7943a3b56 100644 --- a/tests/system/Database/Builder/LikeTest.php +++ b/tests/system/Database/Builder/LikeTest.php @@ -189,9 +189,6 @@ public function testOrNotLike() $this->assertSame($expectedBinds, $builder->getBinds()); } - /** - * @group single - */ public function testCaseInsensitiveLike() { $builder = new BaseBuilder('job', $this->db); diff --git a/tests/system/Database/Live/DeleteTest.php b/tests/system/Database/Live/DeleteTest.php index 9badfb6ec516..68e2a41cb60f 100644 --- a/tests/system/Database/Live/DeleteTest.php +++ b/tests/system/Database/Live/DeleteTest.php @@ -53,11 +53,6 @@ public function testDeleteWithInternalWhere() $this->dontSeeInDatabase('job', ['name' => 'Developer']); } - /** - * @group single - * - * @throws DatabaseException - */ public function testDeleteWithLimit() { $this->seeNumRecords(2, 'user', ['country' => 'US']); diff --git a/tests/system/Database/Live/UpdateTest.php b/tests/system/Database/Live/UpdateTest.php index d69db467cdc2..1b2e8473c47e 100644 --- a/tests/system/Database/Live/UpdateTest.php +++ b/tests/system/Database/Live/UpdateTest.php @@ -181,9 +181,7 @@ public function testUpdateWithWhereSameColumn3() } /** - * @group single - * - * @see https://github.com/codeigniter4/CodeIgniter4/issues/324 + * @see https://github.com/codeigniter4/CodeIgniter4/issues/324 */ public function testUpdatePeriods() { diff --git a/tests/system/Database/Live/WhereTest.php b/tests/system/Database/Live/WhereTest.php index 6c5cd5b81ca3..6687df7d2e9f 100644 --- a/tests/system/Database/Live/WhereTest.php +++ b/tests/system/Database/Live/WhereTest.php @@ -106,9 +106,6 @@ public function testWhereIn() $this->assertSame('Accountant', $jobs[1]->name); } - /** - * @group single - */ public function testWhereNotIn() { $jobs = $this->db->table('job') diff --git a/tests/system/HTTP/Files/FileCollectionTest.php b/tests/system/HTTP/Files/FileCollectionTest.php index 77b7a6c2ac8c..c9d2c0123acf 100644 --- a/tests/system/HTTP/Files/FileCollectionTest.php +++ b/tests/system/HTTP/Files/FileCollectionTest.php @@ -218,9 +218,6 @@ public function testExtensionGuessing() $this->assertSame('zip', $file->guessExtension()); } - /** - * @group single - */ public function testAllReturnsValidSingleFileNestedName() { $_FILES = [ @@ -309,9 +306,6 @@ public function testHasFileWithMultipleFilesWithDifferentNames() $this->assertTrue($collection->hasFile('userfile2')); } - /** - * @group single - */ public function testHasFileWithSingleFileNestedName() { $_FILES = [ diff --git a/tests/system/HTTP/NegotiateTest.php b/tests/system/HTTP/NegotiateTest.php index a9c6b16bbe64..547b50ca8039 100644 --- a/tests/system/HTTP/NegotiateTest.php +++ b/tests/system/HTTP/NegotiateTest.php @@ -81,9 +81,6 @@ public function testNegotiateMediaSupportsStrictMatching() $this->assertSame('', $this->negotiate->media(['text/plain'], true)); } - /** - * @group single - */ public function testAcceptCharsetMatchesBasics() { $this->request->setHeader('Accept-Charset', 'iso-8859-5, unicode-1-1;q=0.8'); diff --git a/tests/system/HTTP/URITest.php b/tests/system/HTTP/URITest.php index 802e6f80bf09..e1b15748ae41 100644 --- a/tests/system/HTTP/URITest.php +++ b/tests/system/HTTP/URITest.php @@ -663,8 +663,6 @@ public function testResolveRelativeURI($rel, $expected) /** * @dataProvider defaultResolutions * - * @group single - * * @param mixed $rel * @param mixed $expected */ @@ -792,8 +790,6 @@ public function testGetQueryWithStrings() /** * @see https://github.com/codeigniter4/CodeIgniter4/issues/331 - * - * @group single */ public function testNoExtraSlashes() { diff --git a/tests/system/Helpers/NumberHelperTest.php b/tests/system/Helpers/NumberHelperTest.php index 818bf014e8f4..84f05607d4a3 100755 --- a/tests/system/Helpers/NumberHelperTest.php +++ b/tests/system/Helpers/NumberHelperTest.php @@ -123,9 +123,6 @@ public function testQuadrillions() $this->assertSame('123.5 quadrillion', number_to_amount('123,456,700,000,000,000', 1, 'en_US')); } - /** - * @group single - */ public function testCurrencyCurrentLocale() { $this->assertSame('$1,235', number_to_currency(1234.56, 'USD', 'en_US')); diff --git a/tests/system/Session/SessionTest.php b/tests/system/Session/SessionTest.php index 37faed7f2c50..1ddad41937c7 100644 --- a/tests/system/Session/SessionTest.php +++ b/tests/system/Session/SessionTest.php @@ -463,9 +463,6 @@ public function testSetTempDataArraySingleTTL() $this->assertLessThanOrEqual($_SESSION['__ci_vars']['baz'], $time + 200); } - /** - * @group single - */ public function testGetTestDataReturnsAll() { $session = $this->getInstance(); diff --git a/tests/system/Throttle/ThrottleTest.php b/tests/system/Throttle/ThrottleTest.php index 93049f0edf32..4bff58c01f51 100644 --- a/tests/system/Throttle/ThrottleTest.php +++ b/tests/system/Throttle/ThrottleTest.php @@ -107,9 +107,6 @@ public function testRemove() $this->assertTrue($throttler->check('127.0.0.1', 1, MINUTE)); } - /** - * @group single - */ public function testDecrementsValues() { $throttler = new Throttler($this->cache); diff --git a/tests/system/View/ParserTest.php b/tests/system/View/ParserTest.php index ab3bb8e65bc1..79bd21b4efe3 100644 --- a/tests/system/View/ParserTest.php +++ b/tests/system/View/ParserTest.php @@ -744,9 +744,6 @@ public function testParseRuns() $this->assertSame($result, $this->parser->renderString($template)); } - /** - * @group parserplugins - */ public function testCanAddAndRemovePlugins() { $this->parser->addPlugin('first', static fn ($str) => $str); @@ -762,9 +759,6 @@ public function testCanAddAndRemovePlugins() $this->assertArrayNotHasKey('first', $setParsers); } - /** - * @group parserplugins - */ public function testParserPluginNoMatches() { $template = 'hit:it'; @@ -772,9 +766,6 @@ public function testParserPluginNoMatches() $this->assertSame('hit:it', $this->parser->renderString($template)); } - /** - * @group parserplugins - */ public function testParserPluginNoParams() { $this->parser->addPlugin('hit:it', static fn ($str) => str_replace('here', 'Hip to the Hop', $str), true); @@ -784,9 +775,6 @@ public function testParserPluginNoParams() $this->assertSame(' stuff Hip to the Hop ', $this->parser->renderString($template)); } - /** - * @group parserplugins - */ public function testParserPluginClosure() { $config = $this->config; @@ -799,9 +787,6 @@ public function testParserPluginClosure() $this->assertSame('Hello, world', $this->parser->renderString($template)); } - /** - * @group parserplugins - */ public function testParserPluginParams() { $this->parser->addPlugin('growth', static function ($str, array $params) { @@ -822,9 +807,6 @@ public function testParserPluginParams() $this->assertSame(' 2 4 6 8', $this->parser->renderString($template)); } - /** - * @group parserplugins - */ public function testParserSingleTag() { $this->parser->addPlugin('hit:it', static fn () => 'Hip to the Hop', false); @@ -834,9 +816,6 @@ public function testParserSingleTag() $this->assertSame('Hip to the Hop', $this->parser->renderString($template)); } - /** - * @group parserplugins - */ public function testParserSingleTagWithParams() { $this->parser->addPlugin('hit:it', static fn (array $params = []) => "{$params['first']} to the {$params['last']}", false); @@ -846,9 +825,6 @@ public function testParserSingleTagWithParams() $this->assertSame('foo to the bar', $this->parser->renderString($template)); } - /** - * @group parserplugins - */ public function testParserSingleTagWithSingleParams() { $this->parser->addPlugin('hit:it', static fn (array $params = []) => "{$params[0]} to the {$params[1]}", false); @@ -858,9 +834,6 @@ public function testParserSingleTagWithSingleParams() $this->assertSame('foo to the bar', $this->parser->renderString($template)); } - /** - * @group parserplugins - */ public function testParserSingleTagWithQuotedParams() { $this->parser->addPlugin('count', static function (array $params = []) { @@ -878,9 +851,6 @@ public function testParserSingleTagWithQuotedParams() $this->assertSame('0. foo bar 1. baz 2. foo bar ', $this->parser->renderString($template)); } - /** - * @group parserplugins - */ public function testParserSingleTagWithNamedParams() { $this->parser->addPlugin('read_params', static function (array $params = []) {