diff --git a/.github/workflows/unit-tests.yml b/.github/workflows/unit-tests.yml new file mode 100644 index 0000000000..20475ee617 --- /dev/null +++ b/.github/workflows/unit-tests.yml @@ -0,0 +1,123 @@ +name: Unit Tests + +on: + push: + branches: [ trunk ] + pull_request: + branches: [ trunk ] + +jobs: + # Standalone PHP tests — no WordPress or database dependency. + php-standalone: + name: "PHP: ${{ matrix.name }}" + runs-on: ubuntu-latest + strategy: + fail-fast: false + matrix: + include: + - name: Serve Happy API + working-directory: api.wordpress.org/public_html/core/serve-happy/1.0 + phpunit-args: "--configuration phpunit.xml --exclude-group serve-happy-live-http" + bootstrap: compat + - name: Browse Happy API + working-directory: api.wordpress.org/public_html/core/browse-happy/1.0 + phpunit-args: "--configuration phpunit.xml" + bootstrap: none + - name: Slack Trac Bot + working-directory: common/includes/tests/slack/trac + phpunit-args: "bot.php" + bootstrap: compat + - name: Slack Props Library + working-directory: common/includes/slack/props/tests + phpunit-args: "." + bootstrap: wpdb-stub + steps: + - uses: actions/checkout@v4 + + - name: Set up PHP + uses: shivammathur/setup-php@v2 + with: + php-version: "8.0" + tools: phpunit:^9 + + - name: Create PHPUnit compatibility bootstrap + if: matrix.bootstrap == 'compat' + run: | + cat > /tmp/phpunit-bootstrap.php << 'PHPEOF' + /tmp/phpunit-bootstrap.php << 'PHPEOF' + assertTrue( $parsed['upgrade'] ); + return; + } + $versions = get_browser_current_versions(); if ( ! empty( $versions[ $parsed['name'] ] ) ) { diff --git a/wordpress.org/public_html/wp-content/plugins/handbook/phpunit/bootstrap.php b/wordpress.org/public_html/wp-content/plugins/handbook/phpunit/bootstrap.php index 294962ca04..20df609eaf 100644 --- a/wordpress.org/public_html/wp-content/plugins/handbook/phpunit/bootstrap.php +++ b/wordpress.org/public_html/wp-content/plugins/handbook/phpunit/bootstrap.php @@ -14,6 +14,10 @@ if ( ! $_tests_dir && false !== ( $pos = stripos( __FILE__, '/src/wp-content/plugins/' ) ) ) { $_tests_dir = substr( __FILE__, 0, $pos ) . '/tests/phpunit/'; } +// Check for wp-env test directory. +elseif ( ! $_tests_dir && file_exists( '/wordpress-phpunit/includes/functions.php' ) ) { + $_tests_dir = '/wordpress-phpunit/'; +} // Elseif no path yet, assume a temp directory path. elseif ( ! $_tests_dir ) { $_tests_dir = rtrim( sys_get_temp_dir(), '/\\' ) . '/wordpress-tests-lib/tests/phpunit/'; diff --git a/wordpress.org/public_html/wp-content/plugins/handbook/phpunit/tests/handbook.php b/wordpress.org/public_html/wp-content/plugins/handbook/phpunit/tests/handbook.php index 9199c54ccc..2c5e00429f 100644 --- a/wordpress.org/public_html/wp-content/plugins/handbook/phpunit/tests/handbook.php +++ b/wordpress.org/public_html/wp-content/plugins/handbook/phpunit/tests/handbook.php @@ -17,7 +17,7 @@ class WPorg_Handbook_Handbook_Test extends WP_UnitTestCase { protected $handbook; - public function setUp() { + public function setUp(): void { parent::setup(); WPorg_Handbook_Init::init(); @@ -25,7 +25,7 @@ public function setUp() { $this->handbook = reset( $handbooks ); } - public function tearDown() { + public function tearDown(): void { parent::tearDown(); foreach ( WPorg_Handbook_Init::get_handbook_objects() as $obj ) { @@ -455,7 +455,7 @@ public function test_handbook_sidebar() { $this->assertTrue( isset( $wp_registered_sidebars[ 'handbook' ] ) ); $this->assertSame( - [ 'name', 'id', 'description', 'class', 'before_widget', 'after_widget', 'before_title', 'after_title', 'before_sidebar', 'after_sidebar' ], + [ 'name', 'id', 'description', 'class', 'before_widget', 'after_widget', 'before_title', 'after_title', 'before_sidebar', 'after_sidebar', 'show_in_rest' ], array_keys( $wp_registered_sidebars[ 'handbook' ] ) ); $this->assertEquals( 'handbook', $wp_registered_sidebars[ 'handbook' ]['id'] ); diff --git a/wordpress.org/public_html/wp-content/plugins/handbook/phpunit/tests/init.php b/wordpress.org/public_html/wp-content/plugins/handbook/phpunit/tests/init.php index 1e1fd2f050..9b03669507 100644 --- a/wordpress.org/public_html/wp-content/plugins/handbook/phpunit/tests/init.php +++ b/wordpress.org/public_html/wp-content/plugins/handbook/phpunit/tests/init.php @@ -4,13 +4,13 @@ class WPorg_Handbook_Init_Test extends WP_UnitTestCase { - public function setUp() { + public function setUp(): void { parent::setup(); WPorg_Handbook_Init::init(); } - public function tearDown() { + public function tearDown(): void { parent::tearDown(); WPorg_Handbook_Init::reset( true ); diff --git a/wordpress.org/public_html/wp-content/plugins/handbook/phpunit/tests/template-tags.php b/wordpress.org/public_html/wp-content/plugins/handbook/phpunit/tests/template-tags.php index aa9b6d91b5..acf9dbad22 100644 --- a/wordpress.org/public_html/wp-content/plugins/handbook/phpunit/tests/template-tags.php +++ b/wordpress.org/public_html/wp-content/plugins/handbook/phpunit/tests/template-tags.php @@ -4,13 +4,13 @@ class WPorg_Handbook_Template_Tags_Test extends WP_UnitTestCase { - public function setUp() { + public function setUp(): void { parent::setup(); WPorg_Handbook_Init::init(); } - public function tearDown() { + public function tearDown(): void { parent::tearDown(); WPorg_Handbook_Init::reset( true ); diff --git a/wordpress.org/public_html/wp-content/plugins/plugin-directory/.wp-env.json b/wordpress.org/public_html/wp-content/plugins/plugin-directory/.wp-env.json new file mode 100644 index 0000000000..970c05e2a2 --- /dev/null +++ b/wordpress.org/public_html/wp-content/plugins/plugin-directory/.wp-env.json @@ -0,0 +1,16 @@ +{ + "core": "WordPress/WordPress#master", + "plugins": [ + ".", + "https://downloads.wordpress.org/plugin/jetpack.latest-stable.zip", + "https://downloads.wordpress.org/plugin/advanced-post-cache.latest-stable.zip", + "https://github.com/WordPress/plugin-check" + ], + "themes": [ + "../../../themes/pub/wporg-plugins-2024", + "https://github.com/WordPress/wporg-parent-2021" + ], + "mappings": { + "wp-content/mu-plugins/wporg-ratings-stub.php": "./tests/stubs/wporg-ratings-stub.php" + } +} diff --git a/wordpress.org/public_html/wp-content/plugins/plugin-directory/tests/bootstrap.php b/wordpress.org/public_html/wp-content/plugins/plugin-directory/tests/bootstrap.php index 4a387afef9..e2b66e38b3 100644 --- a/wordpress.org/public_html/wp-content/plugins/plugin-directory/tests/bootstrap.php +++ b/wordpress.org/public_html/wp-content/plugins/plugin-directory/tests/bootstrap.php @@ -6,6 +6,29 @@ return; } +// Find the WordPress PHPUnit test framework. +$_tests_dir = getenv( 'WP_TESTS_DIR' ); + +if ( ! $_tests_dir ) { + // wp-env test directory. + if ( file_exists( '/wordpress-phpunit/includes/functions.php' ) ) { + $_tests_dir = '/wordpress-phpunit/'; + } else { + $_tests_dir = rtrim( sys_get_temp_dir(), '/\\' ) . '/wordpress-tests-lib/tests/phpunit/'; + } +} + +if ( ! file_exists( $_tests_dir . '/includes/functions.php' ) ) { + echo "Could not find {$_tests_dir}/includes/functions.php\n"; + exit( 1 ); +} + +// Give access to tests_add_filter() function. +require_once $_tests_dir . '/includes/functions.php'; + +// Load Jetpack Search stub if Jetpack is not installed. +require_once __DIR__ . '/stubs/jetpack-search-stub.php'; + /** * Manually load the plugin being tested. */ @@ -14,3 +37,6 @@ function manually_load_plugin() { } tests_add_filter( 'muplugins_loaded', __NAMESPACE__ . '\manually_load_plugin' ); + +// Start up the WP testing environment. +require $_tests_dir . '/includes/bootstrap.php'; diff --git a/wordpress.org/public_html/wp-content/plugins/plugin-directory/tests/phpunit/tests/test-markdown.php b/wordpress.org/public_html/wp-content/plugins/plugin-directory/tests/phpunit/tests/test-markdown.php new file mode 100644 index 0000000000..f7ded4b9d7 --- /dev/null +++ b/wordpress.org/public_html/wp-content/plugins/plugin-directory/tests/phpunit/tests/test-markdown.php @@ -0,0 +1,132 @@ +transform( 'Hello World' ); + $this->assertSame( '

