From 7d407ca953fe5dfd9e694f466560eb91efee2e29 Mon Sep 17 00:00:00 2001 From: Jeroen De Dauw Date: Thu, 18 Jun 2020 23:48:23 +0200 Subject: [PATCH] Support PHPUnit 9.x (#27) Co-authored-by: Oliver Radwell --- composer.json | 2 +- phpunit.xml.dist | 3 - src/Command/ValidateCommand.php | 11 ++-- src/Handler/InputHandler.php | 16 ++--- src/Loader/ConfigLoader.php | 27 +++++++- src/Loader/FileLoader.php | 2 + src/Loader/TestSuiteLoader.php | 12 ++-- src/Model/ConfigurationHolder.php | 51 +++++++++++++++ src/Model/TestCollection.php | 64 +++++++++++++++++++ tests/BaseTestCase.php | 18 ++++++ tests/Command/ValidateCommandTest.php | 34 +++++----- .../OneTestCoveringExistingTwoClassTest.php | 16 +++++ tests/Fixtures/configuration-existing-2.xml | 8 +++ tests/Handler/InputHandlerTest.php | 8 +-- tests/Loader/ConfigLoaderTest.php | 3 +- tests/Loader/TestSuiteLoaderTest.php | 55 ++++++++++++++-- 16 files changed, 275 insertions(+), 55 deletions(-) create mode 100644 src/Model/ConfigurationHolder.php create mode 100644 src/Model/TestCollection.php create mode 100644 tests/Fixtures/OneTestCoveringExistingTwoClassTest.php create mode 100644 tests/Fixtures/configuration-existing-2.xml diff --git a/composer.json b/composer.json index 45de23b..ea0f78e 100644 --- a/composer.json +++ b/composer.json @@ -16,7 +16,7 @@ }, "require": { "php": "^7.0", - "phpunit/phpunit": "^6.0 || ^7.0 || ^8.0", + "phpunit/phpunit": "^6.0 || ^7.0 || ^8.0 || ^9.0", "symfony/console": "^2.7 || ^3.0 || ^4.0 || ^5.0" }, "bin": [ diff --git a/phpunit.xml.dist b/phpunit.xml.dist index b4b4add..ee15866 100644 --- a/phpunit.xml.dist +++ b/phpunit.xml.dist @@ -7,9 +7,6 @@ - - tests/ - src/ diff --git a/src/Command/ValidateCommand.php b/src/Command/ValidateCommand.php index 3492ecd..497e81f 100644 --- a/src/Command/ValidateCommand.php +++ b/src/Command/ValidateCommand.php @@ -49,24 +49,23 @@ protected function execute(InputInterface $input, OutputInterface $output) { $output->writeln($this->getApplication()->getLongVersion()); - $configuration = InputHandler::handleInput($input); + $configurationHolder = InputHandler::handleInput($input); if ($output->getVerbosity() >= OutputInterface::VERBOSITY_VERY_VERBOSE) { $output->writeln(PHP_EOL . sprintf( 'Configuration file loaded: %s', - $configuration->getFilename() + $configurationHolder->getFilename() )); } - $suiteList = TestSuiteLoader::loadSuite($configuration); - if (!count($suiteList)) { + $testCollection = TestSuiteLoader::loadSuite($configurationHolder); + if ($testCollection->isEmpty()) { $output->writeln(PHP_EOL . 'No tests found to validate.'); return 0; } $failedCount = 0; - $suiteIterator = new \RecursiveIteratorIterator($suiteList); /** @var TestCase $suite */ - foreach ($suiteIterator as $suite) { + foreach ($testCollection as $suite) { if ($suite instanceof WarningTestCase) { continue; } diff --git a/src/Handler/InputHandler.php b/src/Handler/InputHandler.php index 8243d0c..29575af 100644 --- a/src/Handler/InputHandler.php +++ b/src/Handler/InputHandler.php @@ -5,7 +5,7 @@ use OckCyp\CoversValidator\Loader\ConfigLoader; use OckCyp\CoversValidator\Loader\FileLoader; use OckCyp\CoversValidator\Locator\ConfigLocator; -use PHPUnit\Util\Configuration; +use OckCyp\CoversValidator\Model\ConfigurationHolder; use Symfony\Component\Console\Input\InputInterface; class InputHandler @@ -14,23 +14,23 @@ class InputHandler * Handle console input * * @param InputInterface $input - * @return Configuration + * @return ConfigurationHolder */ public static function handleInput(InputInterface $input) { $configOption = $input->getOption('configuration'); $configFile = ConfigLocator::locate($configOption); - $configuration = ConfigLoader::loadConfig($configFile); + $configurationHolder = ConfigLoader::loadConfig($configFile); - $phpunit = $configuration->getPHPUnitConfiguration(); + $bootstrap = $configurationHolder->getBootstrap(); if (null !== $input->getOption('bootstrap')) { - $phpunit['bootstrap'] = $input->getOption('bootstrap'); + $bootstrap = $input->getOption('bootstrap'); } - if (isset($phpunit['bootstrap'])) { - FileLoader::loadFile($phpunit['bootstrap']); + if ($bootstrap) { + FileLoader::loadFile($bootstrap); } - return $configuration; + return $configurationHolder; } } diff --git a/src/Loader/ConfigLoader.php b/src/Loader/ConfigLoader.php index f1433b4..990d76e 100644 --- a/src/Loader/ConfigLoader.php +++ b/src/Loader/ConfigLoader.php @@ -2,6 +2,8 @@ namespace OckCyp\CoversValidator\Loader; +use OckCyp\CoversValidator\Model\ConfigurationHolder; +use PHPUnit\TextUI\Configuration\Loader; use PHPUnit\Util\Configuration; class ConfigLoader @@ -10,10 +12,29 @@ class ConfigLoader * Load configuration from file * * @param string $fileName - * @return Configuration + * @return ConfigurationHolder */ - public static function loadConfig($fileName) + public static function loadConfig(string $fileName): ConfigurationHolder { - return Configuration::getInstance($fileName); + if (class_exists(Configuration::class)) { + // @codeCoverageIgnoreStart + $configuration = Configuration::getInstance($fileName); + $filename = $configuration->getFilename(); + $phpunit = $configuration->getPHPUnitConfiguration(); + $bootstrap = ''; + if (isset($phpunit['bootstrap'])) { + $bootstrap = $phpunit['bootstrap']; + } + // @codeCoverageIgnoreEnd + } else { + $loader = new Loader(); + + $configuration = $loader->load($fileName); + $filename = $configuration->filename(); + $phpunit = $configuration->phpunit(); + $bootstrap = $phpunit->hasBootstrap() ? $phpunit->bootstrap() : null; + } + + return new ConfigurationHolder($configuration, $filename, $bootstrap); } } diff --git a/src/Loader/FileLoader.php b/src/Loader/FileLoader.php index bd60ed9..566e047 100644 --- a/src/Loader/FileLoader.php +++ b/src/Loader/FileLoader.php @@ -15,8 +15,10 @@ public static function loadFile($filename) // PHPUnit 6.x \PHPUnit\Util\Fileloader::checkAndLoad($filename); } else { + // @codeCoverageIgnoreStart // PHPUnit 7.x+ \PHPUnit\Util\FileLoader::checkAndLoad($filename); + // @codeCoverageIgnoreEnd } } } diff --git a/src/Loader/TestSuiteLoader.php b/src/Loader/TestSuiteLoader.php index 7672192..21c7501 100644 --- a/src/Loader/TestSuiteLoader.php +++ b/src/Loader/TestSuiteLoader.php @@ -2,19 +2,19 @@ namespace OckCyp\CoversValidator\Loader; -use PHPUnit\Framework\TestSuite; -use PHPUnit\Util\Configuration; +use OckCyp\CoversValidator\Model\ConfigurationHolder; +use OckCyp\CoversValidator\Model\TestCollection; class TestSuiteLoader { /** * Load test suite * - * @param Configuration $configuration - * @return TestSuite + * @param ConfigurationHolder $configurationHolder + * @return TestCollection */ - public static function loadSuite(Configuration $configuration) + public static function loadSuite(ConfigurationHolder $configurationHolder): TestCollection { - return $configuration->getTestSuiteConfiguration(); + return new TestCollection($configurationHolder); } } diff --git a/src/Model/ConfigurationHolder.php b/src/Model/ConfigurationHolder.php new file mode 100644 index 0000000..e79dbce --- /dev/null +++ b/src/Model/ConfigurationHolder.php @@ -0,0 +1,51 @@ +configuration = $configuration; + $this->filename = $filename; + $this->bootstrap = $bootstrap; + } + + public function getFilename(): string + { + return $this->filename; + } + + public function getConfiguration() + { + return $this->configuration; + } + + public function getBootstrap() + { + return $this->bootstrap; + } +} diff --git a/src/Model/TestCollection.php b/src/Model/TestCollection.php new file mode 100644 index 0000000..74fcd84 --- /dev/null +++ b/src/Model/TestCollection.php @@ -0,0 +1,64 @@ +getConfiguration(); + + if ($configuration instanceof PHPUnit8Configuration) { + $this->iterator = $configuration->getTestSuiteConfiguration(); + } else { + $testSuiteMapper = new TestSuiteMapper(); + + $this->iterator = $testSuiteMapper->map($configuration->testSuite(), ''); + } + + $this->iteratorIterator = new \RecursiveIteratorIterator($this->iterator); + } + + public function current() + { + return $this->iteratorIterator->current(); + } + + public function key() + { + return $this->iteratorIterator->key(); + } + + public function next() + { + $this->iteratorIterator->next(); + } + + public function rewind() + { + $this->iteratorIterator->rewind(); + } + + public function valid(): bool + { + return $this->iteratorIterator->valid(); + } + + public function isEmpty(): bool + { + return !\count($this->iterator); + } +} diff --git a/tests/BaseTestCase.php b/tests/BaseTestCase.php index d5d5e12..166a4f6 100644 --- a/tests/BaseTestCase.php +++ b/tests/BaseTestCase.php @@ -19,4 +19,22 @@ protected function getFixtureClassName($class) { return static::FIXTURE_NS_PREFIX . $class; } + + protected function assertRegex(string $pattern, string $string, string $message = '') + { + if (method_exists($this, 'assertMatchesRegularExpression')) { + return $this->assertMatchesRegularExpression($pattern, $string, $message); + } + + return $this->assertRegExp($pattern, $string, $message); + } + + protected function assertNotRegex(string $pattern, string $string, string $message = '') + { + if (method_exists($this, 'assertMatchesRegularExpression')) { + return $this->assertDoesNotMatchRegularExpression($pattern, $string, $message); + } + + return $this->assertNotRegExp($pattern, $string, $message); + } } diff --git a/tests/Command/ValidateCommandTest.php b/tests/Command/ValidateCommandTest.php index 1be12d9..17be8d8 100644 --- a/tests/Command/ValidateCommandTest.php +++ b/tests/Command/ValidateCommandTest.php @@ -18,6 +18,8 @@ * * @covers OckCyp\CoversValidator\Application\CoversValidator * @covers OckCyp\CoversValidator\Command\ValidateCommand + * @covers OckCyp\CoversValidator\Model\TestCollection + * @covers OckCyp\CoversValidator\Model\ConfigurationHolder */ class ValidateCommandTest extends BaseTestCase { @@ -39,7 +41,7 @@ public function testPrintsConfigFileUsed() ); $this->assertEquals(0, $exitCode); - $this->assertRegExp( + $this->assertRegex( sprintf( '{Configuration file loaded: %s}', preg_quote(realpath($configFile)) @@ -59,7 +61,7 @@ public function testReturnsSuccessForEmptyTestSuite() )); $this->assertEquals(0, $exitCode); - $this->assertRegExp('/No tests found to validate./', $commandTester->getDisplay()); + $this->assertRegex('/No tests found to validate./', $commandTester->getDisplay()); } public function testReturnsFailForNonExistentClasses() @@ -74,9 +76,9 @@ public function testReturnsFailForNonExistentClasses() $this->assertGreaterThan(0, $exitCode); $display = $commandTester->getDisplay(); - $this->assertRegExp('/Invalid - /', $display); - $this->assertRegExp('/' . preg_quote(CoversValidator::NAME, '/') . ' (?:version )?' . preg_quote(CoversValidator::VERSION, '/') . '/', $display); - $this->assertRegExp('/There were 1 test\(s\) with invalid @covers tags./', $display); + $this->assertRegex('/Invalid - /', $display); + $this->assertRegex('/' . preg_quote(CoversValidator::NAME, '/') . ' (?:version )?' . preg_quote(CoversValidator::VERSION, '/') . '/', $display); + $this->assertRegex('/There were 1 test\(s\) with invalid @covers tags./', $display); } public function testReturnsFailForEmptyCoversTag() @@ -91,8 +93,8 @@ public function testReturnsFailForEmptyCoversTag() $this->assertGreaterThan(0, $exitCode); $display = $commandTester->getDisplay(); - $this->assertRegExp('/Invalid - /', $display); - $this->assertRegExp('/There were 1 test\(s\) with invalid @covers tags./', $display); + $this->assertRegex('/Invalid - /', $display); + $this->assertRegex('/There were 1 test\(s\) with invalid @covers tags./', $display); } public function testReturnsFailForInvalidCoversTagWithProvider() @@ -107,8 +109,8 @@ public function testReturnsFailForInvalidCoversTagWithProvider() $this->assertGreaterThan(0, $exitCode); $display = $commandTester->getDisplay(); - $this->assertRegExp('/Invalid - /', $display); - $this->assertRegExp('/There were 1 test\(s\) with invalid @covers tags./', $display); + $this->assertRegex('/Invalid - /', $display); + $this->assertRegex('/There were 1 test\(s\) with invalid @covers tags./', $display); } public function testReturnsSuccessForExistingClasses() @@ -128,8 +130,8 @@ public function testReturnsSuccessForExistingClasses() $this->assertEquals(0, $exitCode); $display = $commandTester->getDisplay(); - $this->assertRegExp('/Valid - /', $display); - $this->assertRegExp('/Validating /', $display); + $this->assertRegex('/Valid - /', $display); + $this->assertRegex('/Validating /', $display); } public function testReturnsSuccessForValidCoversTagWithProvider() @@ -144,7 +146,7 @@ public function testReturnsSuccessForValidCoversTagWithProvider() $this->assertSame(0, $exitCode); $display = $commandTester->getDisplay(); - $this->assertRegExp('/Validation complete. All @covers tags are valid./', $display); + $this->assertRegex('/Validation complete. All @covers tags are valid./', $display); } public function testReturnsFailForComboClasses() @@ -159,8 +161,8 @@ public function testReturnsFailForComboClasses() $this->assertGreaterThan(0, $exitCode); $display = $commandTester->getDisplay(); - $this->assertRegExp('/Invalid - /', $display); - $this->assertRegExp('/There were 1 test\(s\) with invalid @covers tags./', $display); + $this->assertRegex('/Invalid - /', $display); + $this->assertRegex('/There were 1 test\(s\) with invalid @covers tags./', $display); } public function testSkipsEmptyTestClasses() @@ -181,8 +183,8 @@ public function testSkipsEmptyTestClasses() $this->assertEquals(0, $exitCode); $display = $commandTester->getDisplay(); // Generated by PHPUnit 6 - $this->assertNotRegExp('/PHPUnit\Framework\WarningTestCase::Warning/', $display); - $this->assertRegExp('/Validation complete. All @covers tags are valid./', $display); + $this->assertNotRegex('/PHPUnit\Framework\WarningTestCase::Warning/', $display); + $this->assertRegex('/Validation complete. All @covers tags are valid./', $display); } public function testApplicationHasDefaultCommand() diff --git a/tests/Fixtures/OneTestCoveringExistingTwoClassTest.php b/tests/Fixtures/OneTestCoveringExistingTwoClassTest.php new file mode 100644 index 0000000..32d795c --- /dev/null +++ b/tests/Fixtures/OneTestCoveringExistingTwoClassTest.php @@ -0,0 +1,16 @@ + + + + + ./OneTestCoveringExistingTwoClassTest.php + + + diff --git a/tests/Handler/InputHandlerTest.php b/tests/Handler/InputHandlerTest.php index 1f0650d..5b84302 100644 --- a/tests/Handler/InputHandlerTest.php +++ b/tests/Handler/InputHandlerTest.php @@ -4,7 +4,7 @@ use OckCyp\CoversValidator\Handler\InputHandler; use OckCyp\CoversValidator\Tests\BaseTestCase; -use PHPUnit\Util\Configuration; +use OckCyp\CoversValidator\Model\ConfigurationHolder; use Symfony\Component\Console\Input\InputInterface; /** @@ -29,7 +29,7 @@ public function testHandlesInputWithNoBootstrap() $config = InputHandler::handleInput($input->reveal()); - $this->assertInstanceOf(Configuration::class, $config); + $this->assertInstanceOf(ConfigurationHolder::class, $config); } /** @@ -55,7 +55,7 @@ class_exists( $config = InputHandler::handleInput($input->reveal()); - $this->assertInstanceOf(Configuration::class, $config); + $this->assertInstanceOf(ConfigurationHolder::class, $config); $this->assertTrue( class_exists( @@ -87,7 +87,7 @@ class_exists( $config = InputHandler::handleInput($input->reveal()); - $this->assertInstanceOf(Configuration::class, $config); + $this->assertInstanceOf(ConfigurationHolder::class, $config); $this->assertTrue( class_exists( diff --git a/tests/Loader/ConfigLoaderTest.php b/tests/Loader/ConfigLoaderTest.php index 1667a05..ce3abae 100644 --- a/tests/Loader/ConfigLoaderTest.php +++ b/tests/Loader/ConfigLoaderTest.php @@ -3,6 +3,7 @@ namespace OckCyp\CoversValidator\Tests\Loader; use OckCyp\CoversValidator\Loader\ConfigLoader; +use OckCyp\CoversValidator\Model\ConfigurationHolder; use OckCyp\CoversValidator\Tests\FileTestCase; class ConfigLoaderTest extends FileTestCase @@ -16,7 +17,7 @@ public function testLoadsConfig() file_put_contents('temp-config.xml', $xml->asXML()); $this->assertInstanceOf( - 'PHPUnit\Util\Configuration', + ConfigurationHolder::class, ConfigLoader::loadConfig('temp-config.xml') ); } diff --git a/tests/Loader/TestSuiteLoaderTest.php b/tests/Loader/TestSuiteLoaderTest.php index b2d4852..4823264 100644 --- a/tests/Loader/TestSuiteLoaderTest.php +++ b/tests/Loader/TestSuiteLoaderTest.php @@ -4,21 +4,62 @@ use OckCyp\CoversValidator\Loader\TestSuiteLoader; use OckCyp\CoversValidator\Tests\BaseTestCase; -use PHPUnit\Framework\TestSuite; -use PHPUnit\Util\Configuration; +use OckCyp\CoversValidator\Model\ConfigurationHolder; +use OckCyp\CoversValidator\Model\TestCollection; +use PHPUnit\TextUI\Configuration\Configuration as PHPUnit9Configuration; +use PHPUnit\TextUI\Configuration\Loader as PHPUnit9ConfigurationLoader; +use PHPUnit\Util\Configuration as PHPUnit8Configuration; class TestSuiteLoaderTest extends BaseTestCase { /** * @covers OckCyp\CoversValidator\Loader\TestSuiteLoader::loadSuite */ - public function testLoadsSuite() + public function testLoadsSuitePHPUnit8() { - $configuration = Configuration::getInstance('tests/Fixtures/configuration-existing.xml'); + if (!class_exists(PHPUnit8Configuration::class)) { + $this->markTestSkipped('Only for PHPUnit 8 and below'); + } - $returnedSuite = TestSuiteLoader::loadSuite($configuration); + $configuration = PHPUnit8Configuration::getInstance('tests/Fixtures/configuration-existing-2.xml'); - $this->assertInstanceOf(TestSuite::class, $returnedSuite); - $this->assertEquals('My Test Suite', $returnedSuite->getName()); + $configurationHolder = new ConfigurationHolder($configuration, '', ''); + + $testCollection = TestSuiteLoader::loadSuite($configurationHolder); + + $this->assertInstanceOf(TestCollection::class, $testCollection); + + foreach ($testCollection as $test) { + $this->assertEquals('testDummyTest', $test->getName()); + + return; + } + } + + /** + * @covers OckCyp\CoversValidator\Loader\TestSuiteLoader::loadSuite + * @covers OckCyp\CoversValidator\Model\TestCollection + */ + public function testLoadsSuitePHPUnit9() + { + if (!class_exists(PHPUnit9Configuration::class)) { + $this->markTestSkipped('Only for PHPUnit 9 and above'); + } + + $loader = new PHPUnit9ConfigurationLoader(); + + $configuration = $loader->load('tests/Fixtures/configuration-existing-2.xml'); + + $configurationHolder = new ConfigurationHolder($configuration, '', ''); + + $testCollection = TestSuiteLoader::loadSuite($configurationHolder); + + $this->assertInstanceOf(TestCollection::class, $testCollection); + + foreach ($testCollection as $key => $test) { + $this->assertEquals('testDummyTest', $test->getName()); + + return; + } } }