PageRenderTime 46ms CodeModel.GetById 16ms RepoModel.GetById 0ms app.codeStats 0ms

/includes/utils.php

https://gitlab.com/Blueprint-Marketing/wordpress-unit-tests
PHP | 365 lines | 280 code | 57 blank | 28 comment | 31 complexity | 66f6692b205f91b4ce589a471c10a5b4 MD5 | raw file
  1. <?php
  2. // misc help functions and utilities
  3. function rand_str($len=32) {
  4. return substr(md5(uniqid(rand())), 0, $len);
  5. }
  6. // strip leading and trailing whitespace from each line in the string
  7. function strip_ws($txt) {
  8. $lines = explode("\n", $txt);
  9. $result = array();
  10. foreach ($lines as $line)
  11. if (trim($line))
  12. $result[] = trim($line);
  13. return trim(join("\n", $result));
  14. }
  15. // helper class for testing code that involves actions and filters
  16. // typical use:
  17. // $ma = new MockAction();
  18. // add_action('foo', array(&$ma, 'action'));
  19. class MockAction {
  20. var $events;
  21. var $debug;
  22. function MockAction($debug=0) {
  23. $this->reset();
  24. $this->debug = $debug;
  25. }
  26. function reset() {
  27. $this->events = array();
  28. }
  29. function current_filter() {
  30. if (is_callable('current_filter'))
  31. return current_filter();
  32. global $wp_actions;
  33. return end($wp_actions);
  34. }
  35. function action($arg) {
  36. if ($this->debug) dmp(__FUNCTION__, $this->current_filter());
  37. $args = func_get_args();
  38. $this->events[] = array('action' => __FUNCTION__, 'tag'=>$this->current_filter(), 'args'=>$args);
  39. return $arg;
  40. }
  41. function action2($arg) {
  42. if ($this->debug) dmp(__FUNCTION__, $this->current_filter());
  43. $args = func_get_args();
  44. $this->events[] = array('action' => __FUNCTION__, 'tag'=>$this->current_filter(), 'args'=>$args);
  45. return $arg;
  46. }
  47. function filter($arg) {
  48. if ($this->debug) dmp(__FUNCTION__, $this->current_filter());
  49. $args = func_get_args();
  50. $this->events[] = array('filter' => __FUNCTION__, 'tag'=>$this->current_filter(), 'args'=>$args);
  51. return $arg;
  52. }
  53. function filter2($arg) {
  54. if ($this->debug) dmp(__FUNCTION__, $this->current_filter());
  55. $args = func_get_args();
  56. $this->events[] = array('filter' => __FUNCTION__, 'tag'=>$this->current_filter(), 'args'=>$args);
  57. return $arg;
  58. }
  59. function filter_append($arg) {
  60. if ($this->debug) dmp(__FUNCTION__, $this->current_filter());
  61. $args = func_get_args();
  62. $this->events[] = array('filter' => __FUNCTION__, 'tag'=>$this->current_filter(), 'args'=>$args);
  63. return $arg . '_append';
  64. }
  65. function filterall($tag, $arg=NULL) {
  66. // this one doesn't return the result, so it's safe to use with the new 'all' filter
  67. if ($this->debug) dmp(__FUNCTION__, $this->current_filter());
  68. $args = func_get_args();
  69. $this->events[] = array('filter' => __FUNCTION__, 'tag'=>$tag, 'args'=>array_slice($args, 1));
  70. }
  71. // return a list of all the actions, tags and args
  72. function get_events() {
  73. return $this->events;
  74. }
  75. // return a count of the number of times the action was called since the last reset
  76. function get_call_count($tag='') {
  77. if ($tag) {
  78. $count = 0;
  79. foreach ($this->events as $e)
  80. if ($e['action'] == $tag)
  81. ++$count;
  82. return $count;
  83. }
  84. return count($this->events);
  85. }
  86. // return an array of the tags that triggered calls to this action
  87. function get_tags() {
  88. $out = array();
  89. foreach ($this->events as $e) {
  90. $out[] = $e['tag'];
  91. }
  92. return $out;
  93. }
  94. // return an array of args passed in calls to this action
  95. function get_args() {
  96. $out = array();
  97. foreach ($this->events as $e)
  98. $out[] = $e['args'];
  99. return $out;
  100. }
  101. }
  102. // convert valid xml to an array tree structure
  103. // kinda lame but it works with a default php 4 install
  104. class testXMLParser {
  105. var $xml;
  106. var $data = array();
  107. function testXMLParser($in) {
  108. $this->xml = xml_parser_create();
  109. xml_set_object($this->xml, $this);
  110. xml_parser_set_option($this->xml,XML_OPTION_CASE_FOLDING, 0);
  111. xml_set_element_handler($this->xml, array(&$this, 'startHandler'), array(&$this, 'endHandler'));
  112. xml_set_character_data_handler($this->xml, array(&$this, 'dataHandler'));
  113. $this->parse($in);
  114. }
  115. function parse($in) {
  116. $parse = xml_parse($this->xml, $in, sizeof($in));
  117. if (!$parse) {
  118. trigger_error(sprintf("XML error: %s at line %d",
  119. xml_error_string(xml_get_error_code($this->xml)),
  120. xml_get_current_line_number($this->xml)), E_USER_ERROR);
  121. xml_parser_free($this->xml);
  122. }
  123. return true;
  124. }
  125. function startHandler($parser, $name, $attributes) {
  126. $data['name'] = $name;
  127. if ($attributes) { $data['attributes'] = $attributes; }
  128. $this->data[] = $data;
  129. }
  130. function dataHandler($parser, $data) {
  131. $index = count($this->data) - 1;
  132. @$this->data[$index]['content'] .= $data;
  133. }
  134. function endHandler($parser, $name) {
  135. if (count($this->data) > 1) {
  136. $data = array_pop($this->data);
  137. $index = count($this->data) - 1;
  138. $this->data[$index]['child'][] = $data;
  139. }
  140. }
  141. }
  142. function xml_to_array($in) {
  143. $p = new testXMLParser($in);
  144. return $p->data;
  145. }
  146. function xml_find($tree /*, $el1, $el2, $el3, .. */) {
  147. $a = func_get_args();
  148. $a = array_slice($a, 1);
  149. $n = count($a);
  150. $out = array();
  151. if ($n < 1)
  152. return $out;
  153. for ($i=0; $i<count($tree); $i++) {
  154. # echo "checking '{$tree[$i][name]}' == '{$a[0]}'\n";
  155. # var_dump($tree[$i]['name'], $a[0]);
  156. if ($tree[$i]['name'] == $a[0]) {
  157. # echo "n == {$n}\n";
  158. if ($n == 1)
  159. $out[] = $tree[$i];
  160. else {
  161. $subtree =& $tree[$i]['child'];
  162. $call_args = array($subtree);
  163. $call_args = array_merge($call_args, array_slice($a, 1));
  164. $out = array_merge($out, call_user_func_array('xml_find', $call_args));
  165. }
  166. }
  167. }
  168. return $out;
  169. }
  170. function xml_join_atts($atts) {
  171. $a = array();
  172. foreach ($atts as $k=>$v)
  173. $a[] = $k.'="'.$v.'"';
  174. return join(' ', $a);
  175. }
  176. function xml_array_dumbdown(&$data) {
  177. $out = array();
  178. foreach (array_keys($data) as $i) {
  179. $name = $data[$i]['name'];
  180. if (!empty($data[$i]['attributes']))
  181. $name .= ' '.xml_join_atts($data[$i]['attributes']);
  182. if (!empty($data[$i]['child'])) {
  183. $out[$name][] = xml_array_dumbdown($data[$i]['child']);
  184. }
  185. else
  186. $out[$name] = $data[$i]['content'];
  187. }
  188. return $out;
  189. }
  190. function dmp() {
  191. $args = func_get_args();
  192. foreach ($args as $thing)
  193. echo (is_scalar($thing) ? strval($thing) : var_export($thing, true)), "\n";
  194. }
  195. function dmp_filter($a) {
  196. dmp($a);
  197. return $a;
  198. }
  199. function get_echo($callable, $args = array()) {
  200. ob_start();
  201. call_user_func_array($callable, $args);
  202. return ob_get_clean();
  203. }
  204. // recursively generate some quick assertEquals tests based on an array
  205. function gen_tests_array($name, $array) {
  206. $out = array();
  207. foreach ($array as $k=>$v) {
  208. if (is_numeric($k))
  209. $index = strval($k);
  210. else
  211. $index = "'".addcslashes($k, "\n\r\t'\\")."'";
  212. if (is_string($v)) {
  213. $out[] = '$this->assertEquals( \'' . addcslashes($v, "\n\r\t'\\") . '\', $'.$name.'['.$index.'] );';
  214. }
  215. elseif (is_numeric($v)) {
  216. $out[] = '$this->assertEquals( ' . $v . ', $'.$name.'['.$index.'] );';
  217. }
  218. elseif (is_array($v)) {
  219. $out[] = gen_tests_array("{$name}[{$index}]", $v);
  220. }
  221. }
  222. return join("\n", $out)."\n";
  223. }
  224. /**
  225. * Use to create objects by yourself
  226. */
  227. class MockClass {};
  228. /**
  229. * Drops all tables from the WordPress database
  230. */
  231. function drop_tables() {
  232. global $wpdb;
  233. $tables = $wpdb->get_col('SHOW TABLES;');
  234. foreach ($tables as $table)
  235. $wpdb->query("DROP TABLE IF EXISTS {$table}");
  236. }
  237. function print_backtrace() {
  238. $bt = debug_backtrace();
  239. echo "Backtrace:\n";
  240. $i = 0;
  241. foreach ($bt as $stack) {
  242. echo ++$i, ": ";
  243. if ( isset($stack['class']) )
  244. echo $stack['class'].'::';
  245. if ( isset($stack['function']) )
  246. echo $stack['function'].'() ';
  247. echo "line {$stack[line]} in {$stack[file]}\n";
  248. }
  249. echo "\n";
  250. }
  251. // mask out any input fields matching the given name
  252. function mask_input_value($in, $name='_wpnonce') {
  253. return preg_replace('@<input([^>]*) name="'.preg_quote($name).'"([^>]*) value="[^>]*" />@', '<input$1 name="'.preg_quote($name).'"$2 value="***" />', $in);
  254. }
  255. $GLOBALS['_wp_die_disabled'] = false;
  256. function _wp_die_handler( $message, $title = '', $args = array() ) {
  257. if ( !$GLOBALS['_wp_die_disabled'] ) {
  258. _default_wp_die_handler( $message, $title, $args );
  259. } else {
  260. //Ignore at our peril
  261. }
  262. }
  263. function _disable_wp_die() {
  264. $GLOBALS['_wp_die_disabled'] = true;
  265. }
  266. function _enable_wp_die() {
  267. $GLOBALS['_wp_die_disabled'] = false;
  268. }
  269. function _wp_die_handler_filter() {
  270. return '_wp_die_handler';
  271. }
  272. if ( !function_exists( 'str_getcsv' ) ) {
  273. function str_getcsv( $input, $delimiter = ',', $enclosure = '"', $escape = "\\" ) {
  274. $fp = fopen( 'php://temp/', 'r+' );
  275. fputs( $fp, $input );
  276. rewind( $fp );
  277. $data = fgetcsv( $fp, strlen( $input ), $delimiter, $enclosure );
  278. fclose( $fp );
  279. return $data;
  280. }
  281. }
  282. function _rmdir( $path ) {
  283. if ( in_array(basename( $path ), array( '.', '..' ) ) ) {
  284. return;
  285. } elseif ( is_file( $path ) ) {
  286. unlink( $path );
  287. } elseif ( is_dir( $path ) ) {
  288. foreach ( scandir( $path ) as $file )
  289. _rmdir( $path . '/' . $file );
  290. rmdir( $path );
  291. }
  292. }
  293. /**
  294. * Removes the post type and its taxonomy associations.
  295. */
  296. function _unregister_post_type( $cpt_name ) {
  297. unset( $GLOBALS['wp_post_types'][ $cpt_name ] );
  298. unset( $GLOBALS['_wp_post_type_features'][ $cpt_name ] );
  299. foreach ( $GLOBALS['wp_taxonomies'] as $taxonomy ) {
  300. if ( false !== $key = array_search( $cpt_name, $taxonomy->object_type ) ) {
  301. unset( $taxonomy->object_type[$key] );
  302. }
  303. }
  304. }
  305. function _unregister_taxonomy( $taxonomy_name ) {
  306. unset( $GLOBALS['wp_taxonomies'][$taxonomy_name] );
  307. }