Hello World

', $result ); + } + + function test_transform_empty_string(): void { + $md = new Markdown(); + $result = $md->transform( '' ); + $this->assertSame( '', $result ); + } + + function test_transform_trims_output(): void { + $md = new Markdown(); + $result = $md->transform( " \n Hello \n " ); + $this->assertSame( $result, trim( $result ) ); + } + + /** + * Test the custom `= Section Title =` header syntax. + * + * This is WordPress plugin readme specific — converts `= Title =` to

. + */ + function test_transform_equals_header(): void { + $md = new Markdown(); + $result = $md->transform( '= Section Title =' ); + $this->assertStringContainsString( '

Section Title

', $result ); + } + + function test_transform_multiple_equals_headers(): void { + $md = new Markdown(); + $result = $md->transform( "= First =\n\nContent\n\n= Second =" ); + $this->assertStringContainsString( '

First

', $result ); + $this->assertStringContainsString( '

Second

', $result ); + } + + function test_equals_header_with_leading_whitespace(): void { + $md = new Markdown(); + $result = $md->transform( ' = Indented Header =' ); + $this->assertStringContainsString( '

Indented Header

', $result ); + } + + /** + * Test code_trick:
 blocks preserve underscores in code.
+	 *
+	 * This is custom logic in Markdown::code_trick() — pre-existing HTML code blocks
+	 * are converted to backtick format before markdown processing, so markdown
+	 * does not mangle underscores and other special characters inside code.
+	 *
+	 * The block needs surrounding content so trim() does not strip indentation.
+	 */
+	function test_code_trick_preserves_underscores_in_pre_code(): void {
+		$md    = new Markdown();
+		$input = "Some text before.\n\n
\$my_var = some_function();\n\$other_var = 1;
\n\nSome text after."; + $result = $md->transform( $input ); + + // Underscores should NOT be converted to tags inside code blocks. + $this->assertStringNotContainsString( '', $result ); + $this->assertStringContainsString( 'my_var', $result ); + $this->assertStringContainsString( 'some_function', $result ); + } + + function test_code_trick_inline_code_preserves_underscores(): void { + $md = new Markdown(); + $input = "Use my_var_name for the setting."; + $result = $md->transform( $input ); + + // Inline code should also preserve underscores. + $this->assertStringNotContainsString( '', $result ); + $this->assertStringContainsString( 'my_var_name', $result ); + } + + /** + * Test code_trick: bbPress-style backtick code blocks at line start are + * converted to indented code (4 spaces) for markdown processing. + */ + function test_code_trick_bbpress_backtick_block(): void { + $md = new Markdown(); + $input = "Some text.\n\n`some_code_here`\n\nMore text."; + $result = $md->transform( $input ); + + $this->assertStringContainsString( 'some_code_here', $result ); + } + + /** + * Test that inline markdown code (backticks) in mid-line is preserved. + */ + function test_inline_backtick_code_preserved(): void { + $md = new Markdown(); + $result = $md->transform( 'Use `add_filter()` to modify output.' ); + $this->assertStringContainsString( 'add_filter()', $result ); + } + + /** + * Test standard markdown features (these verify the upstream MarkdownExtra + * library works correctly through our transform() wrapper). + */ + function test_transform_bold(): void { + $md = new Markdown(); + $result = $md->transform( '**bold text**' ); + $this->assertStringContainsString( 'bold text', $result ); + } + + function test_transform_italic(): void { + $md = new Markdown(); + $result = $md->transform( '*italic text*' ); + $this->assertStringContainsString( 'italic text', $result ); + } + + function test_transform_link(): void { + $md = new Markdown(); + $result = $md->transform( '[Example](https://example.com)' ); + $this->assertStringContainsString( 'Example', $result ); + } + + function test_transform_unordered_list(): void { + $md = new Markdown(); + $result = $md->transform( "* Item 1\n* Item 2\n* Item 3" ); + $this->assertStringContainsString( '
  • Item 1
  • ', $result ); + $this->assertStringContainsString( '
      ', $result ); + } +} diff --git a/wordpress.org/public_html/wp-content/plugins/plugin-directory/tests/phpunit/tests/test-plugin-directory.php b/wordpress.org/public_html/wp-content/plugins/plugin-directory/tests/phpunit/tests/test-plugin-directory.php new file mode 100644 index 0000000000..2c44e870de --- /dev/null +++ b/wordpress.org/public_html/wp-content/plugins/plugin-directory/tests/phpunit/tests/test-plugin-directory.php @@ -0,0 +1,259 @@ +post->create( array_merge( [ + 'post_type' => 'plugin', + 'post_status' => 'publish', + 'post_modified' => $now, + 'post_modified_gmt' => $gmt, + ], $args ) ); + } + + /** + * Test that the 'plugin' post type is registered. + */ + function test_plugin_post_type_registered(): void { + $this->assertTrue( post_type_exists( 'plugin' ) ); + } + + function test_plugin_post_type_is_public(): void { + $post_type = get_post_type_object( 'plugin' ); + $this->assertTrue( $post_type->public ); + } + + function test_plugin_post_type_has_rest_support(): void { + $post_type = get_post_type_object( 'plugin' ); + $this->assertTrue( $post_type->show_in_rest ); + } + + /** + * Test that expected taxonomies are registered. + * + * @dataProvider data_expected_taxonomies + */ + function test_taxonomy_registered( $taxonomy ): void { + $this->assertTrue( taxonomy_exists( $taxonomy ), "Taxonomy '{$taxonomy}' should be registered." ); + } + + function data_expected_taxonomies(): array { + return [ + 'plugin_section' => [ 'plugin_section' ], + 'plugin_tags' => [ 'plugin_tags' ], + 'plugin_category' => [ 'plugin_category' ], + 'plugin_contributors' => [ 'plugin_contributors' ], + 'plugin_built_for' => [ 'plugin_built_for' ], + 'plugin_business_model' => [ 'plugin_business_model' ], + 'plugin_committers' => [ 'plugin_committers' ], + 'plugin_support_reps' => [ 'plugin_support_reps' ], + ]; + } + + /** + * Test that custom post statuses are registered. + * + * @dataProvider data_expected_post_statuses + */ + function test_post_status_registered( $status ): void { + $this->assertNotFalse( + get_post_status_object( $status ), + "Post status '{$status}' should be registered." + ); + } + + function data_expected_post_statuses(): array { + return [ + 'new' => [ 'new' ], + 'pending' => [ 'pending' ], + 'disabled' => [ 'disabled' ], + 'approved' => [ 'approved' ], + 'closed' => [ 'closed' ], + 'rejected' => [ 'rejected' ], + ]; + } + + /** + * Test that a plugin post can be created. + */ + function test_can_create_plugin_post(): void { + $post_id = $this->create_plugin_post( [ + 'post_title' => 'Test Tool', + 'post_name' => 'test-tool', + ] ); + + $this->assertIsInt( $post_id ); + $this->assertGreaterThan( 0, $post_id ); + + $post = get_post( $post_id ); + $this->assertSame( 'plugin', $post->post_type ); + $this->assertSame( 'Test Tool', $post->post_title ); + } + + /** + * Test that plugin meta fields can be stored and retrieved. + */ + function test_plugin_meta_fields(): void { + $post_id = $this->create_plugin_post( [ 'post_name' => 'meta-test' ] ); + + update_post_meta( $post_id, 'stable_tag', '2.0.0' ); + update_post_meta( $post_id, 'tested', '6.4' ); + update_post_meta( $post_id, 'requires', '5.0' ); + update_post_meta( $post_id, 'requires_php', '7.4' ); + update_post_meta( $post_id, 'active_installs', 50000 ); + update_post_meta( $post_id, 'downloads', 100000 ); + update_post_meta( $post_id, 'rating', 90 ); + + $this->assertSame( '2.0.0', get_post_meta( $post_id, 'stable_tag', true ) ); + $this->assertSame( '6.4', get_post_meta( $post_id, 'tested', true ) ); + $this->assertSame( '5.0', get_post_meta( $post_id, 'requires', true ) ); + $this->assertSame( '7.4', get_post_meta( $post_id, 'requires_php', true ) ); + $this->assertEquals( 50000, get_post_meta( $post_id, 'active_installs', true ) ); + $this->assertEquals( 100000, get_post_meta( $post_id, 'downloads', true ) ); + $this->assertEquals( 90, get_post_meta( $post_id, 'rating', true ) ); + } + + /** + * Test that terms can be assigned to the plugin_tags taxonomy. + */ + function test_assign_plugin_tags(): void { + $post_id = $this->create_plugin_post(); + + wp_set_object_terms( $post_id, [ 'seo', 'performance' ], 'plugin_tags' ); + + $terms = wp_get_object_terms( $post_id, 'plugin_tags', [ 'fields' => 'names' ] ); + $this->assertContains( 'seo', $terms ); + $this->assertContains( 'performance', $terms ); + } + + /** + * Test that terms can be assigned to the plugin_contributors taxonomy. + */ + function test_assign_plugin_contributors(): void { + $post_id = $this->create_plugin_post(); + + wp_set_object_terms( $post_id, [ 'johndoe' ], 'plugin_contributors' ); + + $terms = wp_get_object_terms( $post_id, 'plugin_contributors', [ 'fields' => 'names' ] ); + $this->assertContains( 'johndoe', $terms ); + } + + /** + * Test disabled post status is public (visible to non-logged-in users). + */ + function test_disabled_status_is_public(): void { + $status = get_post_status_object( 'disabled' ); + $this->assertTrue( $status->public ); + } + + /** + * Test closed post status is public (visible to non-logged-in users). + */ + function test_closed_status_is_public(): void { + $status = get_post_status_object( 'closed' ); + $this->assertTrue( $status->public ); + } + + /** + * Test that 'new' post status is not public. + */ + function test_new_status_is_not_public(): void { + $status = get_post_status_object( 'new' ); + $this->assertFalse( $status->public ); + } + + /** + * Test filter_wp_insert_post_data preserves post_modified for plugin posts. + */ + function test_filter_wp_insert_post_data_preserves_modified(): void { + $instance = Plugin_Directory::instance(); + + $data = [ + 'post_modified' => '2024-01-15 10:00:00', + 'post_modified_gmt' => '2024-01-15 10:00:00', + 'post_status' => 'publish', + 'post_name' => 'test', + ]; + $postarr = [ + 'post_type' => 'plugin', + 'post_modified' => '2024-01-15 10:00:00', + 'post_modified_gmt' => '2024-01-15 10:00:00', + 'post_status' => 'publish', + ]; + + $result = $instance->filter_wp_insert_post_data( $data, $postarr ); + + $this->assertSame( '2024-01-15 10:00:00', $result['post_modified'] ); + $this->assertSame( '2024-01-15 10:00:00', $result['post_modified_gmt'] ); + } + + /** + * Test filter_wp_insert_post_data ignores non-plugin post types. + */ + function test_filter_wp_insert_post_data_ignores_non_plugin(): void { + $instance = Plugin_Directory::instance(); + + $data = [ + 'post_modified' => '2024-01-15 10:00:00', + 'post_modified_gmt' => '2024-01-15 10:00:00', + 'post_status' => 'publish', + 'post_name' => 'test', + ]; + $postarr = [ + 'post_type' => 'post', + 'post_modified' => '2024-06-01 12:00:00', + 'post_modified_gmt' => '2024-06-01 12:00:00', + ]; + + $result = $instance->filter_wp_insert_post_data( $data, $postarr ); + + // Should return data unchanged for non-plugin types. + $this->assertSame( $data, $result ); + } + + /** + * Test filter_wp_insert_post_data preserves slug for pending plugin posts. + */ + function test_filter_wp_insert_post_data_preserves_pending_slug(): void { + $instance = Plugin_Directory::instance(); + + $now = current_time( 'mysql' ); + $gmt = current_time( 'mysql', true ); + + $post_id = $this->create_plugin_post( [ + 'post_name' => 'my-pending-tool', + 'post_status' => 'pending', + ] ); + + $data = [ + 'post_modified' => $now, + 'post_modified_gmt' => $gmt, + 'post_status' => 'pending', + 'post_name' => '', // WP clears slug for pending posts. + ]; + $postarr = [ + 'post_type' => 'plugin', + 'post_modified' => $now, + 'post_modified_gmt' => $gmt, + 'post_status' => 'pending', + 'ID' => $post_id, + ]; + + $result = $instance->filter_wp_insert_post_data( $data, $postarr ); + + $this->assertSame( 'my-pending-tool', $result['post_name'] ); + } +} diff --git a/wordpress.org/public_html/wp-content/plugins/plugin-directory/tests/phpunit/tests/test-readme-parser.php b/wordpress.org/public_html/wp-content/plugins/plugin-directory/tests/phpunit/tests/test-readme-parser.php new file mode 100644 index 0000000000..49f0124acc --- /dev/null +++ b/wordpress.org/public_html/wp-content/plugins/plugin-directory/tests/phpunit/tests/test-readme-parser.php @@ -0,0 +1,243 @@ +assertSame( 'My Test Plugin', $parser->name ); + } + + function test_parses_contributors(): void { + // Create a user so the contributor sanitization finds them. + self::factory()->user->create( [ 'user_login' => 'johndoe', 'user_nicename' => 'johndoe' ] ); + + $parser = new Parser( self::$valid_readme ); + $this->assertSame( [ 'johndoe' ], $parser->contributors ); + } + + function test_invalid_contributor_produces_warning(): void { + $parser = new Parser( self::$valid_readme ); + + // 'johndoe' does not exist as a WP user, so it should be ignored with a warning. + $this->assertEmpty( $parser->contributors ); + $this->assertArrayHasKey( 'contributor_ignored', $parser->warnings ); + } + + function test_parses_tags(): void { + $parser = new Parser( self::$valid_readme ); + $this->assertSame( [ 'test', 'unit-test' ], $parser->tags ); + } + + function test_parses_requires(): void { + $parser = new Parser( self::$valid_readme ); + $this->assertSame( '5.0', $parser->requires ); + } + + function test_parses_tested(): void { + $parser = new Parser( self::$valid_readme ); + $this->assertSame( '6.4', $parser->tested ); + } + + function test_parses_stable_tag(): void { + $parser = new Parser( self::$valid_readme ); + $this->assertSame( '1.2.3', $parser->stable_tag ); + } + + function test_parses_requires_php(): void { + $parser = new Parser( self::$valid_readme ); + $this->assertSame( '7.4', $parser->requires_php ); + } + + function test_parses_short_description(): void { + $parser = new Parser( self::$valid_readme ); + $this->assertSame( 'A short description of the plugin.', $parser->short_description ); + } + + function test_parses_license(): void { + $parser = new Parser( self::$valid_readme ); + $this->assertSame( 'GPLv2', $parser->license ); + } + + function test_parses_sections(): void { + $parser = new Parser( self::$valid_readme ); + + $this->assertArrayHasKey( 'description', $parser->sections ); + $this->assertArrayHasKey( 'installation', $parser->sections ); + $this->assertArrayHasKey( 'faq', $parser->sections ); + $this->assertArrayHasKey( 'changelog', $parser->sections ); + } + + function test_description_section_content(): void { + $parser = new Parser( self::$valid_readme ); + $this->assertStringContainsString( 'longer description', $parser->sections['description'] ); + } + + function test_faq_parsed(): void { + $parser = new Parser( self::$valid_readme ); + $this->assertNotEmpty( $parser->faq ); + $this->assertArrayHasKey( 'How does it work?', $parser->faq ); + } + + function test_empty_readme_produces_warnings(): void { + $parser = new Parser( '' ); + $this->assertEmpty( $parser->name ); + } + + function test_readme_without_name_header(): void { + $readme = <<<'README' +Contributors: johndoe +Tags: test +Requires at least: 5.0 +Tested up to: 6.0 +Stable tag: 1.0 + +Short description. + +== Description == + +Long description. +README; + $parser = new Parser( $readme ); + $this->assertArrayHasKey( 'invalid_plugin_name_header', $parser->warnings ); + } + + function test_readme_alias_sections(): void { + $readme = <<<'README' +=== Test Plugin === +Contributors: johndoe +Stable tag: 1.0 + +Short description. + +== Frequently Asked Questions == + += Question? = + +Answer. + +== Change Log == + += 1.0 = +* Initial release. +README; + $parser = new Parser( $readme ); + + // 'frequently_asked_questions' is aliased to 'faq'. + $this->assertArrayHasKey( 'faq', $parser->sections ); + + // 'change_log' is aliased to 'changelog'. + $this->assertArrayHasKey( 'changelog', $parser->sections ); + } + + function test_ignored_tags_filtered(): void { + $readme = <<<'README' +=== Test Plugin === +Contributors: johndoe +Tags: plugin, wordpress, seo, test +Stable tag: 1.0 + +Short description. + +== Description == + +A plugin. +README; + $parser = new Parser( $readme ); + + // 'plugin' and 'wordpress' should be filtered out. + $this->assertNotContains( 'plugin', $parser->tags ); + $this->assertNotContains( 'wordpress', $parser->tags ); + $this->assertContains( 'seo', $parser->tags ); + $this->assertContains( 'test', $parser->tags ); + } + + function test_valid_headers_mapping(): void { + // 'tested up to' and 'tested' both map to 'tested'. + $readme_tested_up_to = <<<'README' +=== Test === +Contributors: johndoe +Tested up to: 6.5 +Stable tag: 1.0 + +Short desc. +README; + $parser = new Parser( $readme_tested_up_to ); + $this->assertSame( '6.5', $parser->tested ); + + // 'requires at least' maps to 'requires'. + $readme_requires = <<<'README' +=== Test === +Contributors: johndoe +Requires at least: 5.5 +Stable tag: 1.0 + +Short desc. +README; + $parser = new Parser( $readme_requires ); + $this->assertSame( '5.5', $parser->requires ); + } + + function test_long_short_description_produces_warning(): void { + $long_desc = str_repeat( 'a ', 100 ); // 200 chars. + $readme = "=== Test ===\nContributors: johndoe\nStable tag: 1.0\n\n{$long_desc}\n\n== Description ==\n\nDesc."; + + $parser = new Parser( $readme ); + $this->assertArrayHasKey( 'trimmed_short_description', $parser->warnings ); + } + + function test_donate_link_parsed(): void { + $readme = <<<'README' +=== Test === +Contributors: johndoe +Donate link: https://example.com/donate +Stable tag: 1.0 + +Short desc. + +== Description == + +Desc. +README; + $parser = new Parser( $readme ); + $this->assertSame( 'https://example.com/donate', $parser->donate_link ); + } +} diff --git a/wordpress.org/public_html/wp-content/plugins/plugin-directory/tests/phpunit/tests/test-readme-validator.php b/wordpress.org/public_html/wp-content/plugins/plugin-directory/tests/phpunit/tests/test-readme-validator.php new file mode 100644 index 0000000000..09149494a4 --- /dev/null +++ b/wordpress.org/public_html/wp-content/plugins/plugin-directory/tests/phpunit/tests/test-readme-validator.php @@ -0,0 +1,366 @@ +user->create( [ 'user_login' => 'validatoruser', 'user_nicename' => 'validatoruser' ] ); + } + + function test_valid_readme_has_no_errors(): void { + $validator = Validator::instance(); + $result = $validator->validate( self::$valid_readme ); + + $this->assertEmpty( $result['errors'], 'Expected no errors for valid readme. Got: ' . print_r( $result['errors'], true ) ); + } + + function test_valid_readme_has_no_warnings(): void { + $validator = Validator::instance(); + $result = $validator->validate( self::$valid_readme ); + + $this->assertEmpty( $result['warnings'], 'Expected no warnings for valid readme. Got: ' . print_r( $result['warnings'], true ) ); + } + + function test_missing_plugin_name_is_error(): void { + $readme = <<<'README' +Contributors: johndoe +Stable tag: 1.0 + +Short description. + +== Description == + +Long description. +README; + $validator = Validator::instance(); + $result = $validator->validate( $readme ); + + $this->assertArrayHasKey( 'invalid_plugin_name_header', $result['errors'] ); + } + + function test_missing_tested_is_warning(): void { + $readme = <<<'README' +=== Test Tool === +Contributors: validatoruser +Requires at least: 5.0 +Stable tag: 1.0 +License: GPLv2 + +Short description. + +== Description == + +Long description. +README; + $validator = Validator::instance(); + $result = $validator->validate( $readme ); + + $this->assertArrayHasKey( 'tested_header_missing', $result['warnings'] ); + } + + function test_missing_stable_tag_is_warning(): void { + $readme = <<<'README' +=== Test Tool === +Contributors: validatoruser +Tested up to: 6.4 +License: GPLv2 + +Short description. + +== Description == + +Long description. +README; + $validator = Validator::instance(); + $result = $validator->validate( $readme ); + + $this->assertArrayHasKey( 'stable_tag_invalid', $result['warnings'] ); + } + + function test_trunk_stable_tag_is_warning(): void { + $readme = <<<'README' +=== Test Tool === +Contributors: validatoruser +Tested up to: 6.4 +Stable tag: trunk +License: GPLv2 + +Short description. + +== Description == + +Long description. +README; + $validator = Validator::instance(); + $result = $validator->validate( $readme ); + + $this->assertArrayHasKey( 'stable_tag_invalid', $result['warnings'] ); + } + + function test_missing_requires_is_note(): void { + $readme = <<<'README' +=== Test Tool === +Contributors: validatoruser +Tested up to: 6.4 +Stable tag: 1.0 +License: GPLv2 + +Short description. + +== Description == + +Long description. +README; + $validator = Validator::instance(); + $result = $validator->validate( $readme ); + + $this->assertArrayHasKey( 'requires_header_missing', $result['notes'] ); + } + + function test_missing_requires_php_is_note(): void { + $readme = <<<'README' +=== Test Tool === +Contributors: validatoruser +Tested up to: 6.4 +Stable tag: 1.0 +Requires at least: 5.0 +License: GPLv2 + +Short description. + +== Description == + +Long description. +README; + $validator = Validator::instance(); + $result = $validator->validate( $readme ); + + $this->assertArrayHasKey( 'requires_php_header_missing', $result['notes'] ); + } + + function test_missing_faq_is_note(): void { + $readme = <<<'README' +=== Test Tool === +Contributors: validatoruser +Tested up to: 6.4 +Stable tag: 1.0 +License: GPLv2 + +Short description. + +== Description == + +Long description. + +== Changelog == + += 1.0 = +* Initial release. +README; + $validator = Validator::instance(); + $result = $validator->validate( $readme ); + + $this->assertArrayHasKey( 'faq_missing', $result['notes'] ); + } + + function test_missing_changelog_is_note(): void { + $readme = <<<'README' +=== Test Tool === +Contributors: validatoruser +Tested up to: 6.4 +Stable tag: 1.0 +License: GPLv2 + +Short description. + +== Description == + +Long description. +README; + $validator = Validator::instance(); + $result = $validator->validate( $readme ); + + $this->assertArrayHasKey( 'changelog_missing', $result['notes'] ); + } + + function test_missing_screenshots_is_note(): void { + $readme = <<<'README' +=== Test Tool === +Contributors: validatoruser +Tested up to: 6.4 +Stable tag: 1.0 +License: GPLv2 + +Short description. + +== Description == + +Long description. +README; + $validator = Validator::instance(); + $result = $validator->validate( $readme ); + + $this->assertArrayHasKey( 'screenshots_missing', $result['notes'] ); + } + + function test_missing_donate_link_is_note(): void { + $readme = <<<'README' +=== Test Tool === +Contributors: validatoruser +Tested up to: 6.4 +Stable tag: 1.0 +License: GPLv2 + +Short description. + +== Description == + +Long description. +README; + $validator = Validator::instance(); + $result = $validator->validate( $readme ); + + $this->assertArrayHasKey( 'donate_link_missing', $result['notes'] ); + } + + function test_missing_license_is_warning(): void { + $readme = <<<'README' +=== Test Tool === +Contributors: validatoruser +Tested up to: 6.4 +Stable tag: 1.0 + +Short description. + +== Description == + +Long description. +README; + $validator = Validator::instance(); + $result = $validator->validate( $readme ); + + $this->assertArrayHasKey( 'license_missing', $result['warnings'] ); + } + + /** + * Test translate_code_to_message returns strings for known codes. + * + * @dataProvider data_translate_code_to_message + */ + function test_translate_code_to_message( $code ): void { + $validator = Validator::instance(); + $result = $validator->translate_code_to_message( $code ); + + $this->assertIsString( $result ); + $this->assertNotEmpty( $result ); + } + + function data_translate_code_to_message(): array { + return [ + 'invalid name' => [ 'invalid_plugin_name_header' ], + 'tested missing' => [ 'tested_header_missing' ], + 'stable tag invalid' => [ 'stable_tag_invalid' ], + 'contributors missing' => [ 'contributors_missing' ], + 'faq missing' => [ 'faq_missing' ], + 'changelog missing' => [ 'changelog_missing' ], + 'screenshots missing' => [ 'screenshots_missing' ], + 'donate link missing' => [ 'donate_link_missing' ], + 'license missing' => [ 'license_missing' ], + 'requires missing' => [ 'requires_header_missing' ], + 'requires php missing' => [ 'requires_php_header_missing' ], + 'upgrade notice' => [ 'upgrade_notice_missing' ], + ]; + } + + function test_translate_code_to_message_unknown_code_returns_false(): void { + $validator = Validator::instance(); + $result = $validator->translate_code_to_message( 'nonexistent_code' ); + + $this->assertFalse( $result ); + } + + function test_translate_code_contributor_ignored_with_data(): void { + $validator = Validator::instance(); + $result = $validator->translate_code_to_message( 'contributor_ignored', [ 'fakeuser1', 'fakeuser2' ] ); + + $this->assertIsString( $result ); + $this->assertStringContainsString( 'fakeuser1', $result ); + $this->assertStringContainsString( 'fakeuser2', $result ); + } + + function test_translate_code_contributor_ignored_without_data(): void { + $validator = Validator::instance(); + $result = $validator->translate_code_to_message( 'contributor_ignored' ); + + $this->assertIsString( $result ); + $this->assertStringContainsString( 'Contributors', $result ); + } + + function test_validate_content_returns_translated_messages(): void { + $validator = Validator::instance(); + $result = $validator->validate_content( '' ); + + // validate_content translates error codes to human-readable strings. + foreach ( $result['errors'] as $message ) { + $this->assertIsString( $message ); + } + foreach ( $result['warnings'] as $message ) { + $this->assertIsString( $message ); + } + foreach ( $result['notes'] as $message ) { + $this->assertIsString( $message ); + } + } + + function test_last_content_stored(): void { + $validator = Validator::instance(); + $readme = "=== Test ===\nStable tag: 1.0\n\nDesc."; + $validator->validate( $readme ); + + $this->assertSame( $readme, $validator->last_content ); + } +} diff --git a/wordpress.org/public_html/wp-content/plugins/plugin-directory/tests/phpunit/tests/test-template.php b/wordpress.org/public_html/wp-content/plugins/plugin-directory/tests/phpunit/tests/test-template.php new file mode 100644 index 0000000000..8656dfeb80 --- /dev/null +++ b/wordpress.org/public_html/wp-content/plugins/plugin-directory/tests/phpunit/tests/test-template.php @@ -0,0 +1,258 @@ +post->create_and_get( array_merge( [ + 'post_type' => 'plugin', + 'post_status' => 'publish', + 'post_modified' => $now, + 'post_modified_gmt' => $gmt, + ], $args ) ); + } + + /** + * @dataProvider data_sanitize_active_installs + */ + function test_sanitize_active_installs( $input, $expected ): void { + // floor() returns float, so use assertEquals for loose type comparison. + $this->assertEquals( $expected, Template::sanitize_active_installs( $input ) ); + } + + function data_sanitize_active_installs(): array { + return [ + 'zero' => [ 0, 0 ], + 'single digit' => [ 5, 0 ], + 'ten' => [ 10, 10 ], + 'twelve' => [ 12, 10 ], + 'ninety nine' => [ 99, 90 ], + 'one hundred' => [ 100, 100 ], + 'hundred fifty' => [ 150, 100 ], + 'nine ninety nine' => [ 999, 900 ], + 'one thousand' => [ 1000, 1000 ], + 'one thousand five' => [ 1500, 1000 ], + 'ten thousand' => [ 10000, 10000 ], + 'fifteen thousand' => [ 15000, 10000 ], + 'hundred thousand' => [ 100000, 100000 ], + 'five hundred k' => [ 500000, 500000 ], + 'one million' => [ 1000000, 1000000 ], + 'five million' => [ 5000000, 5000000 ], + 'ten million' => [ 10000000, 10000000 ], + 'over ten million' => [ 15000000, 10000000 ], + 'fifty million' => [ 50000000, 10000000 ], + ]; + } + + /** + * @dataProvider data_format_active_installs_for_display + */ + function test_format_active_installs_for_display( $input, $expected ): void { + $this->assertSame( $expected, Template::format_active_installs_for_display( $input ) ); + } + + function data_format_active_installs_for_display(): array { + return [ + 'zero' => [ 0, 'Fewer than 10' ], + 'five' => [ 5, 'Fewer than 10' ], + 'nine' => [ 9, 'Fewer than 10' ], + 'ten' => [ 10, '10+' ], + 'hundred' => [ 100, '100+' ], + 'thousand' => [ 1000, '1,000+' ], + 'ten thousand' => [ 10000, '10,000+' ], + 'one million' => [ 1000000, '1+ million' ], + 'two million' => [ 2000000, '2+ million' ], + 'ten million' => [ 10000000, '10+ million' ], + ]; + } + + function test_get_plugin_section_titles(): void { + $titles = Template::get_plugin_section_titles(); + + $this->assertIsArray( $titles ); + + $expected_keys = [ + 'description', + 'installation', + 'faq', + 'screenshots', + 'changelog', + 'stats', + 'support', + 'reviews', + 'developers', + 'other_notes', + 'blocks', + ]; + + $this->assertSame( $expected_keys, array_keys( $titles ) ); + } + + function test_get_current_major_wp_version_returns_float(): void { + $version = Template::get_current_major_wp_version(); + + $this->assertIsFloat( $version ); + $this->assertGreaterThan( 0, $version ); + } + + /** + * @dataProvider data_encode + */ + function test_encode( $input, $expected ): void { + $this->assertSame( $expected, Template::encode( $input ) ); + } + + function data_encode(): array { + return [ + 'plain ascii' => [ 'Hello World', 'Hello World' ], + 'empty string' => [ '', '' ], + 'numeric entity' => [ 'café', 'café' ], + 'utf8 e-acute' => [ "caf\xC3\xA9", 'café' ], + 'utf8 em-dash' => [ "\xE2\x80\x94", '—' ], + 'utf8 copyright' => [ "\xC2\xA9", '©' ], + // encode() round-trips & < > via htmlentities + htmlspecialchars_decode (ENT_NOQUOTES). + 'ampersand' => [ 'A & B', 'A & B' ], + 'angle brackets' => [ 'a < b > c', 'a < b > c' ], + ]; + } + + /** + * Test dashicons_stars output. + * + * @dataProvider data_dashicons_stars + */ + function test_dashicons_stars( $rating, $filled, $half, $empty_stars ): void { + $output = Template::dashicons_stars( $rating ); + + $this->assertSame( $filled, substr_count( $output, 'dashicons-star-filled' ) ); + $this->assertSame( $half, substr_count( $output, 'dashicons-star-half' ) ); + $this->assertSame( $empty_stars, substr_count( $output, 'dashicons-star-empty' ) ); + } + + function data_dashicons_stars(): array { + // [ rating, filled, half, empty ] + return [ + 'zero stars' => [ 0, 0, 0, 5 ], + 'one star' => [ 1, 1, 0, 4 ], + 'two and a half' => [ 2.5, 2, 1, 2 ], + 'four stars' => [ 4, 4, 0, 1 ], + 'five stars' => [ 5, 5, 0, 0 ], + 'three point 3' => [ 3.3, 3, 1, 1 ], + ]; + } + + function test_get_close_reasons_returns_expected_keys(): void { + $reasons = Template::get_close_reasons(); + + $this->assertIsArray( $reasons ); + $this->assertArrayHasKey( 'security-issue', $reasons ); + $this->assertArrayHasKey( 'author-request', $reasons ); + $this->assertArrayHasKey( 'guideline-violation', $reasons ); + $this->assertArrayHasKey( 'licensing-trademark-violation', $reasons ); + $this->assertArrayHasKey( 'merged-into-core', $reasons ); + $this->assertArrayHasKey( 'unused', $reasons ); + } + + function test_get_rejection_reasons_returns_expected_keys(): void { + $reasons = Template::get_rejection_reasons(); + + $this->assertIsArray( $reasons ); + $this->assertArrayHasKey( '3-month', $reasons ); + $this->assertArrayHasKey( 'security', $reasons ); + $this->assertArrayHasKey( 'duplicate', $reasons ); + $this->assertArrayHasKey( 'banned', $reasons ); + } + + function test_download_link_with_version(): void { + $plugin = $this->create_plugin_post( [ 'post_name' => 'test-download' ] ); + update_post_meta( $plugin->ID, 'stable_tag', '2.1.0' ); + + $link = Template::download_link( $plugin, '1.0.0' ); + $this->assertSame( 'https://downloads.wordpress.org/plugin/test-download.1.0.0.zip', $link ); + + $link = Template::download_link( $plugin, 'latest' ); + $this->assertSame( 'https://downloads.wordpress.org/plugin/test-download.2.1.0.zip', $link ); + + $link = Template::download_link( $plugin, 'trunk' ); + $this->assertSame( 'https://downloads.wordpress.org/plugin/test-download.zip', $link ); + } + + function test_get_support_url_standard(): void { + $plugin = $this->create_plugin_post( [ 'post_name' => 'my-cool-tool' ] ); + + $url = Template::get_support_url( $plugin ); + $this->assertSame( 'https://wordpress.org/support/plugin/my-cool-tool/', $url ); + } + + function test_get_support_url_buddypress(): void { + $plugin = $this->create_plugin_post( [ 'post_name' => 'buddypress' ] ); + + $url = Template::get_support_url( $plugin ); + $this->assertSame( 'https://buddypress.org/support/', $url ); + } + + function test_get_support_url_bbpress(): void { + $plugin = $this->create_plugin_post( [ 'post_name' => 'bbpress' ] ); + + $url = Template::get_support_url( $plugin ); + $this->assertSame( 'https://bbpress.org/forums/', $url ); + } + + function test_geopattern_icon_url_format(): void { + $plugin = $this->create_plugin_post( [ 'post_name' => 'geo-test' ] ); + + $url = Template::get_geopattern_icon_url( $plugin ); + $this->assertStringContainsString( 'geo-test', $url ); + $this->assertStringContainsString( 'geopattern-icon', $url ); + $this->assertStringEndsWith( '.svg', $url ); + } + + function test_geopattern_icon_url_with_color(): void { + $plugin = $this->create_plugin_post( [ 'post_name' => 'geo-color' ] ); + + $url = Template::get_geopattern_icon_url( $plugin, 'ff5500' ); + $this->assertStringContainsString( 'geo-color_ff5500', $url ); + } + + function test_geopattern_icon_url_with_invalid_color(): void { + $plugin = $this->create_plugin_post( [ 'post_name' => 'geo-invalid' ] ); + + $url = Template::get_geopattern_icon_url( $plugin, 'notacolor' ); + $this->assertStringNotContainsString( '_notacolor', $url ); + } + + function test_is_plugin_outdated(): void { + $plugin = $this->create_plugin_post( [ 'post_name' => 'old-tool' ] ); + + // Set tested to a very old version. + update_post_meta( $plugin->ID, 'tested', '4.0' ); + $this->assertTrue( Template::is_plugin_outdated( $plugin ) ); + + // Set tested to current version. + $current = Template::get_current_major_wp_version(); + update_post_meta( $plugin->ID, 'tested', (string) $current ); + $this->assertFalse( Template::is_plugin_outdated( $plugin ) ); + } + + function test_get_rollout_strategies(): void { + $strategies = Template::get_rollout_strategies(); + + $this->assertIsArray( $strategies ); + $this->assertArrayHasKey( '', $strategies ); + $this->assertArrayHasKey( 'manual-updates-24hr', $strategies ); + $this->assertArrayHasKey( 'name', $strategies[''] ); + $this->assertArrayHasKey( 'description', $strategies[''] ); + } +} diff --git a/wordpress.org/public_html/wp-content/plugins/plugin-directory/tests/phpunit/tests/test-trademarks.php b/wordpress.org/public_html/wp-content/plugins/plugin-directory/tests/phpunit/tests/test-trademarks.php new file mode 100644 index 0000000000..f7904bf61f --- /dev/null +++ b/wordpress.org/public_html/wp-content/plugins/plugin-directory/tests/phpunit/tests/test-trademarks.php @@ -0,0 +1,120 @@ +assertFalse( Trademarks::check_slug( $slug ) ); + } + + function data_clean_slugs(): array { + // Note: 'plugin' is a trademarked slug, so avoid it in clean slugs. + return [ + 'generic slug' => [ 'my-cool-tool' ], + 'simple slug' => [ 'hello-world' ], + 'numeric slug' => [ 'acme-2024' ], + 'short slug' => [ 'foo' ], + ]; + } + + /** + * Test that trademarked prefix slugs are detected. + * + * @dataProvider data_trademarked_prefix_slugs + */ + function test_trademarked_prefix_slugs( $slug, $expected_trademark ): void { + $result = Trademarks::check_slug( $slug ); + $this->assertIsArray( $result ); + $this->assertContains( $expected_trademark, $result ); + } + + function data_trademarked_prefix_slugs(): array { + return [ + 'google prefix' => [ 'google-analytics-tool', 'google-' ], + 'facebook in slug' => [ 'my-facebook-share', 'facebook' ], + 'jetpack prefix' => [ 'jetpack-addon', 'jetpack-' ], + 'stripe prefix' => [ 'stripe-payments', 'stripe-' ], + 'paypal prefix' => [ 'paypal-checkout', 'paypal-' ], + 'woocommerce slug' => [ 'woocommerce-extras', 'woocommerce' ], + 'instagram slug' => [ 'instagram-feed-widget', 'instagram' ], + 'twitter slug' => [ 'twitter-cards', 'twitter-' ], + 'chatgpt prefix' => [ 'chatgpt-assistant', 'chatgpt-' ], + ]; + } + + /** + * Test the for-woocommerce exception. + */ + function test_for_woocommerce_exception(): void { + // "something-for-woocommerce" is allowed. + $this->assertFalse( Trademarks::check_slug( 'my-payments-for-woocommerce' ) ); + + // But "woocommerce-something" is not. + $result = Trademarks::check_slug( 'woocommerce-payments' ); + $this->assertIsArray( $result ); + } + + /** + * Test that check() converts a plugin name to slug first. + */ + function test_check_converts_name_to_slug(): void { + // "My Cool Tool" should be clean (note: 'plugin' is trademarked). + $this->assertFalse( Trademarks::check( 'My Cool Tool' ) ); + + // "Google Maps Helper" should be trademarked (contains 'google-'). + $result = Trademarks::check( 'Google Maps Helper' ); + $this->assertIsArray( $result ); + } + + /** + * Test that trademark exceptions work. + */ + function test_trademark_exceptions(): void { + // Without exception, jetpack- is trademarked. + $result = Trademarks::check_slug( 'jetpack-boost-extra' ); + $this->assertIsArray( $result ); + + // With automattic.com exception, jetpack- is allowed. + $result = Trademarks::check_slug( 'jetpack-boost-extra', [ 'automattic.com' ] ); + $this->assertFalse( $result ); + } + + /** + * Test published plugin exception for wp- prefix. + */ + function test_published_plugin_wp_prefix_exception(): void { + // wp- is flagged for new plugins. + $result = Trademarks::check_slug( 'wp-super-cache' ); + $this->assertIsArray( $result ); + + // published-plugin exception allows wp-. + $result = Trademarks::check_slug( 'wp-super-cache', [ 'published-plugin' ] ); + $this->assertFalse( $result ); + } + + /** + * Test portmanteau detection (e.g. woopress). + */ + function test_portmanteau_detection(): void { + $result = Trademarks::check_slug( 'woopress' ); + $this->assertIsArray( $result ); + } + + /** + * Test that the trademarked slugs list is not empty. + */ + function test_trademarked_slugs_list_is_populated(): void { + $this->assertNotEmpty( Trademarks::$trademarked_slugs ); + $this->assertGreaterThan( 50, count( Trademarks::$trademarked_slugs ) ); + } +} diff --git a/wordpress.org/public_html/wp-content/plugins/plugin-directory/tests/phpunit/tests/wporg-plugin-api-performance.php b/wordpress.org/public_html/wp-content/plugins/plugin-directory/tests/phpunit/tests/wporg-plugin-api-performance.php index 1dd1c8b7b3..5ebaf06640 100644 --- a/wordpress.org/public_html/wp-content/plugins/plugin-directory/tests/phpunit/tests/wporg-plugin-api-performance.php +++ b/wordpress.org/public_html/wp-content/plugins/plugin-directory/tests/phpunit/tests/wporg-plugin-api-performance.php @@ -44,12 +44,12 @@ class Tests_Plugins_API_Performance extends WP_UnitTestCase { 'contributors' => true, ); - function setUp() { + function setUp(): void { parent::setUp(); add_filter( 'http_headers_useragent', array( $this, 'filter_http_headers_useragent' ) ); } - function tearDown() { + function tearDown(): void { remove_filter( 'http_headers_useragent', array( $this, 'filter_http_headers_useragent' ) ); parent::tearDown(); } @@ -64,7 +64,7 @@ static function averages( $values, $decimals = 4 ) { } - static function tearDownAfterClass() { + static function tearDownAfterClass(): void { global $wporg_plugin_api_performance; echo 'Performance summary for ' . get_called_class() . ":\n"; diff --git a/wordpress.org/public_html/wp-content/plugins/plugin-directory/tests/phpunit/tests/wporg-plugin-api.php b/wordpress.org/public_html/wp-content/plugins/plugin-directory/tests/phpunit/tests/wporg-plugin-api.php index 7f04e61be3..4d837d6336 100644 --- a/wordpress.org/public_html/wp-content/plugins/plugin-directory/tests/phpunit/tests/wporg-plugin-api.php +++ b/wordpress.org/public_html/wp-content/plugins/plugin-directory/tests/phpunit/tests/wporg-plugin-api.php @@ -44,12 +44,12 @@ class Tests_Plugins_API extends WP_UnitTestCase { 'donate_link' => true, ); - function setUp() { + function setUp(): void { parent::setUp(); add_filter( 'http_headers_useragent', array( $this, 'filter_http_headers_useragent' ) ); } - function tearDown() { + function tearDown(): void { remove_filter( 'http_headers_useragent', array( $this, 'filter_http_headers_useragent' ) ); parent::tearDown(); } diff --git a/wordpress.org/public_html/wp-content/plugins/plugin-directory/tests/stubs/jetpack-search-stub.php b/wordpress.org/public_html/wp-content/plugins/plugin-directory/tests/stubs/jetpack-search-stub.php new file mode 100644 index 0000000000..79f97f7971 --- /dev/null +++ b/wordpress.org/public_html/wp-content/plugins/plugin-directory/tests/stubs/jetpack-search-stub.php @@ -0,0 +1,42 @@ +found_posts`. + * + * @return array|null + */ + public function get_last_query_info() { + return null; + } + } +} diff --git a/wordpress.org/public_html/wp-content/plugins/plugin-directory/tests/stubs/wporg-ratings-stub.php b/wordpress.org/public_html/wp-content/plugins/plugin-directory/tests/stubs/wporg-ratings-stub.php new file mode 100644 index 0000000000..e8fb8eb147 --- /dev/null +++ b/wordpress.org/public_html/wp-content/plugins/plugin-directory/tests/stubs/wporg-ratings-stub.php @@ -0,0 +1,34 @@ +