Changeset 44701
- Timestamp:
- 01/28/2019 02:10:24 PM (6 years ago)
- Location:
- trunk
- Files:
-
- 3 added
- 8 edited
- 3 copied
- 1 moved
Legend:
- Unmodified
- Added
- Removed
-
trunk/.travis.yml
r44219 r44701 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" -
trunk/phpunit.xml.dist
r44126 r44701 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> -
trunk/tests/phpunit/includes/abstract-testcase.php
r44700 r44701 13 13 * All WordPress unit tests should inherit from this class. 14 14 */ 15 class WP_UnitTestCase extends PHPUnit_Framework_TestCase {15 abstract class WP_UnitTestCase_Base extends PHPUnit_Framework_TestCase { 16 16 17 17 protected static $forced_tickets = array(); … … 275 275 * Saves the action and filter-related globals so they can be restored later. 276 276 * 277 * Stores $wp_actions, $wp_current_filter, and $wp_filter 278 * on a class variableso they can be restored on tearDown() using _restore_hooks().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 279 * 280 280 * @global array $wp_actions … … 583 583 $this->assertNotEmpty( $sub_array ); 584 584 } 585 }586 587 /**588 * Asserts that a condition is not false.589 *590 * This method has been backported from a more recent PHPUnit version, as tests running on PHP 5.2 use591 * PHPUnit 3.6.x.592 *593 * @since 4.7.4594 *595 * @param bool $condition Condition to check.596 * @param string $message Optional. Message to display when the assertion fails.597 *598 * @throws PHPUnit_Framework_AssertionFailedError599 */600 public static function assertNotFalse( $condition, $message = '' ) {601 self::assertThat( $condition, self::logicalNot( self::isFalse() ), $message );602 585 } 603 586 -
trunk/tests/phpunit/includes/bootstrap.php
r44536 r44701 8 8 */ 9 9 if ( class_exists( 'PHPUnit\Runner\Version' ) ) { 10 require_once dirname( __FILE__ ) . '/phpunit6 -compat.php';10 require_once dirname( __FILE__ ) . '/phpunit6/compat.php'; 11 11 } 12 12 … … 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'; … … 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 ) { … … 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 ) { … … 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'] ); -
trunk/tests/phpunit/includes/functions.php
r44118 r44701 1 1 <?php 2 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 } 2 18 3 19 /** -
trunk/tests/phpunit/includes/phpunit6/compat.php
r44700 r44701 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(); -
trunk/tests/phpunit/includes/phpunit7/speed-trap-listener.php
r44700 r44701 55 55 * @param float $time 56 56 */ 57 public function addError( PHPUnit _Framework_Test $test, Exception $e, $time ){57 public function addError( PHPUnit\Framework\Test $test, Throwable $t, float $time ): void { 58 58 } 59 59 … … 66 66 * @since Method available since Release 5.1.0 67 67 */ 68 public function addWarning( PHPUnit _Framework_Test $test, PHPUnit_Framework_Warning $e, $time ){68 public function addWarning( PHPUnit\Framework\Test $test, PHPUnit\Framework\Warning $e, float $time ): void { 69 69 } 70 70 … … 76 76 * @param float $time 77 77 */ 78 public function addFailure( PHPUnit _Framework_Test $test, PHPUnit_Framework_AssertionFailedError $e, $time ){78 public function addFailure( PHPUnit\Framework\Test $test, PHPUnit\Framework\AssertionFailedError $e, float $time ): void { 79 79 } 80 80 … … 86 86 * @param float $time 87 87 */ 88 public function addIncompleteTest( PHPUnit _Framework_Test $test, Exception $e, $time ){88 public function addIncompleteTest( PHPUnit\Framework\Test $test, Throwable $t, float $time ): void { 89 89 } 90 90 … … 97 97 * @since Method available since Release 4.0.0 98 98 */ 99 public function addRiskyTest( PHPUnit _Framework_Test $test, Exception $e, $time ){99 public function addRiskyTest( PHPUnit\Framework\Test $test, Throwable $t, float $time ): void { 100 100 } 101 101 … … 107 107 * @param float $time 108 108 */ 109 public function addSkippedTest( PHPUnit _Framework_Test $test, Exception $e, $time ){109 public function addSkippedTest( PHPUnit\Framework\Test $test, Throwable $t, float $time ): void { 110 110 } 111 111 … … 115 115 * @param PHPUnit_Framework_Test $test 116 116 */ 117 public function startTest( PHPUnit _Framework_Test $test ){117 public function startTest( PHPUnit\Framework\Test $test ): void { 118 118 } 119 119 … … 124 124 * @param float $time 125 125 */ 126 public function endTest( PHPUnit _Framework_Test $test, $time ){126 public function endTest( PHPUnit\Framework\Test $test, float $time ): void { 127 127 if ( ! $test instanceof PHPUnit_Framework_TestCase ) { 128 128 return; … … 142 142 * @param PHPUnit_Framework_TestSuite $suite 143 143 */ 144 public function startTestSuite( PHPUnit _Framework_TestSuite $suite ){144 public function startTestSuite( PHPUnit\Framework\TestSuite $suite ): void { 145 145 $this->suites++; 146 146 } … … 151 151 * @param PHPUnit_Framework_TestSuite $suite 152 152 */ 153 public function endTestSuite( PHPUnit _Framework_TestSuite $suite ){153 public function endTestSuite( PHPUnit\Framework\TestSuite $suite ): void { 154 154 $this->suites--; 155 155 -
trunk/tests/phpunit/includes/phpunit7/testcase.php
r44700 r44701 1 1 <?php 2 2 3 require_once dirname( __FILE__ ) . '/factory.php'; 4 require_once dirname( __FILE__ ) . '/trac.php'; 3 require_once dirname( dirname( __FILE__ ) ) . '/abstract-testcase.php'; 5 4 6 5 /** … … 13 12 * All WordPress unit tests should inherit from this class. 14 13 */ 15 class WP_UnitTestCase extends PHPUnit_Framework_TestCase { 16 17 protected static $forced_tickets = array(); 18 protected $expected_deprecated = array(); 19 protected $caught_deprecated = array(); 20 protected $expected_doing_it_wrong = array(); 21 protected $caught_doing_it_wrong = array(); 22 23 protected static $hooks_saved = array(); 24 protected static $ignore_files; 25 26 function __isset( $name ) { 27 return 'factory' === $name; 28 } 29 30 function __get( $name ) { 31 if ( 'factory' === $name ) { 32 return self::factory(); 33 } 34 } 35 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 278 * on a class variable 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 14 class WP_UnitTestCase extends WP_UnitTestCase_Base { 587 15 /** 588 16 * Asserts that a condition is not false. … … 598 26 * @throws PHPUnit_Framework_AssertionFailedError 599 27 */ 600 public static function assertNotFalse( $condition, $message = '' ){28 public static function assertNotFalse( $condition, string $message = '' ): void { 601 29 self::assertThat( $condition, self::logicalNot( self::isFalse() ), $message ); 602 30 } 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 31 } -
trunk/tests/phpunit/includes/testcase-canonical.php
r42343 r44701 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 ) ) { -
trunk/tests/phpunit/includes/testcase.php
r44633 r44701 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 6 5 /** … … 13 12 * All WordPress unit tests should inherit from this class. 14 13 */ 15 class WP_UnitTestCase extends PHPUnit_Framework_TestCase { 16 17 protected static $forced_tickets = array(); 18 protected $expected_deprecated = array(); 19 protected $caught_deprecated = array(); 20 protected $expected_doing_it_wrong = array(); 21 protected $caught_doing_it_wrong = array(); 22 23 protected static $hooks_saved = array(); 24 protected static $ignore_files; 25 26 function __isset( $name ) { 27 return 'factory' === $name; 28 } 29 30 function __get( $name ) { 31 if ( 'factory' === $name ) { 32 return self::factory(); 33 } 34 } 35 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 278 * on a class variable 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 } 14 class WP_UnitTestCase extends WP_UnitTestCase_Base { 586 15 587 16 /** … … 601 30 self::assertThat( $condition, self::logicalNot( self::isFalse() ), $message ); 602 31 } 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 32 } -
trunk/tests/phpunit/multisite.xml
r44128 r44701 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> -
trunk/tests/phpunit/tests/post/query.php
r44456 r44701 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() );
Note: See TracChangeset
for help on using the changeset viewer.