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/** 72 * The loop to output the test coverage info 73 * Should output: Extension, Class Name, Method/Function Name, Test Status, Test Files 74 */ 75foreach($extension_method_info as $record) { 76 echo $record[EXTENSION_NAME] . ","; 77 echo $record[CLASS_NAME] . ","; 78 echo $record[METHOD_NAME] . ","; 79 echo $record[IS_TESTED] . ","; 80 echo $record[TESTS] . "\n"; 81} 82 83/** 84 * Marks the "tested" status of methods in $method_info according 85 * to whether they are tested in $phpt_files 86 */ 87function mark_methods_as_tested($method_info, $phpt_files) { 88 89 foreach($phpt_files as $phpt_file) { 90 $tested_functions = extract_tests($phpt_file); 91 92 foreach($tested_functions as $tested_function) { 93 94 // go through method info array marking this function as tested 95 foreach($method_info as &$current_method_record) { 96 if (strcasecmp($tested_function, $current_method_record[METHOD_NAME]) == 0) { 97 // matched the method name 98 if ($current_method_record[IS_DUPLICATE] == true) { 99 // we cannot be sure which class this method corresponds to, 100 // so mark method as needing to be verified 101 $current_method_record[IS_TESTED] = "verify"; 102 } else { 103 $current_method_record[IS_TESTED] = "yes"; 104 } 105 $current_method_record[TESTS] .= $phpt_file . "; "; 106 } 107 } 108 } 109 } 110 return $method_info; 111} 112 113/** 114 * returns an array containing a record for each defined method. 115 */ 116function populate_method_info() { 117 118 $method_info = array(); 119 120 // get functions 121 $all_functions = get_defined_functions(); 122 $internal_functions = $all_functions["internal"]; 123 124 foreach ($internal_functions as $function) { 125 // populate new method record 126 $function_record = array(); 127 $function_record[CLASS_NAME] = "Function"; 128 $function_record[METHOD_NAME] = $function; 129 $function_record[IS_TESTED] = "no"; 130 $function_record[TESTS] = ""; 131 $function_record[IS_DUPLICATE] = false; 132 133 // record the extension that the function belongs to 134 $reflectionFunction = new ReflectionFunction($function); 135 $extension = $reflectionFunction->getExtension(); 136 if ($extension != null) { 137 $function_record[EXTENSION_NAME] = $extension->getName(); 138 } else { 139 $function_record[EXTENSION_NAME] = ""; 140 } 141 // insert new method record into info array 142 $method_info[] = $function_record; 143 } 144 145 // get methods 146 $all_classes = get_declared_classes(); 147 foreach ($all_classes as $class) { 148 $reflectionClass = new ReflectionClass($class); 149 $methods = $reflectionClass->getMethods(); 150 foreach ($methods as $method) { 151 // populate new method record 152 $new_method_record = array(); 153 $new_method_record[CLASS_NAME] = $reflectionClass->getName(); 154 $new_method_record[METHOD_NAME] = $method->getName(); 155 $new_method_record[IS_TESTED] = "no"; 156 $new_method_record[TESTS] = ""; 157 158 $extension = $reflectionClass->getExtension(); 159 if ($extension != null) { 160 $new_method_record[EXTENSION_NAME] = $extension->getName(); 161 } else { 162 $new_method_record[EXTENSION_NAME] = ""; 163 } 164 165 // check for duplicate method names 166 $new_method_record[IS_DUPLICATE] = false; 167 foreach ($method_info as &$current_record) { 168 if (strcmp($current_record[METHOD_NAME], $new_method_record[METHOD_NAME]) == 0) { 169 $new_method_record[IS_DUPLICATE] = true; 170 $current_record[IS_DUPLICATE] = true; 171 } 172 } 173 // insert new method record into info array 174 $method_info[] = $new_method_record; 175 } 176 } 177 178 return $method_info; 179} 180 181function get_phpt_files($dir, &$phpt_file_count, &$all_phpt) 182{ 183 $thisdir = dir($dir.'/'); //include the trailing slash 184 while(($file = $thisdir->read()) !== false) { 185 if ($file != '.' && $file != '..') { 186 $path = $thisdir->path.$file; 187 if(is_dir($path) == true) { 188 get_phpt_files($path , $phpt_file_count , $all_phpt); 189 } else { 190 if (preg_match("/\w+\.phpt$/", $file)) { 191 $all_phpt[$phpt_file_count] = $path; 192 $phpt_file_count++; 193 } 194 } 195 } 196 } 197} 198 199/** 200 * Extract tests from a specified file, returns an array of tested function tokens 201 */ 202function extract_tests($file) { 203 $code = file_get_contents($file); 204 205 if (!preg_match('/--FILE--\s*(.*)\s*--(EXPECTF|EXPECTREGEX|EXPECT)?--/is', $code, $r)) { 206 //print "Unable to get code in ".$file."\n"; 207 return array(); 208 } 209 210 $tokens = token_get_all($r[1]); 211 $functions = array_filter($tokens, 'filter_functions'); 212 $functions = array_map( 'map_token_value',$functions); 213 $functions = array_unique($functions); 214 215 return $functions; 216} 217 218function filter_functions($x) { 219 return $x[0] == 307; 220} 221 222function map_token_value($x) { 223 return $x[1]; 224} 225 226 227?> 228