From 80c411be44891c78aeb961a7ccfe541440be73cc Mon Sep 17 00:00:00 2001 From: danilopolani Date: Wed, 30 Mar 2022 15:39:50 +0200 Subject: [PATCH 1/2] add config loader to read phpunit file and get the tests directory or fallback --- bin/pest | 5 +- src/ConfigLoader.php | 110 +++++++++++++++++++++++++++++++++++++++++++ src/Support/Str.php | 18 +++++++ 3 files changed, 132 insertions(+), 1 deletion(-) create mode 100644 src/ConfigLoader.php diff --git a/bin/pest b/bin/pest index c83b6446..439a6dec 100755 --- a/bin/pest +++ b/bin/pest @@ -2,6 +2,7 @@ getParameterOption('--test-directory', 'tests')); + $phpunitConfig = new ConfigLoader($rootPath); + + $testSuite = TestSuite::getInstance($rootPath, $argv->getParameterOption('--test-directory', $phpunitConfig->getTestsDirectory())); $isDecorated = $argv->getParameterOption('--colors', 'always') !== 'never'; $output = new ConsoleOutput(ConsoleOutput::VERBOSITY_NORMAL, $isDecorated); diff --git a/src/ConfigLoader.php b/src/ConfigLoader.php new file mode 100644 index 00000000..49a005a1 --- /dev/null +++ b/src/ConfigLoader.php @@ -0,0 +1,110 @@ +loadConfiguration(); + } + + /** + * Get the tests directory or fallback to default path. + */ + public function getTestsDirectory(): string + { + if (is_null($this->config)) { + return self::DEFAULT_TESTS_PATH; + } + + $suiteDirectory = $this->config->xpath('/phpunit/testsuites/testsuite/directory'); + + // @phpstan-ignore-next-line + if (!$suiteDirectory || count($suiteDirectory) === 0) { + return self::DEFAULT_TESTS_PATH; + } + + $directory = (string) ($suiteDirectory[0] ?? ''); + + if ($directory === '') { + return self::DEFAULT_TESTS_PATH; + } + + // Return the whole directory if only a separator found (e.g. `./tests`) + if (substr_count($directory, DIRECTORY_SEPARATOR) === 1) { + return is_dir($directory) ? $directory : self::DEFAULT_TESTS_PATH; + } + + $basePath = Str::beforeLast($directory, DIRECTORY_SEPARATOR); + + return is_dir($basePath) ? $basePath : self::DEFAULT_TESTS_PATH; + } + + /** + * Load the configuration file. + */ + private function loadConfiguration(): void + { + $configPath = $this->getConfigurationFilePath(); + + if ($configPath === false) { + return; + } + + $oldReportingLevel = error_reporting(0); + $content = file_get_contents($configPath); + + if ($content !== false) { + try { + $this->config = new SimpleXMLElement($content); + } catch (Throwable) { // @phpstan-ignore-line + // @ignoreException + } + } + + // Restore the correct error reporting + error_reporting($oldReportingLevel); + } + + /** + * Get the configuration file path. + */ + private function getConfigurationFilePath(): string|false + { + $candidates = [ + $this->rootPath . '/phpunit.xml', + $this->rootPath . '/phpunit.dist.xml', + $this->rootPath . '/phpunit.xml.dist', + ]; + + foreach ($candidates as $candidate) { + if (is_file($candidate)) { + return realpath($candidate); + } + } + + return false; + } +} diff --git a/src/Support/Str.php b/src/Support/Str.php index a7217704..0314e11f 100644 --- a/src/Support/Str.php +++ b/src/Support/Str.php @@ -58,4 +58,22 @@ final class Str return (string) preg_replace('/[^A-Z_a-z0-9\\\\]/', '', $code); } + + /** + * Get the portion of a string before the last occurrence of a given value. + */ + public static function beforeLast(string $subject, string $search): string + { + if ($search === '') { + return $subject; + } + + $pos = mb_strrpos($subject, $search); + + if ($pos === false) { + return $subject; + } + + return substr($subject, 0, $pos); + } } From 751a532124a1d46de61922e653533b8b3a69607b Mon Sep 17 00:00:00 2001 From: danilopolani Date: Fri, 1 Apr 2022 14:34:43 +0200 Subject: [PATCH 2/2] start ConfigLoader tests --- bin/pest | 7 +++--- src/ConfigLoader.php | 49 ++++++++++++++++++++----------------- tests/Unit/ConfigLoader.php | 19 ++++++++++++++ 3 files changed, 49 insertions(+), 26 deletions(-) create mode 100644 tests/Unit/ConfigLoader.php diff --git a/bin/pest b/bin/pest index 439a6dec..d6829c9a 100755 --- a/bin/pest +++ b/bin/pest @@ -29,9 +29,10 @@ use Symfony\Component\Console\Output\OutputInterface; $rootPath = dirname($autoloadPath, 2); $argv = new ArgvInput(); - $phpunitConfig = new ConfigLoader($rootPath); - - $testSuite = TestSuite::getInstance($rootPath, $argv->getParameterOption('--test-directory', $phpunitConfig->getTestsDirectory())); + $testSuite = TestSuite::getInstance( + $rootPath, + $argv->getParameterOption('--test-directory', (new ConfigLoader($rootPath))->getTestsDirectory()) + ); $isDecorated = $argv->getParameterOption('--colors', 'always') !== 'never'; $output = new ConsoleOutput(ConsoleOutput::VERBOSITY_NORMAL, $isDecorated); diff --git a/src/ConfigLoader.php b/src/ConfigLoader.php index 49a005a1..b3af2c0d 100644 --- a/src/ConfigLoader.php +++ b/src/ConfigLoader.php @@ -13,14 +13,17 @@ use Throwable; */ final class ConfigLoader { - private ?SimpleXMLElement $config = null; - /** * Default path if config loading went wrong. * * @var string */ - private const DEFAULT_TESTS_PATH = 'tests'; + public const DEFAULT_TESTS_PATH = 'tests'; + + /** + * XML tree of the PHPUnit configuration file. + */ + private ?SimpleXMLElement $config = null; /** * Creates a new instance of the config loader. @@ -62,6 +65,26 @@ final class ConfigLoader return is_dir($basePath) ? $basePath : self::DEFAULT_TESTS_PATH; } + /** + * Get the configuration file path. + */ + public function getConfigurationFilePath(): string|false + { + $candidates = [ + $this->rootPath . '/phpunit.xml', + $this->rootPath . '/phpunit.dist.xml', + $this->rootPath . '/phpunit.xml.dist', + ]; + + foreach ($candidates as $candidate) { + if (is_file($candidate)) { + return realpath($candidate); + } + } + + return false; + } + /** * Load the configuration file. */ @@ -87,24 +110,4 @@ final class ConfigLoader // Restore the correct error reporting error_reporting($oldReportingLevel); } - - /** - * Get the configuration file path. - */ - private function getConfigurationFilePath(): string|false - { - $candidates = [ - $this->rootPath . '/phpunit.xml', - $this->rootPath . '/phpunit.dist.xml', - $this->rootPath . '/phpunit.xml.dist', - ]; - - foreach ($candidates as $candidate) { - if (is_file($candidate)) { - return realpath($candidate); - } - } - - return false; - } } diff --git a/tests/Unit/ConfigLoader.php b/tests/Unit/ConfigLoader.php new file mode 100644 index 00000000..cae011ba --- /dev/null +++ b/tests/Unit/ConfigLoader.php @@ -0,0 +1,19 @@ +toBeNull(); + expect($instance->getConfigurationFilePath())->toBeFalse(); + expect($instance->getTestsDirectory())->toBe(ConfigLoader::DEFAULT_TESTS_PATH); +}); + +it('fallbacks to default path if phpunit is not a valid XML')->skip(); +it('fallbacks to default path if failing to read phpunit content')->skip(); +it('fallbacks to default path if there is no test suites directory')->skip(); +it('fallbacks to default path if test suite directory has no value')->skip(); +it('fallbacks to default path if test suite directory does not exist')->skip(); +it('returns the parent folder of first test suite directory')->skip();