1<?php 2 3 4$usage = <<<USAGE 5 6Usage: php find_tested.php [path_to_test_files] ([extension]) 7 8Outputs test coverage information for functions and methods in csv format. 9Supplying an optional extension name outputs only information for functions and methods from that extension. 10 11Output format: 12Extension, Class Name, Method/Function Name, Test Status, Test Files 13 14A test status of "verify" for a method means that there is at least one other method of the same name, so test coverage must be verified manually. 15 16USAGE; 17 18 19/* method record fields */ 20define("CLASS_NAME", "CLASS_NAME"); 21define("METHOD_NAME", "METHOD_NAME"); 22define("EXTENSION_NAME", "EXTENSION_NAME"); 23define("IS_DUPLICATE", "IS_DUPLICATE"); 24define("IS_TESTED", "IS_TESTED"); 25define("TESTS", "TESTS"); 26 27 28// process command line args 29$num_params = $argc; 30if ($num_params < 2 || $num_params > 3) { 31 die($usage); 32} 33 34$extension_test_path = $argv[1]; 35 36if ($num_params == 3) { 37 $extension_name = $argv[2]; 38 39 // check extension exists 40 $extensions = get_loaded_extensions(); 41 if (!in_array($extension_name, $extensions)) { 42 echo "Error: extension $extension_name is not loaded. Loaded extensions:\n"; 43 foreach($extensions as $extension) { 44 echo "$extension\n"; 45 } 46 die(); 47 } 48} else { 49 $extension_name = false; 50} 51 52 53$method_info = populate_method_info(); 54 55if ($extension_name != false) { 56 // get only the methods from the extension we are querying 57 $extension_method_info = array(); 58 foreach($method_info as $method_record) { 59 if (strcasecmp($extension_name, $method_record[EXTENSION_NAME]) == 0) { 60 $extension_method_info[] = $method_record; 61 } 62 } 63} else { 64 $extension_method_info = $method_info; 65} 66 67get_phpt_files($extension_test_path, $count, $phpt_files); 68 69$extension_method_info = mark_methods_as_tested($extension_method_info, $phpt_files); 70 71 72foreach($extension_method_info as $record) { 73 echo $record[EXTENSION_NAME] . ","; 74 echo $record[CLASS_NAME] . ","; 75 echo $record[METHOD_NAME] . ","; 76 echo $record[IS_TESTED] . ","; 77 echo $record[TESTS] . "\n"; 78} 79 80/** 81 * Marks the "tested" status of methods in $method_info according 82 * to whether they are tested in $phpt_files 83 */ 84function mark_methods_as_tested($method_info, $phpt_files) { 85 86 foreach($phpt_files as $phpt_file) { 87 $tested_functions = extract_tests($phpt_file); 88 89 foreach($tested_functions as $tested_function) { 90 91 // go through method info array marking this function as tested 92 foreach($method_info as &$current_method_record) { 93 if (strcasecmp($tested_function, $current_method_record[METHOD_NAME]) == 0) { 94 // matched the method name 95 if ($current_method_record[IS_DUPLICATE] == true) { 96 // we cannot be sure which class this method corresponds to, 97 // so mark method as needing to be verified 98 $current_method_record[IS_TESTED] = "verify"; 99 } else { 100 $current_method_record[IS_TESTED] = "yes"; 101 } 102 $current_method_record[TESTS] .= $phpt_file . "; "; 103 } 104 } 105 } 106 } 107 return $method_info; 108} 109 110/** 111 * returns an array containing a record for each defined method. 112 */ 113function populate_method_info() { 114 115 $method_info = array(); 116 117 // get functions 118 $all_functions = get_defined_functions(); 119 $internal_functions = $all_functions["internal"]; 120 121 foreach ($internal_functions as $function) { 122 // populate new method record 123 $function_record = array(); 124 $function_record[CLASS_NAME] = "Function"; 125 $function_record[METHOD_NAME] = $function; 126 $function_record[IS_TESTED] = "no"; 127 $function_record[TESTS] = ""; 128 $function_record[IS_DUPLICATE] = false; 129 130 // record the extension that the function belongs to 131 $reflectionFunction = new ReflectionFunction($function); 132 $extension = $reflectionFunction->getExtension(); 133 if ($extension != null) { 134 $function_record[EXTENSION_NAME] = $extension->getName(); 135 } else { 136 $function_record[EXTENSION_NAME] = ""; 137 } 138 // insert new method record into info array 139 $method_info[] = $function_record; 140 } 141 142 // get methods 143 $all_classes = get_declared_classes(); 144 foreach ($all_classes as $class) { 145 $reflectionClass = new ReflectionClass($class); 146 $methods = $reflectionClass->getMethods(); 147 foreach ($methods as $method) { 148 // populate new method record 149 $new_method_record = array(); 150 $new_method_record[CLASS_NAME] = $reflectionClass->getName(); 151 $new_method_record[METHOD_NAME] = $method->getName(); 152 $new_method_record[IS_TESTED] = "no"; 153 $new_method_record[TESTS] = ""; 154 155 $extension = $reflectionClass->getExtension(); 156 if ($extension != null) { 157 $new_method_record[EXTENSION_NAME] = $extension->getName(); 158 } else { 159 $new_method_record[EXTENSION_NAME] = ""; 160 } 161 162 // check for duplicate method names 163 $new_method_record[IS_DUPLICATE] = false; 164 foreach ($method_info as &$current_record) { 165 if (strcmp($current_record[METHOD_NAME], $new_method_record[METHOD_NAME]) == 0) { 166 $new_method_record[IS_DUPLICATE] = true; 167 $current_record[IS_DUPLICATE] = true; 168 } 169 } 170 // insert new method record into info array 171 $method_info[] = $new_method_record; 172 } 173 } 174 175 return $method_info; 176} 177 178function get_phpt_files($dir, &$phpt_file_count, &$all_phpt) 179{ 180 $thisdir = dir($dir.'/'); //include the trailing slash 181 while(($file = $thisdir->read()) !== false) { 182 if ($file != '.' && $file != '..') { 183 $path = $thisdir->path.$file; 184 if(is_dir($path) == true) { 185 get_phpt_files($path , $phpt_file_count , $all_phpt); 186 } else { 187 if (preg_match("/\w+\.phpt$/", $file)) { 188 $all_phpt[$phpt_file_count] = $path; 189 $phpt_file_count++; 190 } 191 } 192 } 193 } 194} 195 196function extract_tests($file) { 197 $code = file_get_contents($file); 198 199 if (!preg_match('/--FILE--\s*(.*)\s*--(EXPECTF|EXPECTREGEX|EXPECT)?--/is', $code, $r)) { 200// print "Unable to get code in ".$file."\n"; 201 return array(); 202 } 203 204 $tokens = token_get_all($r[1]); 205 $functions = array_filter($tokens, 'filter_functions'); 206 $functions = array_map( 'map_token_value',$functions); 207 $functions = array_unique($functions); 208 209 return $functions; 210} 211 212function filter_functions($x) { 213 return $x[0] == 307; 214} 215 216function map_token_value($x) { 217 return $x[1]; 218} 219 220 221?> 222 223