Index: modules/simpletest/simpletest.info =================================================================== RCS file: /cvs/drupal/drupal/modules/simpletest/simpletest.info,v retrieving revision 1.4 diff -u -r1.4 simpletest.info --- modules/simpletest/simpletest.info 11 Oct 2008 02:33:01 -0000 1.4 +++ modules/simpletest/simpletest.info 1 May 2009 01:17:37 -0000 @@ -5,4 +5,5 @@ version = VERSION core = 7.x files[] = simpletest.module +files[] = simpletest.pages.inc files[] = simpletest.install Index: modules/simpletest/simpletest.module =================================================================== RCS file: /cvs/drupal/drupal/modules/simpletest/simpletest.module,v retrieving revision 1.40 diff -u -r1.40 simpletest.module --- modules/simpletest/simpletest.module 27 Apr 2009 07:44:09 -0000 1.40 +++ modules/simpletest/simpletest.module 1 May 2009 01:17:38 -0000 @@ -2,6 +2,11 @@ // $Id: simpletest.module,v 1.40 2009/04/27 07:44:09 dries Exp $ /** + * @file + * Provides testing functionality. + */ + +/** * Implementation of hook_help(). */ function simpletest_help($path, $arg) { @@ -35,6 +40,14 @@ 'description' => 'Run tests against Drupal core and your active modules. These tests help assure that your site code is working as designed.', 'access arguments' => array('administer unit tests'), ); + $items['admin/development/testing/results/%'] = array( + 'title' => 'Test result', + 'page callback' => 'drupal_get_form', + 'page arguments' => array('simpletest_result_form', 4), + 'description' => 'View result of tests.', + 'access arguments' => array('administer unit tests'), + 'type' => MENU_CALLBACK, + ); return $items; } @@ -56,247 +69,14 @@ function simpletest_theme() { return array( 'simpletest_test_table' => array( - 'arguments' => array('table' => NULL) + 'arguments' => array('table' => NULL), + 'file' => 'simpletest.pages.inc', ), 'simpletest_result_summary' => array( - 'arguments' => array('form' => NULL) - ), - ); -} - -/** - * Menu callback for both running tests and listing possible tests - */ -function simpletest_test_form() { - $form = array(); - - // List out all tests in groups for selection. - $uncategorized_tests = simpletest_get_all_tests(); - $tests = simpletest_categorize_tests($uncategorized_tests); - $selected_tests = array(); - - if (isset($_SESSION['test_id'])) { - // Select all results using the active test ID used to group them. - $results = db_query("SELECT * FROM {simpletest} WHERE test_id = %d ORDER BY test_class, message_id", $_SESSION['test_id']); - - $summary = array( - '#theme' => 'simpletest_result_summary', - '#pass' => 0, - '#fail' => 0, - '#exception' => 0, - '#weight' => -10, - ); - $form['summary'] = $summary; - $form['results'] = array(); - $group_summary = array(); - $map = array( - 'pass' => theme('image', 'misc/watchdog-ok.png'), - 'fail' => theme('image', 'misc/watchdog-error.png'), - 'exception' => theme('image', 'misc/watchdog-warning.png'), - ); - $header = array(t('Message'), t('Group'), t('Filename'), t('Line'), t('Function'), array('colspan' => 2, 'data' => t('Status'))); - while ($result = db_fetch_object($results)) { - $class = $result->test_class; - $info = call_user_func(array($class, 'getInfo')); - $group = $info['group']; - $selected_tests[$group][$class] = TRUE; - if (!isset($group_summary[$group])) { - $group_summary[$group] = $summary; - } - $element = &$form['results'][$group][$class]; - if (!isset($element)) { - $element['summary'] = $summary; - } - $status = $result->status; - // This reporter can only handle pass, fail and exception. - if (isset($map[$status])) { - $element['#title'] = $info['name']; - $status_index = '#'. $status; - $form['summary'][$status_index]++; - $group_summary[$group][$status_index]++; - $element['summary'][$status_index]++; - $element['result_table']['#rows'][] = array( - 'data' => array( - $result->message, - $result->message_group, - basename($result->file), - $result->line, - $result->function, - $map[$status], - ), - 'class' => "simpletest-$status", - ); - } - unset($element); - } - - // Clear test results. - simpletest_clean_results_table($_SESSION['test_id']); - unset($_SESSION['test_id']); - - $all_ok = TRUE; - foreach ($form['results'] as $group => &$elements) { - $group_ok = TRUE; - foreach ($elements as $class => &$element) { - $info = call_user_func(array($class, 'getInfo')); - $ok = $element['summary']['#fail'] + $element['summary']['#exception'] == 0; - $element += array( - '#type' => 'fieldset', - '#collapsible' => TRUE, - '#collapsed' => $ok, - '#description' => $info['description'], - ); - $element['result_table']['#markup'] = theme('table', $header, $element['result_table']['#rows']); - $element['summary']['#ok'] = $ok; - $group_ok = $group_ok && $ok; - } - $elements += array( - '#type' => 'fieldset', - '#title' => $group, - '#collapsible' => TRUE, - '#collapsed' => $group_ok, - 'summary' => $group_summary[$group], - ); - $elements['summary']['#ok'] = $group_ok; - $all_ok = $group_ok && $all_ok; - } - $form['summary']['#ok'] = $all_ok; - } - $form['tests'] = array( - '#type' => 'fieldset', - '#title' => t('Tests'), - '#description' => t('Select the tests you would like to run, and click Run tests.'), - ); - $form['tests']['table'] = array( - '#theme' => 'simpletest_test_table' - ); - foreach ($tests as $group_name => $test_group) { - $form['tests']['table'][$group_name] = array( - '#collapsed' => TRUE, - ); - foreach ($test_group as $class => $info) { - $is_selected = isset($selected_tests[$group_name][$class]); - $form['tests']['table'][$group_name][$class] = array( - '#type' => 'checkbox', - '#title' => $info['name'], - '#default_value' => $is_selected, - '#description' => $info['description'], - ); - if ($is_selected) { - $form['tests']['table'][$group_name]['#collapsed'] = FALSE; - } - } - } - - // Action buttons. - $form['tests']['op'] = array( - '#type' => 'submit', - '#value' => t('Run tests'), - ); - $form['reset'] = array( - '#type' => 'fieldset', - '#collapsible' => FALSE, - '#collapsed' => FALSE, - '#title' => t('Clean test environment'), - '#description' => t('Remove tables with the prefix "simpletest" and temporary directories that are left over from tests that crashed. This is intended for developers when creating tests.'), - ); - $form['reset']['op'] = array( - '#type' => 'submit', - '#value' => t('Clean environment'), - '#submit' => array('simpletest_clean_environment'), - ); - - return $form; -} - -function theme_simpletest_test_table($table) { - drupal_add_css(drupal_get_path('module', 'simpletest') . '/simpletest.css'); - drupal_add_js(drupal_get_path('module', 'simpletest') . '/simpletest.js'); - - // Create header for test selection table. - $header = array( - theme('table_select_header_cell'), - array('data' => t('Test'), 'class' => 'simpletest_test'), - array('data' => t('Description'), 'class' => 'simpletest_description'), - ); - - // Define the images used to expand/collapse the test groups. - $js = array( - 'images' => array( - theme('image', 'misc/menu-collapsed.png', 'Expand', 'Expand'), - theme('image', 'misc/menu-expanded.png', 'Collapsed', 'Collapsed'), + 'arguments' => array('form' => NULL), + 'file' => 'simpletest.pages.inc', ), ); - - // Go through each test group and create a row. - $rows = array(); - foreach (element_children($table) as $key) { - $element = &$table[$key]; - $row = array(); - - // Make the class name safe for output on the page by replacing all - // non-word/decimal characters with a dash (-). - $test_class = strtolower(trim(preg_replace("/[^\w\d]/", "-", $key))); - - // Select the right "expand"/"collapse" image, depending on whether the - // category is expanded (at least one test selected) or not. - $collapsed = !empty($element['#collapsed']); - $image_index = $collapsed ? 0 : 1; - - // Place-holder for checkboxes to select group of tests. - $row[] = array('id' => $test_class, 'class' => 'simpletest-select-all'); - - // Expand/collapse image and group title. - $row[] = array( - 'data' => '
 ' . - '', - 'style' => 'font-weight: bold;' - ); - - $row[] = isset($element['#description']) ? $element['#description'] : ' '; - $rows[] = array('data' => $row, 'class' => 'simpletest-group'); - - // Add individual tests to group. - $current_js = array( - 'testClass' => $test_class . '-test', - 'testNames' => array(), - 'imageDirection' => $image_index, - 'clickActive' => FALSE, - ); - foreach (element_children($element) as $test_name) { - $test = $element[$test_name]; - $row = array(); - - $current_js['testNames'][] = 'edit-' . $test_name; - - // Store test title and description so that checkbox won't render them. - $title = $test['#title']; - $description = $test['#description']; - - unset($test['#title']); - unset($test['#description']); - - // Test name is used to determine what tests to run. - $test['#name'] = $test_name; - - $row[] = drupal_render($test); - $row[] = theme('indentation', 1) . ''; - $row[] = '
