Index: code_coverage.module
===================================================================
RCS file: /cvs/drupal-contrib/contributions/modules/code_coverage/code_coverage.module,v
retrieving revision 1.4
diff -u -r1.4 code_coverage.module
--- code_coverage.module	29 Jun 2008 00:43:48 -0000	1.4
+++ code_coverage.module	11 Mar 2010 09:32:21 -0000
@@ -1,35 +1,12 @@
 <?php
 // $Id: code_coverage.module,v 1.4 2008/06/29 00:43:48 cwgordon7 Exp $
 
-if (preg_match("/^simpletest\d+$/", $_SERVER['HTTP_USER_AGENT']) && function_exists('xdebug_start_code_coverage')) {
-  xdebug_start_code_coverage(XDEBUG_CC_UNUSED | XDEBUG_CC_DEAD_CODE);
-  register_shutdown_function('code_coverage_log');
-}
-
 /**
- * Checks to make sure our code is where it needs to be. (And if not, displays
- * a very scary warning to the user).
+ * @file
+ * Records code coverage while running tests.
+ *
+ * @author Jimmy Berry ("boombatower", http://drupal.org/user/214218)
  */
-function code_coverage_check_hacks() {
-  if (!preg_match("/^simpletest\d+$/", $_SERVER['HTTP_USER_AGENT']) && user_access('administer code coverage')) {
-    // Make sure our stuff is in index.php.
-    if (!variable_get('code_coverage_hacks', FALSE)) {
-      $passes = TRUE;
-      foreach (array('index.php', 'xmlrpc.php') as $file) {
-        $code = 'require_once \'./' . str_replace('\\', '/', substr(str_replace(getcwd(), '', __FILE__), 1)) . '\';' . "\n";
-        $contents = file_get_contents("./$file");
-        if (strpos($contents, $code) === FALSE) {
-          $passes = FALSE;
-          drupal_set_message(t('You must add the following code to the top of your @file file in order for code coverage reporting to work.<code><pre>@code</pre></code>', array('@code' => $code, '@file' => $file)), 'warning', FALSE);
-        }
-      }
-      if ($passes) {
-        variable_set('code_coverage_hacks', TRUE);
-      }
-    }
-    code_coverage_fetch_data();
-  }
-}
 
 /**
  * Implementation of hook_perm().
@@ -54,7 +31,6 @@
     'page arguments' => array('code_coverage_settings_form'),
     'access arguments' => array('administer code coverage'),
   );
-
   $items['coverage'] = array(
     'title' => 'Code coverage',
     'description' => 'Generate code coverage reports based on the collected coverage data.',
@@ -66,55 +42,6 @@
 }
 
 /**
- * Implementation of hook_cron().
- */
-function code_coverage_cron() {
-  variable_del('code_coverage_hacks');
-}
-
-/**
- * Implementation of hook_help().
- */
-function code_coverage_help() {
-  static $checked = FALSE;
-  if ($checked) {
-    return;
-  }
-  $checked = TRUE;
-  code_coverage_check_hacks();
-}
-
-/**
- * Stop recording. This is registered as a shutdown function.
- */
-function code_coverage_log() {
-  global $db_prefix, $db_prefix_original;
-  $preserved_prefix = $db_prefix;
-  $db_prefix = $db_prefix_original;
-  $GLOBALS['conf'] = variable_init();
-  $info = xdebug_get_code_coverage();
-  $text = '';
-  foreach ($info as $file => $lines) {
-    $basename = basename($file);
-    if ($basename != 'code_coverage.module' && $basename != 'code_coverage.install' && $basename != 'code_coverage.admin.inc' && $basename != 'settings.php') {
-      $text .= $file;
-      $text .= '$';
-      foreach ($lines as $line => $count) {
-        if ($count == -1) {
-          $count = 0;
-        }
-        $text .= sprintf('%s-%s,', $line, $count);
-      }
-      $text = substr($text, 0, -1);
-      $text .= "\n";
-    }
-  }
-  file_put_contents(variable_get('code_coverage_tmp_storage', '/tmp/') . variable_get('code_coverage_id', 1) . '.txt', $text, FILE_APPEND);
-  $db_prefix = $preserved_prefix;
-  $GLOBALS['conf'] = variable_init();
-}
-
-/**
  * Fetch all the code coverage data from a file and store it to the database.
  */
 function code_coverage_fetch_data() {
Index: code_coverage.install
===================================================================
RCS file: /cvs/drupal-contrib/contributions/modules/code_coverage/code_coverage.install,v
retrieving revision 1.2
diff -u -r1.2 code_coverage.install
--- code_coverage.install	28 Jun 2008 05:33:14 -0000	1.2
+++ code_coverage.install	11 Mar 2010 09:32:21 -0000
@@ -2,57 +2,119 @@
 // $Id: code_coverage.install,v 1.2 2008/06/28 05:33:14 cwgordon7 Exp $
 
 /**
- * Implementation of hook_install().
+ * @file
+ * Provides installation related functions.
+ *
+ * @author Jimmy Berry ("boombatower", http://drupal.org/user/214218)
  */
-function code_coverage_install() {
-  drupal_install_schema('code_coverage');
-}
 
 /**
- * Implementation of hook_uninstall().
+ * Implements hook_requirements().
  */
-function code_coverage_uninstall() {
-  drupal_uninstall_schema('code_coverage');
+function code_coverage_requirements($phase) {
+  global $code_coverage_installed;
+  $requirements = array();
+  $t = get_t();
+
+  $xdebug = function_exists('xdebug_start_code_coverage');
+  $requirements['code_coverage_xdebug'] = array(
+    'title' => $t('Xdebug'),
+    'value' => $xdebug ? $t('Installed') : $t('Missing'),
+    'severity' => $xdebug ? REQUIREMENT_OK : REQUIREMENT_ERROR,
+  );
+
+  $installed = !empty($code_coverage_installed) && $code_coverage_installed;
+  $requirements['code_coverage_xdebug'] = array(
+    'title' => $t('Xdebug patch'),
+    'value' => $installed ? $t('Installed') : $t('Missing'),
+    'severity' => $installed ? REQUIREMENT_OK : REQUIREMENT_ERROR,
+  );
+
+  return $requirements;
 }
 
 /**
- * Implementation of hook_schema().
+ * Implements hook_schema().
  */
 function code_coverage_schema() {
   $schema = array();
 
-  $schema['code_coverage'] = array(
-    'description' => t('A log of Drupal\'s code coverage.'),
+  $schema['code_coverage_file'] = array(
+    'description' => 'Files related to a coverage set.',
     'fields' => array(
-      'cid' => array(
-        'description' => t('The coverage id of this set of coverage tests.'),
+      'file_id' => array(
+        'description' => 'Unique file ID.',
+        'type' => 'serial',
+        'unsigned' => TRUE,
+        'not null' => TRUE,
+      ),
+      'coverage_set' => array(
+        'description' => 'Coverage set identifier.',
         'type' => 'int',
+        'unsigned' => TRUE,
         'not null' => TRUE,
-        'default' => 0,
       ),
-      'filename' => array(
-        'description' => t('The path to the file of this line of code (absolute).'),
+      'path' => array(
+        'description' => 'Relative path to file.',
         'type' => 'varchar',
         'length' => 255,
         'not null' => TRUE,
         'default' => '',
       ),
+    ),
+    'primary key' => array('file_id'),
+    'indexes' => array(
+      'coverage_set' => array('coverage_set'),
+      'path' => array('path'),
+    ),
+  );
+  $schema['code_coverage_line'] = array(
+    'description' => 'Lines related to a file.',
+    'fields' => array(
+      'file_id' => array(
+        'description' => 'Reference to file.',
+        'type' => 'int',
+        'unsigned' => TRUE,
+        'not null' => TRUE,
+      ),
       'line' => array(
-        'description' => t('The line number of the line of code.'),
+        'description' => 'Line number in file.',
         'type' => 'int',
+        'unsigned' => TRUE,
         'not null' => TRUE,
-        'default' => 0,
       ),
-      'times' => array(
-        'description' => t('The number of times the line of code has been hit while running tests.'),
+      'count' => array(
+        'description' => 'Number of times line was executed.',
+        'type' => 'int',
+        'size' => 'big',
+        'not null' => TRUE,
+      ),
+    ),
+    'primary key' => array('file_id', 'line'),
+  );
+  $schema['code_coverage_log'] = array(
+    'description' => 'Lines related to a file.',
+    'fields' => array(
+      'file_id' => array(
+        'description' => 'Reference to file.',
+        'type' => 'int',
+        'unsigned' => TRUE,
+        'not null' => TRUE,
+      ),
+      'line' => array(
+        'description' => 'Line number in file.',
+        'type' => 'int',
+        'unsigned' => TRUE,
+        'not null' => TRUE,
+      ),
+      'count' => array(
+        'description' => 'Number of times line was executed.',
         'type' => 'int',
         'size' => 'big',
         'not null' => TRUE,
-        'default' => 0,
       ),
     ),
-    'primary key' => array('cid', 'filename', 'line'),
   );
 
   return $schema;
-}
\ No newline at end of file
+}
Index: code_coverage.info
===================================================================
RCS file: /cvs/drupal-contrib/contributions/modules/code_coverage/code_coverage.info,v
retrieving revision 1.2
diff -u -r1.2 code_coverage.info
--- code_coverage.info	10 Mar 2010 23:01:26 -0000	1.2
+++ code_coverage.info	11 Mar 2010 09:32:21 -0000
@@ -6,4 +6,5 @@
 files[] = code_coverage.admin.inc
 files[] = code_coverage.module
 files[] = code_coverage.install
+files[] = code_coverage.xdebug.inc
 dependencies[] = simpletest
Index: code_coverage.xdebug.inc
===================================================================
RCS file: code_coverage.xdebug.inc
diff -N code_coverage.xdebug.inc
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ code_coverage.xdebug.inc	1 Jan 1970 00:00:00 -0000
@@ -0,0 +1,90 @@
+<?php
+// $Id$
+
+/**
+ * @file
+ * Provides Xdebug integration for Drupal.
+ *
+ * @author Jimmy Berry ("boombatower", http://drupal.org/user/214218)
+ */
+
+if (strpos($_SERVER['HTTP_USER_AGENT'], 'simpletest') !== FALSE) {
+  xdebug_start_code_coverage();
+//  xdebug_start_code_coverage(XDEBUG_CC_UNUSED);
+//  xdebug_start_code_coverage(XDEBUG_CC_UNUSED | XDEBUG_CC_DEAD_CODE);
+  drupal_register_shutdown_function('code_coverage_record');
+}
+
+/**
+ * Stop recording. This is registered as a shutdown function.
+ */
+function code_coverage_record() {
+  global $db_prefix;
+  $db_prefix_testing = $db_prefix;
+  $db_prefix = preg_replace('/s\d+$/m', '', $db_prefix);
+  $info = drupal_parse_info_file(DRUPAL_ROOT . '/' . drupal_get_path('module', 'code_coverage') . '/code_coverage.info');
+//  $coverage_set = db_select('simpletest_test_id', 's') // TODO
+//    ->fields('s', 'test_id')
+//    ->orderBy('test_id', 'DESC')
+//    ->range(0, 1)
+//    ->execute()
+//    ->fetchField();
+  $coverage_set = 1;
+
+  // Cycle through the code coverage for each file.
+  $coverage = xdebug_get_code_coverage();
+  foreach ($coverage as $file => $lines) {
+    // Use the relative file path and ensure that the file is not part of the
+    // code_coverage module.
+    $relative = str_replace(DRUPAL_ROOT . '/', '', $file); // TODO Deal with symbolic links.
+    $base = basename($relative);
+    if (!in_array($base, $info['files'])) {
+      // Determine the file_id if it has already been created.
+      $file_id = db_select('code_coverage_file', 'f')
+        ->fields('f', array('file_id'))
+        ->condition('coverage_set', $coverage_set)
+        ->condition('path', $relative)
+        ->execute()
+        ->fetchField();
+
+      // Create a file record if not already done.
+      if (!$file_id) {
+        $file = array(
+          'coverage_set' => $coverage_set,
+          'path' => $relative,
+        );
+        drupal_write_record('code_coverage_file', $file);
+        $file_id = $file['file_id'];
+      }
+
+      $insert = db_insert('code_coverage_log')->fields(array('file_id', 'line', 'count'));
+      foreach ($lines as $line => $count) {
+        // Ignore line 0.
+        if ($line) {
+          $insert->values(array(
+            'file_id' => $file_id,
+            'line' => $line,
+            'count' => $count,
+          ));
+        }
+      }
+      $insert->execute();
+    }
+  }
+
+  code_coverage_process(); // TODO Remove.
+
+  $db_prefix = $db_prefix_testing;
+}
+
+function code_coverage_process() {
+  $query = db_select('code_coverage_log', 'l')
+    ->fields('l', array('file_id', 'line'))
+    ->groupBy('file_id')
+    ->groupBy('line');
+  $query->addExpression('SUM(count)', 'count');
+  $lines = $query->execute();
+  foreach ($lines as $line) {
+    drupal_write_record('code_coverage_line', $line);
+  }
+}
