<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN"
"http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head><meta http-equiv="content-type" content="text/html; charset=utf-8" />
<title>[51598] trunk: Build/Test Tools: Make the polyfills loading more flexible.</title>
</head>
<body>

<style type="text/css"><!--
#msg dl.meta { border: 1px #006 solid; background: #369; padding: 6px; color: #fff; }
#msg dl.meta dt { float: left; width: 6em; font-weight: bold; }
#msg dt:after { content:':';}
#msg dl, #msg dt, #msg ul, #msg li, #header, #footer, #logmsg { font-family: verdana,arial,helvetica,sans-serif; font-size: 10pt;  }
#msg dl a { font-weight: bold}
#msg dl a:link    { color:#fc3; }
#msg dl a:active  { color:#ff0; }
#msg dl a:visited { color:#cc6; }
h3 { font-family: verdana,arial,helvetica,sans-serif; font-size: 10pt; font-weight: bold; }
#msg pre { white-space: pre-line; overflow: auto; background: #ffc; border: 1px #fa0 solid; padding: 6px; }
#logmsg { background: #ffc; border: 1px #fa0 solid; padding: 1em 1em 0 1em; }
#logmsg p, #logmsg pre, #logmsg blockquote { margin: 0 0 1em 0; }
#logmsg p, #logmsg li, #logmsg dt, #logmsg dd { line-height: 14pt; }
#logmsg h1, #logmsg h2, #logmsg h3, #logmsg h4, #logmsg h5, #logmsg h6 { margin: .5em 0; }
#logmsg h1:first-child, #logmsg h2:first-child, #logmsg h3:first-child, #logmsg h4:first-child, #logmsg h5:first-child, #logmsg h6:first-child { margin-top: 0; }
#logmsg ul, #logmsg ol { padding: 0; list-style-position: inside; margin: 0 0 0 1em; }
#logmsg ul { text-indent: -1em; padding-left: 1em; }#logmsg ol { text-indent: -1.5em; padding-left: 1.5em; }
#logmsg > ul, #logmsg > ol { margin: 0 0 1em 0; }
#logmsg pre { background: #eee; padding: 1em; }
#logmsg blockquote { border: 1px solid #fa0; border-left-width: 10px; padding: 1em 1em 0 1em; background: white;}
#logmsg dl { margin: 0; }
#logmsg dt { font-weight: bold; }
#logmsg dd { margin: 0; padding: 0 0 0.5em 0; }
#logmsg dd:before { content:'\00bb';}
#logmsg table { border-spacing: 0px; border-collapse: collapse; border-top: 4px solid #fa0; border-bottom: 1px solid #fa0; background: #fff; }
#logmsg table th { text-align: left; font-weight: normal; padding: 0.2em 0.5em; border-top: 1px dotted #fa0; }
#logmsg table td { text-align: right; border-top: 1px dotted #fa0; padding: 0.2em 0.5em; }
#logmsg table thead th { text-align: center; border-bottom: 1px solid #fa0; }
#logmsg table th.Corner { text-align: left; }
#logmsg hr { border: none 0; border-top: 2px dashed #fa0; height: 1px; }
#header, #footer { color: #fff; background: #636; border: 1px #300 solid; padding: 6px; }
#patch { width: 100%; }
#patch h4 {font-family: verdana,arial,helvetica,sans-serif;font-size:10pt;padding:8px;background:#369;color:#fff;margin:0;}
#patch .propset h4, #patch .binary h4 {margin:0;}
#patch pre {padding:0;line-height:1.2em;margin:0;}
#patch .diff {width:100%;background:#eee;padding: 0 0 10px 0;overflow:auto;}
#patch .propset .diff, #patch .binary .diff  {padding:10px 0;}
#patch span {display:block;padding:0 10px;}
#patch .modfile, #patch .addfile, #patch .delfile, #patch .propset, #patch .binary, #patch .copfile {border:1px solid #ccc;margin:10px 0;}
#patch ins {background:#dfd;text-decoration:none;display:block;padding:0 10px;}
#patch del {background:#fdd;text-decoration:none;display:block;padding:0 10px;}
#patch .lines, .info {color:#888;background:#fff;}
--></style>
<div id="msg">
<dl class="meta" style="font-size: 105%">
<dt style="float: left; width: 6em; font-weight: bold">Revision</dt> <dd><a style="font-weight: bold" href="https://core.trac.wordpress.org/changeset/51598">51598</a><script type="application/ld+json">{"@context":"http://schema.org","@type":"EmailMessage","description":"Review this Commit","action":{"@type":"ViewAction","url":"https://core.trac.wordpress.org/changeset/51598","name":"Review Commit"}}</script></dd>
<dt style="float: left; width: 6em; font-weight: bold">Author</dt> <dd>SergeyBiryukov</dd>
<dt style="float: left; width: 6em; font-weight: bold">Date</dt> <dd>2021-08-10 21:13:38 +0000 (Tue, 10 Aug 2021)</dd>
</dl>

