diff --git a/includes/batch.inc b/includes/batch.inc index 22692f0ad59908c37107ac13fbf1ab0aa401c89a..c4f481a056e9ff370b7c5b5c98b5ec1188810063 100644 --- a/includes/batch.inc +++ b/includes/batch.inc @@ -22,6 +22,13 @@ function _batch_page() { // Register database update for end of processing. register_shutdown_function('_batch_shutdown'); + // Add batch-specific css. + foreach ($batch['sets'] as $batch_set) { + foreach ($batch_set['css'] as $css) { + drupal_add_css($css); + } + } + $op = isset($_REQUEST['op']) ? $_REQUEST['op'] : ''; $output = NULL; switch ($op) { diff --git a/includes/form.inc b/includes/form.inc index b2472c68edf105184a040b2a6dffbde9f8207f1f..3df1a60f443138e493a69afbbb9b6497ff1eeae6 100644 --- a/includes/form.inc +++ b/includes/form.inc @@ -2387,6 +2387,7 @@ function form_clean_id($id = NULL, $flush = FALSE) { * 'operations' and 'finished' functions, for instance if they don't * reside in the original '.module' file. The path should be relative to * the base_path(), and thus should be built using drupal_get_path(). + * 'css' : an array of paths to CSS files to be used on the progress page. * * Operations are added as new batch sets. Batch sets are used to ensure * clean code independence, ensuring that several batches submitted by @@ -2419,6 +2420,7 @@ function batch_set($batch_definition) { 'init_message' => $t('Initializing.'), 'progress_message' => $t('Remaining @remaining of @total.'), 'error_message' => $t('An error has occurred.'), + 'css' => array(), ); $batch_set = $init + $batch_definition + $defaults; diff --git a/modules/contact/contact.test b/modules/contact/contact.test index b6b87d1ecdd1fbcfcc0401ab7ae3112771634ad9..6cfe6299478f847f8c57811a0fd5fea6467544da 100644 --- a/modules/contact/contact.test +++ b/modules/contact/contact.test @@ -1,14 +1,18 @@ <?php // $Id$ -class ContactTestCase extends DrupalWebTestCase { +/** + * Test the sitewide contact form. + */ +class ContactSitewideTestCase extends DrupalWebTestCase { + /** * Implementation of getInfo(). */ function getInfo() { return array( - 'name' => t('Contact functionality'), - 'description' => t('Test site-wide contact form and personal contact form functionality.'), + 'name' => t('Site-wide contact form'), + 'description' => t('Tests site-wide contact form functionality.'), 'group' => t('Contact'), ); } @@ -110,60 +114,6 @@ class ContactTestCase extends DrupalWebTestCase { $this->deleteCategories(); } - /** - * Test personal contact form. - */ - function testPersonalContact() { - $admin_user = $this->drupalCreateUser(array('administer site-wide contact form')); - $this->drupalLogin($admin_user); - - // Enable the personal contact form. - $edit = array(); - $edit['contact_default_status'] = TRUE; - $this->drupalPost('admin/build/contact/settings', $edit, t('Save configuration')); - $this->assertText(t('The configuration options have been saved.'), t('Setting successfully saved.')); - - // Reload variables. - $this->drupalLogout(); - - // Create web users and attempt to use personal contact forms with default set to true. - $web_user1 = $this->drupalCreateUser(array()); - $web_user2 = $this->drupalCreateUser(array()); - - $this->drupalLogin($web_user1); - - $this->drupalGet('user/' . $web_user2->uid . '/contact'); - $this->assertResponse(200, t('Access to personal contact form granted.')); - - $edit = array(); - $edit['subject'] = $this->randomName(16); - $edit['message'] = $this->randomName(64); - $this->drupalPost(NULL, $edit, t('Send e-mail')); - $this->assertText(t('The message has been sent.'), t('Message sent.')); - - $this->drupalLogout(); - - $this->drupalLogin($admin_user); - - // Disable the personal contact form. - $edit = array(); - $edit['contact_default_status'] = FALSE; - $this->drupalPost('admin/build/contact/settings', $edit, t('Save configuration')); - $this->assertText(t('The configuration options have been saved.'), t('Setting successfully saved.')); - - // Reload variables. - $this->drupalLogout(); - - // Create web users and attempt to use personal contact forms with default set to false. - $web_user3 = $this->drupalCreateUser(array()); - $web_user4 = $this->drupalCreateUser(array()); - - $this->drupalLogin($web_user3); - - $this->drupalGet('user/' . $web_user4->uid . '/contact'); - $this->assertResponse(403, t('Access to personal contact form denied.')); - } - /** * Add a category. * @@ -249,3 +199,81 @@ class ContactTestCase extends DrupalWebTestCase { $this->assertText(t('The changes have been saved.'), t(' [permission] Saved changes.')); } } + +/** + * Test the personal contact form. + */ +class ContactPersonalTestCase extends DrupalWebTestCase { + + /** + * Implementation of getInfo(). + */ + function getInfo() { + return array( + 'name' => t('Personal contact form'), + 'description' => t('Tests personal contact form functionality.'), + 'group' => t('Contact'), + ); + } + + /** + * Implementation of setUp(). + */ + function setUp() { + parent::setUp('contact'); + } + + /** + * Test personal contact form. + */ + function testPersonalContact() { + $admin_user = $this->drupalCreateUser(array('administer site-wide contact form')); + $this->drupalLogin($admin_user); + + // Enable the personal contact form. + $edit = array(); + $edit['contact_default_status'] = TRUE; + $this->drupalPost('admin/build/contact/settings', $edit, t('Save configuration')); + $this->assertText(t('The configuration options have been saved.'), t('Setting successfully saved.')); + + // Reload variables. + $this->drupalLogout(); + + // Create web users and attempt to use personal contact forms with default set to true. + $web_user1 = $this->drupalCreateUser(array()); + $web_user2 = $this->drupalCreateUser(array()); + + $this->drupalLogin($web_user1); + + $this->drupalGet('user/' . $web_user2->uid . '/contact'); + $this->assertResponse(200, t('Access to personal contact form granted.')); + + $edit = array(); + $edit['subject'] = $this->randomName(16); + $edit['message'] = $this->randomName(64); + $this->drupalPost(NULL, $edit, t('Send e-mail')); + $this->assertText(t('The message has been sent.'), t('Message sent.')); + + $this->drupalLogout(); + + $this->drupalLogin($admin_user); + + // Disable the personal contact form. + $edit = array(); + $edit['contact_default_status'] = FALSE; + $this->drupalPost('admin/build/contact/settings', $edit, t('Save configuration')); + $this->assertText(t('The configuration options have been saved.'), t('Setting successfully saved.')); + + // Reload variables. + $this->drupalLogout(); + + // Create web users and attempt to use personal contact forms with default set to false. + $web_user3 = $this->drupalCreateUser(array()); + $web_user4 = $this->drupalCreateUser(array()); + + $this->drupalLogin($web_user3); + + $this->drupalGet('user/' . $web_user4->uid . '/contact'); + $this->assertResponse(403, t('Access to personal contact form denied.')); + } +} \ No newline at end of file diff --git a/modules/php/php.test b/modules/php/php.test index 29d0bad54765086f6ccc7a235cefdf14da5dbb7d..a046dc808832518b6a430166d36cfd82f04749e5 100644 --- a/modules/php/php.test +++ b/modules/php/php.test @@ -1,17 +1,10 @@ <?php // $Id$ +/** + * Base PHP test case class. + */ class PHPTestCase extends DrupalWebTestCase { - /** - * Implementation of getInfo(). - */ - function getInfo() { - return array( - 'name' => t('PHP filter functionality'), - 'description' => t('Make sure that PHP filter evaluates PHP code when enabled and that users who don\'t have access to filter can\'t see it'), - 'group' => t('PHP'), - ); - } /** * Implementation of getInfo(). @@ -28,6 +21,37 @@ class PHPTestCase extends DrupalWebTestCase { $this->assertText('PHP code', t('On PHP code filter page.')); } + /** + * Create a test node with PHP code in the body. + * + * @param stdObject User object to create node for. + * @return stdObject Node object. + */ + function createNodeWithCode($user) { + $node = $this->drupalCreateNode(array('uid' => $user->uid)); + $edit = array(); + $edit['body'] = '<?php print "SimpleTest PHP was executed!"; ?>'; + $this->drupalPost('node/' . $node->nid . '/edit', $edit, t('Save')); + $this->assertRaw(t('Page %title has been updated.', array('%title' => $node->title)), t('PHP code inserted into node.')); + return $node; + } +} + +/** + * Tests to make sure the PHP filter actually evaluates PHP code when used. + */ +class PHPFitlerTestCase extends PHPTestCase { + /** + * Implementation of getInfo(). + */ + function getInfo() { + return array( + 'name' => t('PHP filter functionality'), + 'description' => t('Make sure that PHP filter properly evaluates PHP code when enabled.'), + 'group' => t('PHP'), + ); + } + /** * Make sure that the PHP filter evaluates PHP code when used. */ @@ -57,6 +81,22 @@ class PHPTestCase extends DrupalWebTestCase { $this->assertNoText('print', t('PHP code isn\'t displayed.')); $this->assertText('SimpleTest PHP was executed!', t('PHP code has been evaluated.')); } +} + +/** + * Tests to make sure access to the PHP filter is properly restricted. + */ +class PHPAccessTestCase extends PHPTestCase { + /** + * Implementation of getInfo(). + */ + function getInfo() { + return array( + 'name' => t('PHP filter access check'), + 'description' => t('Make sure that users who don\'t have access to the PHP filter can\'t see it.'), + 'group' => t('PHP'), + ); + } /** * Make sure that user can't use the PHP filter when not given access. @@ -75,19 +115,4 @@ class PHPTestCase extends DrupalWebTestCase { $this->drupalGet('node/' . $node->nid . '/edit'); $this->assertNoFieldByName('format', '3', t('Format not available.')); } - - /** - * Create a test node with PHP code in the body. - * - * @param stdObject User object to create node for. - * @return stdObject Node object. - */ - function createNodeWithCode($user) { - $node = $this->drupalCreateNode(array('uid' => $user->uid)); - $edit = array(); - $edit['body'] = '<?php print "SimpleTest PHP was executed!"; ?>'; - $this->drupalPost('node/' . $node->nid . '/edit', $edit, t('Save')); - $this->assertRaw(t('Page %title has been updated.', array('%title' => $node->title)), t('PHP code inserted into node.')); - return $node; - } -} +} \ No newline at end of file diff --git a/modules/simpletest/drupal_web_test_case.php b/modules/simpletest/drupal_web_test_case.php index 0d0147302fd8548bae241ed3255096f46690d826..ef371234915ec2a408e1c50e9677659e04c78c81 100644 --- a/modules/simpletest/drupal_web_test_case.php +++ b/modules/simpletest/drupal_web_test_case.php @@ -4,7 +4,7 @@ /** * Test case for typical Drupal tests. */ -class DrupalWebTestCase extends UnitTestCase { +class DrupalWebTestCase { protected $_logged_in = FALSE; protected $_content; protected $plain_text; @@ -19,26 +19,290 @@ class DrupalWebTestCase extends UnitTestCase { protected $db_prefix_original; protected $original_file_directory; + var $_results = array('#pass' => 0, '#fail' => 0, '#exception' => 0); + + /** + * Constructor for DrupalWebTestCase. + * + * @param @test_id + * Tests with the same id are reported together. + */ + function __construct($test_id = NULL) { + $this->test_id = $test_id; + } + + /** + * This function stores the assert. Do not call directly. + * + * @param $status + * Can be 'pass', 'fail', 'exception'. TRUE is a synonym for 'pass', FALSE + * for 'fail'. + * @param $message + * The message string. + * @param $group + * WHich group this assert belongs to. + * @param $custom_caller + * By default, the assert comes from a function which names start with + * 'test'. Instead, you can specify where this assert originates from + * by passing in an associative array as $custom_caller. Key 'file' is + * the name of the source file, 'line' is the line number and 'function' + * is the caller function itself. + */ + protected function _assert($status, $message = '', $group = 'Other', $custom_caller = NULL) { + global $db_prefix; + if (is_bool($status)) { + $status = $status ? 'pass' : 'fail'; + } + $this->_results['#' . $status]++; + if (!isset($custom_caller)) { + $callers = debug_backtrace(); + array_shift($callers); + foreach ($callers as $function) { + if (substr($function['function'], 0, 6) != 'assert' && $function['function'] != 'pass' && $function['function'] != 'fail') { + break; + } + } + } + else { + $function = $custom_caller; + } + $current_db_prefix = $db_prefix; + $db_prefix = $this->db_prefix_original; + db_query("INSERT INTO {simpletest} (test_id, test_class, status, message, message_group, caller, line, file) VALUES (%d, '%s', '%s', '%s', '%s', '%s', '%s', '%s')", $this->test_id, get_class($this), $status, $message, $group, $function['function'], $function['line'], $function['file']); + $db_prefix = $current_db_prefix; + return $status; + } + + /** + * Check to see if a value is not false (not an empty string, 0, NULL, or FALSE). + * + * @param $value + * The value on which the assertion is to be done. + * @param $message + * The message to display along with the assertion. + * @param $group + * The type of assertion - examples are "Browser", "PHP". + * @return + * The status passed in. + */ + protected function assertTrue($value, $message = '', $group = 'Other') { + return $this->_assert((bool) $value, $message ? $message : t('%value is TRUE', array('%value' => $value)), $group); + } + + /** + * Check to see if a value is false (an empty string, 0, NULL, or FALSE). + * + * @param $value + * The value on which the assertion is to be done. + * @param $message + * The message to display along with the assertion. + * @param $group + * The type of assertion - examples are "Browser", "PHP". + * @return + * The status passed in. + */ + protected function assertFalse($value, $message = '', $group = 'Other') { + return $this->_assert(!$value, $message ? $message : t('%value is FALSE', array('%value' => $value)), $group); + } + + /** + * Check to see if a value is NULL. + * + * @param $value + * The value on which the assertion is to be done. + * @param $message + * The message to display along with the assertion. + * @param $group + * The type of assertion - examples are "Browser", "PHP". + * @return + * The status passed in. + */ + protected function assertNull($value, $message = '', $group = 'Other') { + return $this->_assert(!isset($value), $message ? $message : t('%value is NULL', array('%value' => $value)), $group); + } + + /** + * Check to see if a value is not NULL. + * + * @param $value + * The value on which the assertion is to be done. + * @param $message + * The message to display along with the assertion. + * @param $group + * The type of assertion - examples are "Browser", "PHP". + * @return + * The status passed in. + */ + protected function assertNotNull($value, $message = '', $group = 'Other') { + return $this->_assert(isset($value), $message ? $message : t('%value is not NULL', array('%value' => $value)), $group); + } + + /** + * Check to see if two values are equal. + * + * @param $first + * The first value to check. + * @param $second + * The second value to check. + * @param $message + * The message to display along with the assertion. + * @param $group + * The type of assertion - examples are "Browser", "PHP". + * @return + * The status passed in. + */ + protected function assertEqual($first, $second, $message = '', $group = 'Other') { + return $this->_assert($first == $second, $message ? $message : t('%first is equal to %second', array('%first' => $first, '%second' => $second)), $group); + } + + /** + * Check to see if two values are not equal. + * + * @param $first + * The first value to check. + * @param $second + * The second value to check. + * @param $message + * The message to display along with the assertion. + * @param $group + * The type of assertion - examples are "Browser", "PHP". + * @return + * The status passed in. + */ + protected function assertNotEqual($first, $second, $message = '', $group = 'Other') { + return $this->_assert($first != $second, $message ? $message : t('%first is not equal to %second', array('%first' => $first, '%second' => $second)), $group); + } + + /** + * Check to see if two values are identical. + * + * @param $first + * The first value to check. + * @param $second + * The second value to check. + * @param $message + * The message to display along with the assertion. + * @param $group + * The type of assertion - examples are "Browser", "PHP". + * @return + * The status passed in. + */ + protected function assertIdentical($first, $second, $message = '', $group = 'Other') { + return $this->_assert($first === $second, $message ? $message : t('%first is identical to %second', array('%first' => $first, '%second' => $second)), $group); + } + + /** + * Check to see if two values are not identical. + * + * @param $first + * The first value to check. + * @param $second + * The second value to check. + * @param $message + * The message to display along with the assertion. + * @param $group + * The type of assertion - examples are "Browser", "PHP". + * @return + * The status passed in. + */ + protected function assertNotIdentical($first, $second, $message = '', $group = 'Other') { + return $this->_assert($first !== $second, $message ? $message : t('%first is not identical to %second', array('%first' => $first, '%second' => $second)), $group); + } + + /** + * Fire an assertion that is always positive. + * + * @param $message + * The message to display along with the assertion. + * @param $group + * The type of assertion - examples are "Browser", "PHP". + * @return + * TRUE. + */ + protected function pass($message = NULL, $group = 'Other') { + return $this->_assert(TRUE, $message, $group); + } + /** - * Retrieve the test information from getInfo(). + * Fire an assertion that is always negative. * - * @param string $label Name of the test to be used by the SimpleTest library. + * @param $message + * The message to display along with the assertion. + * @param $group + * The type of assertion - examples are "Browser", "PHP". + * @return + * FALSE. + */ + protected function fail($message = NULL, $group = 'Other') { + return $this->_assert(FALSE, $message, $group); + } + + /** + * Fire an error assertion. + * + * @param $message + * The message to display along with the assertion. + * @param $group + * The type of assertion - examples are "Browser", "PHP". + * @param $custom_caller + * The caller of the error. + */ + protected function error($message = '', $group = 'Other', $custom_caller = NULL) { + return $this->_assert('exception', $message, $group, $custom_caller); + } + + /** + * Run all tests in this class. */ - function __construct($label = NULL) { - if (!$label) { - if (method_exists($this, 'getInfo')) { - $info = $this->getInfo(); - $label = $info['name']; + function run() { + set_error_handler(array($this, 'errorHandler')); + $this->setUp(); + $methods = array(); + // Iterate through all the methods in this class. + foreach (get_class_methods(get_class($this)) as $method) { + // If the current method starts with "test", run it - it's a test. + if (strtolower(substr($method, 0, 4)) == 'test') { + $this->$method(); } } - parent::__construct($label); + // Finish up. + $this->tearDown(); + restore_error_handler(); + } + + /** + * Handle errors. + * + * @see set_error_handler + */ + function errorHandler($severity, $message, $file = NULL, $line = NULL) { + $severity = $severity & error_reporting(); + if ($severity) { + $error_map = array( + E_STRICT => 'Run-time notice', + E_WARNING => 'Warning', + E_NOTICE => 'Notice', + E_CORE_ERROR => 'Core error', + E_CORE_WARNING => 'Core warning', + E_USER_ERROR => 'User error', + E_USER_WARNING => 'User warning', + E_USER_NOTICE => 'User notice', + E_RECOVERABLE_ERROR => 'Recoverable error', + ); + $this->error($message, $error_map[$severity], array( + 'function' => '', + 'line' => $line, + 'file' => $file, + )); + } + return TRUE; } /** * Creates a node based on default settings. * - * @param settings - * An assocative array of settings to change from the defaults, keys are + * @param $settings + * An associative array of settings to change from the defaults, keys are * node properties, for example 'body' => 'Hello, world!'. * @return object Created node object. */ @@ -62,8 +326,8 @@ function drupalCreateNode($settings = array()) { ); $defaults['teaser'] = $defaults['body']; // If we already have a node, we use the original node's created time, and this - if (isset($settings['created'])) { - $defaults['date'] = format_date($settings['created'], 'custom', 'Y-m-d H:i:s O'); + if (isset($defaults['created'])) { + $defaults['date'] = format_date($defaults['created'], 'custom', 'Y-m-d H:i:s O'); } if (empty($settings['uid'])) { global $user; @@ -82,10 +346,11 @@ function drupalCreateNode($settings = array()) { /** * Creates a custom content type based on default settings. * - * @param settings + * @param $settings * An array of settings to change from the defaults. * Example: 'type' => 'foo'. - * @return object Created content type. + * @return + * Created content type. */ function drupalCreateContentType($settings = array()) { // find a non-existent random type name. @@ -126,9 +391,12 @@ function drupalCreateContentType($settings = array()) { /** * Get a list files that can be used in tests. * - * @param string $type File type, possible values: 'binary', 'html', 'image', 'javascript', 'php', 'sql', 'text'. - * @param integer $size File size in bytes to match. Please check the tests/files folder. - * @return array List of files that match filter. + * @param $type + * File type, possible values: 'binary', 'html', 'image', 'javascript', 'php', 'sql', 'text'. + * @param $size + * File size in bytes to match. Please check the tests/files folder. + * @return + * List of files that match filter. */ function drupalGetTestFiles($type, $size = NULL) { $files = array(); @@ -166,9 +434,12 @@ function drupalCompareFiles($file1, $file2) { /** * Generates a random string. * - * @param integer $number Number of characters in length to append to the prefix. - * @param string $prefix Prefix to use. - * @return string Randomly generated string. + * @param $number + * Number of characters in length to append to the prefix. + * @param $prefix + * Prefix to use. + * @return + * Randomly generated string. */ function randomName($number = 4, $prefix = 'simpletest_') { $chars = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ_'; @@ -185,8 +456,10 @@ function randomName($number = 4, $prefix = 'simpletest_') { * Create a user with a given set of permissions. The permissions correspond to the * names given on the privileges page. * - * @param array $permissions Array of permission names to assign to user. - * @return A fully loaded user object with pass_raw property, or FALSE if account + * @param $permissions + * Array of permission names to assign to user. + * @return + * A fully loaded user object with pass_raw property, or FALSE if account * creation fails. */ function drupalCreateUser($permissions = NULL) { @@ -218,8 +491,10 @@ function drupalCreateUser($permissions = NULL) { /** * Internal helper function; Create a role with specified permissions. * - * @param array $permissions Array of permission names to assign to role. - * @return integer Role ID of newly created role, or FALSE if role creation failed. + * @param $permissions + * Array of permission names to assign to role. + * @return + * Role ID of newly created role, or FALSE if role creation failed. */ private function _drupalCreateRole($permissions = NULL) { // Generate string version of permissions list. @@ -253,9 +528,12 @@ private function _drupalCreateRole($permissions = NULL) { /** * Check to make sure that the array of permissions are valid. * - * @param array $permissions Permissions to check. - * @param boolean $reset Reset cached available permissions. - * @return boolean Valid. + * @param $permissions + * Permissions to check. + * @param $reset + * Reset cached available permissions. + * @return + * TRUE or FALSE depending on whether the permissions are valid. */ private function checkPermissions(array $permissions, $reset = FALSE) { static $available; @@ -279,9 +557,11 @@ private function checkPermissions(array $permissions, $reset = FALSE) { * user out before logging in the specified user. If no user is specified then a new * user will be created and logged in. * - * @param object $user User object representing the user to login. - * @return object User that was logged in. Useful if no user was passed in order - * to retreive the created user. + * @param $user + * User object representing the user to login. + * @return + * User that was logged in. Useful if no user was passed in order to retrieve + * the created user. */ function drupalLogin($user = NULL) { if ($this->_logged_in) { @@ -369,8 +649,6 @@ function setUp() { $this->original_file_directory = file_directory_path(); variable_set('file_directory_path', file_directory_path() . '/' . $db_prefix); file_check_directory(file_directory_path(), TRUE); // Create the files directory. - - parent::setUp(); } /** @@ -423,27 +701,14 @@ function tearDown() { // Close the CURL handler. $this->curlClose(); + restore_error_handler(); } - parent::tearDown(); - } - - /** - * Set necessary reporter info. - */ - function run(&$reporter) { - $arr = array('class' => get_class($this)); - if (method_exists($this, 'getInfo')) { - $arr = array_merge($arr, $this->getInfo()); - } - $reporter->test_info_stack[] = $arr; - parent::run($reporter); - array_pop($reporter->test_info_stack); } /** * Initializes the cURL connection and gets a session cookie. * - * This function will add authentaticon headers as specified in + * This function will add authentication headers as specified in * simpletest_httpauth_username and simpletest_httpauth_pass variables. * Also, see the description of $curl_options among the properties. */ @@ -471,10 +736,12 @@ protected function curlConnect() { } /** - * Peforms a cURL exec with the specified options after calling curlConnect(). + * Performs a cURL exec with the specified options after calling curlConnect(). * - * @param array $curl_options Custom cURL options. - * @return string Content returned from the exec. + * @param + * $curl_options Custom cURL options. + * @return + * Content returned from the exec. */ protected function curlExec($curl_options) { $this->curlConnect(); @@ -498,9 +765,10 @@ protected function curlClose() { } /** - * Parse content returned from curlExec using DOM and simplexml. + * Parse content returned from curlExec using DOM and SimpleXML. * - * @return SimpleXMLElement A SimpleXMLElement or FALSE on failure. + * @return + * A SimpleXMLElement or FALSE on failure. */ protected function parse() { if (!$this->elements) { @@ -523,9 +791,12 @@ protected function parse() { /** * Retrieves a Drupal path or an absolute path. * - * @param $path string Drupal path or url to load into internal browser - * @param array $options Options to be forwarded to url(). - * @return The retrieved HTML string, also available as $this->drupalGetContent() + * @param $path + * Drupal path or url to load into internal browser + * @param $options + * Options to be forwarded to url(). + * @return + * The retrieved HTML string, also available as $this->drupalGetContent() */ function drupalGet($path, $options = array()) { $options['absolute'] = TRUE; @@ -542,14 +813,14 @@ function drupalGet($path, $options = array()) { * Execute a POST request on a Drupal page. * It will be done as usual POST request with SimpleBrowser. * - * @param string $path + * @param $path * Location of the post form. Either a Drupal path or an absolute path or * NULL to post to the current page. - * @param array $edit + * @param $edit * Field data in an assocative array. Changes the current input fields * (where possible) to the values indicated. A checkbox can be set to * TRUE to be checked and FALSE to be unchecked. - * @param string $submit + * @param $submit * Value of the submit button. * @param $tamper * If this is set to TRUE then you can post anything, otherwise hidden and @@ -604,15 +875,15 @@ function drupalPost($path, $edit, $submit, $tamper = FALSE) { * exist and attempt to create POST data in the correct manner for the particular * field type. * - * @param array $post + * @param $post * Reference to array of post values. - * @param array $edit + * @param $edit * Reference to array of edit values to be checked against the form. - * @param string $submit + * @param $submit * Form submit button value. - * @param array $form + * @param $form * Array of form elements. - * @return boolean + * @return * Submit value matches a valid submit input in the form. */ protected function handleForm(&$post, &$edit, &$upload, $submit, $form) { @@ -622,13 +893,12 @@ protected function handleForm(&$post, &$edit, &$upload, $submit, $form) { foreach ($elements as $element) { // SimpleXML objects need string casting all the time. $name = (string) $element['name']; - $id = (string) $element['id']; // This can either be the type of <input> or the name of the tag itself // for <select> or <textarea>. $type = isset($element['type']) ? (string)$element['type'] : $element->getName(); $value = isset($element['value']) ? (string)$element['value'] : ''; $done = FALSE; - if (isset($edit[$name]) || isset($edit[$id])) { + if (isset($edit[$name])) { switch ($type) { case 'text': case 'textarea': @@ -733,8 +1003,10 @@ protected function handleForm(&$post, &$edit, &$upload, $submit, $form) { /** * Get all option elements, including nested options, in a select. * - * @param SimpleXMLElement $element - * @return array Option elements in select. + * @param $element + * The element for which to get the options. + * @return + * Option elements in select. */ private function getAllOptions(SimpleXMLElement $element) { $options = array(); @@ -759,10 +1031,12 @@ private function getAllOptions(SimpleXMLElement $element) { * for successful click. * WARNING: Assertion fails on empty ("") output from the clicked link. * - * @param string $label Text between the anchor tags. - * @param integer $index Link position counting from zero. - * @param boolean $reporting Assertions or not. - * @return boolean/string Page on success. + * @param $label + * Text between the anchor tags. + * @param $index + * Link position counting from zero. + * @return + * Page on success, or FALSE on failure. */ function clickLink($label, $index = 0) { $url_before = $this->getUrl(); @@ -782,7 +1056,7 @@ function clickLink($label, $index = 0) { /** * Takes a path and returns an absolute path. * - * @param @path + * @param $path * The path, can be a Drupal path or a site-relative path. It might have a * query, too. Can even be an absolute path which is just passed through. * @return @@ -810,7 +1084,8 @@ function getAbsoluteUrl($path) { /** * Get the current url from the cURL handler. * - * @return string current url. + * @return + * The current url. */ function getUrl() { return curl_getinfo($this->ch, CURLINFO_EFFECTIVE_URL); @@ -827,24 +1102,34 @@ function drupalGetContent() { * Pass if the raw text IS found on the loaded page, fail otherwise. Raw text * refers to the raw HTML that the page generated. * - * @param string $raw Raw string to look for. - * @param string $message Message to display. - * @return boolean TRUE on pass. + * @param $raw + * Raw (HTML) string to look for. + * @param $message + * Message to display. + * @param $group + * The group this message belongs to, defaults to 'Other'. + * @return + * TRUE on pass, FALSE on fail. */ function assertRaw($raw, $message = "%s", $group = 'Other') { - return $this->assertFalse(strpos($this->_content, $raw) === FALSE, $message, $group); + return $this->_assert(strpos($this->_content, $raw) !== FALSE, $message, $group); } /** * Pass if the raw text is NOT found on the loaded page, fail otherwise. Raw text * refers to the raw HTML that the page generated. * - * @param string $raw Raw string to look for. - * @param string $message Message to display. - * @return boolean TRUE on pass. + * @param $raw + * Raw (HTML) string to look for. + * @param $message + * Message to display. + * @param $group + * The group this message belongs to, defaults to 'Other'. + * @return + * TRUE on pass, FALSE on fail. */ function assertNoRaw($raw, $message = "%s", $group = 'Other') { - return $this->assertTrue(strpos($this->_content, $raw) === FALSE, $message, $group); + return $this->_assert(strpos($this->_content, $raw) === FALSE, $message, $group); } /** @@ -852,9 +1137,14 @@ function assertNoRaw($raw, $message = "%s", $group = 'Other') { * is the equivilent of what a user would see when viewing through a web browser. * In other words the HTML has been filtered out of the contents. * - * @param string $raw Text string to look for. - * @param string $message Message to display. - * @return boolean TRUE on pass. + * @param $text + * Plain text to look for. + * @param $message + * Message to display. + * @param $group + * The group this message belongs to, defaults to 'Other'. + * @return + * TRUE on pass, FALSE on fail. */ function assertText($text, $message = '', $group = 'Other') { return $this->assertTextHelper($text, $message, $group = 'Other', FALSE); @@ -865,22 +1155,34 @@ function assertText($text, $message = '', $group = 'Other') { * is the equivilent of what a user would see when viewing through a web browser. * In other words the HTML has been filtered out of the contents. * - * @param string $raw Text string to look for. - * @param string $message Message to display. - * @return boolean TRUE on pass. + * @param $text + * Plain text to look for. + * @param $message + * Message to display. + * @param $group + * The group this message belongs to, defaults to 'Other'. + * @return + * TRUE on pass, FALSE on fail. */ function assertNoText($text, $message = '', $group = 'Other') { return $this->assertTextHelper($text, $message, $group, TRUE); } /** - * Filter out the HTML of the page and assert that the plain text us found. Called by - * the plain text assertions. + * Helper for assertText and assertNoText. + * + * It is not recommended to call this function directly. * - * @param string $text Text to look for. - * @param string $message Message to display. - * @param boolean $not_exists The assert to make in relation to the text's existance. - * @return boolean Assertion result. + * @param $text + * Plain text to look for. + * @param $message + * Message to display. + * @param $group + * The group this message belongs to. + * @param $not_exists + * TRUE if this text should not exist, FALSE if it should. + * @return + * TRUE on pass, FALSE on fail. */ protected function assertTextHelper($text, $message, $group, $not_exists) { if ($this->plain_text === FALSE) { @@ -889,49 +1191,70 @@ protected function assertTextHelper($text, $message, $group, $not_exists) { if (!$message) { $message = '"' . $text . '"' . ($not_exists ? ' not found.' : ' found.'); } - return $this->assertTrue($not_exists == (strpos($this->plain_text, $text) === FALSE), $message, $group); + return $this->_assert($not_exists == (strpos($this->plain_text, $text) === FALSE), $message, $group); } /** * Will trigger a pass if the Perl regex pattern is found in the raw content. * - * @param string $pattern Perl regex to look for including the regex delimiters. - * @param string $message Message to display. - * @return boolean True if pass. + * @param $pattern + * Perl regex to look for including the regex delimiters. + * @param $message + * Message to display. + * @param $group + * The group this message belongs to. + * @return + * TRUE on pass, FALSE on fail. */ function assertPattern($pattern, $message = '%s', $group = 'Other') { - return $this->assertTrue(preg_match($pattern, $this->drupalGetContent()), $message, $group); + return $this->_assert((bool) preg_match($pattern, $this->drupalGetContent()), $message, $group); } /** * Will trigger a pass if the perl regex pattern is not present in raw content. * - * @param string $pattern Perl regex to look for including the regex delimiters. - * @param string $message Message to display. - * @return boolean True if pass. + * @param $pattern + * Perl regex to look for including the regex delimiters. + * @param $message + * Message to display. + * @param $group + * The group this message belongs to. + * @return + * TRUE on pass, FALSE on fail. */ function assertNoPattern($pattern, $message = '%s', $group = 'Other') { - return $this->assertFalse(preg_match($pattern, $this->drupalGetContent()), $message, $group); + return $this->_assert(!preg_match($pattern, $this->drupalGetContent()), $message, $group); } /** * Pass if the page title is the given string. * - * @param $title Text string to look for. - * @param $message Message to display. - * @return boolean TRUE on pass. + * @param $title + * The string the title should be. + * @param $message + * Message to display. + * @param $group + * The group this message belongs to. + * @return + * TRUE on pass, FALSE on fail. */ function assertTitle($title, $message, $group = 'Other') { - return $this->assertTrue($this->parse() && $this->elements->xpath('//title[text()="' . $title . '"]'), $message, $group); + return $this->_assert($this->parse() && $this->elements->xpath('//title[text()="' . $title . '"]'), $message, $group); } /** * Assert that a field exists in the current page by the given XPath. * - * @param string $xpath XPath used to find the field. - * @param string $value Value of the field to assert. - * @param string $message Message to display. - * @return boolean Assertion result. + * @param $xpath + * XPath used to find the field. + * @param $value + * Value of the field to assert. + * @param $message + * Message to display. + * @param $group + * The group this message belongs to. + * @return + * TRUE on pass, FALSE on fail. */ function assertFieldByXPath($xpath, $value, $message, $group = 'Other') { $fields = array(); @@ -953,12 +1276,18 @@ function assertFieldByXPath($xpath, $value, $message, $group = 'Other') { } /** - * Assert that a field does not exists in the current page by the given XPath. + * Assert that a field does not exist in the current page by the given XPath. * - * @param string $xpath XPath used to find the field. - * @param string $value Value of the field to assert. - * @param string $message Message to display. - * @return boolean Assertion result. + * @param $xpath + * XPath used to find the field. + * @param $value + * Value of the field to assert. + * @param $message + * Message to display. + * @param $group + * The group this message belongs to. + * @return + * TRUE on pass, FALSE on fail. */ function assertNoFieldByXPath($xpath, $value, $message, $group = 'Other') { $fields = array(); @@ -982,22 +1311,34 @@ function assertNoFieldByXPath($xpath, $value, $message, $group = 'Other') { /** * Assert that a field exists in the current page with the given name and value. * - * @param string $name Name of field to assert. - * @param string $value Value of the field to assert. - * @param string $message Message to display. - * @return boolean Assertion result. + * @param $name + * Name of field to assert. + * @param $value + * Value of the field to assert. + * @param $message + * Message to display. + * @param $group + * The group this message belongs to. + * @return + * TRUE on pass, FALSE on fail. */ function assertFieldByName($name, $value = '', $message = '') { return $this->assertFieldByXPath($this->_constructFieldXpath('name', $name), $value, $message ? $message : t('Found field by name @name', array('@name' => $name)), t('Browser')); } /** - * Assert that a field does not exists in the current page with the given name and value. + * Assert that a field does not exist with the given name and value. * - * @param string $name Name of field to assert. - * @param string $value Value of the field to assert. - * @param string $message Message to display. - * @return boolean Assertion result. + * @param $name + * Name of field to assert. + * @param $value + * Value of the field to assert. + * @param $message + * Message to display. + * @param $group + * The group this message belongs to. + * @return + * TRUE on pass, FALSE on fail. */ function assertNoFieldByName($name, $value = '', $message = '') { return $this->assertNoFieldByXPath($this->_constructFieldXpath('name', $name), $value, $message ? $message : t('Did not find field by name @name', array('@name' => $name)), t('Browser')); @@ -1006,44 +1347,66 @@ function assertNoFieldByName($name, $value = '', $message = '') { /** * Assert that a field exists in the current page with the given id and value. * - * @param string $id Id of field to assert. - * @param string $value Value of the field to assert. - * @param string $message Message to display. - * @return boolean Assertion result. + * @param $id + * Id of field to assert. + * @param $value + * Value of the field to assert. + * @param $message + * Message to display. + * @param $group + * The group this message belongs to. + * @return + * TRUE on pass, FALSE on fail. */ function assertFieldById($id, $value = '', $message = '') { return $this->assertFieldByXPath($this->_constructFieldXpath('id', $id), $value, $message ? $message : t('Found field by id @id', array('@id' => $id)), t('Browser')); } /** - * Assert that a field does not exists in the current page with the given id and value. + * Assert that a field does not exist with the given id and value. * - * @param string $id Id of field to assert. - * @param string $value Value of the field to assert. - * @param string $message Message to display. - * @return boolean Assertion result. + * @param $id + * Id of field to assert. + * @param $value + * Value of the field to assert. + * @param $message + * Message to display. + * @param $group + * The group this message belongs to. + * @return + * TRUE on pass, FALSE on fail. */ function assertNoFieldById($id, $value = '', $message = '') { return $this->assertNoFieldByXPath($this->_constructFieldXpath('id', $id), $value, $message ? $message : t('Did not find field by id @id', array('@id' => $id)), t('Browser')); } /** - * Assert that a field exists in the current page with the given name or id. + * Assert that a field exists with the given name or id. * - * @param string $field Name or id of the field. - * @param string $message Message to display. - * @return boolean Assertion result. + * @param $field + * Name or id of field to assert. + * @param $message + * Message to display. + * @param $group + * The group this message belongs to. + * @return + * TRUE on pass, FALSE on fail. */ function assertField($field, $message = '', $group = 'Other') { return $this->assertFieldByXPath($this->_constructFieldXpath('name', $field) . '|' . $this->_constructFieldXpath('id', $field), '', $message, $group); } /** - * Assert that a field does not exists in the current page with the given name or id. + * Assert that a field does not exist with the given name or id. * - * @param string $field Name or id of the field. - * @param string $message Message to display. - * @return boolean Assertion result. + * @param $field + * Name or id of field to assert. + * @param $message + * Message to display. + * @param $group + * The group this message belongs to. + * @return + * TRUE on pass, FALSE on fail. */ function assertNoField($field, $message = '', $group = 'Other') { return $this->assertNoFieldByXPath($this->_constructFieldXpath('name', $field) . '|' . $this->_constructFieldXpath('id', $field), '', $message, $group); @@ -1052,9 +1415,12 @@ function assertNoField($field, $message = '', $group = 'Other') { /** * Construct an XPath for the given set of attributes and value. * - * @param array $attribute Field attributes. - * @param string $value Value of field. - * @return string XPath for specified values. + * @param $attribute + * Field attributes. + * @param $value + * Value of field. + * @return + * XPath for specified values. */ function _constructFieldXpath($attribute, $value) { return '//textarea[@' . $attribute . '="' . $value . '"]|//input[@' . $attribute . '="' . $value . '"]|//select[@' . $attribute . '="' . $value . '"]'; @@ -1063,10 +1429,13 @@ function _constructFieldXpath($attribute, $value) { /** * Assert the page responds with the specified response code. * - * @param integer $code Reponse code. For example 200 is a successful page request. For - * a list of all codes see http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html. - * @param string $message Message to display. - * @return boolean Assertion result. + * @param $code + * Reponse code. For example 200 is a successful page request. For a list + * of all codes see http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html. + * @param $message + * Message to display. + * @return + * Assertion result. */ function assertResponse($code, $message = '') { $curl_code = curl_getinfo($this->ch, CURLINFO_HTTP_CODE); diff --git a/modules/simpletest/simpletest.css b/modules/simpletest/simpletest.css index 6ceda61114dbdc8ffc8e2bb015be3e3db3f9d1f1..e917629a5a97d4168738a741968480036afaa0db 100644 --- a/modules/simpletest/simpletest.css +++ b/modules/simpletest/simpletest.css @@ -25,11 +25,11 @@ table#simpletest-form-table tr.simpletest-group td { } div.simpletest-pass { - background: #b6ffb6; + color: #33a333; } div.simpletest-fail { - background: #ffc9c9; + color: #a30000; } tr.simpletest-pass.odd { diff --git a/modules/simpletest/simpletest.install b/modules/simpletest/simpletest.install index 074d250a6e3f6212d9263f7db9d080896f83f87a..6ede82d7937f21d25db9fa843741b236152bf834 100644 --- a/modules/simpletest/simpletest.install +++ b/modules/simpletest/simpletest.install @@ -5,6 +5,7 @@ * Implementation of hook_install(). */ function simpletest_install() { + drupal_install_schema('simpletest'); // Check for files directory. $path = file_directory_path() . '/simpletest'; if (file_check_directory($path, FILE_CREATE_DIRECTORY)) { @@ -95,6 +96,7 @@ function simpletest_uninstall() { variable_del('simpletest_httpauth_username'); variable_del('simpletest_httpauth_pass'); variable_del('simpletest_devel'); + drupal_uninstall_schema('simpletest'); } /** @@ -133,3 +135,125 @@ function simpletest_requirements($phase) { return $requirements; } + +function simpletest_schema() { + $schema['simpletest'] = array( + 'description' => t('Stores simpletest messages'), + 'fields' => array( + 'message_id' => array( + 'type' => 'serial', + 'not null' => TRUE, + 'description' => t('Primary Key: Unique simpletest message ID.'), + ), + 'test_id' => array( + 'type' => 'int', + 'not null' => TRUE, + 'default' => 0, + 'description' => t('Test id, messages belonging to the same id are reported together'), + ), + 'test_class' => array( + 'type' => 'varchar', + 'length' => 255, + 'not null' => TRUE, + 'default' => '', + 'description' => t('The name of the class that created this message.'), + ), + 'status' => array( + 'type' => 'varchar', + 'length' => 9, + 'not null' => TRUE, + 'default' => '', + 'description' => t('Message status. Core understands pass, fail, exception.'), + ), + 'message' => array( + 'type' => 'varchar', + 'length' => 255, + 'not null' => TRUE, + 'default' => '', + 'description' => t('The message itself.'), + ), + 'message_group' => array( + 'type' => 'varchar', + 'length' => 255, + 'not null' => TRUE, + 'default' => '', + 'description' => t('The message group this message belongs to. For example: warning, browser, user.'), + ), + 'caller' => array( + 'type' => 'varchar', + 'length' => 255, + 'not null' => TRUE, + 'default' => '', + 'description' => t('Name of the caller function or method that created this message.'), + ), + 'line' => array( + 'type' => 'int', + 'not null' => TRUE, + 'default' => 0, + 'description' => t('Line number of the caller.'), + ), + 'file' => array( + 'type' => 'varchar', + 'length' => 255, + 'not null' => TRUE, + 'default' => '', + 'description' => t('Name of the file where the caller is.'), + ), + ), + 'primary key' => array('message_id'), + 'indexes' => array( + 'reporter' => array('test_class, message_id'), + ), + ); + $schema['simpletest_test_id'] = array( + 'description' => t('Stores simpletest test IDs.'), + 'fields' => array( + 'message_id' => array( + 'type' => 'serial', + 'not null' => TRUE, + 'description' => t('Primary Key: Unique simpletest ID.'), + ), + ), + 'primary key' => array('message_id'), + ); + return $schema; +} + +/** + * Create the simpletest tables. + */ +function simpletest_update_7000() { + $ret = array(); + $schema = array(); + + $schema['simpletest'] = array( + 'fields' => array( + 'message_id' => array('type' => 'serial', 'not null' => TRUE), + 'test_id' => array('type' => 'int', 'not null' => TRUE, 'default' => 0), + 'test_class' => array('type' => 'varchar', 'length' => 255, 'not null' => TRUE, 'default' => ''), + 'status' => array('type' => 'varchar', 'length' => 9, 'not null' => TRUE, 'default' => ''), + 'message' => array('type' => 'varchar', 'length' => 255, 'not null' => TRUE, 'default' => ''), + 'message_group' => array('type' => 'varchar', 'length' => 255, 'not null' => TRUE, 'default' => ''), + 'caller' => array('type' => 'varchar', 'length' => 255, 'not null' => TRUE, 'default' => ''), + 'line' => array('type' => 'int', 'not null' => TRUE, 'default' => 0), + 'file' => array('type' => 'varchar', 'length' => 255, 'not null' => TRUE, 'default' => ''), + ), + 'primary key' => array('message_id'), + 'indexes' => array( + 'reporter' => array('test_class, message_id'), + ), + ); + + $schema['simpletest_test_id'] = array( + 'fields' => array( + 'message_id' => array('type' => 'serial', 'not null' => TRUE), + ), + 'primary key' => array('message_id'), + ); + + foreach ($schema as $name => $definition) { + db_create_table($ret, $name, $definition); + } + + return $ret; +} \ No newline at end of file diff --git a/modules/simpletest/simpletest.module b/modules/simpletest/simpletest.module index 5e0a11a8412e680f6b71c93193a12b017b7e4fed..ee072c275630e8cad4f830f54d9ea2cf0d7af9d1 100644 --- a/modules/simpletest/simpletest.module +++ b/modules/simpletest/simpletest.module @@ -22,7 +22,8 @@ function simpletest_help($path, $arg) { function simpletest_menu() { $items['admin/build/testing'] = array( 'title' => 'Testing', - 'page callback' => 'simpletest_entrypoint', + 'page callback' => 'drupal_get_form', + 'page arguments' => array('simpletest_test_form'), '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'), ); @@ -50,104 +51,123 @@ function simpletest_perm() { */ function simpletest_theme() { return array( - 'simpletest_overview_form' => array( + 'simpletest_test_form' => array( + 'arguments' => array('form' => NULL) + ), + 'simpletest_result_summary' => array( 'arguments' => array('form' => NULL) ), ); } /** - * Try to load the simepletest - * @return boolean TRUE if the load succeeded + * Menu callback for both running tests and listing possible tests */ -function simpletest_load() { - global $user; - static $loaded; - if (!$loaded) { - $loaded = TRUE; - if ($user->uid != 1) { - drupal_set_message(t('It is strongly suggested to run the tests with the first user!')); +function simpletest_test_form() { + global $db_prefix, $db_prefix_original; + $form = array(); + $uncategorized_tests = simpletest_get_all_tests(); + $tests = simpletest_categorize_tests($uncategorized_tests); + if (isset($_SESSION['test_id'])) { + $results = db_query("SELECT * FROM {simpletest} WHERE test_id = %d ORDER BY test_class, message_id", $_SESSION['test_id']); + unset($_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 = $uncategorized_tests[$class]->getInfo(); + $group = $info['group']; + 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->caller, + $map[$status], + ), + 'class' => "simpletest-$status", + ); + } + unset($element); } - $path = drupal_get_path('module', 'simpletest') . '/'; - foreach (array('simpletest.php', 'unit_tester.php', 'reporter.php', 'drupal_reporter.php', 'drupal_web_test_case.php', 'drupal_test_suite.php') as $file) { - require_once($path . $file); + $all_ok = TRUE; + foreach ($form['results'] as $group => &$elements) { + $group_ok = TRUE; + foreach ($elements as $class => &$element) { + $info = $uncategorized_tests[$class]->getInfo(); + $ok = $element['summary']['#fail'] + $element['summary']['#exception'] == 0; + $element += array( + '#type' => 'fieldset', + '#collapsible' => TRUE, + '#collapsed' => $ok, + '#description' => $info['description'], + ); + $element['result_table']['#value'] = 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; } -} - -/** - * Menu callback for both running tests and listing possible tests - */ -function simpletest_entrypoint() { - 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; - } - 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 - */ -function simpletest_overview_form() { - $output = array( - '#theme' => 'simpletest_overview_form' - ); - - $total_test = &simpletest_get_total_test(); - - $test_instances = $total_test->getTestInstances(); - uasort($test_instances, 'simpletest_compare_instances'); - - foreach ($test_instances as $group_test) { - $group = array(); - $tests = $group_test->getTestInstances(); - $group_class = str_replace(' ', '-', strtolower($group_test->getLabel())); - $group['tests'] = array( - '#type' => 'fieldset', - '#collapsible' => TRUE, - '#collapsed' => TRUE, - '#title' => 'Tests', - '#attributes' => array('class' => $group_class), - ); - foreach ($tests as $test) { + foreach ($tests as $group_name => $test_group) { + foreach ($test_group as $test) { $test_info = $test->getInfo(); - $group['tests'][get_class($test)] = array( + $test_class = get_class($test); + $form['tests'][$group_name][$test_class] = array( '#type' => 'checkbox', '#title' => $test_info['name'], '#default_value' => 0, '#description' => $test_info['description'], ); } - $output[] = $group + array( - '#type' => 'fieldset', - '#collapsible' => FALSE, - '#title' => $group_test->getLabel(), - '#attributes' => array('class' => 'all-tests'), - ); } - $output['run'] = array( + $form['run'] = array( '#type' => 'fieldset', '#collapsible' => FALSE, '#collapsed' => FALSE, '#title' => t('Run tests'), ); - $output['run']['running_options'] = array( + $form['run']['running_options'] = array( '#type' => 'radios', '#default_value' => 'selected_tests', '#options' => array( @@ -155,25 +175,23 @@ function simpletest_overview_form() { 'selected_tests' => t('Run selected tests'), ), ); - $output['run']['op'] = array( + $form['run']['op'] = array( '#type' => 'submit', '#value' => t('Run tests'), - '#submit' => array('simpletest_run_selected_tests') ); - - $output['reset'] = array( + $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.') ); - $output['reset']['op'] = array( + $form['reset']['op'] = array( '#type' => 'submit', '#value' => t('Clean environment'), '#submit' => array('simpletest_clean_environment') ); - return $output; + return $form; } /** @@ -181,7 +199,9 @@ function simpletest_overview_form() { * * @ingroup themeable */ -function theme_simpletest_overview_form($form) { +function theme_simpletest_test_form($form) { + drupal_add_css(drupal_get_path('module', 'simpletest') .'/simpletest.css', 'module'); + drupal_add_js(drupal_get_path('module', 'simpletest') .'/simpletest.js', 'module'); $header = array( array('data' => t('Run'), 'class' => 'simpletest_run checkbox'), array('data' => t('Test'), 'class' => 'simpletest_test'), @@ -196,92 +216,250 @@ function theme_simpletest_overview_form($form) { // Go through each test group and create a row: $rows = array(); - foreach (element_children($form) as $gid) { - if (isset($form[$gid]['tests'])) { - $element = &$form[$gid]; - $test_class = strtolower(trim(preg_replace("/[^\w\d]/", "-",$element["#title"]))); - - $row = array(); - $row[] = array('id' => $test_class, 'class' => 'simpletest-select-all'); - $row[] = array( - 'data' => '<div class="simpletest-image" id="simpletest-test-group-' . $test_class . '">' . $js['images'][0] . '</div> <label for="' . $test_class . '-select-all" class="simpletest-group-label">' . $element['#title'] . '</label>', - ); - $row[] = $element['#description']; - $rows[] = array('data' => $row, 'class' => 'simpletest-group'); - $current_js = array('testClass' => $test_class . '-test', 'testNames' => array(), 'imageDirection' => 0, 'clickActive' => FALSE); - - // Go through each test in the group and create table rows setting them to invisible: - foreach (element_children($element['tests']) as $test_name) { - $current_js['testNames'][] = 'edit-' . $test_name; - $test = $element['tests'][$test_name]; - foreach (array('title', 'description') as $key) { - $$key = $test['#' . $key]; - unset($test['#' . $key]); - } - $test['#name'] = $test_name; - $themed_test = drupal_render($test); - $row = array(); - $row[] = $themed_test; - $row[] = theme('indentation', 1) . '<label for="edit-' . $test_name . '">' . $title . '</label>'; - $row[] = '<div class="description">' . $description . '</div>'; - $rows[] = array('data' => $row, 'style' => 'display: none;', 'class' => $test_class . '-test'); + foreach (element_children($form['tests']) as $key) { + $element = &$form['tests'][$key]; + $test_class = strtolower(trim(preg_replace("/[^\w\d]/", "-", $key))); + $row = array(); + $row[] = array('id' => $test_class, 'class' => 'simpletest-select-all'); + $row[] = array( + 'data' => '<div class="simpletest-image" id="simpletest-test-group-'. $test_class .'">'. $js['images'][0] .'</div> <label for="'. $test_class .'-select-all" class="simpletest-group-label">'. $key .'</label>', + 'style' => 'font-weight: bold;' + ); + $row[] = isset($element['#description']) ? $element['#description'] : ' '; + $rows[] = array('data' => $row, 'class' => 'simpletest-group'); + + $current_js = array('testClass' => $test_class .'-test', 'testNames' => array(), 'imageDirection' => 0, 'clickActive' => FALSE); + foreach (element_children($element) as $test_name) { + $current_js['testNames'][] = 'edit-'. $test_name; + $test = $element[$test_name]; + foreach (array('title', 'description') as $key) { + $$key = $test['#'. $key]; + unset($test['#'. $key]); } - $js['simpletest-test-group-' . $test_class] = $current_js; - unset($form[$gid]); // Remove test group from form. + $test['#name'] = $test_name; + $themed_test = drupal_render($test); + $row = array(); + $row[] = $themed_test; + $row[] = theme('indentation', 1) .'<label for="edit-'. $test_name .'">'. $title .'</label>'; + $row[] = '<div class="description">'. $description .'</div>'; + $rows[] = array('data' => $row, 'style' => 'display: none;', 'class' => $test_class .'-test'); } + $js['simpletest-test-group-'. $test_class] = $current_js; } + unset($form['tests']); drupal_add_js(array('simpleTest' => $js), 'setting'); - // Output test groups: $output = ''; + if (isset($form['results'])) { + $output .= drupal_render($form['summary']); + $output .= drupal_render($form['results']); + } if (count($rows)) { $output .= theme('table', $header, $rows, array('id' => 'simpletest-form-table')); } - // Output the rest of the form, excluded test groups which have been removed: $output .= drupal_render($form); return $output; } +function theme_simpletest_result_summary($form, $text = NULL) { + return '<div class="simpletest-'. ($form['#ok'] ? 'pass' : 'fail') .'">' . _simpletest_format_summary_line($form) . '</div>'; +} + +function _simpletest_format_summary_line($summary) { + return t('@pass, @fail, @exception', array( + '@pass' => format_plural(isset($summary['#pass']) ? $summary['#pass'] : 0, '1 pass', '@count passes'), + '@fail' => format_plural(isset($summary['#fail']) ? $summary['#fail'] : 0, '1 fail', '@count fails'), + '@exception' => format_plural(isset($summary['#exception']) ? $summary['#exception'] : 0, '1 exception', '@count exceptions'), + )); +} + /** - * Compare two test instance objects for use in sorting. + * Run selected tests. */ -function simpletest_compare_instances(&$a, &$b) { - if (substr_compare($a->_label, $b->_label, 0) > 0) { - return 1; +function simpletest_test_form_submit($form, &$form_state) { + $output = ''; + $batch_mode = !preg_match("/^simpletest\d+$/", $_SERVER['HTTP_USER_AGENT']); + $tests_list = array(); + $run_all_tests = $form_state['values']['running_options'] == 'all_tests'; + simpletest_get_all_tests(); + foreach ($form_state['values'] as $class_name => $value) { + if (class_exists($class_name) && ($value === 1 || $run_all_tests)) { + $tests_list[] = $class_name; + } + } + if (count($tests_list) > 0 ) { + simpletest_run_tests($tests_list, 'drupal', $batch_mode); + } + else { + drupal_set_message(t('No test has been selected.'), 'error'); } - return -1; } /** - * Run selected tests. + * Actually runs tests + * @param $test_list + * List of tests to run. + * @param $reporter + * Which reporter to use. Allowed values are: text, xml, html and drupal, + * drupal being the default. + * @param $batch_mode + * Whether to use the batch API or not. */ -function simpletest_run_selected_tests($form, &$form_state) { - $form_state['redirect'] = FALSE; - $output = ''; - switch ($form_state['values']['running_options']) { - case 'all_tests': - $output = simpletest_run_tests(); - break; - case 'selected_tests': - $tests_list = array(); - foreach ($form_state['values'] as $item => $value) { - if ($value === 1 && strpos($item, 'selectall') === FALSE) { - $tests_list[] = $item; +function simpletest_run_tests($test_list, $reporter = 'drupal', $batch_mode = FALSE) { + global $db_prefix, $db_prefix_original; + cache_clear_all(); + db_query('INSERT INTO {simpletest_test_id} VALUES (default)'); + $test_id = db_last_insert_id('simpletest_test_id', 'test_id'); + + if ($batch_mode) { + $batch = array( + 'title' => t('Running SimpleTests'), + 'operations' => array( + array('_simpletest_batch_operation', array($test_list, $test_id)), + ), + 'finished' => '_simpletest_batch_finished', + 'redirect' => 'admin/build/testing', + 'progress_message' => t('Processing tests.'), + 'css' => array(drupal_get_path('module', 'simpletest') .'/simpletest.css'), + 'init_message' => t('SimpleTest is initializing...') . ' ' . format_plural(count($test_list), "one test case will run.", "@count test cases will run."), + ); + batch_set($batch); + } + else { + simpletest_get_all_tests(); + foreach ($test_list as $test_class) { + $test = new $test_class($test_id); + $test->run(); + } + $_SESSION['test_id'] = $test_id; + } +} + +/** + * Batch operation callback. + */ +function _simpletest_batch_operation($test_list_init, $test_id, &$context) { + // Ensure that all classes are loaded before we unserialize some instances. + simpletest_get_all_tests(); + + // Get working values. + if (!isset($context['sandbox']['max'])) { + // First iteration: initialize working values. + $test_list = $test_list_init; + $context['sandbox']['max'] = count($test_list); + $test_results = array('#pass' => 0, '#fail' => 0, '#exception' => 0); + } + else { + // Nth iteration: get the current values where we last stored them. + $test_list = $context['sandbox']['tests']; + $test_results = $context['sandbox']['test_results']; + } + $max = $context['sandbox']['max']; + + // Perform the next test. + $test_class = array_shift($test_list); + $test = new $test_class($test_id); + $test->run(); + $size = count($test_list); + $info = $test->getInfo(); + + // Gather results and compose the report. + $test_results[$test_class] = $test->_results; + foreach ($test_results[$test_class] as $key => $value) { + $test_results[$key] += $value; + } + $test_results[$test_class]['#name'] = $info['name']; + $items = array(); + foreach (element_children($test_results) as $class) { + $items[] = '<div class="simpletest-' . ($test_results[$class]['#fail'] + $test_results[$class]['#exception'] ? 'fail' : 'pass') . '">' . t('@name: @summary', array('@name' => $test_results[$class]['#name'], '@summary' => _simpletest_format_summary_line($test_results[$class]))) . '</div>'; + } + $message = t('Processed test @num of @max - %test.', array('%test' => $info['name'], '@num' => $max - $size, '@max' => $max)); + $message .= theme('item_list', $items); + $context['message'] = $message; + // TODO: Do we want a summary of all? + + // Save working values for the next iteration. + $context['sandbox']['tests'] = $test_list; + $context['sandbox']['test_results'] = $test_results; + // The test_id is the only thing we need to save for the report page. + $context['results']['test_id'] = $test_id; + + // Multistep processing: report progress. + $context['finished'] = 1 - $size / $max; +} + +function _simpletest_batch_finished($success, $results, $operations) { + $_SESSION['test_id'] = $results['test_id']; + if ($success) { + drupal_set_message(t('The tests have finished running.')); + } + else { + drupal_set_message(t('The tests did not successfully finish.'), 'error'); + } +} + +/** + * Get a list of all of the tests. + * + * @return + * An array of tests, with the class name as the keys and the instantiated + * versions of the classes as the values. + */ +function simpletest_get_all_tests() { + static $formatted_classes; + if (!isset($formatted_classes)) { + require_once drupal_get_path('module', 'simpletest') . '/drupal_web_test_case.php'; + $files = array(); + foreach (array_keys(module_rebuild_cache()) as $module) { + $module_path = drupal_get_path('module', $module); + $test = $module_path . "/$module.test"; + if (file_exists($test)) { + $files[] = $test; + } + + $tests_directory = $module_path . '/tests'; + if (is_dir($tests_directory)) { + foreach (file_scan_directory($tests_directory, '\.test$') as $file) { + $files[] = $file->filename; } } - if (count($tests_list) > 0 ) { - $output = simpletest_run_tests($tests_list); - break; + } + + $existing_classes = get_declared_classes(); + foreach ($files as $file) { + include_once($file); + } + $classes = array_values(array_diff(get_declared_classes(), $existing_classes)); + $formatted_classes = array(); + foreach ($classes as $key => $class) { + if (method_exists($class, 'getInfo')) { + $formatted_classes[$class] = new $class; } - // Fall through - default: - drupal_set_message(t('No test has been selected.'), 'error'); + } } + if (count($formatted_classes) == 0) { + drupal_set_message('No test cases found.', 'error'); + return FALSE; + } + return $formatted_classes; +} - simpletest_running_output($output); - return FALSE; +/** + * Categorize the tests into groups. + * + * @param $tests + * A list of tests from simpletest_get_all_tests. + * @see simpletest_get_all_tests. + */ +function simpletest_categorize_tests($tests) { + $groups = array(); + foreach ($tests as $test => $instance) { + $info = $instance->getInfo(); + $groups[$info['group']][$test] = $instance; + } + return $groups; } /** @@ -324,13 +502,16 @@ function simpletest_get_like_tables($base_table = 'simpletest', $count = FALSE) $database = substr($url['path'], 1); $select = $count ? 'COUNT(table_name)' : 'table_name'; $result = db_query("SELECT $select FROM information_schema.tables WHERE table_schema = '$database' AND table_name LIKE '$db_prefix$base_table%'"); + $schema = drupal_get_schema_unprocessed('simpletest'); if ($count) { return db_result($result); } $tables = array(); while ($table = db_result($result)) { - $tables[] = $table; + if (!isset($schema[$table])) { + $tables[] = $table; + } } return $tables; } @@ -378,65 +559,6 @@ function simpletest_clean_temporary_directory($path) { rmdir($path); } -/** - * Actually runs tests - * @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') { - static $test_running; - if (!$test_running) { - $test_running = TRUE; - $test = simpletest_get_total_test($test_list); - switch ($reporter) { - case 'text': - $reporter = &new TextReporter(); - break; - case 'xml': - $reporter = &new XMLReporter(); - break; - case 'html': - $reporter = &new HtmlReporter(); - break; - case 'drupal': - $reporter = &new DrupalReporter(); - break; - } - - 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(); - } - } -} - -/** - * 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 - * @return DrupalTests object - */ -function &simpletest_get_total_test($classes = NULL) { - static $total_test; - if (!$total_test) { - simpletest_load(); - $total_test = &new DrupalTests(); - } - if (!is_null($classes)) { - $dut = new DrupalTests($classes); - return $dut; - } - return $total_test; -} - function simpletest_settings() { $form = array(); @@ -473,5 +595,4 @@ function simpletest_settings() { ); return system_settings_form($form); - } diff --git a/modules/simpletest/simpletest.test b/modules/simpletest/simpletest.test index b3425dd93c7997547fbf5c833ee1ebefa0fc0b25..2da05d6a33c5fd98f2ef7cd3a0aae54cf08ada5e 100644 --- a/modules/simpletest/simpletest.test +++ b/modules/simpletest/simpletest.test @@ -62,7 +62,6 @@ class SimpleTestTestCase extends DrupalWebTestCase { else { // Run this test from web interface. $this->drupalGet('admin/build/testing'); - $this->assertText(t('It is strongly suggested to run the tests with the first user!')); $edit = array(); $edit['SimpleTestTestCase'] = TRUE; @@ -89,11 +88,11 @@ class SimpleTestTestCase extends DrupalWebTestCase { * Confirm that the stub test produced the desired results. */ function confirmStubTestResults() { - $this->assertAssertion($this->pass, '[Other]', 'Pass'); - $this->assertAssertion($this->fail, '[Other]', 'Fail'); + $this->assertAssertion($this->pass, 'Other', 'Pass'); + $this->assertAssertion($this->fail, 'Other', 'Fail'); - $this->assertAssertion(t('Created permissions: @perms', array('@perms' => $this->valid_permission)), '[Role]', 'Pass'); - $this->assertAssertion(t('Invalid permission %permission.', array('%permission' => $this->invalid_permission)), '[Role]', 'Fail'); + $this->assertAssertion(t('Created permissions: @perms', array('@perms' => $this->valid_permission)), 'Role', 'Pass'); + $this->assertAssertion(t('Invalid permission %permission.', array('%permission' => $this->invalid_permission)), 'Role', 'Fail'); } /** @@ -128,16 +127,17 @@ class SimpleTestTestCase extends DrupalWebTestCase { if ($this->parse()) { if ($fieldset = $this->getResultFieldSet()) { // Code assumes this is the only test in group. - $results['summary'] = $this->asText($fieldset->div[1]); + $results['summary'] = $this->asText($fieldset->div); $results['name'] = $this->asText($fieldset->fieldset->legend); $results['assertions'] = array(); - $tbody = $fieldset->fieldset->div[2]->table->tbody; + $tbody = $fieldset->fieldset->table->tbody; foreach ($tbody->tr as $row) { $assertion = array(); $assertion['message'] = $this->asText($row->td[0]); $assertion['type'] = $this->asText($row->td[1]); - $assertion['status'] = $this->asText($row->td[2]); + $ok_url = (url('misc/watchdog-ok.png') == 'misc/watchdog-ok.png') ? 'misc/watchdog-ok.png' : (base_path() . 'misc/watchdog-ok.png'); + $assertion['status'] = ($row->td[5]->img['src'] == $ok_url) ? 'Pass' : 'Fail'; $results['assertions'][] = $assertion; } } @@ -164,10 +164,15 @@ class SimpleTestTestCase extends DrupalWebTestCase { /** * Extract the text contained by the element. * - * @param SimpleXMLElement $element Element to extract text from. - * @return string Extracted text. + * @param $element + * Element to extract text from. + * @return + * Extracted text. */ function asText(SimpleXMLElement $element) { + if (!is_object($element)) { + return $this->fail('The element is not an element.'); + } return trim(strip_tags($element->asXML())); } diff --git a/scripts/run-tests.sh b/scripts/run-tests.sh index 245f3b39509671601cf1d29bea0c45cfd944537c..996c50ff347118fa45ca477d86643305daf22a78 100755 --- a/scripts/run-tests.sh +++ b/scripts/run-tests.sh @@ -1,4 +1,4 @@ -#!/usr/bin/php +#!/Applications/MAMP/bin/php5/bin/php <?php // $Id$ @@ -37,9 +37,6 @@ need this parameter if Drupal is in a subdirectory on your localhost and you have not set \$base_url in settings.php. - --reporter Immediatly preceeds the name of the output reporter to use. This - Defaults to "text", while other options include "xml" and "html". - --all Run all available tests. --class Run tests identified by speficic class names. @@ -67,6 +64,7 @@ $clean = FALSE; $all = FALSE; $class_names = FALSE; +$verbose = FALSE; $test_names = array(); while ($param = array_shift($_SERVER['argv'])) { @@ -89,12 +87,6 @@ case '--clean': $clean = TRUE; break; - case '--reporter': - $reporter = array_shift($_SERVER['argv']); - if (!in_array($reporter, array("text", "xml", "html"))) { - $reporter = "text"; - } - break; default: $test_names += explode(',', $param); break; @@ -116,8 +108,7 @@ drupal_bootstrap(DRUPAL_BOOTSTRAP_FULL); if (!module_exists('simpletest')) { - echo("ERROR: The simpletest module must be enabled before this script can run.\n"); - exit; + die(t('Error: The simpletest module must be enabled before this script can run.') ."\n"); } if ($clean) { @@ -131,34 +122,28 @@ exit; } -// Run tests as user #1. -$GLOBALS['user'] = user_load(1); - -//Load simpletest files -$total_test = &simpletest_get_total_test(); - -$test_instances = $total_test->getTestInstances(); - -if ($list) { - // Display all availabe tests. - echo("Available test groups:\n----------------------\n"); - foreach ($test_instances as $group_test) { - echo($group_test->getLabel() . "\n"); - } - exit; -} +$tests = simpletest_get_all_tests(); +$test_list = array(); if ($all) { - $test_list = NULL; + $test_list = $tests; } -else { - if ($class_names) { - $test_list = _run_tests_check_classes($test_names, $test_instances); +else if ($class_names) { + foreach ($test_names as $test) { + if (isset($tests[$test])) { + $test_list[$test] = $tests[$test]; + } } - else { - $test_list = _run_tests_find_classes($test_names, $test_instances); +} +else { + $groups = simpletest_categorize_tests($tests); + foreach ($test_names as $test) { + if (isset($groups[$test])) { + $test_list += $groups[$test]; + } } } + if (empty($test_list) && !$all) { echo("ERROR: No valid tests were specified.\n"); exit; @@ -171,55 +156,30 @@ } // Tell the user about what tests are to be run. -if (!$all && $reporter == 'text') { +if (!$all) { echo("Tests to be run:\n"); - foreach ($test_list as $name) { - echo("- " . $name . "\n"); + foreach ($test_list as $instance) { + $info = $instance->getInfo(); + echo("- " . $info['name'] . "\n"); } echo("\n"); } -simpletest_run_tests(array_keys($test_list), $reporter); +db_query('INSERT INTO {simpletest_test_id} VALUES (default)'); +$test_id = db_last_insert_id('simpletest_test_id', 'test_id'); -// Utility functions: -/** - * Check that each class name exists as a test, return the list of valid ones. - */ -function _run_tests_check_classes($test_names, $test_instances) { - $test_list = array(); - $test_names = array_flip($test_names); - - foreach ($test_instances as $group_test) { - $tests = $group_test->getTestInstances(); - foreach ($tests as $test) { - $class = get_class($test); - $info = $test->getInfo(); - if (isset($test_names[$class])) { - $test_list[$class] = $info['name']; - } - } - } - return $test_list; -} +$test_results = array('#pass' => 0, '#fail' => 0, '#exception' => 0); -/** - * Check that each group name exists, return the list of class in valid groups. - */ -function _run_tests_find_classes($test_names, &$test_instances) { - $test_list = array(); - $test_names = array_flip($test_names); - - uasort($test_instances, 'simpletest_compare_instances'); - foreach ($test_instances as $group_test) { - $group = $group_test->getLabel(); - if (isset($test_names[$group])) { - $tests = $group_test->getTestInstances(); - foreach ($tests as $test) { - $info = $test->getInfo(); - $test_list[get_class($test)] = $info['name']; - } - } +foreach ($test_list as $class => $instance) { + $instance = new $class($test_id); + $instance->run(); + $info = $instance->getInfo(); + $test_results[$class] = $instance->_results; + foreach ($test_results[$class] as $key => $value) { + $test_results[$key] += $value; } - return $test_list; + echo(t('@name: @summary', array('@name' => $info['name'], '@summary' => _simpletest_format_summary_line($test_results[$class]))) . "\n"); } +echo(_simpletest_format_summary_line($test_results) . "\n"); +