? modules/simpletest/drupal_structured_reporter.php Index: modules/simpletest/drupal_test_suite.php =================================================================== RCS file: /cvs/drupal/drupal/modules/simpletest/drupal_test_suite.php,v retrieving revision 1.3 diff -u -r1.3 drupal_test_suite.php --- modules/simpletest/drupal_test_suite.php 6 May 2008 11:21:10 -0000 1.3 +++ modules/simpletest/drupal_test_suite.php 6 Jun 2008 01:32:32 -0000 @@ -65,9 +65,9 @@ foreach ($groups as $group_name => $group) { $group_test = &new DrupalTestSuite($group_name); foreach ($group as $key => $v) { - $group_test->addTestCase($group[$key]); + $group_test->add($group[$key]); } - $this->addTestCase($group_test); + $this->add($group_test); } } Index: modules/simpletest/simpletest.module =================================================================== RCS file: /cvs/drupal/drupal/modules/simpletest/simpletest.module,v retrieving revision 1.3 diff -u -r1.3 simpletest.module --- modules/simpletest/simpletest.module 10 May 2008 07:46:22 -0000 1.3 +++ modules/simpletest/simpletest.module 6 Jun 2008 01:32:32 -0000 @@ -82,24 +82,23 @@ simpletest_load(); drupal_add_css(drupal_get_path('module', 'simpletest') . '/simpletest.css', 'module'); drupal_add_js(drupal_get_path('module', 'simpletest') . '/simpletest.js', 'module'); - $output = drupal_get_form('simpletest_overview_form'); - if (simpletest_running_output()) { - return simpletest_running_output() . $output; + $output = drupal_get_form('simpletest_overview_form'); + + if (isset($_SESSION['simpletest_reporter'])) { + $reporter = $_SESSION['simpletest_reporter']; + if (is_string($reporter)) { + $reporter = unserialize($_SESSION['simpletest_reporter']); + } + $output = $reporter->getOutput() . drupal_get_form('simpletest_overview_form'); + unset($_SESSION['simpletest_reporter']); + return $output; } else { return $output; } } -function simpletest_running_output($output = NULL) { - static $o; - if ($output != NULL) { - $o = $output; - } - return $o; -} - /** * Form callback; make the form to run tests */ @@ -155,6 +154,11 @@ 'selected_tests' => t('Run selected tests'), ), ); + $output['run']['use_batch'] = array( + '#type' => 'checkbox', + '#default_value' => TRUE, + '#title' => t('Display testing progress'), + ); $output['run']['op'] = array( '#type' => 'submit', '#value' => t('Run tests'), @@ -260,9 +264,11 @@ function simpletest_run_selected_tests($form, &$form_state) { $form_state['redirect'] = FALSE; $output = ''; + $batch = $form_state['values']['use_batch']; + unset($form_state['values']['use_batch']); switch ($form_state['values']['running_options']) { case 'all_tests': - $output = simpletest_run_tests(); + $output = simpletest_run_tests(NULL, 'drupal', $batch); break; case 'selected_tests': $tests_list = array(); @@ -272,7 +278,7 @@ } } if (count($tests_list) > 0 ) { - $output = simpletest_run_tests($tests_list); + $output = simpletest_run_tests($tests_list, 'drupal', $batch); break; } // Fall through @@ -280,7 +286,6 @@ drupal_set_message(t('No test has been selected.'), 'error'); } - simpletest_running_output($output); return FALSE; } @@ -383,11 +388,11 @@ * @param array $test_list list of tests to run or DEFAULT NULL run all tests * @param boolean $html_reporter TRUE if you want results in simple html, FALSE for full drupal page */ -function simpletest_run_tests($test_list = NULL, $reporter = 'drupal') { +function simpletest_run_tests($test_list = NULL, $reporter = 'drupal', $batch = FALSE) { static $test_running; if (!$test_running) { $test_running = TRUE; - $test = simpletest_get_total_test($test_list); + $tests = simpletest_get_total_test($test_list); switch ($reporter) { case 'text': $reporter = &new TextReporter(); @@ -404,21 +409,80 @@ } cache_clear_all(); - $results = $test->run($reporter); - $test_running = FALSE; - switch (get_class($reporter)) { - case 'TextReporter': - case 'XMLReporter': - case 'HtmlReporter': - return $results; - case 'DrupalReporter': - return $reporter->getOutput(); + if ($batch) { + $operations = array(); + $operations[] = array('_simpletest_batch_operation', array(serialize($tests), serialize($reporter))); + + $batch = array( + 'title' => t('Running SimpleTests'), + 'operations' => $operations, + 'finished' => '_simpletest_batch_finished', + 'redirect' => 'admin/build/testing', + 'progress_message' => t('Processing tests.'), + 'init_message' => t('SimpleTest is initializing...') . ' ' . format_plural($tests->getSize(), "one test case will run.", "@count test cases will run."), + ); + batch_set($batch); + return; + } + else { + $results = $tests->run($reporter); + $test_running = FALSE; + if (get_class($reporter) == 'DrupalReporter') { + $_SESSION['simpletest_reporter'] = $reporter; + } + return $results; } } } /** + * Batch operation callback. + */ +function _simpletest_batch_operation($tests, $reporter, &$context) { + // Ensure that all classes are loaded. + simpletest_get_total_test(); + $reporter = unserialize( isset($context['sandbox']['reporter']) ? $context['sandbox']['reporter'] : $reporter); + $tests = unserialize( isset($context['sandbox']['tests']) ? $context['sandbox']['tests'] : $tests); + + if (!isset($context['sandbox']['progress'])) { + $context['sandbox']['progress'] = 0; + $context['sandbox']['max'] = $tests->getSize(); + } + + $test_ran = $tests->runOneByOne($reporter); + $context['sandbox']['progress']++; + + $context['message'] = t('Processed test %test (remaining: @count of @max)', array('%test' => $test_ran, '@count' => $tests->getSize(), '@max' => $context['sandbox']['max'])); + + // Put back the reporter and tests + $context['sandbox']['reporter'] = serialize($reporter); + $context['sandbox']['tests'] = serialize($tests); + + // Multistep processing: report progress. + if (($size = $tests->getSize()) != 0) { + $context['finished'] = 1 - $size / $context['sandbox']['max']; + } + else { + // Finished: save the reporter + $context['results'][] = $context['sandbox']['reporter']; + } +} + +/** + * Batch finished callback. + */ +function _simpletest_batch_finished($success, $results, $operations) { + $_SESSION['simpletest_reporter'] = array_pop($results); + if ($success) { + drupal_set_message(t('The tests have finished running.')); + } + else { + drupal_set_message(t('The tests did not successfully finish.'), 'error'); + } +} + +/** * This function makes sure no unnecessary copies of the DrupalTests object are instantiated * @param array $classes list of all classes the test should concern or * DEFAULT NULL @@ -473,5 +537,4 @@ ); return system_settings_form($form); - } Index: modules/simpletest/simpletest.test =================================================================== RCS file: /cvs/drupal/drupal/modules/simpletest/simpletest.test,v retrieving revision 1.1 diff -u -r1.1 simpletest.test --- modules/simpletest/simpletest.test 28 May 2008 14:07:46 -0000 1.1 +++ modules/simpletest/simpletest.test 6 Jun 2008 01:32:32 -0000 @@ -59,6 +59,7 @@ $edit = array(); $edit['SimpleTestTestCase'] = TRUE; + $edit['use_batch'] = FALSE; $this->drupalPost(NULL, $edit, t('Run tests')); $this->getTestResults(); Index: modules/simpletest/test_case.php =================================================================== RCS file: /cvs/drupal/drupal/modules/simpletest/test_case.php,v retrieving revision 1.3 diff -u -r1.3 test_case.php --- modules/simpletest/test_case.php 10 May 2008 06:55:09 -0000 1.3 +++ modules/simpletest/test_case.php 6 Jun 2008 01:32:33 -0000 @@ -390,6 +390,8 @@ class TestSuite { var $_label; var $_test_cases; + var $_size = 0; + var $_already_ran = FALSE; /** * Sets the name of the test suite. @@ -400,6 +402,7 @@ function TestSuite($label = false) { $this->_label = $label; $this->_test_cases = array(); + $this->_size = 0; } /** @@ -421,19 +424,14 @@ * @deprecated */ function addTestCase(&$test_case) { - $this->_test_cases[] = &$test_case; + $this->add($test_case); } /** * @deprecated */ function addTestClass($class) { - if (TestSuite::getBaseTestCase($class) == 'testsuite') { - $this->_test_cases[] = &new $class(); - } - else { - $this->_test_cases[] = $class; - } + $this->add($class); } /** @@ -447,12 +445,11 @@ function add(&$test_case) { if (!is_string($test_case)) { $this->_test_cases[] = &$test_case; - } - elseif (TestSuite::getBaseTestCase($class) == 'testsuite') { - $this->_test_cases[] = &new $class(); + $this->_size += $test_case->getSize(); } else { $this->_test_cases[] = $class; + $this->_size += $test_case->getSize(); } } @@ -509,22 +506,51 @@ return $reporter->getStatus(); } + function runOneByOne(&$reporter) { + if ($this->getSize() == 0) { + // Nothing to do, exit early + return; + } + + if (!$this->_already_ran) { + $this->_already_ran = TRUE; + $reporter->paintGroupStart($this->getLabel(), $this->getSize()); + } + + $test = array_shift($this->_test_cases); + if (is_string($test)) { + $test = &new $test(); + } + + if (is_a($test, 'TestSuite')) { + // This is a test suite, run one test at a time + $this->_size -= $test->getSize(); + $test_ran = $test->runOneByOne($reporter); + if ($test->getSize() > 0) { + // Requeue this test suite + array_unshift($this->_test_cases, $test); + $this->_size += $test->getSize(); + } + } + else { + $this->_size -= 1; + $test->run($reporter); + $test_ran = $test->getLabel(); + } + + if ($this->getSize() == 0) { + $reporter->paintGroupEnd($this->getLabel()); + } + return $test_ran; + } + /** * Number of contained test cases. * @return integer Total count of cases in the group. * @access public */ function getSize() { - $count = 0; - foreach ($this->_test_cases as $case) { - if (is_string($case)) { - $count++; - } - else { - $count += $case->getSize(); - } - } - return $count; + return $this->_size; } /**