<!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>[44701] trunk: Build/Test Tools: Add support for PHPUnit 7.x.</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/44701">44701</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/44701","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>2019-01-28 14:10:24 +0000 (Mon, 28 Jan 2019)</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: Add support for PHPUnit 7.x.

* Create an abstract `WP_UnitTestCase_Base` class to share between PHPUnit 7.x and older versions.
* Add a speed-trap loader to determine which `SpeedTrapListener` class needs to be loaded for the current PHPUnit version.
* Remove unnecessary `PHPUnit\Util\Test` and `PHPUnit_Util_Getopt` inheritances.
* Update Travis CI config to use PHPUnit 7.x for PHP 7.1, 7.2, and nightly PHP versions.

Props jipmoors, netweb, desrosj, ayeshrajans, soulseekah, SergeyBiryukov.
See <a href="https://core.trac.wordpress.org/ticket/43218">#43218</a>.</pre>

<h3>Modified Paths</h3>
<ul>
<li><a href="#trunktravisyml">trunk/.travis.yml</a></li>
<li><a href="#trunkphpunitxmldist">trunk/phpunit.xml.dist</a></li>
<li><a href="#trunktestsphpunitincludesbootstrapphp">trunk/tests/phpunit/includes/bootstrap.php</a></li>
<li><a href="#trunktestsphpunitincludesfunctionsphp">trunk/tests/phpunit/includes/functions.php</a></li>
<li><a href="#trunktestsphpunitincludestestcasecanonicalphp">trunk/tests/phpunit/includes/testcase-canonical.php</a></li>
<li><a href="#trunktestsphpunitincludestestcasephp">trunk/tests/phpunit/includes/testcase.php</a></li>
<li><a href="#trunktestsphpunitmultisitexml">trunk/tests/phpunit/multisite.xml</a></li>
<li><a href="#trunktestsphpunittestspostqueryphp">trunk/tests/phpunit/tests/post/query.php</a></li>
</ul>

<h3>Added Paths</h3>
<ul>
<li><a href="#trunktestsphpunitincludesabstracttestcasephp">trunk/tests/phpunit/includes/abstract-testcase.php</a></li>
<li><a href="#trunktestsphpunitincludeslistenerloaderphp">trunk/tests/phpunit/includes/listener-loader.php</a></li>
<li>trunk/tests/phpunit/includes/phpunit6/</li>
<li><a href="#trunktestsphpunitincludesphpunit6compatphp">trunk/tests/phpunit/includes/phpunit6/compat.php</a></li>
<li>trunk/tests/phpunit/includes/phpunit7/</li>
<li><a href="#trunktestsphpunitincludesphpunit7speedtraplistenerphp">trunk/tests/phpunit/includes/phpunit7/speed-trap-listener.php</a></li>
<li><a href="#trunktestsphpunitincludesphpunit7testcasephp">trunk/tests/phpunit/includes/phpunit7/testcase.php</a></li>
</ul>

<h3>Removed Paths</h3>
<ul>
<li><a href="#trunktestsphpunitincludesphpunit6compatphp">trunk/tests/phpunit/includes/phpunit6-compat.php</a></li>
</ul>

