diff options
Diffstat (limited to 'modules/simpletest/tests')
40 files changed, 1078 insertions, 81 deletions
diff --git a/modules/simpletest/tests/ajax.test b/modules/simpletest/tests/ajax.test index 957979249..9a76b9692 100644 --- a/modules/simpletest/tests/ajax.test +++ b/modules/simpletest/tests/ajax.test @@ -116,6 +116,64 @@ class AJAXFrameworkTestCase extends AJAXTestCase { ); $this->assertCommand($commands, $expected, t('Custom error message is output.')); } + + /** + * Test that new JavaScript and CSS files added during an AJAX request are returned. + */ + function testLazyLoad() { + $expected = array( + 'setting_name' => 'ajax_forms_test_lazy_load_form_submit', + 'setting_value' => 'executed', + 'css' => drupal_get_path('module', 'system') . '/system.admin.css', + 'js' => drupal_get_path('module', 'system') . '/system.js', + ); + + // Get the base page. + $this->drupalGet('ajax_forms_test_lazy_load_form'); + $original_settings = $this->drupalGetSettings(); + $original_css = $original_settings['ajaxPageState']['css']; + $original_js = $original_settings['ajaxPageState']['js']; + + // Verify that the base page doesn't have the settings and files that are to + // be lazy loaded as part of the next request. + $this->assertTrue(!isset($original_settings[$expected['setting_name']]), t('Page originally lacks the %setting, as expected.', array('%setting' => $expected['setting_name']))); + $this->assertTrue(!isset($original_settings[$expected['css']]), t('Page originally lacks the %css file, as expected.', array('%css' => $expected['css']))); + $this->assertTrue(!isset($original_settings[$expected['js']]), t('Page originally lacks the %js file, as expected.', array('%js' => $expected['js']))); + + // Submit the AJAX request. + $commands = $this->drupalPostAJAX(NULL, array(), array('op' => t('Submit'))); + $new_settings = $this->drupalGetSettings(); + $new_css = $new_settings['ajaxPageState']['css']; + $new_js = $new_settings['ajaxPageState']['js']; + + // Verify the expected setting was added. + $this->assertIdentical($new_settings[$expected['setting_name']], $expected['setting_value'], t('Page now has the %setting.', array('%setting' => $expected['setting_name']))); + + // Verify the expected CSS file was added, both to Drupal.settings, and as + // an AJAX command for inclusion into the HTML. + // @todo A drupal_css_defaults() function in Drupal 8 would be nice. + $expected_css_html = drupal_get_css(array($expected['css'] => array( + 'type' => 'file', + 'group' => CSS_DEFAULT, + 'weight' => 0, + 'every_page' => FALSE, + 'media' => 'all', + 'preprocess' => TRUE, + 'data' => $expected['css'], + 'browsers' => array('IE' => TRUE, '!IE' => TRUE), + )), TRUE); + $this->assertEqual($new_css, $original_css + array($expected['css'] => 1), t('Page state now has the %css file.', array('%css' => $expected['css']))); + $this->assertCommand($commands, array('data' => $expected_css_html), t('Page now has the %css file.', array('%css' => $expected['css']))); + + // Verify the expected JS file was added, both to Drupal.settings, and as + // an AJAX command for inclusion into the HTML. By testing for an exact HTML + // string containing the SCRIPT tag, we also ensure that unexpected + // JavaScript code, such as a jQuery.extend() that would potentially clobber + // rather than properly merge settings, didn't accidentally get added. + $expected_js_html = drupal_get_js('header', array($expected['js'] => drupal_js_defaults($expected['js'])), TRUE); + $this->assertEqual($new_js, $original_js + array($expected['js'] => 1), t('Page state now has the %js file.', array('%js' => $expected['js']))); + $this->assertCommand($commands, array('data' => $expected_js_html), t('Page now has the %js file.', array('%js' => $expected['js']))); + } } /** diff --git a/modules/simpletest/tests/ajax_forms_test.module b/modules/simpletest/tests/ajax_forms_test.module index d38cbbb90..075b005ea 100644 --- a/modules/simpletest/tests/ajax_forms_test.module +++ b/modules/simpletest/tests/ajax_forms_test.module @@ -29,6 +29,12 @@ function ajax_forms_test_menu() { 'page arguments' => array('ajax_forms_test_validation_form'), 'access callback' => TRUE, ); + $items['ajax_forms_test_lazy_load_form'] = array( + 'title' => 'AJAX forms lazy load test', + 'page callback' => 'drupal_get_form', + 'page arguments' => array('ajax_forms_test_lazy_load_form'), + 'access callback' => TRUE, + ); return $items; } @@ -457,3 +463,38 @@ function ajax_forms_test_validation_form_callback($form, $form_state) { drupal_set_message(t("Callback: drivertext=%drivertext, spare_required_field=%spare_required_field", array('%drivertext' => $form_state['values']['drivertext'], '%spare_required_field' => $form_state['values']['spare_required_field']))); return '<div id="message_area">ajax_forms_test_validation_form_callback at ' . date('c') . '</div>'; } + +/** + * Form builder: Builds a form that triggers a simple AJAX callback. + */ +function ajax_forms_test_lazy_load_form($form, &$form_state) { + $form['submit'] = array( + '#type' => 'submit', + '#value' => t('Submit'), + '#ajax' => array( + 'callback' => 'ajax_forms_test_lazy_load_form_ajax', + ), + ); + return $form; +} + +/** + * Form submit handler: Adds JavaScript and CSS that wasn't on the original form. + */ +function ajax_forms_test_lazy_load_form_submit($form, &$form_state) { + drupal_add_js(array('ajax_forms_test_lazy_load_form_submit' => 'executed'), 'setting'); + drupal_add_css(drupal_get_path('module', 'system') . '/system.admin.css'); + drupal_add_js(drupal_get_path('module', 'system') . '/system.js'); + $form_state['rebuild'] = TRUE; +} + +/** + * AJAX callback for the ajax_forms_test_lazy_load_form() form. + * + * This function returns nothing, because all we're interested in testing is + * ajax_render() adding commands for JavaScript and CSS added during the page + * request, such as the ones added in ajax_forms_test_lazy_load_form_submit(). + */ +function ajax_forms_test_lazy_load_form_ajax($form, &$form_state) { + return NULL; +} diff --git a/modules/simpletest/tests/bootstrap.test b/modules/simpletest/tests/bootstrap.test index cb4fe8e2a..014fc9488 100644 --- a/modules/simpletest/tests/bootstrap.test +++ b/modules/simpletest/tests/bootstrap.test @@ -350,8 +350,18 @@ class BootstrapGetFilenameTestCase extends DrupalUnitTestCase { // Retrieving the location of a theme engine. $this->assertIdentical(drupal_get_filename('theme_engine', 'phptemplate'), 'themes/engines/phptemplate/phptemplate.engine', t('Retrieve theme engine location.')); - // Retrieving a file that is definitely not stored in the database. + // Retrieving the location of a profile. Profiles are a special case with + // a fixed location and naming. $this->assertIdentical(drupal_get_filename('profile', 'standard'), 'profiles/standard/standard.profile', t('Retrieve install profile location.')); + + // When a file is not found in the database cache, drupal_get_filename() + // searches several locations on the filesystem, including the DRUPAL_ROOT + // directory. We use the '.script' extension below because this is a + // non-existent filetype that will definitely not exist in the database. + // Since there is already a scripts directory, drupal_get_filename() will + // automatically check there for 'script' files, just as it does for (e.g.) + // 'module' files in modules. + $this->assertIdentical(drupal_get_filename('script', 'test'), 'scripts/test.script', t('Retrieve test script location.')); } } diff --git a/modules/simpletest/tests/common.test b/modules/simpletest/tests/common.test index c266dc3b4..5650d8c01 100644 --- a/modules/simpletest/tests/common.test +++ b/modules/simpletest/tests/common.test @@ -56,6 +56,14 @@ class DrupalAlterTestCase extends DrupalWebTestCase { $this->assertEqual($array_copy, $array_expected, t('First argument to drupal_alter() was altered.')); $this->assertEqual($entity_copy, $entity_expected, t('Second argument to drupal_alter() was altered.')); $this->assertEqual($array2_copy, $array2_expected, t('Third argument to drupal_alter() was altered.')); + + // Verify alteration order when passing an array of types to drupal_alter(). + // common_test_module_implements_alter() places 'block' implementation after + // other modules. + $array_copy = $array; + $array_expected = array('foo' => 'Drupal block theme'); + drupal_alter(array('drupal_alter', 'drupal_alter_foo'), $array_copy); + $this->assertEqual($array_copy, $array_expected, t('hook_TYPE_alter() implementations ran in correct order.')); } } @@ -516,7 +524,7 @@ class CommonSizeTestCase extends DrupalUnitTestCase { /** * Test drupal_explode_tags() and drupal_implode_tags(). */ -class DrupalTagsHandlingTestCase extends DrupalWebTestCase { +class DrupalTagsHandlingTestCase extends DrupalUnitTestCase { var $validTags = array( 'Drupal' => 'Drupal', 'Drupal with some spaces' => 'Drupal with some spaces', @@ -1739,6 +1747,37 @@ class DrupalRenderTestCase extends DrupalWebTestCase { '@type' => var_export($element['#type'], TRUE), ))); } + + /** + * Tests caching of an empty render item. + */ + function testDrupalRenderCache() { + // Force a request via GET. + $request_method = $_SERVER['REQUEST_METHOD']; + $_SERVER['REQUEST_METHOD'] = 'GET'; + // Create an empty element. + $test_element = array( + '#cache' => array( + 'cid' => 'render_cache_test', + ), + '#markup' => '', + ); + + // Render the element and confirm that it goes through the rendering + // process (which will set $element['#printed']). + $element = $test_element; + drupal_render($element); + $this->assertTrue(isset($element['#printed']), t('No cache hit')); + + // Render the element again and confirm that it is retrieved from the cache + // instead (so $element['#printed'] will not be set). + $element = $test_element; + drupal_render($element); + $this->assertFalse(isset($element['#printed']), t('Cache hit')); + + // Restore the previous request method. + $_SERVER['REQUEST_METHOD'] = $request_method; + } } /** @@ -2064,7 +2103,7 @@ class DrupalErrorCollectionUnitTest extends DrupalWebTestCase { function assertError($error, $group, $function, $file, $message = NULL) { $this->assertEqual($error['group'], $group, t("Group was %group", array('%group' => $group))); $this->assertEqual($error['caller']['function'], $function, t("Function was %function", array('%function' => $function))); - $this->assertEqual(basename($error['caller']['file']), $file, t("File was %file", array('%file' => $file))); + $this->assertEqual(drupal_basename($error['caller']['file']), $file, t("File was %file", array('%file' => $file))); if (isset($message)) { $this->assertEqual($error['message'], $message, t("Message was %message", array('%message' => $message))); } @@ -2074,7 +2113,7 @@ class DrupalErrorCollectionUnitTest extends DrupalWebTestCase { /** * Test the drupal_parse_info_file() API function. */ -class ParseInfoFilesTestCase extends DrupalWebTestCase { +class ParseInfoFilesTestCase extends DrupalUnitTestCase { public static function getInfo() { return array( 'name' => 'Parsing .info files', @@ -2333,8 +2372,10 @@ class DrupalJSONTest extends DrupalUnitTestCase { $str .= chr($i); } // Characters that must be escaped. - $html_unsafe = array('<', '>', '&'); - $html_unsafe_escaped = array('\u003c', '\u003e', '\u0026'); + // We check for unescaped " separately. + $html_unsafe = array('<', '>', '\'', '&'); + // The following are the encoded forms of: < > ' & " + $html_unsafe_escaped = array('\u003C', '\u003E', '\u0027', '\u0026', '\u0022'); // Verify there aren't character encoding problems with the source string. $this->assertIdentical(strlen($str), 128, t('A string with the full ASCII table has the correct length.')); @@ -2346,6 +2387,11 @@ class DrupalJSONTest extends DrupalUnitTestCase { $json = drupal_json_encode($str); $this->assertTrue(strlen($json) > strlen($str), t('A JSON encoded string is larger than the source string.')); + // The first and last characters should be ", and no others. + $this->assertTrue($json[0] == '"', t('A JSON encoded string begins with ".')); + $this->assertTrue($json[strlen($json) - 1] == '"', t('A JSON encoded string ends with ".')); + $this->assertTrue(substr_count($json, '"') == 2, t('A JSON encoded string contains exactly two ".')); + // Verify that encoding/decoding is reversible. $json_decoded = drupal_json_decode($json); $this->assertIdentical($str, $json_decoded, t('Encoding a string to JSON and decoding back results in the original string.')); diff --git a/modules/simpletest/tests/common_test.module b/modules/simpletest/tests/common_test.module index c400eaed1..e75b45237 100644 --- a/modules/simpletest/tests/common_test.module +++ b/modules/simpletest/tests/common_test.module @@ -166,6 +166,34 @@ function bartik_drupal_alter_alter(&$data, &$arg2 = NULL, &$arg3 = NULL) { } /** + * Implements hook_TYPE_alter() on behalf of block module. + * + * This is for verifying that drupal_alter(array(TYPE1, TYPE2), ...) allows + * hook_module_implements_alter() to affect the order in which module + * implementations are executed. + */ +function block_drupal_alter_foo_alter(&$data, &$arg2 = NULL, &$arg3 = NULL) { + $data['foo'] .= ' block'; +} + +/** + * Implements hook_module_implements_alter(). + * + * @see block_drupal_alter_foo_alter() + */ +function common_test_module_implements_alter(&$implementations, $hook) { + // For drupal_alter(array('drupal_alter', 'drupal_alter_foo'), ...), make the + // block module implementations run after all the other modules. Note that + // when drupal_alter() is called with an array of types, the first type is + // considered primary and controls the module order. + if ($hook == 'drupal_alter_alter' && isset($implementations['block'])) { + $group = $implementations['block']; + unset($implementations['block']); + $implementations['block'] = $group; + } +} + +/** * Implements hook_theme(). */ function common_test_theme() { diff --git a/modules/simpletest/tests/database_test.test b/modules/simpletest/tests/database_test.test index 87d386aa7..7b15cf3fa 100644 --- a/modules/simpletest/tests/database_test.test +++ b/modules/simpletest/tests/database_test.test @@ -2062,6 +2062,16 @@ class DatabaseSelectComplexTestCase extends DatabaseTestCase { $this->assertEqual($record->$age_field, 27, t('Correct data retrieved.')); } + function testHavingCountQuery() { + $query = db_select('test') + ->extend('PagerDefault') + ->having('age + 1 > 0'); + $query->addField('test', 'age'); + $query->addExpression('age + 1'); + $count = count($query->execute()->fetchCol()); + $this->assertEqual($count, 4, t('Counted the correct number of records.')); + } + /** * Test that countQuery properly removes 'all_fields' statements and * ordering clauses. @@ -3426,35 +3436,89 @@ class DatabaseTransactionTestCase extends DatabaseTestCase { */ function testTransactionWithDdlStatement() { // First, test that a commit works normally, even with DDL statements. - try { - $this->transactionOuterLayer('D', FALSE, TRUE); - - // Because we committed, the inserted rows should both be present. - $saved_age = db_query('SELECT age FROM {test} WHERE name = :name', array(':name' => 'DavidD'))->fetchField(); - $this->assertIdentical($saved_age, '24', t('Can retrieve DavidD row after commit.')); - $saved_age = db_query('SELECT age FROM {test} WHERE name = :name', array(':name' => 'DanielD'))->fetchField(); - $this->assertIdentical($saved_age, '19', t('Can retrieve DanielD row after commit.')); - // The created table should also exist. - $count = db_query('SELECT COUNT(id) FROM {database_test_1}')->fetchField(); - $this->assertIdentical($count, '0', t('Table was successfully created inside a transaction.')); - } - catch (Exception $e) { - $this->fail((string) $e); - } + $transaction = db_transaction(); + $this->insertRow('row'); + $this->executeDDLStatement(); + unset($transaction); + $this->assertRowPresent('row'); - // If we rollback the transaction, an exception might be thrown. - try { - $this->transactionOuterLayer('E', TRUE, TRUE); + // Even in different order. + $this->cleanUp(); + $transaction = db_transaction(); + $this->executeDDLStatement(); + $this->insertRow('row'); + unset($transaction); + $this->assertRowPresent('row'); + + // Even with stacking. + $this->cleanUp(); + $transaction = db_transaction(); + $transaction2 = db_transaction(); + $this->executeDDLStatement(); + unset($transaction2); + $transaction3 = db_transaction(); + $this->insertRow('row'); + unset($transaction3); + unset($transaction); + $this->assertRowPresent('row'); + + // A transaction after a DDL statement should still work the same. + $this->cleanUp(); + $transaction = db_transaction(); + $transaction2 = db_transaction(); + $this->executeDDLStatement(); + unset($transaction2); + $transaction3 = db_transaction(); + $this->insertRow('row'); + $transaction3->rollback(); + unset($transaction3); + unset($transaction); + $this->assertRowAbsent('row'); + + // The behavior of a rollback depends on the type of database server. + if (Database::getConnection()->supportsTransactionalDDL()) { + // For database servers that support transactional DDL, a rollback + // of a transaction including DDL statements should be possible. + $this->cleanUp(); + $transaction = db_transaction(); + $this->insertRow('row'); + $this->executeDDLStatement(); + $transaction->rollback(); + unset($transaction); + $this->assertRowAbsent('row'); - // Because we rolled back, the inserted rows shouldn't be present. - $saved_age = db_query('SELECT age FROM {test} WHERE name = :name', array(':name' => 'DavidE'))->fetchField(); - $this->assertNotIdentical($saved_age, '24', t('Cannot retrieve DavidE row after rollback.')); - $saved_age = db_query('SELECT age FROM {test} WHERE name = :name', array(':name' => 'DanielE'))->fetchField(); - $this->assertNotIdentical($saved_age, '19', t('Cannot retrieve DanielE row after rollback.')); + // Including with stacking. + $this->cleanUp(); + $transaction = db_transaction(); + $transaction2 = db_transaction(); + $this->executeDDLStatement(); + unset($transaction2); + $transaction3 = db_transaction(); + $this->insertRow('row'); + unset($transaction3); + $transaction->rollback(); + unset($transaction); + $this->assertRowAbsent('row'); } - catch (Exception $e) { - // An exception also lets the test pass. - $this->assertTrue(true, t('Exception thrown on rollback after a DDL statement was executed.')); + else { + // For database servers that do not support transactional DDL, + // the DDL statement should commit the transaction stack. + $this->cleanUp(); + $transaction = db_transaction(); + $this->insertRow('row'); + $this->executeDDLStatement(); + // Rollback the outer transaction. + try { + $transaction->rollback(); + unset($transaction); + // @TODO: an exception should be triggered here, but is not, because + // "ROLLBACK" fails silently in MySQL if there is no transaction active. + // $this->fail(t('Rolling back a transaction containing DDL should fail.')); + } + catch (DatabaseTransactionNoActiveException $e) { + $this->pass(t('Rolling back a transaction containing DDL should fail.')); + } + $this->assertRowPresent('row'); } } @@ -3470,6 +3534,24 @@ class DatabaseTransactionTestCase extends DatabaseTestCase { } /** + * Execute a DDL statement. + */ + protected function executeDDLStatement() { + static $count = 0; + $table = array( + 'fields' => array( + 'id' => array( + 'type' => 'serial', + 'unsigned' => TRUE, + 'not null' => TRUE, + ), + ), + 'primary key' => array('id'), + ); + db_create_table('database_test_' . ++$count, $table); + } + + /** * Start over for a new test. */ protected function cleanUp() { @@ -3513,8 +3595,8 @@ class DatabaseTransactionTestCase extends DatabaseTestCase { * Test transaction stacking and commit / rollback. */ function testTransactionStacking() { - // This test won't work right if transactions are supported. - if (Database::getConnection()->supportsTransactions()) { + // This test won't work right if transactions are not supported. + if (!Database::getConnection()->supportsTransactions()) { return; } @@ -3593,26 +3675,33 @@ class DatabaseTransactionTestCase extends DatabaseTestCase { $this->insertRow('outer'); $transaction2 = db_transaction(); $this->insertRow('inner'); + $transaction3 = db_transaction(); + $this->insertRow('inner2'); // Rollback the outer transaction. try { $transaction->rollback(); unset($transaction); $this->fail(t('Rolling back the outer transaction while the inner transaction is active resulted in an exception.')); } - catch (Exception $e) { + catch (DatabaseTransactionOutOfOrderException $e) { $this->pass(t('Rolling back the outer transaction while the inner transaction is active resulted in an exception.')); } $this->assertFalse($database->inTransaction(), t('No more in a transaction after rolling back the outer transaction')); - // Try to commit the inner transaction. + // Try to commit one inner transaction. + unset($transaction3); + $this->pass(t('Trying to commit an inner transaction resulted in an exception.')); + // Try to rollback one inner transaction. try { + $transaction->rollback(); unset($transaction2); - $this->fail(t('Trying to commit the inner transaction resulted in an exception.')); + $this->fail(t('Trying to commit an inner transaction resulted in an exception.')); } - catch (Exception $e) { - $this->pass(t('Trying to commit the inner transaction resulted in an exception.')); + catch (DatabaseTransactionNoActiveException $e) { + $this->pass(t('Trying to commit an inner transaction resulted in an exception.')); } $this->assertRowAbsent('outer'); $this->assertRowAbsent('inner'); + $this->assertRowAbsent('inner2'); } } diff --git a/modules/simpletest/tests/entity_cache_test_dependency.module b/modules/simpletest/tests/entity_cache_test_dependency.module index 73a11495f..2d4b3be4d 100644 --- a/modules/simpletest/tests/entity_cache_test_dependency.module +++ b/modules/simpletest/tests/entity_cache_test_dependency.module @@ -11,7 +11,7 @@ function entity_cache_test_dependency_entity_info() { return array( 'entity_cache_test' => array( - 'label' => 'Entity Cache Test', + 'label' => variable_get('entity_cache_test_label', 'Entity Cache Test'), ), ); } diff --git a/modules/simpletest/tests/entity_query.test b/modules/simpletest/tests/entity_query.test index ec951f8e2..d5e5524f2 100644 --- a/modules/simpletest/tests/entity_query.test +++ b/modules/simpletest/tests/entity_query.test @@ -22,10 +22,10 @@ class EntityFieldQueryTestCase extends DrupalWebTestCase { function setUp() { parent::setUp(array('field_test')); - field_attach_create_bundle('test_entity_bundle_key', 'bundle1'); - field_attach_create_bundle('test_entity_bundle_key', 'bundle2'); - field_attach_create_bundle('test_entity', 'test_bundles'); - field_attach_create_bundle('test_entity_bundle', 'test_entity_bundle'); + field_test_create_bundle('bundle1'); + field_test_create_bundle('bundle2'); + field_test_create_bundle('test_bundle'); + field_test_create_bundle('test_entity_bundle'); $instances = array(); $this->fields = array(); @@ -1084,7 +1084,6 @@ class EntityFieldQueryTestCase extends DrupalWebTestCase { $this->fields[0]['cardinality'] = 1; field_update_field($this->fields[0]); field_test_entity_info_translatable('test_entity', TRUE); - drupal_static_reset('field_available_languages'); // Create more items with different languages. $entity = new stdClass(); @@ -1121,7 +1120,6 @@ class EntityFieldQueryTestCase extends DrupalWebTestCase { $this->fields[0]['translatable'] = TRUE; field_update_field($this->fields[0]); field_test_entity_info_translatable('test_entity', TRUE); - drupal_static_reset('field_available_languages'); // Create more items with different languages. $entity = new stdClass(); diff --git a/modules/simpletest/tests/file.test b/modules/simpletest/tests/file.test index 55e3b0aa3..4c56bfcce 100644 --- a/modules/simpletest/tests/file.test +++ b/modules/simpletest/tests/file.test @@ -198,7 +198,9 @@ class FileTestCase extends DrupalWebTestCase { */ function createFile($filepath = NULL, $contents = NULL, $scheme = NULL) { if (!isset($filepath)) { - $filepath = $this->randomName(); + // Prefix with non-latin characters to ensure that all file-related + // tests work with international filenames. + $filepath = 'Файл для тестирования ' . $this->randomName(); } if (!isset($scheme)) { $scheme = file_default_scheme(); @@ -214,7 +216,7 @@ class FileTestCase extends DrupalWebTestCase { $file = new stdClass(); $file->uri = $filepath; - $file->filename = basename($file->uri); + $file->filename = drupal_basename($file->uri); $file->filemime = 'text/plain'; $file->uid = 1; $file->timestamp = REQUEST_TIME; @@ -372,11 +374,11 @@ class FileValidatorTest extends DrupalWebTestCase { $this->image = new stdClass(); $this->image->uri = 'misc/druplicon.png'; - $this->image->filename = basename($this->image->uri); + $this->image->filename = drupal_basename($this->image->uri); $this->non_image = new stdClass(); $this->non_image->uri = 'misc/jquery.js'; - $this->non_image->filename = basename($this->non_image->uri); + $this->non_image->filename = drupal_basename($this->non_image->uri); } /** @@ -539,7 +541,7 @@ class FileUnmanagedSaveDataTest extends FileTestCase { // Provide a filename. $filepath = file_unmanaged_save_data($contents, 'public://asdf.txt', FILE_EXISTS_REPLACE); $this->assertTrue($filepath, t('Unnamed file saved correctly.')); - $this->assertEqual('asdf.txt', basename($filepath), t('File was named correctly.')); + $this->assertEqual('asdf.txt', drupal_basename($filepath), t('File was named correctly.')); $this->assertEqual($contents, file_get_contents($filepath), t('Contents of the file are correct.')); $this->assertFilePermissions($filepath, variable_get('file_chmod_file', 0664)); } @@ -666,7 +668,7 @@ class FileSaveUploadTest extends FileHookTestCase { $this->drupalPost('file-test/upload', $edit, t('Submit')); $this->assertResponse(200, t('Received a 200 response for posted test file.')); $this->assertRaw(t('You WIN!')); - $this->assertTrue(is_file('temporary://' . $dir . '/' . trim(basename($image3_realpath)))); + $this->assertTrue(is_file('temporary://' . $dir . '/' . trim(drupal_basename($image3_realpath)))); // Check that file_load_multiple() with no arguments returns FALSE. $this->assertFalse(file_load_multiple(), t('No files were loaded.')); @@ -2202,7 +2204,7 @@ class FileSaveDataTest extends FileHookTestCase { $this->assertTrue($result, t('Unnamed file saved correctly.')); $this->assertEqual(file_default_scheme(), file_uri_scheme($result->uri), t("File was placed in Drupal's files directory.")); - $this->assertEqual($result->filename, basename($result->uri), t("Filename was set to the file's basename.")); + $this->assertEqual($result->filename, drupal_basename($result->uri), t("Filename was set to the file's basename.")); $this->assertEqual($contents, file_get_contents($result->uri), t('Contents of the file are correct.')); $this->assertEqual($result->filemime, 'application/octet-stream', t('A MIME type was set.')); $this->assertEqual($result->status, FILE_STATUS_PERMANENT, t("The file's status was set to permanent.")); @@ -2220,11 +2222,14 @@ class FileSaveDataTest extends FileHookTestCase { function testWithFilename() { $contents = $this->randomName(8); - $result = file_save_data($contents, 'public://' . 'asdf.txt'); + // Using filename with non-latin characters. + $filename = 'Текстовый файл.txt'; + + $result = file_save_data($contents, 'public://' . $filename); $this->assertTrue($result, t('Unnamed file saved correctly.')); $this->assertEqual('public', file_uri_scheme($result->uri), t("File was placed in Drupal's files directory.")); - $this->assertEqual('asdf.txt', basename($result->uri), t('File was named correctly.')); + $this->assertEqual($filename, drupal_basename($result->uri), t('File was named correctly.')); $this->assertEqual($contents, file_get_contents($result->uri), t('Contents of the file are correct.')); $this->assertEqual($result->filemime, 'text/plain', t('A MIME type was set.')); $this->assertEqual($result->status, FILE_STATUS_PERMANENT, t("The file's status was set to permanent.")); @@ -2336,7 +2341,10 @@ class FileDownloadTest extends FileTestCase { // Test generating an URL to a created file. $file = $this->createFile(); $url = file_create_url($file->uri); - $this->assertEqual($GLOBALS['base_url'] . '/' . file_stream_wrapper_get_instance_by_scheme('public')->getDirectoryPath() . '/' . $file->filename, $url, t('Correctly generated a URL for a created file.')); + // URLs can't contain characters outside the ASCII set so $filename has to be + // encoded. + $filename = $GLOBALS['base_url'] . '/' . file_stream_wrapper_get_instance_by_scheme('public')->getDirectoryPath() . '/' . rawurlencode($file->filename); + $this->assertEqual($filename, $url, t('Correctly generated a URL for a created file.')); $this->drupalHead($url); $this->assertResponse(200, t('Confirmed that the generated URL is correct by downloading the created file.')); @@ -2356,16 +2364,20 @@ class FileDownloadTest extends FileTestCase { // Set file downloads to private so handler functions get called. // Create a file. - $file = $this->createFile(NULL, NULL, 'private'); + $contents = $this->randomName(8); + $file = $this->createFile(NULL, $contents, 'private'); $url = file_create_url($file->uri); // Set file_test access header to allow the download. file_test_set_return('download', array('x-foo' => 'Bar')); - $this->drupalHead($url); + $this->drupalGet($url); $headers = $this->drupalGetHeaders(); - $this->assertEqual($headers['x-foo'] , 'Bar', t('Found header set by file_test module on private download.')); + $this->assertEqual($headers['x-foo'], 'Bar', t('Found header set by file_test module on private download.')); $this->assertResponse(200, t('Correctly allowed access to a file when file_test provides headers.')); + // Test that the file transfered correctly. + $this->assertEqual($contents, $this->content, t('Contents of the file are correct.')); + // Deny access to all downloads via a -1 header. file_test_set_return('download', -1); $this->drupalHead($url); @@ -2602,7 +2614,7 @@ class FileMimeTypeTest extends DrupalWebTestCase { * Test mapping of mimetypes from filenames. */ public function testFileMimeTypeDetection() { - $prefix = 'simpletest://'; + $prefix = 'public://'; $test_case = array( 'test.jar' => 'application/java-archive', diff --git a/modules/simpletest/tests/file_test.module b/modules/simpletest/tests/file_test.module index b3c43e071..1b11316f9 100644 --- a/modules/simpletest/tests/file_test.module +++ b/modules/simpletest/tests/file_test.module @@ -138,7 +138,7 @@ function _file_test_form_submit(&$form, &$form_state) { /** * Reset/initialize the history of calls to the file_* hooks. * - * @see file_test_get_calls() + * @see file_test_get_calls() * @see file_test_reset() */ function file_test_reset() { diff --git a/modules/simpletest/tests/form.test b/modules/simpletest/tests/form.test index fe2c1bbfb..13fdca201 100644 --- a/modules/simpletest/tests/form.test +++ b/modules/simpletest/tests/form.test @@ -588,9 +588,17 @@ class FormsElementsLabelsTestCase extends DrupalWebTestCase { $elements = $this->xpath('//input[@id="edit-form-checkboxes-test-third-checkbox"]/following-sibling::label[@for="edit-form-checkboxes-test-third-checkbox" and @class="option"]'); $this->assertTrue(isset($elements[0]), t("Label follows field and label option class correct for regular checkboxes.")); + // Make sure the label is rendered for checkboxes. + $elements = $this->xpath('//input[@id="edit-form-checkboxes-test-0"]/following-sibling::label[@for="edit-form-checkboxes-test-0" and @class="option"]'); + $this->assertTrue(isset($elements[0]), t("Label 0 found checkbox.")); + $elements = $this->xpath('//input[@id="edit-form-radios-test-second-radio"]/following-sibling::label[@for="edit-form-radios-test-second-radio" and @class="option"]'); $this->assertTrue(isset($elements[0]), t("Label follows field and label option class correct for regular radios.")); + // Make sure the label is rendered for radios. + $elements = $this->xpath('//input[@id="edit-form-radios-test-0"]/following-sibling::label[@for="edit-form-radios-test-0" and @class="option"]'); + $this->assertTrue(isset($elements[0]), t("Label 0 found radios.")); + // Exercise various defaults for checkboxes and modifications to ensure // appropriate override and correct behaviour. $elements = $this->xpath('//input[@id="edit-form-checkbox-test"]/following-sibling::label[@for="edit-form-checkbox-test" and @class="option"]'); diff --git a/modules/simpletest/tests/form_test.module b/modules/simpletest/tests/form_test.module index 23aca244b..0a748d2df 100644 --- a/modules/simpletest/tests/form_test.module +++ b/modules/simpletest/tests/form_test.module @@ -688,6 +688,7 @@ function form_label_test_form() { 'first-checkbox' => t('First checkbox'), 'second-checkbox' => t('Second checkbox'), 'third-checkbox' => t('Third checkbox'), + '0' => t('0'), ), ); $form['form_radios_test'] = array( @@ -697,6 +698,7 @@ function form_label_test_form() { 'first-radio' => t('First radio'), 'second-radio' => t('Second radio'), 'third-radio' => t('Third radio'), + '0' => t('0'), ), // Test #field_prefix and #field_suffix placement. '#field_prefix' => '<span id="form-test-radios-field-prefix">' . t('Radios #field_prefix element') . '</span>', diff --git a/modules/simpletest/tests/mail.test b/modules/simpletest/tests/mail.test index a6c7b40e5..09dcde60c 100644 --- a/modules/simpletest/tests/mail.test +++ b/modules/simpletest/tests/mail.test @@ -22,7 +22,7 @@ class MailTestCase extends DrupalWebTestCase implements MailSystemInterface { } function setUp() { - parent::setUp(); + parent::setUp(array('simpletest')); // Set MailTestCase (i.e. this class) as the SMTP library variable_set('mail_system', array('default-system' => 'MailTestCase')); @@ -35,10 +35,28 @@ class MailTestCase extends DrupalWebTestCase implements MailSystemInterface { global $language; // Use MailTestCase for sending a message. - $message = drupal_mail('simpletest', 'mail_test', 'testing@drupal.org', $language); + $message = drupal_mail('simpletest', 'mail_test', 'testing@example.com', $language); // Assert whether the message was sent through the send function. - $this->assertEqual(self::$sent_message['to'], 'testing@drupal.org', t('Pluggable mail system is extendable.')); + $this->assertEqual(self::$sent_message['to'], 'testing@example.com', t('Pluggable mail system is extendable.')); + } + + /** + * Test that message sending may be canceled. + * + * @see simpletest_mail_alter() + */ + function testCancelMessage() { + global $language; + + // Reset the class variable holding a copy of the last sent message. + self::$sent_message = NULL; + + // Send a test message that simpletest_mail_alter should cancel. + $message = drupal_mail('simpletest', 'cancel_test', 'cancel@example.com', $language); + + // Assert that the message was not actually sent. + $this->assertNull(self::$sent_message, 'Message was canceled.'); } /** diff --git a/modules/simpletest/tests/path.test b/modules/simpletest/tests/path.test index 4998ffa38..8b3e6dc48 100644 --- a/modules/simpletest/tests/path.test +++ b/modules/simpletest/tests/path.test @@ -201,6 +201,14 @@ class UrlAlterFunctionalTest extends DrupalWebTestCase { } /** + * Tests that $_GET['q'] is initialized when the request path is empty. + */ + function testGetQInitialized() { + $this->drupalGet(''); + $this->assertText("\$_GET['q'] is non-empty with an empty request path.", "\$_GET['q'] is initialized with an empty request path."); + } + + /** * Assert that an outbound path is altered to an expected value. * * @param $original diff --git a/modules/simpletest/tests/system_incompatible_core_version_dependencies_test.info b/modules/simpletest/tests/system_incompatible_core_version_dependencies_test.info new file mode 100644 index 000000000..002c0d286 --- /dev/null +++ b/modules/simpletest/tests/system_incompatible_core_version_dependencies_test.info @@ -0,0 +1,7 @@ +name = "System incompatible core version dependencies test" +description = "Support module for testing system dependencies." +package = Testing +version = VERSION +core = 7.x +hidden = TRUE +dependencies[] = system_incompatible_core_version_test diff --git a/modules/simpletest/tests/system_incompatible_core_version_dependencies_test.module b/modules/simpletest/tests/system_incompatible_core_version_dependencies_test.module new file mode 100644 index 000000000..b3d9bbc7f --- /dev/null +++ b/modules/simpletest/tests/system_incompatible_core_version_dependencies_test.module @@ -0,0 +1 @@ +<?php diff --git a/modules/simpletest/tests/system_incompatible_core_version_test.info b/modules/simpletest/tests/system_incompatible_core_version_test.info new file mode 100644 index 000000000..ced53e9d5 --- /dev/null +++ b/modules/simpletest/tests/system_incompatible_core_version_test.info @@ -0,0 +1,6 @@ +name = "System incompatible core version test" +description = "Support module for testing system dependencies." +package = Testing +version = VERSION +core = 5.x +hidden = TRUE diff --git a/modules/simpletest/tests/system_incompatible_core_version_test.module b/modules/simpletest/tests/system_incompatible_core_version_test.module new file mode 100644 index 000000000..b3d9bbc7f --- /dev/null +++ b/modules/simpletest/tests/system_incompatible_core_version_test.module @@ -0,0 +1 @@ +<?php diff --git a/modules/simpletest/tests/system_incompatible_module_version_dependencies_test.info b/modules/simpletest/tests/system_incompatible_module_version_dependencies_test.info new file mode 100644 index 000000000..48db9eae3 --- /dev/null +++ b/modules/simpletest/tests/system_incompatible_module_version_dependencies_test.info @@ -0,0 +1,8 @@ +name = "System incompatible module version dependencies test" +description = "Support module for testing system dependencies." +package = Testing +version = VERSION +core = 7.x +hidden = TRUE +; system_incompatible_module_version_test declares version 1.0 +dependencies[] = system_incompatible_module_version_test (>2.0) diff --git a/modules/simpletest/tests/system_incompatible_module_version_dependencies_test.module b/modules/simpletest/tests/system_incompatible_module_version_dependencies_test.module new file mode 100644 index 000000000..b3d9bbc7f --- /dev/null +++ b/modules/simpletest/tests/system_incompatible_module_version_dependencies_test.module @@ -0,0 +1 @@ +<?php diff --git a/modules/simpletest/tests/system_incompatible_module_version_test.info b/modules/simpletest/tests/system_incompatible_module_version_test.info new file mode 100644 index 000000000..9dfc686cf --- /dev/null +++ b/modules/simpletest/tests/system_incompatible_module_version_test.info @@ -0,0 +1,6 @@ +name = "System incompatible module version test" +description = "Support module for testing system dependencies." +package = Testing +version = 1.0 +core = 7.x +hidden = TRUE diff --git a/modules/simpletest/tests/system_incompatible_module_version_test.module b/modules/simpletest/tests/system_incompatible_module_version_test.module new file mode 100644 index 000000000..b3d9bbc7f --- /dev/null +++ b/modules/simpletest/tests/system_incompatible_module_version_test.module @@ -0,0 +1 @@ +<?php diff --git a/modules/simpletest/tests/system_test.module b/modules/simpletest/tests/system_test.module index 9516c9183..8cb0e837f 100644 --- a/modules/simpletest/tests/system_test.module +++ b/modules/simpletest/tests/system_test.module @@ -264,6 +264,14 @@ function system_test_system_info_alter(&$info, $file, $type) { if ($file->name == 'system_dependencies_test') { $info['hidden'] = FALSE; } + if (in_array($file->name, array( + 'system_incompatible_module_version_dependencies_test', + 'system_incompatible_core_version_dependencies_test', + 'system_incompatible_module_version_test', + 'system_incompatible_core_version_test', + ))) { + $info['hidden'] = FALSE; + } if ($file->name == 'requirements1_test' || $file->name == 'requirements2_test') { $info['hidden'] = FALSE; } diff --git a/modules/simpletest/tests/theme.test b/modules/simpletest/tests/theme.test index 53557e361..af1141124 100644 --- a/modules/simpletest/tests/theme.test +++ b/modules/simpletest/tests/theme.test @@ -9,6 +9,8 @@ * Unit tests for the Theme API. */ class ThemeUnitTest extends DrupalWebTestCase { + protected $profile = 'testing'; + public static function getInfo() { return array( 'name' => 'Theme API', @@ -194,7 +196,7 @@ class ThemeItemListUnitTest extends DrupalWebTestCase { /** * Unit tests for theme_links(). */ -class ThemeLinksUnitTest extends DrupalUnitTestCase { +class ThemeLinksTest extends DrupalWebTestCase { public static function getInfo() { return array( 'name' => 'Links', @@ -380,3 +382,54 @@ class ThemeHtmlTag extends DrupalUnitTestCase { $this->assertEqual('<title>title test</title>'."\n", theme_html_tag($tag), t('Test title tag generation.')); } } + +/** + * Tests for the ThemeRegistry class. + */ +class ThemeRegistryTestCase extends DrupalWebTestCase { + public static function getInfo() { + return array( + 'name' => 'ThemeRegistry', + 'description' => 'Tests the behavior of the ThemeRegistry class', + 'group' => 'Theme', + ); + } + function setUp() { + parent::setUp('theme_test'); + } + + /** + * Tests the behavior of the theme registry class. + */ + function testRaceCondition() { + $_SERVER['REQUEST_METHOD'] = 'GET'; + $cid = 'test_theme_registry'; + + // Directly instantiate the theme registry, this will cause a base cache + // entry to be written in __construct(). + $registry = new ThemeRegistry($cid, 'cache'); + + $this->assertTrue(cache_get($cid), 'Cache entry was created.'); + + // Trigger a cache miss for an offset. + $this->assertTrue($registry['theme_test_template_test'], 'Offset was returned correctly from the theme registry.'); + // This will cause the ThemeRegistry class to write an updated version of + // the cache entry when it is destroyed, usually at the end of the request. + // Before that happens, manually delete the cache entry we created earlier + // so that the new entry is written from scratch. + cache_clear_all($cid, 'cache'); + + // Destroy the class so that it triggers a cache write for the offset. + unset($registry); + + $this->assertTrue(cache_get($cid), 'Cache entry was created.'); + + // Create a new instance of the class. Confirm that both the offset + // requested previously, and one that has not yet been requested are both + // available. + $registry = new ThemeRegistry($cid, 'cache'); + + $this->assertTrue($registry['theme_test_template_test'], 'Offset was returned correctly from the theme registry'); + $this->assertTrue($registry['theme_test_template_test_2'], 'Offset was returned correctly from the theme registry'); + } +} diff --git a/modules/simpletest/tests/theme_test.module b/modules/simpletest/tests/theme_test.module index 160d192dd..48e2e83c6 100644 --- a/modules/simpletest/tests/theme_test.module +++ b/modules/simpletest/tests/theme_test.module @@ -1,6 +1,28 @@ <?php /** + * Implements hook_theme(). + */ +function theme_test_theme($existing, $type, $theme, $path) { + $items['theme_test_template_test'] = array( + 'template' => 'theme_test.template_test', + ); + $items['theme_test_template_test_2'] = array( + 'template' => 'theme_test.template_test', + ); + + return $items; +} + +/** + * Implements hook_system_theme_info(). + */ +function theme_test_system_theme_info() { + $themes['test_theme'] = drupal_get_path('module', 'theme_test') . '/themes/test_theme/test_theme.info'; + return $themes; +} + +/** * Implements hook_menu(). */ function theme_test_menu() { diff --git a/modules/simpletest/tests/theme_test.template_test.tpl.php b/modules/simpletest/tests/theme_test.template_test.tpl.php new file mode 100644 index 000000000..cde8faadd --- /dev/null +++ b/modules/simpletest/tests/theme_test.template_test.tpl.php @@ -0,0 +1,2 @@ +<!-- Output for Theme API test --> +Fail: Template not overridden. diff --git a/modules/simpletest/tests/themes/test_theme/template.php b/modules/simpletest/tests/themes/test_theme/template.php new file mode 100644 index 000000000..ef8118a6d --- /dev/null +++ b/modules/simpletest/tests/themes/test_theme/template.php @@ -0,0 +1,21 @@ +<?php + +/** + * Tests a theme overriding a suggestion of a base theme hook. + */ +function test_theme_breadcrumb__suggestion($variables) { + // Tests that preprocess functions for the base theme hook get called even + // when the suggestion has an implementation. + return 'test_theme_breadcrumb__suggestion: ' . $variables['theme_test_preprocess_breadcrumb']; +} + +/** + * Tests a theme implementing an alter hook. + * + * The confusing function name here is due to this being an implementation of + * the alter hook invoked when the 'theme_test' module calls + * drupal_alter('theme_test_alter'). + */ +function test_theme_theme_test_alter_alter(&$data) { + $data = 'test_theme_theme_test_alter_alter was invoked'; +} diff --git a/modules/simpletest/tests/themes/test_theme/test_theme.info b/modules/simpletest/tests/themes/test_theme/test_theme.info new file mode 100644 index 000000000..dd5584b0b --- /dev/null +++ b/modules/simpletest/tests/themes/test_theme/test_theme.info @@ -0,0 +1,16 @@ +name = Test theme +description = Theme for testing the theme system +core = 7.x +hidden = TRUE + +; Normally, themes may list CSS files like this, and if they exist in the theme +; folder, then they get added to the page. If they have the same file name as a +; module CSS file, then the theme's version overrides the module's version, so +; that the module's version is not added to the page. Additionally, a theme may +; have an entry like this one, without having the corresponding CSS file in the +; theme's folder, and in this case, it just stops the module's version from +; being loaded, and does not replace it with an alternate version. We have this +; here in order for a test to ensure that this correctly prevents the module +; version from being loaded, and that errors aren't caused by the lack of this +; file within the theme folder. +stylesheets[all][] = system.base.css diff --git a/modules/simpletest/tests/unicode.test b/modules/simpletest/tests/unicode.test index 47a4938fe..cf7991b6c 100644 --- a/modules/simpletest/tests/unicode.test +++ b/modules/simpletest/tests/unicode.test @@ -8,7 +8,7 @@ /** * Test unicode handling features implemented in unicode.inc. */ -class UnicodeUnitTest extends DrupalWebTestCase { +class UnicodeUnitTest extends DrupalUnitTestCase { /** * Whether to run the extended version of the tests (including non latin1 characters). diff --git a/modules/simpletest/tests/update_script_test.info b/modules/simpletest/tests/update_script_test.info new file mode 100644 index 000000000..be1e3d849 --- /dev/null +++ b/modules/simpletest/tests/update_script_test.info @@ -0,0 +1,6 @@ +name = "Update script test" +description = "Support module for update script testing." +package = Testing +version = VERSION +core = 7.x +hidden = TRUE diff --git a/modules/simpletest/tests/update_script_test.install b/modules/simpletest/tests/update_script_test.install new file mode 100644 index 000000000..6955ef11d --- /dev/null +++ b/modules/simpletest/tests/update_script_test.install @@ -0,0 +1,45 @@ +<?php + +/** + * @file + * Install, update and uninstall functions for the update_script_test module. + */ + +/** + * Implements hook_requirements(). + */ +function update_script_test_requirements($phase) { + $requirements = array(); + + if ($phase == 'update') { + // Set a requirements warning or error when the test requests it. + $requirement_type = variable_get('update_script_test_requirement_type'); + switch ($requirement_type) { + case REQUIREMENT_WARNING: + $requirements['update_script_test'] = array( + 'title' => 'Update script test', + 'value' => 'Warning', + 'description' => 'This is a requirements warning provided by the update_script_test module.', + 'severity' => REQUIREMENT_WARNING, + ); + break; + case REQUIREMENT_ERROR: + $requirements['update_script_test'] = array( + 'title' => 'Update script test', + 'value' => 'Error', + 'description' => 'This is a requirements error provided by the update_script_test module.', + 'severity' => REQUIREMENT_ERROR, + ); + break; + } + } + + return $requirements; +} + +/** + * Dummy update function to run during the tests. + */ +function update_script_test_update_7000() { + return t('The update_script_test_update_7000() update was executed successfully.'); +} diff --git a/modules/simpletest/tests/update_script_test.module b/modules/simpletest/tests/update_script_test.module new file mode 100644 index 000000000..beb5a71ec --- /dev/null +++ b/modules/simpletest/tests/update_script_test.module @@ -0,0 +1,18 @@ +<?php + +/** + * @file + * This file provides testing functionality for update.php. + */ + +/** + * Implements hook_flush_caches(). + * + * This sets a message to confirm that all caches are cleared whenever + * update.php completes. + * + * @see UpdateScriptFunctionalTest::testRequirements() + */ +function update_script_test_flush_caches() { + drupal_set_message(t('hook_flush_caches() invoked for update_script_test.module.')); +} diff --git a/modules/simpletest/tests/upgrade/drupal-6.node_type_broken.database.php b/modules/simpletest/tests/upgrade/drupal-6.node_type_broken.database.php new file mode 100644 index 000000000..1dc1946b3 --- /dev/null +++ b/modules/simpletest/tests/upgrade/drupal-6.node_type_broken.database.php @@ -0,0 +1,34 @@ +<?php +db_insert('comments')->fields(array( + 'cid', + 'pid', + 'nid', + 'uid', + 'subject', + 'comment', + 'hostname', + 'timestamp', + 'status', + 'format', + 'thread', + 'name', + 'mail', + 'homepage', +)) +->values(array( + 'cid' => 1, + 'pid' => 0, + 'nid' => 37, + 'uid' => 3, + 'subject' => 'Comment title 1', + 'comment' => 'Comment body 1 - Comment body 1 - Comment body 1 - Comment body 1 - Comment body 1 - Comment body 1 - Comment body 1 - Comment body 1', + 'hostname' => '127.0.0.1', + 'timestamp' => 1008617630, + 'status' => 0, + 'format' => 1, + 'thread' => '01/', + 'name' => NULL, + 'mail' => NULL, + 'homepage' => '', +)) +->execute(); diff --git a/modules/simpletest/tests/upgrade/drupal-7.bare.minimal.database.php.gz b/modules/simpletest/tests/upgrade/drupal-7.bare.minimal.database.php.gz Binary files differnew file mode 100644 index 000000000..41be271f5 --- /dev/null +++ b/modules/simpletest/tests/upgrade/drupal-7.bare.minimal.database.php.gz diff --git a/modules/simpletest/tests/upgrade/drupal-7.bare.standard_all.database.php.gz b/modules/simpletest/tests/upgrade/drupal-7.bare.standard_all.database.php.gz Binary files differnew file mode 100644 index 000000000..c47ae8783 --- /dev/null +++ b/modules/simpletest/tests/upgrade/drupal-7.bare.standard_all.database.php.gz diff --git a/modules/simpletest/tests/upgrade/drupal-7.filled.minimal.database.php.gz b/modules/simpletest/tests/upgrade/drupal-7.filled.minimal.database.php.gz Binary files differnew file mode 100644 index 000000000..de2dceb17 --- /dev/null +++ b/modules/simpletest/tests/upgrade/drupal-7.filled.minimal.database.php.gz diff --git a/modules/simpletest/tests/upgrade/drupal-7.filled.standard_all.database.php.gz b/modules/simpletest/tests/upgrade/drupal-7.filled.standard_all.database.php.gz Binary files differnew file mode 100644 index 000000000..5cc5690e1 --- /dev/null +++ b/modules/simpletest/tests/upgrade/drupal-7.filled.standard_all.database.php.gz diff --git a/modules/simpletest/tests/upgrade/upgrade.node.test b/modules/simpletest/tests/upgrade/upgrade.node.test index cd44790c7..b49a40b0d 100644 --- a/modules/simpletest/tests/upgrade/upgrade.node.test +++ b/modules/simpletest/tests/upgrade/upgrade.node.test @@ -51,6 +51,38 @@ class NodeBodyUpgradePathTestCase extends UpgradePathTestCase { } /** + * Tests the upgrade path for node disabled node types. + * + * Load a filled installation of Drupal 6 and run the upgrade process on it. + */ +class DisabledNodeTypeTestCase extends UpgradePathTestCase { + public static function getInfo() { + return array( + 'name' => 'Disabled node type upgrade path', + 'description' => 'Disabled node type upgrade path tests.', + 'group' => 'Upgrade path', + ); + } + + public function setUp() { + // Path to the database dump. + $this->databaseDumpFiles = array( + drupal_get_path('module', 'simpletest') . '/tests/upgrade/drupal-6.filled.database.php', + drupal_get_path('module', 'simpletest') . '/tests/upgrade/drupal-6.node_type_broken.database.php', + ); + parent::setUp(); + } + + /** + * Tests a successful upgrade. + */ + public function testDisabledNodeTypeUpgrade() { + $this->assertTrue($this->performUpgrade(), t('The upgrade was completed successfully.')); + $this->assertTrue(field_info_instance('comment', 'comment_body', 'comment_node_broken'), 'Comment body field instance was created for comments attached to the disabled broken node type'); + } +} + +/** * Upgrade test for node type poll. * * Load a bare installation of Drupal 6 and run the upgrade process on it. diff --git a/modules/simpletest/tests/upgrade/upgrade.test b/modules/simpletest/tests/upgrade/upgrade.test index 7f934fe7b..2602b09a2 100644 --- a/modules/simpletest/tests/upgrade/upgrade.test +++ b/modules/simpletest/tests/upgrade/upgrade.test @@ -28,9 +28,60 @@ abstract class UpgradePathTestCase extends DrupalWebTestCase { var $loadedModules = array(); /** + * Flag to indicate whether zlib is installed or not. + */ + var $zlibInstalled = TRUE; + + /** + * Flag to indicate whether there are pending updates or not. + */ + var $pendingUpdates = TRUE; + + /** + * Constructs an UpgradePathTestCase object. + * + * @param $test_id + * (optional) The ID of the test. Tests with the same id are reported + * together. + */ + function __construct($test_id = NULL) { + parent::__construct($test_id); + $this->zlibInstalled = function_exists('gzopen'); + } + + /** + * Prepares the appropriate session for the release of Drupal being upgraded. + */ + protected function prepareD7Session() { + // Generate and set a D6-compatible session cookie. + $this->curlInitialize(); + $sid = drupal_hash_base64(uniqid(mt_rand(), TRUE) . drupal_random_bytes(55)); + $session_name = update_get_d6_session_name(); + curl_setopt($this->curlHandle, CURLOPT_COOKIE, rawurlencode($session_name) . '=' . rawurlencode($sid)); + + // Force our way into the session of the child site. + drupal_save_session(TRUE); + // A session cannot be written without the ssid column which is missing on + // Drupal 6 sites. + db_add_field('sessions', 'ssid', array('description' => "Secure session ID. The value is generated by Drupal's session handlers.", 'type' => 'varchar', 'length' => 128, 'not null' => TRUE, 'default' => '')); + _drupal_session_write($sid, ''); + // Remove the temporarily added ssid column. + db_drop_field('sessions', 'ssid'); + drupal_save_session(FALSE); + } + + /** * Override of DrupalWebTestCase::setUp() specialized for upgrade testing. */ protected function setUp() { + // We are going to set a missing zlib requirement property for usage + // during the performUpgrade() and tearDown() methods. Also set that the + // tests failed. + if (!$this->zlibInstalled) { + parent::setUp(); + return; + } + global $user, $language, $conf; // Load the Update API. @@ -92,7 +143,11 @@ abstract class UpgradePathTestCase extends DrupalWebTestCase { $conf = array(); // Load the database from the portable PHP dump. + // The files may be gzipped. foreach ($this->databaseDumpFiles as $file) { + if (substr($file, -3) == '.gz') { + $file = "compress.zlib://$file"; + } require $file; } @@ -109,26 +164,14 @@ abstract class UpgradePathTestCase extends DrupalWebTestCase { $user = db_query('SELECT * FROM {users} WHERE uid = :uid', array(':uid' => 1))->fetchObject(); // Generate and set a D6-compatible session cookie. - $this->curlInitialize(); - $sid = drupal_hash_base64(uniqid(mt_rand(), TRUE) . drupal_random_bytes(55)); - $session_name = update_get_d6_session_name(); - curl_setopt($this->curlHandle, CURLOPT_COOKIE, rawurlencode($session_name) . '=' . rawurlencode($sid)); - - // Force our way into the session of the child site. - drupal_save_session(TRUE); - // A session cannot be written without the ssid column which is missing on - // Drupal 6 sites. - db_add_field('sessions', 'ssid', array('description' => "Secure session ID. The value is generated by Drupal's session handlers.", 'type' => 'varchar', 'length' => 128, 'not null' => TRUE, 'default' => '')); - _drupal_session_write($sid, ''); - // Remove the temporarily added ssid column. - db_drop_field('sessions', 'ssid'); - drupal_save_session(FALSE); + $this->prepareD7Session(); // Restore necessary variables. $this->variable_set('clean_url', $clean_url_original); $this->variable_set('site_mail', 'simpletest@example.com'); drupal_set_time_limit($this->timeLimit); + $this->setup = TRUE; } /** @@ -137,6 +180,11 @@ abstract class UpgradePathTestCase extends DrupalWebTestCase { protected function tearDown() { global $user, $language; + if (!$this->zlibInstalled) { + parent::tearDown(); + return; + } + // In case a fatal error occurred that was not in the test process read the // log to pick up any fatal errors. simpletest_log_read($this->testId, $this->databasePrefix, get_class($this), TRUE); @@ -231,6 +279,11 @@ abstract class UpgradePathTestCase extends DrupalWebTestCase { * TRUE if the upgrade succeeded, FALSE otherwise. */ protected function performUpgrade($register_errors = TRUE) { + if (!$this->zlibInstalled) { + $this->fail(t('Missing zlib requirement for upgrade tests.')); + return FALSE; + } + $update_url = $GLOBALS['base_url'] . '/update.php'; // Load the first update screen. @@ -245,6 +298,14 @@ abstract class UpgradePathTestCase extends DrupalWebTestCase { return FALSE; } + // The test should pass if there are no pending updates. + $content = $this->drupalGetContent(); + if (strpos($content, t('No pending updates.')) !== FALSE) { + $this->pass(t('No pending updates and therefore no upgrade process to test.')); + $this->pendingUpdates = FALSE; + return TRUE; + } + // Go! $this->drupalPost(NULL, array(), t('Apply pending updates')); if (!$this->assertResponse(200)) { @@ -319,6 +380,26 @@ abstract class UpgradePathTestCase extends DrupalWebTestCase { } /** + * Performs end-to-end point test of the release update path. + */ +abstract class UpdatePathTestCase extends UpgradePathTestCase { + /** + * Overrides UpgradePathTestCase::prepareD7Session(). + */ + protected function prepareD7Session() { + // Generate and set a D7-compatible session cookie. + $this->curlInitialize(); + $sid = drupal_hash_base64(uniqid(mt_rand(), TRUE) . drupal_random_bytes(55)); + curl_setopt($this->curlHandle, CURLOPT_COOKIE, rawurlencode(session_name()) . '=' . rawurlencode($sid)); + + // Force our way into the session of the child site. + drupal_save_session(TRUE); + _drupal_session_write($sid, ''); + drupal_save_session(FALSE); + } +} + +/** * Perform basic upgrade tests. * * Load a bare installation of Drupal 6 and run the upgrade process on it. @@ -351,7 +432,7 @@ class BasicUpgradePath extends UpgradePathTestCase { // Destroy a table that the upgrade process needs. db_drop_table('access'); // Assert that the upgrade fails. - $this->assertFalse($this->performUpgrade(FALSE), t('A failed upgrade should return messages.')); + $this->assertFalse($this->performUpgrade(FALSE) && $this->pendingUpdates, t('A failed upgrade should return messages.')); } /** @@ -408,3 +489,309 @@ class BasicUpgradePath extends UpgradePathTestCase { $this->assertFalse($update_d6, t('The D6 upgrade flag variable has been correctly disabled.')); } } + +/** + * Performs point release update tests on a bare database. + * + * Loads an installation of Drupal 7.0 and runs the update process on it. + * + * The install contains the standard profile (plus all optional) modules + * without any content so that an update from any of the modules under this + * profile installation can be wholly tested. + */ +class BasicStandardUpdatePath extends UpdatePathTestCase { + public static function getInfo() { + return array( + 'name' => 'Basic standard + all profile update path', + 'description' => 'Basic update path tests for a standard profile install with all enabled modules.', + 'group' => 'Upgrade path', + ); + } + + public function setUp() { + // Path to the database dump files. + $this->databaseDumpFiles = array( + drupal_get_path('module', 'simpletest') . '/tests/upgrade/drupal-7.bare.standard_all.database.php.gz', + ); + parent::setUp(); + } + + /** + * Tests a successful point release update. + */ + public function testBasicStandardUpdate() { + $this->assertTrue($this->performUpgrade(), t('The upgrade was completed successfully.')); + + // Hit the frontpage. + $this->drupalGet(''); + $this->assertResponse(200); + + // Verify that we are still logged in. + $this->drupalGet('user'); + $this->clickLink(t('Edit')); + $this->assertEqual($this->getUrl(), url('user/1/edit', array('absolute' => TRUE)), t('We are still logged in as admin at the end of the upgrade.')); + + // Logout and verify that we can login back in with our initial password. + $this->drupalLogout(); + $this->drupalLogin((object) array( + 'uid' => 1, + 'name' => 'admin', + 'pass_raw' => 'admin', + )); + + // The previous login should've triggered a password rehash, so login one + // more time to make sure the new hash is readable. + $this->drupalLogout(); + $this->drupalLogin((object) array( + 'uid' => 1, + 'name' => 'admin', + 'pass_raw' => 'admin', + )); + + // Test that the site name is correctly displayed. + $this->assertText('drupal', t('The site name is correctly displayed.')); + + // Verify that the main admin sections are available. + $this->drupalGet('admin'); + $this->assertText(t('Content')); + $this->assertText(t('Appearance')); + $this->assertText(t('People')); + $this->assertText(t('Configuration')); + $this->assertText(t('Reports')); + $this->assertText(t('Structure')); + $this->assertText(t('Modules')); + + // Confirm that no {menu_links} entry exists for user/autocomplete. + $result = db_query('SELECT COUNT(*) FROM {menu_links} WHERE link_path = :user_autocomplete', array(':user_autocomplete' => 'user/autocomplete'))->fetchField(); + $this->assertFalse($result, t('No {menu_links} entry exists for user/autocomplete')); + } +} + +/** + * Performs point release update tests on a bare database. + * + * Loads an installation of Drupal 7.0 and runs the update process on it. + * + * The install contains the minimal profile modules (without any generated + * content) so that an update from of a site under this profile may be tested. + */ +class BasicMinimalUpdatePath extends UpdatePathTestCase { + public static function getInfo() { + return array( + 'name' => 'Basic minimal profile update path', + 'description' => 'Basic update path tests for a minimal profile install.', + 'group' => 'Upgrade path', + ); + } + + public function setUp() { + // Path to the database dump files. + $this->databaseDumpFiles = array( + drupal_get_path('module', 'simpletest') . '/tests/upgrade/drupal-7.bare.minimal.database.php.gz', + ); + parent::setUp(); + } + + /** + * Tests a successful point release update. + */ + public function testBasicMinimalUpdate() { + $this->assertTrue($this->performUpgrade(), t('The upgrade was completed successfully.')); + + // Hit the frontpage. + $this->drupalGet(''); + $this->assertResponse(200); + + // Verify that we are still logged in. + $this->drupalGet('user'); + $this->clickLink(t('Edit')); + $this->assertEqual($this->getUrl(), url('user/1/edit', array('absolute' => TRUE)), t('We are still logged in as admin at the end of the upgrade.')); + + // Logout and verify that we can login back in with our initial password. + $this->drupalLogout(); + $this->drupalLogin((object) array( + 'uid' => 1, + 'name' => 'admin', + 'pass_raw' => 'admin', + )); + + // The previous login should've triggered a password rehash, so login one + // more time to make sure the new hash is readable. + $this->drupalLogout(); + $this->drupalLogin((object) array( + 'uid' => 1, + 'name' => 'admin', + 'pass_raw' => 'admin', + )); + + // Test that the site name is correctly displayed. + $this->assertText('drupal', t('The site name is correctly displayed.')); + + // Verify that the main admin sections are available. + $this->drupalGet('admin'); + $this->assertText(t('Content')); + $this->assertText(t('Appearance')); + $this->assertText(t('People')); + $this->assertText(t('Configuration')); + $this->assertText(t('Reports')); + $this->assertText(t('Structure')); + $this->assertText(t('Modules')); + + // Confirm that no {menu_links} entry exists for user/autocomplete. + $result = db_query('SELECT COUNT(*) FROM {menu_links} WHERE link_path = :user_autocomplete', array(':user_autocomplete' => 'user/autocomplete'))->fetchField(); + $this->assertFalse($result, t('No {menu_links} entry exists for user/autocomplete')); + } +} + +/** + * Performs point release update tests on a 'filled' database. + * + * Loads an installation of Drupal 7.0 and runs the update process on it. + * + * The install contains the standard profile (plus all optional) modules + * with generated content so that an update from any of the modules under this + * profile installation can be wholly tested. + */ +class FilledStandardUpdatePath extends UpdatePathTestCase { + public static function getInfo() { + return array( + 'name' => 'Basic standard + all profile update path, populated database', + 'description' => 'Basic update path tests for a standard profile install with all enabled modules and a populated database.', + 'group' => 'Upgrade path', + ); + } + + public function setUp() { + // Path to the database dump files. + $this->databaseDumpFiles = array( + drupal_get_path('module', 'simpletest') . '/tests/upgrade/drupal-7.filled.standard_all.database.php.gz', + ); + parent::setUp(); + } + + /** + * Tests a successful point release update. + */ + public function testFilledStandardUpdate() { + $this->assertTrue($this->performUpgrade(), t('The upgrade was completed successfully.')); + + // Hit the frontpage. + $this->drupalGet(''); + $this->assertResponse(200); + + // Verify that we are still logged in. + $this->drupalGet('user'); + $this->clickLink(t('Edit')); + $this->assertEqual($this->getUrl(), url('user/1/edit', array('absolute' => TRUE)), t('We are still logged in as admin at the end of the upgrade.')); + + // Logout and verify that we can login back in with our initial password. + $this->drupalLogout(); + $this->drupalLogin((object) array( + 'uid' => 1, + 'name' => 'admin', + 'pass_raw' => 'admin', + )); + + // The previous login should've triggered a password rehash, so login one + // more time to make sure the new hash is readable. + $this->drupalLogout(); + $this->drupalLogin((object) array( + 'uid' => 1, + 'name' => 'admin', + 'pass_raw' => 'admin', + )); + + // Test that the site name is correctly displayed. + $this->assertText('drupal', t('The site name is correctly displayed.')); + + // Verify that the main admin sections are available. + $this->drupalGet('admin'); + $this->assertText(t('Content')); + $this->assertText(t('Appearance')); + $this->assertText(t('People')); + $this->assertText(t('Configuration')); + $this->assertText(t('Reports')); + $this->assertText(t('Structure')); + $this->assertText(t('Modules')); + + // Confirm that no {menu_links} entry exists for user/autocomplete. + $result = db_query('SELECT COUNT(*) FROM {menu_links} WHERE link_path = :user_autocomplete', array(':user_autocomplete' => 'user/autocomplete'))->fetchField(); + $this->assertFalse($result, t('No {menu_links} entry exists for user/autocomplete')); + } +} + +/** + * Performs point release update tests on a populated database. + * + * Loads an installation of Drupal 7.0 and runs the update process on it. + * + * The install contains the minimal profile modules (along with generated + * content) so that an update from of a site under this profile may be tested. + */ +class FilledMinimalUpdatePath extends UpdatePathTestCase { + public static function getInfo() { + return array( + 'name' => 'Basic minimal profile update path, populated database', + 'description' => 'Basic update path tests for a minimal profile install with a populated database.', + 'group' => 'Upgrade path', + ); + } + + public function setUp() { + // Path to the database dump files. + $this->databaseDumpFiles = array( + drupal_get_path('module', 'simpletest') . '/tests/upgrade/drupal-7.filled.minimal.database.php.gz', + ); + parent::setUp(); + } + + /** + * Tests a successful point release update. + */ + public function testFilledStandardUpdate() { + $this->assertTrue($this->performUpgrade(), t('The upgrade was completed successfully.')); + + // Hit the frontpage. + $this->drupalGet(''); + $this->assertResponse(200); + + // Verify that we are still logged in. + $this->drupalGet('user'); + $this->clickLink(t('Edit')); + $this->assertEqual($this->getUrl(), url('user/1/edit', array('absolute' => TRUE)), t('We are still logged in as admin at the end of the upgrade.')); + + // Logout and verify that we can login back in with our initial password. + $this->drupalLogout(); + $this->drupalLogin((object) array( + 'uid' => 1, + 'name' => 'admin', + 'pass_raw' => 'admin', + )); + + // The previous login should've triggered a password rehash, so login one + // more time to make sure the new hash is readable. + $this->drupalLogout(); + $this->drupalLogin((object) array( + 'uid' => 1, + 'name' => 'admin', + 'pass_raw' => 'admin', + )); + + // Test that the site name is correctly displayed. + $this->assertText('drupal', t('The site name is correctly displayed.')); + + // Verify that the main admin sections are available. + $this->drupalGet('admin'); + $this->assertText(t('Content')); + $this->assertText(t('Appearance')); + $this->assertText(t('People')); + $this->assertText(t('Configuration')); + $this->assertText(t('Reports')); + $this->assertText(t('Structure')); + $this->assertText(t('Modules')); + + // Confirm that no {menu_links} entry exists for user/autocomplete. + $result = db_query('SELECT COUNT(*) FROM {menu_links} WHERE link_path = :user_autocomplete', array(':user_autocomplete' => 'user/autocomplete'))->fetchField(); + $this->assertFalse($result, t('No {menu_links} entry exists for user/autocomplete')); + } +} diff --git a/modules/simpletest/tests/url_alter_test.module b/modules/simpletest/tests/url_alter_test.module index e229ab986..9287ff523 100644 --- a/modules/simpletest/tests/url_alter_test.module +++ b/modules/simpletest/tests/url_alter_test.module @@ -30,6 +30,10 @@ function url_alter_test_foo() { * Implements hook_url_inbound_alter(). */ function url_alter_test_url_inbound_alter(&$path, $original_path, $path_language) { + if (!request_path() && !empty($_GET['q'])) { + drupal_set_message("\$_GET['q'] is non-empty with an empty request path."); + } + // Rewrite user/username to user/uid. if (preg_match('!^user/([^/]+)(/.*)?!', $path, $matches)) { if ($account = user_load_by_name($matches[1])) { |