Index: modules/simpletest/simpletest.module
===================================================================
RCS file: /cvs/drupal/drupal/modules/simpletest/simpletest.module,v
retrieving revision 1.63
diff -u -r1.63 simpletest.module
--- modules/simpletest/simpletest.module	30 Jul 2009 10:46:53 -0000	1.63
+++ modules/simpletest/simpletest.module	31 Jul 2009 02:28:22 -0000
@@ -252,6 +252,11 @@
  *   Found any entries in log.
  */
 function simpletest_log_read($test_id, $prefix, $test_class, $during_test = FALSE) {
+  return simpletest_log_read_errors($test_id, $prefix, $test_class, $during_test) ||
+          simpletest_log_read_debug($test_id, $prefix, $test_class, $during_test);
+}
+
+function simpletest_log_read_errors($test_id, $prefix, $test_class, $during_test = FALSE) {
   $log = file_directory_path() . ($during_test ? '' : '/simpletest/' . substr($prefix, 10)) . '/error.log';
   $found = FALSE;
   if (file_exists($log)) {
@@ -275,6 +280,26 @@
   return $found;
 }
 
+function simpletest_log_read_debug($test_id, $prefix, $test_class, $during_test = FALSE) {
+  $log = file_directory_path() . ($during_test ? '' : '/simpletest/' . substr($prefix, 10)) . '/drupal_debug.log';
+  $found = FALSE;
+  if (file_exists($log)) {
+    $contents = file_get_contents($log);
+
+    if (preg_match_all('/\[Debug\] (.*?); in function (.*?) defined in (.*?) on line (\d+)/s', $contents, $matches, PREG_SET_ORDER)) {
+      foreach ($matches as $match) {
+        $caller = array(
+          'function' => $match[2],
+          'line' => $match[4],
+          'file' => $match[3],
+        );
+        DrupalTestCase::insertAssert($test_id, $test_class, TRUE, $match[1], 'Debug', $caller);
+      }
+    }
+  }
+  return $found;
+}
+
 /**
  * Get a list of all of the tests provided by the system.
  *
Index: modules/simpletest/drupal_web_test_case.php
===================================================================
RCS file: /cvs/drupal/drupal/modules/simpletest/drupal_web_test_case.php,v
retrieving revision 1.132
diff -u -r1.132 drupal_web_test_case.php
--- modules/simpletest/drupal_web_test_case.php	30 Jul 2009 10:46:53 -0000	1.132
+++ modules/simpletest/drupal_web_test_case.php	31 Jul 2009 02:28:22 -0000
@@ -395,6 +395,8 @@
     }
 
     set_error_handler(array($this, 'errorHandler'));
+    drupal_register_debug_function('_simpletest_drupal_debug');
+
     $methods = array();
     // Iterate through all the methods in this class.
     foreach (get_class_methods(get_class($this)) as $method) {
Index: includes/common.inc
===================================================================
RCS file: /cvs/drupal/drupal/includes/common.inc,v
retrieving revision 1.949
diff -u -r1.949 common.inc
--- includes/common.inc	30 Jul 2009 19:57:09 -0000	1.949
+++ includes/common.inc	31 Jul 2009 02:28:22 -0000
@@ -3476,6 +3476,8 @@
     // phase so as long as it is a SimpleTest user-agent it is valid.
     ini_set('log_errors', 1);
     ini_set('error_log', file_directory_path() . '/error.log');
+
+    drupal_register_debug_function('_simpletest_drupal_debug');
   }
 
   // Emit the correct charset HTTP header.
@@ -4845,3 +4847,129 @@
   }
   variable_set('css_js_query_string', $new_character . substr($string_history, 0, 19));
 }
+
+/**
+ * Register debug function to be called by drupal_debug().
+ *
+ * The function allows overriding of the default debug functionality provided
+ * by core.
+ *
+ * @param $function
+ *   (optional) Debug function to register, or NULL to leave current value.
+ * @return
+ *   The registered debug function.
+ */
+function drupal_register_debug_function($function = NULL) {
+  $debug_function = &drupal_static(__FUNCTION__, '_drupal_debug');
+
+  if ($function) {
+    $debug_function = $function;
+  }
+
+  return $debug_function;
+}
+
+/**
+ * Alias for drupal_debug().
+ *
+ * @see drupal_debug()
+ */
+function dd($data, $label = NULL) {
+  drupal_debug($data, $label, debug_backtrace());
+}
+
+/**
+ * Debug function used to outputting debug information.
+ *
+ * The debug information is passed on to the registered debug function that was
+ * set using drupal_register_debug_function().
+ *
+ * @param $data
+ *   Data to be output.
+ * @param $label
+ *   Label to prefix the data.
+ * @param $backtrace
+ *   (optional) Internal backtrace parameter used when called by dd().
+ */
+function drupal_debug($data, $label = NULL, array $backtrace = array()) {
+  // If the backtrace has not been set by dd() then retrieve the backtrace.
+  if (!$backtrace) {
+    $backtrace = debug_backtrace();
+  }
+
+  $function = drupal_register_debug_function();
+  $function($data, $label, $backtrace);
+}
+
+/**
+ * Default debug implementation.
+ *
+ * If the error_level variable is set to ERROR_REPORTING_DISPLAY_ALL then the
+ * data will be ouput via drupal_set_message(). Data is always output to the
+ * temporary file directory in the file 'drupal_debug.log'.
+ *
+ * @param $data
+ *   Data to be output.
+ * @param $label
+ *   Label to prefix the data.
+ * @param $backtrace
+ *   Backtrace from debug_backtrace() called from the debug wrapper.
+ * @return If successfully wrote debug data to file TRUE, otherwise FALSE.
+ */
+function _drupal_debug($data, $label = NULL, array $backtrace) {
+  $string = _drupal_debug_message($data, $label, $backtrace);
+
+  if (variable_get('error_level', ERROR_REPORTING_DISPLAY_ALL) == ERROR_REPORTING_DISPLAY_ALL) {
+    drupal_set_message($string);
+  }
+
+  $file = file_directory_temp() . '/drupal_debug.log';
+  if (file_put_contents($file, $string, FILE_APPEND) === FALSE) {
+    drupal_set_message(t('The temporary debug log cound not be written.'), 'error');
+    return FALSE;
+  }
+  return TRUE;
+}
+
+/**
+ * SimpleTest debug implemtation.
+ *
+ * Store debug output in a file in the test file directory.
+ *
+ * @see _drupal_debug()
+ */
+function _simpletest_drupal_debug($data, $label = NULL, array $backtrace) {
+  $string = _drupal_debug_message($data, $label, $backtrace);
+  $file = file_directory_path() . '/drupal_debug.log';
+  if (file_put_contents($file, $string, FILE_APPEND) === FALSE) {
+    trigger_error('The temporary debug log cound not be written.');
+    return FALSE;
+  }
+  return TRUE;
+}
+
+/**
+ * Create the standard debug message.
+ *
+ * @param $data
+ *   Data to be output.
+ * @param $label
+ *   Label to prefix the data.
+ * @param $backtrace
+ *   Backtrace from debug_backtrace() called from the debug wrapper.
+ * @return
+ *   Standard debug message of the following format:
+ *   [Debug] STRING; in function FUNCTION defined in FILE on line LINE.
+ */
+function _drupal_debug_message($data, $label = NULL, array $backtrace) {
+  // Print $data contents to string.
+  $string = print_r($data, TRUE) . "\n";
+  if ($label) {
+    $string = $label . ': ' . $string;
+  }
+  $string = trim($string);
+
+  // Add prefix to indicate beginning of debug data.
+  $caller = _drupal_get_last_caller($backtrace);
+  return "[Debug] $string; in function {$caller['function']} defined in {$caller['file']} on line {$caller['line']}.\n";
+}
