Ticket #43218: 43218.diff
| File 43218.diff, 89.2 KB (added by , 7 years ago) |
|---|
-
.travis.yml
67 67 # Install the specified version of PHPUnit depending on the PHP version: 68 68 if [[ "$WP_TRAVISCI" == "travis:phpunit" ]]; then 69 69 case "$TRAVIS_PHP_VERSION" in 70 7.3|7.2|7.1|7.0|nightly) 70 7.3|7.2|7.1|nightly) 71 echo "Using PHPUnit 7.x" 72 travis_retry composer global require "phpunit/phpunit:^7" 73 ;; 74 7.0) 71 75 echo "Using PHPUnit 6.x" 72 76 travis_retry composer global require "phpunit/phpunit:^6" 73 77 ;; -
Gruntfile.js
650 650 phpunit: { 651 651 'default': { 652 652 cmd: 'phpunit', 653 args: ['- -verbose', '-c', 'phpunit.xml.dist']653 args: ['-c', 'phpunit.xml.dist'] 654 654 }, 655 655 ajax: { 656 656 cmd: 'phpunit', 657 args: ['- -verbose', '-c', 'phpunit.xml.dist', '--group', 'ajax']657 args: ['-c', 'phpunit.xml.dist', '--group', 'ajax'] 658 658 }, 659 659 multisite: { 660 660 cmd: 'phpunit', 661 args: ['- -verbose', '-c', 'tests/phpunit/multisite.xml']661 args: ['-c', 'tests/phpunit/multisite.xml'] 662 662 }, 663 663 'ms-files': { 664 664 cmd: 'phpunit', 665 args: ['- -verbose', '-c', 'tests/phpunit/multisite.xml', '--group', 'ms-files']665 args: ['-c', 'tests/phpunit/multisite.xml', '--group', 'ms-files'] 666 666 }, 667 667 'external-http': { 668 668 cmd: 'phpunit', 669 args: ['- -verbose', '-c', 'phpunit.xml.dist', '--group', 'external-http']669 args: ['-c', 'phpunit.xml.dist', '--group', 'external-http'] 670 670 }, 671 671 'restapi-jsclient': { 672 672 cmd: 'phpunit', 673 args: ['- -verbose', '-c', 'phpunit.xml.dist', '--group', 'restapi-jsclient']673 args: ['-c', 'phpunit.xml.dist', '--group', 'restapi-jsclient'] 674 674 } 675 675 }, 676 676 uglify: { -
phpunit.xml.dist
1 1 <phpunit 2 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 name="default">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 <exclude>tests/phpunit/tests/rest-api/rest-autosaves-controller.php</exclude>17 <file phpVersion="5.3.0">tests/phpunit/tests/actions/closures.php</file>18 <file phpVersion="5.3.0">tests/phpunit/tests/image/editor.php</file>19 <file phpVersion="5.3.0">tests/phpunit/tests/image/editorGd.php</file>20 <file phpVersion="5.3.0">tests/phpunit/tests/image/editorImagick.php</file>21 <file phpVersion="5.3.0">tests/phpunit/tests/oembed/headers.php</file>22 </testsuite>23 <!-- Sets the DOING_AUTOSAVE constant, so needs to be run last -->24 <testsuite name="restapi-autosave">25 <file>tests/phpunit/tests/rest-api/rest-autosaves-controller.php</file>26 </testsuite>27 </testsuites>28 <groups>29 <exclude>30 <group>ajax</group>31 <group>ms-files</group>32 <group>ms-required</group>33 <group>external-http</group>34 </exclude>35 </groups>36 <logging>37 <log type="junit" target="tests/phpunit/build/logs/junit.xml" logIncompleteSkipped="false"/>38 </logging>39 <php>40 <const name="WP_RUN_CORE_TESTS" value="1" />41 </php>3 backupGlobals="false" 4 colors="true" 5 beStrictAboutTestsThatDoNotTestAnything="true" 6 > 7 <testsuites> 8 <!-- Default test suite to run all tests --> 9 <testsuite name="default"> 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 <exclude>tests/phpunit/tests/rest-api/rest-autosaves-controller.php</exclude> 17 <file phpVersion="5.3.0">tests/phpunit/tests/actions/closures.php</file> 18 <file phpVersion="5.3.0">tests/phpunit/tests/image/editor.php</file> 19 <file phpVersion="5.3.0">tests/phpunit/tests/image/editorGd.php</file> 20 <file phpVersion="5.3.0">tests/phpunit/tests/image/editorImagick.php</file> 21 <file phpVersion="5.3.0">tests/phpunit/tests/oembed/headers.php</file> 22 </testsuite> 23 <!-- Sets the DOING_AUTOSAVE constant, so needs to be run last --> 24 <testsuite name="restapi-autosave"> 25 <file>tests/phpunit/tests/rest-api/rest-autosaves-controller.php</file> 26 </testsuite> 27 </testsuites> 28 <groups> 29 <exclude> 30 <group>ajax</group> 31 <group>ms-files</group> 32 <group>ms-required</group> 33 <group>external-http</group> 34 </exclude> 35 </groups> 36 <logging> 37 <log type="junit" target="tests/phpunit/build/logs/junit.xml" logIncompleteSkipped="false"/> 38 </logging> 39 <php> 40 <const name="WP_RUN_CORE_TESTS" value="1" /> 41 </php> 42 42 <listeners> 43 <listener class="SpeedTrapListener" file="tests/phpunit/includes/ speed-trap-listener.php">43 <listener class="SpeedTrapListener" file="tests/phpunit/includes/listener-loader.php"> 44 44 <arguments> 45 45 <array> 46 46 <element key="slowThreshold"> -
tests/phpunit/includes/abstract-testcase.php
1 <?php 2 3 require_once dirname( __FILE__ ) . '/factory.php'; 4 require_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 */ 15 abstract 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
118 118 // Delete any default posts & related data 119 119 _delete_all_posts(); 120 120 121 require dirname( __FILE__ ) . '/testcase.php'; 121 if ( version_compare( tests_get_phpunit_version(), '7.0', '>=' ) ) { 122 require dirname( __FILE__ ) . '/phpunit7/testcase.php'; 123 } else { 124 require dirname( __FILE__ ) . '/testcase.php'; 125 } 126 122 127 require dirname( __FILE__ ) . '/testcase-rest-api.php'; 123 128 require dirname( __FILE__ ) . '/testcase-rest-controller.php'; 124 129 require dirname( __FILE__ ) . '/testcase-rest-post-type-controller.php'; … … 144 149 * If WP_TESTS_FORCE_KNOWN_BUGS is already set in wp-tests-config.php, then 145 150 * how you call phpunit has no effect. 146 151 */ 147 class WP_PHPUnit_Util_Getopt extends PHPUnit_Util_Getopt{152 class WP_PHPUnit_Util_Getopt { 148 153 protected $longOptions = array( 149 154 'exclude-group=', 150 155 'group=', … … 157 162 next( $argv ); 158 163 try { 159 164 if ( strlen( $arg ) > 1 && $arg[0] === '-' && $arg[1] === '-' ) { 160 PHPUnit_Util_Getopt::parseLongOption( substr( $arg, 2 ), $this->longOptions, $options, $argv );165 self::parseLongOption( substr( $arg, 2 ), $this->longOptions, $options, $argv ); 161 166 } 162 167 } catch ( PHPUnit_Framework_Exception $e ) { 163 168 // Enforcing recognized arguments or correctly formed arguments is … … 208 213 echo PHP_EOL; 209 214 } 210 215 } 216 217 /** 218 * Copied from https://raw.githubusercontent.com/sebastianbergmann/phpunit/6.5.7/src/Util/Getopt.php 219 * 220 * @param $arg 221 * @param $long_options 222 * @param $opts 223 * @param $args 224 */ 225 protected static function parseLongOption( $arg, $long_options, &$opts, &$args ) { 226 $count = count( $long_options ); 227 $list = explode( '=', $arg ); 228 $opt = $list[0]; 229 $opt_arg = null; 230 231 if ( count( $list ) > 1 ) { 232 $opt_arg = $list[1]; 233 } 234 235 $opt_len = strlen( $opt ); 236 237 for ( $i = 0; $i < $count; $i++ ) { 238 $long_opt = $long_options[ $i ]; 239 $opt_start = substr( $long_opt, 0, $opt_len ); 240 241 if ( $opt_start != $opt ) { 242 continue; 243 } 244 245 $opt_rest = substr( $long_opt, $opt_len ); 246 247 if ( $opt_rest != '' && $opt[0] != '=' && $i + 1 < $count && 248 $opt == substr( $long_options[ $i + 1 ], 0, $opt_len ) ) { 249 throw new Exception( 250 "option --$opt is ambiguous" 251 ); 252 } 253 254 if ( substr( $long_opt, -1 ) == '=' ) { 255 if ( substr( $long_opt, -2 ) != '==' ) { 256 if ( ! strlen( $opt_arg ) ) { 257 if ( false === $opt_arg = current( $args ) ) { 258 throw new Exception( 259 "option --$opt requires an argument" 260 ); 261 } 262 next( $args ); 263 } 264 } 265 } elseif ( $opt_arg ) { 266 throw new Exception( 267 "option --$opt doesn't allow an argument" 268 ); 269 } 270 271 $full_option = '--' . preg_replace( '/={1,2}$/', '', $long_opt ); 272 $opts[] = array( $full_option, $opt_arg ); 273 274 return; 275 } 276 277 throw new Exception( "unrecognized option --$opt" ); 278 } 211 279 } 212 280 new WP_PHPUnit_Util_Getopt( $_SERVER['argv'] ); -
tests/phpunit/includes/functions.php
1 1 <?php 2 2 3 3 /** 4 * Retrieves PHPUnit runner version. 5 */ 6 function 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 /** 4 20 * Resets various `$_SERVER` variables that can get altered during tests. 5 21 */ 6 22 function tests_reset__SERVER() { -
tests/phpunit/includes/listener-loader.php
1 <?php 2 3 if ( version_compare( tests_get_phpunit_version(), '7.1', '>=' ) ) { 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
15 15 class_alias( 'PHPUnit\Util\GlobalState', 'PHPUnit_Util_GlobalState' ); 16 16 class_alias( 'PHPUnit\Util\Getopt', 'PHPUnit_Util_Getopt' ); 17 17 18 class PHPUnit_Util_Test extends PHPUnit\Util\Test{18 class PHPUnit_Util_Test { 19 19 20 20 public static function getTickets( $className, $methodName ) { 21 $annotations = self::parseTestMethodAnnotations( $className, $methodName );21 $annotations = PHPUnit\Util\Test::parseTestMethodAnnotations( $className, $methodName ); 22 22 23 23 $tickets = array(); 24 24 -
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 */ 7 class 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 3 require_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 */ 14 class 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
236 236 public function assertCanonical( $test_url, $expected, $ticket = 0, $expected_doing_it_wrong = array() ) { 237 237 $this->expected_doing_it_wrong = array_merge( $this->expected_doing_it_wrong, (array) $expected_doing_it_wrong ); 238 238 239 $ticket_ref = ( $ticket > 0 ) ? 'Ticket #' . $ticket : null;239 $ticket_ref = ( $ticket > 0 ) ? 'Ticket #' . $ticket : ''; 240 240 241 241 if ( is_string( $expected ) ) { 242 242 $expected = array( 'url' => $expected ); -
tests/phpunit/includes/testcase.php
1 1 <?php 2 2 3 require_once dirname( __FILE__ ) . '/factory.php'; 4 require_once dirname( __FILE__ ) . '/trac.php'; 3 require_once dirname( __FILE__ ) . '/abstract-testcase.php'; 5 4 5 6 6 /** 7 7 * Defines a basic fixture to run multiple tests. 8 8 * … … 12 12 * 13 13 * All WordPress unit tests should inherit from this class. 14 14 */ 15 class WP_UnitTestCase extends PHPUnit_Framework_TestCase {15 class WP_UnitTestCase extends WP_UnitTestCase_Base { 16 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 17 /** 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 only55 $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 taxonomies119 * are reset for each test. We skip this step for non-core tests,120 * given the large number of plugins that register post types and121 * 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.0145 */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 runs186 *187 * For test runs on Travis for something other than trunk/master188 * we want to skip tests that only need to run for master.189 */190 public function skipOnAutomatedBranches() {191 // gentenv can be disabled192 if ( ! function_exists( 'getenv' ) ) {193 return false;194 }195 196 // https://docs.travis-ci.com/user/environment-variables/#Default-Environment-Variables197 $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 case231 * a test forgets to unregister a post type on its own, or fails before232 * 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 case247 * a test forgets to unregister a taxonomy on its own, or fails before248 * 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` variables268 */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 $wp_actions, $wp_current_filter, and $wp_filter277 * on a class variable so they can be restored on tearDown() using _restore_hooks().278 *279 * @global array $wp_actions280 * @global array $wp_current_filter281 * @global array $wp_filter282 * @return void283 */284 protected function _backup_hooks() {285 $globals = array( 'wp_actions', 'wp_current_filter' );286 foreach ( $globals as $key ) {287 self::$hooks_saved[ $key ] = $GLOBALS[ $key ];288 }289 self::$hooks_saved['wp_filter'] = array();290 foreach ( $GLOBALS['wp_filter'] as $hook_name => $hook_object ) {291 self::$hooks_saved['wp_filter'][ $hook_name ] = clone $hook_object;292 }293 }294 295 /**296 * Restores the hook-related globals to their state at setUp()297 * so that future tests aren't affected by hooks set during this last test.298 *299 * @global array $wp_actions300 * @global array $wp_current_filter301 * @global array $wp_filter302 * @return void303 */304 protected function _restore_hooks() {305 $globals = array( 'wp_actions', 'wp_current_filter' );306 foreach ( $globals as $key ) {307 if ( isset( self::$hooks_saved[ $key ] ) ) {308 $GLOBALS[ $key ] = self::$hooks_saved[ $key ];309 }310 }311 if ( isset( self::$hooks_saved['wp_filter'] ) ) {312 $GLOBALS['wp_filter'] = array();313 foreach ( self::$hooks_saved['wp_filter'] as $hook_name => $hook_object ) {314 $GLOBALS['wp_filter'][ $hook_name ] = clone $hook_object;315 }316 }317 }318 319 static function flush_cache() {320 global $wp_object_cache;321 $wp_object_cache->group_ops = array();322 $wp_object_cache->stats = array();323 $wp_object_cache->memcache_debug = array();324 $wp_object_cache->cache = array();325 if ( method_exists( $wp_object_cache, '__remoteset' ) ) {326 $wp_object_cache->__remoteset();327 }328 wp_cache_flush();329 wp_cache_add_global_groups( array( 'users', 'userlogins', 'usermeta', 'user_meta', 'useremail', 'userslugs', 'site-transient', 'site-options', 'blog-lookup', 'blog-details', 'rss', 'global-posts', 'blog-id-cache', 'networks', 'sites', 'site-details', 'blog_meta' ) );330 wp_cache_add_non_persistent_groups( array( 'comment', 'counts', 'plugins' ) );331 }332 333 function start_transaction() {334 global $wpdb;335 $wpdb->query( 'SET autocommit = 0;' );336 $wpdb->query( 'START TRANSACTION;' );337 add_filter( 'query', array( $this, '_create_temporary_tables' ) );338 add_filter( 'query', array( $this, '_drop_temporary_tables' ) );339 }340 341 /**342 * Commit the queries in a transaction.343 *344 * @since 4.1.0345 */346 public static function commit_transaction() {347 global $wpdb;348 $wpdb->query( 'COMMIT;' );349 }350 351 function _create_temporary_tables( $query ) {352 if ( 'CREATE TABLE' === substr( trim( $query ), 0, 12 ) ) {353 return substr_replace( trim( $query ), 'CREATE TEMPORARY TABLE', 0, 12 );354 }355 return $query;356 }357 358 function _drop_temporary_tables( $query ) {359 if ( 'DROP TABLE' === substr( trim( $query ), 0, 10 ) ) {360 return substr_replace( trim( $query ), 'DROP TEMPORARY TABLE', 0, 10 );361 }362 return $query;363 }364 365 function get_wp_die_handler( $handler ) {366 return array( $this, 'wp_die_handler' );367 }368 369 function wp_die_handler( $message ) {370 if ( ! is_scalar( $message ) ) {371 $message = '0';372 }373 374 throw new WPDieException( $message );375 }376 377 function expectDeprecated() {378 $annotations = $this->getAnnotations();379 foreach ( array( 'class', 'method' ) as $depth ) {380 if ( ! empty( $annotations[ $depth ]['expectedDeprecated'] ) ) {381 $this->expected_deprecated = array_merge( $this->expected_deprecated, $annotations[ $depth ]['expectedDeprecated'] );382 }383 if ( ! empty( $annotations[ $depth ]['expectedIncorrectUsage'] ) ) {384 $this->expected_doing_it_wrong = array_merge( $this->expected_doing_it_wrong, $annotations[ $depth ]['expectedIncorrectUsage'] );385 }386 }387 add_action( 'deprecated_function_run', array( $this, 'deprecated_function_run' ) );388 add_action( 'deprecated_argument_run', array( $this, 'deprecated_function_run' ) );389 add_action( 'deprecated_hook_run', array( $this, 'deprecated_function_run' ) );390 add_action( 'doing_it_wrong_run', array( $this, 'doing_it_wrong_run' ) );391 add_action( 'deprecated_function_trigger_error', '__return_false' );392 add_action( 'deprecated_argument_trigger_error', '__return_false' );393 add_action( 'deprecated_hook_trigger_error', '__return_false' );394 add_action( 'doing_it_wrong_trigger_error', '__return_false' );395 }396 397 function expectedDeprecated() {398 $errors = array();399 400 $not_caught_deprecated = array_diff( $this->expected_deprecated, $this->caught_deprecated );401 foreach ( $not_caught_deprecated as $not_caught ) {402 $errors[] = "Failed to assert that $not_caught triggered a deprecated notice";403 }404 405 $unexpected_deprecated = array_diff( $this->caught_deprecated, $this->expected_deprecated );406 foreach ( $unexpected_deprecated as $unexpected ) {407 $errors[] = "Unexpected deprecated notice for $unexpected";408 }409 410 $not_caught_doing_it_wrong = array_diff( $this->expected_doing_it_wrong, $this->caught_doing_it_wrong );411 foreach ( $not_caught_doing_it_wrong as $not_caught ) {412 $errors[] = "Failed to assert that $not_caught triggered an incorrect usage notice";413 }414 415 $unexpected_doing_it_wrong = array_diff( $this->caught_doing_it_wrong, $this->expected_doing_it_wrong );416 foreach ( $unexpected_doing_it_wrong as $unexpected ) {417 $errors[] = "Unexpected incorrect usage notice for $unexpected";418 }419 420 // Perform an assertion, but only if there are expected or unexpected deprecated calls or wrongdoings421 if ( ! empty( $this->expected_deprecated ) ||422 ! empty( $this->expected_doing_it_wrong ) ||423 ! empty( $this->caught_deprecated ) ||424 ! empty( $this->caught_doing_it_wrong ) ) {425 $this->assertEmpty( $errors, implode( "\n", $errors ) );426 }427 }428 429 /**430 * Declare an expected `_deprecated_function()` or `_deprecated_argument()` call from within a test.431 *432 * @since 4.2.0433 *434 * @param string $deprecated Name of the function, method, class, or argument that is deprecated. Must match435 * first parameter of the `_deprecated_function()` or `_deprecated_argument()` call.436 */437 public function setExpectedDeprecated( $deprecated ) {438 array_push( $this->expected_deprecated, $deprecated );439 }440 441 /**442 * Declare an expected `_doing_it_wrong()` call from within a test.443 *444 * @since 4.2.0445 *446 * @param string $deprecated Name of the function, method, or class that appears in the first argument of the447 * source `_doing_it_wrong()` call.448 */449 public function setExpectedIncorrectUsage( $doing_it_wrong ) {450 array_push( $this->expected_doing_it_wrong, $doing_it_wrong );451 }452 453 /**454 * PHPUnit 6+ compatibility shim.455 *456 * @param mixed $exception457 * @param string $message458 * @param int|string $code459 */460 public function setExpectedException( $exception, $message = '', $code = null ) {461 if ( method_exists( 'PHPUnit_Framework_TestCase', 'setExpectedException' ) ) {462 parent::setExpectedException( $exception, $message, $code );463 } else {464 $this->expectException( $exception );465 if ( '' !== $message ) {466 $this->expectExceptionMessage( $message );467 }468 if ( null !== $code ) {469 $this->expectExceptionCode( $code );470 }471 }472 }473 474 function deprecated_function_run( $function ) {475 if ( ! in_array( $function, $this->caught_deprecated ) ) {476 $this->caught_deprecated[] = $function;477 }478 }479 480 function doing_it_wrong_run( $function ) {481 if ( ! in_array( $function, $this->caught_doing_it_wrong ) ) {482 $this->caught_doing_it_wrong[] = $function;483 }484 }485 486 function assertWPError( $actual, $message = '' ) {487 $this->assertInstanceOf( 'WP_Error', $actual, $message );488 }489 490 function assertNotWPError( $actual, $message = '' ) {491 if ( is_wp_error( $actual ) && '' === $message ) {492 $message = $actual->get_error_message();493 }494 $this->assertNotInstanceOf( 'WP_Error', $actual, $message );495 }496 497 function assertIXRError( $actual, $message = '' ) {498 $this->assertInstanceOf( 'IXR_Error', $actual, $message );499 }500 501 function assertNotIXRError( $actual, $message = '' ) {502 if ( $actual instanceof IXR_Error && '' === $message ) {503 $message = $actual->message;504 }505 $this->assertNotInstanceOf( 'IXR_Error', $actual, $message );506 }507 508 function assertEqualFields( $object, $fields ) {509 foreach ( $fields as $field_name => $field_value ) {510 if ( $object->$field_name != $field_value ) {511 $this->fail();512 }513 }514 }515 516 function assertDiscardWhitespace( $expected, $actual ) {517 $this->assertEquals( preg_replace( '/\s*/', '', $expected ), preg_replace( '/\s*/', '', $actual ) );518 }519 520 /**521 * Asserts that the contents of two un-keyed, single arrays are equal, without accounting for the order of elements.522 *523 * @since 3.5.0524 *525 * @param array $expected Expected array.526 * @param array $actual Array to check.527 */528 function assertEqualSets( $expected, $actual ) {529 sort( $expected );530 sort( $actual );531 $this->assertEquals( $expected, $actual );532 }533 534 /**535 * Asserts that the contents of two keyed, single arrays are equal, without accounting for the order of elements.536 *537 * @since 4.1.0538 *539 * @param array $expected Expected array.540 * @param array $actual Array to check.541 */542 function assertEqualSetsWithIndex( $expected, $actual ) {543 ksort( $expected );544 ksort( $actual );545 $this->assertEquals( $expected, $actual );546 }547 548 /**549 * Asserts that the given variable is a multidimensional array, and that all arrays are non-empty.550 *551 * @since 4.8.0552 *553 * @param array $array Array to check.554 */555 function assertNonEmptyMultidimensionalArray( $array ) {556 $this->assertTrue( is_array( $array ) );557 $this->assertNotEmpty( $array );558 559 foreach ( $array as $sub_array ) {560 $this->assertTrue( is_array( $sub_array ) );561 $this->assertNotEmpty( $sub_array );562 }563 }564 565 /**566 18 * Asserts that a condition is not false. 567 19 * 568 20 * This method has been backported from a more recent PHPUnit version, as tests running on PHP 5.2 use … … 578 30 public static function assertNotFalse( $condition, $message = '' ) { 579 31 self::assertThat( $condition, self::logicalNot( self::isFalse() ), $message ); 580 32 } 581 582 /**583 * Sets the global state to as if a given URL has been requested.584 *585 * This sets:586 * - The super globals.587 * - The globals.588 * - The query variables.589 * - The main query.590 *591 * @since 3.5.0592 *593 * @param string $url The URL for the request.594 */595 function go_to( $url ) {596 // note: the WP and WP_Query classes like to silently fetch parameters597 // from all over the place (globals, GET, etc), which makes it tricky598 // to run them more than once without very carefully clearing everything599 $_GET = $_POST = array();600 foreach ( array( 'query_string', 'id', 'postdata', 'authordata', 'day', 'currentmonth', 'page', 'pages', 'multipage', 'more', 'numpages', 'pagenow' ) as $v ) {601 if ( isset( $GLOBALS[ $v ] ) ) {602 unset( $GLOBALS[ $v ] );603 }604 }605 $parts = parse_url( $url );606 if ( isset( $parts['scheme'] ) ) {607 $req = isset( $parts['path'] ) ? $parts['path'] : '';608 if ( isset( $parts['query'] ) ) {609 $req .= '?' . $parts['query'];610 // parse the url query vars into $_GET611 parse_str( $parts['query'], $_GET );612 }613 } else {614 $req = $url;615 }616 if ( ! isset( $parts['query'] ) ) {617 $parts['query'] = '';618 }619 620 $_SERVER['REQUEST_URI'] = $req;621 unset( $_SERVER['PATH_INFO'] );622 623 self::flush_cache();624 unset( $GLOBALS['wp_query'], $GLOBALS['wp_the_query'] );625 $GLOBALS['wp_the_query'] = new WP_Query();626 $GLOBALS['wp_query'] = $GLOBALS['wp_the_query'];627 628 $public_query_vars = $GLOBALS['wp']->public_query_vars;629 $private_query_vars = $GLOBALS['wp']->private_query_vars;630 631 $GLOBALS['wp'] = new WP();632 $GLOBALS['wp']->public_query_vars = $public_query_vars;633 $GLOBALS['wp']->private_query_vars = $private_query_vars;634 635 _cleanup_query_vars();636 637 $GLOBALS['wp']->main( $parts['query'] );638 }639 640 /**641 * Allows tests to be skipped on single or multisite installs by using @group annotations.642 *643 * This is a custom extension of the PHPUnit requirements handling.644 *645 * Contains legacy code for skipping tests that are associated with an open Trac ticket. Core tests no longer646 * support this behaviour.647 *648 * @since 3.5.0649 */650 protected function checkRequirements() {651 parent::checkRequirements();652 653 $annotations = $this->getAnnotations();654 655 $groups = array();656 if ( ! empty( $annotations['class']['group'] ) ) {657 $groups = array_merge( $groups, $annotations['class']['group'] );658 }659 if ( ! empty( $annotations['method']['group'] ) ) {660 $groups = array_merge( $groups, $annotations['method']['group'] );661 }662 663 if ( ! empty( $groups ) ) {664 if ( in_array( 'ms-required', $groups, true ) ) {665 $this->skipWithoutMultisite();666 }667 668 if ( in_array( 'ms-excluded', $groups, true ) ) {669 $this->skipWithMultisite();670 }671 }672 673 // Core tests no longer check against open Trac tickets, but others using WP_UnitTestCase may do so.674 if ( defined( 'WP_RUN_CORE_TESTS' ) && WP_RUN_CORE_TESTS ) {675 return;676 }677 678 if ( WP_TESTS_FORCE_KNOWN_BUGS ) {679 return;680 }681 $tickets = PHPUnit_Util_Test::getTickets( get_class( $this ), $this->getName( false ) );682 foreach ( $tickets as $ticket ) {683 if ( is_numeric( $ticket ) ) {684 $this->knownWPBug( $ticket );685 } elseif ( 'Plugin' == substr( $ticket, 0, 6 ) ) {686 $ticket = substr( $ticket, 6 );687 if ( $ticket && is_numeric( $ticket ) ) {688 $this->knownPluginBug( $ticket );689 }690 }691 }692 }693 694 /**695 * Skips the current test if there is an open Trac ticket associated with it.696 *697 * @since 3.5.0698 *699 * @param int $ticket_id Ticket number.700 */701 function knownWPBug( $ticket_id ) {702 if ( WP_TESTS_FORCE_KNOWN_BUGS || in_array( $ticket_id, self::$forced_tickets ) ) {703 return;704 }705 if ( ! TracTickets::isTracTicketClosed( 'https://core.trac.wordpress.org', $ticket_id ) ) {706 $this->markTestSkipped( sprintf( 'WordPress Ticket #%d is not fixed', $ticket_id ) );707 }708 }709 710 /**711 * Skips the current test if there is an open Unit Test Trac ticket associated with it.712 *713 * @since 3.5.0714 *715 * @deprecated No longer used since the Unit Test Trac was merged into the Core Trac.716 *717 * @param int $ticket_id Ticket number.718 */719 function knownUTBug( $ticket_id ) {720 return;721 }722 723 /**724 * Skips the current test if there is an open Plugin Trac ticket associated with it.725 *726 * @since 3.5.0727 *728 * @param int $ticket_id Ticket number.729 */730 function knownPluginBug( $ticket_id ) {731 if ( WP_TESTS_FORCE_KNOWN_BUGS || in_array( 'Plugin' . $ticket_id, self::$forced_tickets ) ) {732 return;733 }734 if ( ! TracTickets::isTracTicketClosed( 'https://plugins.trac.wordpress.org', $ticket_id ) ) {735 $this->markTestSkipped( sprintf( 'WordPress Plugin Ticket #%d is not fixed', $ticket_id ) );736 }737 }738 739 /**740 * Adds a Trac ticket number to the `$forced_tickets` property.741 *742 * @since 3.5.0743 *744 * @param int $ticket Ticket number.745 */746 public static function forceTicket( $ticket ) {747 self::$forced_tickets[] = $ticket;748 }749 750 /**751 * Custom preparations for the PHPUnit process isolation template.752 *753 * When restoring global state between tests, PHPUnit defines all the constants that were already defined, and then754 * includes included files. This does not work with WordPress, as the included files define the constants.755 *756 * This method defines the constants after including files.757 *758 * @param Text_Template $template759 */760 function prepareTemplate( Text_Template $template ) {761 $template->setVar( array( 'constants' => '' ) );762 $template->setVar( array( 'wp_constants' => PHPUnit_Util_GlobalState::getConstantsAsString() ) );763 parent::prepareTemplate( $template );764 }765 766 /**767 * Creates a unique temporary file name.768 *769 * The directory in which the file is created depends on the environment configuration.770 *771 * @since 3.5.0772 *773 * @return string|bool Path on success, else false.774 */775 function temp_filename() {776 $tmp_dir = '';777 $dirs = array( 'TMP', 'TMPDIR', 'TEMP' );778 foreach ( $dirs as $dir ) {779 if ( isset( $_ENV[ $dir ] ) && ! empty( $_ENV[ $dir ] ) ) {780 $tmp_dir = $dir;781 break;782 }783 }784 if ( empty( $tmp_dir ) ) {785 $tmp_dir = '/tmp';786 }787 $tmp_dir = realpath( $tmp_dir );788 return tempnam( $tmp_dir, 'wpunit' );789 }790 791 /**792 * Checks each of the WP_Query is_* functions/properties against expected boolean value.793 *794 * Any properties that are listed by name as parameters will be expected to be true; all others are795 * expected to be false. For example, assertQueryTrue('is_single', 'is_feed') means is_single()796 * and is_feed() must be true and everything else must be false to pass.797 *798 * @since 2.5.0799 * @since 3.8.0 Moved from `Tests_Query_Conditionals` to `WP_UnitTestCase`.800 *801 * @param string $prop,... Any number of WP_Query properties that are expected to be true for the current request.802 */803 function assertQueryTrue() {804 global $wp_query;805 $all = array(806 'is_404',807 'is_admin',808 'is_archive',809 'is_attachment',810 'is_author',811 'is_category',812 'is_comment_feed',813 'is_date',814 'is_day',815 'is_embed',816 'is_feed',817 'is_front_page',818 'is_home',819 'is_month',820 'is_page',821 'is_paged',822 'is_post_type_archive',823 'is_posts_page',824 'is_preview',825 'is_robots',826 'is_search',827 'is_single',828 'is_singular',829 'is_tag',830 'is_tax',831 'is_time',832 'is_trackback',833 'is_year',834 );835 $true = func_get_args();836 837 foreach ( $true as $true_thing ) {838 $this->assertContains( $true_thing, $all, "Unknown conditional: {$true_thing}." );839 }840 841 $passed = true;842 $message = '';843 844 foreach ( $all as $query_thing ) {845 $result = is_callable( $query_thing ) ? call_user_func( $query_thing ) : $wp_query->$query_thing;846 847 if ( in_array( $query_thing, $true ) ) {848 if ( ! $result ) {849 $message .= $query_thing . ' is false but is expected to be true. ' . PHP_EOL;850 $passed = false;851 }852 } elseif ( $result ) {853 $message .= $query_thing . ' is true but is expected to be false. ' . PHP_EOL;854 $passed = false;855 }856 }857 858 if ( ! $passed ) {859 $this->fail( $message );860 }861 }862 863 /**864 * Selectively deletes a file.865 *866 * Does not delete a file if its path is set in the `$ignore_files` property.867 *868 * @param string $file File path.869 */870 function unlink( $file ) {871 $exists = is_file( $file );872 if ( $exists && ! in_array( $file, self::$ignore_files ) ) {873 //error_log( $file );874 unlink( $file );875 } elseif ( ! $exists ) {876 $this->fail( "Trying to delete a file that doesn't exist: $file" );877 }878 }879 880 /**881 * Selectively deletes files from a directory.882 *883 * Does not delete files if their paths are set in the `$ignore_files` property.884 *885 * @param string $path Directory path.886 */887 function rmdir( $path ) {888 $files = $this->files_in_dir( $path );889 foreach ( $files as $file ) {890 if ( ! in_array( $file, self::$ignore_files ) ) {891 $this->unlink( $file );892 }893 }894 }895 896 /**897 * Deletes files added to the `uploads` directory during tests.898 *899 * This method works in tandem with the `setUp()` and `rmdir()` methods:900 * - `setUp()` scans the `uploads` directory before every test, and stores its contents inside of the901 * `$ignore_files` property.902 * - `rmdir()` and its helper methods only delete files that are not listed in the `$ignore_files` property. If903 * called during `tearDown()` in tests, this will only delete files added during the previously run test.904 */905 function remove_added_uploads() {906 $uploads = wp_upload_dir();907 $this->rmdir( $uploads['basedir'] );908 }909 910 /**911 * Returns a list of all files contained inside a directory.912 *913 * @since 4.0.0914 *915 * @param string $dir Path to the directory to scan.916 *917 * @return array List of file paths.918 */919 function files_in_dir( $dir ) {920 $files = array();921 922 $iterator = new RecursiveDirectoryIterator( $dir );923 $objects = new RecursiveIteratorIterator( $iterator );924 foreach ( $objects as $name => $object ) {925 if ( is_file( $name ) ) {926 $files[] = $name;927 }928 }929 930 return $files;931 }932 933 /**934 * Returns a list of all files contained inside the `uploads` directory.935 *936 * @since 4.0.0937 *938 * @return array List of file paths.939 */940 function scan_user_uploads() {941 static $files = array();942 if ( ! empty( $files ) ) {943 return $files;944 }945 946 $uploads = wp_upload_dir();947 $files = $this->files_in_dir( $uploads['basedir'] );948 return $files;949 }950 951 /**952 * Deletes all directories contained inside a directory.953 *954 * @since 4.1.0955 *956 * @param string $path Path to the directory to scan.957 */958 function delete_folders( $path ) {959 $this->matched_dirs = array();960 if ( ! is_dir( $path ) ) {961 return;962 }963 964 $this->scandir( $path );965 foreach ( array_reverse( $this->matched_dirs ) as $dir ) {966 rmdir( $dir );967 }968 rmdir( $path );969 }970 971 /**972 * Retrieves all directories contained inside a directory and stores them in the `$matched_dirs` property. Hidden973 * directories are ignored.974 *975 * This is a helper for the `delete_folders()` method.976 *977 * @since 4.1.0978 *979 * @param string $dir Path to the directory to scan.980 */981 function scandir( $dir ) {982 foreach ( scandir( $dir ) as $path ) {983 if ( 0 !== strpos( $path, '.' ) && is_dir( $dir . '/' . $path ) ) {984 $this->matched_dirs[] = $dir . '/' . $path;985 $this->scandir( $dir . '/' . $path );986 }987 }988 }989 990 /**991 * Converts a microtime string into a float.992 *993 * @since 4.1.0994 *995 * @param string $microtime Time string generated by `microtime()`.996 *997 * @return float `microtime()` output as a float.998 */999 protected function _microtime_to_float( $microtime ) {1000 $time_array = explode( ' ', $microtime );1001 return array_sum( $time_array );1002 }1003 1004 /**1005 * Deletes a user from the database in a Multisite-agnostic way.1006 *1007 * @since 4.3.01008 *1009 * @param int $user_id User ID.1010 *1011 * @return bool True if the user was deleted.1012 */1013 public static function delete_user( $user_id ) {1014 if ( is_multisite() ) {1015 return wpmu_delete_user( $user_id );1016 } else {1017 return wp_delete_user( $user_id );1018 }1019 }1020 1021 /**1022 * Resets permalinks and flushes rewrites.1023 *1024 * @since 4.4.01025 *1026 * @global WP_Rewrite $wp_rewrite1027 *1028 * @param string $structure Optional. Permalink structure to set. Default empty.1029 */1030 public function set_permalink_structure( $structure = '' ) {1031 global $wp_rewrite;1032 1033 $wp_rewrite->init();1034 $wp_rewrite->set_permalink_structure( $structure );1035 $wp_rewrite->flush_rules();1036 }1037 1038 /**1039 * Creates an attachment post from an uploaded file.1040 *1041 * @since 4.4.01042 *1043 * @param array $upload Array of information about the uploaded file, provided by wp_upload_bits().1044 * @param int $parent_post_id Optional. Parent post ID.1045 *1046 * @return int|WP_Error The attachment ID on success. The value 0 or WP_Error on failure.1047 */1048 function _make_attachment( $upload, $parent_post_id = 0 ) {1049 $type = '';1050 if ( ! empty( $upload['type'] ) ) {1051 $type = $upload['type'];1052 } else {1053 $mime = wp_check_filetype( $upload['file'] );1054 if ( $mime ) {1055 $type = $mime['type'];1056 }1057 }1058 1059 $attachment = array(1060 'post_title' => basename( $upload['file'] ),1061 'post_content' => '',1062 'post_type' => 'attachment',1063 'post_parent' => $parent_post_id,1064 'post_mime_type' => $type,1065 'guid' => $upload['url'],1066 );1067 1068 $id = wp_insert_attachment( $attachment, $upload['file'], $parent_post_id );1069 wp_update_attachment_metadata( $id, wp_generate_attachment_metadata( $id, $upload['file'] ) );1070 return $id;1071 }1072 1073 /**1074 * Updates the modified and modified GMT date of a post in the database.1075 *1076 * @since 4.8.01077 *1078 * @global wpdb $wpdb WordPress database abstraction object.1079 *1080 * @param int $post_id Post ID.1081 * @param string $date Post date, in the format YYYY-MM-DD HH:MM:SS.1082 *1083 * @return int|false 1 on success, or false on error.1084 */1085 protected function update_post_modified( $post_id, $date ) {1086 global $wpdb;1087 return $wpdb->update(1088 $wpdb->posts,1089 array(1090 'post_modified' => $date,1091 'post_modified_gmt' => $date,1092 ),1093 array(1094 'ID' => $post_id,1095 ),1096 array(1097 '%s',1098 '%s',1099 ),1100 array(1101 '%d',1102 )1103 );1104 }1105 33 } -
tests/phpunit/multisite.xml
1 1 <phpunit 2 2 bootstrap="includes/bootstrap.php" 3 backupGlobals="false"4 colors="true"5 beStrictAboutTestsThatDoNotTestAnything="true"6 >7 <php>8 <const name="WP_TESTS_MULTISITE" value="1" />9 </php>10 <testsuites>11 <!-- Default test suite to run all tests -->12 <testsuite name="default">13 <directory suffix=".php">tests</directory>14 <exclude>tests/phpunit/tests/actions/closures.php</exclude>15 <exclude>tests/phpunit/tests/image/editor.php</exclude>16 <exclude>tests/phpunit/tests/image/editorGd.php</exclude>17 <exclude>tests/phpunit/tests/image/editorImagick.php</exclude>18 <!-- Path relative to the checkout root, for PHPUnit 3.6.x -->19 <exclude>tests/phpunit/tests/rest-api/rest-autosaves-controller.php</exclude>20 <!-- Same path relative to the configuration file, for PHPUnit 4.0.0+ -->21 <exclude>tests/rest-api/rest-autosaves-controller.php</exclude>22 <file phpVersion="5.3.0">tests/phpunit/tests/actions/closures.php</file>23 <file phpVersion="5.3.0">tests/phpunit/tests/image/editor.php</file>24 <file phpVersion="5.3.0">tests/phpunit/tests/image/editorGd.php</file>25 <file phpVersion="5.3.0">tests/phpunit/tests/image/editorImagick.php</file>26 </testsuite>27 <!-- Sets the DOING_AUTOSAVE constant, so needs to be run last -->28 <testsuite name="restapi-autosave">29 <!-- Path relative to the checkout root, for PHPUnit 3.6.x -->30 <file>tests/phpunit/tests/rest-api/rest-autosaves-controller.php</file>31 <!-- Same path relative to the configuration file, for PHPUnit 4.0.0+ -->32 <file>tests/rest-api/rest-autosaves-controller.php</file>33 </testsuite>34 </testsuites>35 <groups>36 <exclude>37 <group>ajax</group>38 <group>ms-files</group>39 <group>ms-excluded</group>40 <group>external-http</group>41 <group>oembed-headers</group>42 </exclude>43 </groups>44 <php>45 <const name="WP_RUN_CORE_TESTS" value="1" />46 </php>47 <listeners>48 <listener class="SpeedTrapListener" file="tests/phpunit/includes/speed-trap-listener.php">49 <arguments>50 <array>51 <element key="slowThreshold">52 <integer>150</integer>53 </element>54 </array>55 </arguments>56 </listener>57 </listeners>3 backupGlobals="false" 4 colors="true" 5 beStrictAboutTestsThatDoNotTestAnything="true" 6 > 7 <php> 8 <const name="WP_TESTS_MULTISITE" value="1" /> 9 </php> 10 <testsuites> 11 <!-- Default test suite to run all tests --> 12 <testsuite name="default"> 13 <directory suffix=".php">tests</directory> 14 <exclude>tests/phpunit/tests/actions/closures.php</exclude> 15 <exclude>tests/phpunit/tests/image/editor.php</exclude> 16 <exclude>tests/phpunit/tests/image/editorGd.php</exclude> 17 <exclude>tests/phpunit/tests/image/editorImagick.php</exclude> 18 <!-- Path relative to the checkout root, for PHPUnit 3.6.x --> 19 <exclude>tests/phpunit/tests/rest-api/rest-autosaves-controller.php</exclude> 20 <!-- Same path relative to the configuration file, for PHPUnit 4.0.0+ --> 21 <exclude>tests/rest-api/rest-autosaves-controller.php</exclude> 22 <file phpVersion="5.3.0">tests/phpunit/tests/actions/closures.php</file> 23 <file phpVersion="5.3.0">tests/phpunit/tests/image/editor.php</file> 24 <file phpVersion="5.3.0">tests/phpunit/tests/image/editorGd.php</file> 25 <file phpVersion="5.3.0">tests/phpunit/tests/image/editorImagick.php</file> 26 </testsuite> 27 <!-- Sets the DOING_AUTOSAVE constant, so needs to be run last --> 28 <testsuite name="restapi-autosave"> 29 <!-- Path relative to the checkout root, for PHPUnit 3.6.x --> 30 <file>tests/phpunit/tests/rest-api/rest-autosaves-controller.php</file> 31 <!-- Same path relative to the configuration file, for PHPUnit 4.0.0+ --> 32 <file>tests/rest-api/rest-autosaves-controller.php</file> 33 </testsuite> 34 </testsuites> 35 <groups> 36 <exclude> 37 <group>ajax</group> 38 <group>ms-files</group> 39 <group>ms-excluded</group> 40 <group>external-http</group> 41 <group>oembed-headers</group> 42 </exclude> 43 </groups> 44 <php> 45 <const name="WP_RUN_CORE_TESTS" value="1" /> 46 </php> 47 <listeners> 48 <listener class="SpeedTrapListener" file="tests/phpunit/includes/listener-loader.php"> 49 <arguments> 50 <array> 51 <element key="slowThreshold"> 52 <integer>150</integer> 53 </element> 54 </array> 55 </arguments> 56 </listener> 57 </listeners> 58 58 </phpunit> -
tests/phpunit/tests/post/query.php
719 719 720 720 $q->posts = $posts; 721 721 722 $methd = new \ReflectionMethod( 'WP_Query', 'set_found_posts' );722 $methd = new ReflectionMethod( 'WP_Query', 'set_found_posts' ); 723 723 $methd->setAccessible( true ); 724 724 $methd->invoke( $q, array( 'no_found_rows' => false ), array() ); 725 725