| 1 | <?php |
|---|
| 2 | |
|---|
| 3 | require_once dirname( __FILE__ ) . '/factory.php'; |
|---|
| 4 | require_once dirname( __FILE__ ) . '/trac.php'; |
|---|
| 5 | |
|---|
| 6 | class WP_UnitTestCase extends PHPUnit_Framework_TestCase { |
|---|
| 7 | |
|---|
| 8 | protected static $forced_tickets = array(); |
|---|
| 9 | protected $expected_deprecated = array(); |
|---|
| 10 | protected $caught_deprecated = array(); |
|---|
| 11 | protected $expected_doing_it_wrong = array(); |
|---|
| 12 | protected $caught_doing_it_wrong = array(); |
|---|
| 13 | |
|---|
| 14 | protected static $hooks_saved = array(); |
|---|
| 15 | protected static $ignore_files; |
|---|
| 16 | |
|---|
| 17 | function __isset( $name ) { |
|---|
| 18 | return 'factory' === $name; |
|---|
| 19 | } |
|---|
| 20 | |
|---|
| 21 | function __get( $name ) { |
|---|
| 22 | if ( 'factory' === $name ) { |
|---|
| 23 | return self::factory(); |
|---|
| 24 | } |
|---|
| 25 | } |
|---|
| 26 | |
|---|
| 27 | protected static function factory() { |
|---|
| 28 | static $factory = null; |
|---|
| 29 | if ( ! $factory ) { |
|---|
| 30 | $factory = new WP_UnitTest_Factory(); |
|---|
| 31 | } |
|---|
| 32 | return $factory; |
|---|
| 33 | } |
|---|
| 34 | |
|---|
| 35 | public static function get_called_class() { |
|---|
| 36 | if ( function_exists( 'get_called_class' ) ) { |
|---|
| 37 | return get_called_class(); |
|---|
| 38 | } |
|---|
| 39 | |
|---|
| 40 | // PHP 5.2 only |
|---|
| 41 | $backtrace = debug_backtrace(); |
|---|
| 42 | // [0] WP_UnitTestCase::get_called_class() |
|---|
| 43 | // [1] WP_UnitTestCase::setUpBeforeClass() |
|---|
| 44 | if ( 'call_user_func' === $backtrace[2]['function'] ) { |
|---|
| 45 | return $backtrace[2]['args'][0][0]; |
|---|
| 46 | } |
|---|
| 47 | return $backtrace[2]['class']; |
|---|
| 48 | } |
|---|
| 49 | |
|---|
| 50 | public static function setUpBeforeClass() { |
|---|
| 51 | parent::setUpBeforeClass(); |
|---|
| 52 | |
|---|
| 53 | $c = self::get_called_class(); |
|---|
| 54 | if ( ! method_exists( $c, 'wpSetUpBeforeClass' ) ) { |
|---|
| 55 | return; |
|---|
| 56 | } |
|---|
| 57 | |
|---|
| 58 | call_user_func( array( $c, 'wpSetUpBeforeClass' ), self::factory() ); |
|---|
| 59 | |
|---|
| 60 | self::commit_transaction(); |
|---|
| 61 | } |
|---|
| 62 | |
|---|
| 63 | public static function tearDownAfterClass() { |
|---|
| 64 | parent::tearDownAfterClass(); |
|---|
| 65 | |
|---|
| 66 | $c = self::get_called_class(); |
|---|
| 67 | if ( ! method_exists( $c, 'wpTearDownAfterClass' ) ) { |
|---|
| 68 | return; |
|---|
| 69 | } |
|---|
| 70 | |
|---|
| 71 | call_user_func( array( $c, 'wpTearDownAfterClass' ) ); |
|---|
| 72 | |
|---|
| 73 | self::commit_transaction(); |
|---|
| 74 | } |
|---|
| 75 | |
|---|
| 76 | function setUp() { |
|---|
| 77 | set_time_limit(0); |
|---|
| 78 | |
|---|
| 79 | if ( ! self::$ignore_files ) { |
|---|
| 80 | self::$ignore_files = $this->scan_user_uploads(); |
|---|
| 81 | } |
|---|
| 82 | |
|---|
| 83 | if ( ! self::$hooks_saved ) { |
|---|
| 84 | $this->_backup_hooks(); |
|---|
| 85 | } |
|---|
| 86 | |
|---|
| 87 | global $wpdb, $wp_rewrite; |
|---|
| 88 | $wpdb->suppress_errors = false; |
|---|
| 89 | $wpdb->show_errors = true; |
|---|
| 90 | $wpdb->db_connect(); |
|---|
| 91 | ini_set('display_errors', 1 ); |
|---|
| 92 | $this->clean_up_global_scope(); |
|---|
| 93 | |
|---|
| 94 | /* |
|---|
| 95 | * When running core tests, ensure that post types and taxonomies |
|---|
| 96 | * are reset for each test. We skip this step for non-core tests, |
|---|
| 97 | * given the large number of plugins that register post types and |
|---|
| 98 | * taxonomies at 'init'. |
|---|
| 99 | */ |
|---|
| 100 | if ( defined( 'WP_RUN_CORE_TESTS' ) && WP_RUN_CORE_TESTS ) { |
|---|
| 101 | $this->reset_post_types(); |
|---|
| 102 | $this->reset_taxonomies(); |
|---|
| 103 | $this->reset_post_statuses(); |
|---|
| 104 | |
|---|
| 105 | if ( $wp_rewrite->permalink_structure ) { |
|---|
| 106 | $this->set_permalink_structure( '' ); |
|---|
| 107 | } |
|---|
| 108 | } |
|---|
| 109 | |
|---|
| 110 | $this->start_transaction(); |
|---|
| 111 | $this->expectDeprecated(); |
|---|
| 112 | add_filter( 'wp_die_handler', array( $this, 'get_wp_die_handler' ) ); |
|---|
| 113 | } |
|---|
| 114 | |
|---|
| 115 | /** |
|---|
| 116 | * Detect post-test failure conditions. |
|---|
| 117 | * |
|---|
| 118 | * We use this method to detect expectedDeprecated and expectedIncorrectUsage annotations. |
|---|
| 119 | * |
|---|
| 120 | * @since 4.2.0 |
|---|
| 121 | */ |
|---|
| 122 | protected function assertPostConditions() { |
|---|
| 123 | $this->expectedDeprecated(); |
|---|
| 124 | } |
|---|
| 125 | |
|---|
| 126 | function tearDown() { |
|---|
| 127 | global $wpdb, $wp_query, $wp, $post; |
|---|
| 128 | $wpdb->query( 'ROLLBACK' ); |
|---|
| 129 | if ( is_multisite() ) { |
|---|
| 130 | while ( ms_is_switched() ) { |
|---|
| 131 | restore_current_blog(); |
|---|
| 132 | } |
|---|
| 133 | } |
|---|
| 134 | $wp_query = new WP_Query(); |
|---|
| 135 | $wp = new WP(); |
|---|
| 136 | $post = null; |
|---|
| 137 | remove_theme_support( 'html5' ); |
|---|
| 138 | remove_filter( 'query', array( $this, '_create_temporary_tables' ) ); |
|---|
| 139 | remove_filter( 'query', array( $this, '_drop_temporary_tables' ) ); |
|---|
| 140 | remove_filter( 'wp_die_handler', array( $this, 'get_wp_die_handler' ) ); |
|---|
| 141 | $this->_restore_hooks(); |
|---|
| 142 | wp_set_current_user( 0 ); |
|---|
| 143 | } |
|---|
| 144 | |
|---|
| 145 | function clean_up_global_scope() { |
|---|
| 146 | $_GET = array(); |
|---|
| 147 | $_POST = array(); |
|---|
| 148 | $this->flush_cache(); |
|---|
| 149 | } |
|---|
| 150 | |
|---|
| 151 | /** |
|---|
| 152 | * Unregister existing post types and register defaults. |
|---|
| 153 | * |
|---|
| 154 | * Run before each test in order to clean up the global scope, in case |
|---|
| 155 | * a test forgets to unregister a post type on its own, or fails before |
|---|
| 156 | * it has a chance to do so. |
|---|
| 157 | */ |
|---|
| 158 | protected function reset_post_types() { |
|---|
| 159 | foreach ( get_post_types() as $pt ) { |
|---|
| 160 | _unregister_post_type( $pt ); |
|---|
| 161 | } |
|---|
| 162 | create_initial_post_types(); |
|---|
| 163 | } |
|---|
| 164 | |
|---|
| 165 | /** |
|---|
| 166 | * Unregister existing taxonomies and register defaults. |
|---|
| 167 | * |
|---|
| 168 | * Run before each test in order to clean up the global scope, in case |
|---|
| 169 | * a test forgets to unregister a taxonomy on its own, or fails before |
|---|
| 170 | * it has a chance to do so. |
|---|
| 171 | */ |
|---|
| 172 | protected function reset_taxonomies() { |
|---|
| 173 | foreach ( get_taxonomies() as $tax ) { |
|---|
| 174 | _unregister_taxonomy( $tax ); |
|---|
| 175 | } |
|---|
| 176 | create_initial_taxonomies(); |
|---|
| 177 | } |
|---|
| 178 | |
|---|
| 179 | /** |
|---|
| 180 | * Unregister non-built-in post statuses. |
|---|
| 181 | */ |
|---|
| 182 | protected function reset_post_statuses() { |
|---|
| 183 | foreach ( get_post_stati( array( '_builtin' => false ) ) as $post_status ) { |
|---|
| 184 | _unregister_post_status( $post_status ); |
|---|
| 185 | } |
|---|
| 186 | } |
|---|
| 187 | |
|---|
| 188 | /** |
|---|
| 189 | * Saves the action and filter-related globals so they can be restored later. |
|---|
| 190 | * |
|---|
| 191 | * Stores $merged_filters, $wp_actions, $wp_current_filter, and $wp_filter |
|---|
| 192 | * on a class variable so they can be restored on tearDown() using _restore_hooks(). |
|---|
| 193 | * |
|---|
| 194 | * @global array $merged_filters |
|---|
| 195 | * @global array $wp_actions |
|---|
| 196 | * @global array $wp_current_filter |
|---|
| 197 | * @global array $wp_filter |
|---|
| 198 | * @return void |
|---|
| 199 | */ |
|---|
| 200 | protected function _backup_hooks() { |
|---|
| 201 | $globals = array( 'merged_filters', 'wp_actions', 'wp_current_filter', 'wp_filter' ); |
|---|
| 202 | foreach ( $globals as $key ) { |
|---|
| 203 | self::$hooks_saved[ $key ] = $GLOBALS[ $key ]; |
|---|
| 204 | } |
|---|
| 205 | } |
|---|
| 206 | |
|---|
| 207 | /** |
|---|
| 208 | * Restores the hook-related globals to their state at setUp() |
|---|
| 209 | * so that future tests aren't affected by hooks set during this last test. |
|---|
| 210 | * |
|---|
| 211 | * @global array $merged_filters |
|---|
| 212 | * @global array $wp_actions |
|---|
| 213 | * @global array $wp_current_filter |
|---|
| 214 | * @global array $wp_filter |
|---|
| 215 | * @return void |
|---|
| 216 | */ |
|---|
| 217 | protected function _restore_hooks() { |
|---|
| 218 | $globals = array( 'merged_filters', 'wp_actions', 'wp_current_filter', 'wp_filter' ); |
|---|
| 219 | foreach ( $globals as $key ) { |
|---|
| 220 | if ( isset( self::$hooks_saved[ $key ] ) ) { |
|---|
| 221 | $GLOBALS[ $key ] = self::$hooks_saved[ $key ]; |
|---|
| 222 | } |
|---|
| 223 | } |
|---|
| 224 | } |
|---|
| 225 | |
|---|
| 226 | function flush_cache() { |
|---|
| 227 | global $wp_object_cache; |
|---|
| 228 | $wp_object_cache->group_ops = array(); |
|---|
| 229 | $wp_object_cache->stats = array(); |
|---|
| 230 | $wp_object_cache->memcache_debug = array(); |
|---|
| 231 | $wp_object_cache->cache = array(); |
|---|
| 232 | if ( method_exists( $wp_object_cache, '__remoteset' ) ) { |
|---|
| 233 | $wp_object_cache->__remoteset(); |
|---|
| 234 | } |
|---|
| 235 | wp_cache_flush(); |
|---|
| 236 | wp_cache_add_global_groups( array( 'users', 'userlogins', 'usermeta', 'user_meta', 'site-transient', 'site-options', 'site-lookup', 'blog-lookup', 'blog-details', 'rss', 'global-posts', 'blog-id-cache' ) ); |
|---|
| 237 | wp_cache_add_non_persistent_groups( array( 'comment', 'counts', 'plugins' ) ); |
|---|
| 238 | } |
|---|
| 239 | |
|---|
| 240 | function start_transaction() { |
|---|
| 241 | global $wpdb; |
|---|
| 242 | $wpdb->query( 'SET autocommit = 0;' ); |
|---|
| 243 | $wpdb->query( 'START TRANSACTION;' ); |
|---|
| 244 | add_filter( 'query', array( $this, '_create_temporary_tables' ) ); |
|---|
| 245 | add_filter( 'query', array( $this, '_drop_temporary_tables' ) ); |
|---|
| 246 | } |
|---|
| 247 | |
|---|
| 248 | /** |
|---|
| 249 | * Commit the queries in a transaction. |
|---|
| 250 | * |
|---|
| 251 | * @since 4.1.0 |
|---|
| 252 | */ |
|---|
| 253 | public static function commit_transaction() { |
|---|
| 254 | global $wpdb; |
|---|
| 255 | $wpdb->query( 'COMMIT;' ); |
|---|
| 256 | } |
|---|
| 257 | |
|---|
| 258 | function _create_temporary_tables( $query ) { |
|---|
| 259 | if ( 'CREATE TABLE' === substr( trim( $query ), 0, 12 ) ) |
|---|
| 260 | return substr_replace( trim( $query ), 'CREATE TEMPORARY TABLE', 0, 12 ); |
|---|
| 261 | return $query; |
|---|
| 262 | } |
|---|
| 263 | |
|---|
| 264 | function _drop_temporary_tables( $query ) { |
|---|
| 265 | if ( 'DROP TABLE' === substr( trim( $query ), 0, 10 ) ) |
|---|
| 266 | return substr_replace( trim( $query ), 'DROP TEMPORARY TABLE', 0, 10 ); |
|---|
| 267 | return $query; |
|---|
| 268 | } |
|---|
| 269 | |
|---|
| 270 | function get_wp_die_handler( $handler ) { |
|---|
| 271 | return array( $this, 'wp_die_handler' ); |
|---|
| 272 | } |
|---|
| 273 | |
|---|
| 274 | function wp_die_handler( $message ) { |
|---|
| 275 | throw new WPDieException( $message ); |
|---|
| 276 | } |
|---|
| 277 | |
|---|
| 278 | function expectDeprecated() { |
|---|
| 279 | $annotations = $this->getAnnotations(); |
|---|
| 280 | foreach ( array( 'class', 'method' ) as $depth ) { |
|---|
| 281 | if ( ! empty( $annotations[ $depth ]['expectedDeprecated'] ) ) |
|---|
| 282 | $this->expected_deprecated = array_merge( $this->expected_deprecated, $annotations[ $depth ]['expectedDeprecated'] ); |
|---|
| 283 | if ( ! empty( $annotations[ $depth ]['expectedIncorrectUsage'] ) ) |
|---|
| 284 | $this->expected_doing_it_wrong = array_merge( $this->expected_doing_it_wrong, $annotations[ $depth ]['expectedIncorrectUsage'] ); |
|---|
| 285 | } |
|---|
| 286 | add_action( 'deprecated_function_run', array( $this, 'deprecated_function_run' ) ); |
|---|
| 287 | add_action( 'deprecated_argument_run', array( $this, 'deprecated_function_run' ) ); |
|---|
| 288 | add_action( 'doing_it_wrong_run', array( $this, 'doing_it_wrong_run' ) ); |
|---|
| 289 | add_action( 'deprecated_function_trigger_error', '__return_false' ); |
|---|
| 290 | add_action( 'deprecated_argument_trigger_error', '__return_false' ); |
|---|
| 291 | add_action( 'doing_it_wrong_trigger_error', '__return_false' ); |
|---|
| 292 | } |
|---|
| 293 | |
|---|
| 294 | function expectedDeprecated() { |
|---|
| 295 | $errors = array(); |
|---|
| 296 | |
|---|
| 297 | $not_caught_deprecated = array_diff( $this->expected_deprecated, $this->caught_deprecated ); |
|---|
| 298 | foreach ( $not_caught_deprecated as $not_caught ) { |
|---|
| 299 | $errors[] = "Failed to assert that $not_caught triggered a deprecated notice"; |
|---|
| 300 | } |
|---|
| 301 | |
|---|
| 302 | $unexpected_deprecated = array_diff( $this->caught_deprecated, $this->expected_deprecated ); |
|---|
| 303 | foreach ( $unexpected_deprecated as $unexpected ) { |
|---|
| 304 | $errors[] = "Unexpected deprecated notice for $unexpected"; |
|---|
| 305 | } |
|---|
| 306 | |
|---|
| 307 | $not_caught_doing_it_wrong = array_diff( $this->expected_doing_it_wrong, $this->caught_doing_it_wrong ); |
|---|
| 308 | foreach ( $not_caught_doing_it_wrong as $not_caught ) { |
|---|
| 309 | $errors[] = "Failed to assert that $not_caught triggered an incorrect usage notice"; |
|---|
| 310 | } |
|---|
| 311 | |
|---|
| 312 | $unexpected_doing_it_wrong = array_diff( $this->caught_doing_it_wrong, $this->expected_doing_it_wrong ); |
|---|
| 313 | foreach ( $unexpected_doing_it_wrong as $unexpected ) { |
|---|
| 314 | $errors[] = "Unexpected incorrect usage notice for $unexpected"; |
|---|
| 315 | } |
|---|
| 316 | |
|---|
| 317 | if ( ! empty( $errors ) ) { |
|---|
| 318 | $this->fail( implode( "\n", $errors ) ); |
|---|
| 319 | } |
|---|
| 320 | } |
|---|
| 321 | |
|---|
| 322 | /** |
|---|
| 323 | * Declare an expected `_deprecated_function()` or `_deprecated_argument()` call from within a test. |
|---|
| 324 | * |
|---|
| 325 | * @since 4.2.0 |
|---|
| 326 | * |
|---|
| 327 | * @param string $deprecated Name of the function, method, class, or argument that is deprecated. Must match |
|---|
| 328 | * first parameter of the `_deprecated_function()` or `_deprecated_argument()` call. |
|---|
| 329 | */ |
|---|
| 330 | public function setExpectedDeprecated( $deprecated ) { |
|---|
| 331 | array_push( $this->expected_deprecated, $deprecated ); |
|---|
| 332 | } |
|---|
| 333 | |
|---|
| 334 | /** |
|---|
| 335 | * Declare an expected `_doing_it_wrong()` call from within a test. |
|---|
| 336 | * |
|---|
| 337 | * @since 4.2.0 |
|---|
| 338 | * |
|---|
| 339 | * @param string $deprecated Name of the function, method, or class that appears in the first argument of the |
|---|
| 340 | * source `_doing_it_wrong()` call. |
|---|
| 341 | */ |
|---|
| 342 | public function setExpectedIncorrectUsage( $doing_it_wrong ) { |
|---|
| 343 | array_push( $this->expected_doing_it_wrong, $doing_it_wrong ); |
|---|
| 344 | } |
|---|
| 345 | |
|---|
| 346 | function deprecated_function_run( $function ) { |
|---|
| 347 | if ( ! in_array( $function, $this->caught_deprecated ) ) |
|---|
| 348 | $this->caught_deprecated[] = $function; |
|---|
| 349 | } |
|---|
| 350 | |
|---|
| 351 | function doing_it_wrong_run( $function ) { |
|---|
| 352 | if ( ! in_array( $function, $this->caught_doing_it_wrong ) ) |
|---|
| 353 | $this->caught_doing_it_wrong[] = $function; |
|---|
| 354 | } |
|---|
| 355 | |
|---|
| 356 | function assertWPError( $actual, $message = '' ) { |
|---|
| 357 | $this->assertInstanceOf( 'WP_Error', $actual, $message ); |
|---|
| 358 | } |
|---|
| 359 | |
|---|
| 360 | function assertNotWPError( $actual, $message = '' ) { |
|---|
| 361 | if ( is_wp_error( $actual ) && '' === $message ) { |
|---|
| 362 | $message = $actual->get_error_message(); |
|---|
| 363 | } |
|---|
| 364 | $this->assertNotInstanceOf( 'WP_Error', $actual, $message ); |
|---|
| 365 | } |
|---|
| 366 | |
|---|
| 367 | function assertEqualFields( $object, $fields ) { |
|---|
| 368 | foreach( $fields as $field_name => $field_value ) { |
|---|
| 369 | if ( $object->$field_name != $field_value ) { |
|---|
| 370 | $this->fail(); |
|---|
| 371 | } |
|---|
| 372 | } |
|---|
| 373 | } |
|---|
| 374 | |
|---|
| 375 | function assertDiscardWhitespace( $expected, $actual ) { |
|---|
| 376 | $this->assertEquals( preg_replace( '/\s*/', '', $expected ), preg_replace( '/\s*/', '', $actual ) ); |
|---|
| 377 | } |
|---|
| 378 | |
|---|
| 379 | function assertEqualSets( $expected, $actual ) { |
|---|
| 380 | sort( $expected ); |
|---|
| 381 | sort( $actual ); |
|---|
| 382 | $this->assertEquals( $expected, $actual ); |
|---|
| 383 | } |
|---|
| 384 | |
|---|
| 385 | function assertEqualSetsWithIndex( $expected, $actual ) { |
|---|
| 386 | ksort( $expected ); |
|---|
| 387 | ksort( $actual ); |
|---|
| 388 | $this->assertEquals( $expected, $actual ); |
|---|
| 389 | } |
|---|
| 390 | |
|---|
| 391 | function go_to( $url ) { |
|---|
| 392 | // note: the WP and WP_Query classes like to silently fetch parameters |
|---|
| 393 | // from all over the place (globals, GET, etc), which makes it tricky |
|---|
| 394 | // to run them more than once without very carefully clearing everything |
|---|
| 395 | $_GET = $_POST = array(); |
|---|
| 396 | foreach (array('query_string', 'id', 'postdata', 'authordata', 'day', 'currentmonth', 'page', 'pages', 'multipage', 'more', 'numpages', 'pagenow') as $v) { |
|---|
| 397 | if ( isset( $GLOBALS[$v] ) ) unset( $GLOBALS[$v] ); |
|---|
| 398 | } |
|---|
| 399 | $parts = parse_url($url); |
|---|
| 400 | if (isset($parts['scheme'])) { |
|---|
| 401 | $req = isset( $parts['path'] ) ? $parts['path'] : ''; |
|---|
| 402 | if (isset($parts['query'])) { |
|---|
| 403 | $req .= '?' . $parts['query']; |
|---|
| 404 | // parse the url query vars into $_GET |
|---|
| 405 | parse_str($parts['query'], $_GET); |
|---|
| 406 | } |
|---|
| 407 | } else { |
|---|
| 408 | $req = $url; |
|---|
| 409 | } |
|---|
| 410 | if ( ! isset( $parts['query'] ) ) { |
|---|
| 411 | $parts['query'] = ''; |
|---|
| 412 | } |
|---|
| 413 | |
|---|
| 414 | $_SERVER['REQUEST_URI'] = $req; |
|---|
| 415 | unset($_SERVER['PATH_INFO']); |
|---|
| 416 | |
|---|
| 417 | $this->flush_cache(); |
|---|
| 418 | unset($GLOBALS['wp_query'], $GLOBALS['wp_the_query']); |
|---|
| 419 | $GLOBALS['wp_the_query'] = new WP_Query(); |
|---|
| 420 | $GLOBALS['wp_query'] = $GLOBALS['wp_the_query']; |
|---|
| 421 | |
|---|
| 422 | $public_query_vars = $GLOBALS['wp']->public_query_vars; |
|---|
| 423 | $private_query_vars = $GLOBALS['wp']->private_query_vars; |
|---|
| 424 | |
|---|
| 425 | $GLOBALS['wp'] = new WP(); |
|---|
| 426 | $GLOBALS['wp']->public_query_vars = $public_query_vars; |
|---|
| 427 | $GLOBALS['wp']->private_query_vars = $private_query_vars; |
|---|
| 428 | |
|---|
| 429 | _cleanup_query_vars(); |
|---|
| 430 | |
|---|
| 431 | $GLOBALS['wp']->main($parts['query']); |
|---|
| 432 | } |
|---|
| 433 | |
|---|
| 434 | protected function checkRequirements() { |
|---|
| 435 | parent::checkRequirements(); |
|---|
| 436 | |
|---|
| 437 | // Core tests no longer check against open Trac tickets, but others using WP_UnitTestCase may do so. |
|---|
| 438 | if ( defined( 'WP_RUN_CORE_TESTS' ) && WP_RUN_CORE_TESTS ) { |
|---|
| 439 | return; |
|---|
| 440 | } |
|---|
| 441 | |
|---|
| 442 | if ( WP_TESTS_FORCE_KNOWN_BUGS ) |
|---|
| 443 | return; |
|---|
| 444 | $tickets = PHPUnit_Util_Test::getTickets( get_class( $this ), $this->getName( false ) ); |
|---|
| 445 | foreach ( $tickets as $ticket ) { |
|---|
| 446 | if ( is_numeric( $ticket ) ) { |
|---|
| 447 | $this->knownWPBug( $ticket ); |
|---|
| 448 | } elseif ( 'UT' == substr( $ticket, 0, 2 ) ) { |
|---|
| 449 | $ticket = substr( $ticket, 2 ); |
|---|
| 450 | if ( $ticket && is_numeric( $ticket ) ) |
|---|
| 451 | $this->knownUTBug( $ticket ); |
|---|
| 452 | } elseif ( 'Plugin' == substr( $ticket, 0, 6 ) ) { |
|---|
| 453 | $ticket = substr( $ticket, 6 ); |
|---|
| 454 | if ( $ticket && is_numeric( $ticket ) ) |
|---|
| 455 | $this->knownPluginBug( $ticket ); |
|---|
| 456 | } |
|---|
| 457 | } |
|---|
| 458 | } |
|---|
| 459 | |
|---|
| 460 | /** |
|---|
| 461 | * Skips the current test if there is an open WordPress ticket with id $ticket_id |
|---|
| 462 | */ |
|---|
| 463 | function knownWPBug( $ticket_id ) { |
|---|
| 464 | if ( WP_TESTS_FORCE_KNOWN_BUGS || in_array( $ticket_id, self::$forced_tickets ) ) |
|---|
| 465 | return; |
|---|
| 466 | if ( ! TracTickets::isTracTicketClosed( 'https://core.trac.wordpress.org', $ticket_id ) ) |
|---|
| 467 | $this->markTestSkipped( sprintf( 'WordPress Ticket #%d is not fixed', $ticket_id ) ); |
|---|
| 468 | } |
|---|
| 469 | |
|---|
| 470 | /** |
|---|
| 471 | * Skips the current test if there is an open unit tests ticket with id $ticket_id |
|---|
| 472 | */ |
|---|
| 473 | function knownUTBug( $ticket_id ) { |
|---|
| 474 | if ( WP_TESTS_FORCE_KNOWN_BUGS || in_array( 'UT' . $ticket_id, self::$forced_tickets ) ) |
|---|
| 475 | return; |
|---|
| 476 | if ( ! TracTickets::isTracTicketClosed( 'https://unit-tests.trac.wordpress.org', $ticket_id ) ) |
|---|
| 477 | $this->markTestSkipped( sprintf( 'Unit Tests Ticket #%d is not fixed', $ticket_id ) ); |
|---|
| 478 | } |
|---|
| 479 | |
|---|
| 480 | /** |
|---|
| 481 | * Skips the current test if there is an open plugin ticket with id $ticket_id |
|---|
| 482 | */ |
|---|
| 483 | function knownPluginBug( $ticket_id ) { |
|---|
| 484 | if ( WP_TESTS_FORCE_KNOWN_BUGS || in_array( 'Plugin' . $ticket_id, self::$forced_tickets ) ) |
|---|
| 485 | return; |
|---|
| 486 | if ( ! TracTickets::isTracTicketClosed( 'https://plugins.trac.wordpress.org', $ticket_id ) ) |
|---|
| 487 | $this->markTestSkipped( sprintf( 'WordPress Plugin Ticket #%d is not fixed', $ticket_id ) ); |
|---|
| 488 | } |
|---|
| 489 | |
|---|
| 490 | public static function forceTicket( $ticket ) { |
|---|
| 491 | self::$forced_tickets[] = $ticket; |
|---|
| 492 | } |
|---|
| 493 | |
|---|
| 494 | /** |
|---|
| 495 | * Define constants after including files. |
|---|
| 496 | */ |
|---|
| 497 | function prepareTemplate( Text_Template $template ) { |
|---|
| 498 | $template->setVar( array( 'constants' => '' ) ); |
|---|
| 499 | $template->setVar( array( 'wp_constants' => PHPUnit_Util_GlobalState::getConstantsAsString() ) ); |
|---|
| 500 | parent::prepareTemplate( $template ); |
|---|
| 501 | } |
|---|
| 502 | |
|---|
| 503 | /** |
|---|
| 504 | * Returns the name of a temporary file |
|---|
| 505 | */ |
|---|
| 506 | function temp_filename() { |
|---|
| 507 | $tmp_dir = ''; |
|---|
| 508 | $dirs = array( 'TMP', 'TMPDIR', 'TEMP' ); |
|---|
| 509 | foreach( $dirs as $dir ) |
|---|
| 510 | if ( isset( $_ENV[$dir] ) && !empty( $_ENV[$dir] ) ) { |
|---|
| 511 | $tmp_dir = $dir; |
|---|
| 512 | break; |
|---|
| 513 | } |
|---|
| 514 | if ( empty( $tmp_dir ) ) { |
|---|
| 515 | $tmp_dir = '/tmp'; |
|---|
| 516 | } |
|---|
| 517 | $tmp_dir = realpath( $tmp_dir ); |
|---|
| 518 | return tempnam( $tmp_dir, 'wpunit' ); |
|---|
| 519 | } |
|---|
| 520 | |
|---|
| 521 | /** |
|---|
| 522 | * Check each of the WP_Query is_* functions/properties against expected boolean value. |
|---|
| 523 | * |
|---|
| 524 | * Any properties that are listed by name as parameters will be expected to be true; any others are |
|---|
| 525 | * expected to be false. For example, assertQueryTrue('is_single', 'is_feed') means is_single() |
|---|
| 526 | * and is_feed() must be true and everything else must be false to pass. |
|---|
| 527 | * |
|---|
| 528 | * @param string $prop,... Any number of WP_Query properties that are expected to be true for the current request. |
|---|
| 529 | */ |
|---|
| 530 | function assertQueryTrue(/* ... */) { |
|---|
| 531 | global $wp_query; |
|---|
| 532 | $all = array( |
|---|
| 533 | 'is_404', |
|---|
| 534 | 'is_admin', |
|---|
| 535 | 'is_archive', |
|---|
| 536 | 'is_attachment', |
|---|
| 537 | 'is_author', |
|---|
| 538 | 'is_category', |
|---|
| 539 | 'is_comment_feed', |
|---|
| 540 | 'is_comments_popup', |
|---|
| 541 | 'is_date', |
|---|
| 542 | 'is_day', |
|---|
| 543 | 'is_embed', |
|---|
| 544 | 'is_feed', |
|---|
| 545 | 'is_home', |
|---|
| 546 | 'is_month', |
|---|
| 547 | 'is_page', |
|---|
| 548 | 'is_paged', |
|---|
| 549 | 'is_post_type_archive', |
|---|
| 550 | 'is_posts_page', |
|---|
| 551 | 'is_preview', |
|---|
| 552 | 'is_robots', |
|---|
| 553 | 'is_search', |
|---|
| 554 | 'is_single', |
|---|
| 555 | 'is_singular', |
|---|
| 556 | 'is_tag', |
|---|
| 557 | 'is_tax', |
|---|
| 558 | 'is_time', |
|---|
| 559 | 'is_trackback', |
|---|
| 560 | 'is_year', |
|---|
| 561 | ); |
|---|
| 562 | $true = func_get_args(); |
|---|
| 563 | |
|---|
| 564 | $passed = true; |
|---|
| 565 | $not_false = $not_true = array(); // properties that were not set to expected values |
|---|
| 566 | |
|---|
| 567 | foreach ( $all as $query_thing ) { |
|---|
| 568 | $result = is_callable( $query_thing ) ? call_user_func( $query_thing ) : $wp_query->$query_thing; |
|---|
| 569 | |
|---|
| 570 | if ( in_array( $query_thing, $true ) ) { |
|---|
| 571 | if ( ! $result ) { |
|---|
| 572 | array_push( $not_true, $query_thing ); |
|---|
| 573 | $passed = false; |
|---|
| 574 | } |
|---|
| 575 | } else if ( $result ) { |
|---|
| 576 | array_push( $not_false, $query_thing ); |
|---|
| 577 | $passed = false; |
|---|
| 578 | } |
|---|
| 579 | } |
|---|
| 580 | |
|---|
| 581 | $message = ''; |
|---|
| 582 | if ( count($not_true) ) |
|---|
| 583 | $message .= implode( $not_true, ', ' ) . ' is expected to be true. '; |
|---|
| 584 | if ( count($not_false) ) |
|---|
| 585 | $message .= implode( $not_false, ', ' ) . ' is expected to be false.'; |
|---|
| 586 | $this->assertTrue( $passed, $message ); |
|---|
| 587 | } |
|---|
| 588 | |
|---|
| 589 | function unlink( $file ) { |
|---|
| 590 | $exists = is_file( $file ); |
|---|
| 591 | if ( $exists && ! in_array( $file, self::$ignore_files ) ) { |
|---|
| 592 | //error_log( $file ); |
|---|
| 593 | unlink( $file ); |
|---|
| 594 | } elseif ( ! $exists ) { |
|---|
| 595 | $this->fail( "Trying to delete a file that doesn't exist: $file" ); |
|---|
| 596 | } |
|---|
| 597 | } |
|---|
| 598 | |
|---|
| 599 | function rmdir( $path ) { |
|---|
| 600 | $files = $this->files_in_dir( $path ); |
|---|
| 601 | foreach ( $files as $file ) { |
|---|
| 602 | if ( ! in_array( $file, self::$ignore_files ) ) { |
|---|
| 603 | $this->unlink( $file ); |
|---|
| 604 | } |
|---|
| 605 | } |
|---|
| 606 | } |
|---|
| 607 | |
|---|
| 608 | function remove_added_uploads() { |
|---|
| 609 | // Remove all uploads. |
|---|
| 610 | $uploads = wp_upload_dir(); |
|---|
| 611 | $this->rmdir( $uploads['basedir'] ); |
|---|
| 612 | } |
|---|
| 613 | |
|---|
| 614 | function files_in_dir( $dir ) { |
|---|
| 615 | $files = array(); |
|---|
| 616 | |
|---|
| 617 | $iterator = new RecursiveDirectoryIterator( $dir ); |
|---|
| 618 | $objects = new RecursiveIteratorIterator( $iterator ); |
|---|
| 619 | foreach ( $objects as $name => $object ) { |
|---|
| 620 | if ( is_file( $name ) ) { |
|---|
| 621 | $files[] = $name; |
|---|
| 622 | } |
|---|
| 623 | } |
|---|
| 624 | |
|---|
| 625 | return $files; |
|---|
| 626 | } |
|---|
| 627 | |
|---|
| 628 | function scan_user_uploads() { |
|---|
| 629 | static $files = array(); |
|---|
| 630 | if ( ! empty( $files ) ) { |
|---|
| 631 | return $files; |
|---|
| 632 | } |
|---|
| 633 | |
|---|
| 634 | $uploads = wp_upload_dir(); |
|---|
| 635 | $files = $this->files_in_dir( $uploads['basedir'] ); |
|---|
| 636 | return $files; |
|---|
| 637 | } |
|---|
| 638 | |
|---|
| 639 | function delete_folders( $path ) { |
|---|
| 640 | $this->matched_dirs = array(); |
|---|
| 641 | if ( ! is_dir( $path ) ) { |
|---|
| 642 | return; |
|---|
| 643 | } |
|---|
| 644 | |
|---|
| 645 | $this->scandir( $path ); |
|---|
| 646 | foreach ( array_reverse( $this->matched_dirs ) as $dir ) { |
|---|
| 647 | rmdir( $dir ); |
|---|
| 648 | } |
|---|
| 649 | rmdir( $path ); |
|---|
| 650 | } |
|---|
| 651 | |
|---|
| 652 | function scandir( $dir ) { |
|---|
| 653 | foreach ( scandir( $dir ) as $path ) { |
|---|
| 654 | if ( 0 !== strpos( $path, '.' ) && is_dir( $dir . '/' . $path ) ) { |
|---|
| 655 | $this->matched_dirs[] = $dir . '/' . $path; |
|---|
| 656 | $this->scandir( $dir . '/' . $path ); |
|---|
| 657 | } |
|---|
| 658 | } |
|---|
| 659 | } |
|---|
| 660 | |
|---|
| 661 | /** |
|---|
| 662 | * Helper to Convert a microtime string into a float |
|---|
| 663 | */ |
|---|
| 664 | protected function _microtime_to_float($microtime ){ |
|---|
| 665 | $time_array = explode( ' ', $microtime ); |
|---|
| 666 | return array_sum( $time_array ); |
|---|
| 667 | } |
|---|
| 668 | |
|---|
| 669 | /** |
|---|
| 670 | * Multisite-agnostic way to delete a user from the database. |
|---|
| 671 | * |
|---|
| 672 | * @since 4.3.0 |
|---|
| 673 | */ |
|---|
| 674 | public static function delete_user( $user_id ) { |
|---|
| 675 | if ( is_multisite() ) { |
|---|
| 676 | return wpmu_delete_user( $user_id ); |
|---|
| 677 | } else { |
|---|
| 678 | return wp_delete_user( $user_id ); |
|---|
| 679 | } |
|---|
| 680 | } |
|---|
| 681 | |
|---|
| 682 | /** |
|---|
| 683 | * Utility method that resets permalinks and flushes rewrites. |
|---|
| 684 | * |
|---|
| 685 | * @since 4.4.0 |
|---|
| 686 | * |
|---|
| 687 | * @global WP_Rewrite $wp_rewrite |
|---|
| 688 | * |
|---|
| 689 | * @param string $structure Optional. Permalink structure to set. Default empty. |
|---|
| 690 | */ |
|---|
| 691 | public function set_permalink_structure( $structure = '' ) { |
|---|
| 692 | global $wp_rewrite; |
|---|
| 693 | |
|---|
| 694 | $wp_rewrite->init(); |
|---|
| 695 | $wp_rewrite->set_permalink_structure( $structure ); |
|---|
| 696 | $wp_rewrite->flush_rules(); |
|---|
| 697 | } |
|---|
| 698 | |
|---|
| 699 | function _make_attachment($upload, $parent_post_id = 0) { |
|---|
| 700 | $type = ''; |
|---|
| 701 | if ( !empty($upload['type']) ) { |
|---|
| 702 | $type = $upload['type']; |
|---|
| 703 | } else { |
|---|
| 704 | $mime = wp_check_filetype( $upload['file'] ); |
|---|
| 705 | if ($mime) |
|---|
| 706 | $type = $mime['type']; |
|---|
| 707 | } |
|---|
| 708 | |
|---|
| 709 | $attachment = array( |
|---|
| 710 | 'post_title' => basename( $upload['file'] ), |
|---|
| 711 | 'post_content' => '', |
|---|
| 712 | 'post_type' => 'attachment', |
|---|
| 713 | 'post_parent' => $parent_post_id, |
|---|
| 714 | 'post_mime_type' => $type, |
|---|
| 715 | 'guid' => $upload[ 'url' ], |
|---|
| 716 | ); |
|---|
| 717 | |
|---|
| 718 | // Save the data |
|---|
| 719 | $id = wp_insert_attachment( $attachment, $upload[ 'file' ], $parent_post_id ); |
|---|
| 720 | wp_update_attachment_metadata( $id, wp_generate_attachment_metadata( $id, $upload['file'] ) ); |
|---|
| 721 | return $id; |
|---|
| 722 | } |
|---|
| 723 | } |
|---|