2
// $Id: code_coverage.admin.inc,v 1.11 2008/06/29 23:46:23 cwgordon7 Exp $
5
* Returns all the currently supported reporters.
8
* All the currently supported reports, in the format 'code' => 'readable'.
10
function code_coverage_available_reporters() {
13
'db' => t('Database dump'),
20
* FAPI callback for the code coverage settings form.
22
function code_coverage_settings_form() {
23
drupal_add_js(drupal_get_path('module', 'code_coverage') .'/code_coverage.js');
26
$form['#prefix'] = t('Changing these settings does not require regeneration of coverage statistics.');
28
// Generate a list of all files we /could/ generate reports for.
29
$result = db_query('SELECT DISTINCT(filename) FROM {code_coverage}');
31
while ($filename = db_fetch_array($result)) {
32
$files[$filename['filename']] = str_replace('\\', '/', substr(str_replace(getcwd() , '', $filename['filename']), 1));
35
$form['code_coverage_all'] = array(
36
'#type' => 'checkbox',
37
'#title' => t('Include all files'),
38
'#description' => t('If checked, all files will be included in coverage reports. Otherwise, you may chose from a list of files to include.'),
39
'#default_value' => variable_get('code_coverage_all', TRUE),
42
$form['code_coverage_files'] = array(
44
'#title' => t('Code coverage files'),
45
'#description' => t('Select the files which should be included in all code coverage reports.'),
48
'#default_value' => variable_get('code_coverage_files', array()),
51
$form['code_coverage_format'] = array(
53
'#title' => t('Available code coverage report formats.'),
54
'#options' => code_coverage_available_reporters(),
55
'#description' => t('Select the format in which code coverage reports should be allowed to be generated.'),
56
'#default_value' => variable_get('code_coverage_format', array('html')),
61
$form['code_coverage_covered'] = array(
63
'#title' => t('Definition of coverage'),
64
'#description' => t('Select the number of calls at or beyond which a line of code is considered "covered".'),
65
'#options' => drupal_map_assoc(array(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 12, 15, 20, 25, 35, 50, 75, 100)),
66
'#default_value' => variable_get('code_coverage_covered', 1),
70
$form['code_coverage_file_good'] = array(
72
'#title' => t('Point of "good" coverage'),
73
'#description' => t('Select the percentage of called lines a file needs to have to be considered to have "good" coverage.'),
74
'#options' => drupal_map_assoc(array(10, 25, 40, 50, 60, 65, 70, 75, 80, 85, 90, 93, 95, 96, 97, 98, 99, 100)),
75
'#default_value' => variable_get('code_coverage_file_good', 80),
79
$form['code_coverage_file_ok'] = array(
81
'#title' => t('Point of "ok" coverage'),
82
'#description' => t('Select the percentage of called lines a file needs to have to be considered to have "ok" coverage.'),
83
'#options' => drupal_map_assoc(array(10, 25, 40, 50, 60, 65, 70, 75, 80, 85, 90, 93, 95, 96, 97, 98, 99, 100)),
84
'#default_value' => variable_get('code_coverage_file_ok', 60),
88
$form['code_coverage_tmp_storage'] = array(
89
'#type' => 'textfield',
90
'#title' => t('Temporary storage'),
91
'#description' => t('A place to temporarily store data, as an absolute path. You should include a trailing slash.'),
92
'#default_value' => variable_get('code_coverage_tmp_storage', '/tmp/'),
96
return system_settings_form($form);
100
* Menu callback for the generation of the actual coverage report.
102
function code_coverage_generate_report($reporter = NULL, $cid = NULL) {
103
$reporters = variable_get('code_coverage_format', array('html'));
104
if (is_null($cid) && count($reporters) == 1) {
107
$reporter = array_shift($copy);
109
if (is_null($reporter)) {
111
$reporter_names = code_coverage_available_reporters();
112
foreach ($reporters as $reporter) {
113
if (isset($reporter_names[$reporter])) {
114
$items[] = l($reporter_names[$reporter], 'coverage/' . $reporter);
117
return theme('item_list', $items, t('Choose from any of the following formats.'));
119
$callback = 'code_coverage_generate_' . $reporter . '_report';
120
if (!function_exists($callback) || !in_array($reporter, $reporters)) {
121
return t('The %format format is not available.', array('%format' => $reporter));
125
$result = db_query('SELECT DISTINCT(cid) FROM {code_coverage}');
127
while ($cid = db_fetch_array($result)) {
128
$items[] = l(t('Code coverage report #@num', array('@num' => $cid['cid'])), 'coverage/'. $reporter . '/' . $cid['cid']);
130
return theme('item_list', $items, t('Choose from any of the following reports.'), 'ol');
132
$covered = variable_get('code_coverage_covered', 1);
134
if (!isset($_GET['file'])) {
135
$files = variable_get('code_coverage_all', TRUE) ? NULL : variable_get('code_coverage_files', array());
136
if (is_array($files) && empty($files)) {
137
return t('No code coverage data found.');
141
$files = $_GET['file'];
142
if (file_exists($files)) {
146
$lines = code_coverage_load_lines($files, $cid);
147
if (isset($file) && !isset($lines[$file]) || empty($lines)) {
148
return drupal_not_found();
150
return $callback($lines, $covered, isset($file) ? $file : NULL, $cid);
154
* Helper function for code_coverage_generate_report() - loads all of the lines
158
* The files to restrict the load to.
160
* An array of lines loaded from the database.
162
function code_coverage_load_lines($files, $cid) {
163
if (is_array($files)) {
164
$placeholders = db_placeholders($files, 'varchar');
165
$result = db_query('SELECT * FROM {code_coverage} WHERE filename IN (' . $placeholders . ') AND cid = %d', array_merge($files, array($cid)));
167
elseif (!is_null($files)) {
168
$result = db_query("SELECT * FROM {code_coverage} WHERE filename = '%s' AND cid = %d", $files, $cid);
171
$result = db_query('SELECT * FROM {code_coverage} WHERE cid = %d', $cid);
174
while ($line = db_fetch_array($result)) {
175
$lines[$line['filename']][$line['line']] = $line['times'];
182
* Callback for CSV reporter.
184
function code_coverage_generate_csv_report($lines, $covered, $file, $cid) {
186
foreach ($lines as $file => $info) {
187
foreach ($info as $line => $count) {
188
$csv .= '"' . str_replace('"', '""', $file) . '",' . $line . ',' . $count . "\n";
191
header('Content-Type: text/plain');
193
drupal_page_footer();
198
* Callback for database reporter.
200
function code_coverage_generate_db_report($lines, $covered, $file, $cid) {
202
$queries[] = '<?php';
203
foreach ($lines as $file => $info) {
204
foreach ($info as $line => $count) {
205
$queries[] = 'db_query(\'INSERT INTO {code_coverage} (cid, filename, line, times) VALUES (%d, \\\'%s\\\' %d, %d)\', ' . $cid . ', ' . var_export($file, TRUE) . ', ' . $line . ', ' . $count . ');';
208
header('Content-Type: text/plain');
209
print implode("\n", $queries);
210
drupal_page_footer();
214
function code_coverage_render_filter_form() {
216
$form['sample_textfield'] = array(
217
'#description' => 'Filter list of files by entering regular expression.',
219
'#type' => 'textfield',
220
'#title' => 'Filter',
221
'#id' => 'file-filter',
223
return drupal_render_form('file-filter-form', $form);
227
* Callback for HTML reporter.
229
function code_coverage_generate_html_report($lines, $covered, $file, $cid) {
230
drupal_add_css(drupal_get_path('module', 'code_coverage') .'/code_coverage.css');
232
$good = variable_get('code_coverage_file_good', 80);
233
$ok = variable_get('code_coverage_file_ok', 60);
234
drupal_add_js(drupal_get_path('module', 'code_coverage') .'/code_coverage.js');
235
drupal_add_js(drupal_get_path('module', 'code_coverage') .'/file_list_filter.js');
237
foreach ($lines as $file => $info) {
238
$covered_lines[$file] = 0;
239
$uncovered_lines[$file] = 0;
240
foreach ($info as $line => $count) {
241
if ($count >= $covered) {
242
$covered_lines[$file]++;
245
$uncovered_lines[$file]++;
249
$row[] = l(str_replace('\\', '/', substr(str_replace(getcwd() , '', $file), 1)), 'coverage/html/' . $cid, array('query' => array('file' => $file)));
250
$row[] = $covered_lines[$file];
251
$row[] = $uncovered_lines[$file];
252
$row[] = sprintf('%04.2f%%', ($covered_lines[$file] * 100) / ($covered_lines[$file] + $uncovered_lines[$file]));
253
$rows[] = array('data' => $row, 'class' => ((substr(end($row), 0, -1) >= $good) ? 'code-coverage-covered' : ((substr(end($row), 0, -1) >= $ok) ? 'code-coverage-moderate' : 'code-coverage-uncovered')));
255
$total_covered = array_sum($covered_lines);
256
$total_uncovered = array_sum($uncovered_lines);
258
$row[] = t('Overall');
259
$row[] = $total_covered;
260
$row[] = $total_uncovered;
261
$row[] = sprintf('%04.2f%%', ($total_covered * 100) / ($total_covered + $total_uncovered));
262
$row = array('data' => $row, 'class' => 'code-coverage-overview ' . ((substr(end($row), 0, -1) > $good) ? 'code-coverage-covered' : ((substr(end($row), 0, -1) > $ok) ? 'code-coverage-moderate' : 'code-coverage-uncovered')));
263
array_unshift($rows, $row);
265
return code_coverage_render_filter_form() .
266
theme('table', array(t('File !arrow', array('!arrow' => theme('image', 'misc/arrow-asc.png'))), t('Covered lines'), t('Uncovered lines'), t('Code coverage %')), $rows, array('class' => 'code-coverage-overview-report'));
269
drupal_set_title(t('Code coverage for @file', array('@file' => str_replace('\\', '/', substr(str_replace(getcwd() , '', $file), 1)))));
270
$contents = file_get_contents($file);
271
$file_lines = explode("\n", $contents);
272
$lines = $lines[$file];
274
foreach ($file_lines as $key => $line) {
277
$row[] = isset($lines[$key + 1]) ? $lines[$key + 1] : '';
278
$row[] = '<pre>' . check_plain(wordwrap($line)) . '</pre>';
279
$rows[] = array('data' => $row, 'id' => 'code-coverage-' . ($key + 1), 'class' => (isset($lines[$key + 1]) ? ($lines[$key + 1] >= $covered ? 'code-coverage-covered' : 'code-coverage-uncovered') : 'code-coverage-none'));
281
return theme('table', array(t('Line #'), t('Times called'), t('Code')), $rows, array('class' => 'code-coverage-file-report'));
286
* Callback for XML reporter.
288
function code_coverage_generate_xml_report($lines, $covered, $file, $cid) {
289
$xml = '<?xml version="1.0" encoding="utf-8"?>' . "\n";
290
$xml .= '<coverage_report>' . "\n";
291
foreach ($lines as $file => $info) {
292
$xml .= ' <file>' . "\n";
293
$xml .= ' <filename>' . check_plain($file) . '</filename>' . "\n";
294
$xml .= ' <coverage>' . "\n";
295
foreach ($info as $line => $count) {
296
$xml .= ' <line>' . "\n";
297
$xml .= ' <number>' . $line . '</number>' . "\n";
298
$xml .= ' <count>' . $count . '</count>' . "\n";
299
$xml .= ' </line>' . "\n";
301
$xml .= ' </coverage>' . "\n";
302
$xml .= ' </file>' . "\n";
304
$xml .= '</coverage_report>';
305
header('Content-Type: text/xml');
307
drupal_page_footer();
b'\\ No newline at end of file'