From 3284c067030c37ed79c4ac8412c0a095a939ef61 Mon Sep 17 00:00:00 2001 From: Guy Sartorelli Date: Tue, 9 Aug 2022 17:01:45 +1200 Subject: [PATCH] API Remove PHPUnit 5.7 compatability hacks --- composer.json | 5 +- src/Core/BaseKernel.php | 30 +- src/Core/Manifest/ClassLoader.php | 5 +- src/Core/Manifest/ClassManifest.php | 9 +- src/Core/Manifest/ManifestFileFinder.php | 51 +- src/Core/Manifest/Module.php | 133 -- src/Core/Manifest/ModuleLoader.php | 5 +- src/Core/Manifest/ModuleManifest.php | 9 +- src/Dev/Constraint/SSListContains.php | 184 +- src/Dev/Constraint/SSListContainsOnly.php | 20 +- .../SSListContainsOnlyMatchingItems.php | 121 +- src/Dev/Constraint/ViewableDataContains.php | 135 +- src/Dev/FunctionalTest.php | 475 +----- src/Dev/SapphireTest.php | 1496 +---------------- src/Dev/TestKernel.php | 21 - src/View/ThemeManifest.php | 9 +- .../Core/Manifest/ManifestFileFinderTest.php | 55 - tests/php/Core/Manifest/ModuleTest.php | 49 - .../myvendor/phpunit5module/_config.php | 1 - .../myvendor/phpunit5module/code/logic.txt | 1 - .../myvendor/phpunit5module/composer.json | 6 - .../phpunit5module/tests/phpunit5tests.txt | 1 - .../myvendor/phpunit9module/_config.php | 1 - .../myvendor/phpunit9module/code/logic.txt | 1 - .../myvendor/phpunit9module/composer.json | 6 - .../phpunit9module/tests/phpunit9tests.txt | 1 - .../empty-require-dev/composer.json | 11 - .../future-phpunit/composer.json | 13 - .../inbetween-phpunit/composer.json | 13 - .../no-require-dev/composer.json | 10 - .../old-phpunit/composer.json | 13 - .../phpunit-five-exact-version/composer.json | 13 - .../phpunit-five-seven/composer.json | 13 - .../phpunit-five-tilde/composer.json | 13 - .../phpunit-five-zero/composer.json | 13 - .../phpunit-nine-exact/composer.json | 13 - .../phpunit-nine-five/composer.json | 13 - .../phpunit-nine-x/composer.json | 13 - .../phpunit-nine/composer.json | 13 - .../recipe-testing-one-flag/composer.json | 13 - .../recipe-testing-one-two-x/composer.json | 13 - .../recipe-testing-one-x/composer.json | 13 - .../recipe-testing-one/composer.json | 13 - .../recipe-testing-two-exact/composer.json | 13 - .../recipe-testing-two-x/composer.json | 13 - .../recipe-testing-two/composer.json | 13 - .../sminnee-five-seven/composer.json | 13 - .../sminnee-five-star/composer.json | 13 - .../sminnee-five/composer.json | 13 - 49 files changed, 115 insertions(+), 3009 deletions(-) delete mode 100644 tests/php/Core/Manifest/fixtures/manifestfilefinder/vendor/myvendor/phpunit5module/_config.php delete mode 100644 tests/php/Core/Manifest/fixtures/manifestfilefinder/vendor/myvendor/phpunit5module/code/logic.txt delete mode 100644 tests/php/Core/Manifest/fixtures/manifestfilefinder/vendor/myvendor/phpunit5module/composer.json delete mode 100644 tests/php/Core/Manifest/fixtures/manifestfilefinder/vendor/myvendor/phpunit5module/tests/phpunit5tests.txt delete mode 100644 tests/php/Core/Manifest/fixtures/manifestfilefinder/vendor/myvendor/phpunit9module/_config.php delete mode 100644 tests/php/Core/Manifest/fixtures/manifestfilefinder/vendor/myvendor/phpunit9module/code/logic.txt delete mode 100644 tests/php/Core/Manifest/fixtures/manifestfilefinder/vendor/myvendor/phpunit9module/composer.json delete mode 100644 tests/php/Core/Manifest/fixtures/manifestfilefinder/vendor/myvendor/phpunit9module/tests/phpunit9tests.txt delete mode 100644 tests/php/Core/Manifest/fixtures/phpunit-detection/empty-require-dev/composer.json delete mode 100644 tests/php/Core/Manifest/fixtures/phpunit-detection/future-phpunit/composer.json delete mode 100644 tests/php/Core/Manifest/fixtures/phpunit-detection/inbetween-phpunit/composer.json delete mode 100644 tests/php/Core/Manifest/fixtures/phpunit-detection/no-require-dev/composer.json delete mode 100644 tests/php/Core/Manifest/fixtures/phpunit-detection/old-phpunit/composer.json delete mode 100644 tests/php/Core/Manifest/fixtures/phpunit-detection/phpunit-five-exact-version/composer.json delete mode 100644 tests/php/Core/Manifest/fixtures/phpunit-detection/phpunit-five-seven/composer.json delete mode 100644 tests/php/Core/Manifest/fixtures/phpunit-detection/phpunit-five-tilde/composer.json delete mode 100644 tests/php/Core/Manifest/fixtures/phpunit-detection/phpunit-five-zero/composer.json delete mode 100644 tests/php/Core/Manifest/fixtures/phpunit-detection/phpunit-nine-exact/composer.json delete mode 100644 tests/php/Core/Manifest/fixtures/phpunit-detection/phpunit-nine-five/composer.json delete mode 100644 tests/php/Core/Manifest/fixtures/phpunit-detection/phpunit-nine-x/composer.json delete mode 100644 tests/php/Core/Manifest/fixtures/phpunit-detection/phpunit-nine/composer.json delete mode 100644 tests/php/Core/Manifest/fixtures/phpunit-detection/recipe-testing-one-flag/composer.json delete mode 100644 tests/php/Core/Manifest/fixtures/phpunit-detection/recipe-testing-one-two-x/composer.json delete mode 100644 tests/php/Core/Manifest/fixtures/phpunit-detection/recipe-testing-one-x/composer.json delete mode 100644 tests/php/Core/Manifest/fixtures/phpunit-detection/recipe-testing-one/composer.json delete mode 100644 tests/php/Core/Manifest/fixtures/phpunit-detection/recipe-testing-two-exact/composer.json delete mode 100644 tests/php/Core/Manifest/fixtures/phpunit-detection/recipe-testing-two-x/composer.json delete mode 100644 tests/php/Core/Manifest/fixtures/phpunit-detection/recipe-testing-two/composer.json delete mode 100644 tests/php/Core/Manifest/fixtures/phpunit-detection/sminnee-five-seven/composer.json delete mode 100644 tests/php/Core/Manifest/fixtures/phpunit-detection/sminnee-five-star/composer.json delete mode 100644 tests/php/Core/Manifest/fixtures/phpunit-detection/sminnee-five/composer.json diff --git a/composer.json b/composer.json index b3ab2c9ce..4ad1370c4 100644 --- a/composer.json +++ b/composer.json @@ -25,7 +25,6 @@ "php": "^8.1", "bramus/monolog-colored-line-formatter": "^2.0.3", "composer/installers": "^2.1.1", - "composer/semver": "^3.3.2", "guzzlehttp/guzzle": "^7.4.5", "guzzlehttp/psr7": "^2.4.0", "embed/embed": "^4.4.4", @@ -60,9 +59,7 @@ "squizlabs/php_codesniffer": "^3.7" }, "conflict": { - "egulias/email-validator": "^2", - "phpunit/phpunit": "^6 || ^7 || ^8", - "cwp/cwp-core": "<2.11.0" + "egulias/email-validator": "^2" }, "provide": { "psr/container-implementation": "1.0.0" diff --git a/src/Core/BaseKernel.php b/src/Core/BaseKernel.php index 8b57ff0a5..1534c68cf 100644 --- a/src/Core/BaseKernel.php +++ b/src/Core/BaseKernel.php @@ -180,18 +180,10 @@ abstract class BaseKernel implements Kernel protected function bootManifests($flush) { // Setup autoloader - $this->getClassLoader()->init( - $this->getIncludeTests(), - $flush, - $this->getIgnoredCIConfigs() - ); + $this->getClassLoader()->init($this->getIncludeTests(), $flush); // Find modules - $this->getModuleLoader()->init( - $this->getIncludeTests(), - $flush, - $this->getIgnoredCIConfigs() - ); + $this->getModuleLoader()->init($this->getIncludeTests(), $flush); // Flush config if ($flush) { @@ -209,11 +201,7 @@ abstract class BaseKernel implements Kernel $defaultSet->setProject( ModuleManifest::config()->get('project') ); - $defaultSet->init( - $this->getIncludeTests(), - $flush, - $this->getIgnoredCIConfigs() - ); + $defaultSet->init($this->getIncludeTests(), $flush); } } @@ -372,18 +360,6 @@ abstract class BaseKernel implements Kernel ]); } - /** - * When manifests are discovering files, tests files in modules using the following CI library type will be ignored. - * - * The purpose of this method is to avoid loading PHPUnit test files with incompatible definitions. - * - * @return string[] List of CI types to ignore as defined by `Module`. - */ - protected function getIgnoredCIConfigs(): array - { - return []; - } - /** * @return bool */ diff --git a/src/Core/Manifest/ClassLoader.php b/src/Core/Manifest/ClassLoader.php index 201bcdf0c..c791808d4 100644 --- a/src/Core/Manifest/ClassLoader.php +++ b/src/Core/Manifest/ClassLoader.php @@ -120,14 +120,13 @@ class ClassLoader * * @param bool $includeTests * @param bool $forceRegen - * @param string[] $ignoredCIConfigs */ - public function init($includeTests = false, $forceRegen = false, array $ignoredCIConfigs = []) + public function init($includeTests = false, $forceRegen = false) { foreach ($this->manifests as $manifest) { /** @var ClassManifest $instance */ $instance = $manifest['instance']; - $instance->init($includeTests, $forceRegen, $ignoredCIConfigs); + $instance->init($includeTests, $forceRegen); } $this->registerAutoloader(); diff --git a/src/Core/Manifest/ClassManifest.php b/src/Core/Manifest/ClassManifest.php index f476e76e9..55a59838f 100644 --- a/src/Core/Manifest/ClassManifest.php +++ b/src/Core/Manifest/ClassManifest.php @@ -276,9 +276,8 @@ class ClassManifest * * @param bool $includeTests * @param bool $forceRegen - * @param string[] $ignoredCIConfigs */ - public function init($includeTests = false, $forceRegen = false, array $ignoredCIConfigs = []) + public function init($includeTests = false, $forceRegen = false) { $this->cache = $this->buildCache($includeTests); @@ -292,7 +291,7 @@ class ClassManifest } // Build - $this->regenerate($includeTests, $ignoredCIConfigs); + $this->regenerate($includeTests); } /** @@ -539,9 +538,8 @@ class ClassManifest * Completely regenerates the manifest file. * * @param bool $includeTests - * @param string[] $ignoredCIConfigs */ - public function regenerate($includeTests, array $ignoredCIConfigs = []) + public function regenerate($includeTests) { // Reset the manifest so stale info doesn't cause errors. $this->loadState([]); @@ -553,7 +551,6 @@ class ClassManifest 'name_regex' => '/^[^_].*\\.php$/', 'ignore_files' => ['index.php', 'cli-script.php'], 'ignore_tests' => !$includeTests, - 'ignored_ci_configs' => $ignoredCIConfigs, 'file_callback' => function ($basename, $pathname, $depth) use ($includeTests, $finder) { $this->handleFile($basename, $pathname, $includeTests); }, diff --git a/src/Core/Manifest/ManifestFileFinder.php b/src/Core/Manifest/ManifestFileFinder.php index f53446980..493d91175 100644 --- a/src/Core/Manifest/ManifestFileFinder.php +++ b/src/Core/Manifest/ManifestFileFinder.php @@ -2,7 +2,6 @@ namespace SilverStripe\Core\Manifest; -use RuntimeException; use SilverStripe\Assets\FileFinder; /** @@ -11,9 +10,8 @@ use SilverStripe\Assets\FileFinder; * - Only modules with _config.php files are scanned. * - If a _manifest_exclude file is present inside a directory it is ignored. * - Assets and module language directories are ignored. - * - Module tests directories are skipped if either of these conditions is meant: - * - the `ignore_tests` option is not set to false. - * - the module PHP CI configuration matches one of the `ignored_ci_configs` + * - Module tests directories are skipped if the `ignore_tests` option is not + * set to false. */ class ManifestFileFinder extends FileFinder { @@ -30,7 +28,6 @@ class ManifestFileFinder extends FileFinder 'ignore_tests' => true, 'min_depth' => 1, 'ignore_dirs' => ['node_modules'], - 'ignored_ci_configs' => [] ]; public function acceptDir($basename, $pathname, $depth) @@ -71,14 +68,6 @@ class ManifestFileFinder extends FileFinder return false; } - // Skip if test dir inside vendor module with unexpected CI Configuration - if ($depth > 3 && $basename === self::TESTS_DIR && $ignoredCIConfig = $this->getOption('ignored_ci_configs')) { - $ciLib = $this->findModuleCIPhpConfiguration($basename, $pathname, $depth); - if (in_array($ciLib, $ignoredCIConfig ?? [])) { - return false; - } - } - return parent::acceptDir($basename, $pathname, $depth); } @@ -257,40 +246,4 @@ class ManifestFileFinder extends FileFinder return false; } - - /** - * Find out the root of the current module and read the PHP CI configuration from tho composer file - * - * @param string $basename Name of the current folder - * @param string $pathname Full path the parent folder - * @param string $depth Depth of the current folder - */ - private function findModuleCIPhpConfiguration(string $basename, string $pathname, int $depth): string - { - if ($depth < 1) { - // We went all the way back to the root of the project - return Module::CI_UNKNOWN; - } - - // We pop the current folder and use the next entry the pathname - $newBasename = basename($pathname ?? ''); - $newPathname = dirname($pathname ?? ''); - $newDepth = $depth - 1; - - if ($this->isDirectoryModule($newBasename, $newPathname, $newDepth)) { - // We've reached the root of the module folder, we can read the PHP CI config now - $module = new Module($newPathname, $this->upLevels($newPathname, $newDepth)); - $config = $module->getCIConfig(); - - if (empty($config['PHP'])) { - // This should never happen - throw new RuntimeException('Module::getCIConfig() did not return a PHP CI value'); - } - - return $config['PHP']; - } - - // We haven't reach our module root yet ... let's look up one more level - return $this->findModuleCIPhpConfiguration($newBasename, $newPathname, $newDepth); - } } diff --git a/src/Core/Manifest/Module.php b/src/Core/Manifest/Module.php index 1872c7637..20e68b8b0 100644 --- a/src/Core/Manifest/Module.php +++ b/src/Core/Manifest/Module.php @@ -2,10 +2,8 @@ namespace SilverStripe\Core\Manifest; -use Composer\Semver\Semver; use Exception; use InvalidArgumentException; -use RuntimeException; use Serializable; use SilverStripe\Core\Path; use SilverStripe\Dev\Deprecation; @@ -21,23 +19,6 @@ class Module implements Serializable */ const TRIM_CHARS = ' /\\'; - /** - * Return value of getCIConfig() when module uses PHPUNit 9 - */ - const CI_PHPUNIT_NINE = 'CI_PHPUNIT_NINE'; - - /** - * Return value of getCIConfig() when module uses PHPUNit 5 - */ - const CI_PHPUNIT_FIVE = 'CI_PHPUNIT_FIVE'; - - /** - * Return value of getCIConfig() when module does not use any CI - */ - const CI_UNKNOWN = 'CI_UNKNOWN'; - - - /** * Full directory path to this module with no trailing slash * @@ -325,120 +306,6 @@ class Module implements Serializable ->getResource($path) ->exists(); } - - /** - * Determine what configurations the module is using to run various aspects of its CI. THe only aspect - * that is observed is `PHP` - * @return array List of configuration aspects e.g.: `['PHP' => 'CI_PHPUNIT_NINE']` - * @internal - */ - public function getCIConfig(): array - { - return [ - 'PHP' => $this->getPhpCiConfig() - ]; - } - - /** - * Determine what CI Configuration the module uses to test its PHP code. - */ - private function getPhpCiConfig(): string - { - // We don't have any composer data at all - if (empty($this->composerData)) { - return self::CI_UNKNOWN; - } - - // We don't have any dev dependencies - if (empty($this->composerData['require-dev']) || !is_array($this->composerData['require-dev'])) { - return self::CI_UNKNOWN; - } - - // We are assuming a typical setup where the CI lib is defined in require-dev rather than require - $requireDev = $this->composerData['require-dev']; - - // Try to pick which CI we are using based on phpunit constraint - $phpUnitConstraint = $this->requireDevConstraint(['sminnee/phpunit', 'phpunit/phpunit']); - if ($phpUnitConstraint) { - if ($this->constraintSatisfies( - $phpUnitConstraint, - ['5.7.0', '5.0.0', '5.x-dev', '5.7.x-dev'], - 5 - )) { - return self::CI_PHPUNIT_FIVE; - } - if ($this->constraintSatisfies( - $phpUnitConstraint, - ['9.0.0', '9.5.0', '9.x-dev', '9.5.x-dev'], - 9 - )) { - return self::CI_PHPUNIT_NINE; - } - } - - // Try to pick which CI we are using based on recipe-testing constraint - $recipeTestingConstraint = $this->requireDevConstraint(['silverstripe/recipe-testing']); - if ($recipeTestingConstraint) { - if ($this->constraintSatisfies( - $recipeTestingConstraint, - ['1.0.0', '1.1.0', '1.2.0', '1.1.x-dev', '1.2.x-dev', '1.x-dev'], - 1 - )) { - return self::CI_PHPUNIT_FIVE; - } - if ($this->constraintSatisfies( - $recipeTestingConstraint, - ['2.0.0', '2.0.x-dev', '2.x-dev'], - 2 - )) { - return self::CI_PHPUNIT_NINE; - } - } - - return self::CI_UNKNOWN; - } - - /** - * Retrieve the constraint for the first module that is found in the require-dev section - * @param string[] $modules - * @return false|string - */ - private function requireDevConstraint(array $modules) - { - if (empty($this->composerData['require-dev']) || !is_array($this->composerData['require-dev'])) { - return false; - } - - $requireDev = $this->composerData['require-dev']; - foreach ($modules as $module) { - if (isset($requireDev[$module])) { - return $requireDev[$module]; - } - } - - return false; - } - - /** - * Determines if the provided constraint allows at least one of the version provided - */ - private function constraintSatisfies( - string $constraint, - array $possibleVersions, - int $majorVersionFallback - ): bool { - // Let's see of any of our possible versions is allowed by the constraint - if (!empty(Semver::satisfiedBy($possibleVersions, $constraint))) { - return true; - } - - // Let's see if we are using an exact version constraint. e.g. ~1.2.3 or 1.2.3 or ~1.2 or 1.2.* - if (preg_match("/^~?$majorVersionFallback(\.(\d+)|\*){0,2}/", $constraint ?? '')) { - return true; - } - - return false; - } } /** diff --git a/src/Core/Manifest/ModuleLoader.php b/src/Core/Manifest/ModuleLoader.php index b68aa4799..10dbe948b 100644 --- a/src/Core/Manifest/ModuleLoader.php +++ b/src/Core/Manifest/ModuleLoader.php @@ -91,12 +91,11 @@ class ModuleLoader * * @param bool $includeTests * @param bool $forceRegen - * @param string[] $ignoredCIConfigs */ - public function init($includeTests = false, $forceRegen = false, array $ignoredCIConfigs = []) + public function init($includeTests = false, $forceRegen = false) { foreach ($this->manifests as $manifest) { - $manifest->init($includeTests, $forceRegen, $ignoredCIConfigs); + $manifest->init($includeTests, $forceRegen); } } } diff --git a/src/Core/Manifest/ModuleManifest.php b/src/Core/Manifest/ModuleManifest.php index 64fcbcdb6..0c5d117f5 100644 --- a/src/Core/Manifest/ModuleManifest.php +++ b/src/Core/Manifest/ModuleManifest.php @@ -121,9 +121,8 @@ class ModuleManifest /** * @param bool $includeTests * @param bool $forceRegen Force the manifest to be regenerated. - * @param string[] $ignoredCIConfigs */ - public function init($includeTests = false, $forceRegen = false, array $ignoredCIConfigs = []) + public function init($includeTests = false, $forceRegen = false) { // build cache from factory if ($this->cacheFactory) { @@ -138,7 +137,7 @@ class ModuleManifest $this->modules = $this->cache->get($this->cacheKey) ?: []; } if (empty($this->modules)) { - $this->regenerate($includeTests, $ignoredCIConfigs); + $this->regenerate($includeTests); } } @@ -163,9 +162,8 @@ class ModuleManifest * Does _not_ build the actual variant * * @param bool $includeTests - * @param string[] $ignoredCIConfigs */ - public function regenerate($includeTests = false, array $ignoredCIConfigs = []) + public function regenerate($includeTests = false) { $this->modules = []; @@ -173,7 +171,6 @@ class ModuleManifest $finder->setOptions([ 'min_depth' => 0, 'ignore_tests' => !$includeTests, - 'ignored_ci_configs' => $ignoredCIConfigs, 'dir_callback' => function ($basename, $pathname, $depth) use ($finder) { if ($finder->isDirectoryModule($basename, $pathname, $depth)) { $this->addModule($pathname); diff --git a/src/Dev/Constraint/SSListContains.php b/src/Dev/Constraint/SSListContains.php index d778cad46..bb3b0b9dd 100644 --- a/src/Dev/Constraint/SSListContains.php +++ b/src/Dev/Constraint/SSListContains.php @@ -2,8 +2,6 @@ namespace SilverStripe\Dev\Constraint; -use PHPUnit_Framework_Constraint; -use PHPUnit_Framework_ExpectationFailedException; use PHPUnit\Framework\Constraint\Constraint; use PHPUnit\Framework\ExpectationFailedException; use SilverStripe\Dev\SSListExporter; @@ -11,171 +9,12 @@ use SilverStripe\Dev\TestOnly; use SilverStripe\ORM\SS_List; use SilverStripe\View\ViewableData; -/* ------------------------------------------------- - * - * This version of SSListContains is for phpunit 9 - * The phpunit 5 version is lower down in this file - * phpunit 6, 7 and 8 are not supported - * - * @see SilverStripe\Dev\SapphireTest - * - * ------------------------------------------------- - */ - -if (class_exists(Constraint::class)) { - - /** - * Constraint for checking if a SS_List contains items matching the given - * key-value pairs. - */ - // Ignore multiple classes in same file - // @codingStandardsIgnoreStart - class SSListContains extends Constraint implements TestOnly - { - // @codingStandardsIgnoreEnd - /** - * @var array - */ - protected $matches = []; - - /** - * Check if the list has left over items that don't match - * - * @var bool - */ - protected $hasLeftoverItems = false; - - public function __construct(array $matches) - { - $this->exporter = new SSListExporter(); - - $this->matches = $matches; - } - - /** - * Evaluates the constraint for parameter $other - * - * If $returnResult is set to false (the default), an exception is thrown - * in case of a failure. null is returned otherwise. - * - * If $returnResult is true, the result of the evaluation is returned as - * a boolean value instead: true in case of success, false in case of a - * failure. - * - * @param SS_List $other Value or object to evaluate. - * @param string $description Additional information about the test - * @param bool $returnResult Whether to return a result or throw an exception - * - * @return null|bool - * - * @throws PHPUnit_Framework_ExpectationFailedException - */ - public function evaluate($other, $description = '', $returnResult = false): ?bool - { - $success = true; - - foreach ($other as $item) { - $this->checkIfItemEvaluatesRemainingMatches($item); - } - - //we have remaining matches? - if (count($this->matches ?? []) !== 0) { - $success = false; - $this->hasLeftoverItems = true; - } - - if ($returnResult) { - return $success; - } - - if (!$success) { - $this->fail($other, $description); - } - - return null; - } - - /** - * @param ViewableData $item - * @return bool - */ - protected function checkIfItemEvaluatesRemainingMatches(ViewableData $item): bool - { - $success = false; - foreach ($this->matches as $key => $match) { - $constraint = new ViewableDataContains($match); - - if ($constraint->evaluate($item, '', true)) { - $success = true; - unset($this->matches[$key]); - break; - } - } - - return $success; - } - - /** - * Returns a string representation of the object. - * - * @return string - */ - public function toString(): string - { - $matchToString = function ($key, $value) { - return ' "' . $key . '" is "' . $value . '"'; - }; - - $matchesToString = function ($matches) use ($matchToString) { - $matchesAsString = implode(' and ', array_map( - $matchToString, - array_keys($matches ?? []), - array_values($matches ?? []) - )); - - return '(' . $matchesAsString . ')'; - }; - - $allMatchesAsString = implode( - "\n or ", - array_map($matchesToString, $this->matches ?? []) - ); - - - return $this->getStubForToString() . $allMatchesAsString; - } - - /** - * @return string - */ - protected function getStubForToString(): string - { - return ' contains an item matching '; - } - } -} - -/* ------------------------------------------------- - * - * This version of FunctionalTest is for phpunit 5 - * The phpunit 9 version is at the top of this file - * - * ------------------------------------------------- - */ - -if (!class_exists(PHPUnit_Framework_Constraint::class)) { - return; -} - /** * Constraint for checking if a SS_List contains items matching the given * key-value pairs. */ -// Ignore multiple classes in same file -// @codingStandardsIgnoreStart -class SSListContains extends PHPUnit_Framework_Constraint implements TestOnly +class SSListContains extends Constraint implements TestOnly { - // @codingStandardsIgnoreEnd /** * @var array */ @@ -188,7 +27,7 @@ class SSListContains extends PHPUnit_Framework_Constraint implements TestOnly */ protected $hasLeftoverItems = false; - public function __construct($matches) + public function __construct(array $matches) { $this->exporter = new SSListExporter(); @@ -209,11 +48,9 @@ class SSListContains extends PHPUnit_Framework_Constraint implements TestOnly * @param string $description Additional information about the test * @param bool $returnResult Whether to return a result or throw an exception * - * @return null|bool - * * @throws ExpectationFailedException */ - public function evaluate($other, $description = '', $returnResult = false) + public function evaluate($other, $description = '', $returnResult = false): ?bool { $success = true; @@ -238,11 +75,7 @@ class SSListContains extends PHPUnit_Framework_Constraint implements TestOnly return null; } - /** - * @param ViewableData $item - * @return bool - */ - protected function checkIfItemEvaluatesRemainingMatches(ViewableData $item) + protected function checkIfItemEvaluatesRemainingMatches(ViewableData $item): bool { $success = false; foreach ($this->matches as $key => $match) { @@ -260,10 +93,8 @@ class SSListContains extends PHPUnit_Framework_Constraint implements TestOnly /** * Returns a string representation of the object. - * - * @return string */ - public function toString() + public function toString(): string { $matchToString = function ($key, $value) { return ' "' . $key . '" is "' . $value . '"'; @@ -288,10 +119,7 @@ class SSListContains extends PHPUnit_Framework_Constraint implements TestOnly return $this->getStubForToString() . $allMatchesAsString; } - /** - * @return string - */ - protected function getStubForToString() + protected function getStubForToString(): string { return ' contains an item matching '; } diff --git a/src/Dev/Constraint/SSListContainsOnly.php b/src/Dev/Constraint/SSListContainsOnly.php index 20486ea0b..f7fdef978 100644 --- a/src/Dev/Constraint/SSListContainsOnly.php +++ b/src/Dev/Constraint/SSListContainsOnly.php @@ -2,26 +2,10 @@ namespace SilverStripe\Dev\Constraint; -use PHPUnit_Framework_Constraint; -use PHPUnit_Framework_ExpectationFailedException; -use PHPUnit\Framework\Constraint\Constraint; use PHPUnit\Framework\ExpectationFailedException; use SilverStripe\Dev\TestOnly; use SilverStripe\ORM\SS_List; -/* ------------------------------------------------- - * - * This version of SSListContains is for both phpunit5 and phpunit 9 because it extends SSListContains - * phpunit 6, 7 and 8 are not supported - * - * @see SilverStripe\Dev\SapphireTest - * - * ------------------------------------------------- - */ -if (!class_exists(Constraint::class) && !class_exists(PHPUnit_Framework_Constraint::class)) { - return; -} - /** * Constraint for checking if a SS_List contains only items matching the given * key-value pairs. Each match must correspond to 1 distinct record. @@ -49,9 +33,7 @@ class SSListContainsOnly extends SSListContains implements TestOnly * @param string $description Additional information about the test * @param bool $returnResult Whether to return a result or throw an exception * - * @return null|bool - * - * @throws PHPUnit_Framework_ExpectationFailedException|ExpectationFailedException + * @throws ExpectationFailedException */ public function evaluate($other, $description = '', $returnResult = false): ?bool { diff --git a/src/Dev/Constraint/SSListContainsOnlyMatchingItems.php b/src/Dev/Constraint/SSListContainsOnlyMatchingItems.php index e0c9b335f..f093b3e01 100644 --- a/src/Dev/Constraint/SSListContainsOnlyMatchingItems.php +++ b/src/Dev/Constraint/SSListContainsOnlyMatchingItems.php @@ -2,127 +2,18 @@ namespace SilverStripe\Dev\Constraint; -use PHPUnit_Framework_Constraint; -use PHPUnit_Framework_ExpectationFailedException; use PHPUnit\Framework\Constraint\Constraint; use PHPUnit\Framework\ExpectationFailedException; use SilverStripe\Dev\SSListExporter; use SilverStripe\Dev\TestOnly; use SilverStripe\ORM\SS_List; -/* ------------------------------------------------- - * - * This version of SSListContainsOnlyMatchingItems is for phpunit 9 - * The phpunit 5 version is lower down in this file - * phpunit 6, 7 and 8 are not supported - * - * @see SilverStripe\Dev\SapphireTest - * - * ------------------------------------------------- - */ - -if (class_exists(Constraint::class)) { - - /** - * Constraint for checking if every item in a SS_List matches a given match, - * e.g. every Member has isActive set to true - */ - // Ignore multiple classes in same file - // @codingStandardsIgnoreStart - class SSListContainsOnlyMatchingItems extends Constraint implements TestOnly - { - // @codingStandardsIgnoreEnd - /** - * @var array - */ - private $match; - - /** - * @var ViewableDataContains - */ - private $constraint; - - public function __construct($match) - { - $this->exporter = new SSListExporter(); - - $this->constraint = new ViewableDataContains($match); - $this->match = $match; - } - - /** - * Evaluates the constraint for parameter $other - * - * If $returnResult is set to false (the default), an exception is thrown - * in case of a failure. null is returned otherwise. - * - * If $returnResult is true, the result of the evaluation is returned as - * a boolean value instead: true in case of success, false in case of a - * failure. - * - * @param SS_List $other Value or object to evaluate. - * @param string $description Additional information about the test - * @param bool $returnResult Whether to return a result or throw an exception - * - * @return null|bool - * - * @throws ExpectationFailedException - */ - public function evaluate($other, $description = '', $returnResult = false): ?bool - { - $success = true; - - foreach ($other as $item) { - if (!$this->constraint->evaluate($item, '', true)) { - $success = false; - break; - } - } - - if ($returnResult) { - return $success; - } - - if (!$success) { - $this->fail($other, $description); - } - - return null; - } - - /** - * Returns a string representation of the object. - * - * @return string - */ - public function toString(): string - { - return 'contains only Objects where "' . key($this->match ?? []) . '" is "' . current($this->match ?? []) . '"'; - } - } -} - -if (!class_exists(PHPUnit_Framework_Constraint::class)) { - return; -} - -/* ------------------------------------------------- - * - * This version of SSListContainsOnlyMatchingItems is for phpunit 5 - * The phpunit 9 version is at the top of this file - * - * ------------------------------------------------- - */ - /** * Constraint for checking if every item in a SS_List matches a given match, * e.g. every Member has isActive set to true */ -// Ignore multiple classes in same file -// @codingStandardsIgnoreStart -class SSListContainsOnlyMatchingItems extends PHPUnit_Framework_Constraint implements TestOnly +class SSListContainsOnlyMatchingItems extends Constraint implements TestOnly { - // @codingStandardsIgnoreEnd /** * @var array */ @@ -155,11 +46,9 @@ class SSListContainsOnlyMatchingItems extends PHPUnit_Framework_Constraint imple * @param string $description Additional information about the test * @param bool $returnResult Whether to return a result or throw an exception * - * @return null|bool - * - * @throws PHPUnit_Framework_ExpectationFailedException + * @throws ExpectationFailedException */ - public function evaluate($other, $description = '', $returnResult = false) + public function evaluate($other, $description = '', $returnResult = false): ?bool { $success = true; @@ -183,10 +72,8 @@ class SSListContainsOnlyMatchingItems extends PHPUnit_Framework_Constraint imple /** * Returns a string representation of the object. - * - * @return string */ - public function toString() + public function toString(): string { return 'contains only Objects where "' . key($this->match ?? []) . '" is "' . current($this->match ?? []) . '"'; } diff --git a/src/Dev/Constraint/ViewableDataContains.php b/src/Dev/Constraint/ViewableDataContains.php index e487515d2..c7b258159 100644 --- a/src/Dev/Constraint/ViewableDataContains.php +++ b/src/Dev/Constraint/ViewableDataContains.php @@ -2,134 +2,18 @@ namespace SilverStripe\Dev\Constraint; -use PHPUnit_Framework_Constraint; -use PHPUnit_Framework_ExpectationFailedException; -use PHPUnit_Util_InvalidArgumentHelper; use PHPUnit\Framework\Constraint\Constraint; use PHPUnit\Framework\ExpectationFailedException; use SilverStripe\Dev\TestOnly; use SilverStripe\View\ViewableData; use SilverStripe\Dev\SapphireTest; -/* ------------------------------------------------- - * - * This version of ViewableDataContains is for phpunit 9 - * The phpunit 5 version is lower down in this file - * phpunit 6, 7 and 8 are not supported - * - * @see SilverStripe\Dev\SapphireTest - * - * ------------------------------------------------- - */ - -if (class_exists(Constraint::class)) { - - /** - * Constraint for checking if a ViewableData (e.g. ArrayData or any DataObject) contains fields matching the given - * key-value pairs. - */ - // Ignore multiple classes in same file - // @codingStandardsIgnoreStart - class ViewableDataContains extends Constraint implements TestOnly - { - // @codingStandardsIgnoreEnd - /** - * @var array - */ - private $match; - - /** - * ViewableDataContains constructor. - * @param array $match - */ - public function __construct(array $match) - { - if (!is_array($match)) { - throw SapphireTest::createInvalidArgumentException( - 1, - 'array' - ); - } - - $this->match = $match; - } - - /** - * Evaluates the constraint for parameter $other - * - * If $returnResult is set to false (the default), an exception is thrown - * in case of a failure. null is returned otherwise. - * - * If $returnResult is true, the result of the evaluation is returned as - * a boolean value instead: true in case of success, false in case of a - * failure. - * - * @param ViewableData $other Value or object to evaluate. - * @param string $description Additional information about the test - * @param bool $returnResult Whether to return a result or throw an exception - * - * @return null|bool - * - * @throws ExpectationFailedException - */ - public function evaluate($other, $description = '', $returnResult = false): ?bool - { - $success = true; - - foreach ($this->match as $fieldName => $value) { - if ($other->$fieldName != $value) { - $success = false; - break; - } - } - - if ($returnResult) { - return $success; - } - - if (!$success) { - $this->fail($other, $description); - } - - return null; - } - - - /** - * Returns a string representation of the object. - * - * @todo: add representation for more than one match - * - * @return string - */ - public function toString(): string - { - return 'contains only Objects where "' . key($this->match ?? []) . '" is "' . current($this->match ?? []) . '"'; - } - } -} - -/* ------------------------------------------------- - * - * This version of ViewableDataContains is for phpunit 5 - * The phpunit 9 version is at the top of this file - * - * ------------------------------------------------- - */ - -if (!class_exists(PHPUnit_Framework_Constraint::class)) { - return; -} - /** * Constraint for checking if a ViewableData (e.g. ArrayData or any DataObject) contains fields matching the given * key-value pairs. */ -// Ignore multiple classes in same file -// @codingStandardsIgnoreStart -class ViewableDataContains extends PHPUnit_Framework_Constraint implements TestOnly +class ViewableDataContains extends Constraint implements TestOnly { - // @codingStandardsIgnoreEnd /** * @var array */ @@ -137,13 +21,11 @@ class ViewableDataContains extends PHPUnit_Framework_Constraint implements TestO /** * ViewableDataContains constructor. - * @param array $match */ - public function __construct($match) + public function __construct(array $match) { - parent::__construct(); if (!is_array($match)) { - throw PHPUnit_Util_InvalidArgumentHelper::factory( + throw SapphireTest::createInvalidArgumentException( 1, 'array' ); @@ -166,11 +48,9 @@ class ViewableDataContains extends PHPUnit_Framework_Constraint implements TestO * @param string $description Additional information about the test * @param bool $returnResult Whether to return a result or throw an exception * - * @return null|bool - * - * @throws PHPUnit_Framework_ExpectationFailedException + * @throws ExpectationFailedException */ - public function evaluate($other, $description = '', $returnResult = false) + public function evaluate($other, $description = '', $returnResult = false): ?bool { $success = true; @@ -192,14 +72,13 @@ class ViewableDataContains extends PHPUnit_Framework_Constraint implements TestO return null; } + /** * Returns a string representation of the object. * * @todo: add representation for more than one match - * - * @return string */ - public function toString() + public function toString(): string { return 'contains only Objects where "' . key($this->match ?? []) . '" is "' . current($this->match ?? []) . '"'; } diff --git a/src/Dev/FunctionalTest.php b/src/Dev/FunctionalTest.php index d712a7645..90a47bedc 100644 --- a/src/Dev/FunctionalTest.php +++ b/src/Dev/FunctionalTest.php @@ -2,10 +2,7 @@ namespace SilverStripe\Dev; -use PHPUnit_Framework_AssertionFailedError; -use PHPUnit_Extensions_GroupTestSuite; use PHPUnit\Framework\AssertionFailedError; -use PHPUnit\Framework\Constraint\IsEqualCanonicalizing; use SilverStripe\Control\Director; use SilverStripe\Control\HTTPResponse; use SilverStripe\Control\Session; @@ -15,463 +12,6 @@ use SilverStripe\Security\SecurityToken; use SilverStripe\View\SSViewer; use SimpleXMLElement; -/* ------------------------------------------------- - * - * This version of FunctionalTest is for phpunit 9 - * The phpunit 5 version is lower down in this file - * phpunit 6, 7 and 8 are not supported - * - * @see SilverStripe\Dev\SapphireTest - * - * IsEqualCanonicalizing::class is a new class added in PHPUnit 9, testing that this class exists - * to ensure that we're not using a a prior, incompatible version of PHPUnit - * - * ------------------------------------------------- - */ -if (class_exists(IsEqualCanonicalizing::class)) { - - /** - * SilverStripe-specific testing object designed to support functional testing of your web app. It simulates get/post - * requests, form submission, and can validate resulting HTML, looking up content by CSS selector. - * - * The example below shows how it works. - * - * - * public function testMyForm() { - * // Visit a URL - * $this->get("your/url"); - * - * // Submit a form on the page that you get in response - * $this->submitForm("MyForm_ID", "action_dologin", array("Email" => "invalid email ^&*&^")); - * - * // Validate the content that is returned - * $this->assertExactMatchBySelector("#MyForm_ID p.error", array("That email address is invalid.")); - * } - * - */ - // Ignore multiple classes in same file - // @codingStandardsIgnoreStart - class FunctionalTest extends SapphireTest implements TestOnly - { - // @codingStandardsIgnoreEnd - /** - * Set this to true on your sub-class to disable the use of themes in this test. - * This can be handy for functional testing of modules without having to worry about whether a user has changed - * behaviour by replacing the theme. - * - * @var bool - */ - protected static $disable_themes = false; - - /** - * Set this to true on your sub-class to use the draft site by default for every test in this class. - * - * @deprecated 4.2.0:5.0.0 Use ?stage=Stage in your ->get() querystring requests instead - * @var bool - */ - protected static $use_draft_site = false; - - /** - * @var TestSession - */ - protected $mainSession = null; - - /** - * CSSContentParser for the most recently requested page. - * - * @var CSSContentParser - */ - protected $cssParser = null; - - /** - * If this is true, then 30x Location headers will be automatically followed. - * If not, then you will have to manually call $this->mainSession->followRedirection() to follow them. - * However, this will let you inspect the intermediary headers - * - * @var bool - */ - protected $autoFollowRedirection = true; - - /** - * Returns the {@link Session} object for this test - * - * @return Session - */ - public function session() - { - return $this->mainSession->session(); - } - - protected function setUp(): void - { - parent::setUp(); - - // Skip calling FunctionalTest directly. - if (static::class == __CLASS__) { - $this->markTestSkipped(sprintf('Skipping %s ', static::class)); - } - - $this->mainSession = new TestSession(); - - // Disable theme, if necessary - if (static::get_disable_themes()) { - SSViewer::config()->update('theme_enabled', false); - } - - // Flush user - $this->logOut(); - - // Switch to draft site, if necessary - // If you rely on this you should be crafting stage-specific urls instead though. - if (static::get_use_draft_site()) { - $this->useDraftSite(); - } - - // Unprotect the site, tests are running with the assumption it's off. They will enable it on a case-by-case - // basis. - BasicAuth::protect_entire_site(false); - - SecurityToken::disable(); - } - - protected function tearDown(): void - { - SecurityToken::enable(); - unset($this->mainSession); - parent::tearDown(); - } - - /** - * Run a test while mocking the base url with the provided value - * @param string $url The base URL to use for this test - * @param callable $callback The test to run - */ - protected function withBaseURL($url, $callback) - { - $oldBase = Config::inst()->get(Director::class, 'alternate_base_url'); - Config::modify()->set(Director::class, 'alternate_base_url', $url); - $callback($this); - Config::modify()->set(Director::class, 'alternate_base_url', $oldBase); - } - - /** - * Run a test while mocking the base folder with the provided value - * @param string $folder The base folder to use for this test - * @param callable $callback The test to run - */ - protected function withBaseFolder($folder, $callback) - { - $oldFolder = Config::inst()->get(Director::class, 'alternate_base_folder'); - Config::modify()->set(Director::class, 'alternate_base_folder', $folder); - $callback($this); - Config::modify()->set(Director::class, 'alternate_base_folder', $oldFolder); - } - - /** - * Submit a get request - * @uses Director::test() - * - * @param string $url - * @param Session $session - * @param array $headers - * @param array $cookies - * @return HTTPResponse - */ - public function get($url, $session = null, $headers = null, $cookies = null) - { - $this->cssParser = null; - $response = $this->mainSession->get($url, $session, $headers, $cookies); - if ($this->autoFollowRedirection && is_object($response) && $response->getHeader('Location')) { - $response = $this->mainSession->followRedirection(); - } - return $response; - } - - /** - * Submit a post request - * - * @uses Director::test() - * @param string $url - * @param array $data - * @param array $headers - * @param Session $session - * @param string $body - * @param array $cookies - * @return HTTPResponse - */ - public function post($url, $data, $headers = null, $session = null, $body = null, $cookies = null) - { - $this->cssParser = null; - $response = $this->mainSession->post($url, $data, $headers, $session, $body, $cookies); - if ($this->autoFollowRedirection && is_object($response) && $response->getHeader('Location')) { - $response = $this->mainSession->followRedirection(); - } - return $response; - } - - /** - * Submit the form with the given HTML ID, filling it out with the given data. - * Acts on the most recent response. - * - * Any data parameters have to be present in the form, with exact form field name - * and values, otherwise they are removed from the submission. - * - * Caution: Parameter names have to be formatted - * as they are in the form submission, not as they are interpreted by PHP. - * Wrong: array('mycheckboxvalues' => array(1 => 'one', 2 => 'two')) - * Right: array('mycheckboxvalues[1]' => 'one', 'mycheckboxvalues[2]' => 'two') - * - * @see http://www.simpletest.org/en/form_testing_documentation.html - * - * @param string $formID HTML 'id' attribute of a form (loaded through a previous response) - * @param string $button HTML 'name' attribute of the button (NOT the 'id' attribute) - * @param array $data Map of GET/POST data. - * @return HTTPResponse - */ - public function submitForm($formID, $button = null, $data = []) - { - $this->cssParser = null; - $response = $this->mainSession->submitForm($formID, $button, $data); - if ($this->autoFollowRedirection && is_object($response) && $response->getHeader('Location')) { - $response = $this->mainSession->followRedirection(); - } - return $response; - } - - /** - * Return the most recent content - * - * @return string - */ - public function content() - { - return $this->mainSession->lastContent(); - } - - /** - * Find an attribute in a SimpleXMLElement object by name. - * @param SimpleXMLElement $object - * @param string $attribute Name of attribute to find - * @return SimpleXMLElement object of the attribute - */ - public function findAttribute($object, $attribute) - { - $found = false; - foreach ($object->attributes() as $a => $b) { - if ($a == $attribute) { - $found = $b; - } - } - return $found; - } - - /** - * Return a CSSContentParser for the most recent content. - * - * @return CSSContentParser - */ - public function cssParser() - { - if (!$this->cssParser) { - $this->cssParser = new CSSContentParser($this->mainSession->lastContent()); - } - return $this->cssParser; - } - - /** - * Assert that the most recently queried page contains a number of content tags specified by a CSS selector. - * The given CSS selector will be applied to the HTML of the most recent page. The content of every matching tag - * will be examined. The assertion fails if one of the expectedMatches fails to appear. - * - * Note:   characters are stripped from the content; make sure that your assertions take this into account. - * - * @param string $selector A basic CSS selector, e.g. 'li.jobs h3' - * @param array|string $expectedMatches The content of at least one of the matched tags - * @param string $message - * @throws AssertionFailedError - */ - public function assertPartialMatchBySelector($selector, $expectedMatches, $message = null) - { - if (is_string($expectedMatches)) { - $expectedMatches = [$expectedMatches]; - } - - $items = $this->cssParser()->getBySelector($selector); - - $actuals = []; - if ($items) { - foreach ($items as $item) { - $actuals[trim(preg_replace('/\s+/', ' ', (string)$item))] = true; - } - } - - $message = $message ?: - "Failed asserting the CSS selector '$selector' has a partial match to the expected elements:\n'" - . implode("'\n'", $expectedMatches) . "'\n\n" - . "Instead the following elements were found:\n'" . implode("'\n'", array_keys($actuals ?? [])) . "'"; - - foreach ($expectedMatches as $match) { - $this->assertTrue(isset($actuals[$match]), $message); - } - } - - /** - * Assert that the most recently queried page contains a number of content tags specified by a CSS selector. - * The given CSS selector will be applied to the HTML of the most recent page. The full HTML of every matching tag - * will be examined. The assertion fails if one of the expectedMatches fails to appear. - * - * Note:   characters are stripped from the content; make sure that your assertions take this into account. - * - * @param string $selector A basic CSS selector, e.g. 'li.jobs h3' - * @param array|string $expectedMatches The content of *all* matching tags as an array - * @param string $message - * @throws AssertionFailedError - */ - public function assertExactMatchBySelector($selector, $expectedMatches, $message = null) - { - if (is_string($expectedMatches)) { - $expectedMatches = [$expectedMatches]; - } - - $items = $this->cssParser()->getBySelector($selector); - - $actuals = []; - if ($items) { - foreach ($items as $item) { - $actuals[] = trim(preg_replace('/\s+/', ' ', (string)$item) ?? ''); - } - } - - $message = $message ?: - "Failed asserting the CSS selector '$selector' has an exact match to the expected elements:\n'" - . implode("'\n'", $expectedMatches) . "'\n\n" - . "Instead the following elements were found:\n'" . implode("'\n'", $actuals) . "'"; - - $this->assertTrue($expectedMatches == $actuals, $message); - } - - /** - * Assert that the most recently queried page contains a number of content tags specified by a CSS selector. - * The given CSS selector will be applied to the HTML of the most recent page. The content of every matching tag - * will be examined. The assertion fails if one of the expectedMatches fails to appear. - * - * Note:   characters are stripped from the content; make sure that your assertions take this into account. - * - * @param string $selector A basic CSS selector, e.g. 'li.jobs h3' - * @param array|string $expectedMatches The content of at least one of the matched tags - * @param string $message - * @throws AssertionFailedError - */ - public function assertPartialHTMLMatchBySelector($selector, $expectedMatches, $message = null) - { - if (is_string($expectedMatches)) { - $expectedMatches = [$expectedMatches]; - } - - $items = $this->cssParser()->getBySelector($selector); - - $actuals = []; - if ($items) { - /** @var SimpleXMLElement $item */ - foreach ($items as $item) { - $actuals[$item->asXML()] = true; - } - } - - $message = $message ?: - "Failed asserting the CSS selector '$selector' has a partial match to the expected elements:\n'" - . implode("'\n'", $expectedMatches) . "'\n\n" - . "Instead the following elements were found:\n'" . implode("'\n'", array_keys($actuals ?? [])) . "'"; - - foreach ($expectedMatches as $match) { - $this->assertTrue(isset($actuals[$match]), $message); - } - } - - /** - * Assert that the most recently queried page contains a number of content tags specified by a CSS selector. - * The given CSS selector will be applied to the HTML of the most recent page. The full HTML of every matching tag - * will be examined. The assertion fails if one of the expectedMatches fails to appear. - * - * Note:   characters are stripped from the content; make sure that your assertions take this into account. - * - * @param string $selector A basic CSS selector, e.g. 'li.jobs h3' - * @param array|string $expectedMatches The content of *all* matched tags as an array - * @param string $message - * @throws AssertionFailedError - */ - public function assertExactHTMLMatchBySelector($selector, $expectedMatches, $message = null) - { - $items = $this->cssParser()->getBySelector($selector); - - $actuals = []; - if ($items) { - /** @var SimpleXMLElement $item */ - foreach ($items as $item) { - $actuals[] = $item->asXML(); - } - } - - $message = $message ?: - "Failed asserting the CSS selector '$selector' has an exact match to the expected elements:\n'" - . implode("'\n'", $expectedMatches) . "'\n\n" - . "Instead the following elements were found:\n'" . implode("'\n'", $actuals) . "'"; - - $this->assertTrue($expectedMatches == $actuals, $message); - } - - /** - * Use the draft (stage) site for testing. - * This is helpful if you're not testing publication functionality and don't want "stage management" cluttering - * your test. - * - * @deprecated 4.2.0:5.0.0 Use ?stage=Stage querystring arguments instead of useDraftSite - * @param bool $enabled toggle the use of the draft site - */ - public function useDraftSite($enabled = true) - { - Deprecation::notice('5.0', 'Use ?stage=Stage querystring arguments instead of useDraftSite'); - if ($enabled) { - $this->session()->set('readingMode', 'Stage.Stage'); - $this->session()->set('unsecuredDraftSite', true); - } else { - $this->session()->clear('readingMode'); - $this->session()->clear('unsecuredDraftSite'); - } - } - - /** - * @return bool - */ - public static function get_disable_themes() - { - return static::$disable_themes; - } - - /** - * @deprecated 4.2.0:5.0.0 Use ?stage=Stage in your querystring arguments instead - * @return bool - */ - public static function get_use_draft_site() - { - return static::$use_draft_site; - } - } -} - -/* ------------------------------------------------- - * - * This version of FunctionalTest is for PHPUnit 5 - * The PHPUnit 9 version is at the top of this file - * - * PHPUnit_Extensions_GroupTestSuite is a class that only exists in PHPUnit 5 - * - * ------------------------------------------------- - */ -if (!class_exists(PHPUnit_Extensions_GroupTestSuite::class)) { - return; -} - /** * SilverStripe-specific testing object designed to support functional testing of your web app. It simulates get/post * requests, form submission, and can validate resulting HTML, looking up content by CSS selector. @@ -491,11 +31,8 @@ if (!class_exists(PHPUnit_Extensions_GroupTestSuite::class)) { * } * */ -// Ignore multiple classes in same file -// @codingStandardsIgnoreStart class FunctionalTest extends SapphireTest implements TestOnly { - // @codingStandardsIgnoreEnd /** * Set this to true on your sub-class to disable the use of themes in this test. * This can be handy for functional testing of modules without having to worry about whether a user has changed @@ -544,7 +81,7 @@ class FunctionalTest extends SapphireTest implements TestOnly return $this->mainSession->session(); } - protected function setUp() + protected function setUp(): void { parent::setUp(); @@ -576,7 +113,7 @@ class FunctionalTest extends SapphireTest implements TestOnly SecurityToken::disable(); } - protected function tearDown() + protected function tearDown(): void { SecurityToken::enable(); unset($this->mainSession); @@ -730,7 +267,7 @@ class FunctionalTest extends SapphireTest implements TestOnly * @param string $selector A basic CSS selector, e.g. 'li.jobs h3' * @param array|string $expectedMatches The content of at least one of the matched tags * @param string $message - * @throws PHPUnit_Framework_AssertionFailedError + * @throws AssertionFailedError */ public function assertPartialMatchBySelector($selector, $expectedMatches, $message = null) { @@ -767,7 +304,7 @@ class FunctionalTest extends SapphireTest implements TestOnly * @param string $selector A basic CSS selector, e.g. 'li.jobs h3' * @param array|string $expectedMatches The content of *all* matching tags as an array * @param string $message - * @throws PHPUnit_Framework_AssertionFailedError + * @throws AssertionFailedError */ public function assertExactMatchBySelector($selector, $expectedMatches, $message = null) { @@ -802,7 +339,7 @@ class FunctionalTest extends SapphireTest implements TestOnly * @param string $selector A basic CSS selector, e.g. 'li.jobs h3' * @param array|string $expectedMatches The content of at least one of the matched tags * @param string $message - * @throws PHPUnit_Framework_AssertionFailedError + * @throws AssertionFailedError */ public function assertPartialHTMLMatchBySelector($selector, $expectedMatches, $message = null) { @@ -840,7 +377,7 @@ class FunctionalTest extends SapphireTest implements TestOnly * @param string $selector A basic CSS selector, e.g. 'li.jobs h3' * @param array|string $expectedMatches The content of *all* matched tags as an array * @param string $message - * @throws PHPUnit_Framework_AssertionFailedError + * @throws AssertionFailedError */ public function assertExactHTMLMatchBySelector($selector, $expectedMatches, $message = null) { diff --git a/src/Dev/SapphireTest.php b/src/Dev/SapphireTest.php index 0bde7d7c8..aed11730a 100644 --- a/src/Dev/SapphireTest.php +++ b/src/Dev/SapphireTest.php @@ -1,19 +1,11 @@ " notation - * between the fixtures, they act independent of each other. - * - * @var string|array - */ - protected static $fixture_file = null; - - /** - * @deprecated 4.0..5.0 Use FixtureTestState instead - * @var FixtureFactory - */ - protected $fixtureFactory; - - /** - * @var Boolean If set to TRUE, this will force a test database to be generated - * in {@link setUp()}. Note that this flag is overruled by the presence of a - * {@link $fixture_file}, which always forces a database build. - * - * @var bool - */ - protected $usesDatabase = null; - - /** - * This test will cleanup its state via transactions. - * If set to false a full schema is forced between tests, but at a performance cost. - * - * @var bool - */ - protected $usesTransactions = true; - - /** - * @var bool - */ - protected static $is_running_test = false; - - /** - * By default, setUp() does not require default records. Pass - * class names in here, and the require/augment default records - * function will be called on them. - * - * @var array - */ - protected $requireDefaultRecordsFrom = []; - - /** - * A list of extensions that can't be applied during the execution of this run. If they are - * applied, they will be temporarily removed and a database migration called. - * - * The keys of the are the classes that the extensions can't be applied the extensions to, and - * the values are an array of illegal extensions on that class. - * - * Set a class to `*` to remove all extensions (unadvised) - * - * @var array - */ - protected static $illegal_extensions = []; - - /** - * A list of extensions that must be applied during the execution of this run. If they are - * not applied, they will be temporarily added and a database migration called. - * - * The keys of the are the classes to apply the extensions to, and the values are an array - * of required extensions on that class. - * - * Example: - * - * array("MyTreeDataObject" => array("Versioned", "Hierarchy")) - * - * - * @var array - */ - protected static $required_extensions = []; - - /** - * By default, the test database won't contain any DataObjects that have the interface TestOnly. - * This variable lets you define additional TestOnly DataObjects to set up for this test. - * Set it to an array of DataObject subclass names. - * - * @var array - */ - protected static $extra_dataobjects = []; - - /** - * List of class names of {@see Controller} objects to register routes for - * Controllers must implement Link() method - * - * @var array - */ - protected static $extra_controllers = []; - - /** - * We need to disabling backing up of globals to avoid overriding - * the few globals SilverStripe relies on, like $lang for the i18n subsystem. - * - * @see http://sebastian-bergmann.de/archives/797-Global-Variables-and-PHPUnit.html - */ - protected $backupGlobals = false; - - /** - * State management container for SapphireTest - * - * @var SapphireTestState - */ - protected static $state = null; - - /** - * Temp database helper - * - * @var TempDatabase - */ - protected static $tempDB = null; - - /** - * @return TempDatabase - */ - public static function tempDB() - { - if (!class_exists(TempDatabase::class)) { - return null; - } - - if (!static::$tempDB) { - static::$tempDB = TempDatabase::create(); - } - return static::$tempDB; - } - - /** - * Gets illegal extensions for this class - * - * @return array - */ - public static function getIllegalExtensions() - { - return static::$illegal_extensions; - } - - /** - * Gets required extensions for this class - * - * @return array - */ - public static function getRequiredExtensions() - { - return static::$required_extensions; - } - - /** - * Check if test bootstrapping has been performed. Must not be relied on - * outside of unit tests. - * - * @return bool - */ - protected static function is_running_test() - { - return self::$is_running_test; - } - - /** - * Set test running state - * - * @param bool $bool - */ - protected static function set_is_running_test($bool) - { - self::$is_running_test = $bool; - } - - /** - * @return String - */ - public static function get_fixture_file() - { - return static::$fixture_file; - } - - /** - * @return bool - */ - public function getUsesDatabase() - { - return $this->usesDatabase; - } - - /** - * @return bool - */ - public function getUsesTransactions() - { - return $this->usesTransactions; - } - - /** - * @return array - */ - public function getRequireDefaultRecordsFrom() - { - return $this->requireDefaultRecordsFrom; - } - - /** - * Setup the test. - * Always sets up in order: - * - Reset php state - * - Nest - * - Custom state helpers - * - * User code should call parent::setUp() before custom setup code - */ - protected function setUp(): void - { - if (!defined('FRAMEWORK_PATH')) { - trigger_error( - 'Missing constants, did you remember to include the test bootstrap in your phpunit.xml file?', - E_USER_WARNING - ); - } - - // Call state helpers - static::$state->setUp($this); - - // We cannot run the tests on this abstract class. - if (static::class == __CLASS__) { - $this->markTestSkipped(sprintf('Skipping %s ', static::class)); - } - - // i18n needs to be set to the defaults or tests fail - if (class_exists(i18n::class)) { - i18n::set_locale(i18n::config()->uninherited('default_locale')); - } - - // Set default timezone consistently to avoid NZ-specific dependencies - date_default_timezone_set('UTC'); - - if (class_exists(Member::class)) { - Member::set_password_validator(null); - } - - if (class_exists(Cookie::class)) { - Cookie::config()->update('report_errors', false); - } - - if (class_exists(RootURLController::class)) { - RootURLController::reset(); - } - - if (class_exists(Security::class)) { - Security::clear_database_is_ready(); - } - - // Set up test routes - $this->setUpRoutes(); - - $fixtureFiles = $this->getFixturePaths(); - - if ($this->shouldSetupDatabaseForCurrentTest($fixtureFiles)) { - // Assign fixture factory to deprecated prop in case old tests use it over the getter - /** @var FixtureTestState $fixtureState */ - $fixtureState = static::$state->getStateByName('fixtures'); - $this->fixtureFactory = $fixtureState->getFixtureFactory(static::class); - - $this->logInWithPermission('ADMIN'); - } - - // turn off template debugging - if (class_exists(SSViewer::class)) { - SSViewer::config()->update('source_file_comments', false); - } - - // Set up the test mailer - if (class_exists(TestMailer::class)) { - Injector::inst()->registerService(new TestMailer(), Mailer::class); - } - - if (class_exists(Email::class)) { - Email::config()->remove('send_all_emails_to'); - Email::config()->remove('send_all_emails_from'); - Email::config()->remove('cc_all_emails_to'); - Email::config()->remove('bcc_all_emails_to'); - } - } - - - /** - * Helper method to determine if the current test should enable a test database - * - * @param $fixtureFiles - * @return bool - */ - protected function shouldSetupDatabaseForCurrentTest($fixtureFiles) - { - $databaseEnabledByDefault = $fixtureFiles || $this->usesDatabase; - - return ($databaseEnabledByDefault && !$this->currentTestDisablesDatabase()) - || $this->currentTestEnablesDatabase(); - } - - /** - * Helper method to check, if the current test uses the database. - * This can be switched on with the annotation "@useDatabase" - * - * @return bool - */ - protected function currentTestEnablesDatabase() - { - $annotations = $this->getAnnotations(); - - return array_key_exists('useDatabase', $annotations['method'] ?? []) - && $annotations['method']['useDatabase'][0] !== 'false'; - } - - /** - * Helper method to check, if the current test uses the database. - * This can be switched on with the annotation "@useDatabase false" - * - * @return bool - */ - protected function currentTestDisablesDatabase() - { - $annotations = $this->getAnnotations(); - - return array_key_exists('useDatabase', $annotations['method'] ?? []) - && $annotations['method']['useDatabase'][0] === 'false'; - } - - /** - * Called once per test case ({@link SapphireTest} subclass). - * This is different to {@link setUp()}, which gets called once - * per method. Useful to initialize expensive operations which - * don't change state for any called method inside the test, - * e.g. dynamically adding an extension. See {@link teardownAfterClass()} - * for tearing down the state again. - * - * Always sets up in order: - * - Reset php state - * - Nest - * - Custom state helpers - * - * User code should call parent::setUpBeforeClass() before custom setup code - * - * @throws Exception - */ - public static function setUpBeforeClass(): void - { - // Start tests - static::start(); - - if (!static::$state) { - throw new Exception('SapphireTest failed to bootstrap!'); - } - - // Call state helpers - static::$state->setUpOnce(static::class); - - // Build DB if we have objects - if (class_exists(DataObject::class) && static::getExtraDataObjects()) { - DataObject::reset(); - static::resetDBSchema(true, true); - } - } - - /** - * tearDown method that's called once per test class rather once per test method. - * - * Always sets up in order: - * - Custom state helpers - * - Unnest - * - Reset php state - * - * User code should call parent::tearDownAfterClass() after custom tear down code - */ - public static function tearDownAfterClass(): void - { - // Call state helpers - static::$state->tearDownOnce(static::class); - - // Reset DB schema - static::resetDBSchema(); - } - - /** - * @return FixtureFactory|false - * @deprecated 4.0.0:5.0.0 - */ - public function getFixtureFactory() - { - Deprecation::notice('5.0', __FUNCTION__ . ' is deprecated, use ' . FixtureTestState::class . ' instead'); - /** @var FixtureTestState $state */ - $state = static::$state->getStateByName('fixtures'); - return $state->getFixtureFactory(static::class); - } - - /** - * Sets a new fixture factory - * @param FixtureFactory $factory - * @return $this - * @deprecated 4.0.0:5.0.0 - */ - public function setFixtureFactory(FixtureFactory $factory) - { - Deprecation::notice('5.0', __FUNCTION__ . ' is deprecated, use ' . FixtureTestState::class . ' instead'); - /** @var FixtureTestState $state */ - $state = static::$state->getStateByName('fixtures'); - $state->setFixtureFactory($factory, static::class); - $this->fixtureFactory = $factory; - return $this; - } - - /** - * Get the ID of an object from the fixture. - * - * @param string $className The data class or table name, as specified in your fixture file. Parent classes won't work - * @param string $identifier The identifier string, as provided in your fixture file - * @return int - */ - protected function idFromFixture($className, $identifier) - { - /** @var FixtureTestState $state */ - $state = static::$state->getStateByName('fixtures'); - $id = $state->getFixtureFactory(static::class)->getId($className, $identifier); - - if (!$id) { - throw new InvalidArgumentException(sprintf( - "Couldn't find object '%s' (class: %s)", - $identifier, - $className - )); - } - - return $id; - } - - /** - * Return all of the IDs in the fixture of a particular class name. - * Will collate all IDs form all fixtures if multiple fixtures are provided. - * - * @param string $className The data class or table name, as specified in your fixture file - * @return array A map of fixture-identifier => object-id - */ - protected function allFixtureIDs($className) - { - /** @var FixtureTestState $state */ - $state = static::$state->getStateByName('fixtures'); - return $state->getFixtureFactory(static::class)->getIds($className); - } - - /** - * Get an object from the fixture. - * - * @param string $className The data class or table name, as specified in your fixture file. Parent classes won't work - * @param string $identifier The identifier string, as provided in your fixture file - * - * @return DataObject - */ - protected function objFromFixture($className, $identifier) - { - /** @var FixtureTestState $state */ - $state = static::$state->getStateByName('fixtures'); - $obj = $state->getFixtureFactory(static::class)->get($className, $identifier); - - if (!$obj) { - throw new InvalidArgumentException(sprintf( - "Couldn't find object '%s' (class: %s)", - $identifier, - $className - )); - } - - return $obj; - } - - /** - * Load a YAML fixture file into the database. - * Once loaded, you can use idFromFixture() and objFromFixture() to get items from the fixture. - * Doesn't clear existing fixtures. - * @param string $fixtureFile The location of the .yml fixture file, relative to the site base dir - * @deprecated 4.0.0:5.0.0 - * - */ - public function loadFixture($fixtureFile) - { - Deprecation::notice('5.0', __FUNCTION__ . ' is deprecated, use ' . FixtureTestState::class . ' instead'); - $fixture = Injector::inst()->create(YamlFixture::class, $fixtureFile); - $fixture->writeInto($this->getFixtureFactory()); - } - - /** - * Clear all fixtures which were previously loaded through - * {@link loadFixture()} - */ - public function clearFixtures() - { - /** @var FixtureTestState $state */ - $state = static::$state->getStateByName('fixtures'); - $state->getFixtureFactory(static::class)->clear(); - } - - /** - * Useful for writing unit tests without hardcoding folder structures. - * - * @return string Absolute path to current class. - */ - protected function getCurrentAbsolutePath() - { - $filename = ClassLoader::inst()->getItemPath(static::class); - if (!$filename) { - throw new LogicException('getItemPath returned null for ' . static::class - . '. Try adding flush=1 to the test run.'); - } - return dirname($filename ?? ''); - } - - /** - * @return string File path relative to webroot - */ - protected function getCurrentRelativePath() - { - $base = Director::baseFolder(); - $path = $this->getCurrentAbsolutePath(); - if (substr($path ?? '', 0, strlen($base ?? '')) == $base) { - $path = preg_replace('/^\/*/', '', substr($path ?? '', strlen($base ?? ''))); - } - return $path; - } - - /** - * Setup the test. - * Always sets up in order: - * - Custom state helpers - * - Unnest - * - Reset php state - * - * User code should call parent::tearDown() after custom tear down code - */ - protected function tearDown(): void - { - // Reset mocked datetime - if (class_exists(DBDatetime::class)) { - DBDatetime::clear_mock_now(); - } - - // Stop the redirection that might have been requested in the test. - // Note: Ideally a clean Controller should be created for each test. - // Now all tests executed in a batch share the same controller. - if (class_exists(Controller::class)) { - $controller = Controller::has_curr() ? Controller::curr() : null; - if ($controller && ($response = $controller->getResponse()) && $response->getHeader('Location')) { - $response->setStatusCode(200); - $response->removeHeader('Location'); - } - } - - // Call state helpers - static::$state->tearDown($this); - } - - /** - * Clear the log of emails sent - * - * @return bool True if emails cleared - */ - public function clearEmails() - { - /** @var Mailer $mailer */ - $mailer = Injector::inst()->get(Mailer::class); - if ($mailer instanceof TestMailer) { - $mailer->clearEmails(); - return true; - } - return false; - } - - /** - * Search for an email that was sent. - * All of the parameters can either be a string, or, if they start with "/", a PREG-compatible regular expression. - * @param string $to - * @param string $from - * @param string $subject - * @param string $content - * @return array|null Contains keys: 'Type', 'To', 'From', 'Subject', 'Content', 'PlainContent', 'AttachedFiles', - * 'HtmlContent' - */ - public static function findEmail($to, $from = null, $subject = null, $content = null) - { - /** @var Mailer $mailer */ - $mailer = Injector::inst()->get(Mailer::class); - if ($mailer instanceof TestMailer) { - return $mailer->findEmail($to, $from, $subject, $content); - } - return null; - } - - /** - * Assert that the matching email was sent since the last call to clearEmails() - * All of the parameters can either be a string, or, if they start with "/", a PREG-compatible regular expression. - * - * @param string $to - * @param string $from - * @param string $subject - * @param string $content - */ - public static function assertEmailSent($to, $from = null, $subject = null, $content = null) - { - $found = (bool)static::findEmail($to, $from, $subject, $content); - - $infoParts = ''; - $withParts = []; - if ($to) { - $infoParts .= " to '$to'"; - } - if ($from) { - $infoParts .= " from '$from'"; - } - if ($subject) { - $withParts[] = "subject '$subject'"; - } - if ($content) { - $withParts[] = "content '$content'"; - } - if ($withParts) { - $infoParts .= ' with ' . implode(' and ', $withParts); - } - - static::assertTrue( - $found, - "Failed asserting that an email was sent$infoParts." - ); - } - - - /** - * Assert that the given {@link SS_List} includes DataObjects matching the given key-value - * pairs. Each match must correspond to 1 distinct record. - * - * @param SS_List|array $matches The patterns to match. Each pattern is a map of key-value pairs. You can - * either pass a single pattern or an array of patterns. - * @param SS_List $list The {@link SS_List} to test. - * @param string $message - * - * Examples - * -------- - * Check that $members includes an entry with Email = sam@example.com: - * $this->assertListContains(['Email' => '...@example.com'], $members); - * - * Check that $members includes entries with Email = sam@example.com and with - * Email = ingo@example.com: - * $this->assertListContains([ - * ['Email' => '...@example.com'], - * ['Email' => 'i...@example.com'], - * ], $members); - */ - public static function assertListContains($matches, SS_List $list, $message = '') - { - if (!is_array($matches)) { - throw self::createInvalidArgumentException( - 1, - 'array' - ); - } - - static::assertThat( - $list, - new SSListContains( - $matches - ), - $message - ); - } - - /** - * @param $matches - * @param $dataObjectSet - * @deprecated 4.0.0:5.0.0 Use assertListContains() instead - * - */ - public function assertDOSContains($matches, $dataObjectSet) - { - Deprecation::notice('5.0', 'Use assertListContains() instead'); - static::assertListContains($matches, $dataObjectSet); - } - - /** - * Asserts that no items in a given list appear in the given dataobject list - * - * @param SS_List|array $matches The patterns to match. Each pattern is a map of key-value pairs. You can - * either pass a single pattern or an array of patterns. - * @param SS_List $list The {@link SS_List} to test. - * @param string $message - * - * Examples - * -------- - * Check that $members doesn't have an entry with Email = sam@example.com: - * $this->assertListNotContains(['Email' => '...@example.com'], $members); - * - * Check that $members doesn't have entries with Email = sam@example.com and with - * Email = ingo@example.com: - * $this->assertListNotContains([ - * ['Email' => '...@example.com'], - * ['Email' => 'i...@example.com'], - * ], $members); - */ - public static function assertListNotContains($matches, SS_List $list, $message = '') - { - if (!is_array($matches)) { - throw self::createInvalidArgumentException( - 1, - 'array' - ); - } - - $constraint = new LogicalNot( - new SSListContains( - $matches - ) - ); - - static::assertThat( - $list, - $constraint, - $message - ); - } - - /** - * @param $matches - * @param $dataObjectSet - * @deprecated 4.0.0:5.0.0 Use assertListNotContains() instead - * - */ - public static function assertNotDOSContains($matches, $dataObjectSet) - { - Deprecation::notice('5.0', 'Use assertListNotContains() instead'); - static::assertListNotContains($matches, $dataObjectSet); - } - - /** - * Assert that the given {@link SS_List} includes only DataObjects matching the given - * key-value pairs. Each match must correspond to 1 distinct record. - * - * Example - * -------- - * Check that *only* the entries Sam Minnee and Ingo Schommer exist in $members. Order doesn't - * matter: - * $this->assertListEquals([ - * ['FirstName' =>'Sam', 'Surname' => 'Minnee'], - * ['FirstName' => 'Ingo', 'Surname' => 'Schommer'], - * ], $members); - * - * @param mixed $matches The patterns to match. Each pattern is a map of key-value pairs. You can - * either pass a single pattern or an array of patterns. - * @param mixed $list The {@link SS_List} to test. - * @param string $message - */ - public static function assertListEquals($matches, SS_List $list, $message = '') - { - if (!is_array($matches)) { - throw self::createInvalidArgumentException( - 1, - 'array' - ); - } - - static::assertThat( - $list, - new SSListContainsOnly( - $matches - ), - $message - ); - } - - /** - * @param $matches - * @param SS_List $dataObjectSet - * @deprecated 4.0.0:5.0.0 Use assertListEquals() instead - * - */ - public function assertDOSEquals($matches, $dataObjectSet) - { - Deprecation::notice('5.0', 'Use assertListEquals() instead'); - static::assertListEquals($matches, $dataObjectSet); - } - - - /** - * Assert that the every record in the given {@link SS_List} matches the given key-value - * pairs. - * - * Example - * -------- - * Check that every entry in $members has a Status of 'Active': - * $this->assertListAllMatch(['Status' => 'Active'], $members); - * - * @param mixed $match The pattern to match. The pattern is a map of key-value pairs. - * @param mixed $list The {@link SS_List} to test. - * @param string $message - */ - public static function assertListAllMatch($match, SS_List $list, $message = '') - { - if (!is_array($match)) { - throw self::createInvalidArgumentException( - 1, - 'array' - ); - } - - static::assertThat( - $list, - new SSListContainsOnlyMatchingItems( - $match - ), - $message - ); - } - - /** - * @param $match - * @param SS_List $dataObjectSet - * @deprecated 4.0.0:5.0.0 Use assertListAllMatch() instead - * - */ - public function assertDOSAllMatch($match, SS_List $dataObjectSet) - { - Deprecation::notice('5.0', 'Use assertListAllMatch() instead'); - static::assertListAllMatch($match, $dataObjectSet); - } - - /** - * Removes sequences of repeated whitespace characters from SQL queries - * making them suitable for string comparison - * - * @param string $sql - * @return string The cleaned and normalised SQL string - */ - protected static function normaliseSQL($sql) - { - return trim(preg_replace('/\s+/m', ' ', $sql ?? '') ?? ''); - } - - /** - * Asserts that two SQL queries are equivalent - * - * @param string $expectedSQL - * @param string $actualSQL - * @param string $message - */ - public static function assertSQLEquals( - $expectedSQL, - $actualSQL, - $message = '' - ) { - // Normalise SQL queries to remove patterns of repeating whitespace - $expectedSQL = static::normaliseSQL($expectedSQL); - $actualSQL = static::normaliseSQL($actualSQL); - - static::assertEquals($expectedSQL, $actualSQL, $message); - } - - /** - * Asserts that a SQL query contains a SQL fragment - * - * @param string $needleSQL - * @param string $haystackSQL - * @param string $message - */ - public static function assertSQLContains( - $needleSQL, - $haystackSQL, - $message = '' - ) { - $needleSQL = static::normaliseSQL($needleSQL); - $haystackSQL = static::normaliseSQL($haystackSQL); - if (is_iterable($haystackSQL)) { - /** @var iterable $iterableHaystackSQL */ - $iterableHaystackSQL = $haystackSQL; - static::assertContains($needleSQL, $iterableHaystackSQL, $message); - } else { - static::assertStringContainsString($needleSQL, $haystackSQL, $message); - } - } - - /** - * Asserts that a SQL query contains a SQL fragment - * - * @param string $needleSQL - * @param string $haystackSQL - * @param string $message - */ - public static function assertSQLNotContains( - $needleSQL, - $haystackSQL, - $message = '' - ) { - $needleSQL = static::normaliseSQL($needleSQL); - $haystackSQL = static::normaliseSQL($haystackSQL); - if (is_iterable($haystackSQL)) { - /** @var iterable $iterableHaystackSQL */ - $iterableHaystackSQL = $haystackSQL; - static::assertNotContains($needleSQL, $iterableHaystackSQL, $message); - } else { - static::assertStringNotContainsString($needleSQL, $haystackSQL, $message); - } - } - - /** - * Start test environment - */ - public static function start() - { - if (static::is_running_test()) { - return; - } - - // Health check - if (InjectorLoader::inst()->countManifests()) { - throw new LogicException('SapphireTest::start() cannot be called within another application'); - } - static::set_is_running_test(true); - - // Test application - $kernel = new TestKernel(BASE_PATH); - - // PHPUnit 9 only logic to exclude old test still targeting PHPUNit 5.7 - $kernel->setIgnoredCIConfigs([Module::CI_PHPUNIT_FIVE, Module::CI_UNKNOWN]); - - if (class_exists(HTTPApplication::class)) { - // Mock request - $_SERVER['argv'] = ['vendor/bin/phpunit', '/']; - $request = CLIRequestBuilder::createFromEnvironment(); - - $app = new HTTPApplication($kernel); - $flush = array_key_exists('flush', $request->getVars() ?? []); - - // Custom application - $res = $app->execute($request, function (HTTPRequest $request) { - // Start session and execute - $request->getSession()->init($request); - - // Invalidate classname spec since the test manifest will now pull out new subclasses for each internal class - // (e.g. Member will now have various subclasses of DataObjects that implement TestOnly) - DataObject::reset(); - - // Set dummy controller; - $controller = Controller::create(); - $controller->setRequest($request); - $controller->pushCurrent(); - $controller->doInit(); - }, $flush); - - if ($res && $res->isError()) { - throw new LogicException($res->getBody()); - } - } else { - // Allow flush from the command line in the absence of HTTPApplication's special sauce - $flush = false; - foreach ($_SERVER['argv'] as $arg) { - if (preg_match('/^(--)?flush(=1)?$/', $arg ?? '')) { - $flush = true; - } - } - $kernel->boot($flush); - } - - // Register state - static::$state = SapphireTestState::singleton(); - // Register temp DB holder - static::tempDB(); - } - - /** - * Reset the testing database's schema, but only if it is active - * @param bool $includeExtraDataObjects If true, the extraDataObjects tables will also be included - * @param bool $forceCreate Force DB to be created if it doesn't exist - */ - public static function resetDBSchema($includeExtraDataObjects = false, $forceCreate = false) - { - if (!static::$tempDB) { - return; - } - - // Check if DB is active before reset - if (!static::$tempDB->isUsed()) { - if (!$forceCreate) { - return; - } - static::$tempDB->build(); - } - $extraDataObjects = $includeExtraDataObjects ? static::getExtraDataObjects() : []; - static::$tempDB->resetDBSchema((array)$extraDataObjects); - } - - /** - * A wrapper for automatically performing callbacks as a user with a specific permission - * - * @param string|array $permCode - * @param callable $callback - * @return mixed - */ - public function actWithPermission($permCode, $callback) - { - return Member::actAs($this->createMemberWithPermission($permCode), $callback); - } - - /** - * Create Member and Group objects on demand with specific permission code - * - * @param string|array $permCode - * @return Member - */ - protected function createMemberWithPermission($permCode) - { - if (is_array($permCode)) { - $permArray = $permCode; - $permCode = implode('.', $permCode); - } else { - $permArray = [$permCode]; - } - - // Check cached member - if (isset($this->cache_generatedMembers[$permCode])) { - $member = $this->cache_generatedMembers[$permCode]; - } else { - // Generate group with these permissions - $group = Group::get()->filterAny([ - 'Code' => "$permCode-group", - 'Title' => "$permCode group", - ])->first(); - if (!$group || !$group->exists()) { - $group = Group::create(); - $group->Title = "$permCode group"; - $group->write(); - } - - // Create each individual permission - foreach ($permArray as $permArrayItem) { - $permission = Permission::create(); - $permission->Code = $permArrayItem; - $permission->write(); - $group->Permissions()->add($permission); - } - - $member = Member::get()->filter([ - 'Email' => "$permCode@example.org", - ])->first(); - if (!$member) { - $member = Member::create(); - } - - $member->FirstName = $permCode; - $member->Surname = 'User'; - $member->Email = "$permCode@example.org"; - $member->write(); - $group->Members()->add($member); - - $this->cache_generatedMembers[$permCode] = $member; - } - return $member; - } - - /** - * Create a member and group with the given permission code, and log in with it. - * Returns the member ID. - * - * @param string|array $permCode Either a permission, or list of permissions - * @return int Member ID - */ - public function logInWithPermission($permCode = 'ADMIN') - { - $member = $this->createMemberWithPermission($permCode); - $this->logInAs($member); - return $member->ID; - } - - /** - * Log in as the given member - * - * @param Member|int|string $member The ID, fixture codename, or Member object of the member that you want to log in - */ - public function logInAs($member) - { - if (is_numeric($member)) { - $member = DataObject::get_by_id(Member::class, $member); - } elseif (!is_object($member)) { - $member = $this->objFromFixture(Member::class, $member); - } - Injector::inst()->get(IdentityStore::class)->logIn($member); - } - - /** - * Log out the current user - */ - public function logOut() - { - /** @var IdentityStore $store */ - $store = Injector::inst()->get(IdentityStore::class); - $store->logOut(); - } - - /** - * Cache for logInWithPermission() - */ - protected $cache_generatedMembers = []; - - /** - * Test against a theme. - * - * @param string $themeBaseDir themes directory - * @param string $theme Theme name - * @param callable $callback - * @throws Exception - */ - protected function useTestTheme($themeBaseDir, $theme, $callback) - { - Config::nest(); - if (strpos($themeBaseDir ?? '', BASE_PATH) === 0) { - $themeBaseDir = substr($themeBaseDir ?? '', strlen(BASE_PATH)); - } - SSViewer::config()->update('theme_enabled', true); - SSViewer::set_themes([$themeBaseDir . '/themes/' . $theme, '$default']); - - try { - $callback(); - } finally { - Config::unnest(); - } - } - - /** - * Get fixture paths for this test - * - * @return array List of paths - */ - protected function getFixturePaths() - { - $fixtureFile = static::get_fixture_file(); - if (empty($fixtureFile)) { - return []; - } - - $fixtureFiles = is_array($fixtureFile) ? $fixtureFile : [$fixtureFile]; - - return array_map(function ($fixtureFilePath) { - return $this->resolveFixturePath($fixtureFilePath); - }, $fixtureFiles ?? []); - } - - /** - * Return all extra objects to scaffold for this test - * @return array - */ - public static function getExtraDataObjects() - { - return static::$extra_dataobjects; - } - - /** - * Get additional controller classes to register routes for - * - * @return array - */ - public static function getExtraControllers() - { - return static::$extra_controllers; - } - - /** - * Map a fixture path to a physical file - * - * @param string $fixtureFilePath - * @return string - */ - protected function resolveFixturePath($fixtureFilePath) - { - // support loading via composer name path. - if (strpos($fixtureFilePath ?? '', ':') !== false) { - return ModuleResourceLoader::singleton()->resolvePath($fixtureFilePath); - } - - // Support fixture paths relative to the test class, rather than relative to webroot - // String checking is faster than file_exists() calls. - $resolvedPath = realpath($this->getCurrentAbsolutePath() . '/' . $fixtureFilePath); - if ($resolvedPath) { - return $resolvedPath; - } - - // Check if file exists relative to base dir - $resolvedPath = realpath(Director::baseFolder() . '/' . $fixtureFilePath); - if ($resolvedPath) { - return $resolvedPath; - } - - return $fixtureFilePath; - } - - protected function setUpRoutes() - { - if (!class_exists(Director::class)) { - return; - } - - // Get overridden routes - $rules = $this->getExtraRoutes(); - - // Add all other routes - foreach (Director::config()->uninherited('rules') as $route => $rule) { - if (!isset($rules[$route])) { - $rules[$route] = $rule; - } - } - - // Add default catch-all rule - $rules['$Controller//$Action/$ID/$OtherID'] = '*'; - - // Add controller-name auto-routing - Director::config()->set('rules', $rules); - } - - /** - * Get extra routes to merge into Director.rules - * - * @return array - */ - protected function getExtraRoutes() - { - $rules = []; - foreach ($this->getExtraControllers() as $class) { - $controllerInst = Controller::singleton($class); - $link = Director::makeRelative($controllerInst->Link()); - $route = rtrim($link ?? '', '/') . '//$Action/$ID/$OtherID'; - $rules[$route] = $class; - } - return $rules; - } - - /** - * Reimplementation of phpunit5 PHPUnit_Util_InvalidArgumentHelper::factory() - * - * @param $argument - * @param $type - * @param $value - */ - public static function createInvalidArgumentException($argument, $type, $value = null) - { - $stack = debug_backtrace(false); - - return new PHPUnitFrameworkException( - sprintf( - 'Argument #%d%sof %s::%s() must be a %s', - $argument, - $value !== null ? ' (' . gettype($value) . '#' . $value . ')' : ' (No Value) ', - $stack[1]['class'], - $stack[1]['function'], - $type - ) - ); - } - - /** - * Returns the annotations for this test. - * - * @return array - */ - public function getAnnotations(): array - { - return TestUtil::parseTestMethodAnnotations( - get_class($this), - $this->getName(false) - ); - } - - /** - * Test safe version of sleep() - * - * @param int $seconds - * @return DBDatetime - * @throws Exception - */ - protected function mockSleep(int $seconds): DBDatetime - { - $now = DBDatetime::now(); - $now->modify(sprintf('+ %d seconds', $seconds)); - DBDatetime::set_mock_now($now); - - return $now; - } - } -} - -/* ------------------------------------------------- - * - * This version of SapphireTest is for phpunit 5 - * The phpunit 9 version is at the top of this file - * - * PHPUnit_Extensions_GroupTestSuite is a class that only exists in phpunit 5 - * - * ------------------------------------------------- - */ -if (!class_exists(PHPUnit_Extensions_GroupTestSuite::class)) { - return; -} - /** - * Test case class for the Sapphire framework. + * Test case class for the Silverstripe framework. * Sapphire unit testing is based on PHPUnit, but provides a number of hooks into our data model that make it easier * to work with. * * This class should not be used anywhere outside of unit tests, as phpunit may not be installed * in production sites. */ -// Ignore multiple classes in same file -// @codingStandardsIgnoreStart -class SapphireTest extends PHPUnit_Framework_TestCase implements TestOnly +class SapphireTest extends TestCase implements TestOnly { - // @codingStandardsIgnoreEnd - /** * Path to fixture data for this test run. * If passed as an array, multiple fixture files will be loaded. @@ -1617,7 +262,7 @@ class SapphireTest extends PHPUnit_Framework_TestCase implements TestOnly * * User code should call parent::setUp() before custom setup code */ - protected function setUp() + protected function setUp(): void { if (!defined('FRAMEWORK_PATH')) { trigger_error( @@ -1632,7 +277,6 @@ class SapphireTest extends PHPUnit_Framework_TestCase implements TestOnly // We cannot run the tests on this abstract class. if (static::class == __CLASS__) { $this->markTestSkipped(sprintf('Skipping %s ', static::class)); - return; } // i18n needs to be set to the defaults or tests fail @@ -1751,7 +395,7 @@ class SapphireTest extends PHPUnit_Framework_TestCase implements TestOnly * * @throws Exception */ - public static function setUpBeforeClass() + public static function setUpBeforeClass(): void { // Start tests static::start(); @@ -1780,7 +424,7 @@ class SapphireTest extends PHPUnit_Framework_TestCase implements TestOnly * * User code should call parent::tearDownAfterClass() after custom tear down code */ - public static function tearDownAfterClass() + public static function tearDownAfterClass(): void { // Call state helpers static::$state->tearDownOnce(static::class); @@ -1943,7 +587,7 @@ class SapphireTest extends PHPUnit_Framework_TestCase implements TestOnly * * User code should call parent::tearDown() after custom tear down code */ - protected function tearDown() + protected function tearDown(): void { // Reset mocked datetime if (class_exists(DBDatetime::class)) { @@ -1965,34 +609,6 @@ class SapphireTest extends PHPUnit_Framework_TestCase implements TestOnly static::$state->tearDown($this); } - public static function assertContains( - $needle, - $haystack, - $message = '', - $ignoreCase = false, - $checkForObjectIdentity = true, - $checkForNonObjectIdentity = false - ) { - if ($haystack instanceof DBField) { - $haystack = (string)$haystack; - } - parent::assertContains($needle, $haystack, $message, $ignoreCase, $checkForObjectIdentity, $checkForNonObjectIdentity); - } - - public static function assertNotContains( - $needle, - $haystack, - $message = '', - $ignoreCase = false, - $checkForObjectIdentity = true, - $checkForNonObjectIdentity = false - ) { - if ($haystack instanceof DBField) { - $haystack = (string)$haystack; - } - parent::assertNotContains($needle, $haystack, $message, $ignoreCase, $checkForObjectIdentity, $checkForNonObjectIdentity); - } - /** * Clear the log of emails sent * @@ -2066,6 +682,7 @@ class SapphireTest extends PHPUnit_Framework_TestCase implements TestOnly ); } + /** * Assert that the given {@link SS_List} includes DataObjects matching the given key-value * pairs. Each match must correspond to 1 distinct record. @@ -2090,7 +707,7 @@ class SapphireTest extends PHPUnit_Framework_TestCase implements TestOnly public static function assertListContains($matches, SS_List $list, $message = '') { if (!is_array($matches)) { - throw PHPUnit_Util_InvalidArgumentHelper::factory( + throw self::createInvalidArgumentException( 1, 'array' ); @@ -2114,7 +731,7 @@ class SapphireTest extends PHPUnit_Framework_TestCase implements TestOnly public function assertDOSContains($matches, $dataObjectSet) { Deprecation::notice('5.0', 'Use assertListContains() instead'); - return static::assertListContains($matches, $dataObjectSet); + static::assertListContains($matches, $dataObjectSet); } /** @@ -2140,13 +757,13 @@ class SapphireTest extends PHPUnit_Framework_TestCase implements TestOnly public static function assertListNotContains($matches, SS_List $list, $message = '') { if (!is_array($matches)) { - throw PHPUnit_Util_InvalidArgumentHelper::factory( + throw self::createInvalidArgumentException( 1, 'array' ); } - $constraint = new PHPUnit_Framework_Constraint_Not( + $constraint = new LogicalNot( new SSListContains( $matches ) @@ -2168,7 +785,7 @@ class SapphireTest extends PHPUnit_Framework_TestCase implements TestOnly public static function assertNotDOSContains($matches, $dataObjectSet) { Deprecation::notice('5.0', 'Use assertListNotContains() instead'); - return static::assertListNotContains($matches, $dataObjectSet); + static::assertListNotContains($matches, $dataObjectSet); } /** @@ -2192,7 +809,7 @@ class SapphireTest extends PHPUnit_Framework_TestCase implements TestOnly public static function assertListEquals($matches, SS_List $list, $message = '') { if (!is_array($matches)) { - throw PHPUnit_Util_InvalidArgumentHelper::factory( + throw self::createInvalidArgumentException( 1, 'array' ); @@ -2216,9 +833,10 @@ class SapphireTest extends PHPUnit_Framework_TestCase implements TestOnly public function assertDOSEquals($matches, $dataObjectSet) { Deprecation::notice('5.0', 'Use assertListEquals() instead'); - return static::assertListEquals($matches, $dataObjectSet); + static::assertListEquals($matches, $dataObjectSet); } + /** * Assert that the every record in the given {@link SS_List} matches the given key-value * pairs. @@ -2235,7 +853,7 @@ class SapphireTest extends PHPUnit_Framework_TestCase implements TestOnly public static function assertListAllMatch($match, SS_List $list, $message = '') { if (!is_array($match)) { - throw PHPUnit_Util_InvalidArgumentHelper::factory( + throw self::createInvalidArgumentException( 1, 'array' ); @@ -2259,7 +877,7 @@ class SapphireTest extends PHPUnit_Framework_TestCase implements TestOnly public function assertDOSAllMatch($match, SS_List $dataObjectSet) { Deprecation::notice('5.0', 'Use assertListAllMatch() instead'); - return static::assertListAllMatch($match, $dataObjectSet); + static::assertListAllMatch($match, $dataObjectSet); } /** @@ -2280,25 +898,17 @@ class SapphireTest extends PHPUnit_Framework_TestCase implements TestOnly * @param string $expectedSQL * @param string $actualSQL * @param string $message - * @param float|int $delta - * @param integer $maxDepth - * @param boolean $canonicalize - * @param boolean $ignoreCase */ public static function assertSQLEquals( $expectedSQL, $actualSQL, - $message = '', - $delta = 0, - $maxDepth = 10, - $canonicalize = false, - $ignoreCase = false + $message = '' ) { // Normalise SQL queries to remove patterns of repeating whitespace $expectedSQL = static::normaliseSQL($expectedSQL); $actualSQL = static::normaliseSQL($actualSQL); - static::assertEquals($expectedSQL, $actualSQL, $message, $delta, $maxDepth, $canonicalize, $ignoreCase); + static::assertEquals($expectedSQL, $actualSQL, $message); } /** @@ -2307,20 +917,21 @@ class SapphireTest extends PHPUnit_Framework_TestCase implements TestOnly * @param string $needleSQL * @param string $haystackSQL * @param string $message - * @param boolean $ignoreCase - * @param boolean $checkForObjectIdentity */ public static function assertSQLContains( $needleSQL, $haystackSQL, - $message = '', - $ignoreCase = false, - $checkForObjectIdentity = true + $message = '' ) { $needleSQL = static::normaliseSQL($needleSQL); $haystackSQL = static::normaliseSQL($haystackSQL); - - static::assertContains($needleSQL, $haystackSQL, $message, $ignoreCase, $checkForObjectIdentity); + if (is_iterable($haystackSQL)) { + /** @var iterable $iterableHaystackSQL */ + $iterableHaystackSQL = $haystackSQL; + static::assertContains($needleSQL, $iterableHaystackSQL, $message); + } else { + static::assertStringContainsString($needleSQL, $haystackSQL, $message); + } } /** @@ -2329,20 +940,21 @@ class SapphireTest extends PHPUnit_Framework_TestCase implements TestOnly * @param string $needleSQL * @param string $haystackSQL * @param string $message - * @param boolean $ignoreCase - * @param boolean $checkForObjectIdentity */ public static function assertSQLNotContains( $needleSQL, $haystackSQL, - $message = '', - $ignoreCase = false, - $checkForObjectIdentity = true + $message = '' ) { $needleSQL = static::normaliseSQL($needleSQL); $haystackSQL = static::normaliseSQL($haystackSQL); - - static::assertNotContains($needleSQL, $haystackSQL, $message, $ignoreCase, $checkForObjectIdentity); + if (is_iterable($haystackSQL)) { + /** @var iterable $iterableHaystackSQL */ + $iterableHaystackSQL = $haystackSQL; + static::assertNotContains($needleSQL, $iterableHaystackSQL, $message); + } else { + static::assertStringNotContainsString($needleSQL, $haystackSQL, $message); + } } /** @@ -2672,6 +1284,42 @@ class SapphireTest extends PHPUnit_Framework_TestCase implements TestOnly return $rules; } + /** + * Reimplementation of phpunit5 PHPUnit_Util_InvalidArgumentHelper::factory() + * + * @param $argument + * @param $type + * @param $value + */ + public static function createInvalidArgumentException($argument, $type, $value = null) + { + $stack = debug_backtrace(false); + + return new PHPUnitFrameworkException( + sprintf( + 'Argument #%d%sof %s::%s() must be a %s', + $argument, + $value !== null ? ' (' . gettype($value) . '#' . $value . ')' : ' (No Value) ', + $stack[1]['class'], + $stack[1]['function'], + $type + ) + ); + } + + /** + * Returns the annotations for this test. + * + * @return array + */ + public function getAnnotations(): array + { + return TestUtil::parseTestMethodAnnotations( + get_class($this), + $this->getName(false) + ); + } + /** * Test safe version of sleep() * diff --git a/src/Dev/TestKernel.php b/src/Dev/TestKernel.php index 3b4f9541d..67229f5ca 100644 --- a/src/Dev/TestKernel.php +++ b/src/Dev/TestKernel.php @@ -9,11 +9,6 @@ use SilverStripe\Core\CoreKernel; */ class TestKernel extends CoreKernel { - - /** @var string[] $ciConfigs */ - private $ciConfigs = []; - - public function __construct($basePath) { $this->setEnvironment(self::DEV); @@ -46,22 +41,6 @@ class TestKernel extends CoreKernel return true; } - - /** - * Set a list of CI configurations that should cause a module's test not to be added to a manifest - * @param string[] $ciConfigs - */ - public function setIgnoredCIConfigs(array $ciConfigs): self - { - $this->ciConfigs = $ciConfigs; - return $this; - } - - protected function getIgnoredCIConfigs(): array - { - return $this->ciConfigs; - } - protected function bootErrorHandling() { // Leave phpunit to capture errors diff --git a/src/View/ThemeManifest.php b/src/View/ThemeManifest.php index c6e3e7dbc..ff1b8d85c 100644 --- a/src/View/ThemeManifest.php +++ b/src/View/ThemeManifest.php @@ -73,9 +73,8 @@ class ThemeManifest implements ThemeList /** * @param bool $includeTests Include tests in the manifest * @param bool $forceRegen Force the manifest to be regenerated. - * @param string[] $ignoredCIConfigs */ - public function init($includeTests = false, $forceRegen = false, array $ignoredCIConfigs = []) + public function init($includeTests = false, $forceRegen = false) { // build cache from factory if ($this->cacheFactory) { @@ -88,7 +87,7 @@ class ThemeManifest implements ThemeList if (!$forceRegen && $this->cache && ($data = $this->cache->get($this->cacheKey))) { $this->themes = $data; } else { - $this->regenerate($includeTests, $ignoredCIConfigs); + $this->regenerate($includeTests); } } @@ -130,16 +129,14 @@ class ThemeManifest implements ThemeList * Regenerates the manifest by scanning the base path. * * @param bool $includeTests - * @param string[] $ignoredCIConfigs */ - public function regenerate($includeTests = false, array $ignoredCIConfigs = []) + public function regenerate($includeTests = false) { $finder = new ManifestFileFinder(); $finder->setOptions([ 'include_themes' => false, 'ignore_dirs' => ['node_modules', THEMES_DIR], 'ignore_tests' => !$includeTests, - 'ignored_ci_configs' => $ignoredCIConfigs, 'dir_callback' => [$this, 'handleDirectory'] ]); diff --git a/tests/php/Core/Manifest/ManifestFileFinderTest.php b/tests/php/Core/Manifest/ManifestFileFinderTest.php index f39a1bbc1..7c0909b10 100644 --- a/tests/php/Core/Manifest/ManifestFileFinderTest.php +++ b/tests/php/Core/Manifest/ManifestFileFinderTest.php @@ -4,7 +4,6 @@ namespace SilverStripe\Core\Tests\Manifest; use SilverStripe\Core\Manifest\ManifestFileFinder; use SilverStripe\Dev\SapphireTest; -use SilverStripe\Core\Manifest\Module; /** * Tests for the {@link ManifestFileFinder} class. @@ -56,8 +55,6 @@ class ManifestFileFinderTest extends SapphireTest [ 'module/module.txt', 'vendor/myvendor/thismodule/module.txt', - 'vendor/myvendor/phpunit5module/code/logic.txt', - 'vendor/myvendor/phpunit9module/code/logic.txt', ] ); } @@ -78,56 +75,6 @@ class ManifestFileFinderTest extends SapphireTest 'vendor/myvendor/thismodule/module.txt', 'vendor/myvendor/thismodule/tests/tests.txt', 'vendor/myvendor/thismodule/code/tests/tests2.txt', - 'vendor/myvendor/phpunit5module/code/logic.txt', - 'vendor/myvendor/phpunit5module/tests/phpunit5tests.txt', - 'vendor/myvendor/phpunit9module/code/logic.txt', - 'vendor/myvendor/phpunit9module/tests/phpunit9tests.txt', - ] - ); - } - - public function testIgnorePHPUnit5Tests() - { - $finder = new ManifestFileFinder(); - $finder->setOption('name_regex', '/\.txt$/'); - $finder->setOption('ignore_tests', false); - $finder->setOption('ignored_ci_configs', [Module::CI_PHPUNIT_FIVE]); - - $this->assertFinderFinds( - $finder, - null, - [ - 'module/module.txt', - 'module/tests/tests.txt', - 'module/code/tests/tests2.txt', - 'vendor/myvendor/thismodule/module.txt', - 'vendor/myvendor/thismodule/tests/tests.txt', - 'vendor/myvendor/thismodule/code/tests/tests2.txt', - 'vendor/myvendor/phpunit5module/code/logic.txt', - 'vendor/myvendor/phpunit9module/code/logic.txt', - 'vendor/myvendor/phpunit9module/tests/phpunit9tests.txt', - ] - ); - } - - public function testIgnoreNonePHPUnit9Tests() - { - $finder = new ManifestFileFinder(); - $finder->setOption('name_regex', '/\.txt$/'); - $finder->setOption('ignore_tests', false); - $finder->setOption('ignored_ci_configs', [Module::CI_PHPUNIT_FIVE, Module::CI_UNKNOWN]); - - $this->assertFinderFinds( - $finder, - null, - [ - 'module/module.txt', - 'module/tests/tests.txt', - 'module/code/tests/tests2.txt', - 'vendor/myvendor/thismodule/module.txt', - 'vendor/myvendor/phpunit5module/code/logic.txt', - 'vendor/myvendor/phpunit9module/code/logic.txt', - 'vendor/myvendor/phpunit9module/tests/phpunit9tests.txt', ] ); } @@ -145,8 +92,6 @@ class ManifestFileFinderTest extends SapphireTest 'module/module.txt', 'themes/themes.txt', 'vendor/myvendor/thismodule/module.txt', - 'vendor/myvendor/phpunit5module/code/logic.txt', - 'vendor/myvendor/phpunit9module/code/logic.txt', ] ); } diff --git a/tests/php/Core/Manifest/ModuleTest.php b/tests/php/Core/Manifest/ModuleTest.php index f4ea2db5a..b62a28941 100644 --- a/tests/php/Core/Manifest/ModuleTest.php +++ b/tests/php/Core/Manifest/ModuleTest.php @@ -21,53 +21,4 @@ class ModuleTest extends SapphireTest $module = new Module($path, $path); $this->assertEquals('customised-resources-dir', $module->getResourcesDir()); } - - /** - * @dataProvider ciConfigProvider - * @param string $fixture The folder containing our test composer file - * @param string $expectedPhpConfig - */ - public function testGetCIConfig($fixture, $expectedPhpConfig) - { - $path = __DIR__ . '/fixtures/phpunit-detection/' . $fixture; - $module = new Module($path, $path); - $this->assertEquals( - $expectedPhpConfig, - $module->getCIConfig()['PHP'], - 'PHP config is set to ' . $expectedPhpConfig - ); - } - - public function ciConfigProvider() - { - return [ - 'empty require-dev' => ['empty-require-dev', Module::CI_UNKNOWN], - 'no require-dev' => ['no-require-dev', Module::CI_UNKNOWN], - 'older version of phpunit' => ['old-phpunit', Module::CI_UNKNOWN], - 'phpunit between 5 and 9' => ['inbetween-phpunit', Module::CI_UNKNOWN], - 'phpunit beyond 9' => ['future-phpunit', Module::CI_UNKNOWN], - - 'phpunit 5.0' => ['phpunit-five-zero', Module::CI_PHPUNIT_FIVE], - 'phpunit 5.7' => ['phpunit-five-seven', Module::CI_PHPUNIT_FIVE], - 'phpunit 5 exact version' => ['phpunit-five-exact-version', Module::CI_PHPUNIT_FIVE], - 'phpunit 5 tilde' => ['phpunit-five-tilde', Module::CI_PHPUNIT_FIVE], - 'sminnee 5.7' => ['sminnee-five-seven', Module::CI_PHPUNIT_FIVE], - 'sminnee 5' => ['sminnee-five-seven', Module::CI_PHPUNIT_FIVE], - 'sminnee 5 star' => ['sminnee-five-star', Module::CI_PHPUNIT_FIVE], - - 'phpunit 9' => ['phpunit-nine', Module::CI_PHPUNIT_NINE], - 'phpunit 9.5' => ['phpunit-nine-five', Module::CI_PHPUNIT_NINE], - 'future phpunit 9' => ['phpunit-nine-x', Module::CI_PHPUNIT_NINE], - 'phpunit 9 exact version' => ['phpunit-nine-exact', Module::CI_PHPUNIT_NINE], - - 'recipe-testing 1' => ['recipe-testing-one', Module::CI_PHPUNIT_FIVE], - 'recipe-testing 1.x' => ['recipe-testing-one-x', Module::CI_PHPUNIT_FIVE], - 'recipe-testing 1.2.x' => ['recipe-testing-one-two-x', Module::CI_PHPUNIT_FIVE], - 'recipe-testing 1 with stability flag' => ['recipe-testing-one-flag', Module::CI_PHPUNIT_FIVE], - - 'recipe-testing 2' => ['recipe-testing-two', Module::CI_PHPUNIT_NINE], - 'recipe-testing 2.x' => ['recipe-testing-two-x', Module::CI_PHPUNIT_NINE], - 'recipe-testing 2 exact' => ['recipe-testing-two-x', Module::CI_PHPUNIT_NINE], - ]; - } } diff --git a/tests/php/Core/Manifest/fixtures/manifestfilefinder/vendor/myvendor/phpunit5module/_config.php b/tests/php/Core/Manifest/fixtures/manifestfilefinder/vendor/myvendor/phpunit5module/_config.php deleted file mode 100644 index b3d9bbc7f..000000000 --- a/tests/php/Core/Manifest/fixtures/manifestfilefinder/vendor/myvendor/phpunit5module/_config.php +++ /dev/null @@ -1 +0,0 @@ -