<pre style='padding-left: 1em; margin: 2em 0; border-left: 2px solid #ccc; line-height: 1.25; font-size: 105%; font-family: sans-serif'>Build/Test Tools: Make the polyfills loading more flexible.

The PHPUnit Polyfills are, since <a href="https://core.trac.wordpress.org/changeset/51559">[51559]</a>, a required dependency for the WP test suite and, by extension, for plugin/theme integration test suites which are based on and use (parts of) the WP core test suite.

However, plugin/theme integration test suites may not use a full WordPress installation.

This commit:
* Removes the presumption that a full WP install, including `vendor` directory, will be available when the test `bootstrap.php` file is run.
* Makes the loading of the PHPUnit Polyfills autoload file more flexible by:
  * Checking if the autoload class contained within the autoload file is already available before attempting to load the file.[[BR]]
    This allows for plugin/theme integration test suites to load the `phpunitpolyfills-autoload.php` file from any location, as long as it is loaded before the WP core test `bootstrap.php` file is run.
  * Allowing for the path to an arbitrary installation location for the PHPUnit Polyfills to be passed as a constant.[[BR]]
    As long as the provided location is a valid file path and the `phpunitpolyfills-autoload.php` file exists in the provided location, that file will be loaded.[[BR]]
    The constant can be declared in a plugin/theme integration test suite native test bootstrap file, or in the `wp-tests-config.php` file, or even in a `phpunit.xml[.dist]` file via `<php><const name="WP_TESTS_PHPUNIT_POLYFILLS_PATH" value="path/to/yoast/phpunit-polyfills"/></php>`.
* Adds a version check for the PHPUnit Polyfills to prevent a mismatch between the version of the package expected by WordPress and the version used by plugins/themes.[[BR]]
  The version this checks for should be in line with the minimum version requirement for the PHPUnit Polyfills as declared in the `composer.json` file.[[BR]]
  This version number should only be updated when new features added in later PHPUnit Polyfills releases are actually used in the WP core test suite.
* Adds appropriate error messages for every possible error condition.
* Upgrades the PHPUnit Polyfills to version 1.0.1, which now includes a version constant.

Follow-up to [51559-51577].

Props jrf, hellofromTonya, swissspidy, jeherve, thomasplevy, SergeyBiryukov.
See <a href="https://core.trac.wordpress.org/ticket/46149">#46149</a>.</pre>

<h3>Modified Paths</h3>
<ul>
<li><a href="#trunkcomposerjson">trunk/composer.json</a></li>
<li><a href="#trunktestsphpunitincludesbootstrapphp">trunk/tests/phpunit/includes/bootstrap.php</a></li>
</ul>

