Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,8 @@
"wp-coding-standards/wpcs": "~3.3.0",
"phpcompatibility/phpcompatibility-wp": "~2.1.3",
"phpstan/phpstan": "2.1.39",
"yoast/phpunit-polyfills": "^1.1.0"
"yoast/phpunit-polyfills": "^1.1.0",
"phpbench/phpbench": "^1.5"
},
"config": {
"allow-plugins": {
Expand Down
74 changes: 74 additions & 0 deletions phpbench-bootstrap.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
<?php
/**
* Bootstrap file for phpbench benchmarks.
*
* Loads WordPress for running benchmarks.
*/

define( 'PHPBENCH_ROOT', __DIR__ );

if ( defined( 'WP_TESTS_CONFIG_FILE_PATH' ) ) {
$config_file_path = WP_TESTS_CONFIG_FILE_PATH;
} else {
$config_file_path = __DIR__ . '/wp-tests-config.php';
}

/*
* Globalize some WordPress variables.
*/
global $wpdb, $current_site, $current_blog, $wp_rewrite, $shortcode_tags, $wp, $phpmailer, $wp_theme_directories;

if ( ! is_readable( $config_file_path ) ) {
exit( 1 );
}
Comment on lines +21 to +23
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

For better debugging, it's helpful to output an error message to stderr when the script exits due to a fatal condition. This will make it easier to diagnose setup issues when running the benchmarks.

if ( ! is_readable( $config_file_path ) ) {
	fwri te( STDERR, "Error: Could not read the WordPress test configuration file from {$config_file_path}. Aborting.\n" );
	exit( 1 );
}


require_once $config_file_path;

if ( ! is_dir( ABSPATH ) ) {
exit( 1 );
}
Comment on lines +27 to +29
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

Similar to the check above, adding an error message here would improve debuggability if ABSPATH is not correctly defined or doesn't point to a directory.

if ( ! is_dir( ABSPATH ) ) {
	fwrite( STDERR, 'Error: The ABSPATH ' . ABSPATH . " is not a directory. Aborting.\n" );
	exit( 1 );
}


function tests_reset__SERVER() { // phpcs:ignore WordPress.NamingConventions.ValidFunctionName.FunctionNameInvalid
$_SERVER['HTTP_HOST'] = WP_TESTS_DOMAIN;
$_SERVER['REMOTE_ADDR'] = '127.0.0.1';
$_SERVER['REQUEST_METHOD'] = 'GET';
$_SERVER['REQUEST_URI'] = '';
$_SERVER['SERVER_NAME'] = WP_TESTS_DOMAIN;
$_SERVER['SERVER_PORT'] = '80';
$_SERVER['SERVER_PROTOCOL'] = 'HTTP/1.1';

unset( $_SERVER['HTTP_REFERER'] );
unset( $_SERVER['HTTPS'] );
}
tests_reset__SERVER();

define( 'WP_TESTS_TABLE_PREFIX', $table_prefix );

define( 'DIR_BENCHMARKDATA', __DIR__ . '/tests/benchmarks/data' );
define( 'DIR_TESTDATA', __DIR__ . '/tests/phpunit/data' );
define( 'WP_LANG_DIR', realpath( DIR_TESTDATA . '/languages' ) );

/*
* Cron tries to make an HTTP request to the site, which always fails,
* because tests are run in CLI mode only.
*/
define( 'DISABLE_WP_CRON', true );

define( 'WP_MEMORY_LIMIT', -1 );
define( 'WP_MAX_MEMORY_LIMIT', -1 );

$PHP_SELF = '/index.php';
$GLOBALS['PHP_SELF'] = '/index.php';
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

This line is redundant. $PHP_SELF is a global variable, so assigning to it on line 60 is sufficient to set the global value. This line can be removed.

$_SERVER['PHP_SELF'] = '/index.php';

if ( ! defined( 'WP_DEFAULT_THEME' ) ) {
define( 'WP_DEFAULT_THEME', 'default' );
}
$wp_theme_directories = array();

if ( file_exists( DIR_TESTDATA . '/themedir1' ) ) {
$wp_theme_directories[] = DIR_TESTDATA . '/themedir1';
}

// Load WordPress.
require_once ABSPATH . 'wp-settings.php';
5 changes: 5 additions & 0 deletions phpbench.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
{
"$schema": "./vendor/phpbench/phpbench/phpbench.schema.json",
"runner.bootstrap": "phpbench-bootstrap.php",
"runner.path": "tests/benchmarks/benchmarks"
}
2 changes: 2 additions & 0 deletions phpcs.xml.dist
Original file line number Diff line number Diff line change
Expand Up @@ -286,6 +286,7 @@

<rule ref="PEAR.NamingConventions.ValidClassName.Invalid">
<exclude-pattern>/tests/phpunit/tests/*</exclude-pattern>
<exclude-pattern>/tests/benchmarks/benchmarks/*</exclude-pattern>
<!-- Exclude some old classes that cannot be renamed, as it would break back compat. -->
<exclude-pattern>/src/wp-admin/includes/class-wp-filesystem-ftpsockets\.php</exclude-pattern>
<exclude-pattern>/src/wp-includes/class-wp-oembed\.php</exclude-pattern>
Expand Down Expand Up @@ -328,6 +329,7 @@
<!-- Exclude the unit tests from the file name rules. -->
<rule ref="WordPress.Files.FileName">
<exclude-pattern>/tests/phpunit/*</exclude-pattern>
<exclude-pattern>/tests/benchmarks/benchmarks/*</exclude-pattern>
</rule>

<!-- WPCS1620: template.php isn't a template tag file. -->
Expand Down
177 changes: 177 additions & 0 deletions tests/benchmarks/benchmarks/html-api/WpHtmlTagProcessorBench.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,177 @@
<?php
/**
* Benchmarks for WP_HTML_Tag_Processor.
*
* @package WordPress
*/

declare(strict_types=1);

use PhpBench\Attributes as Bench;

class WpHtmlTagProcessorBench {
/**
* Processor instance for benchmarks.
*/
private WP_HTML_Tag_Processor|WP_HTML_Processor|null $processor = null;

public function clean_up_processor(): void {
$this->processor = null;
}

/**
* Benchmark normalizing simple Unix paths.
* @param array{0: string} $params
*/
#[Bench\Warmup( 2 )]
#[Bench\Iterations( 50 )]
#[Bench\Revs( 10 )]
#[Bench\BeforeMethods( 'set_up_script_tag_processor' )]
#[Bench\AfterMethods( 'clean_up_processor' )]
#[Bench\ParamProviders( 'provide_script_tag_contents' )]
public function bench_javascript_custom_escape( array $params ): void {
[ $source_text] = $params;
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

To adhere to common PHP coding standards (like PSR-12) and improve consistency, array destructuring should not have a space before the closing bracket. The standard form is [$var] = $array;.

		[$source_text] = $params;

assert( $this->processor->set_modifiable_text( $source_text ), 'Failed to set modifiable text.' );
}

public function set_up_script_tag_processor(): void {
$this->processor = new WP_HTML_Tag_Processor( '<script></script>' );
$this->processor->next_tag();
}

/**
* @return iterable<array{0: string}>
*/
public static function provide_script_tag_contents(): iterable {
yield 'empty' => array( '' );

yield 'short' => array( 'console.log("Hello, World!");' );

yield 'many replacements' => array(
<<<'JS'
/* <!-- and <script> is bad news in JS land! */
const templateString = `
But can't we talk about <script> and </script> tags without breaking everything?
</script>
</SCRIPT>
</SCRIPT >
</SCRIPT
>
</SCRIPT/>
</script/>
</script ignored attributes />
</script />
<script></script>
<script></script>
<script></script>
<script></script>
<script></script>
<script></script>
<script></script>
<script></script>
<script></script>
<script></script>
<script></script>
<script></script>
<script></script>
<script></script>
<script></script>
<script></script>
<script></script>
<script></script>
<script></script>
<script></script>
<script></script>
<script></script>
<script></script>
<script></script>
<script></script>
<script></script>
<script></script>
<script></script>
<script></script>
<script></script>
<script></script>
<script></script>
<script></script>
<script></script>
<script></script>
<script></script>
<script></script>
<script></script>
<script></script>
<script></script>
<script></script>
<script></script>
`;
/* Good luck! */
JS,
);
}

/**
* Benchmark HTML parsing.
* @param array{0: string} $params
*/
#[Bench\Warmup( 2 )]
#[Bench\Iterations( 20 )]
#[Bench\Revs( 5 )]
#[Bench\ParamProviders( 'provide_html' )]
#[Bench\BeforeMethods( 'set_up_html_tag_processor' )]
#[Bench\AfterMethods( 'clean_up_processor' )]
public function bench_tag_processor_html_parsing( array $params ): void {
while ( $this->processor->next_token() ) {
// No-op.
}
}

public function set_up_html_tag_processor( array $params ): void {
$this->processor = new WP_HTML_Tag_Processor( file_get_contents( $params[0] ) );
}

/**
* Benchmark HTML parsing.
* @param array{0: string} $params
*/
#[Bench\Warmup( 2 )]
#[Bench\Iterations( 20 )]
#[Bench\Revs( 3 )]
#[Bench\ParamProviders( 'provide_html' )]
#[Bench\BeforeMethods( 'set_up_html_fragment_processor' )]
#[Bench\AfterMethods( 'clean_up_processor' )]
public function bench_html_fragment_parsing( array $params ): void {
while ( $this->processor->next_token() ) {
// No-op.
}
}

public function set_up_html_fragment_processor( array $params ): void {
$this->processor = WP_HTML_Processor::create_fragment( file_get_contents( $params[0] ) );
}

/**
* Benchmark HTML parsing.
* @param array{0: string} $params
*/
#[Bench\Warmup( 2 )]
#[Bench\Iterations( 20 )]
#[Bench\Revs( 3 )]
#[Bench\ParamProviders( 'provide_html' )]
#[Bench\BeforeMethods( 'set_up_html_full_parser' )]
#[Bench\AfterMethods( 'clean_up_processor' )]
public function bench_html_full_parsing( array $params ): void {
while ( $this->processor->next_token() ) {
// No-op.
}
}

public function set_up_html_full_parser( array $params ): void {
$this->processor = WP_HTML_Processor::create_full_parser( file_get_contents( $params[0] ) );
}

public static function provide_html(): iterable {
yield 'Empty string' => array( 'data:text/html,' );
yield 'Short doc' => array( 'data:text/html,' . rawurlencode( '<h1>Hello, world!</h1>' ) );
yield 'HTML Standard' => array( 'file://' . DIR_BENCHMARKDATA . '/html-standard.html' );
}
}
Loading
Loading