' . $description . '
'; - $rows[] = array('data' => $row, 'class' => $test_class . '-test' . ($collapsed ? ' js-hide' : '')); - } - $js['simpletest-test-group-'. $test_class] = $current_js; - unset($table[$key]); - } - - // Add js array of settings. - drupal_add_js(array('simpleTest' => $js), 'setting'); - - if (empty($rows)) { - return '' . t('No tests to display.') . ''; - } - else { - return theme('table', $header, $rows, array('id' => 'simpletest-form-table')); - } } /** @@ -311,10 +91,6 @@ } } -function theme_simpletest_result_summary($form, $text = NULL) { - return '
' . _simpletest_format_summary_line($form) . '
'; -} - function _simpletest_format_summary_line($summary) { return t('@pass, @fail, and @exception', array( '@pass' => format_plural(isset($summary['#pass']) ? $summary['#pass'] : 0, '1 pass', '@count passes'), @@ -324,28 +100,6 @@ } /** - * Run selected tests. - */ -function simpletest_test_form_submit($form, &$form_state) { - // Ensure that all classes are loaded before we create instances to get test information and run. - simpletest_get_all_tests(); - - // Get list of tests. - $tests_list = array(); - foreach ($form_state['values'] as $class_name => $value) { - if (class_exists($class_name) && $value === 1) { - $tests_list[] = $class_name; - } - } - if (count($tests_list) > 0 ) { - simpletest_run_tests($tests_list, 'drupal'); - } - else { - drupal_set_message(t('No test(s) selected.'), 'error'); - } -} - -/** * Actually runs tests. * * @param $test_list @@ -370,7 +124,6 @@ array('_simpletest_batch_operation', array($test_list, $test_id)), ), 'finished' => '_simpletest_batch_finished', - 'redirect' => 'admin/development/testing', 'progress_message' => '', 'css' => array(drupal_get_path('module', 'simpletest') . '/simpletest.css'), 'init_message' => t('Processing test @num of @max - %test.', array('%test' => $info['name'], '@num' => '1', '@max' => count($test_list))), @@ -382,7 +135,7 @@ // By calling batch_process() directly, we skip that behavior and ensure // that we don't exceed the size of data that can be sent to the database // (max_allowed_packet on MySQL). - batch_process(); + batch_process('admin/development/testing/results/' . $test_id); } /** @@ -438,9 +191,6 @@ } function _simpletest_batch_finished($success, $results, $operations, $elapsed) { - if (isset($results['test_id'])) { - drupal_set_session('test_id', $results['test_id']); - } if ($success) { drupal_set_message(t('The tests finished in @elapsed.', array('@elapsed' => $elapsed))); } Index: modules/simpletest/simpletest.css =================================================================== RCS file: /cvs/drupal/drupal/modules/simpletest/simpletest.css,v retrieving revision 1.4 diff -u -r1.4 simpletest.css --- modules/simpletest/simpletest.css 1 Nov 2008 18:32:22 -0000 1.4 +++ modules/simpletest/simpletest.css 1 May 2009 01:17:37 -0000 @@ -6,7 +6,7 @@ /* Test Table */ #simpletest-form-table th.select-all { - width: 50px; + width: 25px; } th.simpletest_test { Index: modules/simpletest/simpletest.test =================================================================== RCS file: /cvs/drupal/drupal/modules/simpletest/simpletest.test,v retrieving revision 1.18 diff -u -r1.18 simpletest.test --- modules/simpletest/simpletest.test 27 Apr 2009 07:44:09 -0000 1.18 +++ modules/simpletest/simpletest.test 1 May 2009 01:17:38 -0000 @@ -204,10 +204,10 @@ if ($fieldset = $this->getResultFieldSet()) { // Code assumes this is the only test in group. $results['summary'] = $this->asText($fieldset->div); - $results['name'] = $this->asText($fieldset->fieldset->legend); + $results['name'] = $this->asText($fieldset->legend); $results['assertions'] = array(); - $tbody = $fieldset->fieldset->table->tbody; + $tbody = $fieldset->table->tbody; foreach ($tbody->tr as $row) { $assertion = array(); $assertion['message'] = $this->asText($row->td[0]); @@ -233,7 +233,7 @@ $fieldsets = $this->xpath('//fieldset'); $info = $this->getInfo(); foreach ($fieldsets as $fieldset) { - if ($fieldset->legend == $info['group']) { + if ($fieldset->legend == $info['name']) { return $fieldset; } } Index: modules/simpletest/simpletest.pages.inc =================================================================== RCS file: modules/simpletest/simpletest.pages.inc diff -N modules/simpletest/simpletest.pages.inc --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ modules/simpletest/simpletest.pages.inc 1 Jan 1970 00:00:00 -0000 @@ -0,0 +1,396 @@ + 'fieldset', + '#title' => t('Tests'), + '#description' => t('Select the test(s) or test group(s) you would like to run, and click Run tests.'), + ); + + $form['tests']['table'] = array( + '#theme' => 'simpletest_test_table', + ); + + // Generate the list of tests arranged by group. + foreach ($tests as $group_name => $test_group) { + $form['tests']['table'][$group_name] = array( + '#collapsed' => TRUE, + ); + + foreach ($test_group as $class => $info) { + $form['tests']['table'][$group_name][$class] = array( + '#type' => 'checkbox', + '#title' => $info['name'], + '#description' => $info['description'], + ); + } + } + + // Operation buttons. + $form['tests']['op'] = array( + '#type' => 'submit', + '#value' => t('Run tests'), + ); + $form['clean'] = array( + '#type' => 'fieldset', + '#collapsible' => FALSE, + '#collapsed' => FALSE, + '#title' => t('Clean test environment'), + '#description' => t('Remove tables with the prefix "simpletest" and temporary directories that are left over from tests that crashed. This is intended for developers when creating tests.'), + ); + $form['clean']['op'] = array( + '#type' => 'submit', + '#value' => t('Clean environment'), + '#submit' => array('simpletest_clean_environment'), + ); + + return $form; +} + +/** + * Theme the test list generated by simpletest_test_form() into a table. + * + * @param $table Form array that represent a table. + * @return HTML output. + */ +function theme_simpletest_test_table($table) { + drupal_add_css(drupal_get_path('module', 'simpletest') . '/simpletest.css'); + drupal_add_js(drupal_get_path('module', 'simpletest') . '/simpletest.js'); + + // Create header for test selection table. + $header = array( + theme('table_select_header_cell'), + array('data' => t('Test'), 'class' => 'simpletest_test'), + array('data' => t('Description'), 'class' => 'simpletest_description'), + ); + + // Define the images used to expand/collapse the test groups. + $js = array( + 'images' => array( + theme('image', 'misc/menu-collapsed.png', 'Expand', 'Expand'), + theme('image', 'misc/menu-expanded.png', 'Collapsed', 'Collapsed'), + ), + ); + + // Cycle through each test group and create a row. + $rows = array(); + foreach (element_children($table) as $key) { + $element = &$table[$key]; + $row = array(); + + // Make the class name safe for output on the page by replacing all + // non-word/decimal characters with a dash (-). + $test_class = strtolower(trim(preg_replace("/[^\w\d]/", "-", $key))); + + // Select the right "expand"/"collapse" image, depending on whether the + // category is expanded (at least one test selected) or not. + $collapsed = !empty($element['#collapsed']); + $image_index = $collapsed ? 0 : 1; + + // Place-holder for checkboxes to select group of tests. + $row[] = array('id' => $test_class, 'class' => 'simpletest-select-all'); + + // Expand/collapse image and group title. + $row[] = array( + 'data' => '
 ' . + '', + 'style' => 'font-weight: bold;' + ); + + $row[] = ' '; + + $rows[] = array('data' => $row, 'class' => 'simpletest-group'); + + // Add individual tests to group. + $current_js = array( + 'testClass' => $test_class . '-test', + 'testNames' => array(), + 'imageDirection' => $image_index, + 'clickActive' => FALSE, + ); + + // Cycle through each test within the current group. + foreach (element_children($element) as $test_name) { + $test = $element[$test_name]; + $row = array(); + + $current_js['testNames'][] = 'edit-' . $test_name; + + // Store test title and description so that checkbox won't render them. + $title = $test['#title']; + $description = $test['#description']; + + unset($test['#title']); + unset($test['#description']); + + // Test name is used to determine what tests to run. + $test['#name'] = $test_name; + + $row[] = drupal_render($test); + $row[] = theme('indentation', 1) . ''; + $row[] = '