</div>
<div id="patch">
<h3>Diff</h3>
<a id="trunkcomposerjson"></a>
<div class="modfile"><h4 style="background-color: #eee; color: inherit; margin: 1em 0; padding: 1.3em; font-size: 115%">Modified: trunk/composer.json</h4>
<pre class="diff"><span>
<span class="info" style="display: block; padding: 0 10px; color: #888">--- trunk/composer.json       2021-08-10 19:43:33 UTC (rev 51597)
+++ trunk/composer.json 2021-08-10 21:13:38 UTC (rev 51598)
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -17,7 +17,7 @@
</span><span class="cx" style="display: block; padding: 0 10px">                "squizlabs/php_codesniffer": "3.6.0",
</span><span class="cx" style="display: block; padding: 0 10px">                "wp-coding-standards/wpcs": "~2.3.0",
</span><span class="cx" style="display: block; padding: 0 10px">                "phpcompatibility/phpcompatibility-wp": "~2.1.2",
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-                "yoast/phpunit-polyfills": "^1.0"
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+         "yoast/phpunit-polyfills": "^1.0.1"
</ins><span class="cx" style="display: block; padding: 0 10px">         },
</span><span class="cx" style="display: block; padding: 0 10px">        "scripts": {
</span><span class="cx" style="display: block; padding: 0 10px">                "compat": "@php ./vendor/squizlabs/php_codesniffer/bin/phpcs --standard=phpcompat.xml.dist --report=summary,source",
</span></span></pre></div>
<a id="trunktestsphpunitincludesbootstrapphp"></a>
<div class="modfile"><h4 style="background-color: #eee; color: inherit; margin: 1em 0; padding: 1.3em; font-size: 115%">Modified: trunk/tests/phpunit/includes/bootstrap.php</h4>
<pre class="diff"><span>
<span class="info" style="display: block; padding: 0 10px; color: #888">--- trunk/tests/phpunit/includes/bootstrap.php        2021-08-10 19:43:33 UTC (rev 51597)
+++ trunk/tests/phpunit/includes/bootstrap.php  2021-08-10 21:13:38 UTC (rev 51598)
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -46,13 +46,86 @@
</span><span class="cx" style="display: block; padding: 0 10px">        exit( 1 );
</span><span class="cx" style="display: block; padding: 0 10px"> }
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-// Check that the PHPUnit Polyfills autoloader exists.
-$phpunit_polyfills_autoloader = __DIR__ . '/../../../vendor/yoast/phpunit-polyfills/phpunitpolyfills-autoload.php';
-if ( ! file_exists( $phpunit_polyfills_autoloader ) ) {
-       echo 'Error: You need to run `composer update` before running the tests.' . PHP_EOL;
-       echo 'You can still use a PHPUnit phar to run them, but the dependencies do need to be installed.' . PHP_EOL;
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+/*
+ * Load the PHPUnit Polyfills autoloader.
+ *
+ * The PHPUnit Polyfills are a requirement for the WP test suite.
+ *
+ * Plugin/theme integration tests can handle this in any of the following ways:
+ * - When using a full WP install: run `composer update` for the WP install prior to running the tests.
+ * - When using a partial WP test suite install:
+ *   - Add a `yoast/phpunit-polyfills` (dev) requirement to their own `composer.json` file.
+ *   - And then:
+ *     - Either load the PHPUnit Polyfills autoload file prior to running the WP core bootstrap file.
+ *     - Or declare a `WP_TESTS_PHPUNIT_POLYFILLS_PATH` constant pointing to the root directory
+ *       of the PHPUnit Polyfills installation.
+ *       This constant can be declared in the `phpunit.xml[.dist]` file like this:
+ *       `<php><const name="WP_TESTS_PHPUNIT_POLYFILLS_PATH" value="path/to/yoast/phpunit-polyfills"/></php>
+ *       or can be declared as a PHP constant in the `wp-tests-config.php` file or the plugin/theme
+ *       test bootstrap file.
+ */
+if ( ! class_exists( 'Yoast\PHPUnitPolyfills\Autoload' ) ) {
+       // Default location of the autoloader for WP core test runs.
+       $phpunit_polyfills_autoloader = __DIR__ . '/../../../vendor/yoast/phpunit-polyfills/phpunitpolyfills-autoload.php';
+       $phpunit_polyfills_error      = false;
+
+       // Allow for a custom installation location to be provided for plugin/theme integration tests.
+       if ( defined( 'WP_TESTS_PHPUNIT_POLYFILLS_PATH' ) ) {
+               $phpunit_polyfills_path = WP_TESTS_PHPUNIT_POLYFILLS_PATH;
+
+               if ( is_string( WP_TESTS_PHPUNIT_POLYFILLS_PATH )
+                       && '' !== WP_TESTS_PHPUNIT_POLYFILLS_PATH
+               ) {
+                       $phpunit_polyfills_path = rtrim( $phpunit_polyfills_path, '/\\' );
+                       $phpunit_polyfills_path = realpath( $phpunit_polyfills_path . '/phpunitpolyfills-autoload.php' );
+                       if ( false !== $phpunit_polyfills_path ) {
+                               $phpunit_polyfills_autoloader = $phpunit_polyfills_path;
+                       } else {
+                               $phpunit_polyfills_error = true;
+                       }
+               } else {
+                       $phpunit_polyfills_error = true;
+               }
+       }
+
+       if ( $phpunit_polyfills_error || ! file_exists( $phpunit_polyfills_autoloader ) ) {
+               echo 'Error: The PHPUnit Polyfills library is a requirement for running the WP test suite.' . PHP_EOL;
+               if ( isset( $phpunit_polyfills_path ) ) {
+                       printf(
+                               'The PHPUnit Polyfills autoload file was not found in "%s"' . PHP_EOL,
+                               WP_TESTS_PHPUNIT_POLYFILLS_PATH
+                       );
+                       echo 'Please verify that the file path provided in the WP_TESTS_PHPUNIT_POLYFILLS_PATH constant is correct.' . PHP_EOL;
+               } else {
+                       echo 'You need to run `composer update` before running the tests.' . PHP_EOL;
+                       echo 'Once the dependencies are installed, you can run the tests using the Composer-installed version of PHPUnit or using a PHPUnit phar file, but the dependencies do need to be installed whichever way the tests are run.' . PHP_EOL;
+               }
+               exit( 1 );
+       }
+
+       require_once $phpunit_polyfills_autoloader;
+}
+unset( $phpunit_polyfills_autoloader, $phpunit_polyfills_error, $phpunit_polyfills_path );
+
+/*
+ * Minimum version of the PHPUnit Polyfills package as declared in `composer.json`.
+ * Only needs updating when new polyfill features start being used in the test suite.
+ */
+$phpunit_polyfills_minimum_version = '1.0.1';
+if ( class_exists( '\Yoast\PHPUnitPolyfills\Autoload' )
+       && ( defined( '\Yoast\PHPUnitPolyfills\Autoload::VERSION' ) === false
+       || version_compare( \Yoast\PHPUnitPolyfills\Autoload::VERSION, $phpunit_polyfills_minimum_version, '<' ) )
+) {
+       printf(
+               'Error: Version mismatch detected for the PHPUnit Polyfills. Please ensure that PHPUnit Polyfills %s or higher is loaded.' . PHP_EOL,
+               $phpunit_polyfills_minimum_version
+       );
+       if ( ! defined( 'WP_TESTS_PHPUNIT_POLYFILLS_PATH' ) ) {
+               echo 'Please run `composer update` to install the latest version.' . PHP_EOL;
+       }
</ins><span class="cx" style="display: block; padding: 0 10px">         exit( 1 );
</span><span class="cx" style="display: block; padding: 0 10px"> }
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+unset( $phpunit_polyfills_minimum_version );
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px"> // If running core tests, check if all the required PHP extensions are loaded before running the test suite.
</span><span class="cx" style="display: block; padding: 0 10px"> if ( defined( 'WP_RUN_CORE_TESTS' ) && WP_RUN_CORE_TESTS ) {
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -199,10 +272,6 @@
</span><span class="cx" style="display: block; padding: 0 10px">        require __DIR__ . '/phpunit6/compat.php';
</span><span class="cx" style="display: block; padding: 0 10px"> }
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-// Load the PHPUnit Polyfills autoloader (check for existence of the file is done earlier in the script).
-require_once $phpunit_polyfills_autoloader;
-unset( $phpunit_polyfills_autoloader );
-
</del><span class="cx" style="display: block; padding: 0 10px"> require __DIR__ . '/phpunit-adapter-testcase.php';
</span><span class="cx" style="display: block; padding: 0 10px"> require __DIR__ . '/abstract-testcase.php';
</span><span class="cx" style="display: block; padding: 0 10px"> require __DIR__ . '/testcase.php';
</span></span></pre>
</div>
</div>

</body>
</html>