From 1830a0610ef1ba2a92cc2c37c2452fc451d23c7f Mon Sep 17 00:00:00 2001 From: Pascal Birchler Date: Thu, 16 May 2024 14:18:39 +0200 Subject: [PATCH] PHStan for tests & lint fixes --- composer.json | 10 +- inc/CLI/InfoCommand.php | 2 +- inc/CLI/ProjectCommand.php | 4 +- inc/Configuration.php | 22 +-- inc/Export.php | 16 +-- inc/Loader/Base.php | 2 +- inc/Plugin.php | 12 +- inc/Project.php | 2 +- inc/ProjectLocator.php | 10 +- inc/Repository/Base.php | 4 +- inc/Runner.php | 4 +- inc/Updater.php | 4 +- inc/WebhookHandler.php | 6 +- inc/WebhookHandler/Base.php | 8 +- inc/WebhookHandler/Bitbucket.php | 4 +- inc/WebhookHandler/GitHub.php | 6 +- inc/WebhookHandler/GitLab.php | 2 +- inc/WebhookHandlerFactory.php | 4 +- inc/ZipProvider.php | 17 +-- phpcs.xml.dist | 14 +- phpstan.neon.dist | 4 +- tests/phpstan/stubs/factory.php | 129 ++++++++++++++++++ tests/phpstan/stubs/test-stubs.php | 13 ++ tests/phpstan/stubs/testcase-route.php | 55 ++++++++ tests/phpstan/stubs/testcase.php | 68 +++++++++ tests/phpunit/bootstrap.php | 4 +- tests/phpunit/tests/Behat/FeatureContext.php | 18 +-- tests/phpunit/tests/Configuration.php | 17 ++- tests/phpunit/tests/Export.php | 91 ++++++------ tests/phpunit/tests/Loader/Git.php | 16 +-- tests/phpunit/tests/Loader/Mercurial.php | 16 +-- tests/phpunit/tests/Loader/Subversion.php | 16 +-- tests/phpunit/tests/LoaderFactory.php | 20 +-- tests/phpunit/tests/Project.php | 13 +- tests/phpunit/tests/ProjectLocator.php | 25 ++-- tests/phpunit/tests/Repository/Bitbucket.php | 37 ++--- tests/phpunit/tests/Repository/GitHub.php | 31 ++--- tests/phpunit/tests/Repository/GitLab.php | 29 ++-- tests/phpunit/tests/RepositoryFactory.php | 30 ++-- tests/phpunit/tests/RestrictedSiteAccess.php | 2 - tests/phpunit/tests/Runner.php | 16 +-- tests/phpunit/tests/TestCase.php | 24 ++-- tests/phpunit/tests/TranslationApiRoute.php | 85 ++++++++---- tests/phpunit/tests/Updater.php | 28 ++-- .../tests/WebhookHandler/Bitbucket.php | 29 ++-- tests/phpunit/tests/WebhookHandler/GitHub.php | 66 ++++----- tests/phpunit/tests/WebhookHandler/GitLab.php | 10 +- .../tests/WebhookHandler/LegacyGitHub.php | 31 ++--- tests/phpunit/tests/ZipProvider.php | 91 ++++++------ 49 files changed, 742 insertions(+), 425 deletions(-) create mode 100644 tests/phpstan/stubs/factory.php create mode 100644 tests/phpstan/stubs/test-stubs.php create mode 100644 tests/phpstan/stubs/testcase-route.php create mode 100644 tests/phpstan/stubs/testcase.php diff --git a/composer.json b/composer.json index 5de988c7..fff916ea 100644 --- a/composer.json +++ b/composer.json @@ -41,16 +41,18 @@ "wearerequired/traduttore-registry": "^2.0" }, "require-dev": { - "dealerdirect/phpcodesniffer-composer-installer": "^v1.0.0", - "php-stubs/wp-cli-stubs": "^v2.10", + "dealerdirect/phpcodesniffer-composer-installer": "^1.0.0", + "php-stubs/wordpress-tests-stubs": "^6.5", + "php-stubs/wp-cli-stubs": "^2.10", "phpstan/extension-installer": "^1.3", "phpstan/phpstan-deprecation-rules": "^1.2", + "phpstan/phpstan-phpunit": "^1.4", "swissspidy/phpstan-no-private": "^0.2.0", "szepeviktor/phpstan-wordpress": "^1.3", "wearerequired/coding-standards": "^6.0", "wp-cli/extension-command": "^2.0", "wp-cli/rewrite-command": "^2.0", - "wp-cli/wp-cli-tests": "^v4.2.9", + "wp-cli/wp-cli-tests": "^4.2.9", "wpackagist-plugin/glotpress": "^4.0.0", "yoast/phpunit-polyfills": "^1.1" }, @@ -75,8 +77,8 @@ }, "config": { "allow-plugins": { - "dealerdirect/phpcodesniffer-composer-installer": true, "composer/installers": true, + "dealerdirect/phpcodesniffer-composer-installer": true, "phpstan/extension-installer": true }, "process-timeout": 7200, diff --git a/inc/CLI/InfoCommand.php b/inc/CLI/InfoCommand.php index e04e42c7..1325f6f7 100644 --- a/inc/CLI/InfoCommand.php +++ b/inc/CLI/InfoCommand.php @@ -149,7 +149,7 @@ protected function get_svn_binary_path(): ?string { * @return null|string Binary path on success, null otherwise. */ protected function get_wp_binary_path(): ?string { - if ( \defined( 'TRADUTTORE_WP_BIN' ) && TRADUTTORE_WP_BIN ) { + if ( \defined( 'TRADUTTORE_WP_BIN' ) && \is_string( TRADUTTORE_WP_BIN ) ) { return TRADUTTORE_WP_BIN; } diff --git a/inc/CLI/ProjectCommand.php b/inc/CLI/ProjectCommand.php index 62684b0d..e06025e2 100644 --- a/inc/CLI/ProjectCommand.php +++ b/inc/CLI/ProjectCommand.php @@ -88,8 +88,8 @@ public function info( array $args, array $assoc_args ): void { $repository_visibility = $project->get_repository_visibility() ?? '(unknown)'; $repository_ssh_url = $repository ? $repository->get_ssh_url() : '(unknown)'; $repository_https_url = $repository ? $repository->get_https_url() : '(unknown)'; - $repository_instance = $repository ? \get_class( $repository ) : '(unknown)'; - $loader_instance = $loader ? \get_class( $loader ) : '(unknown)'; + $repository_instance = $repository ? $repository::class : '(unknown)'; + $loader_instance = $loader ? $loader::class : '(unknown)'; if ( get_flag_value( $assoc_args, 'format' ) === 'json' ) { $info = [ diff --git a/inc/Configuration.php b/inc/Configuration.php index b2cb857f..a6939d5e 100644 --- a/inc/Configuration.php +++ b/inc/Configuration.php @@ -22,16 +22,16 @@ class Configuration { * * @var string Repository path. */ - protected $path; + protected string $path; /** * Repository configuration. * * @since 3.0.0 * - * @phpstan-var ProjectConfig - * * @var array Repository configuration. + * + * @phpstan-var ProjectConfig */ protected $config = []; @@ -64,9 +64,9 @@ public function get_path(): string { * * @since 3.0.0 * - * @phpstan-return ProjectConfig - * * @return array Repository configuration. + * + * @phpstan-return ProjectConfig */ public function get_config(): array { return $this->config; @@ -77,14 +77,14 @@ public function get_config(): array { * * @since 3.0.0 * + * @param string $key Config key. + * @return string|string[]|null Config value. + * * @phpstan-template T of key-of * @phpstan-param T $key * @phpstan-return ProjectConfig[T] | null - * - * @param string $key Config key. - * @return string|string[]|null Config value. */ - public function get_config_value( string $key ) { + public function get_config_value( string $key ): string|array|null { if ( isset( $this->config[ $key ] ) ) { return $this->config[ $key ]; } @@ -97,9 +97,9 @@ public function get_config_value( string $key ) { * * @since 3.0.0 * - * @phpstan-return ProjectConfig - * * @return array Configuration data if found. + * + * @phpstan-return ProjectConfig */ protected function load_config(): array { $config_file = trailingslashit( $this->path ) . 'traduttore.json'; diff --git a/inc/Export.php b/inc/Export.php index 45ef7c73..eb7014e2 100644 --- a/inc/Export.php +++ b/inc/Export.php @@ -10,7 +10,6 @@ use GP; use GP_Locales; use GP_Translation_Set; -use InvalidArgumentException; /** * Export strings to translation files in PO, MO, and JSON format. @@ -25,7 +24,7 @@ class Export { * * @var \GP_Translation_Set */ - protected $translation_set; + protected GP_Translation_Set $translation_set; /** * The current locale. @@ -43,7 +42,7 @@ class Export { * * @var \Required\Traduttore\Project */ - protected $project; + protected Project $project; /** * List of generated files. @@ -52,7 +51,7 @@ class Export { * * @var string[] */ - protected $files; + protected array $files; /** * Export constructor. @@ -63,12 +62,13 @@ public function __construct( GP_Translation_Set $translation_set ) { $this->translation_set = $translation_set; $this->locale = GP_Locales::by_slug( $translation_set->locale ); + /** + * GlotPress project. + * + * @var \GP_Project $gp_project + */ $gp_project = GP::$project->get( $translation_set->project_id ); - if ( ! $gp_project ) { - throw new InvalidArgumentException( __( 'Project not found', 'traduttore' ) ); - } - $this->project = new Project( $gp_project ); } diff --git a/inc/Loader/Base.php b/inc/Loader/Base.php index a5fe8a74..b9f7bf61 100644 --- a/inc/Loader/Base.php +++ b/inc/Loader/Base.php @@ -21,7 +21,7 @@ abstract class Base implements Loader { * * @var \Required\Traduttore\Repository Repository object. */ - protected $repository; + protected Repository $repository; /** * Class constructor. diff --git a/inc/Plugin.php b/inc/Plugin.php index 6a1adaaa..d9dbc0b4 100644 --- a/inc/Plugin.php +++ b/inc/Plugin.php @@ -189,7 +189,7 @@ static function ( $events ) { 'description' => __( 'When a new translation ZIP file is built', 'traduttore' ), 'message' => function ( $zip_path, $zip_url, GP_Translation_Set $translation_set ) { /** @var \GP_Locale $locale */ - $locale = GP_Locales::by_slug( $translation_set->locale ); + $locale = GP_Locales::by_slug( $translation_set->locale ); $gp_project = GP::$project->get( $translation_set->project_id ); @@ -397,10 +397,10 @@ public function filter_restricted_site_access_is_restricted( bool $is_restricted * * @since 3.0.0 * - * @phpstan-param \WP_REST_Request $request - * * @param \WP_REST_Request $request Request object. * @return bool True if permission is granted, false otherwise. + * + * @phpstan-param \WP_REST_Request $request */ public function incoming_webhook_permission_callback( WP_REST_Request $request ): bool { $result = false; @@ -429,12 +429,12 @@ public function incoming_webhook_permission_callback( WP_REST_Request $request ) * * @since 3.0.0 * - * @phpstan-param \WP_REST_Request $request - * * @param \WP_REST_Request $request Request object. * @return \WP_Error|\WP_REST_Response REST response on success, error object on failure. + * + * @phpstan-param \WP_REST_Request $request */ - public function incoming_webhook_callback( WP_REST_Request $request ) { + public function incoming_webhook_callback( WP_REST_Request $request ): \WP_Error|\WP_REST_Response { $result = new \WP_Error( '400', 'Bad request' ); $handler = ( new WebhookHandlerFactory() )->get_handler( $request ); diff --git a/inc/Project.php b/inc/Project.php index 2ee33b37..cbdb5c96 100644 --- a/inc/Project.php +++ b/inc/Project.php @@ -101,7 +101,7 @@ class Project { * * @var \GP_Project Project information. */ - protected $project; + protected GP_Project $project; /** * Project constructor. diff --git a/inc/ProjectLocator.php b/inc/ProjectLocator.php index 556def8a..f9fb3593 100644 --- a/inc/ProjectLocator.php +++ b/inc/ProjectLocator.php @@ -23,16 +23,16 @@ class ProjectLocator { * * @var \Required\Traduttore\Project|null Project instance. */ - protected $project; + protected ?Project $project; /** * ProjectLocator constructor. * * @since 2.0.0 * - * @param int|string|Project|GP_Project $project Possible GlotPress project ID or path or source code repository path. + * @param int|string|false|null|\Required\Traduttore\Project|\GP_Project $project Possible GlotPress project ID or path or source code repository path. */ - public function __construct( $project ) { + public function __construct( int|string|false|\Required\Traduttore\Project|\GP_Project|null $project ) { $this->project = $this->find_project( $project ); } @@ -52,10 +52,10 @@ public function get_project(): ?Project { * * @since 2.0.0 * - * @param int|string|Project|GP_Project $project Possible GlotPress project ID or path or source code repository path. + * @param int|string|false|null|\Required\Traduttore\Project|\GP_Project $project Possible GlotPress project ID or path or source code repository path. * @return \Required\Traduttore\Project Project instance. */ - protected function find_project( $project ): ?Project { + protected function find_project( int|string|false|\Required\Traduttore\Project|\GP_Project|null $project ): ?Project { if ( ! $project ) { return null; } diff --git a/inc/Repository/Base.php b/inc/Repository/Base.php index 082e721b..661ae561 100644 --- a/inc/Repository/Base.php +++ b/inc/Repository/Base.php @@ -23,7 +23,7 @@ abstract class Base implements Repository { * * @var \Required\Traduttore\Project Project information. */ - protected $project; + protected Project $project; /** * Loader constructor. @@ -106,7 +106,7 @@ public function get_name(): string { } if ( $url ) { - $path = wp_parse_url( $url, PHP_URL_PATH ); + $path = wp_parse_url( $url, PHP_URL_PATH ); $path = $path ? trim( $path, '/' ) : ''; $parts = explode( '/', $path ); $name = implode( '/', array_splice( $parts, 0, 2 ) ); diff --git a/inc/Runner.php b/inc/Runner.php index d9a65fcf..9e5ff096 100644 --- a/inc/Runner.php +++ b/inc/Runner.php @@ -22,7 +22,7 @@ class Runner { * * @var \Required\Traduttore\Loader VCS loader. */ - protected $loader; + protected Loader $loader; /** * Updater instance. @@ -31,7 +31,7 @@ class Runner { * * @var \Required\Traduttore\Updater Translation updater. */ - protected $updater; + protected Updater $updater; /** * Runner constructor. diff --git a/inc/Updater.php b/inc/Updater.php index 8eb00ffb..dc566b50 100644 --- a/inc/Updater.php +++ b/inc/Updater.php @@ -32,7 +32,7 @@ class Updater { * * @var \Required\Traduttore\Project Project information. */ - protected $project; + protected Project $project; /** * Returns a new loader instance for a given project. @@ -221,7 +221,7 @@ protected function create_pot_file( Configuration $config ): ?string { * @return string WP-CLI binary path. */ protected function get_wp_bin(): string { - if ( \defined( 'TRADUTTORE_WP_BIN' ) && TRADUTTORE_WP_BIN ) { + if ( \defined( 'TRADUTTORE_WP_BIN' ) && \is_string( TRADUTTORE_WP_BIN ) ) { return TRADUTTORE_WP_BIN; } diff --git a/inc/WebhookHandler.php b/inc/WebhookHandler.php index 000e27b8..b75b2ee0 100644 --- a/inc/WebhookHandler.php +++ b/inc/WebhookHandler.php @@ -20,9 +20,9 @@ interface WebhookHandler { * * @since 3.0.0 * - * @phpstan-param \WP_REST_Request $request - * * @param \WP_REST_Request $request Request object. + * + * @phpstan-param \WP_REST_Request $request */ public function __construct( WP_REST_Request $request ); @@ -42,5 +42,5 @@ public function permission_callback(): ?bool; * * @return \WP_Error|\WP_REST_Response REST response on success, error object on failure. */ - public function callback(); + public function callback(): \WP_Error|\WP_REST_Response; } diff --git a/inc/WebhookHandler/Base.php b/inc/WebhookHandler/Base.php index b36cb5e5..f59f3398 100644 --- a/inc/WebhookHandler/Base.php +++ b/inc/WebhookHandler/Base.php @@ -26,16 +26,16 @@ abstract class Base implements WebhookHandler { * * @phpstan-var \WP_REST_Request */ - protected $request; + protected WP_REST_Request $request; /** * Class constructor. * * @since 3.0.0 * - * @phpstan-param \WP_REST_Request $request - * * @param \WP_REST_Request $request Request object. + * + * @phpstan-param \WP_REST_Request $request */ public function __construct( WP_REST_Request $request ) { $this->request = $request; @@ -79,7 +79,7 @@ protected function get_secret( ?Project $project = null ): ?string { * * @since 3.0.0 * - * @param string $secret Webhook sync secret. + * @param string|null $secret Webhook sync secret. * @param \Required\Traduttore\WebhookHandler $handler The current webhook handler instance. * @param \Required\Traduttore\Project|null $project The current project if passed through. */ diff --git a/inc/WebhookHandler/Bitbucket.php b/inc/WebhookHandler/Bitbucket.php index d200cb15..33fec60a 100644 --- a/inc/WebhookHandler/Bitbucket.php +++ b/inc/WebhookHandler/Bitbucket.php @@ -34,7 +34,7 @@ public function permission_callback(): ?bool { return false; } - $token = $this->request->get_header( 'x-hub-signature' ); + $token = $this->request->get_header( 'x-hub-signature-256' ); $params = $this->request->get_params(); $locator = new ProjectLocator( $params['repository']['links']['html']['href'] ?? null ); $project = $locator->get_project(); @@ -60,7 +60,7 @@ public function permission_callback(): ?bool { * * @return \WP_Error|\WP_REST_Response REST response on success, error object on failure. */ - public function callback() { + public function callback(): \WP_Error|\WP_REST_Response { $params = $this->request->get_params(); $locator = new ProjectLocator( $params['repository']['links']['html']['href'] ); diff --git a/inc/WebhookHandler/GitHub.php b/inc/WebhookHandler/GitHub.php index 6fa41384..7d548e4a 100644 --- a/inc/WebhookHandler/GitHub.php +++ b/inc/WebhookHandler/GitHub.php @@ -38,7 +38,7 @@ public function permission_callback(): ?bool { return false; } - $token = $this->request->get_header( 'x-hub-signature' ); + $token = $this->request->get_header( 'x-hub-signature-256' ); if ( ! $token ) { return false; @@ -54,7 +54,7 @@ public function permission_callback(): ?bool { return false; } - $payload_signature = 'sha1=' . hash_hmac( 'sha1', $this->request->get_body(), $secret ); + $payload_signature = 'sha256=' . hash_hmac( 'sha256', $this->request->get_body(), $secret ); return hash_equals( $token, $payload_signature ); } @@ -66,7 +66,7 @@ public function permission_callback(): ?bool { * * @return \WP_Error|\WP_REST_Response REST response on success, error object on failure. */ - public function callback() { + public function callback(): \WP_Error|\WP_REST_Response { $event_name = $this->request->get_header( 'x-github-event' ); if ( 'ping' === $event_name ) { diff --git a/inc/WebhookHandler/GitLab.php b/inc/WebhookHandler/GitLab.php index 74b25941..69c65ee3 100644 --- a/inc/WebhookHandler/GitLab.php +++ b/inc/WebhookHandler/GitLab.php @@ -60,7 +60,7 @@ public function permission_callback(): ?bool { * * @return \WP_Error|\WP_REST_Response REST response on success, error object on failure. */ - public function callback() { + public function callback(): \WP_Error|\WP_REST_Response { $params = $this->request->get_params(); // We only care about the default branch but don't want to send an error still. diff --git a/inc/WebhookHandlerFactory.php b/inc/WebhookHandlerFactory.php index d83485b6..8bfb5d67 100644 --- a/inc/WebhookHandlerFactory.php +++ b/inc/WebhookHandlerFactory.php @@ -23,10 +23,10 @@ class WebhookHandlerFactory { * * @since 3.0.0 * - * @phpstan-param \WP_REST_Request $request - * * @param \WP_REST_Request $request Request object. * @return \Required\Traduttore\WebhookHandler Webhook handler instance. + * + * @phpstan-param \WP_REST_Request $request */ public function get_handler( WP_REST_Request $request ): ?WebhookHandler { $handler = null; diff --git a/inc/ZipProvider.php b/inc/ZipProvider.php index 7c3fb28a..ed912fce 100644 --- a/inc/ZipProvider.php +++ b/inc/ZipProvider.php @@ -10,9 +10,9 @@ use DateTime; use DateTimeZone; use GP; +use GP_Locale; use GP_Locales; use GP_Translation_Set; -use InvalidArgumentException; use ZipArchive; /** @@ -42,7 +42,7 @@ class ZipProvider { * * @var \GP_Translation_Set The translation set. */ - protected $translation_set; + protected GP_Translation_Set $translation_set; /** * The current GlotPress locale. @@ -51,7 +51,7 @@ class ZipProvider { * * @var \GP_Locale The locale. */ - protected $locale; + protected GP_Locale $locale; /** * The current project. @@ -60,7 +60,7 @@ class ZipProvider { * * @var \Required\Traduttore\Project The project. */ - protected $project; + protected Project $project; /** * ZipProvider constructor. @@ -73,12 +73,13 @@ public function __construct( GP_Translation_Set $translation_set ) { $this->translation_set = $translation_set; $this->locale = GP_Locales::by_slug( $this->translation_set->locale ); + /** + * GlotPress project. + * + * @var \GP_Project $gp_project + */ $gp_project = GP::$project->get( $this->translation_set->project_id ); - if ( ! $gp_project ) { - throw new InvalidArgumentException( __( 'Project not found', 'traduttore' ) ); - } - $this->project = new Project( $gp_project ); } diff --git a/phpcs.xml.dist b/phpcs.xml.dist index 2e624dc3..55d0f1e4 100644 --- a/phpcs.xml.dist +++ b/phpcs.xml.dist @@ -2,10 +2,19 @@ Coding Standard for Traduttore + + + . - /tests/* + /tests/behat/* + /tests/features/* + /tests/phpstan/* + /tests/phpunit/data/* + /tests/phpunit/bootstrap.php - + + /tests/phpunit/tests + traduttore\.php @@ -19,6 +28,7 @@ + diff --git a/phpstan.neon.dist b/phpstan.neon.dist index ed04ac15..5d481b71 100644 --- a/phpstan.neon.dist +++ b/phpstan.neon.dist @@ -7,9 +7,11 @@ parameters: - vendor/wordpress-plugin/glotpress/gp-includes/routes/_main.php scanFiles: - vendor/php-stubs/wp-cli-stubs/wp-cli-stubs.php + - vendor/php-stubs/wordpress-tests-stubs/wordpress-tests-stubs.php scanDirectories: + - tests/phpstan/stubs/ - vendor/wordpress-plugin/glotpress/gp-includes/ - vendor/wordpress-plugin/glotpress/locales/ paths: - inc/ -# - test/ + - tests/phpunit diff --git a/tests/phpstan/stubs/factory.php b/tests/phpstan/stubs/factory.php new file mode 100644 index 00000000..8d2201c1 --- /dev/null +++ b/tests/phpstan/stubs/factory.php @@ -0,0 +1,129 @@ +factory = new GP_UnitTest_Factory(); + + global $wp_rewrite; + if ( GP_TESTS_PERMALINK_STRUCTURE != $wp_rewrite->permalink_structure ) { + $this->set_permalink_structure( GP_TESTS_PERMALINK_STRUCTURE ); + } + } + + /** + * Utility method that resets permalinks and flushes rewrites. + * + * Also updates the pre_option filter for `permalink_structure`. + * + * @global WP_Rewrite $wp_rewrite + * + * @param string $structure Optional. Permalink structure to set. Default empty. + */ + public function set_permalink_structure( $structure = '' ) { + global $wp_tests_options; + + $wp_tests_options['permalink_structure'] = $structure; + + parent::set_permalink_structure( $structure ); + } + + function clean_up_global_scope() { + parent::clean_up_global_scope(); + + $locales = &GP_Locales::instance(); + $locales->locales = []; + $_GET = []; + $_POST = []; + /** + * @todo re-initialize all thing objects + */ + GP::$translation_set = new GP_Translation_Set; + GP::$original = new GP_Original; + } + + function set_normal_user_as_current() { + $user = $this->factory->user->create(); + wp_set_current_user( $user ); + return $user; + } + + function set_admin_user_as_current() { + $admin = $this->factory->user->create_admin(); + wp_set_current_user( $admin ); + return $admin; + } +} diff --git a/tests/phpunit/bootstrap.php b/tests/phpunit/bootstrap.php index b55717ab..ca54fcbf 100644 --- a/tests/phpunit/bootstrap.php +++ b/tests/phpunit/bootstrap.php @@ -1,8 +1,6 @@ $this->variables['PROJECT_DIR'], - 'BEHAT_FEATURE_TITLE' => self::$feature->getTitle(), - 'BEHAT_SCENARIO_TITLE' => $this->scenario->getTitle(), + 'BEHAT_FEATURE_TITLE' => self::$feature ? self::$feature->getTitle() : null, + 'BEHAT_SCENARIO_TITLE' => $this->scenario ? $this->scenario->getTitle() : null, ] ), $mode @@ -150,7 +150,7 @@ public function when_i_run_the_wp_cli_command( $mode, $command ): void { * * @param string $directory Directory to ensure the existence of. */ - private function ensure_dir_exists( $directory ): void { + private function ensure_dir_exists( string $directory ): void { $parent = dirname( $directory ); if ( ! empty( $parent ) && ! is_dir( $parent ) ) { @@ -165,11 +165,11 @@ private function ensure_dir_exists( $directory ): void { /** * Create a new process with added environment variables. * - * @param string $command Command to run. - * @param array $env Associative array of environment variables to add. + * @param string $command Command to run. + * @param array $env Associative array of environment variables to add. * @return \WP_CLI\Process Process to execute. */ - public function proc_with_env( $command, $env = [] ): Process { + public function proc_with_env( string $command, array $env = [] ): Process { $env = array_merge( self::get_process_env_variables(), $env @@ -192,6 +192,8 @@ public function proc_with_env( $command, $env = [] ): Process { * Get the environment variables required for launched `wp` processes. * * This is copied over from WP_CLI\Tests\Context\FeatureContext, to enable an adaption of FeatureContext::proc(). + * + * @return array */ private static function get_process_env_variables(): array { // Ensure we're using the expected `wp` binary. diff --git a/tests/phpunit/tests/Configuration.php b/tests/phpunit/tests/Configuration.php index 35d51f34..c0e29a74 100644 --- a/tests/phpunit/tests/Configuration.php +++ b/tests/phpunit/tests/Configuration.php @@ -1,38 +1,37 @@ assertSame( dirname( __DIR__ ) . '/data/example-no-config', $config->get_path() ); + $this->assertSame( \dirname( __DIR__ ) . '/data/example-no-config', $config->get_path() ); } public function test_get_config_empty_directory(): void { - $config = new Config( dirname( __DIR__ ) . '/data/example-no-config' ); + $config = new Config( \dirname( __DIR__ ) . '/data/example-no-config' ); $this->assertEmpty( $config->get_config() ); } public function test_get_config_value_empty_directory(): void { - $config = new Config( dirname( __DIR__ ) . '/data/example-no-config' ); + $config = new Config( \dirname( __DIR__ ) . '/data/example-no-config' ); + // @phpstan-ignore-next-line $this->assertNull( $config->get_config_value( 'foo' ) ); } public function test_get_config_composer(): void { - $config = new Config( dirname( __DIR__ ) . '/data/example-with-composer' ); + $config = new Config( \dirname( __DIR__ ) . '/data/example-with-composer' ); $this->assertEqualSets( [ @@ -48,7 +47,7 @@ public function test_get_config_composer(): void { } public function test_get_config_traduttore(): void { - $config = new Config( dirname( __DIR__ ) . '/data/example-with-config' ); + $config = new Config( \dirname( __DIR__ ) . '/data/example-with-config' ); $this->assertEqualSets( [ diff --git a/tests/phpunit/tests/Export.php b/tests/phpunit/tests/Export.php index d5af5e44..9556e1f4 100644 --- a/tests/phpunit/tests/Export.php +++ b/tests/phpunit/tests/Export.php @@ -1,29 +1,26 @@ factory->locale->create( + $locale = $this->factory()->locale->create( [ 'english_name' => 'German', 'native_name' => 'Deutsch', @@ -32,7 +29,7 @@ public function setUp(): void { ] ); - $this->translation_set = $this->factory->translation_set->create_with_project( + $this->translation_set = $this->factory()->translation_set->create_with_project( [ 'locale' => $locale->slug, ], @@ -49,14 +46,14 @@ public function test_does_nothing_for_empty_translation_set(): void { } public function test_creates_only_po_and_mo_files(): void { - $original = $this->factory->original->create( + $original = $this->factory()->original->create( [ 'project_id' => $this->translation_set->project_id, 'references' => 'my-plugin.php', ] ); - $this->factory->translation->create( + $this->factory()->translation->create( [ 'original_id' => $original->id, 'translation_set_id' => $this->translation_set->id, @@ -68,6 +65,8 @@ public function test_creates_only_po_and_mo_files(): void { $actual = $export->export_strings(); + $this->assertIsArray( $actual ); + array_map( 'unlink', $actual ); $this->assertEqualSets( @@ -85,7 +84,7 @@ public function test_creates_multiple_json_files(): void { $filename_2 = 'my-super-minified-script'; /* @var \GP_Original $original_1 */ - $original_1 = $this->factory->original->create( + $original_1 = $this->factory()->original->create( [ 'project_id' => $this->translation_set->project_id, 'references' => $filename_1 . '.js', @@ -93,14 +92,14 @@ public function test_creates_multiple_json_files(): void { ); /* @var \GP_Original $original_2 */ - $original_2 = $this->factory->original->create( + $original_2 = $this->factory()->original->create( [ 'project_id' => $this->translation_set->project_id, 'references' => $filename_2 . '.min.js', ] ); - $this->factory->translation->create( + $this->factory()->translation->create( [ 'original_id' => $original_1->id, 'translation_set_id' => $this->translation_set->id, @@ -108,7 +107,7 @@ public function test_creates_multiple_json_files(): void { ] ); - $this->factory->translation->create( + $this->factory()->translation->create( [ 'original_id' => $original_2->id, 'translation_set_id' => $this->translation_set->id, @@ -120,6 +119,8 @@ public function test_creates_multiple_json_files(): void { $actual = $export->export_strings(); + $this->assertIsArray( $actual ); + $json_filename_1 = 'foo-project-de_DE-' . md5( $filename_1 . '.js' ) . '.json'; $json_filename_2 = 'foo-project-de_DE-' . md5( $filename_2 . '.js' ) . '.json'; @@ -128,6 +129,8 @@ public function test_creates_multiple_json_files(): void { array_map( 'unlink', $actual ); + $this->assertIsString( $json_1 ); + $this->assertIsString( $json_2 ); $this->assertJson( $json_1 ); $this->assertJson( $json_2 ); $this->assertEqualSets( @@ -145,9 +148,8 @@ public function test_creates_multiple_json_files(): void { /** * Modify the mapping of sources to translation entries. * - * @param array $mapping The mapping of sources to translation entries. - * - * @return array The maybe modified mapping. + * @param array $mapping The mapping of sources to translation entries. + * @return array The maybe modified mapping. */ public function filter_map_entries_to_source( array $mapping ): array { $mapping['build.js'] = array_merge( $mapping['my-super-script.js'], $mapping['my-other-script.js'] ); @@ -163,7 +165,7 @@ public function test_map_entries_to_source_filter(): void { $filename_target = 'build.js'; /* @var \GP_Original $original_1 */ - $original_1 = $this->factory->original->create( + $original_1 = $this->factory()->original->create( [ 'project_id' => $this->translation_set->project_id, 'references' => $filename_1, @@ -171,14 +173,14 @@ public function test_map_entries_to_source_filter(): void { ); /* @var \GP_Original $original_2 */ - $original_2 = $this->factory->original->create( + $original_2 = $this->factory()->original->create( [ 'project_id' => $this->translation_set->project_id, 'references' => $filename_2, ] ); - $this->factory->translation->create( + $this->factory()->translation->create( [ 'original_id' => $original_1->id, 'translation_set_id' => $this->translation_set->id, @@ -186,7 +188,7 @@ public function test_map_entries_to_source_filter(): void { ] ); - $this->factory->translation->create( + $this->factory()->translation->create( [ 'original_id' => $original_2->id, 'translation_set_id' => $this->translation_set->id, @@ -200,6 +202,8 @@ public function test_map_entries_to_source_filter(): void { $actual = $export->export_strings(); + $this->assertIsArray( $actual ); + remove_filter( 'traduttore.map_entries_to_source', [ $this, 'filter_map_entries_to_source' ] ); $json_filename_1 = 'foo-project-de_DE-' . md5( $filename_1 ) . '.json'; @@ -213,6 +217,7 @@ public function test_map_entries_to_source_filter(): void { array_map( 'unlink', $actual ); + $this->assertIsString( $json ); $this->assertJson( $json ); $this->assertEqualSets( [ @@ -230,7 +235,7 @@ public function test_js_entries_are_not_in_po_file(): void { $filename_2 = 'my-super-minified-script'; /* @var \GP_Original $original_1 */ - $original_1 = $this->factory->original->create( + $original_1 = $this->factory()->original->create( [ 'project_id' => $this->translation_set->project_id, 'references' => $filename_1 . '.js', @@ -238,7 +243,7 @@ public function test_js_entries_are_not_in_po_file(): void { ); /* @var \GP_Original $original_2 */ - $original_2 = $this->factory->original->create( + $original_2 = $this->factory()->original->create( [ 'project_id' => $this->translation_set->project_id, 'references' => $filename_2 . '.min.js', @@ -246,28 +251,28 @@ public function test_js_entries_are_not_in_po_file(): void { ); /* @var \GP_Original $original_3 */ - $original_3 = $this->factory->original->create( + $original_3 = $this->factory()->original->create( [ 'project_id' => $this->translation_set->project_id, 'references' => 'foo.php', ] ); - $this->factory->translation->create( + $this->factory()->translation->create( [ 'original_id' => $original_1->id, 'translation_set_id' => $this->translation_set->id, 'status' => 'current', ] ); - $this->factory->translation->create( + $this->factory()->translation->create( [ 'original_id' => $original_2->id, 'translation_set_id' => $this->translation_set->id, 'status' => 'current', ] ); - $this->factory->translation->create( + $this->factory()->translation->create( [ 'original_id' => $original_3->id, 'translation_set_id' => $this->translation_set->id, @@ -279,14 +284,19 @@ public function test_js_entries_are_not_in_po_file(): void { $actual = $export->export_strings(); + $this->assertIsArray( $actual ); + $translations = new PO(); $translations->import_from_file( $actual['foo-project-de_DE.po'] ); $json_filename_1 = 'foo-project-de_DE-' . md5( $filename_1 . '.js' ) . '.json'; $json_filename_2 = 'foo-project-de_DE-' . md5( $filename_2 . '.js' ) . '.json'; - $json_1 = json_decode( file_get_contents( $actual[ $json_filename_1 ] ), true ); - $json_2 = json_decode( file_get_contents( $actual[ $json_filename_2 ] ), true ); + $json_1 = json_decode( (string) file_get_contents( $actual[ $json_filename_1 ] ), true ); + $json_2 = json_decode( (string) file_get_contents( $actual[ $json_filename_2 ] ), true ); + + $this->assertIsArray( $json_1 ); + $this->assertIsArray( $json_2 ); array_map( 'unlink', $actual ); @@ -304,7 +314,7 @@ public function test_js_source_entries_are_not_exported_as_json_files(): void { $filename_3 = 'dist/build.js'; /* @var \GP_Original $original_1 */ - $original_1 = $this->factory->original->create( + $original_1 = $this->factory()->original->create( [ 'project_id' => $this->translation_set->project_id, 'references' => "$filename_1 $filename_3", @@ -312,7 +322,7 @@ public function test_js_source_entries_are_not_exported_as_json_files(): void { ); /* @var \GP_Original $original_2 */ - $original_2 = $this->factory->original->create( + $original_2 = $this->factory()->original->create( [ 'project_id' => $this->translation_set->project_id, 'references' => "$filename_2 $filename_3", @@ -320,28 +330,28 @@ public function test_js_source_entries_are_not_exported_as_json_files(): void { ); /* @var \GP_Original $original_3 */ - $original_3 = $this->factory->original->create( + $original_3 = $this->factory()->original->create( [ 'project_id' => $this->translation_set->project_id, 'references' => $filename_3, ] ); - $this->factory->translation->create( + $this->factory()->translation->create( [ 'original_id' => $original_1->id, 'translation_set_id' => $this->translation_set->id, 'status' => 'current', ] ); - $this->factory->translation->create( + $this->factory()->translation->create( [ 'original_id' => $original_2->id, 'translation_set_id' => $this->translation_set->id, 'status' => 'current', ] ); - $this->factory->translation->create( + $this->factory()->translation->create( [ 'original_id' => $original_3->id, 'translation_set_id' => $this->translation_set->id, @@ -353,9 +363,11 @@ public function test_js_source_entries_are_not_exported_as_json_files(): void { $actual = $export->export_strings(); + $this->assertIsArray( $actual ); + $json_filename = 'foo-project-de_DE-' . md5( $filename_3 ) . '.json'; - $json = json_decode( file_get_contents( $actual[ $json_filename ] ), true ); + $json = json_decode( (string) file_get_contents( $actual[ $json_filename ] ), true ); array_map( 'unlink', $actual ); @@ -379,14 +391,14 @@ public function test_json_files_include_file_reference_comment(): void { $filename_1 = 'my-super-script'; /* @var \GP_Original $original_1 */ - $original_1 = $this->factory->original->create( + $original_1 = $this->factory()->original->create( [ 'project_id' => $this->translation_set->project_id, 'references' => $filename_1 . '.js', ] ); - $this->factory->translation->create( + $this->factory()->translation->create( [ 'original_id' => $original_1->id, 'translation_set_id' => $this->translation_set->id, @@ -398,15 +410,18 @@ public function test_json_files_include_file_reference_comment(): void { $actual = $export->export_strings(); + $this->assertIsArray( $actual ); + $json_filename_1 = 'foo-project-de_DE-' . md5( $filename_1 . '.js' ) . '.json'; $json_1 = file_get_contents( $actual[ $json_filename_1 ] ); array_map( 'unlink', $actual ); + $this->assertIsString( $json_1 ); $this->assertJson( $json_1 ); - $json1_encoded = json_decode( $json_1 ); + $json1_encoded = (object) json_decode( $json_1 ); $this->assertSame( $filename_1 . '.js', $json1_encoded->comment->reference ); } } diff --git a/tests/phpunit/tests/Loader/Git.php b/tests/phpunit/tests/Loader/Git.php index b5fa1662..c782429c 100644 --- a/tests/phpunit/tests/Loader/Git.php +++ b/tests/phpunit/tests/Loader/Git.php @@ -1,14 +1,12 @@ project = new Project( - $this->factory->project->create( + $this->factory()->project->create( [ 'name' => 'Sample Project', 'slug' => 'sample-project', @@ -44,8 +42,9 @@ public function test_get_local_path(): void { } public function test_download_repository(): void { - $this->markTestSkipped( 'Need to mock shell command execution' ); + $this->markTestIncomplete( 'Need to mock shell command execution' ); + // @phpstan-ignore-next-line $loader = new GitLoader( new GitHub( $this->project ) ); add_filter( 'traduttore.git_clone_use_https', '__return_true' ); @@ -56,8 +55,9 @@ public function test_download_repository(): void { } public function test_download_existing_repository(): void { - $this->markTestSkipped( 'Need to mock shell command execution' ); + $this->markTestIncomplete( 'Need to mock shell command execution' ); + // @phpstan-ignore-next-line $loader = new GitLoader( new GitHub( $this->project ) ); add_filter( 'traduttore.git_clone_use_https', '__return_true' ); diff --git a/tests/phpunit/tests/Loader/Mercurial.php b/tests/phpunit/tests/Loader/Mercurial.php index 5694f791..8fbc0dc5 100644 --- a/tests/phpunit/tests/Loader/Mercurial.php +++ b/tests/phpunit/tests/Loader/Mercurial.php @@ -1,14 +1,12 @@ project = new Project( - $this->factory->project->create( + $this->factory()->project->create( [ 'name' => 'Sample Project', 'slug' => 'sample-project', @@ -44,8 +42,9 @@ public function test_get_local_path(): void { } public function test_download_repository(): void { - $this->markTestSkipped( 'Need to mock shell command execution' ); + $this->markTestIncomplete( 'Need to mock shell command execution' ); + // @phpstan-ignore-next-line $loader = new MercurialLoader( new Bitbucket( $this->project ) ); add_filter( 'traduttore.hg_clone_use_https', '__return_true' ); @@ -56,8 +55,9 @@ public function test_download_repository(): void { } public function test_download_existing_repository(): void { - $this->markTestSkipped( 'Need to mock shell command execution' ); + $this->markTestIncomplete( 'Need to mock shell command execution' ); + // @phpstan-ignore-next-line $loader = new MercurialLoader( new Bitbucket( $this->project ) ); add_filter( 'traduttore.hg_clone_use_https', '__return_true' ); diff --git a/tests/phpunit/tests/Loader/Subversion.php b/tests/phpunit/tests/Loader/Subversion.php index 6213f1b3..ebc88d21 100644 --- a/tests/phpunit/tests/Loader/Subversion.php +++ b/tests/phpunit/tests/Loader/Subversion.php @@ -1,14 +1,12 @@ project = new Project( - $this->factory->project->create( + $this->factory()->project->create( [ 'name' => 'Sample Project', 'slug' => 'sample-project', @@ -44,8 +42,9 @@ public function test_get_local_path(): void { } public function test_download_repository(): void { - $this->markTestSkipped( 'Need to mock shell command execution' ); + $this->markTestIncomplete( 'Need to mock shell command execution' ); + // @phpstan-ignore-next-line $loader = new SubversionLoader( new Bitbucket( $this->project ) ); add_filter( 'traduttore.svn_checkout_use_https', '__return_true' ); @@ -56,8 +55,9 @@ public function test_download_repository(): void { } public function test_download_existing_repository(): void { - $this->markTestSkipped( 'Need to mock shell command execution' ); + $this->markTestIncomplete( 'Need to mock shell command execution' ); + // @phpstan-ignore-next-line $loader = new SubversionLoader( new Bitbucket( $this->project ) ); add_filter( 'traduttore.svn_checkout_use_https', '__return_true' ); diff --git a/tests/phpunit/tests/LoaderFactory.php b/tests/phpunit/tests/LoaderFactory.php index 938d9a4d..ad367a19 100644 --- a/tests/phpunit/tests/LoaderFactory.php +++ b/tests/phpunit/tests/LoaderFactory.php @@ -1,16 +1,16 @@ factory->project->create( + $this->factory()->project->create( [ 'name' => 'Project', ] @@ -39,7 +39,7 @@ public function test_get_mercurial_loader(): void { public function test_get_git_loader_for_bitbucket_repository(): void { $factory = new Factory(); $project = new Project( - $this->factory->project->create( + $this->factory()->project->create( [ 'name' => 'Project', ] @@ -54,7 +54,7 @@ public function test_get_git_loader_for_bitbucket_repository(): void { public function test_get_git_loader_for_github_repository(): void { $factory = new Factory(); $project = new Project( - $this->factory->project->create( + $this->factory()->project->create( [ 'name' => 'Project', ] @@ -69,7 +69,7 @@ public function test_get_git_loader_for_github_repository(): void { public function test_get_git_loader_for_gitlab_repository(): void { $factory = new Factory(); $project = new Project( - $this->factory->project->create( + $this->factory()->project->create( [ 'name' => 'Project', ] diff --git a/tests/phpunit/tests/Project.php b/tests/phpunit/tests/Project.php index dfbbe78e..0bdf88e8 100644 --- a/tests/phpunit/tests/Project.php +++ b/tests/phpunit/tests/Project.php @@ -1,34 +1,31 @@ gp_project = $this->factory->project->create( + $this->gp_project = $this->factory()->project->create( [ 'name' => 'Project', 'active' => 1, @@ -159,7 +156,7 @@ public function test_get_last_updated_time(): void { $this->project->set_last_updated_time( $time ); $this->assertInstanceOf( DateTime::class, $this->project->get_last_updated_time() ); - $this->assertSame( $time->getTimestamp(), $this->project->get_last_updated_time()->getTimestamp(), 'Last updated time is not identical', 1 ); + $this->assertSame( $time->getTimestamp(), $this->project->get_last_updated_time()->getTimestamp(), 'Last updated time is not identical' ); } public function test_get_repository_webhook_secret(): void { diff --git a/tests/phpunit/tests/ProjectLocator.php b/tests/phpunit/tests/ProjectLocator.php index b58c3201..1c42ffd8 100644 --- a/tests/phpunit/tests/ProjectLocator.php +++ b/tests/phpunit/tests/ProjectLocator.php @@ -1,14 +1,12 @@ root = $this->factory->project->create( + $this->root = $this->factory()->project->create( [ 'name' => 'Root', ] ); - $this->sub = $this->factory->project->create( + $this->sub = $this->factory()->project->create( [ 'name' => 'Sub', 'parent_project_id' => $this->root->id, ] ); - $this->subsub = $this->factory->project->create( + $this->subsub = $this->factory()->project->create( [ 'name' => 'SubSub', 'parent_project_id' => $this->sub->id, @@ -81,48 +79,55 @@ public function test_existing_glotpress_project_instance(): void { $project = $this->root; $locator = new Locator( $project ); + $this->assertInstanceOf( Project::class, $locator->get_project() ); $this->assertSame( $this->root->id, $locator->get_project()->get_id() ); } public function test_find_project_by_glotpress_path(): void { $locator = new Locator( 'root' ); + $this->assertInstanceOf( Project::class, $locator->get_project() ); $this->assertSame( $this->root->id, $locator->get_project()->get_id() ); } public function test_find_project_by_glotpress_subpath(): void { $locator = new Locator( 'root/sub' ); + $this->assertInstanceOf( Project::class, $locator->get_project() ); $this->assertSame( $this->sub->id, $locator->get_project()->get_id() ); } public function test_find_project_by_glotpress_subsubpath(): void { $locator = new Locator( 'root/sub/subsub' ); + $this->assertInstanceOf( Project::class, $locator->get_project() ); $this->assertSame( $this->subsub->id, $locator->get_project()->get_id() ); } public function test_find_project_by_glotpress_id(): void { $locator = new Locator( (int) $this->sub->id ); + $this->assertInstanceOf( Project::class, $locator->get_project() ); $this->assertSame( $this->sub->id, $locator->get_project()->get_id() ); } public function test_find_project_by_glotpress_id_as_string(): void { $locator = new Locator( (string) $this->sub->id ); + $this->assertInstanceOf( Project::class, $locator->get_project() ); $this->assertSame( $this->sub->id, $locator->get_project()->get_id() ); } public function test_find_project_by_github_url(): void { $locator = new Locator( 'https://github.com/wearerequired/traduttore' ); + $this->assertInstanceOf( Project::class, $locator->get_project() ); $this->assertSame( $this->subsub->id, $locator->get_project()->get_id() ); } public function test_find_project_by_repository_name(): void { $project = new Project( - $this->factory->project->create( + $this->factory()->project->create( [ 'name' => 'Foo Bar', ] @@ -133,12 +138,13 @@ public function test_find_project_by_repository_name(): void { $locator = new Locator( 'wearerequired/traduttore-registry' ); + $this->assertInstanceOf( Project::class, $locator->get_project() ); $this->assertSame( $project->get_id(), $locator->get_project()->get_id() ); } public function test_find_project_by_repository_url(): void { $project = new Project( - $this->factory->project->create( + $this->factory()->project->create( [ 'name' => 'Foo Bar', ] @@ -149,6 +155,7 @@ public function test_find_project_by_repository_url(): void { $locator = new Locator( 'https://github.com/wearerequired/traduttore-registry' ); + $this->assertInstanceOf( Project::class, $locator->get_project() ); $this->assertSame( $project->get_id(), $locator->get_project()->get_id() ); } } diff --git a/tests/phpunit/tests/Repository/Bitbucket.php b/tests/phpunit/tests/Repository/Bitbucket.php index a3243351..72134010 100644 --- a/tests/phpunit/tests/Repository/Bitbucket.php +++ b/tests/phpunit/tests/Repository/Bitbucket.php @@ -1,36 +1,33 @@ project = new Project( - $this->factory->project->create( + $this->factory()->project->create( [ 'name' => 'Project', ] @@ -54,7 +51,7 @@ public function test_get_name_falls_back_to_project_slug(): void { public function test_get_name_falls_back_to_source_url_template(): void { $project = new Project( - $this->factory->project->create( + $this->factory()->project->create( [ 'name' => 'Project', 'source_url_template' => 'https://bitbucket.org/wearerequired/traduttore/src/master/%file%#L%line%', @@ -89,11 +86,11 @@ public function test_get_name(): void { * @param false $preempt Whether to preempt an HTTP request's return value. Default false. * @param mixed $r HTTP request arguments. * @param string $url The request URL. - * @return array|false Response data. + * @return array{response: array{ code: int }, body: string}|false Response data. */ - public function mock_repository_visibility_request( $preempt, $r, $url ) { + public function mock_repository_visibility_request( false $preempt, mixed $r, string $url ): array|false { if ( BitbucketRepository::API_BASE . '/repositories/wearerequired/traduttore' === $url ) { - ++ $this->http_request_count; + ++$this->http_request_count; return [ 'response' => [ @@ -109,7 +106,7 @@ public function mock_repository_visibility_request( $preempt, $r, $url ) { public function test_is_public_performs_http_request_and_caches_it(): void { $this->project->set_repository_name( 'wearerequired/traduttore' ); - add_filter( 'pre_http_request', array( $this, 'mock_repository_visibility_request' ), 10, 3 ); + add_filter( 'pre_http_request', [ $this, 'mock_repository_visibility_request' ], 10, 3 ); $repository = new BitbucketRepository( $this->project ); @@ -118,7 +115,7 @@ public function test_is_public_performs_http_request_and_caches_it(): void { $is_public_after = $repository->is_public(); $visibility_after = $repository->get_project()->get_repository_visibility(); - remove_filter( 'pre_http_request', array( $this, 'mock_repository_visibility_request' ), 10 ); + remove_filter( 'pre_http_request', [ $this, 'mock_repository_visibility_request' ], 10 ); $this->assertNull( $visibility_before ); $this->assertTrue( $is_public ); @@ -130,7 +127,7 @@ public function test_is_public_performs_http_request_and_caches_it(): void { public function test_is_public_performs_no_unnecessary_http_request(): void { $this->project->set_repository_name( 'wearerequired/traduttore' ); - add_filter( 'pre_http_request', array( $this, 'mock_repository_visibility_request' ), 10, 3 ); + add_filter( 'pre_http_request', [ $this, 'mock_repository_visibility_request' ], 10, 3 ); $this->project->set_repository_visibility( 'private' ); @@ -139,7 +136,7 @@ public function test_is_public_performs_no_unnecessary_http_request(): void { $visibility_before = $repository->get_project()->get_repository_visibility(); $is_public = $repository->is_public(); - remove_filter( 'pre_http_request', array( $this, 'mock_repository_visibility_request' ), 10 ); + remove_filter( 'pre_http_request', [ $this, 'mock_repository_visibility_request' ], 10 ); $this->assertSame( 'private', $visibility_before ); $this->assertFalse( $is_public ); @@ -273,9 +270,7 @@ public function test_get_https_url_with_credentials(): void { add_filter( 'traduttore.git_https_credentials', - function() { - return 'foo:bar'; - } + fn() => 'foo:bar' ); $url = $repository->get_https_url(); @@ -291,9 +286,7 @@ public function test_get_https_url_with_credentials_for_ht_repository(): void { add_filter( 'traduttore.hg_https_credentials', - function() { - return 'foo:bar'; - } + fn() => 'foo:bar' ); $url = $repository->get_https_url(); diff --git a/tests/phpunit/tests/Repository/GitHub.php b/tests/phpunit/tests/Repository/GitHub.php index 53b110e3..eb14bf24 100644 --- a/tests/phpunit/tests/Repository/GitHub.php +++ b/tests/phpunit/tests/Repository/GitHub.php @@ -1,36 +1,33 @@ project = new Project( - $this->factory->project->create( + $this->factory()->project->create( [ 'name' => 'Project', ] @@ -54,7 +51,7 @@ public function test_get_name_falls_back_to_project_slug(): void { public function test_get_name_falls_back_to_source_url_template(): void { $project = new Project( - $this->factory->project->create( + $this->factory()->project->create( [ 'name' => 'Project', 'source_url_template' => 'https://github.com/wearerequired/traduttore/blob/master/%file%#L%line%', @@ -69,7 +66,7 @@ public function test_get_name_falls_back_to_source_url_template(): void { public function test_get_name_falls_back_to_different_source_url_template(): void { $project = new Project( - $this->factory->project->create( + $this->factory()->project->create( [ 'name' => 'Project', 'source_url_template' => 'https://github.com/wearerequired/traduttore/tree/master/%file%#L%line%', @@ -104,11 +101,11 @@ public function test_get_name(): void { * @param false $preempt Whether to preempt an HTTP request's return value. Default false. * @param mixed $r HTTP request arguments. * @param string $url The request URL. - * @return array|false Response data. + * @return array{response: array{ code: int }, body: string}|false Response data. */ - public function mock_repository_visibility_request( $preempt, $r, $url ) { + public function mock_repository_visibility_request( false $preempt, mixed $r, string $url ): array|false { if ( GitHubRepository::API_BASE . '/repos/wearerequired/traduttore' === $url ) { - ++ $this->http_request_count; + ++$this->http_request_count; return [ 'response' => [ @@ -124,7 +121,7 @@ public function mock_repository_visibility_request( $preempt, $r, $url ) { public function test_is_public_performs_http_request_and_caches_it(): void { $this->project->set_repository_name( 'wearerequired/traduttore' ); - add_filter( 'pre_http_request', array( $this, 'mock_repository_visibility_request' ), 10, 3 ); + add_filter( 'pre_http_request', [ $this, 'mock_repository_visibility_request' ], 10, 3 ); $repository = new GitHubRepository( $this->project ); @@ -133,7 +130,7 @@ public function test_is_public_performs_http_request_and_caches_it(): void { $is_public_after = $repository->is_public(); $visibility_after = $repository->get_project()->get_repository_visibility(); - remove_filter( 'pre_http_request', array( $this, 'mock_repository_visibility_request' ), 10 ); + remove_filter( 'pre_http_request', [ $this, 'mock_repository_visibility_request' ], 10 ); $this->assertNull( $visibility_before ); $this->assertTrue( $is_public ); @@ -145,7 +142,7 @@ public function test_is_public_performs_http_request_and_caches_it(): void { public function test_is_public_performs_no_unnecessary_http_request(): void { $this->project->set_repository_name( 'wearerequired/traduttore' ); - add_filter( 'pre_http_request', array( $this, 'mock_repository_visibility_request' ), 10, 3 ); + add_filter( 'pre_http_request', [ $this, 'mock_repository_visibility_request' ], 10, 3 ); $this->project->set_repository_visibility( 'private' ); @@ -154,7 +151,7 @@ public function test_is_public_performs_no_unnecessary_http_request(): void { $visibility_before = $repository->get_project()->get_repository_visibility(); $is_public = $repository->is_public(); - remove_filter( 'pre_http_request', array( $this, 'mock_repository_visibility_request' ), 10 ); + remove_filter( 'pre_http_request', [ $this, 'mock_repository_visibility_request' ], 10 ); $this->assertSame( 'private', $visibility_before ); $this->assertFalse( $is_public ); diff --git a/tests/phpunit/tests/Repository/GitLab.php b/tests/phpunit/tests/Repository/GitLab.php index cafaf07f..0e0eed6e 100644 --- a/tests/phpunit/tests/Repository/GitLab.php +++ b/tests/phpunit/tests/Repository/GitLab.php @@ -1,36 +1,33 @@ project = new Project( - $this->factory->project->create( + $this->factory()->project->create( [ 'name' => 'Project', ] @@ -54,7 +51,7 @@ public function test_get_name_falls_back_to_project_slug(): void { public function test_get_name_falls_back_to_source_url_template(): void { $project = new Project( - $this->factory->project->create( + $this->factory()->project->create( [ 'name' => 'Project', 'source_url_template' => 'https://gitlab.com/wearerequired/traduttore/blob/master/%file%#L%line%', @@ -103,11 +100,11 @@ public function test_get_host(): void { * @param false $preempt Whether to preempt an HTTP request's return value. Default false. * @param mixed $r HTTP request arguments. * @param string $url The request URL. - * @return array|false Response data. + * @return array{response: array{ code: int }, body: string}|false Response data. */ - public function mock_repository_visibility_request( $preempt, $r, $url ) { + public function mock_repository_visibility_request( false $preempt, mixed $r, string $url ): array|false { if ( GitLabRepository::API_BASE . '/projects/wearerequired%2Ftraduttore' === $url ) { - ++ $this->http_request_count; + ++$this->http_request_count; return [ 'response' => [ @@ -123,7 +120,7 @@ public function mock_repository_visibility_request( $preempt, $r, $url ) { public function test_is_public_performs_http_request_and_caches_it(): void { $this->project->set_repository_name( 'wearerequired/traduttore' ); - add_filter( 'pre_http_request', array( $this, 'mock_repository_visibility_request' ), 10, 3 ); + add_filter( 'pre_http_request', [ $this, 'mock_repository_visibility_request' ], 10, 3 ); $repository = new GitLabRepository( $this->project ); @@ -132,7 +129,7 @@ public function test_is_public_performs_http_request_and_caches_it(): void { $is_public_after = $repository->is_public(); $visibility_after = $repository->get_project()->get_repository_visibility(); - remove_filter( 'pre_http_request', array( $this, 'mock_repository_visibility_request' ), 10 ); + remove_filter( 'pre_http_request', [ $this, 'mock_repository_visibility_request' ], 10 ); $this->assertNull( $visibility_before ); $this->assertTrue( $is_public ); @@ -144,7 +141,7 @@ public function test_is_public_performs_http_request_and_caches_it(): void { public function test_is_public_performs_no_unnecessary_http_request(): void { $this->project->set_repository_name( 'wearerequired/traduttore' ); - add_filter( 'pre_http_request', array( $this, 'mock_repository_visibility_request' ), 10, 3 ); + add_filter( 'pre_http_request', [ $this, 'mock_repository_visibility_request' ], 10, 3 ); $this->project->set_repository_visibility( 'private' ); @@ -153,7 +150,7 @@ public function test_is_public_performs_no_unnecessary_http_request(): void { $visibility_before = $repository->get_project()->get_repository_visibility(); $is_public = $repository->is_public(); - remove_filter( 'pre_http_request', array( $this, 'mock_repository_visibility_request' ), 10 ); + remove_filter( 'pre_http_request', [ $this, 'mock_repository_visibility_request' ], 10 ); $this->assertSame( 'private', $visibility_before ); $this->assertFalse( $is_public ); diff --git a/tests/phpunit/tests/RepositoryFactory.php b/tests/phpunit/tests/RepositoryFactory.php index c431d010..b378b247 100644 --- a/tests/phpunit/tests/RepositoryFactory.php +++ b/tests/phpunit/tests/RepositoryFactory.php @@ -1,15 +1,15 @@ factory->project->create( + $this->factory()->project->create( [ 'name' => 'Project', ] @@ -31,7 +31,7 @@ public function test_get_unknown_repository(): void { public function test_get_unknown_repository_by_type(): void { $factory = new Factory(); $project = new Project( - $this->factory->project->create( + $this->factory()->project->create( [ 'name' => 'Project', ] @@ -46,7 +46,7 @@ public function test_get_unknown_repository_by_type(): void { public function test_get_bitbucket_repository_by_type(): void { $factory = new Factory(); $project = new Project( - $this->factory->project->create( + $this->factory()->project->create( [ 'name' => 'Project', ] @@ -61,7 +61,7 @@ public function test_get_bitbucket_repository_by_type(): void { public function test_get_bitbucket_repository_by_url(): void { $factory = new Factory(); $project = new Project( - $this->factory->project->create( + $this->factory()->project->create( [ 'name' => 'Project', ] @@ -76,7 +76,7 @@ public function test_get_bitbucket_repository_by_url(): void { public function test_get_bitbucket_repository_by_source_url_template(): void { $factory = new Factory(); $project = new Project( - $this->factory->project->create( + $this->factory()->project->create( [ 'name' => 'Project', 'source_url_template' => 'https://bitbucket.org/wearerequired/traduttore/src/master/%file%#L%line%', @@ -90,7 +90,7 @@ public function test_get_bitbucket_repository_by_source_url_template(): void { public function test_get_github_repository_by_type(): void { $factory = new Factory(); $project = new Project( - $this->factory->project->create( + $this->factory()->project->create( [ 'name' => 'Project', ] @@ -105,7 +105,7 @@ public function test_get_github_repository_by_type(): void { public function test_get_github_repository_by_url(): void { $factory = new Factory(); $project = new Project( - $this->factory->project->create( + $this->factory()->project->create( [ 'name' => 'Project', ] @@ -120,7 +120,7 @@ public function test_get_github_repository_by_url(): void { public function test_get_github_repository_by_source_url_template(): void { $factory = new Factory(); $project = new Project( - $this->factory->project->create( + $this->factory()->project->create( [ 'name' => 'Project', 'source_url_template' => 'https://github.com/wearerequired/traduttore/blob/master/%file%#L%line%', @@ -134,7 +134,7 @@ public function test_get_github_repository_by_source_url_template(): void { public function test_get_gitlab_repository_by_type(): void { $factory = new Factory(); $project = new Project( - $this->factory->project->create( + $this->factory()->project->create( [ 'name' => 'Project', ] @@ -149,7 +149,7 @@ public function test_get_gitlab_repository_by_type(): void { public function test_get_gitlab_repository_by_source_url_template(): void { $factory = new Factory(); $project = new Project( - $this->factory->project->create( + $this->factory()->project->create( [ 'name' => 'Project', 'source_url_template' => 'https://gitlab.com/wearerequired/traduttore/blob/master/%file%#L%line%', diff --git a/tests/phpunit/tests/RestrictedSiteAccess.php b/tests/phpunit/tests/RestrictedSiteAccess.php index d086b539..a47301a5 100644 --- a/tests/phpunit/tests/RestrictedSiteAccess.php +++ b/tests/phpunit/tests/RestrictedSiteAccess.php @@ -1,8 +1,6 @@ project = new Project( - $this->factory->project->create( + $this->factory()->project->create( [ 'name' => 'Sample Project', 'slug' => 'sample-project', diff --git a/tests/phpunit/tests/TestCase.php b/tests/phpunit/tests/TestCase.php index c4555a7d..351688c9 100644 --- a/tests/phpunit/tests/TestCase.php +++ b/tests/phpunit/tests/TestCase.php @@ -1,14 +1,12 @@ as_error(); } @@ -31,6 +38,7 @@ protected function assertErrorResponse( $code, $response, $status = null ): void $this->assertSame( $code, $response->get_error_code() ); if ( null !== $status ) { $data = $response->get_error_data(); + $this->assertIsArray( $data ); $this->assertArrayHasKey( 'status', $data ); $this->assertSame( $status, $data['status'] ); } diff --git a/tests/phpunit/tests/TranslationApiRoute.php b/tests/phpunit/tests/TranslationApiRoute.php index b8d19698..a722d89f 100644 --- a/tests/phpunit/tests/TranslationApiRoute.php +++ b/tests/phpunit/tests/TranslationApiRoute.php @@ -1,15 +1,16 @@ locale = $this->factory->locale->create( + $this->locale = $this->factory()->locale->create( [ 'english_name' => 'German', 'native_name' => 'Deutsch', @@ -41,7 +52,7 @@ public function setUp(): void { ] ); - $this->translation_set = $this->factory->translation_set->create_with_project( + $this->translation_set = $this->factory()->translation_set->create_with_project( [ 'locale' => $this->locale->slug, ], @@ -52,7 +63,6 @@ public function setUp(): void { } public function tearDown(): void { - /* @var \WP_Filesystem_Base $wp_filesystem */ global $wp_filesystem; if ( ! $wp_filesystem ) { @@ -70,17 +80,30 @@ public function assert404(): void { $this->assertSame( 404, $this->route->http_status ); } - protected function get_route_callback( $project_path ) { + /** + * @return array{error?: string, translations?: array>} Response data. + */ + protected function get_route_callback( string $project_path ): array { $route = $this->route; + /** + * Route response. + * + * @var string $response + */ $response = get_echo( - function() use ( $route, $project_path ) { - /** @var Route $route */ - return $route->route_callback( $project_path ); + function () use ( $route, $project_path ): void { + /** @var \Required\Traduttore\TranslationApiRoute $route */ + $route->route_callback( $project_path ); } ); - return json_decode( $response, true ); + /** + * @var array{error?: string, translations?: array>} $result + */ + $result = (array) json_decode( $response, true ); + + return $result; } /** @@ -92,7 +115,14 @@ public function test_route_exists(): void { $property = $class->getProperty( 'urls' ); $property->setAccessible( true ); - $this->assertTrue( isset( $property->getValue( GP::$router )['get:/api/translations/(.+?)'] ) ); + /** + * Registered routes. + * + * @var array $routes + */ + $routes = $property->getValue( GP::$router ); + + $this->assertTrue( isset( $routes['get:/api/translations/(.+?)'] ) ); } public function test_invalid_project(): void { @@ -110,9 +140,9 @@ public function test_no_zip_files(): void { } public function test_one_zip_file(): void { - $original = $this->factory->original->create( [ 'project_id' => $this->translation_set->project_id ] ); + $original = $this->factory()->original->create( [ 'project_id' => $this->translation_set->project_id ] ); - $this->factory->translation->create( + $this->factory()->translation->create( [ 'original_id' => $original->id, 'translation_set_id' => $this->translation_set->id, @@ -126,6 +156,7 @@ public function test_one_zip_file(): void { $response = $this->get_route_callback( 'foo-project' ); + $this->assertArrayHasKey( 'translations', $response ); $this->assertCount( 1, $response['translations'] ); $this->assertArrayHasKey( 'language', $response['translations'][0] ); $this->assertSame( 'de_DE', $response['translations'][0]['language'] ); @@ -140,9 +171,9 @@ public function test_one_zip_file(): void { } public function test_missing_build_time(): void { - $original = $this->factory->original->create( [ 'project_id' => $this->translation_set->project_id ] ); + $original = $this->factory()->original->create( [ 'project_id' => $this->translation_set->project_id ] ); - $this->factory->translation->create( + $this->factory()->translation->create( [ 'original_id' => $original->id, 'translation_set_id' => $this->translation_set->id, @@ -158,16 +189,20 @@ public function test_missing_build_time(): void { $response = $this->get_route_callback( 'foo-project' ); + $this->assertArrayHasKey( 'translations', $response ); $this->assertCount( 0, $response['translations'] ); } public function test_uses_stored_project_version(): void { $project = ( new \Required\Traduttore\ProjectLocator( $this->translation_set->project_id ) )->get_project(); + + $this->assertInstanceOf( \Required\Traduttore\Project::class, $project ); + $project->set_version( '1.2.3' ); - $original = $this->factory->original->create( [ 'project_id' => $this->translation_set->project_id ] ); + $original = $this->factory()->original->create( [ 'project_id' => $this->translation_set->project_id ] ); - $this->factory->translation->create( + $this->factory()->translation->create( [ 'original_id' => $original->id, 'translation_set_id' => $this->translation_set->id, @@ -181,7 +216,7 @@ public function test_uses_stored_project_version(): void { $response = $this->get_route_callback( 'foo-project' ); - $this->assertCount( 1, $response['translations'] ); + $this->assertArrayHasKey( 'translations', $response ); $this->assertCount( 1, $response['translations'] ); $this->assertArrayHasKey( 'language', $response['translations'][0] ); $this->assertSame( 'de_DE', $response['translations'][0]['language'] ); diff --git a/tests/phpunit/tests/Updater.php b/tests/phpunit/tests/Updater.php index d9c4d237..fd731018 100644 --- a/tests/phpunit/tests/Updater.php +++ b/tests/phpunit/tests/Updater.php @@ -1,28 +1,26 @@ project = new Project( - $this->factory->project->create( + $this->factory()->project->create( [ 'name' => 'Sample Project', 'slug' => 'sample-project', @@ -43,7 +41,7 @@ public function setUp(): void { } public function test_update_without_config(): void { - $config = new Configuration( dirname( __DIR__ ) . '/data/example-no-config' ); + $config = new Configuration( \dirname( __DIR__ ) . '/data/example-no-config' ); $result = $this->updater->update( $config ); @@ -57,7 +55,7 @@ public function test_update_without_config(): void { } public function test_update_with_composer_config(): void { - $config = new Configuration( dirname( __DIR__ ) . '/data/example-with-composer' ); + $config = new Configuration( \dirname( __DIR__ ) . '/data/example-with-composer' ); $result = $this->updater->update( $config ); @@ -71,7 +69,7 @@ public function test_update_with_composer_config(): void { } public function test_update_with_config_file(): void { - $config = new Configuration( dirname( __DIR__ ) . '/data/example-with-config' ); + $config = new Configuration( \dirname( __DIR__ ) . '/data/example-with-config' ); $result = $this->updater->update( $config ); @@ -109,7 +107,7 @@ public function test_schedule_update_unschedules_existing_event(): void { foreach ( $crons as $timestamp => $cron ) { if ( isset( $cron['traduttore.update'][ $key ] ) ) { - $scheduled_count ++; + $scheduled_count++; } } @@ -121,7 +119,7 @@ public function test_schedule_update_unschedules_existing_event(): void { foreach ( $crons as $timestamp => $cron ) { if ( isset( $cron['traduttore.update'][ $key ] ) ) { - $scheduled_count ++; + $scheduled_count++; } } @@ -135,7 +133,7 @@ public function test_schedule_update_unschedules_existing_event(): void { foreach ( $crons as $timestamp => $cron ) { if ( isset( $cron['traduttore.update'][ $key ] ) ) { - $scheduled_count ++; + $scheduled_count++; } } diff --git a/tests/phpunit/tests/WebhookHandler/Bitbucket.php b/tests/phpunit/tests/WebhookHandler/Bitbucket.php index 979d29cd..6e6bc808 100644 --- a/tests/phpunit/tests/WebhookHandler/Bitbucket.php +++ b/tests/phpunit/tests/WebhookHandler/Bitbucket.php @@ -1,8 +1,6 @@ project = new Project( - $this->factory->project->create( + $this->factory()->project->create( [ 'name' => 'Sample Project', 'source_url_template' => 'https://bitbucket.org/wearerequired/traduttore/blob/master/%file%#L%line%', @@ -52,9 +47,9 @@ public function test_invalid_event_header(): void { public function test_invalid_signature(): void { $request = new WP_REST_Request( 'POST', '/traduttore/v1/incoming-webhook' ); $request->set_body_params( [] ); - $signature = 'sha256=' . hash_hmac( 'sha256', wp_json_encode( $request->get_params() ), 'foo' ); + $signature = 'sha256=' . hash_hmac( 'sha256', (string) wp_json_encode( $request->get_params() ), 'foo' ); $request->add_header( 'x-event-key', 'repo:push' ); - $request->add_header( 'x-hub-signature', $signature ); + $request->add_header( 'x-hub-signature-256', $signature ); $response = rest_get_server()->dispatch( $request ); $this->assertErrorResponse( 'rest_forbidden', $response, 401 ); @@ -100,9 +95,9 @@ public function test_invalid_project(): void { ], ] ); - $signature = 'sha256=' . hash_hmac( 'sha256', wp_json_encode( $request->get_params() ), 'traduttore-test' ); + $signature = 'sha256=' . hash_hmac( 'sha256', (string) wp_json_encode( $request->get_params() ), 'traduttore-test' ); $request->add_header( 'x-event-key', 'repo:push' ); - $request->add_header( 'x-hub-signature', $signature ); + $request->add_header( 'x-hub-signature-256', $signature ); $response = rest_get_server()->dispatch( $request ); $this->assertErrorResponse( 404, $response ); @@ -125,9 +120,9 @@ public function test_valid_project(): void { ], ] ); - $signature = 'sha256=' . hash_hmac( 'sha256', wp_json_encode( $request->get_params() ), 'traduttore-test' ); + $signature = 'sha256=' . hash_hmac( 'sha256', (string) wp_json_encode( $request->get_params() ), 'traduttore-test' ); $request->add_header( 'x-event-key', 'repo:push' ); - $request->add_header( 'x-hub-signature', $signature ); + $request->add_header( 'x-hub-signature-256', $signature ); $response = rest_get_server()->dispatch( $request ); $this->assertSame( 200, $response->get_status() ); @@ -160,9 +155,9 @@ public function test_valid_mercurial_project(): void { ], ] ); - $signature = 'sha256=' . hash_hmac( 'sha256', wp_json_encode( $request->get_params() ), 'traduttore-test' ); + $signature = 'sha256=' . hash_hmac( 'sha256', (string) wp_json_encode( $request->get_params() ), 'traduttore-test' ); $request->add_header( 'x-event-key', 'repo:push' ); - $request->add_header( 'x-hub-signature', $signature ); + $request->add_header( 'x-hub-signature-256', $signature ); $response = rest_get_server()->dispatch( $request ); $this->assertSame( 200, $response->get_status() ); diff --git a/tests/phpunit/tests/WebhookHandler/GitHub.php b/tests/phpunit/tests/WebhookHandler/GitHub.php index 810bdd47..0dafc172 100644 --- a/tests/phpunit/tests/WebhookHandler/GitHub.php +++ b/tests/phpunit/tests/WebhookHandler/GitHub.php @@ -1,8 +1,6 @@ project = new Project( - $this->factory->project->create( + $this->factory()->project->create( [ 'name' => 'Sample Project', 'source_url_template' => 'https://github.com/wearerequired/traduttore/blob/master/%file%#L%line%', @@ -70,9 +68,9 @@ public function test_invalid_signature(): void { $request = new WP_REST_Request( 'POST', '/traduttore/v1/incoming-webhook' ); $request->add_header( 'Content-Type', 'application/json' ); $request->set_body( (string) wp_json_encode( [] ) ); - $signature = 'sha1=' . hash_hmac( 'sha1', $request->get_body(), 'foo' ); + $signature = 'sha256=' . hash_hmac( 'sha256', $request->get_body(), 'foo' ); $request->add_header( 'x-github-event', 'push' ); - $request->add_header( 'x-hub-signature', $signature ); + $request->add_header( 'x-hub-signature-256', $signature ); $response = rest_get_server()->dispatch( $request ); $this->assertErrorResponse( 'rest_forbidden', $response, 401 ); @@ -92,9 +90,9 @@ public function test_invalid_branch(): void { ] ) ); - $signature = 'sha1=' . hash_hmac( 'sha1', $request->get_body(), 'traduttore-test' ); + $signature = 'sha256=' . hash_hmac( 'sha256', $request->get_body(), 'traduttore-test' ); $request->add_header( 'x-github-event', 'push' ); - $request->add_header( 'x-hub-signature', $signature ); + $request->add_header( 'x-hub-signature-256', $signature ); $response = rest_get_server()->dispatch( $request ); $this->assertSame( 200, $response->get_status() ); @@ -120,9 +118,9 @@ public function test_invalid_project(): void { ] ) ); - $signature = 'sha1=' . hash_hmac( 'sha1', $request->get_body(), 'traduttore-test' ); + $signature = 'sha256=' . hash_hmac( 'sha256', $request->get_body(), 'traduttore-test' ); $request->add_header( 'x-github-event', 'push' ); - $request->add_header( 'x-hub-signature', $signature ); + $request->add_header( 'x-hub-signature-256', $signature ); $response = rest_get_server()->dispatch( $request ); $this->assertErrorResponse( 404, $response ); @@ -138,9 +136,9 @@ public function test_invalid_request(): void { ] ) ); - $signature = 'sha1=' . hash_hmac( 'sha1', $request->get_body(), 'traduttore-test' ); + $signature = 'sha256=' . hash_hmac( 'sha256', $request->get_body(), 'traduttore-test' ); $request->add_header( 'x-github-event', 'push' ); - $request->add_header( 'x-hub-signature', $signature ); + $request->add_header( 'x-hub-signature-256', $signature ); $response = rest_get_server()->dispatch( $request ); $this->assertErrorResponse( 400, $response ); @@ -150,7 +148,7 @@ public function test_valid_project(): void { $request = new WP_REST_Request( 'POST', '/traduttore/v1/incoming-webhook' ); $request->add_header( 'Content-Type', 'application/json' ); $request->set_body( - (string) wp_json_encode( + (string) wp_json_encode( [ 'ref' => 'refs/heads/master', 'repository' => [ @@ -165,9 +163,9 @@ public function test_valid_project(): void { ] ) ); - $signature = 'sha1=' . hash_hmac( 'sha1', $request->get_body(), 'traduttore-test' ); + $signature = 'sha256=' . hash_hmac( 'sha256', $request->get_body(), 'traduttore-test' ); $request->add_header( 'x-github-event', 'push' ); - $request->add_header( 'x-hub-signature', $signature ); + $request->add_header( 'x-hub-signature-256', $signature ); $response = rest_get_server()->dispatch( $request ); $this->assertSame( 200, $response->get_status() ); @@ -185,25 +183,27 @@ public function test_valid_project_with_x_www_form_urlencoded_content_type(): vo $request = new WP_REST_Request( 'POST', '/traduttore/v1/incoming-webhook' ); $request->set_header( 'Content-Type', 'application/x-www-form-urlencoded' ); $data = [ - 'payload' => json_encode( [ - 'ref' => 'refs/heads/master', - 'repository' => [ - 'full_name' => 'wearerequired/traduttore', - 'default_branch' => 'master', - 'html_url' => 'https://github.com/wearerequired/traduttore', - 'ssh_url' => 'git@github.com:wearerequired/traduttore.git', - 'clone_url' => 'https://github.com/wearerequired/traduttore.git', - 'url' => 'https://github.com/wearerequired/traduttore', - 'private' => false, - ], - ] ) + 'payload' => json_encode( + [ + 'ref' => 'refs/heads/master', + 'repository' => [ + 'full_name' => 'wearerequired/traduttore', + 'default_branch' => 'master', + 'html_url' => 'https://github.com/wearerequired/traduttore', + 'ssh_url' => 'git@github.com:wearerequired/traduttore.git', + 'clone_url' => 'https://github.com/wearerequired/traduttore.git', + 'url' => 'https://github.com/wearerequired/traduttore', + 'private' => false, + ], + ] + ), ]; $request->set_body_params( $data ); $request->set_body( http_build_query( $data ) ); - $signature = 'sha1=' . hash_hmac( 'sha1', $request->get_body(), 'traduttore-test' ); + $signature = 'sha256=' . hash_hmac( 'sha256', $request->get_body(), 'traduttore-test' ); $request->add_header( 'x-github-event', 'push' ); - $request->add_header( 'x-hub-signature', $signature ); + $request->add_header( 'x-hub-signature-256', $signature ); $response = rest_get_server()->dispatch( $request ); $this->assertSame( 200, $response->get_status() ); @@ -240,9 +240,9 @@ public function test_valid_project_custom_webhook_secret(): void { ] ) ); - $signature = 'sha1=' . hash_hmac( 'sha1', $request->get_body(), $secret ); + $signature = 'sha256=' . hash_hmac( 'sha256', $request->get_body(), $secret ); $request->add_header( 'x-github-event', 'push' ); - $request->add_header( 'x-hub-signature', $signature ); + $request->add_header( 'x-hub-signature-256', $signature ); $response = rest_get_server()->dispatch( $request ); $this->assertSame( 200, $response->get_status() ); diff --git a/tests/phpunit/tests/WebhookHandler/GitLab.php b/tests/phpunit/tests/WebhookHandler/GitLab.php index f4c2c00c..eebaa6a1 100644 --- a/tests/phpunit/tests/WebhookHandler/GitLab.php +++ b/tests/phpunit/tests/WebhookHandler/GitLab.php @@ -1,8 +1,6 @@ project = new Project( - $this->factory->project->create( + $this->factory()->project->create( [ 'name' => 'Sample Project', 'source_url_template' => 'https://gitlab.com/wearerequired/traduttore/blob/master/%file%#L%line%', diff --git a/tests/phpunit/tests/WebhookHandler/LegacyGitHub.php b/tests/phpunit/tests/WebhookHandler/LegacyGitHub.php index 32bf0f93..4bc801d4 100644 --- a/tests/phpunit/tests/WebhookHandler/LegacyGitHub.php +++ b/tests/phpunit/tests/WebhookHandler/LegacyGitHub.php @@ -1,8 +1,6 @@ project = new Project( - $this->factory->project->create( + $this->factory()->project->create( [ 'name' => 'Sample Project', 'source_url_template' => 'https://github.com/wearerequired/traduttore/blob/master/%file%#L%line%', @@ -70,9 +65,9 @@ public function test_invalid_signature(): void { $request = new WP_REST_Request( 'POST', '/github-webhook/v1/push-event' ); $request->add_header( 'Content-Type', 'application/json' ); $request->set_body( (string) wp_json_encode( [] ) ); - $signature = 'sha1=' . hash_hmac( 'sha1', $request->get_body(), 'foo' ); + $signature = 'sha256=' . hash_hmac( 'sha256', $request->get_body(), 'foo' ); $request->add_header( 'x-github-event', 'push' ); - $request->add_header( 'x-hub-signature', $signature ); + $request->add_header( 'x-hub-signature-256', $signature ); $response = rest_get_server()->dispatch( $request ); $this->assertErrorResponse( 'rest_forbidden', $response, 401 ); @@ -92,9 +87,9 @@ public function test_invalid_branch(): void { ] ) ); - $signature = 'sha1=' . hash_hmac( 'sha1', $request->get_body(), 'traduttore-test' ); + $signature = 'sha256=' . hash_hmac( 'sha256', $request->get_body(), 'traduttore-test' ); $request->add_header( 'x-github-event', 'push' ); - $request->add_header( 'x-hub-signature', $signature ); + $request->add_header( 'x-hub-signature-256', $signature ); $response = rest_get_server()->dispatch( $request ); $this->assertSame( 200, $response->get_status() ); @@ -120,9 +115,9 @@ public function test_invalid_project(): void { ] ) ); - $signature = 'sha1=' . hash_hmac( 'sha1', $request->get_body(), 'traduttore-test' ); + $signature = 'sha256=' . hash_hmac( 'sha256', $request->get_body(), 'traduttore-test' ); $request->add_header( 'x-github-event', 'push' ); - $request->add_header( 'x-hub-signature', $signature ); + $request->add_header( 'x-hub-signature-256', $signature ); $response = rest_get_server()->dispatch( $request ); $this->assertErrorResponse( 404, $response ); @@ -147,9 +142,9 @@ public function test_valid_project(): void { ] ) ); - $signature = 'sha1=' . hash_hmac( 'sha1', $request->get_body(), 'traduttore-test' ); + $signature = 'sha256=' . hash_hmac( 'sha256', $request->get_body(), 'traduttore-test' ); $request->add_header( 'x-github-event', 'push' ); - $request->add_header( 'x-hub-signature', $signature ); + $request->add_header( 'x-hub-signature-256', $signature ); $response = rest_get_server()->dispatch( $request ); $this->assertSame( 200, $response->get_status() ); @@ -186,9 +181,9 @@ public function test_valid_project_custom_webhook_secret(): void { ] ) ); - $signature = 'sha1=' . hash_hmac( 'sha1', $request->get_body(), $secret ); + $signature = 'sha256=' . hash_hmac( 'sha256', $request->get_body(), $secret ); $request->add_header( 'x-github-event', 'push' ); - $request->add_header( 'x-hub-signature', $signature ); + $request->add_header( 'x-hub-signature-256', $signature ); $response = rest_get_server()->dispatch( $request ); $this->assertSame( 200, $response->get_status() ); diff --git a/tests/phpunit/tests/ZipProvider.php b/tests/phpunit/tests/ZipProvider.php index b2962980..5145dacb 100644 --- a/tests/phpunit/tests/ZipProvider.php +++ b/tests/phpunit/tests/ZipProvider.php @@ -1,17 +1,14 @@ locale = $this->factory->locale->create( + $this->locale = $this->factory()->locale->create( [ 'slug' => 'de', 'wp_locale' => 'de_DE', ] ); - $this->translation_set = $this->factory->translation_set->create_with_project( + $this->translation_set = $this->factory()->translation_set->create_with_project( [ 'locale' => $this->locale->slug, ], @@ -58,7 +55,7 @@ public function setUp(): void { ] ); - $this->sub_translation_set = $this->factory->translation_set->create_with_project( + $this->sub_translation_set = $this->factory()->translation_set->create_with_project( [ 'locale' => $this->locale->slug, ], @@ -68,7 +65,11 @@ public function setUp(): void { ] ); - $this->project = new \Required\Traduttore\Project( GP::$project->get( $this->translation_set->project_id ) ); + $gp_project = GP::$project->get( $this->translation_set->project_id ); + + $this->assertNotFalse( $gp_project ); + + $this->project = new \Required\Traduttore\Project( $gp_project ); } public function tearDown(): void { @@ -145,9 +146,9 @@ public function test_generate_zip_file_no_filesystem(): void { } public function test_generate_zip_file(): void { - $original = $this->factory->original->create( [ 'project_id' => $this->translation_set->project_id ] ); + $original = $this->factory()->original->create( [ 'project_id' => $this->translation_set->project_id ] ); - $this->factory->translation->create( + $this->factory()->translation->create( [ 'original_id' => $original->id, 'translation_set_id' => $this->translation_set->id, @@ -165,9 +166,9 @@ public function test_generate_zip_file(): void { * @preserveGlobalState disabled */ public function test_generate_zip_file_missing_wp_filesystem(): void { - $original = $this->factory->original->create( [ 'project_id' => $this->translation_set->project_id ] ); + $original = $this->factory()->original->create( [ 'project_id' => $this->translation_set->project_id ] ); - $this->factory->translation->create( + $this->factory()->translation->create( [ 'original_id' => $original->id, 'translation_set_id' => $this->translation_set->id, @@ -185,9 +186,9 @@ public function test_generate_zip_file_missing_wp_filesystem(): void { } public function test_replaces_existing_zip_file(): void { - $original = $this->factory->original->create( [ 'project_id' => $this->translation_set->project_id ] ); + $original = $this->factory()->original->create( [ 'project_id' => $this->translation_set->project_id ] ); - $this->factory->translation->create( + $this->factory()->translation->create( [ 'original_id' => $original->id, 'translation_set_id' => $this->translation_set->id, @@ -219,9 +220,9 @@ public function test_replaces_existing_zip_file(): void { } public function test_get_last_build_time_after_zip_generation(): void { - $original = $this->factory->original->create( [ 'project_id' => $this->translation_set->project_id ] ); + $original = $this->factory()->original->create( [ 'project_id' => $this->translation_set->project_id ] ); - $this->factory->translation->create( + $this->factory()->translation->create( [ 'original_id' => $original->id, 'translation_set_id' => $this->translation_set->id, @@ -237,9 +238,9 @@ public function test_get_last_build_time_after_zip_generation(): void { } public function test_remove_zip_file(): void { - $original = $this->factory->original->create( [ 'project_id' => $this->translation_set->project_id ] ); + $original = $this->factory()->original->create( [ 'project_id' => $this->translation_set->project_id ] ); - $this->factory->translation->create( + $this->factory()->translation->create( [ 'original_id' => $original->id, 'translation_set_id' => $this->translation_set->id, @@ -255,9 +256,9 @@ public function test_remove_zip_file(): void { } public function test_remove_zip_file_resets_build_time(): void { - $original = $this->factory->original->create( [ 'project_id' => $this->translation_set->project_id ] ); + $original = $this->factory()->original->create( [ 'project_id' => $this->translation_set->project_id ] ); - $this->factory->translation->create( + $this->factory()->translation->create( [ 'original_id' => $original->id, 'translation_set_id' => $this->translation_set->id, @@ -284,9 +285,9 @@ public function test_remove_zip_file_does_not_exist(): void { } public function test_remove_zip_file_no_filesystem(): void { - $original = $this->factory->original->create( [ 'project_id' => $this->translation_set->project_id ] ); + $original = $this->factory()->original->create( [ 'project_id' => $this->translation_set->project_id ] ); - $this->factory->translation->create( + $this->factory()->translation->create( [ 'original_id' => $original->id, 'translation_set_id' => $this->translation_set->id, @@ -308,10 +309,13 @@ public function test_remove_zip_file_no_filesystem(): void { } public function test_use_text_domain_for_translation_files(): void { - $project = ( new ProjectLocator( $this->translation_set->project_id ) )->get_project(); - $original = $this->factory->original->create( [ 'project_id' => $this->translation_set->project_id ] ); + $project = ( new ProjectLocator( $this->translation_set->project_id ) )->get_project(); + + $this->assertInstanceOf( \Required\Traduttore\Project::class, $project ); - $this->factory->translation->create( + $original = $this->factory()->original->create( [ 'project_id' => $this->translation_set->project_id ] ); + + $this->factory()->translation->create( [ 'original_id' => $original->id, 'translation_set_id' => $this->translation_set->id, @@ -325,9 +329,9 @@ public function test_use_text_domain_for_translation_files(): void { $result = $provider->generate_zip_file(); $expected_files = [ - 'foo-bar-baz-de_DE.po', - 'foo-bar-baz-de_DE.mo', - 'foo-bar-baz-de_DE.l10n.php' + 'foo-bar-baz-de_DE.po', + 'foo-bar-baz-de_DE.mo', + 'foo-bar-baz-de_DE.l10n.php', ]; $actual_files = []; @@ -335,10 +339,13 @@ public function test_use_text_domain_for_translation_files(): void { $zip->open( $provider->get_zip_path() ); - // phpcs:ignore WordPress.NamingConventions.ValidVariableName.NotSnakeCaseMemberVar - for ( $i = 0; $i < $zip->numFiles; $i ++ ) { - $stat = $zip->statIndex( $i ); - $actual_files[] = $stat['name']; + // phpcs:ignore WordPress.NamingConventions.ValidVariableName.UsedPropertyNotSnakeCase + for ( $i = 0; $i < $zip->numFiles; $i++ ) { + $stat = $zip->statIndex( $i ); + + if ( $stat ) { + $actual_files[] = $stat['name']; + } } $zip->close(); @@ -370,9 +377,9 @@ public function test_schedule_generation_removes_existing_event(): void { $crons = _get_cron_array(); $key = md5( serialize( [ $this->translation_set->id ] ) ); - foreach ( $crons as $timestamp => $cron ) { + foreach ( $crons as $cron ) { if ( isset( $cron['traduttore.generate_zip'][ $key ] ) ) { - $actual_count ++; + $actual_count++; } } @@ -380,11 +387,11 @@ public function test_schedule_generation_removes_existing_event(): void { } public function test_does_not_schedule_generation_after_saving_translation_for_inactive_project(): void { - $original = $this->factory->original->create( [ 'project_id' => $this->translation_set->project_id ] ); + $original = $this->factory()->original->create( [ 'project_id' => $this->translation_set->project_id ] ); $translation_set_id = (int) $this->translation_set->id; /** @var \GP_Translation $translation */ - $translation = $this->factory->translation->create( + $translation = $this->factory()->translation->create( [ 'original_id' => $original->id, 'translation_set_id' => $this->translation_set->id, @@ -408,11 +415,11 @@ public function test_does_not_schedule_generation_after_saving_translation_for_i public function test_schedules_generation_after_saving_translation(): void { $this->project->get_project()->save( [ 'active' => 1 ] ); - $original = $this->factory->original->create( [ 'project_id' => $this->translation_set->project_id ] ); + $original = $this->factory()->original->create( [ 'project_id' => $this->translation_set->project_id ] ); $translation_set_id = (int) $this->translation_set->id; /** @var \GP_Translation $translation */ - $translation = $this->factory->translation->create( + $translation = $this->factory()->translation->create( [ 'original_id' => $original->id, 'translation_set_id' => $this->translation_set->id, @@ -435,7 +442,7 @@ public function test_schedules_generation_after_saving_translation(): void { public function test_does_not_schedule_generation_after_importing_originals_for_inactive_project(): void { /** @var \GP_Original $original */ - $original = $this->factory->original->create( [ 'project_id' => $this->translation_set->project_id ] ); + $original = $this->factory()->original->create( [ 'project_id' => $this->translation_set->project_id ] ); $before = wp_next_scheduled( 'traduttore.generate_zip', [ $this->translation_set->id ] ); @@ -453,7 +460,7 @@ public function test_schedules_generation_after_importing_originals(): void { $this->project->get_project()->save( [ 'active' => 1 ] ); /** @var \GP_Original $original */ - $original = $this->factory->original->create( [ 'project_id' => $this->translation_set->project_id ] ); + $original = $this->factory()->original->create( [ 'project_id' => $this->translation_set->project_id ] ); $before = wp_next_scheduled( 'traduttore.generate_zip', [ $this->translation_set->id ] );