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