Make WordPress Core

Ticket #43218: 43218.3.diff

File 43218.3.diff, 95.5 KB (added by SergeyBiryukov, 8 years ago)
  • phpunit.xml.dist

     
    1 <phpunit
    2         bootstrap="tests/phpunit/includes/bootstrap.php"
    3         backupGlobals="false"
    4         colors="true"
    5         beStrictAboutTestsThatDoNotTestAnything="true"
    6         >
    7     <testsuites>
    8         <!-- Default test suite to run all tests -->
    9         <testsuite>
    10             <directory suffix=".php">tests/phpunit/tests</directory>
    11             <exclude>tests/phpunit/tests/actions/closures.php</exclude>
    12             <exclude>tests/phpunit/tests/image/editor.php</exclude>
    13             <exclude>tests/phpunit/tests/image/editorGd.php</exclude>
    14             <exclude>tests/phpunit/tests/image/editorImagick.php</exclude>
    15             <exclude>tests/phpunit/tests/oembed/headers.php</exclude>
    16             <file phpVersion="5.3.0">tests/phpunit/tests/actions/closures.php</file>
    17             <file phpVersion="5.3.0">tests/phpunit/tests/image/editor.php</file>
    18             <file phpVersion="5.3.0">tests/phpunit/tests/image/editorGd.php</file>
    19             <file phpVersion="5.3.0">tests/phpunit/tests/image/editorImagick.php</file>
    20             <file phpVersion="5.3.0">tests/phpunit/tests/oembed/headers.php</file>
    21         </testsuite>
    22     </testsuites>
    23     <groups>
    24         <exclude>
    25             <group>ajax</group>
    26             <group>ms-files</group>
    27             <group>ms-required</group>
    28             <group>external-http</group>
    29         </exclude>
    30     </groups>
    31     <logging>
    32         <log type="junit" target="tests/phpunit/build/logs/junit.xml" logIncompleteSkipped="false"/>
    33     </logging>
    34     <php>
    35         <const name="WP_RUN_CORE_TESTS" value="1" />
    36     </php>
    37         <listeners>
    38                 <listener class="SpeedTrapListener" file="tests/phpunit/includes/speed-trap-listener.php">
    39                         <arguments>
    40                                 <array>
    41                                         <element key="slowThreshold">
    42                                                 <integer>150</integer>
    43                                         </element>
    44                                 </array>
    45                         </arguments>
    46                 </listener>
    47         </listeners>
    48         <filter>
    49                 <whitelist addUncoveredFilesFromWhitelist="true">
    50                         <directory suffix=".php">src</directory>
    51                         <exclude>
    52                                 <!-- Third party library exclusions -->
    53                                 <file>src/wp-admin/includes/class-ftp*</file>
    54                                 <file>src/wp-admin/includes/class-pclzip.php</file>
    55                                 <file>src/wp-admin/includes/deprecated.php</file>
    56                                 <file>src/wp-admin/includes/ms-deprecated.php</file>
    57 
    58                                 <file>src/wp-includes/atomlib.php</file>
    59                                 <file>src/wp-includes/class-IXR.php</file>
    60                                 <file>src/wp-includes/class-json.php</file>
    61                                 <file>src/wp-includes/class-phpass.php</file>
    62                                 <file>src/wp-includes/class-phpmailer.php</file>
    63                                 <file>src/wp-includes/class-pop3.php</file>
    64                                 <file>src/wp-includes/class-requests.php</file>
    65                                 <file>src/wp-includes/class-simplepie.php</file>
    66                                 <file>src/wp-includes/class-smtp.php</file>
    67                                 <file>src/wp-includes/class-snoopy.php</file>
    68                                 <file>src/wp-includes/deprecated.php</file>
    69                                 <file>src/wp-includes/ms-deprecated.php</file>
    70                                 <file>src/wp-includes/pluggable-deprecated.php</file>
    71                                 <file>src/wp-includes/rss.php</file>
    72 
    73                                 <directory suffix=".php">src/wp-includes/ID3</directory>
    74                                 <directory suffix=".php">src/wp-includes/IXR</directory>
    75                                 <directory suffix=".php">src/wp-includes/random_compat</directory>
    76                                 <directory suffix=".php">src/wp-includes/Requests</directory>
    77                                 <directory suffix=".php">src/wp-includes/SimplePie</directory>
    78                                 <directory suffix=".php">src/wp-includes/Text</directory>
    79                         </exclude>
    80                 </whitelist>
    81         </filter>
    82 </phpunit>
     1<phpunit
     2        bootstrap="tests/phpunit/includes/bootstrap.php"
     3        backupGlobals="false"
     4        colors="true"
     5        beStrictAboutTestsThatDoNotTestAnything="true"
     6        >
     7    <testsuites>
     8        <!-- Default test suite to run all tests -->
     9        <testsuite>
     10            <directory suffix=".php">tests/phpunit/tests</directory>
     11            <exclude>tests/phpunit/tests/actions/closures.php</exclude>
     12            <exclude>tests/phpunit/tests/image/editor.php</exclude>
     13            <exclude>tests/phpunit/tests/image/editorGd.php</exclude>
     14            <exclude>tests/phpunit/tests/image/editorImagick.php</exclude>
     15            <exclude>tests/phpunit/tests/oembed/headers.php</exclude>
     16            <file phpVersion="5.3.0">tests/phpunit/tests/actions/closures.php</file>
     17            <file phpVersion="5.3.0">tests/phpunit/tests/image/editor.php</file>
     18            <file phpVersion="5.3.0">tests/phpunit/tests/image/editorGd.php</file>
     19            <file phpVersion="5.3.0">tests/phpunit/tests/image/editorImagick.php</file>
     20            <file phpVersion="5.3.0">tests/phpunit/tests/oembed/headers.php</file>
     21        </testsuite>
     22    </testsuites>
     23    <groups>
     24        <exclude>
     25            <group>ajax</group>
     26            <group>ms-files</group>
     27            <group>ms-required</group>
     28            <group>external-http</group>
     29        </exclude>
     30    </groups>
     31    <logging>
     32        <log type="junit" target="tests/phpunit/build/logs/junit.xml" logIncompleteSkipped="false"/>
     33    </logging>
     34    <php>
     35        <const name="WP_RUN_CORE_TESTS" value="1" />
     36    </php>
     37        <listeners>
     38                <listener class="SpeedTrapListener" file="tests/phpunit/includes/listener-loader.php">
     39                        <arguments>
     40                                <array>
     41                                        <element key="slowThreshold">
     42                                                <integer>150</integer>
     43                                        </element>
     44                                </array>
     45                        </arguments>
     46                </listener>
     47        </listeners>
     48        <filter>
     49                <whitelist addUncoveredFilesFromWhitelist="true">
     50                        <directory suffix=".php">src</directory>
     51                        <exclude>
     52                                <!-- Third party library exclusions -->
     53                                <file>src/wp-admin/includes/class-ftp*</file>
     54                                <file>src/wp-admin/includes/class-pclzip.php</file>
     55                                <file>src/wp-admin/includes/deprecated.php</file>
     56                                <file>src/wp-admin/includes/ms-deprecated.php</file>
     57
     58                                <file>src/wp-includes/atomlib.php</file>
     59                                <file>src/wp-includes/class-IXR.php</file>
     60                                <file>src/wp-includes/class-json.php</file>
     61                                <file>src/wp-includes/class-phpass.php</file>
     62                                <file>src/wp-includes/class-phpmailer.php</file>
     63                                <file>src/wp-includes/class-pop3.php</file>
     64                                <file>src/wp-includes/class-requests.php</file>
     65                                <file>src/wp-includes/class-simplepie.php</file>
     66                                <file>src/wp-includes/class-smtp.php</file>
     67                                <file>src/wp-includes/class-snoopy.php</file>
     68                                <file>src/wp-includes/deprecated.php</file>
     69                                <file>src/wp-includes/ms-deprecated.php</file>
     70                                <file>src/wp-includes/pluggable-deprecated.php</file>
     71                                <file>src/wp-includes/rss.php</file>
     72
     73                                <directory suffix=".php">src/wp-includes/ID3</directory>
     74                                <directory suffix=".php">src/wp-includes/IXR</directory>
     75                                <directory suffix=".php">src/wp-includes/random_compat</directory>
     76                                <directory suffix=".php">src/wp-includes/Requests</directory>
     77                                <directory suffix=".php">src/wp-includes/SimplePie</directory>
     78                                <directory suffix=".php">src/wp-includes/Text</directory>
     79                        </exclude>
     80                </whitelist>
     81        </filter>
     82</phpunit>
  • tests/phpunit/includes/abstract-testcase.php

     
     1<?php
     2
     3require_once dirname( __FILE__ ) . '/factory.php';
     4require_once dirname( __FILE__ ) . '/trac.php';
     5
     6/**
     7 * Defines a basic fixture to run multiple tests.
     8 *
     9 * Resets the state of the WordPress installation before and after every test.
     10 *
     11 * Includes utility functions and assertions useful for testing WordPress.
     12 *
     13 * All WordPress unit tests should inherit from this class.
     14 */
     15abstract class WP_UnitTestCase_Base extends PHPUnit_Framework_TestCase {
     16
     17        protected static $forced_tickets   = array();
     18        protected $expected_deprecated     = array();
     19        protected $caught_deprecated       = array();
     20        protected $expected_doing_it_wrong = array();
     21        protected $caught_doing_it_wrong   = array();
     22
     23        protected static $hooks_saved = array();
     24        protected static $ignore_files;
     25
     26        function __isset( $name ) {
     27                return 'factory' === $name;
     28        }
     29
     30        function __get( $name ) {
     31                if ( 'factory' === $name ) {
     32                        return self::factory();
     33                }
     34        }
     35
     36        /**
     37         * Fetches the factory object for generating WordPress fixtures.
     38         *
     39         * @return WP_UnitTest_Factory The fixture factory.
     40         */
     41        protected static function factory() {
     42                static $factory = null;
     43                if ( ! $factory ) {
     44                        $factory = new WP_UnitTest_Factory();
     45                }
     46                return $factory;
     47        }
     48
     49        public static function get_called_class() {
     50                if ( function_exists( 'get_called_class' ) ) {
     51                        return get_called_class();
     52                }
     53
     54                // PHP 5.2 only
     55                $backtrace = debug_backtrace();
     56                // [0] WP_UnitTestCase::get_called_class()
     57                // [1] WP_UnitTestCase::setUpBeforeClass()
     58                if ( 'call_user_func' === $backtrace[2]['function'] ) {
     59                        return $backtrace[2]['args'][0][0];
     60                }
     61                return $backtrace[2]['class'];
     62        }
     63
     64        public static function setUpBeforeClass() {
     65                global $wpdb;
     66
     67                $wpdb->suppress_errors = false;
     68                $wpdb->show_errors     = true;
     69                $wpdb->db_connect();
     70                ini_set( 'display_errors', 1 );
     71
     72                parent::setUpBeforeClass();
     73
     74                $c = self::get_called_class();
     75                if ( ! method_exists( $c, 'wpSetUpBeforeClass' ) ) {
     76                        self::commit_transaction();
     77                        return;
     78                }
     79
     80                call_user_func( array( $c, 'wpSetUpBeforeClass' ), self::factory() );
     81
     82                self::commit_transaction();
     83        }
     84
     85        public static function tearDownAfterClass() {
     86                parent::tearDownAfterClass();
     87
     88                _delete_all_data();
     89                self::flush_cache();
     90
     91                $c = self::get_called_class();
     92                if ( ! method_exists( $c, 'wpTearDownAfterClass' ) ) {
     93                        self::commit_transaction();
     94                        return;
     95                }
     96
     97                call_user_func( array( $c, 'wpTearDownAfterClass' ) );
     98
     99                self::commit_transaction();
     100        }
     101
     102        function setUp() {
     103                set_time_limit( 0 );
     104
     105                if ( ! self::$ignore_files ) {
     106                        self::$ignore_files = $this->scan_user_uploads();
     107                }
     108
     109                if ( ! self::$hooks_saved ) {
     110                        $this->_backup_hooks();
     111                }
     112
     113                global $wp_rewrite;
     114
     115                $this->clean_up_global_scope();
     116
     117                /*
     118                 * When running core tests, ensure that post types and taxonomies
     119                 * are reset for each test. We skip this step for non-core tests,
     120                 * given the large number of plugins that register post types and
     121                 * taxonomies at 'init'.
     122                 */
     123                if ( defined( 'WP_RUN_CORE_TESTS' ) && WP_RUN_CORE_TESTS ) {
     124                        $this->reset_post_types();
     125                        $this->reset_taxonomies();
     126                        $this->reset_post_statuses();
     127                        $this->reset__SERVER();
     128
     129                        if ( $wp_rewrite->permalink_structure ) {
     130                                $this->set_permalink_structure( '' );
     131                        }
     132                }
     133
     134                $this->start_transaction();
     135                $this->expectDeprecated();
     136                add_filter( 'wp_die_handler', array( $this, 'get_wp_die_handler' ) );
     137        }
     138
     139        /**
     140         * Detect post-test failure conditions.
     141         *
     142         * We use this method to detect expectedDeprecated and expectedIncorrectUsage annotations.
     143         *
     144         * @since 4.2.0
     145         */
     146        protected function assertPostConditions() {
     147                $this->expectedDeprecated();
     148        }
     149
     150        /**
     151         * After a test method runs, reset any state in WordPress the test method might have changed.
     152         */
     153        function tearDown() {
     154                global $wpdb, $wp_query, $wp;
     155                $wpdb->query( 'ROLLBACK' );
     156                if ( is_multisite() ) {
     157                        while ( ms_is_switched() ) {
     158                                restore_current_blog();
     159                        }
     160                }
     161                $wp_query = new WP_Query();
     162                $wp       = new WP();
     163
     164                // Reset globals related to the post loop and `setup_postdata()`.
     165                $post_globals = array( 'post', 'id', 'authordata', 'currentday', 'currentmonth', 'page', 'pages', 'multipage', 'more', 'numpages' );
     166                foreach ( $post_globals as $global ) {
     167                        $GLOBALS[ $global ] = null;
     168                }
     169
     170                remove_theme_support( 'html5' );
     171                remove_filter( 'query', array( $this, '_create_temporary_tables' ) );
     172                remove_filter( 'query', array( $this, '_drop_temporary_tables' ) );
     173                remove_filter( 'wp_die_handler', array( $this, 'get_wp_die_handler' ) );
     174                $this->_restore_hooks();
     175                wp_set_current_user( 0 );
     176        }
     177
     178        function clean_up_global_scope() {
     179                $_GET  = array();
     180                $_POST = array();
     181                self::flush_cache();
     182        }
     183
     184        /**
     185         * Allow tests to be skipped on some automated runs
     186         *
     187         * For test runs on Travis for something other than trunk/master
     188         * we want to skip tests that only need to run for master.
     189         */
     190        public function skipOnAutomatedBranches() {
     191                // gentenv can be disabled
     192                if ( ! function_exists( 'getenv' ) ) {
     193                        return false;
     194                }
     195
     196                // https://docs.travis-ci.com/user/environment-variables/#Default-Environment-Variables
     197                $travis_branch       = getenv( 'TRAVIS_BRANCH' );
     198                $travis_pull_request = getenv( 'TRAVIS_PULL_REQUEST' );
     199
     200                if ( false !== $travis_pull_request && 'master' !== $travis_branch ) {
     201                        $this->markTestSkipped( 'For automated test runs, this test is only run on trunk/master' );
     202                }
     203        }
     204
     205        /**
     206         * Allow tests to be skipped when Multisite is not in use.
     207         *
     208         * Use in conjunction with the ms-required group.
     209         */
     210        public function skipWithoutMultisite() {
     211                if ( ! is_multisite() ) {
     212                        $this->markTestSkipped( 'Test only runs on Multisite' );
     213                }
     214        }
     215
     216        /**
     217         * Allow tests to be skipped when Multisite is in use.
     218         *
     219         * Use in conjunction with the ms-excluded group.
     220         */
     221        public function skipWithMultisite() {
     222                if ( is_multisite() ) {
     223                        $this->markTestSkipped( 'Test does not run on Multisite' );
     224                }
     225        }
     226
     227        /**
     228         * Unregister existing post types and register defaults.
     229         *
     230         * Run before each test in order to clean up the global scope, in case
     231         * a test forgets to unregister a post type on its own, or fails before
     232         * it has a chance to do so.
     233         */
     234        protected function reset_post_types() {
     235                foreach ( get_post_types( array(), 'objects' ) as $pt ) {
     236                        if ( empty( $pt->tests_no_auto_unregister ) ) {
     237                                _unregister_post_type( $pt->name );
     238                        }
     239                }
     240                create_initial_post_types();
     241        }
     242
     243        /**
     244         * Unregister existing taxonomies and register defaults.
     245         *
     246         * Run before each test in order to clean up the global scope, in case
     247         * a test forgets to unregister a taxonomy on its own, or fails before
     248         * it has a chance to do so.
     249         */
     250        protected function reset_taxonomies() {
     251                foreach ( get_taxonomies() as $tax ) {
     252                        _unregister_taxonomy( $tax );
     253                }
     254                create_initial_taxonomies();
     255        }
     256
     257        /**
     258         * Unregister non-built-in post statuses.
     259         */
     260        protected function reset_post_statuses() {
     261                foreach ( get_post_stati( array( '_builtin' => false ) ) as $post_status ) {
     262                        _unregister_post_status( $post_status );
     263                }
     264        }
     265
     266        /**
     267         * Reset `$_SERVER` variables
     268         */
     269        protected function reset__SERVER() {
     270                tests_reset__SERVER();
     271        }
     272
     273        /**
     274         * Saves the action and filter-related globals so they can be restored later.
     275         *
     276         * Stores $merged_filters, $wp_actions, $wp_current_filter, and $wp_filter
     277         * on a class variable so they can be restored on tearDown() using _restore_hooks().
     278         *
     279         * @global array $merged_filters
     280         * @global array $wp_actions
     281         * @global array $wp_current_filter
     282         * @global array $wp_filter
     283         * @return void
     284         */
     285        protected function _backup_hooks() {
     286                $globals = array( 'wp_actions', 'wp_current_filter' );
     287                foreach ( $globals as $key ) {
     288                        self::$hooks_saved[ $key ] = $GLOBALS[ $key ];
     289                }
     290                self::$hooks_saved['wp_filter'] = array();
     291                foreach ( $GLOBALS['wp_filter'] as $hook_name => $hook_object ) {
     292                        self::$hooks_saved['wp_filter'][ $hook_name ] = clone $hook_object;
     293                }
     294        }
     295
     296        /**
     297         * Restores the hook-related globals to their state at setUp()
     298         * so that future tests aren't affected by hooks set during this last test.
     299         *
     300         * @global array $merged_filters
     301         * @global array $wp_actions
     302         * @global array $wp_current_filter
     303         * @global array $wp_filter
     304         * @return void
     305         */
     306        protected function _restore_hooks() {
     307                $globals = array( 'wp_actions', 'wp_current_filter' );
     308                foreach ( $globals as $key ) {
     309                        if ( isset( self::$hooks_saved[ $key ] ) ) {
     310                                $GLOBALS[ $key ] = self::$hooks_saved[ $key ];
     311                        }
     312                }
     313                if ( isset( self::$hooks_saved['wp_filter'] ) ) {
     314                        $GLOBALS['wp_filter'] = array();
     315                        foreach ( self::$hooks_saved['wp_filter'] as $hook_name => $hook_object ) {
     316                                $GLOBALS['wp_filter'][ $hook_name ] = clone $hook_object;
     317                        }
     318                }
     319        }
     320
     321        static function flush_cache() {
     322                global $wp_object_cache;
     323                $wp_object_cache->group_ops      = array();
     324                $wp_object_cache->stats          = array();
     325                $wp_object_cache->memcache_debug = array();
     326                $wp_object_cache->cache          = array();
     327                if ( method_exists( $wp_object_cache, '__remoteset' ) ) {
     328                        $wp_object_cache->__remoteset();
     329                }
     330                wp_cache_flush();
     331                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' ) );
     332                wp_cache_add_non_persistent_groups( array( 'comment', 'counts', 'plugins' ) );
     333        }
     334
     335        function start_transaction() {
     336                global $wpdb;
     337                $wpdb->query( 'SET autocommit = 0;' );
     338                $wpdb->query( 'START TRANSACTION;' );
     339                add_filter( 'query', array( $this, '_create_temporary_tables' ) );
     340                add_filter( 'query', array( $this, '_drop_temporary_tables' ) );
     341        }
     342
     343        /**
     344         * Commit the queries in a transaction.
     345         *
     346         * @since 4.1.0
     347         */
     348        public static function commit_transaction() {
     349                global $wpdb;
     350                $wpdb->query( 'COMMIT;' );
     351        }
     352
     353        function _create_temporary_tables( $query ) {
     354                if ( 'CREATE TABLE' === substr( trim( $query ), 0, 12 ) ) {
     355                        return substr_replace( trim( $query ), 'CREATE TEMPORARY TABLE', 0, 12 );
     356                }
     357                return $query;
     358        }
     359
     360        function _drop_temporary_tables( $query ) {
     361                if ( 'DROP TABLE' === substr( trim( $query ), 0, 10 ) ) {
     362                        return substr_replace( trim( $query ), 'DROP TEMPORARY TABLE', 0, 10 );
     363                }
     364                return $query;
     365        }
     366
     367        function get_wp_die_handler( $handler ) {
     368                return array( $this, 'wp_die_handler' );
     369        }
     370
     371        function wp_die_handler( $message ) {
     372                if ( ! is_scalar( $message ) ) {
     373                        $message = '0';
     374                }
     375
     376                throw new WPDieException( $message );
     377        }
     378
     379        function expectDeprecated() {
     380                $annotations = $this->getAnnotations();
     381                foreach ( array( 'class', 'method' ) as $depth ) {
     382                        if ( ! empty( $annotations[ $depth ]['expectedDeprecated'] ) ) {
     383                                $this->expected_deprecated = array_merge( $this->expected_deprecated, $annotations[ $depth ]['expectedDeprecated'] );
     384                        }
     385                        if ( ! empty( $annotations[ $depth ]['expectedIncorrectUsage'] ) ) {
     386                                $this->expected_doing_it_wrong = array_merge( $this->expected_doing_it_wrong, $annotations[ $depth ]['expectedIncorrectUsage'] );
     387                        }
     388                }
     389                add_action( 'deprecated_function_run', array( $this, 'deprecated_function_run' ) );
     390                add_action( 'deprecated_argument_run', array( $this, 'deprecated_function_run' ) );
     391                add_action( 'deprecated_hook_run', array( $this, 'deprecated_function_run' ) );
     392                add_action( 'doing_it_wrong_run', array( $this, 'doing_it_wrong_run' ) );
     393                add_action( 'deprecated_function_trigger_error', '__return_false' );
     394                add_action( 'deprecated_argument_trigger_error', '__return_false' );
     395                add_action( 'deprecated_hook_trigger_error', '__return_false' );
     396                add_action( 'doing_it_wrong_trigger_error', '__return_false' );
     397        }
     398
     399        function expectedDeprecated() {
     400                $errors = array();
     401
     402                $not_caught_deprecated = array_diff( $this->expected_deprecated, $this->caught_deprecated );
     403                foreach ( $not_caught_deprecated as $not_caught ) {
     404                        $errors[] = "Failed to assert that $not_caught triggered a deprecated notice";
     405                }
     406
     407                $unexpected_deprecated = array_diff( $this->caught_deprecated, $this->expected_deprecated );
     408                foreach ( $unexpected_deprecated as $unexpected ) {
     409                        $errors[] = "Unexpected deprecated notice for $unexpected";
     410                }
     411
     412                $not_caught_doing_it_wrong = array_diff( $this->expected_doing_it_wrong, $this->caught_doing_it_wrong );
     413                foreach ( $not_caught_doing_it_wrong as $not_caught ) {
     414                        $errors[] = "Failed to assert that $not_caught triggered an incorrect usage notice";
     415                }
     416
     417                $unexpected_doing_it_wrong = array_diff( $this->caught_doing_it_wrong, $this->expected_doing_it_wrong );
     418                foreach ( $unexpected_doing_it_wrong as $unexpected ) {
     419                        $errors[] = "Unexpected incorrect usage notice for $unexpected";
     420                }
     421
     422                // Perform an assertion, but only if there are expected or unexpected deprecated calls or wrongdoings
     423                if ( ! empty( $this->expected_deprecated ) ||
     424                     ! empty( $this->expected_doing_it_wrong ) ||
     425                     ! empty( $this->caught_deprecated ) ||
     426                     ! empty( $this->caught_doing_it_wrong ) ) {
     427                        $this->assertEmpty( $errors, implode( "\n", $errors ) );
     428                }
     429        }
     430
     431        /**
     432         * Declare an expected `_deprecated_function()` or `_deprecated_argument()` call from within a test.
     433         *
     434         * @since 4.2.0
     435         *
     436         * @param string $deprecated Name of the function, method, class, or argument that is deprecated. Must match
     437         *                           first parameter of the `_deprecated_function()` or `_deprecated_argument()` call.
     438         */
     439        public function setExpectedDeprecated( $deprecated ) {
     440                array_push( $this->expected_deprecated, $deprecated );
     441        }
     442
     443        /**
     444         * Declare an expected `_doing_it_wrong()` call from within a test.
     445         *
     446         * @since 4.2.0
     447         *
     448         * @param string $deprecated Name of the function, method, or class that appears in the first argument of the
     449         *                           source `_doing_it_wrong()` call.
     450         */
     451        public function setExpectedIncorrectUsage( $doing_it_wrong ) {
     452                array_push( $this->expected_doing_it_wrong, $doing_it_wrong );
     453        }
     454
     455        /**
     456         * PHPUnit 6+ compatibility shim.
     457         *
     458         * @param mixed      $exception
     459         * @param string     $message
     460         * @param int|string $code
     461         */
     462        public function setExpectedException( $exception, $message = '', $code = null ) {
     463                if ( method_exists( 'PHPUnit_Framework_TestCase', 'setExpectedException' ) ) {
     464                        parent::setExpectedException( $exception, $message, $code );
     465                } else {
     466                        $this->expectException( $exception );
     467                        if ( '' !== $message ) {
     468                                $this->expectExceptionMessage( $message );
     469                        }
     470                        if ( null !== $code ) {
     471                                $this->expectExceptionCode( $code );
     472                        }
     473                }
     474        }
     475
     476        function deprecated_function_run( $function ) {
     477                if ( ! in_array( $function, $this->caught_deprecated ) ) {
     478                        $this->caught_deprecated[] = $function;
     479                }
     480        }
     481
     482        function doing_it_wrong_run( $function ) {
     483                if ( ! in_array( $function, $this->caught_doing_it_wrong ) ) {
     484                        $this->caught_doing_it_wrong[] = $function;
     485                }
     486        }
     487
     488        function assertWPError( $actual, $message = '' ) {
     489                $this->assertInstanceOf( 'WP_Error', $actual, $message );
     490        }
     491
     492        function assertNotWPError( $actual, $message = '' ) {
     493                if ( is_wp_error( $actual ) && '' === $message ) {
     494                        $message = $actual->get_error_message();
     495                }
     496                $this->assertNotInstanceOf( 'WP_Error', $actual, $message );
     497        }
     498
     499        function assertIXRError( $actual, $message = '' ) {
     500                $this->assertInstanceOf( 'IXR_Error', $actual, $message );
     501        }
     502
     503        function assertNotIXRError( $actual, $message = '' ) {
     504                if ( $actual instanceof IXR_Error && '' === $message ) {
     505                        $message = $actual->message;
     506                }
     507                $this->assertNotInstanceOf( 'IXR_Error', $actual, $message );
     508        }
     509
     510        function assertEqualFields( $object, $fields ) {
     511                foreach ( $fields as $field_name => $field_value ) {
     512                        if ( $object->$field_name != $field_value ) {
     513                                $this->fail();
     514                        }
     515                }
     516        }
     517
     518        function assertDiscardWhitespace( $expected, $actual ) {
     519                $this->assertEquals( preg_replace( '/\s*/', '', $expected ), preg_replace( '/\s*/', '', $actual ) );
     520        }
     521
     522        /**
     523         * Asserts that the contents of two un-keyed, single arrays are equal, without accounting for the order of elements.
     524         *
     525         * @since 3.5.0
     526         *
     527         * @param array $expected Expected array.
     528         * @param array $actual   Array to check.
     529         */
     530        function assertEqualSets( $expected, $actual ) {
     531                sort( $expected );
     532                sort( $actual );
     533                $this->assertEquals( $expected, $actual );
     534        }
     535
     536        /**
     537         * Asserts that the contents of two keyed, single arrays are equal, without accounting for the order of elements.
     538         *
     539         * @since 4.1.0
     540         *
     541         * @param array $expected Expected array.
     542         * @param array $actual   Array to check.
     543         */
     544        function assertEqualSetsWithIndex( $expected, $actual ) {
     545                ksort( $expected );
     546                ksort( $actual );
     547                $this->assertEquals( $expected, $actual );
     548        }
     549
     550        /**
     551         * Asserts that the given variable is a multidimensional array, and that all arrays are non-empty.
     552         *
     553         * @since 4.8.0
     554         *
     555         * @param array $array Array to check.
     556         */
     557        function assertNonEmptyMultidimensionalArray( $array ) {
     558                $this->assertTrue( is_array( $array ) );
     559                $this->assertNotEmpty( $array );
     560
     561                foreach ( $array as $sub_array ) {
     562                        $this->assertTrue( is_array( $sub_array ) );
     563                        $this->assertNotEmpty( $sub_array );
     564                }
     565        }
     566
     567        /**
     568         * Sets the global state to as if a given URL has been requested.
     569         *
     570         * This sets:
     571         * - The super globals.
     572         * - The globals.
     573         * - The query variables.
     574         * - The main query.
     575         *
     576         * @since 3.5.0
     577         *
     578         * @param string $url The URL for the request.
     579         */
     580        function go_to( $url ) {
     581                // note: the WP and WP_Query classes like to silently fetch parameters
     582                // from all over the place (globals, GET, etc), which makes it tricky
     583                // to run them more than once without very carefully clearing everything
     584                $_GET = $_POST = array();
     585                foreach ( array( 'query_string', 'id', 'postdata', 'authordata', 'day', 'currentmonth', 'page', 'pages', 'multipage', 'more', 'numpages', 'pagenow' ) as $v ) {
     586                        if ( isset( $GLOBALS[ $v ] ) ) {
     587                                unset( $GLOBALS[ $v ] );
     588                        }
     589                }
     590                $parts = parse_url( $url );
     591                if ( isset( $parts['scheme'] ) ) {
     592                        $req = isset( $parts['path'] ) ? $parts['path'] : '';
     593                        if ( isset( $parts['query'] ) ) {
     594                                $req .= '?' . $parts['query'];
     595                                // parse the url query vars into $_GET
     596                                parse_str( $parts['query'], $_GET );
     597                        }
     598                } else {
     599                        $req = $url;
     600                }
     601                if ( ! isset( $parts['query'] ) ) {
     602                        $parts['query'] = '';
     603                }
     604
     605                $_SERVER['REQUEST_URI'] = $req;
     606                unset( $_SERVER['PATH_INFO'] );
     607
     608                self::flush_cache();
     609                unset( $GLOBALS['wp_query'], $GLOBALS['wp_the_query'] );
     610                $GLOBALS['wp_the_query'] = new WP_Query();
     611                $GLOBALS['wp_query']     = $GLOBALS['wp_the_query'];
     612
     613                $public_query_vars  = $GLOBALS['wp']->public_query_vars;
     614                $private_query_vars = $GLOBALS['wp']->private_query_vars;
     615
     616                $GLOBALS['wp']                     = new WP();
     617                $GLOBALS['wp']->public_query_vars  = $public_query_vars;
     618                $GLOBALS['wp']->private_query_vars = $private_query_vars;
     619
     620                _cleanup_query_vars();
     621
     622                $GLOBALS['wp']->main( $parts['query'] );
     623        }
     624
     625        /**
     626         * Allows tests to be skipped on single or multisite installs by using @group annotations.
     627         *
     628         * This is a custom extension of the PHPUnit requirements handling.
     629         *
     630         * Contains legacy code for skipping tests that are associated with an open Trac ticket. Core tests no longer
     631         * support this behaviour.
     632         *
     633         * @since 3.5.0
     634         */
     635        protected function checkRequirements() {
     636                parent::checkRequirements();
     637
     638                $annotations = $this->getAnnotations();
     639
     640                if ( ! empty( $annotations['group'] ) ) {
     641                        if ( in_array( 'ms-required', $annotations['group'], true ) ) {
     642                                $this->skipWithoutMultisite();
     643                        }
     644                        if ( in_array( 'ms-excluded', $annotations['group'], true ) ) {
     645                                $this->skipWithMultisite();
     646                        }
     647                }
     648
     649                // Core tests no longer check against open Trac tickets, but others using WP_UnitTestCase may do so.
     650                if ( defined( 'WP_RUN_CORE_TESTS' ) && WP_RUN_CORE_TESTS ) {
     651                        return;
     652                }
     653
     654                if ( WP_TESTS_FORCE_KNOWN_BUGS ) {
     655                        return;
     656                }
     657                $tickets = PHPUnit_Util_Test::getTickets( get_class( $this ), $this->getName( false ) );
     658                foreach ( $tickets as $ticket ) {
     659                        if ( is_numeric( $ticket ) ) {
     660                                $this->knownWPBug( $ticket );
     661                        } elseif ( 'Plugin' == substr( $ticket, 0, 6 ) ) {
     662                                $ticket = substr( $ticket, 6 );
     663                                if ( $ticket && is_numeric( $ticket ) ) {
     664                                        $this->knownPluginBug( $ticket );
     665                                }
     666                        }
     667                }
     668        }
     669
     670        /**
     671         * Skips the current test if there is an open Trac ticket associated with it.
     672         *
     673         * @since 3.5.0
     674         *
     675         * @param int $ticket_id Ticket number.
     676         */
     677        function knownWPBug( $ticket_id ) {
     678                if ( WP_TESTS_FORCE_KNOWN_BUGS || in_array( $ticket_id, self::$forced_tickets ) ) {
     679                        return;
     680                }
     681                if ( ! TracTickets::isTracTicketClosed( 'https://core.trac.wordpress.org', $ticket_id ) ) {
     682                        $this->markTestSkipped( sprintf( 'WordPress Ticket #%d is not fixed', $ticket_id ) );
     683                }
     684        }
     685
     686        /**
     687         * Skips the current test if there is an open Unit Test Trac ticket associated with it.
     688         *
     689         * @since 3.5.0
     690         *
     691         * @deprecated No longer used since the Unit Test Trac was merged into the Core Trac.
     692         *
     693         * @param int $ticket_id Ticket number.
     694         */
     695        function knownUTBug( $ticket_id ) {
     696                return;
     697        }
     698
     699        /**
     700         * Skips the current test if there is an open Plugin Trac ticket associated with it.
     701         *
     702         * @since 3.5.0
     703         *
     704         * @param int $ticket_id Ticket number.
     705         */
     706        function knownPluginBug( $ticket_id ) {
     707                if ( WP_TESTS_FORCE_KNOWN_BUGS || in_array( 'Plugin' . $ticket_id, self::$forced_tickets ) ) {
     708                        return;
     709                }
     710                if ( ! TracTickets::isTracTicketClosed( 'https://plugins.trac.wordpress.org', $ticket_id ) ) {
     711                        $this->markTestSkipped( sprintf( 'WordPress Plugin Ticket #%d is not fixed', $ticket_id ) );
     712                }
     713        }
     714
     715        /**
     716         * Adds a Trac ticket number to the `$forced_tickets` property.
     717         *
     718         * @since 3.5.0
     719         *
     720         * @param int $ticket Ticket number.
     721         */
     722        public static function forceTicket( $ticket ) {
     723                self::$forced_tickets[] = $ticket;
     724        }
     725
     726        /**
     727         * Custom preparations for the PHPUnit process isolation template.
     728         *
     729         * When restoring global state between tests, PHPUnit defines all the constants that were already defined, and then
     730         * includes included files. This does not work with WordPress, as the included files define the constants.
     731         *
     732         * This method defines the constants after including files.
     733         *
     734         * @param Text_Template $template
     735         */
     736        function prepareTemplate( Text_Template $template ) {
     737                $template->setVar( array( 'constants' => '' ) );
     738                $template->setVar( array( 'wp_constants' => PHPUnit_Util_GlobalState::getConstantsAsString() ) );
     739                parent::prepareTemplate( $template );
     740        }
     741
     742        /**
     743         * Creates a unique temporary file name.
     744         *
     745         * The directory in which the file is created depends on the environment configuration.
     746         *
     747         * @since 3.5.0
     748         *
     749         * @return string|bool Path on success, else false.
     750         */
     751        function temp_filename() {
     752                $tmp_dir = '';
     753                $dirs    = array( 'TMP', 'TMPDIR', 'TEMP' );
     754                foreach ( $dirs as $dir ) {
     755                        if ( isset( $_ENV[ $dir ] ) && ! empty( $_ENV[ $dir ] ) ) {
     756                                $tmp_dir = $dir;
     757                                break;
     758                        }
     759                }
     760                if ( empty( $tmp_dir ) ) {
     761                        $tmp_dir = '/tmp';
     762                }
     763                $tmp_dir = realpath( $tmp_dir );
     764                return tempnam( $tmp_dir, 'wpunit' );
     765        }
     766
     767        /**
     768         * Checks each of the WP_Query is_* functions/properties against expected boolean value.
     769         *
     770         * Any properties that are listed by name as parameters will be expected to be true; all others are
     771         * expected to be false. For example, assertQueryTrue('is_single', 'is_feed') means is_single()
     772         * and is_feed() must be true and everything else must be false to pass.
     773         *
     774         * @since 2.5.0
     775         * @since 3.8.0 Moved from `Tests_Query_Conditionals` to `WP_UnitTestCase`.
     776         *
     777         * @param string $prop,... Any number of WP_Query properties that are expected to be true for the current request.
     778         */
     779        function assertQueryTrue() {
     780                global $wp_query;
     781                $all  = array(
     782                        'is_404',
     783                        'is_admin',
     784                        'is_archive',
     785                        'is_attachment',
     786                        'is_author',
     787                        'is_category',
     788                        'is_comment_feed',
     789                        'is_date',
     790                        'is_day',
     791                        'is_embed',
     792                        'is_feed',
     793                        'is_front_page',
     794                        'is_home',
     795                        'is_month',
     796                        'is_page',
     797                        'is_paged',
     798                        'is_post_type_archive',
     799                        'is_posts_page',
     800                        'is_preview',
     801                        'is_robots',
     802                        'is_search',
     803                        'is_single',
     804                        'is_singular',
     805                        'is_tag',
     806                        'is_tax',
     807                        'is_time',
     808                        'is_trackback',
     809                        'is_year',
     810                );
     811                $true = func_get_args();
     812
     813                foreach ( $true as $true_thing ) {
     814                        $this->assertContains( $true_thing, $all, "Unknown conditional: {$true_thing}." );
     815                }
     816
     817                $passed  = true;
     818                $message = '';
     819
     820                foreach ( $all as $query_thing ) {
     821                        $result = is_callable( $query_thing ) ? call_user_func( $query_thing ) : $wp_query->$query_thing;
     822
     823                        if ( in_array( $query_thing, $true ) ) {
     824                                if ( ! $result ) {
     825                                        $message .= $query_thing . ' is false but is expected to be true. ' . PHP_EOL;
     826                                        $passed   = false;
     827                                }
     828                        } elseif ( $result ) {
     829                                $message .= $query_thing . ' is true but is expected to be false. ' . PHP_EOL;
     830                                $passed   = false;
     831                        }
     832                }
     833
     834                if ( ! $passed ) {
     835                        $this->fail( $message );
     836                }
     837        }
     838
     839        /**
     840         * Selectively deletes a file.
     841         *
     842         * Does not delete a file if its path is set in the `$ignore_files` property.
     843         *
     844         * @param string $file File path.
     845         */
     846        function unlink( $file ) {
     847                $exists = is_file( $file );
     848                if ( $exists && ! in_array( $file, self::$ignore_files ) ) {
     849                        //error_log( $file );
     850                        unlink( $file );
     851                } elseif ( ! $exists ) {
     852                        $this->fail( "Trying to delete a file that doesn't exist: $file" );
     853                }
     854        }
     855
     856        /**
     857         * Selectively deletes files from a directory.
     858         *
     859         * Does not delete files if their paths are set in the `$ignore_files` property.
     860         *
     861         * @param string $path Directory path.
     862         */
     863        function rmdir( $path ) {
     864                $files = $this->files_in_dir( $path );
     865                foreach ( $files as $file ) {
     866                        if ( ! in_array( $file, self::$ignore_files ) ) {
     867                                $this->unlink( $file );
     868                        }
     869                }
     870        }
     871
     872        /**
     873         * Deletes files added to the `uploads` directory during tests.
     874         *
     875         * This method works in tandem with the `setUp()` and `rmdir()` methods:
     876         * - `setUp()` scans the `uploads` directory before every test, and stores its contents inside of the
     877         *   `$ignore_files` property.
     878         * - `rmdir()` and its helper methods only delete files that are not listed in the `$ignore_files` property. If
     879         *   called during `tearDown()` in tests, this will only delete files added during the previously run test.
     880         */
     881        function remove_added_uploads() {
     882                $uploads = wp_upload_dir();
     883                $this->rmdir( $uploads['basedir'] );
     884        }
     885
     886        /**
     887         * Returns a list of all files contained inside a directory.
     888         *
     889         * @since 4.0.0
     890         *
     891         * @param string $dir Path to the directory to scan.
     892         *
     893         * @return array List of file paths.
     894         */
     895        function files_in_dir( $dir ) {
     896                $files = array();
     897
     898                $iterator = new RecursiveDirectoryIterator( $dir );
     899                $objects  = new RecursiveIteratorIterator( $iterator );
     900                foreach ( $objects as $name => $object ) {
     901                        if ( is_file( $name ) ) {
     902                                $files[] = $name;
     903                        }
     904                }
     905
     906                return $files;
     907        }
     908
     909        /**
     910         * Returns a list of all files contained inside the `uploads` directory.
     911         *
     912         * @since 4.0.0
     913         *
     914         * @return array List of file paths.
     915         */
     916        function scan_user_uploads() {
     917                static $files = array();
     918                if ( ! empty( $files ) ) {
     919                        return $files;
     920                }
     921
     922                $uploads = wp_upload_dir();
     923                $files   = $this->files_in_dir( $uploads['basedir'] );
     924                return $files;
     925        }
     926
     927        /**
     928         * Deletes all directories contained inside a directory.
     929         *
     930         * @since 4.1.0
     931         *
     932         * @param string $path Path to the directory to scan.
     933         */
     934        function delete_folders( $path ) {
     935                $this->matched_dirs = array();
     936                if ( ! is_dir( $path ) ) {
     937                        return;
     938                }
     939
     940                $this->scandir( $path );
     941                foreach ( array_reverse( $this->matched_dirs ) as $dir ) {
     942                        rmdir( $dir );
     943                }
     944                rmdir( $path );
     945        }
     946
     947        /**
     948         * Retrieves all directories contained inside a directory and stores them in the `$matched_dirs` property. Hidden
     949         * directories are ignored.
     950         *
     951         * This is a helper for the `delete_folders()` method.
     952         *
     953         * @since 4.1.0
     954         *
     955         * @param string $dir Path to the directory to scan.
     956         */
     957        function scandir( $dir ) {
     958                foreach ( scandir( $dir ) as $path ) {
     959                        if ( 0 !== strpos( $path, '.' ) && is_dir( $dir . '/' . $path ) ) {
     960                                $this->matched_dirs[] = $dir . '/' . $path;
     961                                $this->scandir( $dir . '/' . $path );
     962                        }
     963                }
     964        }
     965
     966        /**
     967         * Converts a microtime string into a float.
     968         *
     969         * @since 4.1.0
     970         *
     971         * @param string $microtime Time string generated by `microtime()`.
     972         *
     973         * @return float `microtime()` output as a float.
     974         */
     975        protected function _microtime_to_float( $microtime ) {
     976                $time_array = explode( ' ', $microtime );
     977                return array_sum( $time_array );
     978        }
     979
     980        /**
     981         * Deletes a user from the database in a Multisite-agnostic way.
     982         *
     983         * @since 4.3.0
     984         *
     985         * @param int $user_id User ID.
     986         *
     987         * @return bool True if the user was deleted.
     988         */
     989        public static function delete_user( $user_id ) {
     990                if ( is_multisite() ) {
     991                        return wpmu_delete_user( $user_id );
     992                } else {
     993                        return wp_delete_user( $user_id );
     994                }
     995        }
     996
     997        /**
     998         * Resets permalinks and flushes rewrites.
     999         *
     1000         * @since 4.4.0
     1001         *
     1002         * @global WP_Rewrite $wp_rewrite
     1003         *
     1004         * @param string $structure Optional. Permalink structure to set. Default empty.
     1005         */
     1006        public function set_permalink_structure( $structure = '' ) {
     1007                global $wp_rewrite;
     1008
     1009                $wp_rewrite->init();
     1010                $wp_rewrite->set_permalink_structure( $structure );
     1011                $wp_rewrite->flush_rules();
     1012        }
     1013
     1014        /**
     1015         * Creates an attachment post from an uploaded file.
     1016         *
     1017         * @since 4.4.0
     1018         *
     1019         * @param array $upload         Array of information about the uploaded file, provided by wp_upload_bits().
     1020         * @param int   $parent_post_id Optional. Parent post ID.
     1021         *
     1022         * @return int|WP_Error The attachment ID on success. The value 0 or WP_Error on failure.
     1023         */
     1024        function _make_attachment( $upload, $parent_post_id = 0 ) {
     1025                $type = '';
     1026                if ( ! empty( $upload['type'] ) ) {
     1027                        $type = $upload['type'];
     1028                } else {
     1029                        $mime = wp_check_filetype( $upload['file'] );
     1030                        if ( $mime ) {
     1031                                $type = $mime['type'];
     1032                        }
     1033                }
     1034
     1035                $attachment = array(
     1036                        'post_title'     => basename( $upload['file'] ),
     1037                        'post_content'   => '',
     1038                        'post_type'      => 'attachment',
     1039                        'post_parent'    => $parent_post_id,
     1040                        'post_mime_type' => $type,
     1041                        'guid'           => $upload['url'],
     1042                );
     1043
     1044                $id = wp_insert_attachment( $attachment, $upload['file'], $parent_post_id );
     1045                wp_update_attachment_metadata( $id, wp_generate_attachment_metadata( $id, $upload['file'] ) );
     1046                return $id;
     1047        }
     1048
     1049        /**
     1050         * Updates the modified and modified GMT date of a post in the database.
     1051         *
     1052         * @since 4.8.0
     1053         *
     1054         * @global wpdb $wpdb WordPress database abstraction object.
     1055         *
     1056         * @param int    $post_id Post ID.
     1057         * @param string $date    Post date, in the format YYYY-MM-DD HH:MM:SS.
     1058         *
     1059         * @return int|false 1 on success, or false on error.
     1060         */
     1061        protected function update_post_modified( $post_id, $date ) {
     1062                global $wpdb;
     1063                return $wpdb->update(
     1064                        $wpdb->posts,
     1065                        array(
     1066                                'post_modified'     => $date,
     1067                                'post_modified_gmt' => $date,
     1068                        ),
     1069                        array(
     1070                                'ID' => $post_id,
     1071                        ),
     1072                        array(
     1073                                '%s',
     1074                                '%s',
     1075                        ),
     1076                        array(
     1077                                '%d',
     1078                        )
     1079                );
     1080        }
     1081}
  • tests/phpunit/includes/bootstrap.php

     
    108108// Delete any default posts & related data
    109109_delete_all_posts();
    110110
    111 require dirname( __FILE__ ) . '/testcase.php';
     111if ( version_compare( tests_get_phpunit_version(), '7.0', '>=' ) ) {
     112        require dirname( __FILE__ ) . '/phpunit7/testcase.php';
     113} else {
     114        require dirname( __FILE__ ) . '/testcase.php';
     115}
     116
    112117require dirname( __FILE__ ) . '/testcase-rest-api.php';
    113118require dirname( __FILE__ ) . '/testcase-rest-controller.php';
    114119require dirname( __FILE__ ) . '/testcase-rest-post-type-controller.php';
     
    132137 * If WP_TESTS_FORCE_KNOWN_BUGS is already set in wp-tests-config.php, then
    133138 * how you call phpunit has no effect.
    134139 */
    135 class WP_PHPUnit_Util_Getopt extends PHPUnit_Util_Getopt {
     140class WP_PHPUnit_Util_Getopt {
    136141        protected $longOptions = array(
    137142                'exclude-group=',
    138143                'group=',
     
    145150                        next( $argv );
    146151                        try {
    147152                                if ( strlen( $arg ) > 1 && $arg[0] === '-' && $arg[1] === '-' ) {
    148                                         PHPUnit_Util_Getopt::parseLongOption( substr( $arg, 2 ), $this->longOptions, $options, $argv );
     153                                        self::parseLongOption( substr( $arg, 2 ), $this->longOptions, $options, $argv );
    149154                                }
    150155                        } catch ( PHPUnit_Framework_Exception $e ) {
    151156                                // Enforcing recognized arguments or correctly formed arguments is
     
    196201                        echo PHP_EOL;
    197202                }
    198203        }
     204
     205        /**
     206         * Copied from https://raw.githubusercontent.com/sebastianbergmann/phpunit/6.5.7/src/Util/Getopt.php
     207         *
     208         * @param $arg
     209         * @param $long_options
     210         * @param $opts
     211         * @param $args
     212         */
     213    protected static function parseLongOption( $arg, $long_options, &$opts, &$args ) {
     214        $count   = count( $long_options );
     215        $list    = explode( '=', $arg );
     216        $opt     = $list[0];
     217        $opt_arg = null;
     218
     219        if ( count( $list ) > 1 ) {
     220            $opt_arg = $list[1];
     221        }
     222
     223        $opt_len = strlen( $opt );
     224
     225        for ( $i = 0; $i < $count; $i++ ) {
     226            $long_opt  = $long_options[ $i ];
     227            $opt_start = substr( $long_opt, 0, $opt_len );
     228
     229            if ( $opt_start != $opt ) {
     230                continue;
     231            }
     232
     233            $opt_rest = substr( $long_opt, $opt_len );
     234
     235            if ( $opt_rest != '' && $opt[0] != '=' && $i + 1 < $count &&
     236                $opt == substr( $long_options[ $i + 1 ], 0, $opt_len ) ) {
     237                throw new Exception(
     238                    "option --$opt is ambiguous"
     239                );
     240            }
     241
     242            if ( substr( $long_opt, -1 ) == '=' ) {
     243                if ( substr( $long_opt, -2 ) != '==' ) {
     244                    if ( ! strlen( $opt_arg ) ) {
     245                        if ( false === $opt_arg = current( $args ) ) {
     246                            throw new Exception(
     247                                "option --$opt requires an argument"
     248                            );
     249                        }
     250                        next( $args );
     251                    }
     252                }
     253            } elseif ( $opt_arg ) {
     254                throw new Exception(
     255                    "option --$opt doesn't allow an argument"
     256                );
     257            }
     258
     259            $full_option = '--' . preg_replace( '/={1,2}$/', '', $long_opt );
     260            $opts[]      = array( $full_option, $opt_arg );
     261
     262            return;
     263        }
     264
     265        throw new Exception( "unrecognized option --$opt" );
     266    }
    199267}
    200268new WP_PHPUnit_Util_Getopt( $_SERVER['argv'] );
  • tests/phpunit/includes/functions.php

     
    11<?php
    22
    33/**
     4 * Retrieves PHPUnit runner version.
     5 */
     6function tests_get_phpunit_version() {
     7        if ( class_exists( 'PHPUnit_Runner_Version' ) ) {
     8                $version = PHPUnit_Runner_Version::id();
     9        } elseif ( class_exists( 'PHPUnit\Runner\Version' ) ) {
     10                // Must be parsable by PHP 5.2.x.
     11                $version = call_user_func( 'PHPUnit\Runner\Version::id' );
     12        } else {
     13                $version = 0;
     14        }
     15
     16        return $version;
     17}
     18
     19/**
    420 * Resets various `$_SERVER` variables that can get altered during tests.
    521 */
    622function tests_reset__SERVER() {
  • tests/phpunit/includes/listener-loader.php

     
     1<?php
     2
     3if ( version_compare( tests_get_phpunit_version(), '7.0', '>=' ) ) {
     4        require dirname( __FILE__ ) . '/phpunit7/speed-trap-listener.php';
     5} else {
     6        require dirname( __FILE__ ) . '/speed-trap-listener.php';
     7}
  • tests/phpunit/includes/phpunit6-compat.php

     
    1515        class_alias( 'PHPUnit\Util\GlobalState', 'PHPUnit_Util_GlobalState' );
    1616        class_alias( 'PHPUnit\Util\Getopt', 'PHPUnit_Util_Getopt' );
    1717
    18         class PHPUnit_Util_Test extends PHPUnit\Util\Test {
     18        class PHPUnit_Util_Test {
    1919
    2020                public static function getTickets( $className, $methodName ) {
    21                         $annotations = self::parseTestMethodAnnotations( $className, $methodName );
     21                        $annotations = PHPUnit\Util\Test::parseTestMethodAnnotations( $className, $methodName );
    2222
    2323                        $tickets = array();
    2424
  • tests/phpunit/includes/phpunit7/speed-trap-listener.php

     
     1<?php
     2
     3/**
     4 * A PHPUnit TestListener that exposes your slowest running tests by outputting
     5 * results directly to the console.
     6 */
     7class SpeedTrapListener implements PHPUnit_Framework_TestListener {
     8
     9        /**
     10         * Internal tracking for test suites.
     11         *
     12         * Increments as more suites are run, then decremented as they finish. All
     13         * suites have been run when returns to 0.
     14         *
     15         * @var integer
     16         */
     17        protected $suites = 0;
     18
     19        /**
     20         * Time in milliseconds at which a test will be considered "slow" and be
     21         * reported by this listener.
     22         *
     23         * @var int
     24         */
     25        protected $slowThreshold;
     26
     27        /**
     28         * Number of tests to report on for slowness.
     29         *
     30         * @var int
     31         */
     32        protected $reportLength;
     33
     34        /**
     35         * Collection of slow tests.
     36         *
     37         * @var array
     38         */
     39        protected $slow = array();
     40
     41        /**
     42         * Construct a new instance.
     43         *
     44         * @param array $options
     45         */
     46        public function __construct( array $options = array() ) {
     47                $this->loadOptions( $options );
     48        }
     49
     50        /**
     51         * An error occurred.
     52         *
     53         * @param PHPUnit_Framework_Test $test
     54         * @param Exception              $e
     55         * @param float                   $time
     56         */
     57        public function addError( PHPUnit\Framework\Test $test, Throwable $t, float $time ): void {
     58        }
     59
     60        /**
     61         * A warning occurred.
     62         *
     63         * @param PHPUnit_Framework_Test    $test
     64         * @param PHPUnit_Framework_Warning $e
     65         * @param float                     $time
     66         * @since Method available since Release 5.1.0
     67         */
     68        public function addWarning( PHPUnit\Framework\Test $test, PHPUnit\Framework\Warning $e, float $time): void {
     69        }
     70
     71        /**
     72         * A failure occurred.
     73         *
     74         * @param PHPUnit_Framework_Test                 $test
     75         * @param PHPUnit_Framework_AssertionFailedError $e
     76         * @param float                                   $time
     77         */
     78        public function addFailure( PHPUnit\Framework\Test $test, PHPUnit\Framework\AssertionFailedError $e, float $time): void {
     79        }
     80
     81        /**
     82         * Incomplete test.
     83         *
     84         * @param PHPUnit_Framework_Test $test
     85         * @param Exception              $e
     86         * @param float                   $time
     87         */
     88        public function addIncompleteTest( PHPUnit\Framework\Test $test, Throwable $t, float $time): void {
     89        }
     90
     91        /**
     92         * Risky test.
     93         *
     94         * @param PHPUnit_Framework_Test $test
     95         * @param Exception              $e
     96         * @param float                   $time
     97         * @since  Method available since Release 4.0.0
     98         */
     99        public function addRiskyTest( PHPUnit\Framework\Test $test, Throwable $t, float $time): void {
     100        }
     101
     102        /**
     103         * Skipped test.
     104         *
     105         * @param PHPUnit_Framework_Test $test
     106         * @param Exception              $e
     107         * @param float                   $time
     108         */
     109        public function addSkippedTest( PHPUnit\Framework\Test $test, Throwable $t, float $time): void {
     110        }
     111
     112        /**
     113         * A test started.
     114         *
     115         * @param PHPUnit_Framework_Test $test
     116         */
     117        public function startTest( PHPUnit\Framework\Test $test): void {
     118        }
     119
     120        /**
     121         * A test ended.
     122         *
     123         * @param PHPUnit_Framework_Test $test
     124         * @param float                   $time
     125         */
     126        public function endTest( PHPUnit\Framework\Test $test, float $time): void {
     127                if ( ! $test instanceof PHPUnit_Framework_TestCase ) {
     128                        return;
     129                }
     130
     131                $time      = $this->toMilliseconds( $time );
     132                $threshold = $this->getSlowThreshold( $test );
     133
     134                if ( $this->isSlow( $time, $threshold ) ) {
     135                        $this->addSlowTest( $test, $time );
     136                }
     137        }
     138
     139        /**
     140         * A test suite started.
     141         *
     142         * @param PHPUnit_Framework_TestSuite $suite
     143         */
     144        public function startTestSuite( PHPUnit\Framework\TestSuite $suite): void {
     145                $this->suites++;
     146        }
     147
     148        /**
     149         * A test suite ended.
     150         *
     151         * @param PHPUnit_Framework_TestSuite $suite
     152         */
     153        public function endTestSuite( PHPUnit\Framework\TestSuite $suite): void {
     154                $this->suites--;
     155
     156                if ( 0 === $this->suites && $this->hasSlowTests() ) {
     157                        arsort( $this->slow ); // Sort longest running tests to the top
     158
     159                        $this->renderHeader();
     160                        $this->renderBody();
     161                        $this->renderFooter();
     162                }
     163        }
     164
     165        /**
     166         * Whether the given test execution time is considered slow.
     167         *
     168         * @param int $time          Test execution time in milliseconds
     169         * @param int $slowThreshold Test execution time at which a test should be considered slow (milliseconds)
     170         * @return bool
     171         */
     172        protected function isSlow( $time, $slowThreshold ) {
     173                return $time >= $slowThreshold;
     174        }
     175
     176        /**
     177         * Stores a test as slow.
     178         *
     179         * @param PHPUnit_Framework_TestCase $test
     180         * @param int                         $time Test execution time in milliseconds
     181         */
     182        protected function addSlowTest( PHPUnit_Framework_TestCase $test, $time ) {
     183                $label = $this->makeLabel( $test );
     184
     185                $this->slow[ $label ] = $time;
     186        }
     187
     188        /**
     189         * Whether at least one test has been considered slow.
     190         *
     191         * @return bool
     192         */
     193        protected function hasSlowTests() {
     194                return ! empty( $this->slow );
     195        }
     196
     197        /**
     198         * Convert PHPUnit's reported test time (microseconds) to milliseconds.
     199         *
     200         * @param float $time
     201         * @return int
     202         */
     203        protected function toMilliseconds( $time ) {
     204                return (int) round( $time * 1000 );
     205        }
     206
     207        /**
     208         * Label for describing a test.
     209         *
     210         * @param PHPUnit_Framework_TestCase $test
     211         * @return string
     212         */
     213        protected function makeLabel( PHPUnit_Framework_TestCase $test ) {
     214                return sprintf( '%s:%s', get_class( $test ), $test->getName() );
     215        }
     216
     217        /**
     218         * Calculate number of slow tests to report about.
     219         *
     220         * @return int
     221         */
     222        protected function getReportLength() {
     223                return min( count( $this->slow ), $this->reportLength );
     224        }
     225
     226        /**
     227         * Find how many slow tests occurred that won't be shown due to list length.
     228         *
     229         * @return int Number of hidden slow tests
     230         */
     231        protected function getHiddenCount() {
     232                $total   = count( $this->slow );
     233                $showing = $this->getReportLength( $this->slow );
     234
     235                $hidden = 0;
     236                if ( $total > $showing ) {
     237                        $hidden = $total - $showing;
     238                }
     239
     240                return $hidden;
     241        }
     242
     243        /**
     244         * Renders slow test report header.
     245         */
     246        protected function renderHeader() {
     247                echo sprintf( "\n\nYou should really fix these slow tests (>%sms)...\n", $this->slowThreshold );
     248        }
     249
     250        /**
     251         * Renders slow test report body.
     252         */
     253        protected function renderBody() {
     254                $slowTests = $this->slow;
     255
     256                $length = $this->getReportLength( $slowTests );
     257                for ( $i = 1; $i <= $length; ++$i ) {
     258                        $label = key( $slowTests );
     259                        $time  = array_shift( $slowTests );
     260
     261                        echo sprintf( " %s. %sms to run %s\n", $i, $time, $label );
     262                }
     263        }
     264
     265        /**
     266         * Renders slow test report footer.
     267         */
     268        protected function renderFooter() {
     269                if ( $hidden = $this->getHiddenCount( $this->slow ) ) {
     270                        echo sprintf( '...and there %s %s more above your threshold hidden from view', $hidden == 1 ? 'is' : 'are', $hidden );
     271                }
     272        }
     273
     274        /**
     275         * Populate options into class internals.
     276         *
     277         * @param array $options
     278         */
     279        protected function loadOptions( array $options ) {
     280                $this->slowThreshold = isset( $options['slowThreshold'] ) ? $options['slowThreshold'] : 500;
     281                $this->reportLength  = isset( $options['reportLength'] ) ? $options['reportLength'] : 10;
     282        }
     283
     284        /**
     285         * Get slow test threshold for given test. A TestCase can override the
     286         * suite-wide slow threshold by using the annotation @slowThreshold with
     287         * the threshold value in milliseconds.
     288         *
     289         * The following test will only be considered slow when its execution time
     290         * reaches 5000ms (5 seconds):
     291         *
     292         * <code>
     293         *
     294         * @slowThreshold 5000
     295         * public function testLongRunningProcess() {}
     296         * </code>
     297         *
     298         * @param PHPUnit_Framework_TestCase $test
     299         * @return int
     300         */
     301        protected function getSlowThreshold( PHPUnit_Framework_TestCase $test ) {
     302                $ann = $test->getAnnotations();
     303
     304                return isset( $ann['method']['slowThreshold'][0] ) ? $ann['method']['slowThreshold'][0] : $this->slowThreshold;
     305        }
     306}
  • tests/phpunit/includes/phpunit7/testcase.php

     
     1<?php
     2
     3require_once dirname(dirname( __FILE__ ) ) . '/abstract-testcase.php';
     4
     5/**
     6 * Defines a basic fixture to run multiple tests.
     7 *
     8 * Resets the state of the WordPress installation before and after every test.
     9 *
     10 * Includes utility functions and assertions useful for testing WordPress.
     11 *
     12 * All WordPress unit tests should inherit from this class.
     13 */
     14class WP_UnitTestCase extends WP_UnitTestCase_Base {
     15        /**
     16         * Asserts that a condition is not false.
     17         *
     18         * This method has been backported from a more recent PHPUnit version, as tests running on PHP 5.2 use
     19         * PHPUnit 3.6.x.
     20         *
     21         * @since 4.7.4
     22         *
     23         * @param bool   $condition Condition to check.
     24         * @param string $message   Optional. Message to display when the assertion fails.
     25         *
     26         * @throws PHPUnit_Framework_AssertionFailedError
     27         */
     28        public static function assertNotFalse( $condition, string $message = '' ): void {
     29                self::assertThat( $condition, self::logicalNot( self::isFalse() ), $message );
     30        }
     31}
  • tests/phpunit/includes/phpunit7/speed-trap-listener.php

     
     1<?php
     2
     3/**
     4 * A PHPUnit TestListener that exposes your slowest running tests by outputting
     5 * results directly to the console.
     6 */
     7class SpeedTrapListener implements PHPUnit_Framework_TestListener {
     8
     9        /**
     10         * Internal tracking for test suites.
     11         *
     12         * Increments as more suites are run, then decremented as they finish. All
     13         * suites have been run when returns to 0.
     14         *
     15         * @var integer
     16         */
     17        protected $suites = 0;
     18
     19        /**
     20         * Time in milliseconds at which a test will be considered "slow" and be
     21         * reported by this listener.
     22         *
     23         * @var int
     24         */
     25        protected $slowThreshold;
     26
     27        /**
     28         * Number of tests to report on for slowness.
     29         *
     30         * @var int
     31         */
     32        protected $reportLength;
     33
     34        /**
     35         * Collection of slow tests.
     36         *
     37         * @var array
     38         */
     39        protected $slow = array();
     40
     41        /**
     42         * Construct a new instance.
     43         *
     44         * @param array $options
     45         */
     46        public function __construct( array $options = array() ) {
     47                $this->loadOptions( $options );
     48        }
     49
     50        /**
     51         * An error occurred.
     52         *
     53         * @param PHPUnit_Framework_Test $test
     54         * @param Exception              $e
     55         * @param float                   $time
     56         */
     57        public function addError( PHPUnit\Framework\Test $test, Throwable $t, float $time ): void {
     58        }
     59
     60        /**
     61         * A warning occurred.
     62         *
     63         * @param PHPUnit_Framework_Test    $test
     64         * @param PHPUnit_Framework_Warning $e
     65         * @param float                     $time
     66         * @since Method available since Release 5.1.0
     67         */
     68        public function addWarning( PHPUnit\Framework\Test $test, PHPUnit\Framework\Warning $e, float $time): void {
     69        }
     70
     71        /**
     72         * A failure occurred.
     73         *
     74         * @param PHPUnit_Framework_Test                 $test
     75         * @param PHPUnit_Framework_AssertionFailedError $e
     76         * @param float                                   $time
     77         */
     78        public function addFailure( PHPUnit\Framework\Test $test, PHPUnit\Framework\AssertionFailedError $e, float $time): void {
     79        }
     80
     81        /**
     82         * Incomplete test.
     83         *
     84         * @param PHPUnit_Framework_Test $test
     85         * @param Exception              $e
     86         * @param float                   $time
     87         */
     88        public function addIncompleteTest( PHPUnit\Framework\Test $test, Throwable $t, float $time): void {
     89        }
     90
     91        /**
     92         * Risky test.
     93         *
     94         * @param PHPUnit_Framework_Test $test
     95         * @param Exception              $e
     96         * @param float                   $time
     97         * @since  Method available since Release 4.0.0
     98         */
     99        public function addRiskyTest( PHPUnit\Framework\Test $test, Throwable $t, float $time): void {
     100        }
     101
     102        /**
     103         * Skipped test.
     104         *
     105         * @param PHPUnit_Framework_Test $test
     106         * @param Exception              $e
     107         * @param float                   $time
     108         */
     109        public function addSkippedTest( PHPUnit\Framework\Test $test, Throwable $t, float $time): void {
     110        }
     111
     112        /**
     113         * A test started.
     114         *
     115         * @param PHPUnit_Framework_Test $test
     116         */
     117        public function startTest( PHPUnit\Framework\Test $test): void {
     118        }
     119
     120        /**
     121         * A test ended.
     122         *
     123         * @param PHPUnit_Framework_Test $test
     124         * @param float                   $time
     125         */
     126        public function endTest( PHPUnit\Framework\Test $test, float $time): void {
     127                if ( ! $test instanceof PHPUnit_Framework_TestCase ) {
     128                        return;
     129                }
     130
     131                $time      = $this->toMilliseconds( $time );
     132                $threshold = $this->getSlowThreshold( $test );
     133
     134                if ( $this->isSlow( $time, $threshold ) ) {
     135                        $this->addSlowTest( $test, $time );
     136                }
     137        }
     138
     139        /**
     140         * A test suite started.
     141         *
     142         * @param PHPUnit_Framework_TestSuite $suite
     143         */
     144        public function startTestSuite( PHPUnit\Framework\TestSuite $suite): void {
     145                $this->suites++;
     146        }
     147
     148        /**
     149         * A test suite ended.
     150         *
     151         * @param PHPUnit_Framework_TestSuite $suite
     152         */
     153        public function endTestSuite( PHPUnit\Framework\TestSuite $suite): void {
     154                $this->suites--;
     155
     156                if ( 0 === $this->suites && $this->hasSlowTests() ) {
     157                        arsort( $this->slow ); // Sort longest running tests to the top
     158
     159                        $this->renderHeader();
     160                        $this->renderBody();
     161                        $this->renderFooter();
     162                }
     163        }
     164
     165        /**
     166         * Whether the given test execution time is considered slow.
     167         *
     168         * @param int $time          Test execution time in milliseconds
     169         * @param int $slowThreshold Test execution time at which a test should be considered slow (milliseconds)
     170         * @return bool
     171         */
     172        protected function isSlow( $time, $slowThreshold ) {
     173                return $time >= $slowThreshold;
     174        }
     175
     176        /**
     177         * Stores a test as slow.
     178         *
     179         * @param PHPUnit_Framework_TestCase $test
     180         * @param int                         $time Test execution time in milliseconds
     181         */
     182        protected function addSlowTest( PHPUnit_Framework_TestCase $test, $time ) {
     183                $label = $this->makeLabel( $test );
     184
     185                $this->slow[ $label ] = $time;
     186        }
     187
     188        /**
     189         * Whether at least one test has been considered slow.
     190         *
     191         * @return bool
     192         */
     193        protected function hasSlowTests() {
     194                return ! empty( $this->slow );
     195        }
     196
     197        /**
     198         * Convert PHPUnit's reported test time (microseconds) to milliseconds.
     199         *
     200         * @param float $time
     201         * @return int
     202         */
     203        protected function toMilliseconds( $time ) {
     204                return (int) round( $time * 1000 );
     205        }
     206
     207        /**
     208         * Label for describing a test.
     209         *
     210         * @param PHPUnit_Framework_TestCase $test
     211         * @return string
     212         */
     213        protected function makeLabel( PHPUnit_Framework_TestCase $test ) {
     214                return sprintf( '%s:%s', get_class( $test ), $test->getName() );
     215        }
     216
     217        /**
     218         * Calculate number of slow tests to report about.
     219         *
     220         * @return int
     221         */
     222        protected function getReportLength() {
     223                return min( count( $this->slow ), $this->reportLength );
     224        }
     225
     226        /**
     227         * Find how many slow tests occurred that won't be shown due to list length.
     228         *
     229         * @return int Number of hidden slow tests
     230         */
     231        protected function getHiddenCount() {
     232                $total   = count( $this->slow );
     233                $showing = $this->getReportLength( $this->slow );
     234
     235                $hidden = 0;
     236                if ( $total > $showing ) {
     237                        $hidden = $total - $showing;
     238                }
     239
     240                return $hidden;
     241        }
     242
     243        /**
     244         * Renders slow test report header.
     245         */
     246        protected function renderHeader() {
     247                echo sprintf( "\n\nYou should really fix these slow tests (>%sms)...\n", $this->slowThreshold );
     248        }
     249
     250        /**
     251         * Renders slow test report body.
     252         */
     253        protected function renderBody() {
     254                $slowTests = $this->slow;
     255
     256                $length = $this->getReportLength( $slowTests );
     257                for ( $i = 1; $i <= $length; ++$i ) {
     258                        $label = key( $slowTests );
     259                        $time  = array_shift( $slowTests );
     260
     261                        echo sprintf( " %s. %sms to run %s\n", $i, $time, $label );
     262                }
     263        }
     264
     265        /**
     266         * Renders slow test report footer.
     267         */
     268        protected function renderFooter() {
     269                if ( $hidden = $this->getHiddenCount( $this->slow ) ) {
     270                        echo sprintf( '...and there %s %s more above your threshold hidden from view', $hidden == 1 ? 'is' : 'are', $hidden );
     271                }
     272        }
     273
     274        /**
     275         * Populate options into class internals.
     276         *
     277         * @param array $options
     278         */
     279        protected function loadOptions( array $options ) {
     280                $this->slowThreshold = isset( $options['slowThreshold'] ) ? $options['slowThreshold'] : 500;
     281                $this->reportLength  = isset( $options['reportLength'] ) ? $options['reportLength'] : 10;
     282        }
     283
     284        /**
     285         * Get slow test threshold for given test. A TestCase can override the
     286         * suite-wide slow threshold by using the annotation @slowThreshold with
     287         * the threshold value in milliseconds.
     288         *
     289         * The following test will only be considered slow when its execution time
     290         * reaches 5000ms (5 seconds):
     291         *
     292         * <code>
     293         *
     294         * @slowThreshold 5000
     295         * public function testLongRunningProcess() {}
     296         * </code>
     297         *
     298         * @param PHPUnit_Framework_TestCase $test
     299         * @return int
     300         */
     301        protected function getSlowThreshold( PHPUnit_Framework_TestCase $test ) {
     302                $ann = $test->getAnnotations();
     303
     304                return isset( $ann['method']['slowThreshold'][0] ) ? $ann['method']['slowThreshold'][0] : $this->slowThreshold;
     305        }
     306}
  • tests/phpunit/includes/phpunit7/testcase.php

     
     1<?php
     2
     3require_once dirname(dirname( __FILE__ ) ) . '/abstract-testcase.php';
     4
     5/**
     6 * Defines a basic fixture to run multiple tests.
     7 *
     8 * Resets the state of the WordPress installation before and after every test.
     9 *
     10 * Includes utility functions and assertions useful for testing WordPress.
     11 *
     12 * All WordPress unit tests should inherit from this class.
     13 */
     14class WP_UnitTestCase extends WP_UnitTestCase_Base {
     15        /**
     16         * Asserts that a condition is not false.
     17         *
     18         * This method has been backported from a more recent PHPUnit version, as tests running on PHP 5.2 use
     19         * PHPUnit 3.6.x.
     20         *
     21         * @since 4.7.4
     22         *
     23         * @param bool   $condition Condition to check.
     24         * @param string $message   Optional. Message to display when the assertion fails.
     25         *
     26         * @throws PHPUnit_Framework_AssertionFailedError
     27         */
     28        public static function assertNotFalse( $condition, string $message = '' ): void {
     29                self::assertThat( $condition, self::logicalNot( self::isFalse() ), $message );
     30        }
     31}
  • tests/phpunit/includes/testcase-canonical.php

     
    236236        public function assertCanonical( $test_url, $expected, $ticket = 0, $expected_doing_it_wrong = array() ) {
    237237                $this->expected_doing_it_wrong = array_merge( $this->expected_doing_it_wrong, (array) $expected_doing_it_wrong );
    238238
    239                 $ticket_ref = ( $ticket > 0 ) ? 'Ticket #' . $ticket : null;
     239                $ticket_ref = ( $ticket > 0 ) ? 'Ticket #' . $ticket : '';
    240240
    241241                if ( is_string( $expected ) ) {
    242242                        $expected = array( 'url' => $expected );
  • tests/phpunit/includes/testcase.php

     
    11<?php
    22
    3 require_once dirname( __FILE__ ) . '/factory.php';
    4 require_once dirname( __FILE__ ) . '/trac.php';
     3require_once dirname( __FILE__ ) . '/abstract-testcase.php';
    54
     5
    66/**
    77 * Defines a basic fixture to run multiple tests.
    88 *
     
    1212 *
    1313 * All WordPress unit tests should inherit from this class.
    1414 */
    15 class WP_UnitTestCase extends PHPUnit_Framework_TestCase {
    16 
    17         protected static $forced_tickets   = array();
    18         protected $expected_deprecated     = array();
    19         protected $caught_deprecated       = array();
    20         protected $expected_doing_it_wrong = array();
    21         protected $caught_doing_it_wrong   = array();
    22 
    23         protected static $hooks_saved = array();
    24         protected static $ignore_files;
    25 
    26         function __isset( $name ) {
    27                 return 'factory' === $name;
    28         }
    29 
    30         function __get( $name ) {
    31                 if ( 'factory' === $name ) {
    32                         return self::factory();
    33                 }
    34         }
    35 
     15class WP_UnitTestCase extends WP_UnitTestCase_Base {
    3616        /**
    37          * Fetches the factory object for generating WordPress fixtures.
    38          *
    39          * @return WP_UnitTest_Factory The fixture factory.
    40          */
    41         protected static function factory() {
    42                 static $factory = null;
    43                 if ( ! $factory ) {
    44                         $factory = new WP_UnitTest_Factory();
    45                 }
    46                 return $factory;
    47         }
    48 
    49         public static function get_called_class() {
    50                 if ( function_exists( 'get_called_class' ) ) {
    51                         return get_called_class();
    52                 }
    53 
    54                 // PHP 5.2 only
    55                 $backtrace = debug_backtrace();
    56                 // [0] WP_UnitTestCase::get_called_class()
    57                 // [1] WP_UnitTestCase::setUpBeforeClass()
    58                 if ( 'call_user_func' === $backtrace[2]['function'] ) {
    59                         return $backtrace[2]['args'][0][0];
    60                 }
    61                 return $backtrace[2]['class'];
    62         }
    63 
    64         public static function setUpBeforeClass() {
    65                 global $wpdb;
    66 
    67                 $wpdb->suppress_errors = false;
    68                 $wpdb->show_errors     = true;
    69                 $wpdb->db_connect();
    70                 ini_set( 'display_errors', 1 );
    71 
    72                 parent::setUpBeforeClass();
    73 
    74                 $c = self::get_called_class();
    75                 if ( ! method_exists( $c, 'wpSetUpBeforeClass' ) ) {
    76                         self::commit_transaction();
    77                         return;
    78                 }
    79 
    80                 call_user_func( array( $c, 'wpSetUpBeforeClass' ), self::factory() );
    81 
    82                 self::commit_transaction();
    83         }
    84 
    85         public static function tearDownAfterClass() {
    86                 parent::tearDownAfterClass();
    87 
    88                 _delete_all_data();
    89                 self::flush_cache();
    90 
    91                 $c = self::get_called_class();
    92                 if ( ! method_exists( $c, 'wpTearDownAfterClass' ) ) {
    93                         self::commit_transaction();
    94                         return;
    95                 }
    96 
    97                 call_user_func( array( $c, 'wpTearDownAfterClass' ) );
    98 
    99                 self::commit_transaction();
    100         }
    101 
    102         function setUp() {
    103                 set_time_limit( 0 );
    104 
    105                 if ( ! self::$ignore_files ) {
    106                         self::$ignore_files = $this->scan_user_uploads();
    107                 }
    108 
    109                 if ( ! self::$hooks_saved ) {
    110                         $this->_backup_hooks();
    111                 }
    112 
    113                 global $wp_rewrite;
    114 
    115                 $this->clean_up_global_scope();
    116 
    117                 /*
    118                  * When running core tests, ensure that post types and taxonomies
    119                  * are reset for each test. We skip this step for non-core tests,
    120                  * given the large number of plugins that register post types and
    121                  * taxonomies at 'init'.
    122                  */
    123                 if ( defined( 'WP_RUN_CORE_TESTS' ) && WP_RUN_CORE_TESTS ) {
    124                         $this->reset_post_types();
    125                         $this->reset_taxonomies();
    126                         $this->reset_post_statuses();
    127                         $this->reset__SERVER();
    128 
    129                         if ( $wp_rewrite->permalink_structure ) {
    130                                 $this->set_permalink_structure( '' );
    131                         }
    132                 }
    133 
    134                 $this->start_transaction();
    135                 $this->expectDeprecated();
    136                 add_filter( 'wp_die_handler', array( $this, 'get_wp_die_handler' ) );
    137         }
    138 
    139         /**
    140          * Detect post-test failure conditions.
    141          *
    142          * We use this method to detect expectedDeprecated and expectedIncorrectUsage annotations.
    143          *
    144          * @since 4.2.0
    145          */
    146         protected function assertPostConditions() {
    147                 $this->expectedDeprecated();
    148         }
    149 
    150         /**
    151          * After a test method runs, reset any state in WordPress the test method might have changed.
    152          */
    153         function tearDown() {
    154                 global $wpdb, $wp_query, $wp;
    155                 $wpdb->query( 'ROLLBACK' );
    156                 if ( is_multisite() ) {
    157                         while ( ms_is_switched() ) {
    158                                 restore_current_blog();
    159                         }
    160                 }
    161                 $wp_query = new WP_Query();
    162                 $wp       = new WP();
    163 
    164                 // Reset globals related to the post loop and `setup_postdata()`.
    165                 $post_globals = array( 'post', 'id', 'authordata', 'currentday', 'currentmonth', 'page', 'pages', 'multipage', 'more', 'numpages' );
    166                 foreach ( $post_globals as $global ) {
    167                         $GLOBALS[ $global ] = null;
    168                 }
    169 
    170                 remove_theme_support( 'html5' );
    171                 remove_filter( 'query', array( $this, '_create_temporary_tables' ) );
    172                 remove_filter( 'query', array( $this, '_drop_temporary_tables' ) );
    173                 remove_filter( 'wp_die_handler', array( $this, 'get_wp_die_handler' ) );
    174                 $this->_restore_hooks();
    175                 wp_set_current_user( 0 );
    176         }
    177 
    178         function clean_up_global_scope() {
    179                 $_GET  = array();
    180                 $_POST = array();
    181                 self::flush_cache();
    182         }
    183 
    184         /**
    185          * Allow tests to be skipped on some automated runs
    186          *
    187          * For test runs on Travis for something other than trunk/master
    188          * we want to skip tests that only need to run for master.
    189          */
    190         public function skipOnAutomatedBranches() {
    191                 // gentenv can be disabled
    192                 if ( ! function_exists( 'getenv' ) ) {
    193                         return false;
    194                 }
    195 
    196                 // https://docs.travis-ci.com/user/environment-variables/#Default-Environment-Variables
    197                 $travis_branch       = getenv( 'TRAVIS_BRANCH' );
    198                 $travis_pull_request = getenv( 'TRAVIS_PULL_REQUEST' );
    199 
    200                 if ( false !== $travis_pull_request && 'master' !== $travis_branch ) {
    201                         $this->markTestSkipped( 'For automated test runs, this test is only run on trunk/master' );
    202                 }
    203         }
    204 
    205         /**
    206          * Allow tests to be skipped when Multisite is not in use.
    207          *
    208          * Use in conjunction with the ms-required group.
    209          */
    210         public function skipWithoutMultisite() {
    211                 if ( ! is_multisite() ) {
    212                         $this->markTestSkipped( 'Test only runs on Multisite' );
    213                 }
    214         }
    215 
    216         /**
    217          * Allow tests to be skipped when Multisite is in use.
    218          *
    219          * Use in conjunction with the ms-excluded group.
    220          */
    221         public function skipWithMultisite() {
    222                 if ( is_multisite() ) {
    223                         $this->markTestSkipped( 'Test does not run on Multisite' );
    224                 }
    225         }
    226 
    227         /**
    228          * Unregister existing post types and register defaults.
    229          *
    230          * Run before each test in order to clean up the global scope, in case
    231          * a test forgets to unregister a post type on its own, or fails before
    232          * it has a chance to do so.
    233          */
    234         protected function reset_post_types() {
    235                 foreach ( get_post_types( array(), 'objects' ) as $pt ) {
    236                         if ( empty( $pt->tests_no_auto_unregister ) ) {
    237                                 _unregister_post_type( $pt->name );
    238                         }
    239                 }
    240                 create_initial_post_types();
    241         }
    242 
    243         /**
    244          * Unregister existing taxonomies and register defaults.
    245          *
    246          * Run before each test in order to clean up the global scope, in case
    247          * a test forgets to unregister a taxonomy on its own, or fails before
    248          * it has a chance to do so.
    249          */
    250         protected function reset_taxonomies() {
    251                 foreach ( get_taxonomies() as $tax ) {
    252                         _unregister_taxonomy( $tax );
    253                 }
    254                 create_initial_taxonomies();
    255         }
    256 
    257         /**
    258          * Unregister non-built-in post statuses.
    259          */
    260         protected function reset_post_statuses() {
    261                 foreach ( get_post_stati( array( '_builtin' => false ) ) as $post_status ) {
    262                         _unregister_post_status( $post_status );
    263                 }
    264         }
    265 
    266         /**
    267          * Reset `$_SERVER` variables
    268          */
    269         protected function reset__SERVER() {
    270                 tests_reset__SERVER();
    271         }
    272 
    273         /**
    274          * Saves the action and filter-related globals so they can be restored later.
    275          *
    276          * Stores $merged_filters, $wp_actions, $wp_current_filter, and $wp_filter
    277          * on a class variable so they can be restored on tearDown() using _restore_hooks().
    278          *
    279          * @global array $merged_filters
    280          * @global array $wp_actions
    281          * @global array $wp_current_filter
    282          * @global array $wp_filter
    283          * @return void
    284          */
    285         protected function _backup_hooks() {
    286                 $globals = array( 'wp_actions', 'wp_current_filter' );
    287                 foreach ( $globals as $key ) {
    288                         self::$hooks_saved[ $key ] = $GLOBALS[ $key ];
    289                 }
    290                 self::$hooks_saved['wp_filter'] = array();
    291                 foreach ( $GLOBALS['wp_filter'] as $hook_name => $hook_object ) {
    292                         self::$hooks_saved['wp_filter'][ $hook_name ] = clone $hook_object;
    293                 }
    294         }
    295 
    296         /**
    297          * Restores the hook-related globals to their state at setUp()
    298          * so that future tests aren't affected by hooks set during this last test.
    299          *
    300          * @global array $merged_filters
    301          * @global array $wp_actions
    302          * @global array $wp_current_filter
    303          * @global array $wp_filter
    304          * @return void
    305          */
    306         protected function _restore_hooks() {
    307                 $globals = array( 'wp_actions', 'wp_current_filter' );
    308                 foreach ( $globals as $key ) {
    309                         if ( isset( self::$hooks_saved[ $key ] ) ) {
    310                                 $GLOBALS[ $key ] = self::$hooks_saved[ $key ];
    311                         }
    312                 }
    313                 if ( isset( self::$hooks_saved['wp_filter'] ) ) {
    314                         $GLOBALS['wp_filter'] = array();
    315                         foreach ( self::$hooks_saved['wp_filter'] as $hook_name => $hook_object ) {
    316                                 $GLOBALS['wp_filter'][ $hook_name ] = clone $hook_object;
    317                         }
    318                 }
    319         }
    320 
    321         static function flush_cache() {
    322                 global $wp_object_cache;
    323                 $wp_object_cache->group_ops      = array();
    324                 $wp_object_cache->stats          = array();
    325                 $wp_object_cache->memcache_debug = array();
    326                 $wp_object_cache->cache          = array();
    327                 if ( method_exists( $wp_object_cache, '__remoteset' ) ) {
    328                         $wp_object_cache->__remoteset();
    329                 }
    330                 wp_cache_flush();
    331                 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' ) );
    332                 wp_cache_add_non_persistent_groups( array( 'comment', 'counts', 'plugins' ) );
    333         }
    334 
    335         function start_transaction() {
    336                 global $wpdb;
    337                 $wpdb->query( 'SET autocommit = 0;' );
    338                 $wpdb->query( 'START TRANSACTION;' );
    339                 add_filter( 'query', array( $this, '_create_temporary_tables' ) );
    340                 add_filter( 'query', array( $this, '_drop_temporary_tables' ) );
    341         }
    342 
    343         /**
    344          * Commit the queries in a transaction.
    345          *
    346          * @since 4.1.0
    347          */
    348         public static function commit_transaction() {
    349                 global $wpdb;
    350                 $wpdb->query( 'COMMIT;' );
    351         }
    352 
    353         function _create_temporary_tables( $query ) {
    354                 if ( 'CREATE TABLE' === substr( trim( $query ), 0, 12 ) ) {
    355                         return substr_replace( trim( $query ), 'CREATE TEMPORARY TABLE', 0, 12 );
    356                 }
    357                 return $query;
    358         }
    359 
    360         function _drop_temporary_tables( $query ) {
    361                 if ( 'DROP TABLE' === substr( trim( $query ), 0, 10 ) ) {
    362                         return substr_replace( trim( $query ), 'DROP TEMPORARY TABLE', 0, 10 );
    363                 }
    364                 return $query;
    365         }
    366 
    367         function get_wp_die_handler( $handler ) {
    368                 return array( $this, 'wp_die_handler' );
    369         }
    370 
    371         function wp_die_handler( $message ) {
    372                 if ( ! is_scalar( $message ) ) {
    373                         $message = '0';
    374                 }
    375 
    376                 throw new WPDieException( $message );
    377         }
    378 
    379         function expectDeprecated() {
    380                 $annotations = $this->getAnnotations();
    381                 foreach ( array( 'class', 'method' ) as $depth ) {
    382                         if ( ! empty( $annotations[ $depth ]['expectedDeprecated'] ) ) {
    383                                 $this->expected_deprecated = array_merge( $this->expected_deprecated, $annotations[ $depth ]['expectedDeprecated'] );
    384                         }
    385                         if ( ! empty( $annotations[ $depth ]['expectedIncorrectUsage'] ) ) {
    386                                 $this->expected_doing_it_wrong = array_merge( $this->expected_doing_it_wrong, $annotations[ $depth ]['expectedIncorrectUsage'] );
    387                         }
    388                 }
    389                 add_action( 'deprecated_function_run', array( $this, 'deprecated_function_run' ) );
    390                 add_action( 'deprecated_argument_run', array( $this, 'deprecated_function_run' ) );
    391                 add_action( 'deprecated_hook_run', array( $this, 'deprecated_function_run' ) );
    392                 add_action( 'doing_it_wrong_run', array( $this, 'doing_it_wrong_run' ) );
    393                 add_action( 'deprecated_function_trigger_error', '__return_false' );
    394                 add_action( 'deprecated_argument_trigger_error', '__return_false' );
    395                 add_action( 'deprecated_hook_trigger_error', '__return_false' );
    396                 add_action( 'doing_it_wrong_trigger_error', '__return_false' );
    397         }
    398 
    399         function expectedDeprecated() {
    400                 $errors = array();
    401 
    402                 $not_caught_deprecated = array_diff( $this->expected_deprecated, $this->caught_deprecated );
    403                 foreach ( $not_caught_deprecated as $not_caught ) {
    404                         $errors[] = "Failed to assert that $not_caught triggered a deprecated notice";
    405                 }
    406 
    407                 $unexpected_deprecated = array_diff( $this->caught_deprecated, $this->expected_deprecated );
    408                 foreach ( $unexpected_deprecated as $unexpected ) {
    409                         $errors[] = "Unexpected deprecated notice for $unexpected";
    410                 }
    411 
    412                 $not_caught_doing_it_wrong = array_diff( $this->expected_doing_it_wrong, $this->caught_doing_it_wrong );
    413                 foreach ( $not_caught_doing_it_wrong as $not_caught ) {
    414                         $errors[] = "Failed to assert that $not_caught triggered an incorrect usage notice";
    415                 }
    416 
    417                 $unexpected_doing_it_wrong = array_diff( $this->caught_doing_it_wrong, $this->expected_doing_it_wrong );
    418                 foreach ( $unexpected_doing_it_wrong as $unexpected ) {
    419                         $errors[] = "Unexpected incorrect usage notice for $unexpected";
    420                 }
    421 
    422                 // Perform an assertion, but only if there are expected or unexpected deprecated calls or wrongdoings
    423                 if ( ! empty( $this->expected_deprecated ) ||
    424                         ! empty( $this->expected_doing_it_wrong ) ||
    425                         ! empty( $this->caught_deprecated ) ||
    426                         ! empty( $this->caught_doing_it_wrong ) ) {
    427                         $this->assertEmpty( $errors, implode( "\n", $errors ) );
    428                 }
    429         }
    430 
    431         /**
    432          * Declare an expected `_deprecated_function()` or `_deprecated_argument()` call from within a test.
    433          *
    434          * @since 4.2.0
    435          *
    436          * @param string $deprecated Name of the function, method, class, or argument that is deprecated. Must match
    437          *                           first parameter of the `_deprecated_function()` or `_deprecated_argument()` call.
    438          */
    439         public function setExpectedDeprecated( $deprecated ) {
    440                 array_push( $this->expected_deprecated, $deprecated );
    441         }
    442 
    443         /**
    444          * Declare an expected `_doing_it_wrong()` call from within a test.
    445          *
    446          * @since 4.2.0
    447          *
    448          * @param string $deprecated Name of the function, method, or class that appears in the first argument of the
    449          *                           source `_doing_it_wrong()` call.
    450          */
    451         public function setExpectedIncorrectUsage( $doing_it_wrong ) {
    452                 array_push( $this->expected_doing_it_wrong, $doing_it_wrong );
    453         }
    454 
    455         /**
    456          * PHPUnit 6+ compatibility shim.
    457          *
    458          * @param mixed      $exception
    459          * @param string     $message
    460          * @param int|string $code
    461          */
    462         public function setExpectedException( $exception, $message = '', $code = null ) {
    463                 if ( method_exists( 'PHPUnit_Framework_TestCase', 'setExpectedException' ) ) {
    464                         parent::setExpectedException( $exception, $message, $code );
    465                 } else {
    466                         $this->expectException( $exception );
    467                         if ( '' !== $message ) {
    468                                 $this->expectExceptionMessage( $message );
    469                         }
    470                         if ( null !== $code ) {
    471                                 $this->expectExceptionCode( $code );
    472                         }
    473                 }
    474         }
    475 
    476         function deprecated_function_run( $function ) {
    477                 if ( ! in_array( $function, $this->caught_deprecated ) ) {
    478                         $this->caught_deprecated[] = $function;
    479                 }
    480         }
    481 
    482         function doing_it_wrong_run( $function ) {
    483                 if ( ! in_array( $function, $this->caught_doing_it_wrong ) ) {
    484                         $this->caught_doing_it_wrong[] = $function;
    485                 }
    486         }
    487 
    488         function assertWPError( $actual, $message = '' ) {
    489                 $this->assertInstanceOf( 'WP_Error', $actual, $message );
    490         }
    491 
    492         function assertNotWPError( $actual, $message = '' ) {
    493                 if ( is_wp_error( $actual ) && '' === $message ) {
    494                         $message = $actual->get_error_message();
    495                 }
    496                 $this->assertNotInstanceOf( 'WP_Error', $actual, $message );
    497         }
    498 
    499         function assertIXRError( $actual, $message = '' ) {
    500                 $this->assertInstanceOf( 'IXR_Error', $actual, $message );
    501         }
    502 
    503         function assertNotIXRError( $actual, $message = '' ) {
    504                 if ( $actual instanceof IXR_Error && '' === $message ) {
    505                         $message = $actual->message;
    506                 }
    507                 $this->assertNotInstanceOf( 'IXR_Error', $actual, $message );
    508         }
    509 
    510         function assertEqualFields( $object, $fields ) {
    511                 foreach ( $fields as $field_name => $field_value ) {
    512                         if ( $object->$field_name != $field_value ) {
    513                                 $this->fail();
    514                         }
    515                 }
    516         }
    517 
    518         function assertDiscardWhitespace( $expected, $actual ) {
    519                 $this->assertEquals( preg_replace( '/\s*/', '', $expected ), preg_replace( '/\s*/', '', $actual ) );
    520         }
    521 
    522         /**
    523          * Asserts that the contents of two un-keyed, single arrays are equal, without accounting for the order of elements.
    524          *
    525          * @since 3.5.0
    526          *
    527          * @param array $expected Expected array.
    528          * @param array $actual   Array to check.
    529          */
    530         function assertEqualSets( $expected, $actual ) {
    531                 sort( $expected );
    532                 sort( $actual );
    533                 $this->assertEquals( $expected, $actual );
    534         }
    535 
    536         /**
    537          * Asserts that the contents of two keyed, single arrays are equal, without accounting for the order of elements.
    538          *
    539          * @since 4.1.0
    540          *
    541          * @param array $expected Expected array.
    542          * @param array $actual   Array to check.
    543          */
    544         function assertEqualSetsWithIndex( $expected, $actual ) {
    545                 ksort( $expected );
    546                 ksort( $actual );
    547                 $this->assertEquals( $expected, $actual );
    548         }
    549 
    550         /**
    551          * Asserts that the given variable is a multidimensional array, and that all arrays are non-empty.
    552          *
    553          * @since 4.8.0
    554          *
    555          * @param array $array Array to check.
    556          */
    557         function assertNonEmptyMultidimensionalArray( $array ) {
    558                 $this->assertTrue( is_array( $array ) );
    559                 $this->assertNotEmpty( $array );
    560 
    561                 foreach ( $array as $sub_array ) {
    562                         $this->assertTrue( is_array( $sub_array ) );
    563                         $this->assertNotEmpty( $sub_array );
    564                 }
    565         }
    566 
    567         /**
    56817         * Asserts that a condition is not false.
    56918         *
    57019         * This method has been backported from a more recent PHPUnit version, as tests running on PHP 5.2 use
     
    58029        public static function assertNotFalse( $condition, $message = '' ) {
    58130                self::assertThat( $condition, self::logicalNot( self::isFalse() ), $message );
    58231        }
    583 
    584         /**
    585          * Sets the global state to as if a given URL has been requested.
    586          *
    587          * This sets:
    588          * - The super globals.
    589          * - The globals.
    590          * - The query variables.
    591          * - The main query.
    592          *
    593          * @since 3.5.0
    594          *
    595          * @param string $url The URL for the request.
    596          */
    597         function go_to( $url ) {
    598                 // note: the WP and WP_Query classes like to silently fetch parameters
    599                 // from all over the place (globals, GET, etc), which makes it tricky
    600                 // to run them more than once without very carefully clearing everything
    601                 $_GET = $_POST = array();
    602                 foreach ( array( 'query_string', 'id', 'postdata', 'authordata', 'day', 'currentmonth', 'page', 'pages', 'multipage', 'more', 'numpages', 'pagenow' ) as $v ) {
    603                         if ( isset( $GLOBALS[ $v ] ) ) {
    604                                 unset( $GLOBALS[ $v ] );
    605                         }
    606                 }
    607                 $parts = parse_url( $url );
    608                 if ( isset( $parts['scheme'] ) ) {
    609                         $req = isset( $parts['path'] ) ? $parts['path'] : '';
    610                         if ( isset( $parts['query'] ) ) {
    611                                 $req .= '?' . $parts['query'];
    612                                 // parse the url query vars into $_GET
    613                                 parse_str( $parts['query'], $_GET );
    614                         }
    615                 } else {
    616                         $req = $url;
    617                 }
    618                 if ( ! isset( $parts['query'] ) ) {
    619                         $parts['query'] = '';
    620                 }
    621 
    622                 $_SERVER['REQUEST_URI'] = $req;
    623                 unset( $_SERVER['PATH_INFO'] );
    624 
    625                 self::flush_cache();
    626                 unset( $GLOBALS['wp_query'], $GLOBALS['wp_the_query'] );
    627                 $GLOBALS['wp_the_query'] = new WP_Query();
    628                 $GLOBALS['wp_query']     = $GLOBALS['wp_the_query'];
    629 
    630                 $public_query_vars  = $GLOBALS['wp']->public_query_vars;
    631                 $private_query_vars = $GLOBALS['wp']->private_query_vars;
    632 
    633                 $GLOBALS['wp']                     = new WP();
    634                 $GLOBALS['wp']->public_query_vars  = $public_query_vars;
    635                 $GLOBALS['wp']->private_query_vars = $private_query_vars;
    636 
    637                 _cleanup_query_vars();
    638 
    639                 $GLOBALS['wp']->main( $parts['query'] );
    640         }
    641 
    642         /**
    643          * Allows tests to be skipped on single or multisite installs by using @group annotations.
    644          *
    645          * This is a custom extension of the PHPUnit requirements handling.
    646          *
    647          * Contains legacy code for skipping tests that are associated with an open Trac ticket. Core tests no longer
    648          * support this behaviour.
    649          *
    650          * @since 3.5.0
    651          */
    652         protected function checkRequirements() {
    653                 parent::checkRequirements();
    654 
    655                 $annotations = $this->getAnnotations();
    656 
    657                 if ( ! empty( $annotations['group'] ) ) {
    658                         if ( in_array( 'ms-required', $annotations['group'], true ) ) {
    659                                 $this->skipWithoutMultisite();
    660                         }
    661                         if ( in_array( 'ms-excluded', $annotations['group'], true ) ) {
    662                                 $this->skipWithMultisite();
    663                         }
    664                 }
    665 
    666                 // Core tests no longer check against open Trac tickets, but others using WP_UnitTestCase may do so.
    667                 if ( defined( 'WP_RUN_CORE_TESTS' ) && WP_RUN_CORE_TESTS ) {
    668                         return;
    669                 }
    670 
    671                 if ( WP_TESTS_FORCE_KNOWN_BUGS ) {
    672                         return;
    673                 }
    674                 $tickets = PHPUnit_Util_Test::getTickets( get_class( $this ), $this->getName( false ) );
    675                 foreach ( $tickets as $ticket ) {
    676                         if ( is_numeric( $ticket ) ) {
    677                                 $this->knownWPBug( $ticket );
    678                         } elseif ( 'Plugin' == substr( $ticket, 0, 6 ) ) {
    679                                 $ticket = substr( $ticket, 6 );
    680                                 if ( $ticket && is_numeric( $ticket ) ) {
    681                                         $this->knownPluginBug( $ticket );
    682                                 }
    683                         }
    684                 }
    685         }
    686 
    687         /**
    688          * Skips the current test if there is an open Trac ticket associated with it.
    689          *
    690          * @since 3.5.0
    691          *
    692          * @param int $ticket_id Ticket number.
    693          */
    694         function knownWPBug( $ticket_id ) {
    695                 if ( WP_TESTS_FORCE_KNOWN_BUGS || in_array( $ticket_id, self::$forced_tickets ) ) {
    696                         return;
    697                 }
    698                 if ( ! TracTickets::isTracTicketClosed( 'https://core.trac.wordpress.org', $ticket_id ) ) {
    699                         $this->markTestSkipped( sprintf( 'WordPress Ticket #%d is not fixed', $ticket_id ) );
    700                 }
    701         }
    702 
    703         /**
    704          * Skips the current test if there is an open Unit Test Trac ticket associated with it.
    705          *
    706          * @since 3.5.0
    707          *
    708          * @deprecated No longer used since the Unit Test Trac was merged into the Core Trac.
    709          *
    710          * @param int $ticket_id Ticket number.
    711          */
    712         function knownUTBug( $ticket_id ) {
    713                 return;
    714         }
    715 
    716         /**
    717          * Skips the current test if there is an open Plugin Trac ticket associated with it.
    718          *
    719          * @since 3.5.0
    720          *
    721          * @param int $ticket_id Ticket number.
    722          */
    723         function knownPluginBug( $ticket_id ) {
    724                 if ( WP_TESTS_FORCE_KNOWN_BUGS || in_array( 'Plugin' . $ticket_id, self::$forced_tickets ) ) {
    725                         return;
    726                 }
    727                 if ( ! TracTickets::isTracTicketClosed( 'https://plugins.trac.wordpress.org', $ticket_id ) ) {
    728                         $this->markTestSkipped( sprintf( 'WordPress Plugin Ticket #%d is not fixed', $ticket_id ) );
    729                 }
    730         }
    731 
    732         /**
    733          * Adds a Trac ticket number to the `$forced_tickets` property.
    734          *
    735          * @since 3.5.0
    736          *
    737          * @param int $ticket Ticket number.
    738          */
    739         public static function forceTicket( $ticket ) {
    740                 self::$forced_tickets[] = $ticket;
    741         }
    742 
    743         /**
    744          * Custom preparations for the PHPUnit process isolation template.
    745          *
    746          * When restoring global state between tests, PHPUnit defines all the constants that were already defined, and then
    747          * includes included files. This does not work with WordPress, as the included files define the constants.
    748          *
    749          * This method defines the constants after including files.
    750          *
    751          * @param Text_Template $template
    752          */
    753         function prepareTemplate( Text_Template $template ) {
    754                 $template->setVar( array( 'constants' => '' ) );
    755                 $template->setVar( array( 'wp_constants' => PHPUnit_Util_GlobalState::getConstantsAsString() ) );
    756                 parent::prepareTemplate( $template );
    757         }
    758 
    759         /**
    760          * Creates a unique temporary file name.
    761          *
    762          * The directory in which the file is created depends on the environment configuration.
    763          *
    764          * @since 3.5.0
    765          *
    766          * @return string|bool Path on success, else false.
    767          */
    768         function temp_filename() {
    769                 $tmp_dir = '';
    770                 $dirs    = array( 'TMP', 'TMPDIR', 'TEMP' );
    771                 foreach ( $dirs as $dir ) {
    772                         if ( isset( $_ENV[ $dir ] ) && ! empty( $_ENV[ $dir ] ) ) {
    773                                 $tmp_dir = $dir;
    774                                 break;
    775                         }
    776                 }
    777                 if ( empty( $tmp_dir ) ) {
    778                         $tmp_dir = '/tmp';
    779                 }
    780                 $tmp_dir = realpath( $tmp_dir );
    781                 return tempnam( $tmp_dir, 'wpunit' );
    782         }
    783 
    784         /**
    785          * Checks each of the WP_Query is_* functions/properties against expected boolean value.
    786          *
    787          * Any properties that are listed by name as parameters will be expected to be true; all others are
    788          * expected to be false. For example, assertQueryTrue('is_single', 'is_feed') means is_single()
    789          * and is_feed() must be true and everything else must be false to pass.
    790          *
    791          * @since 2.5.0
    792          * @since 3.8.0 Moved from `Tests_Query_Conditionals` to `WP_UnitTestCase`.
    793          *
    794          * @param string $prop,... Any number of WP_Query properties that are expected to be true for the current request.
    795          */
    796         function assertQueryTrue() {
    797                 global $wp_query;
    798                 $all  = array(
    799                         'is_404',
    800                         'is_admin',
    801                         'is_archive',
    802                         'is_attachment',
    803                         'is_author',
    804                         'is_category',
    805                         'is_comment_feed',
    806                         'is_date',
    807                         'is_day',
    808                         'is_embed',
    809                         'is_feed',
    810                         'is_front_page',
    811                         'is_home',
    812                         'is_month',
    813                         'is_page',
    814                         'is_paged',
    815                         'is_post_type_archive',
    816                         'is_posts_page',
    817                         'is_preview',
    818                         'is_robots',
    819                         'is_search',
    820                         'is_single',
    821                         'is_singular',
    822                         'is_tag',
    823                         'is_tax',
    824                         'is_time',
    825                         'is_trackback',
    826                         'is_year',
    827                 );
    828                 $true = func_get_args();
    829 
    830                 foreach ( $true as $true_thing ) {
    831                         $this->assertContains( $true_thing, $all, "Unknown conditional: {$true_thing}." );
    832                 }
    833 
    834                 $passed  = true;
    835                 $message = '';
    836 
    837                 foreach ( $all as $query_thing ) {
    838                         $result = is_callable( $query_thing ) ? call_user_func( $query_thing ) : $wp_query->$query_thing;
    839 
    840                         if ( in_array( $query_thing, $true ) ) {
    841                                 if ( ! $result ) {
    842                                         $message .= $query_thing . ' is false but is expected to be true. ' . PHP_EOL;
    843                                         $passed   = false;
    844                                 }
    845                         } elseif ( $result ) {
    846                                 $message .= $query_thing . ' is true but is expected to be false. ' . PHP_EOL;
    847                                 $passed   = false;
    848                         }
    849                 }
    850 
    851                 if ( ! $passed ) {
    852                         $this->fail( $message );
    853                 }
    854         }
    855 
    856         /**
    857          * Selectively deletes a file.
    858          *
    859          * Does not delete a file if its path is set in the `$ignore_files` property.
    860          *
    861          * @param string $file File path.
    862          */
    863         function unlink( $file ) {
    864                 $exists = is_file( $file );
    865                 if ( $exists && ! in_array( $file, self::$ignore_files ) ) {
    866                         //error_log( $file );
    867                         unlink( $file );
    868                 } elseif ( ! $exists ) {
    869                         $this->fail( "Trying to delete a file that doesn't exist: $file" );
    870                 }
    871         }
    872 
    873         /**
    874          * Selectively deletes files from a directory.
    875          *
    876          * Does not delete files if their paths are set in the `$ignore_files` property.
    877          *
    878          * @param string $path Directory path.
    879          */
    880         function rmdir( $path ) {
    881                 $files = $this->files_in_dir( $path );
    882                 foreach ( $files as $file ) {
    883                         if ( ! in_array( $file, self::$ignore_files ) ) {
    884                                 $this->unlink( $file );
    885                         }
    886                 }
    887         }
    888 
    889         /**
    890          * Deletes files added to the `uploads` directory during tests.
    891          *
    892          * This method works in tandem with the `setUp()` and `rmdir()` methods:
    893          * - `setUp()` scans the `uploads` directory before every test, and stores its contents inside of the
    894          *   `$ignore_files` property.
    895          * - `rmdir()` and its helper methods only delete files that are not listed in the `$ignore_files` property. If
    896          *   called during `tearDown()` in tests, this will only delete files added during the previously run test.
    897          */
    898         function remove_added_uploads() {
    899                 $uploads = wp_upload_dir();
    900                 $this->rmdir( $uploads['basedir'] );
    901         }
    902 
    903         /**
    904          * Returns a list of all files contained inside a directory.
    905          *
    906          * @since 4.0.0
    907          *
    908          * @param string $dir Path to the directory to scan.
    909          *
    910          * @return array List of file paths.
    911          */
    912         function files_in_dir( $dir ) {
    913                 $files = array();
    914 
    915                 $iterator = new RecursiveDirectoryIterator( $dir );
    916                 $objects  = new RecursiveIteratorIterator( $iterator );
    917                 foreach ( $objects as $name => $object ) {
    918                         if ( is_file( $name ) ) {
    919                                 $files[] = $name;
    920                         }
    921                 }
    922 
    923                 return $files;
    924         }
    925 
    926         /**
    927          * Returns a list of all files contained inside the `uploads` directory.
    928          *
    929          * @since 4.0.0
    930          *
    931          * @return array List of file paths.
    932          */
    933         function scan_user_uploads() {
    934                 static $files = array();
    935                 if ( ! empty( $files ) ) {
    936                         return $files;
    937                 }
    938 
    939                 $uploads = wp_upload_dir();
    940                 $files   = $this->files_in_dir( $uploads['basedir'] );
    941                 return $files;
    942         }
    943 
    944         /**
    945          * Deletes all directories contained inside a directory.
    946          *
    947          * @since 4.1.0
    948          *
    949          * @param string $path Path to the directory to scan.
    950          */
    951         function delete_folders( $path ) {
    952                 $this->matched_dirs = array();
    953                 if ( ! is_dir( $path ) ) {
    954                         return;
    955                 }
    956 
    957                 $this->scandir( $path );
    958                 foreach ( array_reverse( $this->matched_dirs ) as $dir ) {
    959                         rmdir( $dir );
    960                 }
    961                 rmdir( $path );
    962         }
    963 
    964         /**
    965          * Retrieves all directories contained inside a directory and stores them in the `$matched_dirs` property. Hidden
    966          * directories are ignored.
    967          *
    968          * This is a helper for the `delete_folders()` method.
    969          *
    970          * @since 4.1.0
    971          *
    972          * @param string $dir Path to the directory to scan.
    973          */
    974         function scandir( $dir ) {
    975                 foreach ( scandir( $dir ) as $path ) {
    976                         if ( 0 !== strpos( $path, '.' ) && is_dir( $dir . '/' . $path ) ) {
    977                                 $this->matched_dirs[] = $dir . '/' . $path;
    978                                 $this->scandir( $dir . '/' . $path );
    979                         }
    980                 }
    981         }
    982 
    983         /**
    984          * Converts a microtime string into a float.
    985          *
    986          * @since 4.1.0
    987          *
    988          * @param string $microtime Time string generated by `microtime()`.
    989          *
    990          * @return float `microtime()` output as a float.
    991          */
    992         protected function _microtime_to_float( $microtime ) {
    993                 $time_array = explode( ' ', $microtime );
    994                 return array_sum( $time_array );
    995         }
    996 
    997         /**
    998          * Deletes a user from the database in a Multisite-agnostic way.
    999          *
    1000          * @since 4.3.0
    1001          *
    1002          * @param int $user_id User ID.
    1003          *
    1004          * @return bool True if the user was deleted.
    1005          */
    1006         public static function delete_user( $user_id ) {
    1007                 if ( is_multisite() ) {
    1008                         return wpmu_delete_user( $user_id );
    1009                 } else {
    1010                         return wp_delete_user( $user_id );
    1011                 }
    1012         }
    1013 
    1014         /**
    1015          * Resets permalinks and flushes rewrites.
    1016          *
    1017          * @since 4.4.0
    1018          *
    1019          * @global WP_Rewrite $wp_rewrite
    1020          *
    1021          * @param string $structure Optional. Permalink structure to set. Default empty.
    1022          */
    1023         public function set_permalink_structure( $structure = '' ) {
    1024                 global $wp_rewrite;
    1025 
    1026                 $wp_rewrite->init();
    1027                 $wp_rewrite->set_permalink_structure( $structure );
    1028                 $wp_rewrite->flush_rules();
    1029         }
    1030 
    1031         /**
    1032          * Creates an attachment post from an uploaded file.
    1033          *
    1034          * @since 4.4.0
    1035          *
    1036          * @param array $upload         Array of information about the uploaded file, provided by wp_upload_bits().
    1037          * @param int   $parent_post_id Optional. Parent post ID.
    1038          *
    1039          * @return int|WP_Error The attachment ID on success. The value 0 or WP_Error on failure.
    1040          */
    1041         function _make_attachment( $upload, $parent_post_id = 0 ) {
    1042                 $type = '';
    1043                 if ( ! empty( $upload['type'] ) ) {
    1044                         $type = $upload['type'];
    1045                 } else {
    1046                         $mime = wp_check_filetype( $upload['file'] );
    1047                         if ( $mime ) {
    1048                                 $type = $mime['type'];
    1049                         }
    1050                 }
    1051 
    1052                 $attachment = array(
    1053                         'post_title'     => basename( $upload['file'] ),
    1054                         'post_content'   => '',
    1055                         'post_type'      => 'attachment',
    1056                         'post_parent'    => $parent_post_id,
    1057                         'post_mime_type' => $type,
    1058                         'guid'           => $upload['url'],
    1059                 );
    1060 
    1061                 $id = wp_insert_attachment( $attachment, $upload['file'], $parent_post_id );
    1062                 wp_update_attachment_metadata( $id, wp_generate_attachment_metadata( $id, $upload['file'] ) );
    1063                 return $id;
    1064         }
    1065 
    1066         /**
    1067          * Updates the modified and modified GMT date of a post in the database.
    1068          *
    1069          * @since 4.8.0
    1070          *
    1071          * @global wpdb $wpdb WordPress database abstraction object.
    1072          *
    1073          * @param int    $post_id Post ID.
    1074          * @param string $date    Post date, in the format YYYY-MM-DD HH:MM:SS.
    1075          *
    1076          * @return int|false 1 on success, or false on error.
    1077          */
    1078         protected function update_post_modified( $post_id, $date ) {
    1079                 global $wpdb;
    1080                 return $wpdb->update(
    1081                         $wpdb->posts,
    1082                         array(
    1083                                 'post_modified'     => $date,
    1084                                 'post_modified_gmt' => $date,
    1085                         ),
    1086                         array(
    1087                                 'ID' => $post_id,
    1088                         ),
    1089                         array(
    1090                                 '%s',
    1091                                 '%s',
    1092                         ),
    1093                         array(
    1094                                 '%d',
    1095                         )
    1096                 );
    1097         }
    109832}
  • tests/phpunit/multisite.xml

     
    3434        <const name="WP_RUN_CORE_TESTS" value="1" />
    3535    </php>
    3636    <listeners>
    37         <listener class="SpeedTrapListener" file="tests/phpunit/includes/speed-trap-listener.php">
     37        <listener class="SpeedTrapListener" file="tests/phpunit/includes/listener-loader.php">
    3838            <arguments>
    3939                <array>
    4040                    <element key="slowThreshold">
  • tests/phpunit/tests/post/query.php

     
    673673
    674674                $q->posts = $posts;
    675675
    676                 $methd = new \ReflectionMethod( 'WP_Query', 'set_found_posts' );
     676                $methd = new ReflectionMethod( 'WP_Query', 'set_found_posts' );
    677677                $methd->setAccessible( true );
    678678                $methd->invoke( $q, array( 'no_found_rows' => false ), array() );
    679679