From bbfc52431857ac16b21d6739b6a31e17d333c58e Mon Sep 17 00:00:00 2001 From: Alda Vigdis Skarphedinsdottir Date: Fri, 22 Mar 2024 00:25:40 +0100 Subject: [PATCH] Linting and documenting the code (#23) - Adding docblocks - Fixing some coding style and linting issues - Rearranging and improving the Composer file - Adding a Database class to handle database operations and checks - Removing the cleanup class as it was unused - Fixing readme a bit --- bootstrap.php | 2 + composer.json | 35 +++-- composer.lock | 188 ++++++++++++++++++++++++++- phpcs.xml | 44 ++++++- readme.md | 11 +- src/Bootstrap.php | 104 +++++++++++---- src/Cleanup.php | 19 --- src/Config.php | 85 +++++++----- src/Database.php | 98 ++++++++++++++ src/Defaults.php | 3 + src/FetchWP.php | 49 ++++++- src/TestHelper.php | 8 +- supressors/SupressFramework.php | 2 +- supressors/SupressFrameworkError.php | 2 +- tests/BootstrapTest.php | 2 +- 15 files changed, 551 insertions(+), 101 deletions(-) delete mode 100644 src/Cleanup.php create mode 100644 src/Database.php diff --git a/bootstrap.php b/bootstrap.php index 886980b..b650647 100644 --- a/bootstrap.php +++ b/bootstrap.php @@ -1,5 +1,7 @@ =5.3", + "squizlabs/php_codesniffer": "^2.3 || ^3.0.2" + }, + "conflict": { + "squizlabs/php_codesniffer": "2.6.2" + }, + "require-dev": { + "phpunit/phpunit": "~4.5 || ^5.0 || ^6.0 || ^7.0" + }, + "suggest": { + "dealerdirect/phpcodesniffer-composer-installer": "^0.5 || This Composer plugin will sort out the PHPCS 'installed_paths' automatically.", + "roave/security-advisories": "dev-master || Helps prevent installing dependencies with known security issues." + }, + "type": "phpcodesniffer-standard", + "notification-url": "https://packagist.org/downloads/", + "license": [ + "LGPL-3.0-or-later" + ], + "authors": [ + { + "name": "Wim Godden", + "homepage": "https://github.com/wimg", + "role": "lead" + }, + { + "name": "Juliette Reinders Folmer", + "homepage": "https://github.com/jrfnl", + "role": "lead" + }, + { + "name": "Contributors", + "homepage": "https://github.com/PHPCompatibility/PHPCompatibility/graphs/contributors" + } + ], + "description": "A set of sniffs for PHP_CodeSniffer that checks for PHP cross-version compatibility.", + "homepage": "http://techblog.wimgodden.be/tag/codesniffer/", + "keywords": [ + "compatibility", + "phpcs", + "standards" + ], + "support": { + "issues": "https://github.com/PHPCompatibility/PHPCompatibility/issues", + "source": "https://github.com/PHPCompatibility/PHPCompatibility" + }, + "time": "2019-12-27T09:44:58+00:00" + }, { "name": "phpcsstandards/phpcsextra", "version": "1.2.1", @@ -2685,6 +2747,53 @@ ], "time": "2024-03-17T23:44:50+00:00" }, + { + "name": "phpstan/phpdoc-parser", + "version": "1.27.0", + "source": { + "type": "git", + "url": "https://github.com/phpstan/phpdoc-parser.git", + "reference": "86e4d5a4b036f8f0be1464522f4c6b584c452757" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/phpstan/phpdoc-parser/zipball/86e4d5a4b036f8f0be1464522f4c6b584c452757", + "reference": "86e4d5a4b036f8f0be1464522f4c6b584c452757", + "shasum": "" + }, + "require": { + "php": "^7.2 || ^8.0" + }, + "require-dev": { + "doctrine/annotations": "^2.0", + "nikic/php-parser": "^4.15", + "php-parallel-lint/php-parallel-lint": "^1.2", + "phpstan/extension-installer": "^1.0", + "phpstan/phpstan": "^1.5", + "phpstan/phpstan-phpunit": "^1.1", + "phpstan/phpstan-strict-rules": "^1.0", + "phpunit/phpunit": "^9.5", + "symfony/process": "^5.2" + }, + "type": "library", + "autoload": { + "psr-4": { + "PHPStan\\PhpDocParser\\": [ + "src/" + ] + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "description": "PHPDoc parser with support for nullable, intersection and generic types", + "support": { + "issues": "https://github.com/phpstan/phpdoc-parser/issues", + "source": "https://github.com/phpstan/phpdoc-parser/tree/1.27.0" + }, + "time": "2024-03-21T13:14:53+00:00" + }, { "name": "psr/container", "version": "2.0.2", @@ -3113,6 +3222,71 @@ }, "time": "2023-09-03T09:24:00+00:00" }, + { + "name": "slevomat/coding-standard", + "version": "8.15.0", + "source": { + "type": "git", + "url": "https://github.com/slevomat/coding-standard.git", + "reference": "7d1d957421618a3803b593ec31ace470177d7817" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/slevomat/coding-standard/zipball/7d1d957421618a3803b593ec31ace470177d7817", + "reference": "7d1d957421618a3803b593ec31ace470177d7817", + "shasum": "" + }, + "require": { + "dealerdirect/phpcodesniffer-composer-installer": "^0.6.2 || ^0.7 || ^1.0", + "php": "^7.2 || ^8.0", + "phpstan/phpdoc-parser": "^1.23.1", + "squizlabs/php_codesniffer": "^3.9.0" + }, + "require-dev": { + "phing/phing": "2.17.4", + "php-parallel-lint/php-parallel-lint": "1.3.2", + "phpstan/phpstan": "1.10.60", + "phpstan/phpstan-deprecation-rules": "1.1.4", + "phpstan/phpstan-phpunit": "1.3.16", + "phpstan/phpstan-strict-rules": "1.5.2", + "phpunit/phpunit": "8.5.21|9.6.8|10.5.11" + }, + "type": "phpcodesniffer-standard", + "extra": { + "branch-alias": { + "dev-master": "8.x-dev" + } + }, + "autoload": { + "psr-4": { + "SlevomatCodingStandard\\": "SlevomatCodingStandard/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "description": "Slevomat Coding Standard for PHP_CodeSniffer complements Consistence Coding Standard by providing sniffs with additional checks.", + "keywords": [ + "dev", + "phpcs" + ], + "support": { + "issues": "https://github.com/slevomat/coding-standard/issues", + "source": "https://github.com/slevomat/coding-standard/tree/8.15.0" + }, + "funding": [ + { + "url": "https://github.com/kukulich", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/slevomat/coding-standard", + "type": "tidelift" + } + ], + "time": "2024-03-09T15:20:58+00:00" + }, { "name": "squizlabs/php_codesniffer", "version": "3.9.0", diff --git a/phpcs.xml b/phpcs.xml index b4f5935..4a170ef 100644 --- a/phpcs.xml +++ b/phpcs.xml @@ -1,6 +1,46 @@ - - ./supressors/* + + + + + + + + + + + + + + + + + + + + + + + + + + + ./vendor/* + + + + ./tests/** + ./supressors/** + + + ./tests/** + ./supressors/** + + \ No newline at end of file diff --git a/readme.md b/readme.md index b0feb25..500e069 100644 --- a/readme.md +++ b/readme.md @@ -10,14 +10,16 @@ In essence, it has the same purpose as the `install-wp-tests.sh` shell script in * Is 100% programmed in PHP, so it does not require skills beyond that to contribute to the project * Has the same dependencies as one can expect from any WordPress development environment (the `cURL` and `ZipArchive` PHP modules) * Does not depend on ancient technology that nobody should use anymore, such as Subversion -* The test environments are downloaded and configured automatically using your PHPUnit configuration file +* The test environments are downloaded and configured automatically using information from your PHPUnit configuration file and environment variables * No need to re-run a script to install a development environment with the same parameters after every time you restart your computer or development environment ![A screenshot of WP-Tests-Strapon, showing the test suite being prepared and run.](https://raw.githubusercontent.com/aldavigdis/wp-tests-strapon/main/docs/images/screenshot1.png) ## Usage -WP-Tests-Strapon integrates with PHPUnit and acts as a bootstrap layer between your WordPress plugin's test suite. Simply run `./vendor/bin/phpunit` as you would generally do after following the installation instructions below. +WP-Tests-Strapon integrates with PHPUnit and acts as a bootstrap layer between it and your WordPress plugin's test suite. Simply run `./vendor/bin/phpunit` as you would generally do after following the installation instructions below. + +For more information on PHPUnit itself and how to write tests, [you should read their documentation](https://phpunit.de/getting-started/phpunit-10.html). ## Installation @@ -82,6 +84,7 @@ The default values can be overridden when the file is generated by setting envir ## The Todo List * Test the database connection when the config file is initialised +* Create the database if it does not exsist * Improve documentation * Add more tests * Add more glitter @@ -90,6 +93,10 @@ The default values can be overridden when the file is generated by setting envir ## FAQ +**Q:** Why did you choose the AGPL license as opposed to a less restrictive one? + +**A:** I don't work for free for your company and the lest anyone using my software can do is to contribute back if they find my software useful. If you would like a different licensing agreement for a fee, then that can be arranged. + **Q:** What's with the emoji everywhere? **A:** What's with you being so boring and dull? diff --git a/src/Bootstrap.php b/src/Bootstrap.php index a268b8d..7b2cfe5 100644 --- a/src/Bootstrap.php +++ b/src/Bootstrap.php @@ -6,8 +6,12 @@ use Aldavigdis\WpTestsStrapon\FetchWP; use Aldavigdis\WpTestsStrapon\Config; +use Aldavigdis\WpTestsStrapon\Database; use Ansi; +/** + * Bootstrap is a class used for running what happens in the bootstrap.php file + */ class Bootstrap { public const MIN_TERMINAL_WIDTH = 30; @@ -181,7 +185,13 @@ class Bootstrap '🩷', '🦩', '💖', '✨', '💗', '🎀', '🩰', '👠', '💄', '💅', '💍', '🐻']; - public static function init(string $wp_version) + /** + * Initialise the bootstrap sequence for a specific WordPress version + * + * This fetches the relevant WP version and runs all the colourful + * functionality of wp-tests-bootstrap. + */ + public static function init(string $wp_version): void { self::displayLogotype(); self::displaySeparator(); @@ -219,9 +229,22 @@ public static function init(string $wp_version) $config = new Config(wp_version: $wp_version); - if ($config->testDatabaseConnection() === true) { + if ($config->save() === true) { + $path = Config::path(); + self::displayLine("A fresh config was saved to '$path'."); + echo PHP_EOL; + } + + if ( + Database::testConnection( + $config->db_host, + $config->db_user, + $config->db_password, + $config->db_name + ) === true + ) { self::displayLine( - 'Connection to the database was successful.' + 'Connection to the database server was successful.' ); } else { self::displayLine( @@ -230,28 +253,39 @@ public static function init(string $wp_version) 'and correct.', '👎' ); - echo PHP_EOL; } - if ($config->save() === true) { - $path = Config::path(); - self::displayLine("A fresh config was saved to '$path'."); - self::displayLine( - 'The configuration parameters in the config file are ' . - 'based on environment variables.', - '🖖' - ); + if ( + Database::exsists( + $config->db_host, + $config->db_user, + $config->db_password, + $config->db_name + ) === true + ) { self::displayLine( - "You can set those in your 'phpunit.xml', in your " . - 'terminal etc.', - '⌨️' + "The '$config->db_name' database exsists." ); + } else { self::displayLine( - 'Read all about it in the WP-Tests-Strapon readme file.', - '📃' + "The '$config->db_name' database does not exist." . + 'Attempting to create it...', + '😰' ); - echo PHP_EOL; + if ( + Database::create( + $config->db_host, + $config->db_user, + $config->db_password, + $config->db_name + ) === true + ) { + self::displayLine('The database was created.'); + } } + + echo PHP_EOL; + } if (FetchWP::isInstalled('develop-trunk', 'wordpress') === false) { @@ -352,6 +386,12 @@ public static function init(string $wp_version) self::displaySeparator(); } + /** + * Get the width for the current terminal + * + * @param int $min The minimum terminal width. + * @param int $max The maximum terminal width. + */ public static function terminalWidth( int $min = self::MIN_TERMINAL_WIDTH, int $max = self::MAX_TERMINAL_WIDTH @@ -394,6 +434,9 @@ public static function terminalWidth( return $width; } + /** + * Display a horizontal separator with a pretty emoji in the middle + */ public static function displaySeparator(): void { $halfwidth = intval((self::terminalWidth() / 2) - 4); @@ -410,17 +453,23 @@ public static function displaySeparator(): void PHP_EOL . PHP_EOL; } - public static function displayLine(string $text, ?string $emoji = null): void + /** + * Display a line of text that starts with a pretty emoji + * + * Displays a line of text that wraps down according to the current terminal + * size. Each line starts with an emoji, which defaults to a green tick. + */ + public static function displayLine(string $text, string $emoji = '✅'): void { $terminal_width = self::terminalWidth() - 10; - if (is_null($emoji) === true) { - $emoji = "✅"; - } $wrapped_text = wordwrap($text, $terminal_width, PHP_EOL . "\t", true); echo " $emoji\t$wrapped_text" . PHP_EOL; } + /** + * Display a line of propaganda + */ public static function displayInspiration(?object $inspo = null): void { if (is_null($inspo) === true) { @@ -429,6 +478,9 @@ public static function displayInspiration(?object $inspo = null): void self::displayLine($inspo->text, $inspo->emoji); } + /** + * Display the WPTS (wp-tests-strapon) logotype as ANSI/ACII art + */ public static function displayLogotype(): void { $spaces = str_repeat(' ', intval((self::terminalWidth() / 2) - 14)); @@ -446,13 +498,19 @@ public static function displayLogotype(): void echo PHP_EOL; } + /** + * Pick a random line of propaganda + */ public static function pickInspiration(): object { $key = array_rand(self::INSPIRATIONS); return (object) self::INSPIRATIONS[$key]; } - public static function configExsists() + /** + * Check if the test config file exsists + */ + public static function configExsists(): bool { $path = Config::path(); diff --git a/src/Cleanup.php b/src/Cleanup.php deleted file mode 100644 index ec0c841..0000000 --- a/src/Cleanup.php +++ /dev/null @@ -1,19 +0,0 @@ -config_contents) . "\n")) { - return true; - } - - return false; - } - - public function testDatabaseConnection() - { - try { - $connection = mysqli_connect( - hostname: $this->db_host, - username: $this->db_user, - password: $this->db_password, - database: $this->db_name - ); - } catch (\Throwable $th) { - return false; - } - - if ($connection !== false) { + if (fwrite($file, rtrim($this->config_contents) . PHP_EOL)) { return true; } return false; } - private function formatComment(string $comment) + /** + * Format a comment block for the configuration file + */ + private function formatComment(string $comment): string { $comment_lines = explode(PHP_EOL, $comment); $entity = ''; if (is_string($comment)) { - $entity .= '/**' . "\n"; + $entity .= '/**' . PHP_EOL; foreach ($comment_lines as $c) { $trimmed_comment = trim($c); $entity .= ' *'; if (empty($trimmed_comment) === false) { $entity .= ' ' . $trimmed_comment; } - $entity .= "\n"; + $entity .= PHP_EOL; } - $entity .= ' **/' . "\n"; + $entity .= ' **/' . PHP_EOL; } return $entity; } - private function cleanName(string $name) + /** + * Clean and strip a variable or constant name + */ + private function cleanName(string $name): string { return trim(addslashes(str_replace([' ', '\''], '_', $name))); } - private function cleanValue(string|bool $value) + /** + * Clean and strip a variable or contant value + */ + private function cleanValue(string|bool $value): string { if (is_bool($value) === true) { if ($value === true) { @@ -210,11 +225,14 @@ private function cleanValue(string|bool $value) return '\'' . trim(addslashes($value)) . '\''; } + /** + * Format a PHP constant declaration in the config file + */ private function formatConstant( string $name, bool|string $value, ?string $comment = null - ) { + ): string { $clean_name = $this->cleanName($name); $clean_value = $this->cleanValue($value); @@ -227,11 +245,14 @@ private function formatConstant( return $entity; } + /** + * Format a variable decleation in the config file + */ private function formatVariable( string $name, string $value, ?string $comment = null - ) { + ): string { $clean_name = $this->cleanName($name); $clean_value = $this->cleanValue($value); diff --git a/src/Database.php b/src/Database.php new file mode 100644 index 0000000..e4ce343 --- /dev/null +++ b/src/Database.php @@ -0,0 +1,98 @@ +query('USE `' . $database . '`'); + } catch (Throwable) { + return false; + } + + if ($result !== false) { + return true; + } + + return false; + } + + /** + * Drop the database + */ + static public function drop( + string $hostname = DB_HOST, + string $username = DB_USER, + string $password = DB_PASSWORD, + string $database = DB_NAME + ): bool { + $mysqli = new mysqli($hostname, $username, $password, null); + + return (bool) $mysqli->query( + 'DROP DATABASE IF EXISTS `' . $database . '`' + ); + } + + /** + * Create the database + */ + static public function create( + string $hostname = DB_HOST, + string $username = DB_USER, + string $password = DB_PASSWORD, + string $database = DB_NAME + ): bool { + $mysqli = new mysqli($hostname, $username, $password, null); + + return (bool) $mysqli->query( + 'CREATE DATABASE IF NOT EXISTS `' . $database . '`' + ); + } +} \ No newline at end of file diff --git a/src/Defaults.php b/src/Defaults.php index 7866fa1..00f7d3a 100644 --- a/src/Defaults.php +++ b/src/Defaults.php @@ -4,6 +4,9 @@ namespace Aldavigdis\WpTestsStrapon; +/** + * The Defaults class contains the default values for the test configuration file + */ class Defaults { public const WP_VERSION = 'master'; diff --git a/src/FetchWP.php b/src/FetchWP.php index 98b361a..9cb29a0 100644 --- a/src/FetchWP.php +++ b/src/FetchWP.php @@ -6,6 +6,10 @@ use ZipArchive; +/** + * FetchWP is a class for fetching WordPress archives from Github and extracting + * them in a location that can be used by wp-tests-strapon + */ class FetchWP { public const WP_VENDOR_BASE_PATH = 'vendor/wordpress/wordpress/'; @@ -20,6 +24,9 @@ class FetchWP public const DEFAULT_WP_VERSION = 'master'; + /** + * Get a full url to a WordPress zip archive on Github + */ public static function archiveUrl( string $wp_version = self::DEFAULT_WP_VERSION, string $base_url = self::WP_DIST_BASE_URL @@ -31,11 +38,20 @@ public static function archiveUrl( return $base_url . $wp_version . '.zip'; } + /** + * Get the base directory for the test environment + * + * This usually starts with /tmp on Linux, but MacOS and Windows use a + * different temp directory per user that needs to be accounted for. + */ public static function extractDirPath(): string { return sys_get_temp_dir() . '/' . 'wp-tests-strapon/'; } + /** + * Get a full path to a WordPress test environment + */ public static function wpInstallationPath( string $wp_version = 'master', string $basename = 'WordPress' @@ -43,11 +59,23 @@ public static function wpInstallationPath( return self::extractDirPath() . $basename . '-' . $wp_version . '/'; } + /** + * Generate a unique file path for a zip archive + */ public static function archiveFilePath(): string { return sys_get_temp_dir() . '/' . uniqid() . '.zip'; } + /** + * Download a zip archive from Github + * + * @param string $wp_version The WordPress version string. + * @param string $base_url The base URL (sans the version string) for the archive. + * + * @return string|false The file path to the downloaded archive on success, + * false on failure. + */ public static function downloadArchive( string $wp_version = 'master', string $base_url = self::WP_DIST_BASE_URL @@ -74,6 +102,14 @@ public static function downloadArchive( return $file_path; } + /** + * Extract downloaded zip archive + * + * @param string $archive_file_path The path to the zip file + * @param bool $delete Delete the zip file if true + * + * @return bool True on success, false on failure. + */ public static function extractArchive( string $archive_file_path, bool $delete = true @@ -84,7 +120,6 @@ public static function extractArchive( $zip = new ZipArchive(); if ($zip->open($archive_file_path) !== true) { - echo "Hmm\n"; return false; } if ($zip->extractTo(self::extractDirPath()) === false) { @@ -99,6 +134,18 @@ public static function extractArchive( return true; } + /** + * Check if a test environment has been installed + * + * @param string $wp_version The WordPress version for the environment + * @param string $basename The "base name" if the environment. This is + * usually WordPress for most versions, but + * wordpress for the unbuilt version of WP as they + * come from different repositories with different + * standards. + * + * @return bool True if the environment is installed, false if it isn't. + */ public static function isInstalled( string $wp_version, string $basename = 'WordPress' diff --git a/src/TestHelper.php b/src/TestHelper.php index 6121624..e82fa51 100644 --- a/src/TestHelper.php +++ b/src/TestHelper.php @@ -4,9 +4,15 @@ namespace Aldavigdis\WpTestsStrapon; +/** + * The TestHelper class contains functions that facilitate the test suite + */ class TestHelper { - public static function SayHello() { + /** + * Echo out a "Hello!" + */ + public static function SayHello(): void { esc_html_e( 'Hello!', 'wp-tests-strapon' ); } } diff --git a/supressors/SupressFramework.php b/supressors/SupressFramework.php index 11ea86c..7893af3 100644 --- a/supressors/SupressFramework.php +++ b/supressors/SupressFramework.php @@ -1,6 +1,6 @@