' . $description . '
'; + + $rows[] = array('data' => $row, 'class' => $test_class . '-test' . ($collapsed ? ' js-hide' : '')); + } + $js['simpletest-test-group-' . $test_class] = $current_js; + unset($table[$key]); + } + + // Add js array of settings. + drupal_add_js(array('simpleTest' => $js), 'setting'); + + if (empty($rows)) { + return '' . t('No tests to display.') . ''; + } + else { + return theme('table', $header, $rows, array('id' => 'simpletest-form-table')); + } +} + +/** + * Run selected tests. + */ +function simpletest_test_form_submit($form, &$form_state) { + // Ensure that all classes are loaded before we create instances to get test information and run. + simpletest_get_all_tests(); + + // Get list of tests. + $tests_list = array(); + foreach ($form_state['values'] as $class_name => $value) { + if (class_exists($class_name) && $value === 1) { + $tests_list[] = $class_name; + } + } + if (count($tests_list) > 0 ) { + simpletest_run_tests($tests_list, 'drupal'); + } + else { + drupal_set_message(t('No test(s) selected.'), 'error'); + } +} + +/** + * Test results form for $test_id. + */ +function simpletest_result_form(&$form_sate, $test_id) { + $form = array(); + + // Make sure there are test results to display and are-run is not being performed. + $results = simpletest_result_get($test_id); + if ($test_id != 're-run' && !$results) { + drupal_set_message(t('No test results to display.'), 'error'); + drupal_goto('admin/development/testing'); + return $form; + } + + // Load all classes and include CSS. + drupal_add_css(drupal_get_path('module', 'simpletest') . '/simpletest.css'); + simpletest_get_all_tests(); + + // Keep track of which test cases passed or failed. + $filter = array( + 'pass' => array(), + 'fail' => array(), + ); + + // Summary result fieldset. + $form['result'] = array( + '#type' => 'fieldset', + '#title' => t('Results'), + ); + $form['result']['summary'] = $summary = array( + '#theme' => 'simpletest_result_summary', + '#pass' => 0, + '#fail' => 0, + '#exception' => 0, + ); + + // Cycle through each test group. + $header = array(t('Message'), t('Group'), t('Filename'), t('Line'), t('Function'), array('colspan' => 2, 'data' => t('Status'))); + $form['result']['results'] = array(); + foreach ($results as $group => $assertions) { + // Create group fieldset with summary information. + $info = call_user_func(array($group, 'getInfo')); + $form['result']['results'][$group] = array( + '#type' => 'fieldset', + '#title' => $info['name'], + '#description' => $info['description'], + '#collapsible' => TRUE, + ); + $form['result']['results'][$group]['summary'] = $summary; + $group_summary = &$form['result']['results'][$group]['summary']; + + // Create table of assertions for the group. + $rows = array(); + foreach ($assertions as $assertion) { + $row = array(); + $row[] = $assertion->message; + $row[] = $assertion->message_group; + $row[] = basename($assertion->file); + $row[] = $assertion->line; + $row[] = $assertion->function; + $row[] = simpletest_result_status_image($assertion->status); + + $rows[] = array('data' => $row, 'class' => 'simpletest-' . $assertion->status); + + $group_summary['#' . $assertion->status]++; + $form['result']['summary']['#' . $assertion->status]++; + } + $form['result']['results'][$group]['table'] = array( + '#markup' => theme('table', $header, $rows), + ); + + // Set summary information. + $group_summary['#ok'] = $group_summary['#fail'] + $group_summary['#exception'] == 0; + $form['result']['results'][$group]['#collapsed'] = $group_summary['#ok']; + + // Store test group (class) as for use in filter. + $filter[$group_summary['#ok'] ? 'pass' : 'fail'][] = $group; + } + + // Overal summary status. + $form['result']['summary']['#ok'] = $form['result']['summary']['#fail'] + $form['result']['summary']['#exception'] == 0; + + // Actions. + $form['#action'] = url('admin/development/testing/results/re-run'); + $form['action'] = array( + '#type' => 'fieldset', + '#title' => t('Actions'), + '#attributes' => array('class' => 'container-inline'), + '#weight' => -11, + ); + + $form['action']['filter'] = array( + '#type' => 'select', + '#title' => 'Filter', + '#options' => array( + 'all' => t('All (@count)', array('@count' => count($filter['pass']) + count($filter['fail']))), + 'pass' => t('Pass (@count)', array('@count' => count($filter['pass']))), + 'fail' => t('Fail (@count)', array('@count' => count($filter['fail']))), + ), + ); + $form['action']['filter']['#default_value'] = ($filter['fail'] ? 'fail' : 'all'); + + // Catagorized test classes for to be used with selected filter value. + $form['action']['filter_pass'] = array( + '#type' => 'hidden', + '#default_value' => implode(',', $filter['pass']), + ); + $form['action']['filter_fail'] = array( + '#type' => 'hidden', + '#default_value' => implode(',', $filter['fail']), + ); + + $form['action']['op'] = array( + '#type' => 'submit', + '#value' => t('Run tests'), + ); + + $form['action']['return'] = array( + '#markup' => l(t('Return to list'), 'admin/development/testing'), + ); + + simpletest_clean_results_table($test_id); + + return $form; +} + +/** + * Re-run the tests that match the filter. + */ +function simpletest_result_form_submit($form, &$form_state) { + $pass = $form_state['values']['filter_pass'] ? explode(',', $form_state['values']['filter_pass']) : array(); + $fail = $form_state['values']['filter_fail'] ? explode(',', $form_state['values']['filter_fail']) : array(); + + if ($form_state['values']['filter'] == 'all') { + $classes = array_merge($pass, $fail); + } + else if ($form_state['values']['filter'] == 'pass') { + $classes = $pass; + } + else { + $classes = $fail; + } + + if (!$classes) { + $form_state['redirect'] = 'admin/development/testing'; + return; + } + + $form_state_execute = array('values' => array()); + foreach ($classes as $class) { + $form_state_execute['values'][$class] = 1; + } + + simpletest_test_form_submit(array(), $form_state_execute); +} + +/** + * Add wrapper div with class based on summary status. + * + * @return HTML output. + */ +function theme_simpletest_result_summary($form) { + return '
' . _simpletest_format_summary_line($form) . '
'; +} + +/** + * Get test results for $test_id. + * + * @param $test_id The test_id to retrieve results of. + * @return Array of results grouped by test_class. + */ +function simpletest_result_get($test_id) { + $results = db_select('simpletest') + ->fields('simpletest') + ->condition('test_id', $test_id) + ->orderBy('test_class') + ->orderBy('message_id') + ->execute(); + + $test_results = array(); + foreach ($results as $result) { + if (!isset($test_results[$result->test_class])) { + $test_results[$result->test_class] = array(); + } + $test_results[$result->test_class][] = $result; + } + return $test_results; +} + +/** + * Get the appropriate image for the status. + * + * @param $status Status string, either: pass, fail, exception. + * @return HTML image or false. + */ +function simpletest_result_status_image($status) { + static $map; + + if (!isset($map)) { + $map = array( + 'pass' => theme('image', 'misc/watchdog-ok.png'), + 'fail' => theme('image', 'misc/watchdog-error.png'), + 'exception' => theme('image', 'misc/watchdog-warning.png'), + ); + } + if (isset($map[$status])) { + return $map[$status]; + } + return FALSE; +}