From 5f43e149d2b4e5ad5b56e6d358538b456849a281 Mon Sep 17 00:00:00 2001 From: Luca Tumedei Date: Sat, 25 Nov 2023 14:16:57 +0100 Subject: [PATCH] feat(WPLoader) add global state control support, fix #673 --- CHANGELOG.md | 4 + docs/modules/WPLoader.md | 68 +++ src/Module/WPLoader.php | 71 ++- src/TestCase/WPTestCase.php | 60 ++- tests/_data/files/BackupControlTestCase.php | 60 +++ ...ackupControlTestCaseOverridingTestCase.php | 33 ++ .../_generated/WploaderTesterActions.php | 2 +- .../WPBrowser/Events/Module/WPLoaderTest.php | 439 ++++++++++++++++++ 8 files changed, 731 insertions(+), 6 deletions(-) create mode 100644 tests/_data/files/BackupControlTestCase.php create mode 100644 tests/_data/files/BackupControlTestCaseOverridingTestCase.php diff --git a/CHANGELOG.md b/CHANGELOG.md index eeb16926f..5eb7e483c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,10 @@ This project adheres to [Semantic Versioning](http://semver.org/). ## [unreleased] Unreleased +### Added + +- Added the `backupGlobals`, `backupGlobalsExcludeList`, `backupStaticAttributes`, `backupStaticAttributesExcludeList` to the `WPLoader` module configuration file to provide a sweeping control over the state snapshot of test cases extending the `WPTestCase` class. Test cases overriding those properties explicitly will have their values respected. + ## [4.0.11] 2023-11-24; ### Fixed diff --git a/docs/modules/WPLoader.md b/docs/modules/WPLoader.md index 2703dce18..a92cf1d0a 100644 --- a/docs/modules/WPLoader.md +++ b/docs/modules/WPLoader.md @@ -82,6 +82,10 @@ When used in this mode, the module supports the following configuration paramete * `WP_HTTP_BLOCK_EXTERNAL` - the `WP_HTTP_BLOCK_EXTERNAL` constant value to use when loading WordPress. If the `wpRootFolder` path points at a configured installation, containing the `wp-config.php` file, then the value of the constant in the configuration file will be used, else it will be randomly generated. +* `backupGlobals` - a boolean value to indicate if the global environment should be backed up before each test. Defaults to `true`. The globals' backup involves serialization of the global state, plugins or themes that define classes developed to prevent serialization of the global state will cause the tests to fail. Set this parameter to `false` to disable the global environment backup, or use a more refined approach setting the `backupGlobalsExcludeList` parameter below. Note that a test case that is explicitly setting the `backupGlobals` property will override this configuration parameter. +* `backupGlobalsExcludeList` - a list of global variables to exclude from the global environment backup. The list must be in the form of array, and it will be merged to the list of globals excluded by default. +* `backupStaticAttributes` - a boolean value to indicate if static attributes of classes should be backed up before each test. Defaults to `true`. The static attributes' backup involves serialization of the global state, plugins or themes that define classes developed to prevent serialization of the global state will cause the tests to fail. Set this parameter to `false` to disable the static attributes backup, or use a more refined approanch setting the `backupStaticAttributesExcludeList` parameter below. Note that a test case that is explicitly setting the `backupStaticAttributes` property will override this configuration parameter. +* `backupStaticAttributesExcludeList` - a list of classes to exclude from the static attributes backup. The list must be in the form of map from class names to the array of method names to exclude from the backup. See an example below. This is an example of an integration suite configured to use the module: @@ -153,6 +157,70 @@ modules: theme: twentytwentythree ``` +The follow example configuration prevents the backup of globals and static attributes in all the tests of the suite that are not explicitly overriding the `backupGlobals` and `backupStaticAttributes` properties: + +```yaml +actor: IntegrationTester +bootstrap: _bootstrap.php +modules: + enabled: + - \Helper\Integration + - lucatume\WPBrowser\Module\WPLoader: + wpRootFolder: /var/wordpress + dbUrl: sqlite:///var/wordpress/wp-tests.sqlite + dump: + - tests/_data/products.sql + - tests/_data/users.sql + - tests/_data/orders.sql + tablePrefix: test_ + domain: wordpress.test + adminEmail: admin@wordpress.test + title: 'Integration Tests' + plugins: + - hello.php + - woocommerce/woocommerce.php + - my-plugin/my-plugin.php + theme: twentytwentythree + backupGlobals: false + backupStaticAttributes: false +``` + +The following configuration prevents the backup of *some* globals and static attributes: + +```yaml +actor: IntegrationTester +bootstrap: _bootstrap.php +modules: + enabled: + - \Helper\Integration + - lucatume\WPBrowser\Module\WPLoader: + wpRootFolder: /var/wordpress + dbUrl: sqlite:///var/wordpress/wp-tests.sqlite + dump: + - tests/_data/products.sql + - tests/_data/users.sql + - tests/_data/orders.sql + tablePrefix: test_ + domain: wordpress.test + adminEmail: admin@wordpress.test + title: 'Integration Tests' + plugins: + - hello.php + - woocommerce/woocommerce.php + - my-plugin/my-plugin.php + theme: twentytwentythree + backupGlobalsExcludeList: + - my_plugin_will_explode_on_wakeup + - another_problematic_global + backupStaticAttributesExcludeList: + - MyPlugin\MyClass: + - instance + - anotherStaticAttributeThatWillExplodeOnWakeup + - AnotherPlugin\AnotherClass: + - instance + - yetAnotherStaticAttributeThatWillExplodeOnWakeup +``` + ### Handling a custom site structure If you're working on a site project using a custom file structure, e.g. [Bedrock][4], you should diff --git a/src/Module/WPLoader.php b/src/Module/WPLoader.php index 76c69e1bd..e02543c34 100644 --- a/src/Module/WPLoader.php +++ b/src/Module/WPLoader.php @@ -19,6 +19,7 @@ use lucatume\WPBrowser\Process\Loop; use lucatume\WPBrowser\Process\ProcessException; use lucatume\WPBrowser\Process\WorkerException; +use lucatume\WPBrowser\Utils\Arr; use lucatume\WPBrowser\Utils\CorePHPUnit; use lucatume\WPBrowser\Utils\Db as DbUtils; use lucatume\WPBrowser\Utils\Filesystem as FS; @@ -118,7 +119,11 @@ class WPLoader extends Module * WP_PLUGIN_DIR?: ?string, * WPMU_PLUGIN_DIR?: ?string, * dump: string|string[], - * dbUrl?: string + * dbUrl?: string, + * backupGlobals?: bool, + * backupGlobalsExcludeList?: string[], + * backupStaticAttributes?: bool, + * backupStaticAttributesExcludeList?: array, * } */ protected array $config = [ @@ -150,7 +155,11 @@ class WPLoader extends Module 'WP_CONTENT_DIR' => null, 'WP_PLUGIN_DIR' => null, 'WPMU_PLUGIN_DIR' => null, - 'dump' => '' + 'dump' => '', + 'backupGlobals' => true, + 'backupGlobalsExcludeList' => [], + 'backupStaticAttributes' => true, + 'backupStaticAttributesExcludeList' => [], ]; private string $wpBootstrapFile; @@ -220,6 +229,48 @@ protected function validateConfig(): void } } + if (isset($this->config['backupGlobals']) && !is_bool($this->config['backupGlobals'])) { + throw new ModuleConfigException( + __CLASS__, + 'The `backupGlobals` configuration parameter must be a boolean.' + ); + } + + if (isset($this->config['backupGlobalsExcludeList']) + && !( + is_array($this->config['backupGlobalsExcludeList']) + && Arr::containsOnly($this->config['backupGlobalsExcludeList'], 'string') + ) + ) { + throw new ModuleConfigException( + __CLASS__, + 'The `backupGlobalsExcludeList` configuration parameter an array of strings.' + ); + } + + if (isset($this->config['backupStaticAttributes']) && !is_bool($this->config['backupStaticAttributes'])) { + throw new ModuleConfigException( + __CLASS__, + 'The `backupStaticAttributes` configuration parameter must be a boolean.' + ); + } + + if (isset($this->config['backupStaticAttributesExcludeList']) + && !( + is_array($this->config['backupStaticAttributesExcludeList']) + && Arr::isAssociative($this->config['backupStaticAttributesExcludeList']) + && Arr::containsOnly( + $this->config['backupStaticAttributesExcludeList'], + static fn($v) => Arr::containsOnly($v, 'string') + ) + ) + ) { + throw new ModuleConfigException( + __CLASS__, + 'The `backupStaticAttributesExcludeList` configuration parameter an array of strings.' + ); + } + parent::validateConfig(); } @@ -274,11 +325,22 @@ public function _initialize(): void * tablePrefix: string, * WP_CONTENT_DIR?: string, * WP_PLUGIN_DIR?: string, - * WPMU_PLUGIN_DIR?: string + * WPMU_PLUGIN_DIR?: string, + * backupGlobals: bool, + * backupGlobalsExcludeList: string[], + * backupStaticAttributes: bool, + * backupStaticAttributesExcludeList: array, * } $config */ $config = $this->config; try { + global $_wpTestsBackupGlobals, $_wpTestsBackupGlobalsExcludeList, + $_wpTestsBackupStaticAttributes, $_wpTestsBackupStaticAttributesExcludeList; + $_wpTestsBackupGlobals = (bool)$config['backupGlobals']; + $_wpTestsBackupGlobalsExcludeList = (array)$config['backupGlobalsExcludeList']; + $_wpTestsBackupStaticAttributes = (bool)$config['backupStaticAttributes']; + $_wpTestsBackupStaticAttributesExcludeList = (array)$config['backupStaticAttributesExcludeList']; + if (empty($config['dbHost']) && str_starts_with($config['dbName'], codecept_root_dir())) { $dbFile = (array_reverse(explode(DIRECTORY_SEPARATOR, $config['dbName']))[0]); $dbDir = rtrim(str_replace($dbFile, '', $config['dbName']), DIRECTORY_SEPARATOR); @@ -324,7 +386,8 @@ public function _initialize(): void $this->installation->getSalts() : []; - foreach ([ + foreach ( + [ 'AUTH_KEY', 'SECURE_AUTH_KEY', 'LOGGED_IN_KEY', diff --git a/src/TestCase/WPTestCase.php b/src/TestCase/WPTestCase.php index 7b15e7e68..9252cc33c 100644 --- a/src/TestCase/WPTestCase.php +++ b/src/TestCase/WPTestCase.php @@ -3,6 +3,7 @@ namespace lucatume\WPBrowser\TestCase; use Codeception\Test\Unit; +use lucatume\WPBrowser\Module\WPLoader; use lucatume\WPBrowser\Module\WPQueries; use ReflectionException; use ReflectionMethod; @@ -39,7 +40,12 @@ class WPTestCase extends Unit // WooCommerce. 'woocommerce', // Additional globals. - '_wp_registered_theme_features' + '_wp_registered_theme_features', + // wp-browser + '_wpTestsBackupGlobals', + '_wpTestsBackupGlobalsExcludeList', + '_wpTestsBackupStaticAttributes', + '_wpTestsBackupStaticAttributesExcludeList' ]; // Backup, and reset, static class attributes between tests. @@ -60,6 +66,58 @@ class WPTestCase extends Unit 'Automattic\WooCommerce\RestApi\Server' => ['instance'] ]; + public function __construct(?string $name = null, array $data = [], $dataName = '') + { + global $_wpTestsBackupGlobals, + $_wpTestsBackupGlobalsExcludeList, + $_wpTestsBackupStaticAttributes, + $_wpTestsBackupStaticAttributesExcludeList; + + $backupGlobalsReflectionProperty = new \ReflectionProperty($this, 'backupGlobals'); + $isDefinedInThis = $backupGlobalsReflectionProperty->getDeclaringClass()->getName() !== WPTestCase::class; + if (!$isDefinedInThis && isset($_wpTestsBackupGlobals) && is_bool($_wpTestsBackupGlobals)) { + $this->backupGlobals = $_wpTestsBackupGlobals; + } + + $backupGlobalsExcludeListReflectionProperty = new \ReflectionProperty($this, 'backupGlobalsExcludeList'); + $isDefinedInThis = $backupGlobalsExcludeListReflectionProperty->getDeclaringClass() + ->getName() !== WPTestCase::class; + if (!$isDefinedInThis + && isset($_wpTestsBackupGlobalsExcludeList) + && is_array($_wpTestsBackupGlobalsExcludeList) + ) { + $this->backupGlobalsExcludeList = array_merge( + $this->backupGlobalsExcludeList, + $_wpTestsBackupGlobalsExcludeList + ); + } + + $backupStaticAttributesReflectionProperty = new \ReflectionProperty($this, 'backupStaticAttributes'); + $isDefinedInThis = $backupStaticAttributesReflectionProperty->getDeclaringClass() + ->getName() !== WPTestCase::class; + if (!$isDefinedInThis && isset($_wpTestsBackupStaticAttributes) && is_bool($_wpTestsBackupStaticAttributes)) { + $this->backupStaticAttributes = $_wpTestsBackupStaticAttributes; + } + + $backupStaticAttributesExcludeListReflectionProperty = new \ReflectionProperty( + $this, + 'backupStaticAttributesExcludeList' + ); + $isDefinedInThis = $backupStaticAttributesExcludeListReflectionProperty->getDeclaringClass() + ->getName() !== WPTestCase::class; + if (!$isDefinedInThis + && isset($_wpTestsBackupStaticAttributesExcludeList) + && is_array($_wpTestsBackupStaticAttributesExcludeList) + ) { + $this->backupStaticAttributesExcludeList = array_merge_recursive( + $this->backupStaticAttributesExcludeList, + $_wpTestsBackupStaticAttributesExcludeList + ); + } + + parent::__construct($name, $data, $dataName); + } + /** * @var array */ diff --git a/tests/_data/files/BackupControlTestCase.php b/tests/_data/files/BackupControlTestCase.php new file mode 100644 index 000000000..975f8a0f3 --- /dev/null +++ b/tests/_data/files/BackupControlTestCase.php @@ -0,0 +1,60 @@ +_before(); + } + + public function testBackupGlobalsIsFalse(): void + { + $this->assertFalse($this->backupGlobals); + } + + public function testBackupGlobalsIsTrue(): void + { + $this->assertTrue($this->backupGlobals); + } + + public function testWillUpdateTheValueOfGlobalVar(): void + { + global $_wpbrowser_test_global_var; + $_wpbrowser_test_global_var = 'updated_value'; + $this->assertTrue(true); // Useless assertion to avoid the test to be marked as risky. + } + + public function testWillAlterStoreStaticAttribute(): void + { + BackupControlTestCaseStore::$staticAttribute = 'updated_value'; + BackupControlTestCaseStore::$staticAttributeTwo = 'updated_value'; + BackupControlTestCaseStore::$staticAttributeThree = 'updated_value'; + BackupControlTestCaseStore::$staticAttributeFour = 'updated_value'; + BackupControlTestCaseStoreTwo::$staticAttribute = 'updated_value'; + BackupControlTestCaseStoreTwo::$staticAttributeTwo = 'updated_value'; + BackupControlTestCaseStoreTwo::$staticAttributeThree = 'updated_value'; + BackupControlTestCaseStoreTwo::$staticAttributeFour = 'updated_value'; + $this->assertTrue(true); // Useless assertion to avoid the test to be marked as risky. + } +} diff --git a/tests/_data/files/BackupControlTestCaseOverridingTestCase.php b/tests/_data/files/BackupControlTestCaseOverridingTestCase.php new file mode 100644 index 000000000..14fce350f --- /dev/null +++ b/tests/_data/files/BackupControlTestCaseOverridingTestCase.php @@ -0,0 +1,33 @@ +_before(); + } + + public function testBackupGlobalsIsFalse(): void + { + $this->assertFalse($this->backupGlobals); + } + + public function testWillAlterStoreStaticAttribute(): void + { + BackupControlTestCaseOverridingStore::$staticAttribute = 'updated_value'; + $this->assertTrue(true); // Useless assertion to avoid the test to be marked as risky. + } +} diff --git a/tests/_support/_generated/WploaderTesterActions.php b/tests/_support/_generated/WploaderTesterActions.php index 184a84a10..9c489023a 100644 --- a/tests/_support/_generated/WploaderTesterActions.php +++ b/tests/_support/_generated/WploaderTesterActions.php @@ -1,4 +1,4 @@ -drop(); + $installation->configure($db); + $installation->install( + 'https://wp.local', + 'admin', + 'password', + 'admin@wp.local', + 'Test' + ); + $testcaseFile = codecept_data_dir('files/BackupControlTestCase.php'); + $overridingTestCaseFile = codecept_data_dir('files/BackupControlTestCaseOverridingTestCase.php'); + + // Set`WPLoader.backupGlobals` to `false`. + $this->config = [ + 'wpRootFolder' => $wpRootDir, + 'dbUrl' => $db->getDbUrl(), + 'backupGlobals' => false, + ]; + $wpLoader = $this->module(); + + $this->assertInIsolation(static function () use ($wpLoader, $testcaseFile) { + $wpLoader->_initialize(); + + Assert::assertTrue(function_exists('do_action')); + + require_once $testcaseFile; + + $testCase = new \BackupControlTestCase('testBackupGlobalsIsFalse'); + /** @var TestResult $result */ + $result = $testCase->run(); + + Assert::assertTrue($result->wasSuccessful()); + }); + + // Set `WPLoader.backupGlobals` to `true`. + $this->config = [ + 'wpRootFolder' => $wpRootDir, + 'dbUrl' => $db->getDbUrl(), + 'backupGlobals' => true, + ]; + $wpLoader = $this->module(); + + $this->assertInIsolation(static function () use ($wpLoader, $testcaseFile) { + $wpLoader->_initialize(); + + Assert::assertTrue(function_exists('do_action')); + + require_once $testcaseFile; + + $testCase = new \BackupControlTestCase('testBackupGlobalsIsTrue'); + /** @var TestResult $result */ + $result = $testCase->run(); + + Assert::assertTrue($result->wasSuccessful()); + }); + + // Do not set `WPLoader.backupGlobals`, but use the default value. + // Set `WPLoader.backupGlobals` to `true`. + $this->config = [ + 'wpRootFolder' => $wpRootDir, + 'dbUrl' => $db->getDbUrl(), + ]; + $wpLoader = $this->module(); + + $this->assertInIsolation(static function () use ($wpLoader, $testcaseFile) { + $wpLoader->_initialize(); + + Assert::assertTrue(function_exists('do_action')); + + require_once $testcaseFile; + + $testCase = new \BackupControlTestCase('testBackupGlobalsIsTrue'); + /** @var TestResult $result */ + $result = $testCase->run(); + + Assert::assertTrue($result->wasSuccessful()); + }); + + // Set `WPLoader.backupGlobals` to `true`, but use a use-case that sets it explicitly to `false`. + $this->config = [ + 'wpRootFolder' => $wpRootDir, + 'dbUrl' => $db->getDbUrl(), + 'backupGlobals' => true, + ]; + $wpLoader = $this->module(); + + $this->assertInIsolation(static function () use ($wpLoader, $overridingTestCaseFile) { + $wpLoader->_initialize(); + + Assert::assertTrue(function_exists('do_action')); + + require_once $overridingTestCaseFile; + + $testCase = new \BackupControlTestCaseOverridingTestCase('testBackupGlobalsIsFalse'); + /** @var TestResult $result */ + $result = $testCase->run(); + + Assert::assertTrue($result->wasSuccessful()); + }); + + $this->config = [ + 'wpRootFolder' => $wpRootDir, + 'dbUrl' => $db->getDbUrl(), + ]; + $wpLoader = $this->module(); + + // Test that globals defined before the test runs should be backed up by default. + $this->assertInIsolation(static function () use ($wpLoader, $testcaseFile) { + $wpLoader->_initialize(); + + Assert::assertTrue(function_exists('do_action')); + + // Set the initial value of the global variable. + global $_wpbrowser_test_global_var; + $_wpbrowser_test_global_var = 'initial_value'; + + require_once $testcaseFile; + + $testCase = new \BackupControlTestCase('testWillUpdateTheValueOfGlobalVar'); + /** @var TestResult $result */ + $result = $testCase->run(); + + Assert::assertTrue($result->wasSuccessful()); + + // Check that the value of the global variable has been updated. + Assert::assertEquals('initial_value', $_wpbrowser_test_global_var); + }); + + $this->config = [ + 'wpRootFolder' => $wpRootDir, + 'dbUrl' => $db->getDbUrl(), + 'backupGlobalsExcludeList' => ['_wpbrowser_test_global_var'], + ]; + $wpLoader = $this->module(); + + // Test that adding a global to the list of `backupGlobalsExcludeList` will not back it up. + $this->assertInIsolation(static function () use ($wpLoader, $testcaseFile) { + $wpLoader->_initialize(); + + Assert::assertTrue(function_exists('do_action')); + + // Set the initial value of the global variable. + global $_wpbrowser_test_global_var; + $_wpbrowser_test_global_var = 'initial_value'; + + require_once $testcaseFile; + + $testCase = new \BackupControlTestCase('testWillUpdateTheValueOfGlobalVar'); + /** @var TestResult $result */ + $result = $testCase->run(); + + Assert::assertTrue($result->wasSuccessful()); + + // Check that the value of the global variable has been updated. + Assert::assertEquals('updated_value', $_wpbrowser_test_global_var); + }); + } + + /** + * It should allow controlling the backup of static attributes in the WPTestCase + * + * @test + */ + public function should_allow_controlling_the_backup_of_static_attributes_in_the_wp_test_case(): void + { + $wpRootDir = FS::tmpDir('wploader_'); + $installation = Installation::scaffold($wpRootDir); + $dbName = Random::dbName(); + $dbHost = Env::get('WORDPRESS_DB_HOST'); + $dbUser = Env::get('WORDPRESS_DB_USER'); + $dbPassword = Env::get('WORDPRESS_DB_PASSWORD'); + $db = new MysqlDatabase($dbName, $dbUser, $dbPassword, $dbHost, 'test_'); + $db->drop(); + $installation->configure($db); + $installation->install( + 'https://wp.local', + 'admin', + 'password', + 'admin@wp.local', + 'Test' + ); + $testcaseFile = codecept_data_dir('files/BackupControlTestCase.php'); + $overridingTestCaseFile = codecept_data_dir('files/BackupControlTestCaseOverridingTestCase.php'); + + // Set`WPLoader.backupStaticAttributes` to `false`. + $this->config = [ + 'wpRootFolder' => $wpRootDir, + 'dbUrl' => $db->getDbUrl(), + 'backupStaticAttributes' => false, + ]; + $wpLoader = $this->module(); + + $this->assertInIsolation(static function () use ($wpLoader, $testcaseFile) { + $wpLoader->_initialize(); + + Assert::assertTrue(function_exists('do_action')); + + require_once $testcaseFile; + + $testCase = new \BackupControlTestCase('testWillAlterStoreStaticAttribute'); + /** @var TestResult $result */ + $result = $testCase->run(); + + Assert::assertTrue($result->wasSuccessful()); + + Assert::assertEquals('updated_value', \BackupControlTestCaseStore::$staticAttribute); + }); + + // Don't set`WPLoader.backupStaticAttributes`, it should be `true` by default. + $this->config = [ + 'wpRootFolder' => $wpRootDir, + 'dbUrl' => $db->getDbUrl() + ]; + $wpLoader = $this->module(); + + $this->assertInIsolation(static function () use ($wpLoader, $testcaseFile) { + $wpLoader->_initialize(); + + Assert::assertTrue(function_exists('do_action')); + + require_once $testcaseFile; + + $testCase = new \BackupControlTestCase('testWillAlterStoreStaticAttribute'); + /** @var TestResult $result */ + $result = $testCase->run(); + + Assert::assertTrue($result->wasSuccessful()); + + Assert::assertEquals('initial_value', \BackupControlTestCaseStore::$staticAttribute); + }); + + // Set the value of `WPLoader.backupStaticAttributes` to `true`, but use a use-case that sets it explicitly to `false`. + $this->config = [ + 'wpRootFolder' => $wpRootDir, + 'dbUrl' => $db->getDbUrl(), + 'backupStaticAttributes' => true, + ]; + $wpLoader = $this->module(); + + $this->assertInIsolation(static function () use ($wpLoader, $overridingTestCaseFile) { + $wpLoader->_initialize(); + + Assert::assertTrue(function_exists('do_action')); + + require_once $overridingTestCaseFile; + + $testCase = new \BackupControlTestCaseOverridingTestCase('testWillAlterStoreStaticAttribute'); + /** @var TestResult $result */ + $result = $testCase->run(); + + Assert::assertTrue($result->wasSuccessful()); + + Assert::assertEquals('updated_value', \BackupControlTestCaseOverridingStore::$staticAttribute); + }); + + // Set the value of the `WPLoader.backupStaticAttributesExcludeList` to not back up the static attribute. + $this->config = [ + 'wpRootFolder' => $wpRootDir, + 'dbUrl' => $db->getDbUrl(), + 'backupStaticAttributesExcludeList' => [ + \BackupControlTestCaseStore::class => ['staticAttribute', 'staticAttributeThree'], + \BackupControlTestCaseStoreTwo::class => ['staticAttributeFour'], + ] + ]; + $wpLoader = $this->module(); + + $this->assertInIsolation( + static function () use ($wpLoader, $testcaseFile) { + $wpLoader->_initialize(); + + Assert::assertTrue(function_exists('do_action')); + + require_once $testcaseFile; + + $testCase = new \BackupControlTestCase('testWillAlterStoreStaticAttribute'); + /** @var TestResult $result */ + $result = $testCase->run(); + + Assert::assertTrue($result->wasSuccessful()); + + Assert::assertEquals('updated_value', \BackupControlTestCaseStore::$staticAttribute); + Assert::assertEquals('initial_value', \BackupControlTestCaseStore::$staticAttributeTwo); + Assert::assertEquals('updated_value', \BackupControlTestCaseStore::$staticAttributeThree); + Assert::assertEquals('initial_value', \BackupControlTestCaseStore::$staticAttributeFour); + Assert::assertEquals('initial_value', \BackupControlTestCaseStoreTwo::$staticAttribute); + Assert::assertEquals('initial_value', \BackupControlTestCaseStoreTwo::$staticAttributeTwo); + Assert::assertEquals('initial_value', \BackupControlTestCaseStoreTwo::$staticAttributeThree); + Assert::assertEquals('updated_value', \BackupControlTestCaseStoreTwo::$staticAttributeFour); + } + ); + } + + public function notABooleanProvider(): array + { + return [ + 'string' => ['string'], + 'integer' => [1], + 'float' => [1.1], + 'array' => [[]], + 'object' => [new stdClass()], + ]; + } + + /** + * It should throw if backupGlobals is not a boolean + * + * @test + * @dataProvider notABooleanProvider + */ + public function should_throw_if_backup_globals_is_not_a_boolean($notABoolean): void + { + $wpRootDir = Env::get('WORDPRESS_ROOT_DIR'); + $db = (new Installation($wpRootDir))->getDb(); + $this->config = [ + 'wpRootFolder' => $wpRootDir, + 'dbUrl' => $db->getDbUrl(), + 'backupGlobals' => $notABoolean, + ]; + + $this->expectException(ModuleConfigException::class); + + $this->module(); + } + + public function notArrayOfStringsProvider(): array + { + return [ + 'string' => ['string'], + 'integer' => [1], + 'float' => [1.1], + 'object' => [new stdClass()], + 'array of integers' => [[1, 2, 3]], + 'array of floats' => [[1.1, 2.2, 3.3]], + 'array of objects' => [[new stdClass(), new stdClass(), new stdClass()]], + 'array of arrays' => [[[1, 2, 3], [4, 5, 6], [7, 8, 9]]], + 'array of mixed' => [[1, 2.2, new stdClass(), [1, 2, 3]]], + ]; + } + + /** + * It should throw if backupGlobalsExcludeList is not an array of strings + * + * @test + * @dataProvider notArrayOfStringsProvider + */ + public function should_throw_if_backup_globals_exclude_list_is_not_an_array_of_strings($input): void + { + $wpRootDir = Env::get('WORDPRESS_ROOT_DIR'); + $db = (new Installation($wpRootDir))->getDb(); + $this->config = [ + 'wpRootFolder' => $wpRootDir, + 'dbUrl' => $db->getDbUrl(), + 'backupGlobalsExcludeList' => $input, + ]; + + $this->expectException(ModuleConfigException::class); + + $this->module(); + } + + /** + * It should throw if backupStaticAttributes is not a boolean + * + * @test + * @dataProvider notABooleanProvider + */ + public function should_throw_if_backup_static_attributes_is_not_a_boolean($notABoolean): void + { + $wpRootDir = Env::get('WORDPRESS_ROOT_DIR'); + $db = (new Installation($wpRootDir))->getDb(); + $this->config = [ + 'wpRootFolder' => $wpRootDir, + 'dbUrl' => $db->getDbUrl(), + 'backupStaticAttributes' => $notABoolean, + ]; + + $this->expectException(ModuleConfigException::class); + + $this->module(); + } + + public function notStaticAttributeExcludeListProvider(): array + { + return [ + 'string' => ['string'], + 'integer' => [1], + 'float' => [1.1], + 'object' => [new stdClass()], + 'array of integers' => [[1, 2, 3]], + 'array of floats' => [[1.1, 2.2, 3.3]], + 'array of objects' => [[new stdClass(), new stdClass(), new stdClass()]], + 'array of arrays' => [[[1, 2, 3], [4, 5, 6], [7, 8, 9]]], + 'array of mixed' => [[1, 2.2, new stdClass(), [1, 2, 3]]], + ]; + } + + /** + * It should throw if backupStaticAttributesExcludeList is not in the correct format + * + * @test + * @dataProvider notStaticAttributeExcludeListProvider + */ + public function should_throw_if_backup_static_attributes_exclude_list_is_not_in_the_correct_format($input): void + { + $wpRootDir = Env::get('WORDPRESS_ROOT_DIR'); + $db = (new Installation($wpRootDir))->getDb(); + $this->config = [ + 'wpRootFolder' => $wpRootDir, + 'dbUrl' => $db->getDbUrl(), + 'backupStaticAttributesExcludeList' => $input, + ]; + + $this->expectException(ModuleConfigException::class); + + $this->module(); + } }