Make WordPress Core

source: trunk/tests/phpunit/includes/utils.php @ 37475

Last change on this file since 37475 was 36525, checked in by boonebgorges, 9 years ago

Introduce publicly_queryable taxonomy argument.

Taxonomies registered as publicly_queryable can be queried as taxonomy
archives.

If not provided explicitly, the value of publicly_queryable is inherited
from public.

Props Chouby.
Fixes #34491.

File size: 11.2 KB
Line 
1<?php
2
3// misc help functions and utilities
4
5function rand_str($len=32) {
6        return substr(md5(uniqid(rand())), 0, $len);
7}
8
9function rand_long_str( $length ) {
10        $chars = 'abcdefghijklmnopqrstuvwxyz';
11        $string = '';
12
13        for ( $i = 0; $i < $length; $i++ ) {
14                $rand = rand( 0, strlen( $chars ) - 1 );
15                $string .= substr( $chars, $rand, 1 );
16        }
17
18        return $string;
19}
20
21// strip leading and trailing whitespace from each line in the string
22function strip_ws($txt) {
23        $lines = explode("\n", $txt);
24        $result = array();
25        foreach ($lines as $line)
26                if (trim($line))
27                        $result[] = trim($line);
28
29        return trim(join("\n", $result));
30}
31
32// helper class for testing code that involves actions and filters
33// typical use:
34// $ma = new MockAction();
35// add_action('foo', array(&$ma, 'action'));
36class MockAction {
37        var $events;
38        var $debug;
39
40        /**
41         * PHP5 constructor.
42         */
43        function __construct( $debug = 0 ) {
44                $this->reset();
45                $this->debug = $debug;
46        }
47
48        function reset() {
49                $this->events = array();
50        }
51
52        function current_filter() {
53                if (is_callable('current_filter'))
54                        return current_filter();
55                global $wp_actions;
56                return end($wp_actions);
57        }
58
59        function action($arg) {
60if ($this->debug) dmp(__FUNCTION__, $this->current_filter());
61                $args = func_get_args();
62                $this->events[] = array('action' => __FUNCTION__, 'tag'=>$this->current_filter(), 'args'=>$args);
63                return $arg;
64        }
65
66        function action2($arg) {
67if ($this->debug) dmp(__FUNCTION__, $this->current_filter());
68
69                $args = func_get_args();
70                $this->events[] = array('action' => __FUNCTION__, 'tag'=>$this->current_filter(), 'args'=>$args);
71                return $arg;
72        }
73
74        function filter($arg) {
75if ($this->debug) dmp(__FUNCTION__, $this->current_filter());
76
77                $args = func_get_args();
78                $this->events[] = array('filter' => __FUNCTION__, 'tag'=>$this->current_filter(), 'args'=>$args);
79                return $arg;
80        }
81
82        function filter2($arg) {
83if ($this->debug) dmp(__FUNCTION__, $this->current_filter());
84
85                $args = func_get_args();
86                $this->events[] = array('filter' => __FUNCTION__, 'tag'=>$this->current_filter(), 'args'=>$args);
87                return $arg;
88        }
89
90        function filter_append($arg) {
91if ($this->debug) dmp(__FUNCTION__, $this->current_filter());
92
93                $args = func_get_args();
94                $this->events[] = array('filter' => __FUNCTION__, 'tag'=>$this->current_filter(), 'args'=>$args);
95                return $arg . '_append';
96        }
97
98        function filterall($tag, $arg=NULL) {
99        // this one doesn't return the result, so it's safe to use with the new 'all' filter
100if ($this->debug) dmp(__FUNCTION__, $this->current_filter());
101
102                $args = func_get_args();
103                $this->events[] = array('filter' => __FUNCTION__, 'tag'=>$tag, 'args'=>array_slice($args, 1));
104        }
105
106        // return a list of all the actions, tags and args
107        function get_events() {
108                return $this->events;
109        }
110
111        // return a count of the number of times the action was called since the last reset
112        function get_call_count($tag='') {
113                if ($tag) {
114                        $count = 0;
115                        foreach ($this->events as $e)
116                                if ($e['action'] == $tag)
117                                        ++$count;
118                        return $count;
119                }
120                return count($this->events);
121        }
122
123        // return an array of the tags that triggered calls to this action
124        function get_tags() {
125                $out = array();
126                foreach ($this->events as $e) {
127                        $out[] = $e['tag'];
128                }
129                return $out;
130        }
131
132        // return an array of args passed in calls to this action
133        function get_args() {
134                $out = array();
135                foreach ($this->events as $e)
136                        $out[] = $e['args'];
137                return $out;
138        }
139}
140
141// convert valid xml to an array tree structure
142// kinda lame but it works with a default php 4 install
143class testXMLParser {
144        var $xml;
145        var $data = array();
146
147        /**
148         * PHP5 constructor.
149         */
150        function __construct( $in ) {
151                $this->xml = xml_parser_create();
152                xml_set_object($this->xml, $this);
153                xml_parser_set_option($this->xml,XML_OPTION_CASE_FOLDING, 0);
154                xml_set_element_handler($this->xml, array($this, 'startHandler'), array($this, 'endHandler'));
155                xml_set_character_data_handler($this->xml, array($this, 'dataHandler'));
156                $this->parse($in);
157        }
158
159        function parse($in) {
160                $parse = xml_parse($this->xml, $in, sizeof($in));
161                if (!$parse) {
162                        trigger_error(sprintf("XML error: %s at line %d",
163                        xml_error_string(xml_get_error_code($this->xml)),
164                        xml_get_current_line_number($this->xml)), E_USER_ERROR);
165                        xml_parser_free($this->xml);
166                }
167                return true;
168        }
169
170        function startHandler($parser, $name, $attributes) {
171                $data['name'] = $name;
172                if ($attributes) { $data['attributes'] = $attributes; }
173                $this->data[] = $data;
174        }
175
176        function dataHandler($parser, $data) {
177                $index = count($this->data) - 1;
178                @$this->data[$index]['content'] .= $data;
179        }
180
181        function endHandler($parser, $name) {
182                if (count($this->data) > 1) {
183                        $data = array_pop($this->data);
184                        $index = count($this->data) - 1;
185                        $this->data[$index]['child'][] = $data;
186                }
187        }
188}
189
190function xml_to_array($in) {
191        $p = new testXMLParser($in);
192        return $p->data;
193}
194
195function xml_find($tree /*, $el1, $el2, $el3, .. */) {
196        $a = func_get_args();
197        $a = array_slice($a, 1);
198        $n = count($a);
199        $out = array();
200
201        if ($n < 1)
202                return $out;
203
204        for ($i=0; $i<count($tree); $i++) {
205#               echo "checking '{$tree[$i][name]}' == '{$a[0]}'\n";
206#               var_dump($tree[$i]['name'], $a[0]);
207                if ($tree[$i]['name'] == $a[0]) {
208#                       echo "n == {$n}\n";
209                        if ($n == 1)
210                                $out[] = $tree[$i];
211                        else {
212                                $subtree =& $tree[$i]['child'];
213                                $call_args = array($subtree);
214                                $call_args = array_merge($call_args, array_slice($a, 1));
215                                $out = array_merge($out, call_user_func_array('xml_find', $call_args));
216                        }
217                }
218        }
219
220        return $out;
221}
222
223function xml_join_atts($atts) {
224        $a = array();
225        foreach ($atts as $k=>$v)
226                $a[] = $k.'="'.$v.'"';
227        return join(' ', $a);
228}
229
230function xml_array_dumbdown(&$data) {
231        $out = array();
232
233        foreach (array_keys($data) as $i) {
234                $name = $data[$i]['name'];
235                if (!empty($data[$i]['attributes']))
236                        $name .= ' '.xml_join_atts($data[$i]['attributes']);
237
238                if (!empty($data[$i]['child'])) {
239                        $out[$name][] = xml_array_dumbdown($data[$i]['child']);
240                }
241                else
242                        $out[$name] = $data[$i]['content'];
243        }
244
245        return $out;
246}
247
248function dmp() {
249        $args = func_get_args();
250
251        foreach ($args as $thing)
252                echo (is_scalar($thing) ? strval($thing) : var_export($thing, true)), "\n";
253}
254
255function dmp_filter($a) {
256        dmp($a);
257        return $a;
258}
259
260function get_echo($callable, $args = array()) {
261        ob_start();
262        call_user_func_array($callable, $args);
263        return ob_get_clean();
264}
265
266// recursively generate some quick assertEquals tests based on an array
267function gen_tests_array($name, $array) {
268        $out = array();
269        foreach ($array as $k=>$v) {
270                if (is_numeric($k))
271                        $index = strval($k);
272                else
273                        $index = "'".addcslashes($k, "\n\r\t'\\")."'";
274
275                if (is_string($v)) {
276                        $out[] = '$this->assertEquals( \'' . addcslashes($v, "\n\r\t'\\") . '\', $'.$name.'['.$index.'] );';
277                }
278                elseif (is_numeric($v)) {
279                        $out[] = '$this->assertEquals( ' . $v . ', $'.$name.'['.$index.'] );';
280                }
281                elseif (is_array($v)) {
282                        $out[] = gen_tests_array("{$name}[{$index}]", $v);
283                }
284        }
285        return join("\n", $out)."\n";
286}
287
288/**
289 * Use to create objects by yourself
290 */
291class MockClass {};
292
293/**
294 * Drops all tables from the WordPress database
295 */
296function drop_tables() {
297        global $wpdb;
298        $tables = $wpdb->get_col('SHOW TABLES;');
299        foreach ($tables as $table)
300                $wpdb->query("DROP TABLE IF EXISTS {$table}");
301}
302
303function print_backtrace() {
304        $bt = debug_backtrace();
305        echo "Backtrace:\n";
306        $i = 0;
307        foreach ($bt as $stack) {
308                echo ++$i, ": ";
309                if ( isset($stack['class']) )
310                        echo $stack['class'].'::';
311                if ( isset($stack['function']) )
312                        echo $stack['function'].'() ';
313                echo "line {$stack[line]} in {$stack[file]}\n";
314        }
315        echo "\n";
316}
317
318// mask out any input fields matching the given name
319function mask_input_value($in, $name='_wpnonce') {
320        return preg_replace('@<input([^>]*) name="'.preg_quote($name).'"([^>]*) value="[^>]*" />@', '<input$1 name="'.preg_quote($name).'"$2 value="***" />', $in);
321}
322
323if ( !function_exists( 'str_getcsv' ) ) {
324        function str_getcsv( $input, $delimiter = ',', $enclosure = '"', $escape = "\\" ) {
325                $fp = fopen( 'php://temp/', 'r+' );
326                fputs( $fp, $input );
327                rewind( $fp );
328                $data = fgetcsv( $fp, strlen( $input ), $delimiter, $enclosure );
329                fclose( $fp );
330                return $data;
331        }
332}
333
334/**
335 * Removes the post type and its taxonomy associations.
336 */
337function _unregister_post_type( $cpt_name ) {
338        unregister_post_type( $cpt_name );
339}
340
341function _unregister_taxonomy( $taxonomy_name ) {
342        unregister_taxonomy( $taxonomy_name );
343}
344
345/**
346 * Unregister a post status.
347 *
348 * @since 4.2.0
349 *
350 * @param string $status
351 */
352function _unregister_post_status( $status ) {
353        unset( $GLOBALS['wp_post_statuses'][ $status ] );
354}
355
356function _cleanup_query_vars() {
357        // clean out globals to stop them polluting wp and wp_query
358        foreach ( $GLOBALS['wp']->public_query_vars as $v )
359                unset( $GLOBALS[$v] );
360
361        foreach ( $GLOBALS['wp']->private_query_vars as $v )
362                unset( $GLOBALS[$v] );
363
364        foreach ( get_taxonomies( array() , 'objects' ) as $t ) {
365                if ( $t->publicly_queryable && ! empty( $t->query_var ) )
366                        $GLOBALS['wp']->add_query_var( $t->query_var );
367        }
368
369        foreach ( get_post_types( array() , 'objects' ) as $t ) {
370                if ( is_post_type_viewable( $t ) && ! empty( $t->query_var ) )
371                        $GLOBALS['wp']->add_query_var( $t->query_var );
372        }
373}
374
375function _clean_term_filters() {
376        remove_filter( 'get_terms',     array( 'Featured_Content', 'hide_featured_term'     ), 10, 2 );
377        remove_filter( 'get_the_terms', array( 'Featured_Content', 'hide_the_featured_term' ), 10, 3 );
378}
379
380/**
381 * Special class for exposing protected wpdb methods we need to access
382 */
383class wpdb_exposed_methods_for_testing extends wpdb {
384        public function __construct() {
385                global $wpdb;
386                $this->dbh = $wpdb->dbh;
387                $this->use_mysqli = $wpdb->use_mysqli;
388                $this->is_mysql = $wpdb->is_mysql;
389                $this->ready = true;
390                $this->field_types = $wpdb->field_types;
391                $this->charset = $wpdb->charset;
392        }
393
394        public function __call( $name, $arguments ) {
395                return call_user_func_array( array( $this, $name ), $arguments );
396        }
397}
398
399/**
400 * Determine approximate backtrack count when running PCRE.
401 *
402 * @return int The backtrack count.
403 */
404function benchmark_pcre_backtracking( $pattern, $subject, $strategy ) {
405        $saved_config = ini_get( 'pcre.backtrack_limit' );
406       
407        // Attempt to prevent PHP crashes.  Adjust these lower when needed.
408        if ( version_compare( phpversion(), '5.4.8', '>' ) ) {
409                $limit = 1000000;
410        } else {
411                $limit = 20000;  // 20,000 is a reasonable upper limit, but see also https://core.trac.wordpress.org/ticket/29557#comment:10
412        }
413
414        // Start with small numbers, so if a crash is encountered at higher numbers we can still debug the problem.
415        for( $i = 4; $i <= $limit; $i *= 2 ) {
416
417                ini_set( 'pcre.backtrack_limit', $i );
418               
419                switch( $strategy ) {
420                case 'split':
421                        preg_split( $pattern, $subject );
422                        break;
423                case 'match':
424                        preg_match( $pattern, $subject );
425                        break;
426                case 'match_all':
427                        $matches = array();
428                        preg_match_all( $pattern, $subject, $matches );
429                        break;
430                }
431
432                ini_set( 'pcre.backtrack_limit', $saved_config );
433
434                switch( preg_last_error() ) {
435                case PREG_NO_ERROR:
436                        return $i;
437                case PREG_BACKTRACK_LIMIT_ERROR:
438                        continue;
439                case PREG_RECURSION_LIMIT_ERROR:
440                        trigger_error('PCRE recursion limit encountered before backtrack limit.');
441                        return;
442                case PREG_BAD_UTF8_ERROR:
443                        trigger_error('UTF-8 error during PCRE benchmark.');
444                        return;
445                case PREG_INTERNAL_ERROR:
446                        trigger_error('Internal error during PCRE benchmark.');
447                        return;
448                default:
449                        trigger_error('Unexpected error during PCRE benchmark.');
450                        return;
451                }
452        }
453
454        return $i;
455}
Note: See TracBrowser for help on using the repository browser.