/[drupal]/contributions/modules/code_coverage/code_coverage.admin.inc
ViewVC logotype

Contents of /contributions/modules/code_coverage/code_coverage.admin.inc

Parent Directory Parent Directory | Revision Log Revision Log | View Revision Graph Revision Graph


Revision 1.11 - (show annotations) (download) (as text)
Sun Jun 29 23:46:23 2008 UTC (16 months, 3 weeks ago) by cwgordon7
Branch: MAIN
CVS Tags: HEAD
Changes since 1.10: +3 -3 lines
File MIME type: text/x-php
UI improvements.
1 <?php
2 // $Id: code_coverage.admin.inc,v 1.10 2008/06/29 03:36:20 cwgordon7 Exp $
3
4 /**
5 * Returns all the currently supported reporters.
6 *
7 * @return
8 * All the currently supported reports, in the format 'code' => 'readable'.
9 */
10 function code_coverage_available_reporters() {
11 return array(
12 'csv' => t('CSV'),
13 'db' => t('Database dump'),
14 'html' => t('HTML'),
15 'xml' => t('XML'),
16 );
17 }
18
19 /**
20 * FAPI callback for the code coverage settings form.
21 */
22 function code_coverage_settings_form() {
23 drupal_add_js(drupal_get_path('module', 'code_coverage') .'/code_coverage.js');
24
25 $form = array();
26 $form['#prefix'] = t('Changing these settings does not require regeneration of coverage statistics.');
27
28 // Generate a list of all files we /could/ generate reports for.
29 $result = db_query('SELECT DISTINCT(filename) FROM {code_coverage}');
30 $files = array();
31 while ($filename = db_fetch_array($result)) {
32 $files[$filename['filename']] = str_replace('\\', '/', substr(str_replace(getcwd() , '', $filename['filename']), 1));
33 }
34
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),
40 );
41
42 $form['code_coverage_files'] = array(
43 '#type' => 'select',
44 '#title' => t('Code coverage files'),
45 '#description' => t('Select the files which should be included in all code coverage reports.'),
46 '#multiple' => TRUE,
47 '#options' => $files,
48 '#default_value' => variable_get('code_coverage_files', array()),
49 );
50
51 $form['code_coverage_format'] = array(
52 '#type' => 'select',
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')),
57 '#multiple' => TRUE,
58 '#required' => TRUE,
59 );
60
61 $form['code_coverage_covered'] = array(
62 '#type' => 'select',
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),
67 '#required' => TRUE,
68 );
69
70 $form['code_coverage_file_good'] = array(
71 '#type' => 'select',
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),
76 '#required' => TRUE,
77 );
78
79 $form['code_coverage_file_ok'] = array(
80 '#type' => 'select',
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),
85 '#required' => TRUE,
86 );
87
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/'),
93 '#required' => TRUE,
94 );
95
96 return system_settings_form($form);
97 }
98
99 /**
100 * Menu callback for the generation of the actual coverage report.
101 */
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) {
105 $cid = $reporter;
106 $copy = $reporters;
107 $reporter = array_shift($copy);
108 }
109 if (is_null($reporter)) {
110 $items = array();
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);
115 }
116 }
117 return theme('item_list', $items, t('Choose from any of the following formats.'));
118 }
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));
122 }
123
124 if (is_null($cid)) {
125 $result = db_query('SELECT DISTINCT(cid) FROM {code_coverage}');
126 $items = array();
127 while ($cid = db_fetch_array($result)) {
128 $items[] = l(t('Code coverage report #@num', array('@num' => $cid['cid'])), 'coverage/'. $reporter . '/' . $cid['cid']);
129 }
130 return theme('item_list', $items, t('Choose from any of the following reports.'), 'ol');
131 }
132 $covered = variable_get('code_coverage_covered', 1);
133
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.');
138 }
139 }
140 else {
141 $files = $_GET['file'];
142 if (file_exists($files)) {
143 $file = $files;
144 }
145 }
146 $lines = code_coverage_load_lines($files, $cid);
147 if (isset($file) && !isset($lines[$file]) || empty($lines)) {
148 return drupal_not_found();
149 }
150 return $callback($lines, $covered, isset($file) ? $file : NULL, $cid);
151 }
152
153 /**
154 * Helper function for code_coverage_generate_report() - loads all of the lines
155 * from the database.
156 *
157 * @param $files
158 * The files to restrict the load to.
159 * @return
160 * An array of lines loaded from the database.
161 */
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)));
166 }
167 elseif (!is_null($files)) {
168 $result = db_query("SELECT * FROM {code_coverage} WHERE filename = '%s' AND cid = %d", $files, $cid);
169 }
170 else {
171 $result = db_query('SELECT * FROM {code_coverage} WHERE cid = %d', $cid);
172 }
173 $lines = array();
174 while ($line = db_fetch_array($result)) {
175 $lines[$line['filename']][$line['line']] = $line['times'];
176 }
177 ksort($lines);
178 return $lines;
179 }
180
181 /**
182 * Callback for CSV reporter.
183 */
184 function code_coverage_generate_csv_report($lines, $covered, $file, $cid) {
185 $csv = '';
186 foreach ($lines as $file => $info) {
187 foreach ($info as $line => $count) {
188 $csv .= '"' . str_replace('"', '""', $file) . '",' . $line . ',' . $count . "\n";
189 }
190 }
191 header('Content-Type: text/plain');
192 print $csv;
193 drupal_page_footer();
194 exit;
195 }
196
197 /**
198 * Callback for database reporter.
199 */
200 function code_coverage_generate_db_report($lines, $covered, $file, $cid) {
201 $queries = array();
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 . ');';
206 }
207 }
208 header('Content-Type: text/plain');
209 print implode("\n", $queries);
210 drupal_page_footer();
211 exit;
212 }
213
214 /**
215 * Callback for HTML reporter.
216 */
217 function code_coverage_generate_html_report($lines, $covered, $file, $cid) {
218 drupal_add_css(drupal_get_path('module', 'code_coverage') .'/code_coverage.css');
219 if (empty($file)) {
220 $good = variable_get('code_coverage_file_good', 80);
221 $ok = variable_get('code_coverage_file_ok', 60);
222 drupal_add_js(drupal_get_path('module', 'code_coverage') .'/code_coverage.js');
223 $rows = array();
224 foreach ($lines as $file => $info) {
225 $covered_lines[$file] = 0;
226 $uncovered_lines[$file] = 0;
227 foreach ($info as $line => $count) {
228 if ($count >= $covered) {
229 $covered_lines[$file]++;
230 }
231 else {
232 $uncovered_lines[$file]++;
233 }
234 }
235 $row = array();
236 $row[] = l(str_replace('\\', '/', substr(str_replace(getcwd() , '', $file), 1)), 'coverage/html/' . $cid, array('query' => array('file' => $file)));
237 $row[] = $covered_lines[$file];
238 $row[] = $uncovered_lines[$file];
239 $row[] = sprintf('%04.2f%%', ($covered_lines[$file] * 100) / ($covered_lines[$file] + $uncovered_lines[$file]));
240 $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')));
241 }
242 $total_covered = array_sum($covered_lines);
243 $total_uncovered = array_sum($uncovered_lines);
244 $row = array();
245 $row[] = t('Overall');
246 $row[] = $total_covered;
247 $row[] = $total_uncovered;
248 $row[] = sprintf('%04.2f%%', ($total_covered * 100) / ($total_covered + $total_uncovered));
249 $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')));
250 array_unshift($rows, $row);
251 return 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'));
252 }
253 else {
254 drupal_set_title(t('Code coverage for @file', array('@file' => str_replace('\\', '/', substr(str_replace(getcwd() , '', $file), 1)))));
255 $contents = file_get_contents($file);
256 $file_lines = explode("\n", $contents);
257 $lines = $lines[$file];
258 $rows = array();
259 foreach ($file_lines as $key => $line) {
260 $row = array();
261 $row[] = $key + 1;
262 $row[] = isset($lines[$key + 1]) ? $lines[$key + 1] : '';
263 $row[] = '<pre>' . check_plain(wordwrap($line)) . '</pre>';
264 $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'));
265 }
266 return theme('table', array(t('Line #'), t('Times called'), t('Code')), $rows, array('class' => 'code-coverage-file-report'));
267 }
268 }
269
270 /**
271 * Callback for XML reporter.
272 */
273 function code_coverage_generate_xml_report($lines, $covered, $file, $cid) {
274 $xml = '<?xml version="1.0" encoding="utf-8"?>' . "\n";
275 $xml .= '<coverage_report>' . "\n";
276 foreach ($lines as $file => $info) {
277 $xml .= ' <file>' . "\n";
278 $xml .= ' <filename>' . check_plain($file) . '</filename>' . "\n";
279 $xml .= ' <coverage>' . "\n";
280 foreach ($info as $line => $count) {
281 $xml .= ' <line>' . "\n";
282 $xml .= ' <number>' . $line . '</number>' . "\n";
283 $xml .= ' <count>' . $count . '</count>' . "\n";
284 $xml .= ' </line>' . "\n";
285 }
286 $xml .= ' </coverage>' . "\n";
287 $xml .= ' </file>' . "\n";
288 }
289 $xml .= '</coverage_report>';
290 header('Content-Type: text/xml');
291 print $xml;
292 drupal_page_footer();
293 exit;
294 }

  ViewVC Help
Powered by ViewVC 1.1.2