</div>
<div id="patch">
<h3>Diff</h3>
<a id="trunktravisyml"></a>
<div class="modfile"><h4 style="background-color: #eee; color: inherit; margin: 1em 0; padding: 1.3em; font-size: 115%">Modified: trunk/.travis.yml</h4>
<pre class="diff"><span>
<span class="info" style="display: block; padding: 0 10px; color: #888">--- trunk/.travis.yml 2019-01-27 14:45:42 UTC (rev 44700)
+++ trunk/.travis.yml   2019-01-28 14:10:24 UTC (rev 44701)
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -67,7 +67,11 @@
</span><span class="cx" style="display: block; padding: 0 10px">   # Install the specified version of PHPUnit depending on the PHP version:
</span><span class="cx" style="display: block; padding: 0 10px">   if [[ "$WP_TRAVISCI" == "travis:phpunit" ]]; then
</span><span class="cx" style="display: block; padding: 0 10px">     case "$TRAVIS_PHP_VERSION" in
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-      7.3|7.2|7.1|7.0|nightly)
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+      7.3|7.2|7.1|nightly)
+        echo "Using PHPUnit 7.x"
+        travis_retry composer global require "phpunit/phpunit:^7"
+        ;;
+      7.0)
</ins><span class="cx" style="display: block; padding: 0 10px">         echo "Using PHPUnit 6.x"
</span><span class="cx" style="display: block; padding: 0 10px">         travis_retry composer global require "phpunit/phpunit:^6"
</span><span class="cx" style="display: block; padding: 0 10px">         ;;
</span></span></pre></div>
<a id="trunkphpunitxmldist"></a>
<div class="modfile"><h4 style="background-color: #eee; color: inherit; margin: 1em 0; padding: 1.3em; font-size: 115%">Modified: trunk/phpunit.xml.dist</h4>
<pre class="diff"><span>
<span class="info" style="display: block; padding: 0 10px; color: #888">--- trunk/phpunit.xml.dist    2019-01-27 14:45:42 UTC (rev 44700)
+++ trunk/phpunit.xml.dist      2019-01-28 14:10:24 UTC (rev 44701)
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -40,7 +40,7 @@
</span><span class="cx" style="display: block; padding: 0 10px">         <const name="WP_RUN_CORE_TESTS" value="1" />
</span><span class="cx" style="display: block; padding: 0 10px">     </php>
</span><span class="cx" style="display: block; padding: 0 10px">        <listeners>
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-                <listener class="SpeedTrapListener" file="tests/phpunit/includes/speed-trap-listener.php">
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+         <listener class="SpeedTrapListener" file="tests/phpunit/includes/listener-loader.php">
</ins><span class="cx" style="display: block; padding: 0 10px">                         <arguments>
</span><span class="cx" style="display: block; padding: 0 10px">                                <array>
</span><span class="cx" style="display: block; padding: 0 10px">                                        <element key="slowThreshold">
</span></span></pre></div>
<a id="trunktestsphpunitincludesabstracttestcasephpfromrev44700trunktestsphpunitincludestestcasephp"></a>
<div class="copfile"><h4 style="background-color: #eee; color: inherit; margin: 1em 0; padding: 1.3em; font-size: 115%">Copied: trunk/tests/phpunit/includes/abstract-testcase.php (from rev 44700, trunk/tests/phpunit/includes/testcase.php)</h4>
<pre class="diff"><span>
<span class="info" style="display: block; padding: 0 10px; color: #888">--- trunk/tests/phpunit/includes/abstract-testcase.php                                (rev 0)
+++ trunk/tests/phpunit/includes/abstract-testcase.php  2019-01-28 14:10:24 UTC (rev 44701)
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -0,0 +1,1110 @@
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+<?php
+
+require_once dirname( __FILE__ ) . '/factory.php';
+require_once dirname( __FILE__ ) . '/trac.php';
+
+/**
+ * Defines a basic fixture to run multiple tests.
+ *
+ * Resets the state of the WordPress installation before and after every test.
+ *
+ * Includes utility functions and assertions useful for testing WordPress.
+ *
+ * All WordPress unit tests should inherit from this class.
+ */
+abstract class WP_UnitTestCase_Base extends PHPUnit_Framework_TestCase {
+
+       protected static $forced_tickets   = array();
+       protected $expected_deprecated     = array();
+       protected $caught_deprecated       = array();
+       protected $expected_doing_it_wrong = array();
+       protected $caught_doing_it_wrong   = array();
+
+       protected static $hooks_saved = array();
+       protected static $ignore_files;
+
+       function __isset( $name ) {
+               return 'factory' === $name;
+       }
+
+       function __get( $name ) {
+               if ( 'factory' === $name ) {
+                       return self::factory();
+               }
+       }
+
+       /**
+        * Fetches the factory object for generating WordPress fixtures.
+        *
+        * @return WP_UnitTest_Factory The fixture factory.
+        */
+       protected static function factory() {
+               static $factory = null;
+               if ( ! $factory ) {
+                       $factory = new WP_UnitTest_Factory();
+               }
+               return $factory;
+       }
+
+       public static function get_called_class() {
+               if ( function_exists( 'get_called_class' ) ) {
+                       return get_called_class();
+               }
+
+               // PHP 5.2 only
+               $backtrace = debug_backtrace();
+               // [0] WP_UnitTestCase::get_called_class()
+               // [1] WP_UnitTestCase::setUpBeforeClass()
+               if ( 'call_user_func' === $backtrace[2]['function'] ) {
+                       return $backtrace[2]['args'][0][0];
+               }
+               return $backtrace[2]['class'];
+       }
+
+       public static function setUpBeforeClass() {
+               global $wpdb;
+
+               $wpdb->suppress_errors = false;
+               $wpdb->show_errors     = true;
+               $wpdb->db_connect();
+               ini_set( 'display_errors', 1 );
+
+               parent::setUpBeforeClass();
+
+               $c = self::get_called_class();
+               if ( ! method_exists( $c, 'wpSetUpBeforeClass' ) ) {
+                       self::commit_transaction();
+                       return;
+               }
+
+               call_user_func( array( $c, 'wpSetUpBeforeClass' ), self::factory() );
+
+               self::commit_transaction();
+       }
+
+       public static function tearDownAfterClass() {
+               parent::tearDownAfterClass();
+
+               _delete_all_data();
+               self::flush_cache();
+
+               $c = self::get_called_class();
+               if ( ! method_exists( $c, 'wpTearDownAfterClass' ) ) {
+                       self::commit_transaction();
+                       return;
+               }
+
+               call_user_func( array( $c, 'wpTearDownAfterClass' ) );
+
+               self::commit_transaction();
+       }
+
+       function setUp() {
+               set_time_limit( 0 );
+
+               if ( ! self::$ignore_files ) {
+                       self::$ignore_files = $this->scan_user_uploads();
+               }
+
+               if ( ! self::$hooks_saved ) {
+                       $this->_backup_hooks();
+               }
+
+               global $wp_rewrite;
+
+               $this->clean_up_global_scope();
+
+               /*
+                * When running core tests, ensure that post types and taxonomies
+                * are reset for each test. We skip this step for non-core tests,
+                * given the large number of plugins that register post types and
+                * taxonomies at 'init'.
+                */
+               if ( defined( 'WP_RUN_CORE_TESTS' ) && WP_RUN_CORE_TESTS ) {
+                       $this->reset_post_types();
+                       $this->reset_taxonomies();
+                       $this->reset_post_statuses();
+                       $this->reset__SERVER();
+
+                       if ( $wp_rewrite->permalink_structure ) {
+                               $this->set_permalink_structure( '' );
+                       }
+               }
+
+               $this->start_transaction();
+               $this->expectDeprecated();
+               add_filter( 'wp_die_handler', array( $this, 'get_wp_die_handler' ) );
+       }
+
+       /**
+        * Detect post-test failure conditions.
+        *
+        * We use this method to detect expectedDeprecated and expectedIncorrectUsage annotations.
+        *
+        * @since 4.2.0
+        */
+       protected function assertPostConditions() {
+               $this->expectedDeprecated();
+       }
+
+       /**
+        * After a test method runs, reset any state in WordPress the test method might have changed.
+        */
+       function tearDown() {
+               global $wpdb, $wp_query, $wp;
+               $wpdb->query( 'ROLLBACK' );
+               if ( is_multisite() ) {
+                       while ( ms_is_switched() ) {
+                               restore_current_blog();
+                       }
+               }
+               $wp_query = new WP_Query();
+               $wp       = new WP();
+
+               // Reset globals related to the post loop and `setup_postdata()`.
+               $post_globals = array( 'post', 'id', 'authordata', 'currentday', 'currentmonth', 'page', 'pages', 'multipage', 'more', 'numpages' );
+               foreach ( $post_globals as $global ) {
+                       $GLOBALS[ $global ] = null;
+               }
+
+               $this->unregister_all_meta_keys();
+               remove_theme_support( 'html5' );
+               remove_filter( 'query', array( $this, '_create_temporary_tables' ) );
+               remove_filter( 'query', array( $this, '_drop_temporary_tables' ) );
+               remove_filter( 'wp_die_handler', array( $this, 'get_wp_die_handler' ) );
+               $this->_restore_hooks();
+               wp_set_current_user( 0 );
+       }
+
+       function clean_up_global_scope() {
+               $_GET  = array();
+               $_POST = array();
+               self::flush_cache();
+       }
+
+       /**
+        * Allow tests to be skipped on some automated runs
+        *
+        * For test runs on Travis for something other than trunk/master
+        * we want to skip tests that only need to run for master.
+        */
+       public function skipOnAutomatedBranches() {
+               // gentenv can be disabled
+               if ( ! function_exists( 'getenv' ) ) {
+                       return false;
+               }
+
+               // https://docs.travis-ci.com/user/environment-variables/#Default-Environment-Variables
+               $travis_branch       = getenv( 'TRAVIS_BRANCH' );
+               $travis_pull_request = getenv( 'TRAVIS_PULL_REQUEST' );
+
+               if ( false !== $travis_pull_request && 'master' !== $travis_branch ) {
+                       $this->markTestSkipped( 'For automated test runs, this test is only run on trunk/master' );
+               }
+       }
+
+       /**
+        * Allow tests to be skipped when Multisite is not in use.
+        *
+        * Use in conjunction with the ms-required group.
+        */
+       public function skipWithoutMultisite() {
+               if ( ! is_multisite() ) {
+                       $this->markTestSkipped( 'Test only runs on Multisite' );
+               }
+       }
+
+       /**
+        * Allow tests to be skipped when Multisite is in use.
+        *
+        * Use in conjunction with the ms-excluded group.
+        */
+       public function skipWithMultisite() {
+               if ( is_multisite() ) {
+                       $this->markTestSkipped( 'Test does not run on Multisite' );
+               }
+       }
+
+       /**
+        * Unregister existing post types and register defaults.
+        *
+        * Run before each test in order to clean up the global scope, in case
+        * a test forgets to unregister a post type on its own, or fails before
+        * it has a chance to do so.
+        */
+       protected function reset_post_types() {
+               foreach ( get_post_types( array(), 'objects' ) as $pt ) {
+                       if ( empty( $pt->tests_no_auto_unregister ) ) {
+                               _unregister_post_type( $pt->name );
+                       }
+               }
+               create_initial_post_types();
+       }
+
+       /**
+        * Unregister existing taxonomies and register defaults.
+        *
+        * Run before each test in order to clean up the global scope, in case
+        * a test forgets to unregister a taxonomy on its own, or fails before
+        * it has a chance to do so.
+        */
+       protected function reset_taxonomies() {
+               foreach ( get_taxonomies() as $tax ) {
+                       _unregister_taxonomy( $tax );
+               }
+               create_initial_taxonomies();
+       }
+
+       /**
+        * Unregister non-built-in post statuses.
+        */
+       protected function reset_post_statuses() {
+               foreach ( get_post_stati( array( '_builtin' => false ) ) as $post_status ) {
+                       _unregister_post_status( $post_status );
+               }
+       }
+
+       /**
+        * Reset `$_SERVER` variables
+        */
+       protected function reset__SERVER() {
+               tests_reset__SERVER();
+       }
+
+       /**
+        * Saves the action and filter-related globals so they can be restored later.
+        *
+        * Stores $wp_actions, $wp_current_filter, and $wp_filter on a class variable
+        * so they can be restored on tearDown() using _restore_hooks().
+        *
+        * @global array $wp_actions
+        * @global array $wp_current_filter
+        * @global array $wp_filter
+        * @return void
+        */
+       protected function _backup_hooks() {
+               $globals = array( 'wp_actions', 'wp_current_filter' );
+               foreach ( $globals as $key ) {
+                       self::$hooks_saved[ $key ] = $GLOBALS[ $key ];
+               }
+               self::$hooks_saved['wp_filter'] = array();
+               foreach ( $GLOBALS['wp_filter'] as $hook_name => $hook_object ) {
+                       self::$hooks_saved['wp_filter'][ $hook_name ] = clone $hook_object;
+               }
+       }
+
+       /**
+        * Restores the hook-related globals to their state at setUp()
+        * so that future tests aren't affected by hooks set during this last test.
+        *
+        * @global array $wp_actions
+        * @global array $wp_current_filter
+        * @global array $wp_filter
+        * @return void
+        */
+       protected function _restore_hooks() {
+               $globals = array( 'wp_actions', 'wp_current_filter' );
+               foreach ( $globals as $key ) {
+                       if ( isset( self::$hooks_saved[ $key ] ) ) {
+                               $GLOBALS[ $key ] = self::$hooks_saved[ $key ];
+                       }
+               }
+               if ( isset( self::$hooks_saved['wp_filter'] ) ) {
+                       $GLOBALS['wp_filter'] = array();
+                       foreach ( self::$hooks_saved['wp_filter'] as $hook_name => $hook_object ) {
+                               $GLOBALS['wp_filter'][ $hook_name ] = clone $hook_object;
+                       }
+               }
+       }
+
+       static function flush_cache() {
+               global $wp_object_cache;
+               $wp_object_cache->group_ops      = array();
+               $wp_object_cache->stats          = array();
+               $wp_object_cache->memcache_debug = array();
+               $wp_object_cache->cache          = array();
+               if ( method_exists( $wp_object_cache, '__remoteset' ) ) {
+                       $wp_object_cache->__remoteset();
+               }
+               wp_cache_flush();
+               wp_cache_add_global_groups( array( 'users', 'userlogins', 'usermeta', 'user_meta', 'useremail', 'userslugs', 'site-transient', 'site-options', 'blog-lookup', 'blog-details', 'rss', 'global-posts', 'blog-id-cache', 'networks', 'sites', 'site-details', 'blog_meta' ) );
+               wp_cache_add_non_persistent_groups( array( 'comment', 'counts', 'plugins' ) );
+       }
+
+       /**
+        * Clean up any registered meta keys.
+        *
+        * @since 5.1.0
+        *
+        * @global array $wp_meta_keys
+        */
+       function unregister_all_meta_keys() {
+               global $wp_meta_keys;
+               if ( ! is_array( $wp_meta_keys ) ) {
+                       return;
+               }
+               foreach ( $wp_meta_keys as $object_type => $type_keys ) {
+                       foreach ( $type_keys as $object_subtype => $subtype_keys ) {
+                               foreach ( $subtype_keys as $key => $value ) {
+                                       unregister_meta_key( $object_type, $key, $object_subtype );
+                               }
+                       }
+               }
+       }
+
+       function start_transaction() {
+               global $wpdb;
+               $wpdb->query( 'SET autocommit = 0;' );
+               $wpdb->query( 'START TRANSACTION;' );
+               add_filter( 'query', array( $this, '_create_temporary_tables' ) );
+               add_filter( 'query', array( $this, '_drop_temporary_tables' ) );
+       }
+
+       /**
+        * Commit the queries in a transaction.
+        *
+        * @since 4.1.0
+        */
+       public static function commit_transaction() {
+               global $wpdb;
+               $wpdb->query( 'COMMIT;' );
+       }
+
+       function _create_temporary_tables( $query ) {
+               if ( 'CREATE TABLE' === substr( trim( $query ), 0, 12 ) ) {
+                       return substr_replace( trim( $query ), 'CREATE TEMPORARY TABLE', 0, 12 );
+               }
+               return $query;
+       }
+
+       function _drop_temporary_tables( $query ) {
+               if ( 'DROP TABLE' === substr( trim( $query ), 0, 10 ) ) {
+                       return substr_replace( trim( $query ), 'DROP TEMPORARY TABLE', 0, 10 );
+               }
+               return $query;
+       }
+
+       function get_wp_die_handler( $handler ) {
+               return array( $this, 'wp_die_handler' );
+       }
+
+       function wp_die_handler( $message ) {
+               if ( ! is_scalar( $message ) ) {
+                       $message = '0';
+               }
+
+               throw new WPDieException( $message );
+       }
+
+       function expectDeprecated() {
+               $annotations = $this->getAnnotations();
+               foreach ( array( 'class', 'method' ) as $depth ) {
+                       if ( ! empty( $annotations[ $depth ]['expectedDeprecated'] ) ) {
+                               $this->expected_deprecated = array_merge( $this->expected_deprecated, $annotations[ $depth ]['expectedDeprecated'] );
+                       }
+                       if ( ! empty( $annotations[ $depth ]['expectedIncorrectUsage'] ) ) {
+                               $this->expected_doing_it_wrong = array_merge( $this->expected_doing_it_wrong, $annotations[ $depth ]['expectedIncorrectUsage'] );
+                       }
+               }
+               add_action( 'deprecated_function_run', array( $this, 'deprecated_function_run' ) );
+               add_action( 'deprecated_argument_run', array( $this, 'deprecated_function_run' ) );
+               add_action( 'deprecated_hook_run', array( $this, 'deprecated_function_run' ) );
+               add_action( 'doing_it_wrong_run', array( $this, 'doing_it_wrong_run' ) );
+               add_action( 'deprecated_function_trigger_error', '__return_false' );
+               add_action( 'deprecated_argument_trigger_error', '__return_false' );
+               add_action( 'deprecated_hook_trigger_error', '__return_false' );
+               add_action( 'doing_it_wrong_trigger_error', '__return_false' );
+       }
+
+       function expectedDeprecated() {
+               $errors = array();
+
+               $not_caught_deprecated = array_diff( $this->expected_deprecated, $this->caught_deprecated );
+               foreach ( $not_caught_deprecated as $not_caught ) {
+                       $errors[] = "Failed to assert that $not_caught triggered a deprecated notice";
+               }
+
+               $unexpected_deprecated = array_diff( $this->caught_deprecated, $this->expected_deprecated );
+               foreach ( $unexpected_deprecated as $unexpected ) {
+                       $errors[] = "Unexpected deprecated notice for $unexpected";
+               }
+
+               $not_caught_doing_it_wrong = array_diff( $this->expected_doing_it_wrong, $this->caught_doing_it_wrong );
+               foreach ( $not_caught_doing_it_wrong as $not_caught ) {
+                       $errors[] = "Failed to assert that $not_caught triggered an incorrect usage notice";
+               }
+
+               $unexpected_doing_it_wrong = array_diff( $this->caught_doing_it_wrong, $this->expected_doing_it_wrong );
+               foreach ( $unexpected_doing_it_wrong as $unexpected ) {
+                       $errors[] = "Unexpected incorrect usage notice for $unexpected";
+               }
+
+               // Perform an assertion, but only if there are expected or unexpected deprecated calls or wrongdoings
+               if ( ! empty( $this->expected_deprecated ) ||
+                       ! empty( $this->expected_doing_it_wrong ) ||
+                       ! empty( $this->caught_deprecated ) ||
+                       ! empty( $this->caught_doing_it_wrong ) ) {
+                       $this->assertEmpty( $errors, implode( "\n", $errors ) );
+               }
+       }
+
+       /**
+        * Declare an expected `_deprecated_function()` or `_deprecated_argument()` call from within a test.
+        *
+        * @since 4.2.0
+        *
+        * @param string $deprecated Name of the function, method, class, or argument that is deprecated. Must match
+        *                           first parameter of the `_deprecated_function()` or `_deprecated_argument()` call.
+        */
+       public function setExpectedDeprecated( $deprecated ) {
+               array_push( $this->expected_deprecated, $deprecated );
+       }
+
+       /**
+        * Declare an expected `_doing_it_wrong()` call from within a test.
+        *
+        * @since 4.2.0
+        *
+        * @param string $deprecated Name of the function, method, or class that appears in the first argument of the
+        *                           source `_doing_it_wrong()` call.
+        */
+       public function setExpectedIncorrectUsage( $doing_it_wrong ) {
+               array_push( $this->expected_doing_it_wrong, $doing_it_wrong );
+       }
+
+       /**
+        * PHPUnit 6+ compatibility shim.
+        *
+        * @param mixed      $exception
+        * @param string     $message
+        * @param int|string $code
+        */
+       public function setExpectedException( $exception, $message = '', $code = null ) {
+               if ( method_exists( 'PHPUnit_Framework_TestCase', 'setExpectedException' ) ) {
+                       parent::setExpectedException( $exception, $message, $code );
+               } else {
+                       $this->expectException( $exception );
+                       if ( '' !== $message ) {
+                               $this->expectExceptionMessage( $message );
+                       }
+                       if ( null !== $code ) {
+                               $this->expectExceptionCode( $code );
+                       }
+               }
+       }
+
+       function deprecated_function_run( $function ) {
+               if ( ! in_array( $function, $this->caught_deprecated ) ) {
+                       $this->caught_deprecated[] = $function;
+               }
+       }
+
+       function doing_it_wrong_run( $function ) {
+               if ( ! in_array( $function, $this->caught_doing_it_wrong ) ) {
+                       $this->caught_doing_it_wrong[] = $function;
+               }
+       }
+
+       function assertWPError( $actual, $message = '' ) {
+               $this->assertInstanceOf( 'WP_Error', $actual, $message );
+       }
+
+       function assertNotWPError( $actual, $message = '' ) {
+               if ( is_wp_error( $actual ) && '' === $message ) {
+                       $message = $actual->get_error_message();
+               }
+               $this->assertNotInstanceOf( 'WP_Error', $actual, $message );
+       }
+
+       function assertIXRError( $actual, $message = '' ) {
+               $this->assertInstanceOf( 'IXR_Error', $actual, $message );
+       }
+
+       function assertNotIXRError( $actual, $message = '' ) {
+               if ( $actual instanceof IXR_Error && '' === $message ) {
+                       $message = $actual->message;
+               }
+               $this->assertNotInstanceOf( 'IXR_Error', $actual, $message );
+       }
+
+       function assertEqualFields( $object, $fields ) {
+               foreach ( $fields as $field_name => $field_value ) {
+                       if ( $object->$field_name != $field_value ) {
+                               $this->fail();
+                       }
+               }
+       }
+
+       function assertDiscardWhitespace( $expected, $actual ) {
+               $this->assertEquals( preg_replace( '/\s*/', '', $expected ), preg_replace( '/\s*/', '', $actual ) );
+       }
+
+       /**
+        * Asserts that the contents of two un-keyed, single arrays are equal, without accounting for the order of elements.
+        *
+        * @since 3.5.0
+        *
+        * @param array $expected Expected array.
+        * @param array $actual   Array to check.
+        */
+       function assertEqualSets( $expected, $actual ) {
+               sort( $expected );
+               sort( $actual );
+               $this->assertEquals( $expected, $actual );
+       }
+
+       /**
+        * Asserts that the contents of two keyed, single arrays are equal, without accounting for the order of elements.
+        *
+        * @since 4.1.0
+        *
+        * @param array $expected Expected array.
+        * @param array $actual   Array to check.
+        */
+       function assertEqualSetsWithIndex( $expected, $actual ) {
+               ksort( $expected );
+               ksort( $actual );
+               $this->assertEquals( $expected, $actual );
+       }
+
+       /**
+        * Asserts that the given variable is a multidimensional array, and that all arrays are non-empty.
+        *
+        * @since 4.8.0
+        *
+        * @param array $array Array to check.
+        */
+       function assertNonEmptyMultidimensionalArray( $array ) {
+               $this->assertTrue( is_array( $array ) );
+               $this->assertNotEmpty( $array );
+
+               foreach ( $array as $sub_array ) {
+                       $this->assertTrue( is_array( $sub_array ) );
+                       $this->assertNotEmpty( $sub_array );
+               }
+       }
+
+       /**
+        * Sets the global state to as if a given URL has been requested.
+        *
+        * This sets:
+        * - The super globals.
+        * - The globals.
+        * - The query variables.
+        * - The main query.
+        *
+        * @since 3.5.0
+        *
+        * @param string $url The URL for the request.
+        */
+       function go_to( $url ) {
+               // note: the WP and WP_Query classes like to silently fetch parameters
+               // from all over the place (globals, GET, etc), which makes it tricky
+               // to run them more than once without very carefully clearing everything
+               $_GET = $_POST = array();
+               foreach ( array( 'query_string', 'id', 'postdata', 'authordata', 'day', 'currentmonth', 'page', 'pages', 'multipage', 'more', 'numpages', 'pagenow' ) as $v ) {
+                       if ( isset( $GLOBALS[ $v ] ) ) {
+                               unset( $GLOBALS[ $v ] );
+                       }
+               }
+               $parts = parse_url( $url );
+               if ( isset( $parts['scheme'] ) ) {
+                       $req = isset( $parts['path'] ) ? $parts['path'] : '';
+                       if ( isset( $parts['query'] ) ) {
+                               $req .= '?' . $parts['query'];
+                               // parse the url query vars into $_GET
+                               parse_str( $parts['query'], $_GET );
+                       }
+               } else {
+                       $req = $url;
+               }
+               if ( ! isset( $parts['query'] ) ) {
+                       $parts['query'] = '';
+               }
+
+               $_SERVER['REQUEST_URI'] = $req;
+               unset( $_SERVER['PATH_INFO'] );
+
+               self::flush_cache();
+               unset( $GLOBALS['wp_query'], $GLOBALS['wp_the_query'] );
+               $GLOBALS['wp_the_query'] = new WP_Query();
+               $GLOBALS['wp_query']     = $GLOBALS['wp_the_query'];
+
+               $public_query_vars  = $GLOBALS['wp']->public_query_vars;
+               $private_query_vars = $GLOBALS['wp']->private_query_vars;
+
+               $GLOBALS['wp']                     = new WP();
+               $GLOBALS['wp']->public_query_vars  = $public_query_vars;
+               $GLOBALS['wp']->private_query_vars = $private_query_vars;
+
+               _cleanup_query_vars();
+
+               $GLOBALS['wp']->main( $parts['query'] );
+       }
+
+       /**
+        * Allows tests to be skipped on single or multisite installs by using @group annotations.
+        *
+        * This is a custom extension of the PHPUnit requirements handling.
+        *
+        * Contains legacy code for skipping tests that are associated with an open Trac ticket. Core tests no longer
+        * support this behaviour.
+        *
+        * @since 3.5.0
+        */
+       protected function checkRequirements() {
+               parent::checkRequirements();
+
+               $annotations = $this->getAnnotations();
+
+               $groups = array();
+               if ( ! empty( $annotations['class']['group'] ) ) {
+                       $groups = array_merge( $groups, $annotations['class']['group'] );
+               }
+               if ( ! empty( $annotations['method']['group'] ) ) {
+                       $groups = array_merge( $groups, $annotations['method']['group'] );
+               }
+
+               if ( ! empty( $groups ) ) {
+                       if ( in_array( 'ms-required', $groups, true ) ) {
+                               $this->skipWithoutMultisite();
+                       }
+
+                       if ( in_array( 'ms-excluded', $groups, true ) ) {
+                               $this->skipWithMultisite();
+                       }
+               }
+
+               // Core tests no longer check against open Trac tickets, but others using WP_UnitTestCase may do so.
+               if ( defined( 'WP_RUN_CORE_TESTS' ) && WP_RUN_CORE_TESTS ) {
+                       return;
+               }
+
+               if ( WP_TESTS_FORCE_KNOWN_BUGS ) {
+                       return;
+               }
+               $tickets = PHPUnit_Util_Test::getTickets( get_class( $this ), $this->getName( false ) );
+               foreach ( $tickets as $ticket ) {
+                       if ( is_numeric( $ticket ) ) {
+                               $this->knownWPBug( $ticket );
+                       } elseif ( 'Plugin' == substr( $ticket, 0, 6 ) ) {
+                               $ticket = substr( $ticket, 6 );
+                               if ( $ticket && is_numeric( $ticket ) ) {
+                                       $this->knownPluginBug( $ticket );
+                               }
+                       }
+               }
+       }
+
+       /**
+        * Skips the current test if there is an open Trac ticket associated with it.
+        *
+        * @since 3.5.0
+        *
+        * @param int $ticket_id Ticket number.
+        */
+       function knownWPBug( $ticket_id ) {
+               if ( WP_TESTS_FORCE_KNOWN_BUGS || in_array( $ticket_id, self::$forced_tickets ) ) {
+                       return;
+               }
+               if ( ! TracTickets::isTracTicketClosed( 'https://core.trac.wordpress.org', $ticket_id ) ) {
+                       $this->markTestSkipped( sprintf( 'WordPress Ticket #%d is not fixed', $ticket_id ) );
+               }
+       }
+
+       /**
+        * Skips the current test if there is an open Unit Test Trac ticket associated with it.
+        *
+        * @since 3.5.0
+        *
+        * @deprecated No longer used since the Unit Test Trac was merged into the Core Trac.
+        *
+        * @param int $ticket_id Ticket number.
+        */
+       function knownUTBug( $ticket_id ) {
+               return;
+       }
+
+       /**
+        * Skips the current test if there is an open Plugin Trac ticket associated with it.
+        *
+        * @since 3.5.0
+        *
+        * @param int $ticket_id Ticket number.
+        */
+       function knownPluginBug( $ticket_id ) {
+               if ( WP_TESTS_FORCE_KNOWN_BUGS || in_array( 'Plugin' . $ticket_id, self::$forced_tickets ) ) {
+                       return;
+               }
+               if ( ! TracTickets::isTracTicketClosed( 'https://plugins.trac.wordpress.org', $ticket_id ) ) {
+                       $this->markTestSkipped( sprintf( 'WordPress Plugin Ticket #%d is not fixed', $ticket_id ) );
+               }
+       }
+
+       /**
+        * Adds a Trac ticket number to the `$forced_tickets` property.
+        *
+        * @since 3.5.0
+        *
+        * @param int $ticket Ticket number.
+        */
+       public static function forceTicket( $ticket ) {
+               self::$forced_tickets[] = $ticket;
+       }
+
+       /**
+        * Custom preparations for the PHPUnit process isolation template.
+        *
+        * When restoring global state between tests, PHPUnit defines all the constants that were already defined, and then
+        * includes included files. This does not work with WordPress, as the included files define the constants.
+        *
+        * This method defines the constants after including files.
+        *
+        * @param Text_Template $template
+        */
+       function prepareTemplate( Text_Template $template ) {
+               $template->setVar( array( 'constants' => '' ) );
+               $template->setVar( array( 'wp_constants' => PHPUnit_Util_GlobalState::getConstantsAsString() ) );
+               parent::prepareTemplate( $template );
+       }
+
+       /**
+        * Creates a unique temporary file name.
+        *
+        * The directory in which the file is created depends on the environment configuration.
+        *
+        * @since 3.5.0
+        *
+        * @return string|bool Path on success, else false.
+        */
+       function temp_filename() {
+               $tmp_dir = '';
+               $dirs    = array( 'TMP', 'TMPDIR', 'TEMP' );
+               foreach ( $dirs as $dir ) {
+                       if ( isset( $_ENV[ $dir ] ) && ! empty( $_ENV[ $dir ] ) ) {
+                               $tmp_dir = $dir;
+                               break;
+                       }
+               }
+               if ( empty( $tmp_dir ) ) {
+                       $tmp_dir = '/tmp';
+               }
+               $tmp_dir = realpath( $tmp_dir );
+               return tempnam( $tmp_dir, 'wpunit' );
+       }
+
+       /**
+        * Checks each of the WP_Query is_* functions/properties against expected boolean value.
+        *
+        * Any properties that are listed by name as parameters will be expected to be true; all others are
+        * expected to be false. For example, assertQueryTrue('is_single', 'is_feed') means is_single()
+        * and is_feed() must be true and everything else must be false to pass.
+        *
+        * @since 2.5.0
+        * @since 3.8.0 Moved from `Tests_Query_Conditionals` to `WP_UnitTestCase`.
+        *
+        * @param string $prop,... Any number of WP_Query properties that are expected to be true for the current request.
+        */
+       function assertQueryTrue() {
+               global $wp_query;
+               $all  = array(
+                       'is_404',
+                       'is_admin',
+                       'is_archive',
+                       'is_attachment',
+                       'is_author',
+                       'is_category',
+                       'is_comment_feed',
+                       'is_date',
+                       'is_day',
+                       'is_embed',
+                       'is_feed',
+                       'is_front_page',
+                       'is_home',
+                       'is_month',
+                       'is_page',
+                       'is_paged',
+                       'is_post_type_archive',
+                       'is_posts_page',
+                       'is_preview',
+                       'is_robots',
+                       'is_search',
+                       'is_single',
+                       'is_singular',
+                       'is_tag',
+                       'is_tax',
+                       'is_time',
+                       'is_trackback',
+                       'is_year',
+               );
+               $true = func_get_args();
+
+               foreach ( $true as $true_thing ) {
+                       $this->assertContains( $true_thing, $all, "Unknown conditional: {$true_thing}." );
+               }
+
+               $passed  = true;
+               $message = '';
+
+               foreach ( $all as $query_thing ) {
+                       $result = is_callable( $query_thing ) ? call_user_func( $query_thing ) : $wp_query->$query_thing;
+
+                       if ( in_array( $query_thing, $true ) ) {
+                               if ( ! $result ) {
+                                       $message .= $query_thing . ' is false but is expected to be true. ' . PHP_EOL;
+                                       $passed   = false;
+                               }
+                       } elseif ( $result ) {
+                               $message .= $query_thing . ' is true but is expected to be false. ' . PHP_EOL;
+                               $passed   = false;
+                       }
+               }
+
+               if ( ! $passed ) {
+                       $this->fail( $message );
+               }
+       }
+
+       /**
+        * Selectively deletes a file.
+        *
+        * Does not delete a file if its path is set in the `$ignore_files` property.
+        *
+        * @param string $file File path.
+        */
+       function unlink( $file ) {
+               $exists = is_file( $file );
+               if ( $exists && ! in_array( $file, self::$ignore_files ) ) {
+                       //error_log( $file );
+                       unlink( $file );
+               } elseif ( ! $exists ) {
+                       $this->fail( "Trying to delete a file that doesn't exist: $file" );
+               }
+       }
+
+       /**
+        * Selectively deletes files from a directory.
+        *
+        * Does not delete files if their paths are set in the `$ignore_files` property.
+        *
+        * @param string $path Directory path.
+        */
+       function rmdir( $path ) {
+               $files = $this->files_in_dir( $path );
+               foreach ( $files as $file ) {
+                       if ( ! in_array( $file, self::$ignore_files ) ) {
+                               $this->unlink( $file );
+                       }
+               }
+       }
+
+       /**
+        * Deletes files added to the `uploads` directory during tests.
+        *
+        * This method works in tandem with the `setUp()` and `rmdir()` methods:
+        * - `setUp()` scans the `uploads` directory before every test, and stores its contents inside of the
+        *   `$ignore_files` property.
+        * - `rmdir()` and its helper methods only delete files that are not listed in the `$ignore_files` property. If
+        *   called during `tearDown()` in tests, this will only delete files added during the previously run test.
+        */
+       function remove_added_uploads() {
+               $uploads = wp_upload_dir();
+               $this->rmdir( $uploads['basedir'] );
+       }
+
+       /**
+        * Returns a list of all files contained inside a directory.
+        *
+        * @since 4.0.0
+        *
+        * @param string $dir Path to the directory to scan.
+        *
+        * @return array List of file paths.
+        */
+       function files_in_dir( $dir ) {
+               $files = array();
+
+               $iterator = new RecursiveDirectoryIterator( $dir );
+               $objects  = new RecursiveIteratorIterator( $iterator );
+               foreach ( $objects as $name => $object ) {
+                       if ( is_file( $name ) ) {
+                               $files[] = $name;
+                       }
+               }
+
+               return $files;
+       }
+
+       /**
+        * Returns a list of all files contained inside the `uploads` directory.
+        *
+        * @since 4.0.0
+        *
+        * @return array List of file paths.
+        */
+       function scan_user_uploads() {
+               static $files = array();
+               if ( ! empty( $files ) ) {
+                       return $files;
+               }
+
+               $uploads = wp_upload_dir();
+               $files   = $this->files_in_dir( $uploads['basedir'] );
+               return $files;
+       }
+
+       /**
+        * Deletes all directories contained inside a directory.
+        *
+        * @since 4.1.0
+        *
+        * @param string $path Path to the directory to scan.
+        */
+       function delete_folders( $path ) {
+               $this->matched_dirs = array();
+               if ( ! is_dir( $path ) ) {
+                       return;
+               }
+
+               $this->scandir( $path );
+               foreach ( array_reverse( $this->matched_dirs ) as $dir ) {
+                       rmdir( $dir );
+               }
+               rmdir( $path );
+       }
+
+       /**
+        * Retrieves all directories contained inside a directory and stores them in the `$matched_dirs` property. Hidden
+        * directories are ignored.
+        *
+        * This is a helper for the `delete_folders()` method.
+        *
+        * @since 4.1.0
+        *
+        * @param string $dir Path to the directory to scan.
+        */
+       function scandir( $dir ) {
+               foreach ( scandir( $dir ) as $path ) {
+                       if ( 0 !== strpos( $path, '.' ) && is_dir( $dir . '/' . $path ) ) {
+                               $this->matched_dirs[] = $dir . '/' . $path;
+                               $this->scandir( $dir . '/' . $path );
+                       }
+               }
+       }
+
+       /**
+        * Converts a microtime string into a float.
+        *
+        * @since 4.1.0
+        *
+        * @param string $microtime Time string generated by `microtime()`.
+        *
+        * @return float `microtime()` output as a float.
+        */
+       protected function _microtime_to_float( $microtime ) {
+               $time_array = explode( ' ', $microtime );
+               return array_sum( $time_array );
+       }
+
+       /**
+        * Deletes a user from the database in a Multisite-agnostic way.
+        *
+        * @since 4.3.0
+        *
+        * @param int $user_id User ID.
+        *
+        * @return bool True if the user was deleted.
+        */
+       public static function delete_user( $user_id ) {
+               if ( is_multisite() ) {
+                       return wpmu_delete_user( $user_id );
+               } else {
+                       return wp_delete_user( $user_id );
+               }
+       }
+
+       /**
+        * Resets permalinks and flushes rewrites.
+        *
+        * @since 4.4.0
+        *
+        * @global WP_Rewrite $wp_rewrite
+        *
+        * @param string $structure Optional. Permalink structure to set. Default empty.
+        */
+       public function set_permalink_structure( $structure = '' ) {
+               global $wp_rewrite;
+
+               $wp_rewrite->init();
+               $wp_rewrite->set_permalink_structure( $structure );
+               $wp_rewrite->flush_rules();
+       }
+
+       /**
+        * Creates an attachment post from an uploaded file.
+        *
+        * @since 4.4.0
+        *
+        * @param array $upload         Array of information about the uploaded file, provided by wp_upload_bits().
+        * @param int   $parent_post_id Optional. Parent post ID.
+        *
+        * @return int|WP_Error The attachment ID on success. The value 0 or WP_Error on failure.
+        */
+       function _make_attachment( $upload, $parent_post_id = 0 ) {
+               $type = '';
+               if ( ! empty( $upload['type'] ) ) {
+                       $type = $upload['type'];
+               } else {
+                       $mime = wp_check_filetype( $upload['file'] );
+                       if ( $mime ) {
+                               $type = $mime['type'];
+                       }
+               }
+
+               $attachment = array(
+                       'post_title'     => basename( $upload['file'] ),
+                       'post_content'   => '',
+                       'post_type'      => 'attachment',
+                       'post_parent'    => $parent_post_id,
+                       'post_mime_type' => $type,
+                       'guid'           => $upload['url'],
+               );
+
+               $id = wp_insert_attachment( $attachment, $upload['file'], $parent_post_id );
+               wp_update_attachment_metadata( $id, wp_generate_attachment_metadata( $id, $upload['file'] ) );
+               return $id;
+       }
+
+       /**
+        * Updates the modified and modified GMT date of a post in the database.
+        *
+        * @since 4.8.0
+        *
+        * @global wpdb $wpdb WordPress database abstraction object.
+        *
+        * @param int    $post_id Post ID.
+        * @param string $date    Post date, in the format YYYY-MM-DD HH:MM:SS.
+        *
+        * @return int|false 1 on success, or false on error.
+        */
+       protected function update_post_modified( $post_id, $date ) {
+               global $wpdb;
+               return $wpdb->update(
+                       $wpdb->posts,
+                       array(
+                               'post_modified'     => $date,
+                               'post_modified_gmt' => $date,
+                       ),
+                       array(
+                               'ID' => $post_id,
+                       ),
+                       array(
+                               '%s',
+                               '%s',
+                       ),
+                       array(
+                               '%d',
+                       )
+               );
+       }
+}
</ins></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        2019-01-27 14:45:42 UTC (rev 44700)
+++ trunk/tests/phpunit/includes/bootstrap.php  2019-01-28 14:10:24 UTC (rev 44701)
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -7,7 +7,7 @@
</span><span class="cx" style="display: block; padding: 0 10px">  * Compatibility with PHPUnit 6+
</span><span class="cx" style="display: block; padding: 0 10px">  */
</span><span class="cx" style="display: block; padding: 0 10px"> if ( class_exists( 'PHPUnit\Runner\Version' ) ) {
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-        require_once dirname( __FILE__ ) . '/phpunit6-compat.php';
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+ require_once dirname( __FILE__ ) . '/phpunit6/compat.php';
</ins><span class="cx" style="display: block; padding: 0 10px"> }
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px"> if ( defined( 'WP_TESTS_CONFIG_FILE_PATH' ) ) {
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -118,7 +118,12 @@
</span><span class="cx" style="display: block; padding: 0 10px"> // Delete any default posts & related data
</span><span class="cx" style="display: block; padding: 0 10px"> _delete_all_posts();
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-require dirname( __FILE__ ) . '/testcase.php';
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+if ( version_compare( tests_get_phpunit_version(), '7.0', '>=' ) ) {
+       require dirname( __FILE__ ) . '/phpunit7/testcase.php';
+} else {
+       require dirname( __FILE__ ) . '/testcase.php';
+}
+
</ins><span class="cx" style="display: block; padding: 0 10px"> require dirname( __FILE__ ) . '/testcase-rest-api.php';
</span><span class="cx" style="display: block; padding: 0 10px"> require dirname( __FILE__ ) . '/testcase-rest-controller.php';
</span><span class="cx" style="display: block; padding: 0 10px"> require dirname( __FILE__ ) . '/testcase-rest-post-type-controller.php';
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -144,10 +149,11 @@
</span><span class="cx" style="display: block; padding: 0 10px">  * If WP_TESTS_FORCE_KNOWN_BUGS is already set in wp-tests-config.php, then
</span><span class="cx" style="display: block; padding: 0 10px">  * how you call phpunit has no effect.
</span><span class="cx" style="display: block; padding: 0 10px">  */
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-class WP_PHPUnit_Util_Getopt extends PHPUnit_Util_Getopt {
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+class WP_PHPUnit_Util_Getopt {
</ins><span class="cx" style="display: block; padding: 0 10px">         protected $longOptions = array(
</span><span class="cx" style="display: block; padding: 0 10px">                'exclude-group=',
</span><span class="cx" style="display: block; padding: 0 10px">                'group=',
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+                'verbose=',
</ins><span class="cx" style="display: block; padding: 0 10px">         );
</span><span class="cx" style="display: block; padding: 0 10px">        function __construct( $argv ) {
</span><span class="cx" style="display: block; padding: 0 10px">                array_shift( $argv );
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -157,7 +163,7 @@
</span><span class="cx" style="display: block; padding: 0 10px">                        next( $argv );
</span><span class="cx" style="display: block; padding: 0 10px">                        try {
</span><span class="cx" style="display: block; padding: 0 10px">                                if ( strlen( $arg ) > 1 && $arg[0] === '-' && $arg[1] === '-' ) {
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-                                        PHPUnit_Util_Getopt::parseLongOption( substr( $arg, 2 ), $this->longOptions, $options, $argv );
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+                                 self::parseLongOption( substr( $arg, 2 ), $this->longOptions, $options, $argv );
</ins><span class="cx" style="display: block; padding: 0 10px">                                 }
</span><span class="cx" style="display: block; padding: 0 10px">                        } catch ( PHPUnit_Framework_Exception $e ) {
</span><span class="cx" style="display: block; padding: 0 10px">                                // Enforcing recognized arguments or correctly formed arguments is
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -208,5 +214,68 @@
</span><span class="cx" style="display: block; padding: 0 10px">                        echo PHP_EOL;
</span><span class="cx" style="display: block; padding: 0 10px">                }
</span><span class="cx" style="display: block; padding: 0 10px">        }
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+
+       /**
+        * Copied from https://raw.githubusercontent.com/sebastianbergmann/phpunit/6.5.7/src/Util/Getopt.php
+        *
+        * @param $arg
+        * @param $long_options
+        * @param $opts
+        * @param $args
+        */
+       protected static function parseLongOption( $arg, $long_options, &$opts, &$args ) {
+               $count   = count( $long_options );
+               $list    = explode( '=', $arg );
+               $opt     = $list[0];
+               $opt_arg = null;
+
+               if ( count( $list ) > 1 ) {
+                       $opt_arg = $list[1];
+               }
+
+               $opt_len = strlen( $opt );
+
+               for ( $i = 0; $i < $count; $i++ ) {
+                       $long_opt  = $long_options[ $i ];
+                       $opt_start = substr( $long_opt, 0, $opt_len );
+
+                       if ( $opt_start != $opt ) {
+                               continue;
+                       }
+
+                       $opt_rest = substr( $long_opt, $opt_len );
+
+                       if ( $opt_rest != '' && $opt[0] != '=' && $i + 1 < $count &&
+                               $opt == substr( $long_options[ $i + 1 ], 0, $opt_len ) ) {
+                               throw new Exception(
+                                       "option --$opt is ambiguous"
+                               );
+                       }
+
+                       if ( substr( $long_opt, -1 ) == '=' ) {
+                               if ( substr( $long_opt, -2 ) != '==' ) {
+                                       if ( ! strlen( $opt_arg ) ) {
+                                               if ( false === $opt_arg = current( $args ) ) {
+                                                       throw new Exception(
+                                                               "option --$opt requires an argument"
+                                                       );
+                                               }
+                                               next( $args );
+                                       }
+                               }
+                       } elseif ( $opt_arg ) {
+                               throw new Exception(
+                                       "option --$opt doesn't allow an argument"
+                               );
+                       }
+
+                       $full_option = '--' . preg_replace( '/={1,2}$/', '', $long_opt );
+                       $opts[]      = array( $full_option, $opt_arg );
+
+                       return;
+               }
+
+               throw new Exception( "unrecognized option --$opt" );
+       }
</ins><span class="cx" style="display: block; padding: 0 10px"> }
</span><span class="cx" style="display: block; padding: 0 10px"> new WP_PHPUnit_Util_Getopt( $_SERVER['argv'] );
</span></span></pre></div>
<a id="trunktestsphpunitincludesfunctionsphp"></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/functions.php</h4>
<pre class="diff"><span>
<span class="info" style="display: block; padding: 0 10px; color: #888">--- trunk/tests/phpunit/includes/functions.php        2019-01-27 14:45:42 UTC (rev 44700)
+++ trunk/tests/phpunit/includes/functions.php  2019-01-28 14:10:24 UTC (rev 44701)
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -1,6 +1,22 @@
</span><span class="cx" style="display: block; padding: 0 10px"> <?php
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px"> /**
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+ * Retrieves PHPUnit runner version.
+ */
+function tests_get_phpunit_version() {
+       if ( class_exists( 'PHPUnit_Runner_Version' ) ) {
+               $version = PHPUnit_Runner_Version::id();
+       } elseif ( class_exists( 'PHPUnit\Runner\Version' ) ) {
+               // Must be parsable by PHP 5.2.x.
+               $version = call_user_func( 'PHPUnit\Runner\Version::id' );
+       } else {
+               $version = 0;
+       }
+
+       return $version;
+}
+
+/**
</ins><span class="cx" style="display: block; padding: 0 10px">  * Resets various `$_SERVER` variables that can get altered during tests.
</span><span class="cx" style="display: block; padding: 0 10px">  */
</span><span class="cx" style="display: block; padding: 0 10px"> function tests_reset__SERVER() {
</span></span></pre></div>
<a id="trunktestsphpunitincludeslistenerloaderphp"></a>
<div class="addfile"><h4 style="background-color: #eee; color: inherit; margin: 1em 0; padding: 1.3em; font-size: 115%">Added: trunk/tests/phpunit/includes/listener-loader.php</h4>
<pre class="diff"><span>
<span class="info" style="display: block; padding: 0 10px; color: #888">--- trunk/tests/phpunit/includes/listener-loader.php                          (rev 0)
+++ trunk/tests/phpunit/includes/listener-loader.php    2019-01-28 14:10:24 UTC (rev 44701)
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -0,0 +1,7 @@
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+<?php
+
+if ( version_compare( tests_get_phpunit_version(), '7.0', '>=' ) ) {
+       require dirname( __FILE__ ) . '/phpunit7/speed-trap-listener.php';
+} else {
+       require dirname( __FILE__ ) . '/speed-trap-listener.php';
+}
</ins></span></pre></div>
<a id="trunktestsphpunitincludesphpunit6compatphpfromrev44700trunktestsphpunitincludesphpunit6compatphp"></a>
<div class="copfile"><h4 style="background-color: #eee; color: inherit; margin: 1em 0; padding: 1.3em; font-size: 115%">Copied: trunk/tests/phpunit/includes/phpunit6/compat.php (from rev 44700, trunk/tests/phpunit/includes/phpunit6-compat.php)</h4>
<pre class="diff"><span>
<span class="info" style="display: block; padding: 0 10px; color: #888">--- trunk/tests/phpunit/includes/phpunit6/compat.php                          (rev 0)
+++ trunk/tests/phpunit/includes/phpunit6/compat.php    2019-01-28 14:10:24 UTC (rev 44701)
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -0,0 +1,38 @@
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+<?php
+
+if ( class_exists( 'PHPUnit\Runner\Version' ) && version_compare( PHPUnit\Runner\Version::id(), '6.0', '>=' ) ) {
+
+       class_alias( 'PHPUnit\Framework\TestCase', 'PHPUnit_Framework_TestCase' );
+       class_alias( 'PHPUnit\Framework\Exception', 'PHPUnit_Framework_Exception' );
+       class_alias( 'PHPUnit\Framework\ExpectationFailedException', 'PHPUnit_Framework_ExpectationFailedException' );
+       class_alias( 'PHPUnit\Framework\Error\Notice', 'PHPUnit_Framework_Error_Notice' );
+       class_alias( 'PHPUnit\Framework\Error\Warning', 'PHPUnit_Framework_Error_Warning' );
+       class_alias( 'PHPUnit\Framework\Test', 'PHPUnit_Framework_Test' );
+       class_alias( 'PHPUnit\Framework\Warning', 'PHPUnit_Framework_Warning' );
+       class_alias( 'PHPUnit\Framework\AssertionFailedError', 'PHPUnit_Framework_AssertionFailedError' );
+       class_alias( 'PHPUnit\Framework\TestSuite', 'PHPUnit_Framework_TestSuite' );
+       class_alias( 'PHPUnit\Framework\TestListener', 'PHPUnit_Framework_TestListener' );
+       class_alias( 'PHPUnit\Util\GlobalState', 'PHPUnit_Util_GlobalState' );
+       class_alias( 'PHPUnit\Util\Getopt', 'PHPUnit_Util_Getopt' );
+
+       class PHPUnit_Util_Test {
+
+               public static function getTickets( $className, $methodName ) {
+                       $annotations = PHPUnit\Util\Test::parseTestMethodAnnotations( $className, $methodName );
+
+                       $tickets = array();
+
+                       if ( isset( $annotations['class']['ticket'] ) ) {
+                               $tickets = $annotations['class']['ticket'];
+                       }
+
+                       if ( isset( $annotations['method']['ticket'] ) ) {
+                               $tickets = array_merge( $tickets, $annotations['method']['ticket'] );
+                       }
+
+                       return array_unique( $tickets );
+               }
+
+       }
+
+}
</ins></span></pre></div>
<a id="trunktestsphpunitincludesphpunit6compatphp"></a>
<div class="delfile"><h4 style="background-color: #eee; color: inherit; margin: 1em 0; padding: 1.3em; font-size: 115%">Deleted: trunk/tests/phpunit/includes/phpunit6-compat.php</h4>
<pre class="diff"><span>
<span class="info" style="display: block; padding: 0 10px; color: #888">--- trunk/tests/phpunit/includes/phpunit6-compat.php  2019-01-27 14:45:42 UTC (rev 44700)
+++ trunk/tests/phpunit/includes/phpunit6-compat.php    2019-01-28 14:10:24 UTC (rev 44701)
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -1,38 +0,0 @@
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-<?php
-
-if ( class_exists( 'PHPUnit\Runner\Version' ) && version_compare( PHPUnit\Runner\Version::id(), '6.0', '>=' ) ) {
-
-       class_alias( 'PHPUnit\Framework\TestCase', 'PHPUnit_Framework_TestCase' );
-       class_alias( 'PHPUnit\Framework\Exception', 'PHPUnit_Framework_Exception' );
-       class_alias( 'PHPUnit\Framework\ExpectationFailedException', 'PHPUnit_Framework_ExpectationFailedException' );
-       class_alias( 'PHPUnit\Framework\Error\Notice', 'PHPUnit_Framework_Error_Notice' );
-       class_alias( 'PHPUnit\Framework\Error\Warning', 'PHPUnit_Framework_Error_Warning' );
-       class_alias( 'PHPUnit\Framework\Test', 'PHPUnit_Framework_Test' );
-       class_alias( 'PHPUnit\Framework\Warning', 'PHPUnit_Framework_Warning' );
-       class_alias( 'PHPUnit\Framework\AssertionFailedError', 'PHPUnit_Framework_AssertionFailedError' );
-       class_alias( 'PHPUnit\Framework\TestSuite', 'PHPUnit_Framework_TestSuite' );
-       class_alias( 'PHPUnit\Framework\TestListener', 'PHPUnit_Framework_TestListener' );
-       class_alias( 'PHPUnit\Util\GlobalState', 'PHPUnit_Util_GlobalState' );
-       class_alias( 'PHPUnit\Util\Getopt', 'PHPUnit_Util_Getopt' );
-
-       class PHPUnit_Util_Test extends PHPUnit\Util\Test {
-
-               public static function getTickets( $className, $methodName ) {
-                       $annotations = self::parseTestMethodAnnotations( $className, $methodName );
-
-                       $tickets = array();
-
-                       if ( isset( $annotations['class']['ticket'] ) ) {
-                               $tickets = $annotations['class']['ticket'];
-                       }
-
-                       if ( isset( $annotations['method']['ticket'] ) ) {
-                               $tickets = array_merge( $tickets, $annotations['method']['ticket'] );
-                       }
-
-                       return array_unique( $tickets );
-               }
-
-       }
-
-}
</del></span></pre></div>
<a id="trunktestsphpunitincludesphpunit7speedtraplistenerphpfromrev44700trunktestsphpunitincludesspeedtraplistenerphp"></a>
<div class="copfile"><h4 style="background-color: #eee; color: inherit; margin: 1em 0; padding: 1.3em; font-size: 115%">Copied: trunk/tests/phpunit/includes/phpunit7/speed-trap-listener.php (from rev 44700, trunk/tests/phpunit/includes/speed-trap-listener.php)</h4>
<pre class="diff"><span>
<span class="info" style="display: block; padding: 0 10px; color: #888">--- trunk/tests/phpunit/includes/phpunit7/speed-trap-listener.php                             (rev 0)
+++ trunk/tests/phpunit/includes/phpunit7/speed-trap-listener.php       2019-01-28 14:10:24 UTC (rev 44701)
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -0,0 +1,306 @@
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+<?php
+
+/**
+ * A PHPUnit TestListener that exposes your slowest running tests by outputting
+ * results directly to the console.
+ */
+class SpeedTrapListener implements PHPUnit_Framework_TestListener {
+
+       /**
+        * Internal tracking for test suites.
+        *
+        * Increments as more suites are run, then decremented as they finish. All
+        * suites have been run when returns to 0.
+        *
+        * @var integer
+        */
+       protected $suites = 0;
+
+       /**
+        * Time in milliseconds at which a test will be considered "slow" and be
+        * reported by this listener.
+        *
+        * @var int
+        */
+       protected $slowThreshold;
+
+       /**
+        * Number of tests to report on for slowness.
+        *
+        * @var int
+        */
+       protected $reportLength;
+
+       /**
+        * Collection of slow tests.
+        *
+        * @var array
+        */
+       protected $slow = array();
+
+       /**
+        * Construct a new instance.
+        *
+        * @param array $options
+        */
+       public function __construct( array $options = array() ) {
+               $this->loadOptions( $options );
+       }
+
+       /**
+        * An error occurred.
+        *
+        * @param PHPUnit_Framework_Test $test
+        * @param Exception              $e
+        * @param float                   $time
+        */
+       public function addError( PHPUnit\Framework\Test $test, Throwable $t, float $time ): void {
+       }
+
+       /**
+        * A warning occurred.
+        *
+        * @param PHPUnit_Framework_Test    $test
+        * @param PHPUnit_Framework_Warning $e
+        * @param float                     $time
+        * @since Method available since Release 5.1.0
+        */
+       public function addWarning( PHPUnit\Framework\Test $test, PHPUnit\Framework\Warning $e, float $time ): void {
+       }
+
+       /**
+        * A failure occurred.
+        *
+        * @param PHPUnit_Framework_Test                 $test
+        * @param PHPUnit_Framework_AssertionFailedError $e
+        * @param float                                   $time
+        */
+       public function addFailure( PHPUnit\Framework\Test $test, PHPUnit\Framework\AssertionFailedError $e, float $time ): void {
+       }
+
+       /**
+        * Incomplete test.
+        *
+        * @param PHPUnit_Framework_Test $test
+        * @param Exception              $e
+        * @param float                   $time
+        */
+       public function addIncompleteTest( PHPUnit\Framework\Test $test, Throwable $t, float $time ): void {
+       }
+
+       /**
+        * Risky test.
+        *
+        * @param PHPUnit_Framework_Test $test
+        * @param Exception              $e
+        * @param float                   $time
+        * @since  Method available since Release 4.0.0
+        */
+       public function addRiskyTest( PHPUnit\Framework\Test $test, Throwable $t, float $time ): void {
+       }
+
+       /**
+        * Skipped test.
+        *
+        * @param PHPUnit_Framework_Test $test
+        * @param Exception              $e
+        * @param float                   $time
+        */
+       public function addSkippedTest( PHPUnit\Framework\Test $test, Throwable $t, float $time ): void {
+       }
+
+       /**
+        * A test started.
+        *
+        * @param PHPUnit_Framework_Test $test
+        */
+       public function startTest( PHPUnit\Framework\Test $test ): void {
+       }
+
+       /**
+        * A test ended.
+        *
+        * @param PHPUnit_Framework_Test $test
+        * @param float                   $time
+        */
+       public function endTest( PHPUnit\Framework\Test $test, float $time ): void {
+               if ( ! $test instanceof PHPUnit_Framework_TestCase ) {
+                       return;
+               }
+
+               $time      = $this->toMilliseconds( $time );
+               $threshold = $this->getSlowThreshold( $test );
+
+               if ( $this->isSlow( $time, $threshold ) ) {
+                       $this->addSlowTest( $test, $time );
+               }
+       }
+
+       /**
+        * A test suite started.
+        *
+        * @param PHPUnit_Framework_TestSuite $suite
+        */
+       public function startTestSuite( PHPUnit\Framework\TestSuite $suite ): void {
+               $this->suites++;
+       }
+
+       /**
+        * A test suite ended.
+        *
+        * @param PHPUnit_Framework_TestSuite $suite
+        */
+       public function endTestSuite( PHPUnit\Framework\TestSuite $suite ): void {
+               $this->suites--;
+
+               if ( 0 === $this->suites && $this->hasSlowTests() ) {
+                       arsort( $this->slow ); // Sort longest running tests to the top
+
+                       $this->renderHeader();
+                       $this->renderBody();
+                       $this->renderFooter();
+               }
+       }
+
+       /**
+        * Whether the given test execution time is considered slow.
+        *
+        * @param int $time          Test execution time in milliseconds
+        * @param int $slowThreshold Test execution time at which a test should be considered slow (milliseconds)
+        * @return bool
+        */
+       protected function isSlow( $time, $slowThreshold ) {
+               return $time >= $slowThreshold;
+       }
+
+       /**
+        * Stores a test as slow.
+        *
+        * @param PHPUnit_Framework_TestCase $test
+        * @param int                         $time Test execution time in milliseconds
+        */
+       protected function addSlowTest( PHPUnit_Framework_TestCase $test, $time ) {
+               $label = $this->makeLabel( $test );
+
+               $this->slow[ $label ] = $time;
+       }
+
+       /**
+        * Whether at least one test has been considered slow.
+        *
+        * @return bool
+        */
+       protected function hasSlowTests() {
+               return ! empty( $this->slow );
+       }
+
+       /**
+        * Convert PHPUnit's reported test time (microseconds) to milliseconds.
+        *
+        * @param float $time
+        * @return int
+        */
+       protected function toMilliseconds( $time ) {
+               return (int) round( $time * 1000 );
+       }
+
+       /**
+        * Label for describing a test.
+        *
+        * @param PHPUnit_Framework_TestCase $test
+        * @return string
+        */
+       protected function makeLabel( PHPUnit_Framework_TestCase $test ) {
+               return sprintf( '%s:%s', get_class( $test ), $test->getName() );
+       }
+
+       /**
+        * Calculate number of slow tests to report about.
+        *
+        * @return int
+        */
+       protected function getReportLength() {
+               return min( count( $this->slow ), $this->reportLength );
+       }
+
+       /**
+        * Find how many slow tests occurred that won't be shown due to list length.
+        *
+        * @return int Number of hidden slow tests
+        */
+       protected function getHiddenCount() {
+               $total   = count( $this->slow );
+               $showing = $this->getReportLength( $this->slow );
+
+               $hidden = 0;
+               if ( $total > $showing ) {
+                       $hidden = $total - $showing;
+               }
+
+               return $hidden;
+       }
+
+       /**
+        * Renders slow test report header.
+        */
+       protected function renderHeader() {
+               echo sprintf( "\n\nYou should really fix these slow tests (>%sms)...\n", $this->slowThreshold );
+       }
+
+       /**
+        * Renders slow test report body.
+        */
+       protected function renderBody() {
+               $slowTests = $this->slow;
+
+               $length = $this->getReportLength( $slowTests );
+               for ( $i = 1; $i <= $length; ++$i ) {
+                       $label = key( $slowTests );
+                       $time  = array_shift( $slowTests );
+
+                       echo sprintf( " %s. %sms to run %s\n", $i, $time, $label );
+               }
+       }
+
+       /**
+        * Renders slow test report footer.
+        */
+       protected function renderFooter() {
+               if ( $hidden = $this->getHiddenCount( $this->slow ) ) {
+                       echo sprintf( '...and there %s %s more above your threshold hidden from view', $hidden == 1 ? 'is' : 'are', $hidden );
+               }
+       }
+
+       /**
+        * Populate options into class internals.
+        *
+        * @param array $options
+        */
+       protected function loadOptions( array $options ) {
+               $this->slowThreshold = isset( $options['slowThreshold'] ) ? $options['slowThreshold'] : 500;
+               $this->reportLength  = isset( $options['reportLength'] ) ? $options['reportLength'] : 10;
+       }
+
+       /**
+        * Get slow test threshold for given test. A TestCase can override the
+        * suite-wide slow threshold by using the annotation @slowThreshold with
+        * the threshold value in milliseconds.
+        *
+        * The following test will only be considered slow when its execution time
+        * reaches 5000ms (5 seconds):
+        *
+        * <code>
+        *
+        * @slowThreshold 5000
+        * public function testLongRunningProcess() {}
+        * </code>
+        *
+        * @param PHPUnit_Framework_TestCase $test
+        * @return int
+        */
+       protected function getSlowThreshold( PHPUnit_Framework_TestCase $test ) {
+               $ann = $test->getAnnotations();
+
+               return isset( $ann['method']['slowThreshold'][0] ) ? $ann['method']['slowThreshold'][0] : $this->slowThreshold;
+       }
+}
</ins></span></pre></div>
<a id="trunktestsphpunitincludesphpunit7testcasephpfromrev44700trunktestsphpunitincludestestcasephp"></a>
<div class="copfile"><h4 style="background-color: #eee; color: inherit; margin: 1em 0; padding: 1.3em; font-size: 115%">Copied: trunk/tests/phpunit/includes/phpunit7/testcase.php (from rev 44700, trunk/tests/phpunit/includes/testcase.php)</h4>
<pre class="diff"><span>
<span class="info" style="display: block; padding: 0 10px; color: #888">--- trunk/tests/phpunit/includes/phpunit7/testcase.php                                (rev 0)
+++ trunk/tests/phpunit/includes/phpunit7/testcase.php  2019-01-28 14:10:24 UTC (rev 44701)
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -0,0 +1,31 @@
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+<?php
+
+require_once dirname( dirname( __FILE__ ) ) . '/abstract-testcase.php';
+
+/**
+ * Defines a basic fixture to run multiple tests.
+ *
+ * Resets the state of the WordPress installation before and after every test.
+ *
+ * Includes utility functions and assertions useful for testing WordPress.
+ *
+ * All WordPress unit tests should inherit from this class.
+ */
+class WP_UnitTestCase extends WP_UnitTestCase_Base {
+       /**
+        * Asserts that a condition is not false.
+        *
+        * This method has been backported from a more recent PHPUnit version, as tests running on PHP 5.2 use
+        * PHPUnit 3.6.x.
+        *
+        * @since 4.7.4
+        *
+        * @param bool   $condition Condition to check.
+        * @param string $message   Optional. Message to display when the assertion fails.
+        *
+        * @throws PHPUnit_Framework_AssertionFailedError
+        */
+       public static function assertNotFalse( $condition, string $message = '' ): void {
+               self::assertThat( $condition, self::logicalNot( self::isFalse() ), $message );
+       }
+}
</ins></span></pre></div>
<a id="trunktestsphpunitincludestestcasecanonicalphp"></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/testcase-canonical.php</h4>
<pre class="diff"><span>
<span class="info" style="display: block; padding: 0 10px; color: #888">--- trunk/tests/phpunit/includes/testcase-canonical.php       2019-01-27 14:45:42 UTC (rev 44700)
+++ trunk/tests/phpunit/includes/testcase-canonical.php 2019-01-28 14:10:24 UTC (rev 44701)
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -236,7 +236,7 @@
</span><span class="cx" style="display: block; padding: 0 10px">        public function assertCanonical( $test_url, $expected, $ticket = 0, $expected_doing_it_wrong = array() ) {
</span><span class="cx" style="display: block; padding: 0 10px">                $this->expected_doing_it_wrong = array_merge( $this->expected_doing_it_wrong, (array) $expected_doing_it_wrong );
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-                $ticket_ref = ( $ticket > 0 ) ? 'Ticket #' . $ticket : null;
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+         $ticket_ref = ( $ticket > 0 ) ? 'Ticket #' . $ticket : '';
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px">                if ( is_string( $expected ) ) {
</span><span class="cx" style="display: block; padding: 0 10px">                        $expected = array( 'url' => $expected );
</span></span></pre></div>
<a id="trunktestsphpunitincludestestcasephp"></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/testcase.php</h4>
<pre class="diff"><span>
<span class="info" style="display: block; padding: 0 10px; color: #888">--- trunk/tests/phpunit/includes/testcase.php 2019-01-27 14:45:42 UTC (rev 44700)
+++ trunk/tests/phpunit/includes/testcase.php   2019-01-28 14:10:24 UTC (rev 44701)
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -1,7 +1,6 @@
</span><span class="cx" style="display: block; padding: 0 10px"> <?php
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-require_once dirname( __FILE__ ) . '/factory.php';
-require_once dirname( __FILE__ ) . '/trac.php';
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+require_once dirname( __FILE__ ) . '/abstract-testcase.php';
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px"> /**
</span><span class="cx" style="display: block; padding: 0 10px">  * Defines a basic fixture to run multiple tests.
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -12,579 +11,9 @@
</span><span class="cx" style="display: block; padding: 0 10px">  *
</span><span class="cx" style="display: block; padding: 0 10px">  * All WordPress unit tests should inherit from this class.
</span><span class="cx" style="display: block; padding: 0 10px">  */
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-class WP_UnitTestCase extends PHPUnit_Framework_TestCase {
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+class WP_UnitTestCase extends WP_UnitTestCase_Base {
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-        protected static $forced_tickets   = array();
-       protected $expected_deprecated     = array();
-       protected $caught_deprecated       = array();
-       protected $expected_doing_it_wrong = array();
-       protected $caught_doing_it_wrong   = array();
-
-       protected static $hooks_saved = array();
-       protected static $ignore_files;
-
-       function __isset( $name ) {
-               return 'factory' === $name;
-       }
-
-       function __get( $name ) {
-               if ( 'factory' === $name ) {
-                       return self::factory();
-               }
-       }
-
</del><span class="cx" style="display: block; padding: 0 10px">         /**
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-         * Fetches the factory object for generating WordPress fixtures.
-        *
-        * @return WP_UnitTest_Factory The fixture factory.
-        */
-       protected static function factory() {
-               static $factory = null;
-               if ( ! $factory ) {
-                       $factory = new WP_UnitTest_Factory();
-               }
-               return $factory;
-       }
-
-       public static function get_called_class() {
-               if ( function_exists( 'get_called_class' ) ) {
-                       return get_called_class();
-               }
-
-               // PHP 5.2 only
-               $backtrace = debug_backtrace();
-               // [0] WP_UnitTestCase::get_called_class()
-               // [1] WP_UnitTestCase::setUpBeforeClass()
-               if ( 'call_user_func' === $backtrace[2]['function'] ) {
-                       return $backtrace[2]['args'][0][0];
-               }
-               return $backtrace[2]['class'];
-       }
-
-       public static function setUpBeforeClass() {
-               global $wpdb;
-
-               $wpdb->suppress_errors = false;
-               $wpdb->show_errors     = true;
-               $wpdb->db_connect();
-               ini_set( 'display_errors', 1 );
-
-               parent::setUpBeforeClass();
-
-               $c = self::get_called_class();
-               if ( ! method_exists( $c, 'wpSetUpBeforeClass' ) ) {
-                       self::commit_transaction();
-                       return;
-               }
-
-               call_user_func( array( $c, 'wpSetUpBeforeClass' ), self::factory() );
-
-               self::commit_transaction();
-       }
-
-       public static function tearDownAfterClass() {
-               parent::tearDownAfterClass();
-
-               _delete_all_data();
-               self::flush_cache();
-
-               $c = self::get_called_class();
-               if ( ! method_exists( $c, 'wpTearDownAfterClass' ) ) {
-                       self::commit_transaction();
-                       return;
-               }
-
-               call_user_func( array( $c, 'wpTearDownAfterClass' ) );
-
-               self::commit_transaction();
-       }
-
-       function setUp() {
-               set_time_limit( 0 );
-
-               if ( ! self::$ignore_files ) {
-                       self::$ignore_files = $this->scan_user_uploads();
-               }
-
-               if ( ! self::$hooks_saved ) {
-                       $this->_backup_hooks();
-               }
-
-               global $wp_rewrite;
-
-               $this->clean_up_global_scope();
-
-               /*
-                * When running core tests, ensure that post types and taxonomies
-                * are reset for each test. We skip this step for non-core tests,
-                * given the large number of plugins that register post types and
-                * taxonomies at 'init'.
-                */
-               if ( defined( 'WP_RUN_CORE_TESTS' ) && WP_RUN_CORE_TESTS ) {
-                       $this->reset_post_types();
-                       $this->reset_taxonomies();
-                       $this->reset_post_statuses();
-                       $this->reset__SERVER();
-
-                       if ( $wp_rewrite->permalink_structure ) {
-                               $this->set_permalink_structure( '' );
-                       }
-               }
-
-               $this->start_transaction();
-               $this->expectDeprecated();
-               add_filter( 'wp_die_handler', array( $this, 'get_wp_die_handler' ) );
-       }
-
-       /**
-        * Detect post-test failure conditions.
-        *
-        * We use this method to detect expectedDeprecated and expectedIncorrectUsage annotations.
-        *
-        * @since 4.2.0
-        */
-       protected function assertPostConditions() {
-               $this->expectedDeprecated();
-       }
-
-       /**
-        * After a test method runs, reset any state in WordPress the test method might have changed.
-        */
-       function tearDown() {
-               global $wpdb, $wp_query, $wp;
-               $wpdb->query( 'ROLLBACK' );
-               if ( is_multisite() ) {
-                       while ( ms_is_switched() ) {
-                               restore_current_blog();
-                       }
-               }
-               $wp_query = new WP_Query();
-               $wp       = new WP();
-
-               // Reset globals related to the post loop and `setup_postdata()`.
-               $post_globals = array( 'post', 'id', 'authordata', 'currentday', 'currentmonth', 'page', 'pages', 'multipage', 'more', 'numpages' );
-               foreach ( $post_globals as $global ) {
-                       $GLOBALS[ $global ] = null;
-               }
-
-               $this->unregister_all_meta_keys();
-               remove_theme_support( 'html5' );
-               remove_filter( 'query', array( $this, '_create_temporary_tables' ) );
-               remove_filter( 'query', array( $this, '_drop_temporary_tables' ) );
-               remove_filter( 'wp_die_handler', array( $this, 'get_wp_die_handler' ) );
-               $this->_restore_hooks();
-               wp_set_current_user( 0 );
-       }
-
-       function clean_up_global_scope() {
-               $_GET  = array();
-               $_POST = array();
-               self::flush_cache();
-       }
-
-       /**
-        * Allow tests to be skipped on some automated runs
-        *
-        * For test runs on Travis for something other than trunk/master
-        * we want to skip tests that only need to run for master.
-        */
-       public function skipOnAutomatedBranches() {
-               // gentenv can be disabled
-               if ( ! function_exists( 'getenv' ) ) {
-                       return false;
-               }
-
-               // https://docs.travis-ci.com/user/environment-variables/#Default-Environment-Variables
-               $travis_branch       = getenv( 'TRAVIS_BRANCH' );
-               $travis_pull_request = getenv( 'TRAVIS_PULL_REQUEST' );
-
-               if ( false !== $travis_pull_request && 'master' !== $travis_branch ) {
-                       $this->markTestSkipped( 'For automated test runs, this test is only run on trunk/master' );
-               }
-       }
-
-       /**
-        * Allow tests to be skipped when Multisite is not in use.
-        *
-        * Use in conjunction with the ms-required group.
-        */
-       public function skipWithoutMultisite() {
-               if ( ! is_multisite() ) {
-                       $this->markTestSkipped( 'Test only runs on Multisite' );
-               }
-       }
-
-       /**
-        * Allow tests to be skipped when Multisite is in use.
-        *
-        * Use in conjunction with the ms-excluded group.
-        */
-       public function skipWithMultisite() {
-               if ( is_multisite() ) {
-                       $this->markTestSkipped( 'Test does not run on Multisite' );
-               }
-       }
-
-       /**
-        * Unregister existing post types and register defaults.
-        *
-        * Run before each test in order to clean up the global scope, in case
-        * a test forgets to unregister a post type on its own, or fails before
-        * it has a chance to do so.
-        */
-       protected function reset_post_types() {
-               foreach ( get_post_types( array(), 'objects' ) as $pt ) {
-                       if ( empty( $pt->tests_no_auto_unregister ) ) {
-                               _unregister_post_type( $pt->name );
-                       }
-               }
-               create_initial_post_types();
-       }
-
-       /**
-        * Unregister existing taxonomies and register defaults.
-        *
-        * Run before each test in order to clean up the global scope, in case
-        * a test forgets to unregister a taxonomy on its own, or fails before
-        * it has a chance to do so.
-        */
-       protected function reset_taxonomies() {
-               foreach ( get_taxonomies() as $tax ) {
-                       _unregister_taxonomy( $tax );
-               }
-               create_initial_taxonomies();
-       }
-
-       /**
-        * Unregister non-built-in post statuses.
-        */
-       protected function reset_post_statuses() {
-               foreach ( get_post_stati( array( '_builtin' => false ) ) as $post_status ) {
-                       _unregister_post_status( $post_status );
-               }
-       }
-
-       /**
-        * Reset `$_SERVER` variables
-        */
-       protected function reset__SERVER() {
-               tests_reset__SERVER();
-       }
-
-       /**
-        * Saves the action and filter-related globals so they can be restored later.
-        *
-        * Stores $wp_actions, $wp_current_filter, and $wp_filter
-        * on a class variable so they can be restored on tearDown() using _restore_hooks().
-        *
-        * @global array $wp_actions
-        * @global array $wp_current_filter
-        * @global array $wp_filter
-        * @return void
-        */
-       protected function _backup_hooks() {
-               $globals = array( 'wp_actions', 'wp_current_filter' );
-               foreach ( $globals as $key ) {
-                       self::$hooks_saved[ $key ] = $GLOBALS[ $key ];
-               }
-               self::$hooks_saved['wp_filter'] = array();
-               foreach ( $GLOBALS['wp_filter'] as $hook_name => $hook_object ) {
-                       self::$hooks_saved['wp_filter'][ $hook_name ] = clone $hook_object;
-               }
-       }
-
-       /**
-        * Restores the hook-related globals to their state at setUp()
-        * so that future tests aren't affected by hooks set during this last test.
-        *
-        * @global array $wp_actions
-        * @global array $wp_current_filter
-        * @global array $wp_filter
-        * @return void
-        */
-       protected function _restore_hooks() {
-               $globals = array( 'wp_actions', 'wp_current_filter' );
-               foreach ( $globals as $key ) {
-                       if ( isset( self::$hooks_saved[ $key ] ) ) {
-                               $GLOBALS[ $key ] = self::$hooks_saved[ $key ];
-                       }
-               }
-               if ( isset( self::$hooks_saved['wp_filter'] ) ) {
-                       $GLOBALS['wp_filter'] = array();
-                       foreach ( self::$hooks_saved['wp_filter'] as $hook_name => $hook_object ) {
-                               $GLOBALS['wp_filter'][ $hook_name ] = clone $hook_object;
-                       }
-               }
-       }
-
-       static function flush_cache() {
-               global $wp_object_cache;
-               $wp_object_cache->group_ops      = array();
-               $wp_object_cache->stats          = array();
-               $wp_object_cache->memcache_debug = array();
-               $wp_object_cache->cache          = array();
-               if ( method_exists( $wp_object_cache, '__remoteset' ) ) {
-                       $wp_object_cache->__remoteset();
-               }
-               wp_cache_flush();
-               wp_cache_add_global_groups( array( 'users', 'userlogins', 'usermeta', 'user_meta', 'useremail', 'userslugs', 'site-transient', 'site-options', 'blog-lookup', 'blog-details', 'rss', 'global-posts', 'blog-id-cache', 'networks', 'sites', 'site-details', 'blog_meta' ) );
-               wp_cache_add_non_persistent_groups( array( 'comment', 'counts', 'plugins' ) );
-       }
-
-       /**
-        * Clean up any registered meta keys.
-        *
-        * @since 5.1.0
-        *
-        * @global array $wp_meta_keys
-        */
-       function unregister_all_meta_keys() {
-               global $wp_meta_keys;
-               if ( ! is_array( $wp_meta_keys ) ) {
-                       return;
-               }
-               foreach ( $wp_meta_keys as $object_type => $type_keys ) {
-                       foreach ( $type_keys as $object_subtype => $subtype_keys ) {
-                               foreach ( $subtype_keys as $key => $value ) {
-                                       unregister_meta_key( $object_type, $key, $object_subtype );
-                               }
-                       }
-               }
-       }
-
-       function start_transaction() {
-               global $wpdb;
-               $wpdb->query( 'SET autocommit = 0;' );
-               $wpdb->query( 'START TRANSACTION;' );
-               add_filter( 'query', array( $this, '_create_temporary_tables' ) );
-               add_filter( 'query', array( $this, '_drop_temporary_tables' ) );
-       }
-
-       /**
-        * Commit the queries in a transaction.
-        *
-        * @since 4.1.0
-        */
-       public static function commit_transaction() {
-               global $wpdb;
-               $wpdb->query( 'COMMIT;' );
-       }
-
-       function _create_temporary_tables( $query ) {
-               if ( 'CREATE TABLE' === substr( trim( $query ), 0, 12 ) ) {
-                       return substr_replace( trim( $query ), 'CREATE TEMPORARY TABLE', 0, 12 );
-               }
-               return $query;
-       }
-
-       function _drop_temporary_tables( $query ) {
-               if ( 'DROP TABLE' === substr( trim( $query ), 0, 10 ) ) {
-                       return substr_replace( trim( $query ), 'DROP TEMPORARY TABLE', 0, 10 );
-               }
-               return $query;
-       }
-
-       function get_wp_die_handler( $handler ) {
-               return array( $this, 'wp_die_handler' );
-       }
-
-       function wp_die_handler( $message ) {
-               if ( ! is_scalar( $message ) ) {
-                       $message = '0';
-               }
-
-               throw new WPDieException( $message );
-       }
-
-       function expectDeprecated() {
-               $annotations = $this->getAnnotations();
-               foreach ( array( 'class', 'method' ) as $depth ) {
-                       if ( ! empty( $annotations[ $depth ]['expectedDeprecated'] ) ) {
-                               $this->expected_deprecated = array_merge( $this->expected_deprecated, $annotations[ $depth ]['expectedDeprecated'] );
-                       }
-                       if ( ! empty( $annotations[ $depth ]['expectedIncorrectUsage'] ) ) {
-                               $this->expected_doing_it_wrong = array_merge( $this->expected_doing_it_wrong, $annotations[ $depth ]['expectedIncorrectUsage'] );
-                       }
-               }
-               add_action( 'deprecated_function_run', array( $this, 'deprecated_function_run' ) );
-               add_action( 'deprecated_argument_run', array( $this, 'deprecated_function_run' ) );
-               add_action( 'deprecated_hook_run', array( $this, 'deprecated_function_run' ) );
-               add_action( 'doing_it_wrong_run', array( $this, 'doing_it_wrong_run' ) );
-               add_action( 'deprecated_function_trigger_error', '__return_false' );
-               add_action( 'deprecated_argument_trigger_error', '__return_false' );
-               add_action( 'deprecated_hook_trigger_error', '__return_false' );
-               add_action( 'doing_it_wrong_trigger_error', '__return_false' );
-       }
-
-       function expectedDeprecated() {
-               $errors = array();
-
-               $not_caught_deprecated = array_diff( $this->expected_deprecated, $this->caught_deprecated );
-               foreach ( $not_caught_deprecated as $not_caught ) {
-                       $errors[] = "Failed to assert that $not_caught triggered a deprecated notice";
-               }
-
-               $unexpected_deprecated = array_diff( $this->caught_deprecated, $this->expected_deprecated );
-               foreach ( $unexpected_deprecated as $unexpected ) {
-                       $errors[] = "Unexpected deprecated notice for $unexpected";
-               }
-
-               $not_caught_doing_it_wrong = array_diff( $this->expected_doing_it_wrong, $this->caught_doing_it_wrong );
-               foreach ( $not_caught_doing_it_wrong as $not_caught ) {
-                       $errors[] = "Failed to assert that $not_caught triggered an incorrect usage notice";
-               }
-
-               $unexpected_doing_it_wrong = array_diff( $this->caught_doing_it_wrong, $this->expected_doing_it_wrong );
-               foreach ( $unexpected_doing_it_wrong as $unexpected ) {
-                       $errors[] = "Unexpected incorrect usage notice for $unexpected";
-               }
-
-               // Perform an assertion, but only if there are expected or unexpected deprecated calls or wrongdoings
-               if ( ! empty( $this->expected_deprecated ) ||
-                       ! empty( $this->expected_doing_it_wrong ) ||
-                       ! empty( $this->caught_deprecated ) ||
-                       ! empty( $this->caught_doing_it_wrong ) ) {
-                       $this->assertEmpty( $errors, implode( "\n", $errors ) );
-               }
-       }
-
-       /**
-        * Declare an expected `_deprecated_function()` or `_deprecated_argument()` call from within a test.
-        *
-        * @since 4.2.0
-        *
-        * @param string $deprecated Name of the function, method, class, or argument that is deprecated. Must match
-        *                           first parameter of the `_deprecated_function()` or `_deprecated_argument()` call.
-        */
-       public function setExpectedDeprecated( $deprecated ) {
-               array_push( $this->expected_deprecated, $deprecated );
-       }
-
-       /**
-        * Declare an expected `_doing_it_wrong()` call from within a test.
-        *
-        * @since 4.2.0
-        *
-        * @param string $deprecated Name of the function, method, or class that appears in the first argument of the
-        *                           source `_doing_it_wrong()` call.
-        */
-       public function setExpectedIncorrectUsage( $doing_it_wrong ) {
-               array_push( $this->expected_doing_it_wrong, $doing_it_wrong );
-       }
-
-       /**
-        * PHPUnit 6+ compatibility shim.
-        *
-        * @param mixed      $exception
-        * @param string     $message
-        * @param int|string $code
-        */
-       public function setExpectedException( $exception, $message = '', $code = null ) {
-               if ( method_exists( 'PHPUnit_Framework_TestCase', 'setExpectedException' ) ) {
-                       parent::setExpectedException( $exception, $message, $code );
-               } else {
-                       $this->expectException( $exception );
-                       if ( '' !== $message ) {
-                               $this->expectExceptionMessage( $message );
-                       }
-                       if ( null !== $code ) {
-                               $this->expectExceptionCode( $code );
-                       }
-               }
-       }
-
-       function deprecated_function_run( $function ) {
-               if ( ! in_array( $function, $this->caught_deprecated ) ) {
-                       $this->caught_deprecated[] = $function;
-               }
-       }
-
-       function doing_it_wrong_run( $function ) {
-               if ( ! in_array( $function, $this->caught_doing_it_wrong ) ) {
-                       $this->caught_doing_it_wrong[] = $function;
-               }
-       }
-
-       function assertWPError( $actual, $message = '' ) {
-               $this->assertInstanceOf( 'WP_Error', $actual, $message );
-       }
-
-       function assertNotWPError( $actual, $message = '' ) {
-               if ( is_wp_error( $actual ) && '' === $message ) {
-                       $message = $actual->get_error_message();
-               }
-               $this->assertNotInstanceOf( 'WP_Error', $actual, $message );
-       }
-
-       function assertIXRError( $actual, $message = '' ) {
-               $this->assertInstanceOf( 'IXR_Error', $actual, $message );
-       }
-
-       function assertNotIXRError( $actual, $message = '' ) {
-               if ( $actual instanceof IXR_Error && '' === $message ) {
-                       $message = $actual->message;
-               }
-               $this->assertNotInstanceOf( 'IXR_Error', $actual, $message );
-       }
-
-       function assertEqualFields( $object, $fields ) {
-               foreach ( $fields as $field_name => $field_value ) {
-                       if ( $object->$field_name != $field_value ) {
-                               $this->fail();
-                       }
-               }
-       }
-
-       function assertDiscardWhitespace( $expected, $actual ) {
-               $this->assertEquals( preg_replace( '/\s*/', '', $expected ), preg_replace( '/\s*/', '', $actual ) );
-       }
-
-       /**
-        * Asserts that the contents of two un-keyed, single arrays are equal, without accounting for the order of elements.
-        *
-        * @since 3.5.0
-        *
-        * @param array $expected Expected array.
-        * @param array $actual   Array to check.
-        */
-       function assertEqualSets( $expected, $actual ) {
-               sort( $expected );
-               sort( $actual );
-               $this->assertEquals( $expected, $actual );
-       }
-
-       /**
-        * Asserts that the contents of two keyed, single arrays are equal, without accounting for the order of elements.
-        *
-        * @since 4.1.0
-        *
-        * @param array $expected Expected array.
-        * @param array $actual   Array to check.
-        */
-       function assertEqualSetsWithIndex( $expected, $actual ) {
-               ksort( $expected );
-               ksort( $actual );
-               $this->assertEquals( $expected, $actual );
-       }
-
-       /**
-        * Asserts that the given variable is a multidimensional array, and that all arrays are non-empty.
-        *
-        * @since 4.8.0
-        *
-        * @param array $array Array to check.
-        */
-       function assertNonEmptyMultidimensionalArray( $array ) {
-               $this->assertTrue( is_array( $array ) );
-               $this->assertNotEmpty( $array );
-
-               foreach ( $array as $sub_array ) {
-                       $this->assertTrue( is_array( $sub_array ) );
-                       $this->assertNotEmpty( $sub_array );
-               }
-       }
-
-       /**
</del><span class="cx" style="display: block; padding: 0 10px">          * Asserts that a condition is not false.
</span><span class="cx" style="display: block; padding: 0 10px">         *
</span><span class="cx" style="display: block; padding: 0 10px">         * This method has been backported from a more recent PHPUnit version, as tests running on PHP 5.2 use
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -600,528 +29,4 @@
</span><span class="cx" style="display: block; padding: 0 10px">        public static function assertNotFalse( $condition, $message = '' ) {
</span><span class="cx" style="display: block; padding: 0 10px">                self::assertThat( $condition, self::logicalNot( self::isFalse() ), $message );
</span><span class="cx" style="display: block; padding: 0 10px">        }
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-
-       /**
-        * Sets the global state to as if a given URL has been requested.
-        *
-        * This sets:
-        * - The super globals.
-        * - The globals.
-        * - The query variables.
-        * - The main query.
-        *
-        * @since 3.5.0
-        *
-        * @param string $url The URL for the request.
-        */
-       function go_to( $url ) {
-               // note: the WP and WP_Query classes like to silently fetch parameters
-               // from all over the place (globals, GET, etc), which makes it tricky
-               // to run them more than once without very carefully clearing everything
-               $_GET = $_POST = array();
-               foreach ( array( 'query_string', 'id', 'postdata', 'authordata', 'day', 'currentmonth', 'page', 'pages', 'multipage', 'more', 'numpages', 'pagenow' ) as $v ) {
-                       if ( isset( $GLOBALS[ $v ] ) ) {
-                               unset( $GLOBALS[ $v ] );
-                       }
-               }
-               $parts = parse_url( $url );
-               if ( isset( $parts['scheme'] ) ) {
-                       $req = isset( $parts['path'] ) ? $parts['path'] : '';
-                       if ( isset( $parts['query'] ) ) {
-                               $req .= '?' . $parts['query'];
-                               // parse the url query vars into $_GET
-                               parse_str( $parts['query'], $_GET );
-                       }
-               } else {
-                       $req = $url;
-               }
-               if ( ! isset( $parts['query'] ) ) {
-                       $parts['query'] = '';
-               }
-
-               $_SERVER['REQUEST_URI'] = $req;
-               unset( $_SERVER['PATH_INFO'] );
-
-               self::flush_cache();
-               unset( $GLOBALS['wp_query'], $GLOBALS['wp_the_query'] );
-               $GLOBALS['wp_the_query'] = new WP_Query();
-               $GLOBALS['wp_query']     = $GLOBALS['wp_the_query'];
-
-               $public_query_vars  = $GLOBALS['wp']->public_query_vars;
-               $private_query_vars = $GLOBALS['wp']->private_query_vars;
-
-               $GLOBALS['wp']                     = new WP();
-               $GLOBALS['wp']->public_query_vars  = $public_query_vars;
-               $GLOBALS['wp']->private_query_vars = $private_query_vars;
-
-               _cleanup_query_vars();
-
-               $GLOBALS['wp']->main( $parts['query'] );
-       }
-
-       /**
-        * Allows tests to be skipped on single or multisite installs by using @group annotations.
-        *
-        * This is a custom extension of the PHPUnit requirements handling.
-        *
-        * Contains legacy code for skipping tests that are associated with an open Trac ticket. Core tests no longer
-        * support this behaviour.
-        *
-        * @since 3.5.0
-        */
-       protected function checkRequirements() {
-               parent::checkRequirements();
-
-               $annotations = $this->getAnnotations();
-
-               $groups = array();
-               if ( ! empty( $annotations['class']['group'] ) ) {
-                       $groups = array_merge( $groups, $annotations['class']['group'] );
-               }
-               if ( ! empty( $annotations['method']['group'] ) ) {
-                       $groups = array_merge( $groups, $annotations['method']['group'] );
-               }
-
-               if ( ! empty( $groups ) ) {
-                       if ( in_array( 'ms-required', $groups, true ) ) {
-                               $this->skipWithoutMultisite();
-                       }
-
-                       if ( in_array( 'ms-excluded', $groups, true ) ) {
-                               $this->skipWithMultisite();
-                       }
-               }
-
-               // Core tests no longer check against open Trac tickets, but others using WP_UnitTestCase may do so.
-               if ( defined( 'WP_RUN_CORE_TESTS' ) && WP_RUN_CORE_TESTS ) {
-                       return;
-               }
-
-               if ( WP_TESTS_FORCE_KNOWN_BUGS ) {
-                       return;
-               }
-               $tickets = PHPUnit_Util_Test::getTickets( get_class( $this ), $this->getName( false ) );
-               foreach ( $tickets as $ticket ) {
-                       if ( is_numeric( $ticket ) ) {
-                               $this->knownWPBug( $ticket );
-                       } elseif ( 'Plugin' == substr( $ticket, 0, 6 ) ) {
-                               $ticket = substr( $ticket, 6 );
-                               if ( $ticket && is_numeric( $ticket ) ) {
-                                       $this->knownPluginBug( $ticket );
-                               }
-                       }
-               }
-       }
-
-       /**
-        * Skips the current test if there is an open Trac ticket associated with it.
-        *
-        * @since 3.5.0
-        *
-        * @param int $ticket_id Ticket number.
-        */
-       function knownWPBug( $ticket_id ) {
-               if ( WP_TESTS_FORCE_KNOWN_BUGS || in_array( $ticket_id, self::$forced_tickets ) ) {
-                       return;
-               }
-               if ( ! TracTickets::isTracTicketClosed( 'https://core.trac.wordpress.org', $ticket_id ) ) {
-                       $this->markTestSkipped( sprintf( 'WordPress Ticket #%d is not fixed', $ticket_id ) );
-               }
-       }
-
-       /**
-        * Skips the current test if there is an open Unit Test Trac ticket associated with it.
-        *
-        * @since 3.5.0
-        *
-        * @deprecated No longer used since the Unit Test Trac was merged into the Core Trac.
-        *
-        * @param int $ticket_id Ticket number.
-        */
-       function knownUTBug( $ticket_id ) {
-               return;
-       }
-
-       /**
-        * Skips the current test if there is an open Plugin Trac ticket associated with it.
-        *
-        * @since 3.5.0
-        *
-        * @param int $ticket_id Ticket number.
-        */
-       function knownPluginBug( $ticket_id ) {
-               if ( WP_TESTS_FORCE_KNOWN_BUGS || in_array( 'Plugin' . $ticket_id, self::$forced_tickets ) ) {
-                       return;
-               }
-               if ( ! TracTickets::isTracTicketClosed( 'https://plugins.trac.wordpress.org', $ticket_id ) ) {
-                       $this->markTestSkipped( sprintf( 'WordPress Plugin Ticket #%d is not fixed', $ticket_id ) );
-               }
-       }
-
-       /**
-        * Adds a Trac ticket number to the `$forced_tickets` property.
-        *
-        * @since 3.5.0
-        *
-        * @param int $ticket Ticket number.
-        */
-       public static function forceTicket( $ticket ) {
-               self::$forced_tickets[] = $ticket;
-       }
-
-       /**
-        * Custom preparations for the PHPUnit process isolation template.
-        *
-        * When restoring global state between tests, PHPUnit defines all the constants that were already defined, and then
-        * includes included files. This does not work with WordPress, as the included files define the constants.
-        *
-        * This method defines the constants after including files.
-        *
-        * @param Text_Template $template
-        */
-       function prepareTemplate( Text_Template $template ) {
-               $template->setVar( array( 'constants' => '' ) );
-               $template->setVar( array( 'wp_constants' => PHPUnit_Util_GlobalState::getConstantsAsString() ) );
-               parent::prepareTemplate( $template );
-       }
-
-       /**
-        * Creates a unique temporary file name.
-        *
-        * The directory in which the file is created depends on the environment configuration.
-        *
-        * @since 3.5.0
-        *
-        * @return string|bool Path on success, else false.
-        */
-       function temp_filename() {
-               $tmp_dir = '';
-               $dirs    = array( 'TMP', 'TMPDIR', 'TEMP' );
-               foreach ( $dirs as $dir ) {
-                       if ( isset( $_ENV[ $dir ] ) && ! empty( $_ENV[ $dir ] ) ) {
-                               $tmp_dir = $dir;
-                               break;
-                       }
-               }
-               if ( empty( $tmp_dir ) ) {
-                       $tmp_dir = '/tmp';
-               }
-               $tmp_dir = realpath( $tmp_dir );
-               return tempnam( $tmp_dir, 'wpunit' );
-       }
-
-       /**
-        * Checks each of the WP_Query is_* functions/properties against expected boolean value.
-        *
-        * Any properties that are listed by name as parameters will be expected to be true; all others are
-        * expected to be false. For example, assertQueryTrue('is_single', 'is_feed') means is_single()
-        * and is_feed() must be true and everything else must be false to pass.
-        *
-        * @since 2.5.0
-        * @since 3.8.0 Moved from `Tests_Query_Conditionals` to `WP_UnitTestCase`.
-        *
-        * @param string $prop,... Any number of WP_Query properties that are expected to be true for the current request.
-        */
-       function assertQueryTrue() {
-               global $wp_query;
-               $all  = array(
-                       'is_404',
-                       'is_admin',
-                       'is_archive',
-                       'is_attachment',
-                       'is_author',
-                       'is_category',
-                       'is_comment_feed',
-                       'is_date',
-                       'is_day',
-                       'is_embed',
-                       'is_feed',
-                       'is_front_page',
-                       'is_home',
-                       'is_month',
-                       'is_page',
-                       'is_paged',
-                       'is_post_type_archive',
-                       'is_posts_page',
-                       'is_preview',
-                       'is_robots',
-                       'is_search',
-                       'is_single',
-                       'is_singular',
-                       'is_tag',
-                       'is_tax',
-                       'is_time',
-                       'is_trackback',
-                       'is_year',
-               );
-               $true = func_get_args();
-
-               foreach ( $true as $true_thing ) {
-                       $this->assertContains( $true_thing, $all, "Unknown conditional: {$true_thing}." );
-               }
-
-               $passed  = true;
-               $message = '';
-
-               foreach ( $all as $query_thing ) {
-                       $result = is_callable( $query_thing ) ? call_user_func( $query_thing ) : $wp_query->$query_thing;
-
-                       if ( in_array( $query_thing, $true ) ) {
-                               if ( ! $result ) {
-                                       $message .= $query_thing . ' is false but is expected to be true. ' . PHP_EOL;
-                                       $passed   = false;
-                               }
-                       } elseif ( $result ) {
-                               $message .= $query_thing . ' is true but is expected to be false. ' . PHP_EOL;
-                               $passed   = false;
-                       }
-               }
-
-               if ( ! $passed ) {
-                       $this->fail( $message );
-               }
-       }
-
-       /**
-        * Selectively deletes a file.
-        *
-        * Does not delete a file if its path is set in the `$ignore_files` property.
-        *
-        * @param string $file File path.
-        */
-       function unlink( $file ) {
-               $exists = is_file( $file );
-               if ( $exists && ! in_array( $file, self::$ignore_files ) ) {
-                       //error_log( $file );
-                       unlink( $file );
-               } elseif ( ! $exists ) {
-                       $this->fail( "Trying to delete a file that doesn't exist: $file" );
-               }
-       }
-
-       /**
-        * Selectively deletes files from a directory.
-        *
-        * Does not delete files if their paths are set in the `$ignore_files` property.
-        *
-        * @param string $path Directory path.
-        */
-       function rmdir( $path ) {
-               $files = $this->files_in_dir( $path );
-               foreach ( $files as $file ) {
-                       if ( ! in_array( $file, self::$ignore_files ) ) {
-                               $this->unlink( $file );
-                       }
-               }
-       }
-
-       /**
-        * Deletes files added to the `uploads` directory during tests.
-        *
-        * This method works in tandem with the `setUp()` and `rmdir()` methods:
-        * - `setUp()` scans the `uploads` directory before every test, and stores its contents inside of the
-        *   `$ignore_files` property.
-        * - `rmdir()` and its helper methods only delete files that are not listed in the `$ignore_files` property. If
-        *   called during `tearDown()` in tests, this will only delete files added during the previously run test.
-        */
-       function remove_added_uploads() {
-               $uploads = wp_upload_dir();
-               $this->rmdir( $uploads['basedir'] );
-       }
-
-       /**
-        * Returns a list of all files contained inside a directory.
-        *
-        * @since 4.0.0
-        *
-        * @param string $dir Path to the directory to scan.
-        *
-        * @return array List of file paths.
-        */
-       function files_in_dir( $dir ) {
-               $files = array();
-
-               $iterator = new RecursiveDirectoryIterator( $dir );
-               $objects  = new RecursiveIteratorIterator( $iterator );
-               foreach ( $objects as $name => $object ) {
-                       if ( is_file( $name ) ) {
-                               $files[] = $name;
-                       }
-               }
-
-               return $files;
-       }
-
-       /**
-        * Returns a list of all files contained inside the `uploads` directory.
-        *
-        * @since 4.0.0
-        *
-        * @return array List of file paths.
-        */
-       function scan_user_uploads() {
-               static $files = array();
-               if ( ! empty( $files ) ) {
-                       return $files;
-               }
-
-               $uploads = wp_upload_dir();
-               $files   = $this->files_in_dir( $uploads['basedir'] );
-               return $files;
-       }
-
-       /**
-        * Deletes all directories contained inside a directory.
-        *
-        * @since 4.1.0
-        *
-        * @param string $path Path to the directory to scan.
-        */
-       function delete_folders( $path ) {
-               $this->matched_dirs = array();
-               if ( ! is_dir( $path ) ) {
-                       return;
-               }
-
-               $this->scandir( $path );
-               foreach ( array_reverse( $this->matched_dirs ) as $dir ) {
-                       rmdir( $dir );
-               }
-               rmdir( $path );
-       }
-
-       /**
-        * Retrieves all directories contained inside a directory and stores them in the `$matched_dirs` property. Hidden
-        * directories are ignored.
-        *
-        * This is a helper for the `delete_folders()` method.
-        *
-        * @since 4.1.0
-        *
-        * @param string $dir Path to the directory to scan.
-        */
-       function scandir( $dir ) {
-               foreach ( scandir( $dir ) as $path ) {
-                       if ( 0 !== strpos( $path, '.' ) && is_dir( $dir . '/' . $path ) ) {
-                               $this->matched_dirs[] = $dir . '/' . $path;
-                               $this->scandir( $dir . '/' . $path );
-                       }
-               }
-       }
-
-       /**
-        * Converts a microtime string into a float.
-        *
-        * @since 4.1.0
-        *
-        * @param string $microtime Time string generated by `microtime()`.
-        *
-        * @return float `microtime()` output as a float.
-        */
-       protected function _microtime_to_float( $microtime ) {
-               $time_array = explode( ' ', $microtime );
-               return array_sum( $time_array );
-       }
-
-       /**
-        * Deletes a user from the database in a Multisite-agnostic way.
-        *
-        * @since 4.3.0
-        *
-        * @param int $user_id User ID.
-        *
-        * @return bool True if the user was deleted.
-        */
-       public static function delete_user( $user_id ) {
-               if ( is_multisite() ) {
-                       return wpmu_delete_user( $user_id );
-               } else {
-                       return wp_delete_user( $user_id );
-               }
-       }
-
-       /**
-        * Resets permalinks and flushes rewrites.
-        *
-        * @since 4.4.0
-        *
-        * @global WP_Rewrite $wp_rewrite
-        *
-        * @param string $structure Optional. Permalink structure to set. Default empty.
-        */
-       public function set_permalink_structure( $structure = '' ) {
-               global $wp_rewrite;
-
-               $wp_rewrite->init();
-               $wp_rewrite->set_permalink_structure( $structure );
-               $wp_rewrite->flush_rules();
-       }
-
-       /**
-        * Creates an attachment post from an uploaded file.
-        *
-        * @since 4.4.0
-        *
-        * @param array $upload         Array of information about the uploaded file, provided by wp_upload_bits().
-        * @param int   $parent_post_id Optional. Parent post ID.
-        *
-        * @return int|WP_Error The attachment ID on success. The value 0 or WP_Error on failure.
-        */
-       function _make_attachment( $upload, $parent_post_id = 0 ) {
-               $type = '';
-               if ( ! empty( $upload['type'] ) ) {
-                       $type = $upload['type'];
-               } else {
-                       $mime = wp_check_filetype( $upload['file'] );
-                       if ( $mime ) {
-                               $type = $mime['type'];
-                       }
-               }
-
-               $attachment = array(
-                       'post_title'     => basename( $upload['file'] ),
-                       'post_content'   => '',
-                       'post_type'      => 'attachment',
-                       'post_parent'    => $parent_post_id,
-                       'post_mime_type' => $type,
-                       'guid'           => $upload['url'],
-               );
-
-               $id = wp_insert_attachment( $attachment, $upload['file'], $parent_post_id );
-               wp_update_attachment_metadata( $id, wp_generate_attachment_metadata( $id, $upload['file'] ) );
-               return $id;
-       }
-
-       /**
-        * Updates the modified and modified GMT date of a post in the database.
-        *
-        * @since 4.8.0
-        *
-        * @global wpdb $wpdb WordPress database abstraction object.
-        *
-        * @param int    $post_id Post ID.
-        * @param string $date    Post date, in the format YYYY-MM-DD HH:MM:SS.
-        *
-        * @return int|false 1 on success, or false on error.
-        */
-       protected function update_post_modified( $post_id, $date ) {
-               global $wpdb;
-               return $wpdb->update(
-                       $wpdb->posts,
-                       array(
-                               'post_modified'     => $date,
-                               'post_modified_gmt' => $date,
-                       ),
-                       array(
-                               'ID' => $post_id,
-                       ),
-                       array(
-                               '%s',
-                               '%s',
-                       ),
-                       array(
-                               '%d',
-                       )
-               );
-       }
</del><span class="cx" style="display: block; padding: 0 10px"> }
</span></span></pre></div>
<a id="trunktestsphpunitmultisitexml"></a>
<div class="modfile"><h4 style="background-color: #eee; color: inherit; margin: 1em 0; padding: 1.3em; font-size: 115%">Modified: trunk/tests/phpunit/multisite.xml</h4>
<pre class="diff"><span>
<span class="info" style="display: block; padding: 0 10px; color: #888">--- trunk/tests/phpunit/multisite.xml 2019-01-27 14:45:42 UTC (rev 44700)
+++ trunk/tests/phpunit/multisite.xml   2019-01-28 14:10:24 UTC (rev 44701)
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -45,7 +45,7 @@
</span><span class="cx" style="display: block; padding: 0 10px">         <const name="WP_RUN_CORE_TESTS" value="1" />
</span><span class="cx" style="display: block; padding: 0 10px">     </php>
</span><span class="cx" style="display: block; padding: 0 10px">     <listeners>
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-        <listener class="SpeedTrapListener" file="tests/phpunit/includes/speed-trap-listener.php">
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+        <listener class="SpeedTrapListener" file="tests/phpunit/includes/listener-loader.php">
</ins><span class="cx" style="display: block; padding: 0 10px">             <arguments>
</span><span class="cx" style="display: block; padding: 0 10px">                 <array>
</span><span class="cx" style="display: block; padding: 0 10px">                     <element key="slowThreshold">
</span></span></pre></div>
<a id="trunktestsphpunittestspostqueryphp"></a>
<div class="modfile"><h4 style="background-color: #eee; color: inherit; margin: 1em 0; padding: 1.3em; font-size: 115%">Modified: trunk/tests/phpunit/tests/post/query.php</h4>
<pre class="diff"><span>
<span class="info" style="display: block; padding: 0 10px; color: #888">--- trunk/tests/phpunit/tests/post/query.php  2019-01-27 14:45:42 UTC (rev 44700)
+++ trunk/tests/phpunit/tests/post/query.php    2019-01-28 14:10:24 UTC (rev 44701)
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -719,7 +719,7 @@
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px">                $q->posts = $posts;
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-                $methd = new \ReflectionMethod( 'WP_Query', 'set_found_posts' );
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+         $methd = new ReflectionMethod( 'WP_Query', 'set_found_posts' );
</ins><span class="cx" style="display: block; padding: 0 10px">                 $methd->setAccessible( true );
</span><span class="cx" style="display: block; padding: 0 10px">                $methd->invoke( $q, array( 'no_found_rows' => false ), array() );
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span></span></pre>
</div>
</div>

</body>
</html>