| 1 |
<?php
|
| 2 |
// $Id: simpletest_unit.module,v 1.16 2008/04/20 07:41:46 boombatower Exp $
|
| 3 |
|
| 4 |
define('SIMPLETEST_UNIT_CALLBACK', 'test_clearinghouse');
|
| 5 |
|
| 6 |
/**
|
| 7 |
* Implementation of hook_menu().
|
| 8 |
*/
|
| 9 |
function simpletest_unit_menu() {
|
| 10 |
$items['admin/build/simpletest/simpletest_unit'] = array(
|
| 11 |
'title' => 'SimpleTest unit',
|
| 12 |
'description' => 'Generate unit test stubs.',
|
| 13 |
'page callback' => 'drupal_get_form',
|
| 14 |
'page arguments' => array('simpletest_unit_settings'),
|
| 15 |
'access arguments' => array('access administration pages')
|
| 16 |
);
|
| 17 |
return $items;
|
| 18 |
}
|
| 19 |
|
| 20 |
/**
|
| 21 |
* Stub generation form.
|
| 22 |
*/
|
| 23 |
function simpletest_unit_settings() {
|
| 24 |
$form = array();
|
| 25 |
$form['generate'] = array(
|
| 26 |
'#type' => 'fieldset',
|
| 27 |
'#title' => t('Generate Test Stubs'),
|
| 28 |
'#description' => t('Unit test stubs will be generated in the <i>simpletest_unit</i> directory so as to not
|
| 29 |
override with the <i>simpletest</i> module. Running the stub generation will override any files in the
|
| 30 |
<i>tests</i> directory in the <i>simpletest_unit</i> module directory. Please be patient while stubs are
|
| 31 |
generated as the process is know to take about 20 seconds.')
|
| 32 |
);
|
| 33 |
$form['generate']['op'] = array(
|
| 34 |
'#type' => 'submit',
|
| 35 |
'#value' => t('Generate stubs'),
|
| 36 |
'#submit' => array('simpletest_unit_generate')
|
| 37 |
);
|
| 38 |
return $form;
|
| 39 |
}
|
| 40 |
|
| 41 |
/**
|
| 42 |
* Generate unit test stubs.
|
| 43 |
*/
|
| 44 |
function simpletest_unit_generate() {
|
| 45 |
require_once(drupal_get_path('module', 'simpletest_unit') .'/simpletest_unit_token_wrapper.php');
|
| 46 |
|
| 47 |
$directories = array('includes', 'modules'); // Directories to scan recursively.
|
| 48 |
|
| 49 |
// Scan files to determine what functions are define by drupal.
|
| 50 |
$wrappers = array();
|
| 51 |
foreach ($directories as $directory) {
|
| 52 |
$wrappers += simpletest_unit_scan_directory($directory);
|
| 53 |
}
|
| 54 |
|
| 55 |
// Get list of all drupal defined functions.
|
| 56 |
$function_names = array();
|
| 57 |
foreach ($wrappers as $wrapper) {
|
| 58 |
$function_names = array_merge($function_names, $wrapper->get_function_names());
|
| 59 |
}
|
| 60 |
|
| 61 |
drupal_set_message(t('Found %functions functions defined in %files files.', array('%functions' => count($function_names), '%files' => count($wrappers))));
|
| 62 |
|
| 63 |
// Remove non-drupal function calls, since only drupal functions need to be overridden.
|
| 64 |
foreach ($wrappers as $wrapper) {
|
| 65 |
$wrapper->clean_calls($function_names);
|
| 66 |
}
|
| 67 |
|
| 68 |
// Generate stub tests.
|
| 69 |
$tests_folder = drupal_get_path('module', 'simpletest_unit') .'/tests/';
|
| 70 |
$drupal_stub_folder = drupal_get_path('module', 'simpletest_unit') .'/drupal_stub/';
|
| 71 |
$drupal_orginal_folder = drupal_get_path('module', 'simpletest_unit') .'/drupal_original/';
|
| 72 |
foreach ($wrappers as $wrapper) {
|
| 73 |
$out = '';
|
| 74 |
foreach ($wrapper->get_functions() as $function) {
|
| 75 |
$out .= simpletest_unit_wrap_function($function['name'], $function['calls']);
|
| 76 |
}
|
| 77 |
$filename = basename($wrapper->get_file_path());
|
| 78 |
$out = simpletest_unit_wrap_test($filename, $out);
|
| 79 |
file_put_contents($tests_folder . $filename .'.test', $out);
|
| 80 |
|
| 81 |
simpletest_unit_check_directories($drupal_stub_folder, dirname($wrapper->get_file_path()));
|
| 82 |
file_put_contents($drupal_stub_folder . $wrapper->get_file_path(), simpletest_unit_generate_stub($wrapper->get_functions()));
|
| 83 |
copy($wrapper->get_file_path(), $drupal_orginal_folder . $wrapper->get_file_path());
|
| 84 |
simpletest_unit_prefix_original($drupal_orginal_folder . $wrapper->get_file_path(), $wrapper->get_functions());
|
| 85 |
}
|
| 86 |
|
| 87 |
drupal_set_message(t('Code stubs generated.'));
|
| 88 |
}
|
| 89 |
|
| 90 |
function simpletest_unit_prefix_original($file, array $functions) {
|
| 91 |
$contents = file_get_contents($file);
|
| 92 |
foreach ($functions as $function) {
|
| 93 |
$contents = str_replace("function {$function['name']}", "function original_{$function['name']}", $contents);
|
| 94 |
}
|
| 95 |
file_put_contents($file, $contents);
|
| 96 |
}
|
| 97 |
|
| 98 |
function simpletest_unit_check_directories($base, $location) {
|
| 99 |
$path = $base;
|
| 100 |
$parts = explode('/', $location);
|
| 101 |
foreach ($parts as $part) {
|
| 102 |
$path = $path . $part;
|
| 103 |
file_check_directory($path, FILE_CREATE_DIRECTORY);
|
| 104 |
file_check_directory(str_replace('drupal_stub', 'drupal_original', $path), FILE_CREATE_DIRECTORY);
|
| 105 |
$path .= '/';
|
| 106 |
}
|
| 107 |
}
|
| 108 |
|
| 109 |
function simpletest_unit_generate_stub(array $functions) {
|
| 110 |
$out = '';
|
| 111 |
foreach ($functions as $function) {
|
| 112 |
$out .= "function {$function['name']}(" . simpletest_unit_export_parameters($function['parameters']) . ") {\n";
|
| 113 |
$out .= " return " . SIMPLETEST_UNIT_CALLBACK . "('{$function['name']}'";
|
| 114 |
$out .= (count($function['parameters']) ? ', ' . implode(', ', str_replace('&', '', array_keys($function['parameters']))) : '');
|
| 115 |
$out .= ");\n";
|
| 116 |
$out .= "}\n\n";
|
| 117 |
}
|
| 118 |
return
|
| 119 |
"<?php
|
| 120 |
// \$Id\$
|
| 121 |
|
| 122 |
" . trim($out) . "\n";
|
| 123 |
}
|
| 124 |
|
| 125 |
/**
|
| 126 |
* Scan derectory recursively, scan appropriate files, and return
|
| 127 |
* token wrappers for further processing.
|
| 128 |
*
|
| 129 |
* @param string $directory Directory to scan.
|
| 130 |
* @return array List of token wrappers.
|
| 131 |
*/
|
| 132 |
function simpletest_unit_scan_directory($directory) {
|
| 133 |
static $wrappers = array();
|
| 134 |
$path = $directory .'/';
|
| 135 |
$files = scandir($path);
|
| 136 |
foreach ($files as $file) {
|
| 137 |
$file_path = $path . $file;
|
| 138 |
if (simpletest_unit_match($file)) {
|
| 139 |
$wrappers[] = simpletest_unit_scan_file($file_path);
|
| 140 |
}
|
| 141 |
else if (simpletest_unit_check_directory($file_path)) {
|
| 142 |
simpletest_unit_scan_directory($file_path);
|
| 143 |
}
|
| 144 |
}
|
| 145 |
return $wrappers;
|
| 146 |
}
|
| 147 |
|
| 148 |
/**
|
| 149 |
* Parse specified file into tokens and return token wrapper.
|
| 150 |
*
|
| 151 |
* @param string $file File to scan.
|
| 152 |
* @return simpletest_unit_token_wrapper Token wrapper for specified file.
|
| 153 |
*/
|
| 154 |
function simpletest_unit_scan_file($file) {
|
| 155 |
$contents = file_get_contents($file);
|
| 156 |
|
| 157 |
// Remove comments.
|
| 158 |
$contents = preg_replace('/^.*?\/\/.*?$/m', '', $contents); // Single line comments.
|
| 159 |
$contents = preg_replace('/\/\*.*?\*\//s', '', $contents); // Block comments.
|
| 160 |
|
| 161 |
$wrapper = new simpletest_unit_token_wrapper($contents, $file);
|
| 162 |
$wrapper->find_functions();
|
| 163 |
$wrapper->clear_tokens(); // Save memory.
|
| 164 |
return $wrapper;
|
| 165 |
}
|
| 166 |
|
| 167 |
/**
|
| 168 |
* Wrap a function for inclusion in test case.
|
| 169 |
*
|
| 170 |
* @param string $function Name of function.
|
| 171 |
* @return string Wrapped function.
|
| 172 |
*/
|
| 173 |
function simpletest_unit_wrap_function($function, array $calls) {
|
| 174 |
$steps = array();
|
| 175 |
foreach ($calls as $call) {
|
| 176 |
$steps[]= array('incoming' => array($call), 'return' => NULL);
|
| 177 |
}
|
| 178 |
|
| 179 |
$out = 'function test_'. $function ."() {\n";
|
| 180 |
if (count($steps)) {
|
| 181 |
$out .= ' ' . SIMPLETEST_UNIT_CALLBACK . "(\n";
|
| 182 |
$steps_out = simpletest_unit_export_array($steps);
|
| 183 |
$steps_out = preg_replace("/'incoming' => array\(\s+(.*?),\s+\)/", "'incoming' => array(\${1})", $steps_out);
|
| 184 |
$steps_out = preg_replace("/.*?\n/", ' ${0}', $steps_out);
|
| 185 |
$out .= $steps_out;
|
| 186 |
$out .= " );\n";
|
| 187 |
$out .= ' ' . SIMPLETEST_UNIT_CALLBACK . "('$function');\n";
|
| 188 |
}
|
| 189 |
$out .= "\n\n // TODO Auto-generated stub.\n";
|
| 190 |
$out .= "}\n\n";
|
| 191 |
return $out;
|
| 192 |
}
|
| 193 |
|
| 194 |
function simpletest_unit_export_array(array &$array) {
|
| 195 |
$out = var_export($array, TRUE) . "\n";
|
| 196 |
$out = preg_replace('/\d+ => /', '', $out);
|
| 197 |
$out = str_replace('array (', 'array(', $out);
|
| 198 |
$out = preg_replace('/=>\s+array\(/', '=> array(', $out);
|
| 199 |
$out = preg_replace('/^\s+$\n/m', '', $out);
|
| 200 |
return $out;
|
| 201 |
}
|
| 202 |
|
| 203 |
/**
|
| 204 |
* Wrap unit test for output.
|
| 205 |
*
|
| 206 |
* @param string $filename Name of file related to test.
|
| 207 |
* @param string $test Contents of test.
|
| 208 |
* @return string Wrapped test case.
|
| 209 |
*/
|
| 210 |
function simpletest_unit_wrap_test($filename, $test) {
|
| 211 |
$class = str_replace(array('.', '-'), '_', $filename);
|
| 212 |
$name = ucwords(str_replace('_', ' ', $class));
|
| 213 |
$class = str_replace(' ', '', $name);
|
| 214 |
return
|
| 215 |
"<?php
|
| 216 |
// \$Id\$
|
| 217 |
|
| 218 |
class {$class}TestCase extends DrupalUnitTestCase {
|
| 219 |
/**
|
| 220 |
* Implementation of getInfo().
|
| 221 |
*/
|
| 222 |
function getInfo() {
|
| 223 |
return array(
|
| 224 |
'name' => t('$name'),
|
| 225 |
'description' => t('Unit tests.'),
|
| 226 |
'group' => t('$name')
|
| 227 |
);
|
| 228 |
}
|
| 229 |
|
| 230 |
". trim(preg_replace('/(.+?)\n/', " $1\n", $test)) ."
|
| 231 |
}
|
| 232 |
";
|
| 233 |
}
|
| 234 |
|
| 235 |
/**
|
| 236 |
* Export the array of paramters as valid PHP syntax.
|
| 237 |
*
|
| 238 |
* @param array $paramters Parameters to be export.
|
| 239 |
* @return string Valid PHP syntax representing paramters.
|
| 240 |
*/
|
| 241 |
function simpletest_unit_export_parameters(array $paramters) {
|
| 242 |
$out = '';
|
| 243 |
foreach ($paramters as $name => $default) {
|
| 244 |
$out .= $name . ($default ? ' = ' . $default : '') . ', ';
|
| 245 |
}
|
| 246 |
return trim($out, ', ');
|
| 247 |
}
|
| 248 |
|
| 249 |
/**
|
| 250 |
* Make sure filename matches the requirements to be included in unit testing.
|
| 251 |
*
|
| 252 |
* @param string $file File to be checked.
|
| 253 |
* @return boolean File matches requirements.
|
| 254 |
*/
|
| 255 |
function simpletest_unit_match($file) {
|
| 256 |
static $patterns = array('*.php', '*.inc', '*.module');
|
| 257 |
foreach ($patterns as $pattern) {
|
| 258 |
if (fnmatch($pattern, $file) && !fnmatch('*.tpl.*', $file)) {
|
| 259 |
return TRUE;
|
| 260 |
}
|
| 261 |
}
|
| 262 |
return FALSE;
|
| 263 |
}
|
| 264 |
|
| 265 |
/**
|
| 266 |
* Make sure the directory is not on the list of directories to ingore.
|
| 267 |
*
|
| 268 |
* @param string $directory Directory to check.
|
| 269 |
* @return boolean Directory is not on the list of directories to ignore.
|
| 270 |
*/
|
| 271 |
function simpletest_unit_check_directory($directory) {
|
| 272 |
static $ignore = array('.', '..', 'CVS');
|
| 273 |
return is_dir($directory) && !in_array(basename($directory), $ignore);
|
| 274 |
}
|