First commit
This commit is contained in:
commit
c6e2478c40
13918 changed files with 2303184 additions and 0 deletions
126
modules/simpletest/tests/actions.test
Normal file
126
modules/simpletest/tests/actions.test
Normal file
|
@ -0,0 +1,126 @@
|
|||
<?php
|
||||
|
||||
class ActionsConfigurationTestCase extends DrupalWebTestCase {
|
||||
public static function getInfo() {
|
||||
return array(
|
||||
'name' => 'Actions configuration',
|
||||
'description' => 'Tests complex actions configuration by adding, editing, and deleting a complex action.',
|
||||
'group' => 'Actions',
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test the configuration of advanced actions through the administration
|
||||
* interface.
|
||||
*/
|
||||
function testActionConfiguration() {
|
||||
// Create a user with permission to view the actions administration pages.
|
||||
$user = $this->drupalCreateUser(array('administer actions'));
|
||||
$this->drupalLogin($user);
|
||||
|
||||
// Make a POST request to admin/config/system/actions/manage.
|
||||
$edit = array();
|
||||
$edit['action'] = drupal_hash_base64('system_goto_action');
|
||||
$this->drupalPost('admin/config/system/actions/manage', $edit, t('Create'));
|
||||
|
||||
// Make a POST request to the individual action configuration page.
|
||||
$edit = array();
|
||||
$action_label = $this->randomName();
|
||||
$edit['actions_label'] = $action_label;
|
||||
$edit['url'] = 'admin';
|
||||
$this->drupalPost('admin/config/system/actions/configure/' . drupal_hash_base64('system_goto_action'), $edit, t('Save'));
|
||||
|
||||
// Make sure that the new complex action was saved properly.
|
||||
$this->assertText(t('The action has been successfully saved.'), t("Make sure we get a confirmation that we've successfully saved the complex action."));
|
||||
$this->assertText($action_label, t("Make sure the action label appears on the configuration page after we've saved the complex action."));
|
||||
|
||||
// Make another POST request to the action edit page.
|
||||
$this->clickLink(t('configure'));
|
||||
preg_match('|admin/config/system/actions/configure/(\d+)|', $this->getUrl(), $matches);
|
||||
$aid = $matches[1];
|
||||
$edit = array();
|
||||
$new_action_label = $this->randomName();
|
||||
$edit['actions_label'] = $new_action_label;
|
||||
$edit['url'] = 'admin';
|
||||
$this->drupalPost(NULL, $edit, t('Save'));
|
||||
|
||||
// Make sure that the action updated properly.
|
||||
$this->assertText(t('The action has been successfully saved.'), t("Make sure we get a confirmation that we've successfully updated the complex action."));
|
||||
$this->assertNoText($action_label, t("Make sure the old action label does NOT appear on the configuration page after we've updated the complex action."));
|
||||
$this->assertText($new_action_label, t("Make sure the action label appears on the configuration page after we've updated the complex action."));
|
||||
|
||||
// Make sure that deletions work properly.
|
||||
$this->clickLink(t('delete'));
|
||||
$edit = array();
|
||||
$this->drupalPost("admin/config/system/actions/delete/$aid", $edit, t('Delete'));
|
||||
|
||||
// Make sure that the action was actually deleted.
|
||||
$this->assertRaw(t('Action %action was deleted', array('%action' => $new_action_label)), t('Make sure that we get a delete confirmation message.'));
|
||||
$this->drupalGet('admin/config/system/actions/manage');
|
||||
$this->assertNoText($new_action_label, t("Make sure the action label does not appear on the overview page after we've deleted the action."));
|
||||
$exists = db_query('SELECT aid FROM {actions} WHERE callback = :callback', array(':callback' => 'drupal_goto_action'))->fetchField();
|
||||
$this->assertFalse($exists, t('Make sure the action is gone from the database after being deleted.'));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Test actions executing in a potential loop, and make sure they abort properly.
|
||||
*/
|
||||
class ActionLoopTestCase extends DrupalWebTestCase {
|
||||
public static function getInfo() {
|
||||
return array(
|
||||
'name' => 'Actions executing in a potentially infinite loop',
|
||||
'description' => 'Tests actions executing in a loop, and makes sure they abort properly.',
|
||||
'group' => 'Actions',
|
||||
);
|
||||
}
|
||||
|
||||
function setUp() {
|
||||
parent::setUp('dblog', 'trigger', 'actions_loop_test');
|
||||
}
|
||||
|
||||
/**
|
||||
* Set up a loop with 3 - 12 recursions, and see if it aborts properly.
|
||||
*/
|
||||
function testActionLoop() {
|
||||
$user = $this->drupalCreateUser(array('administer actions'));
|
||||
$this->drupalLogin($user);
|
||||
|
||||
$hash = drupal_hash_base64('actions_loop_test_log');
|
||||
$edit = array('aid' => $hash);
|
||||
$this->drupalPost('admin/structure/trigger/actions_loop_test', $edit, t('Assign'));
|
||||
|
||||
// Delete any existing watchdog messages to clear the plethora of
|
||||
// "Action added" messages from when Drupal was installed.
|
||||
db_delete('watchdog')->execute();
|
||||
// To prevent this test from failing when xdebug is enabled, the maximum
|
||||
// recursion level should be kept low enough to prevent the xdebug
|
||||
// infinite recursion protection mechanism from aborting the request.
|
||||
// See http://drupal.org/node/587634.
|
||||
variable_set('actions_max_stack', 7);
|
||||
$this->triggerActions();
|
||||
}
|
||||
|
||||
/**
|
||||
* Create an infinite loop by causing a watchdog message to be set,
|
||||
* which causes the actions to be triggered again, up to actions_max_stack
|
||||
* times.
|
||||
*/
|
||||
protected function triggerActions() {
|
||||
$this->drupalGet('<front>', array('query' => array('trigger_actions_on_watchdog' => TRUE)));
|
||||
$expected = array();
|
||||
$expected[] = 'Triggering action loop';
|
||||
for ($i = 1; $i <= variable_get('actions_max_stack', 35); $i++) {
|
||||
$expected[] = "Test log #$i";
|
||||
}
|
||||
$expected[] = 'Stack overflow: too many calls to actions_do(). Aborting to prevent infinite recursion.';
|
||||
|
||||
$result = db_query("SELECT message FROM {watchdog} WHERE type = 'actions_loop_test' OR type = 'actions' ORDER BY wid");
|
||||
$loop_started = FALSE;
|
||||
foreach ($result as $row) {
|
||||
$expected_message = array_shift($expected);
|
||||
$this->assertEqual($row->message, $expected_message, t('Expected message %expected, got %message.', array('%expected' => $expected_message, '%message' => $row->message)));
|
||||
}
|
||||
$this->assertTrue(empty($expected), t('All expected messages found.'));
|
||||
}
|
||||
}
|
12
modules/simpletest/tests/actions_loop_test.info
Normal file
12
modules/simpletest/tests/actions_loop_test.info
Normal file
|
@ -0,0 +1,12 @@
|
|||
name = Actions loop test
|
||||
description = Support module for action loop testing.
|
||||
package = Testing
|
||||
version = VERSION
|
||||
core = 7.x
|
||||
hidden = TRUE
|
||||
|
||||
; Information added by Drupal.org packaging script on 2017-06-21
|
||||
version = "7.56"
|
||||
project = "drupal"
|
||||
datestamp = "1498069849"
|
||||
|
11
modules/simpletest/tests/actions_loop_test.install
Normal file
11
modules/simpletest/tests/actions_loop_test.install
Normal file
|
@ -0,0 +1,11 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* Implements hook_install().
|
||||
*/
|
||||
function actions_loop_test_install() {
|
||||
db_update('system')
|
||||
->fields(array('weight' => 1))
|
||||
->condition('name', 'actions_loop_test')
|
||||
->execute();
|
||||
}
|
95
modules/simpletest/tests/actions_loop_test.module
Normal file
95
modules/simpletest/tests/actions_loop_test.module
Normal file
|
@ -0,0 +1,95 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* Implements hook_trigger_info().
|
||||
*/
|
||||
function actions_loop_test_trigger_info() {
|
||||
return array(
|
||||
'actions_loop_test' => array(
|
||||
'watchdog' => array(
|
||||
'label' => t('When a message is logged'),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements hook_watchdog().
|
||||
*/
|
||||
function actions_loop_test_watchdog(array $log_entry) {
|
||||
// If the triggering actions are not explicitly enabled, abort.
|
||||
if (empty($_GET['trigger_actions_on_watchdog'])) {
|
||||
return;
|
||||
}
|
||||
// Get all the action ids assigned to the trigger on the watchdog hook's
|
||||
// "run" event.
|
||||
$aids = trigger_get_assigned_actions('watchdog');
|
||||
// We can pass in any applicable information in $context. There isn't much in
|
||||
// this case, but we'll pass in the hook name as the bare minimum.
|
||||
$context = array(
|
||||
'hook' => 'watchdog',
|
||||
);
|
||||
// Fire the actions on the associated object ($log_entry) and the context
|
||||
// variable.
|
||||
actions_do(array_keys($aids), $log_entry, $context);
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements hook_init().
|
||||
*/
|
||||
function actions_loop_test_init() {
|
||||
if (!empty($_GET['trigger_actions_on_watchdog'])) {
|
||||
watchdog_skip_semaphore('actions_loop_test', 'Triggering action loop');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements hook_action_info().
|
||||
*/
|
||||
function actions_loop_test_action_info() {
|
||||
return array(
|
||||
'actions_loop_test_log' => array(
|
||||
'label' => t('Write a message to the log.'),
|
||||
'type' => 'system',
|
||||
'configurable' => FALSE,
|
||||
'triggers' => array('any'),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Write a message to the log.
|
||||
*/
|
||||
function actions_loop_test_log() {
|
||||
$count = &drupal_static(__FUNCTION__, 0);
|
||||
$count++;
|
||||
watchdog_skip_semaphore('actions_loop_test', "Test log #$count");
|
||||
}
|
||||
|
||||
/**
|
||||
* Replacement of the watchdog() function that eliminates the use of semaphores
|
||||
* so that we can test the abortion of an action loop.
|
||||
*/
|
||||
function watchdog_skip_semaphore($type, $message, $variables = array(), $severity = WATCHDOG_NOTICE, $link = NULL) {
|
||||
global $user, $base_root;
|
||||
|
||||
// Prepare the fields to be logged
|
||||
$log_entry = array(
|
||||
'type' => $type,
|
||||
'message' => $message,
|
||||
'variables' => $variables,
|
||||
'severity' => $severity,
|
||||
'link' => $link,
|
||||
'user' => $user,
|
||||
'uid' => isset($user->uid) ? $user->uid : 0,
|
||||
'request_uri' => $base_root . request_uri(),
|
||||
'referer' => $_SERVER['HTTP_REFERER'],
|
||||
'ip' => ip_address(),
|
||||
'timestamp' => REQUEST_TIME,
|
||||
);
|
||||
|
||||
// Call the logging hooks to log/process the message
|
||||
foreach (module_implements('watchdog') as $module) {
|
||||
module_invoke($module, 'watchdog', $log_entry);
|
||||
}
|
||||
}
|
617
modules/simpletest/tests/ajax.test
Normal file
617
modules/simpletest/tests/ajax.test
Normal file
|
@ -0,0 +1,617 @@
|
|||
<?php
|
||||
|
||||
class AJAXTestCase extends DrupalWebTestCase {
|
||||
function setUp() {
|
||||
$modules = func_get_args();
|
||||
if (isset($modules[0]) && is_array($modules[0])) {
|
||||
$modules = $modules[0];
|
||||
}
|
||||
parent::setUp(array_unique(array_merge(array('ajax_test', 'ajax_forms_test'), $modules)));
|
||||
}
|
||||
|
||||
/**
|
||||
* Assert that a command with the required properties exists within the array of Ajax commands returned by the server.
|
||||
*
|
||||
* The Ajax framework, via the ajax_deliver() and ajax_render() functions,
|
||||
* returns an array of commands. This array sometimes includes commands
|
||||
* automatically provided by the framework in addition to commands returned by
|
||||
* a particular page callback. During testing, we're usually interested that a
|
||||
* particular command is present, and don't care whether other commands
|
||||
* precede or follow the one we're interested in. Additionally, the command
|
||||
* we're interested in may include additional data that we're not interested
|
||||
* in. Therefore, this function simply asserts that one of the commands in
|
||||
* $haystack contains all of the keys and values in $needle. Furthermore, if
|
||||
* $needle contains a 'settings' key with an array value, we simply assert
|
||||
* that all keys and values within that array are present in the command we're
|
||||
* checking, and do not consider it a failure if the actual command contains
|
||||
* additional settings that aren't part of $needle.
|
||||
*
|
||||
* @param $haystack
|
||||
* An array of Ajax commands returned by the server.
|
||||
* @param $needle
|
||||
* Array of info we're expecting in one of those commands.
|
||||
* @param $message
|
||||
* An assertion message.
|
||||
*/
|
||||
protected function assertCommand($haystack, $needle, $message) {
|
||||
$found = FALSE;
|
||||
foreach ($haystack as $command) {
|
||||
// If the command has additional settings that we're not testing for, do
|
||||
// not consider that a failure.
|
||||
if (isset($command['settings']) && is_array($command['settings']) && isset($needle['settings']) && is_array($needle['settings'])) {
|
||||
$command['settings'] = array_intersect_key($command['settings'], $needle['settings']);
|
||||
}
|
||||
// If the command has additional data that we're not testing for, do not
|
||||
// consider that a failure. Also, == instead of ===, because we don't
|
||||
// require the key/value pairs to be in any particular order
|
||||
// (http://www.php.net/manual/en/language.operators.array.php).
|
||||
if (array_intersect_key($command, $needle) == $needle) {
|
||||
$found = TRUE;
|
||||
break;
|
||||
}
|
||||
}
|
||||
$this->assertTrue($found, $message);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests primary Ajax framework functions.
|
||||
*/
|
||||
class AJAXFrameworkTestCase extends AJAXTestCase {
|
||||
protected $profile = 'testing';
|
||||
|
||||
public static function getInfo() {
|
||||
return array(
|
||||
'name' => 'AJAX framework',
|
||||
'description' => 'Performs tests on AJAX framework functions.',
|
||||
'group' => 'AJAX',
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test that ajax_render() returns JavaScript settings generated during the page request.
|
||||
*
|
||||
* @todo Add tests to ensure that ajax_render() returns commands for new CSS
|
||||
* and JavaScript files to be loaded by the page. See
|
||||
* http://drupal.org/node/561858.
|
||||
*/
|
||||
function testAJAXRender() {
|
||||
$commands = $this->drupalGetAJAX('ajax-test/render');
|
||||
|
||||
// Verify that there is a command to load settings added with
|
||||
// drupal_add_js().
|
||||
$expected = array(
|
||||
'command' => 'settings',
|
||||
'settings' => array('basePath' => base_path(), 'ajax' => 'test'),
|
||||
);
|
||||
$this->assertCommand($commands, $expected, t('ajax_render() loads settings added with drupal_add_js().'));
|
||||
|
||||
// Verify that Ajax settings are loaded for #type 'link'.
|
||||
$this->drupalGet('ajax-test/link');
|
||||
$settings = $this->drupalGetSettings();
|
||||
$this->assertEqual($settings['ajax']['ajax-link']['url'], url('filter/tips'));
|
||||
$this->assertEqual($settings['ajax']['ajax-link']['wrapper'], 'block-system-main');
|
||||
}
|
||||
|
||||
/**
|
||||
* Test behavior of ajax_render_error().
|
||||
*/
|
||||
function testAJAXRenderError() {
|
||||
// Verify default error message.
|
||||
$commands = $this->drupalGetAJAX('ajax-test/render-error');
|
||||
$expected = array(
|
||||
'command' => 'alert',
|
||||
'text' => t('An error occurred while handling the request: The server received invalid input.'),
|
||||
);
|
||||
$this->assertCommand($commands, $expected, t('ajax_render_error() invokes alert command.'));
|
||||
|
||||
// Verify custom error message.
|
||||
$edit = array(
|
||||
'message' => 'Custom error message.',
|
||||
);
|
||||
$commands = $this->drupalGetAJAX('ajax-test/render-error', array('query' => $edit));
|
||||
$expected = array(
|
||||
'command' => 'alert',
|
||||
'text' => $edit['message'],
|
||||
);
|
||||
$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',
|
||||
);
|
||||
// @todo D8: Add a drupal_css_defaults() helper function.
|
||||
$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);
|
||||
$expected_js_html = drupal_get_js('header', array($expected['js'] => drupal_js_defaults($expected['js'])), TRUE);
|
||||
|
||||
// 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 requests.
|
||||
$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 without triggering files getting added.
|
||||
$commands = $this->drupalPostAJAX(NULL, array('add_files' => FALSE), array('op' => t('Submit')));
|
||||
$new_settings = $this->drupalGetSettings();
|
||||
|
||||
// Verify the setting was not added when not expected.
|
||||
$this->assertTrue(!isset($new_settings['setting_name']), t('Page still lacks the %setting, as expected.', array('%setting' => $expected['setting_name'])));
|
||||
// Verify a settings command does not add CSS or scripts to Drupal.settings
|
||||
// and no command inserts the corresponding tags on the page.
|
||||
$found_settings_command = FALSE;
|
||||
$found_markup_command = FALSE;
|
||||
foreach ($commands as $command) {
|
||||
if ($command['command'] == 'settings' && (array_key_exists('css', $command['settings']['ajaxPageState']) || array_key_exists('js', $command['settings']['ajaxPageState']))) {
|
||||
$found_settings_command = TRUE;
|
||||
}
|
||||
if (isset($command['data']) && ($command['data'] == $expected_js_html || $command['data'] == $expected_css_html)) {
|
||||
$found_markup_command = TRUE;
|
||||
}
|
||||
}
|
||||
$this->assertFalse($found_settings_command, t('Page state still lacks the %css and %js files, as expected.', array('%css' => $expected['css'], '%js' => $expected['js'])));
|
||||
$this->assertFalse($found_markup_command, t('Page still lacks the %css and %js files, as expected.', array('%css' => $expected['css'], '%js' => $expected['js'])));
|
||||
|
||||
// Submit the AJAX request and trigger adding files.
|
||||
$commands = $this->drupalPostAJAX(NULL, array('add_files' => TRUE), 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.
|
||||
$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.
|
||||
$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'])));
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests that overridden CSS files are not added during lazy load.
|
||||
*/
|
||||
function testLazyLoadOverriddenCSS() {
|
||||
// The test theme overrides system.base.css without an implementation,
|
||||
// thereby removing it.
|
||||
theme_enable(array('test_theme'));
|
||||
variable_set('theme_default', 'test_theme');
|
||||
|
||||
// This gets the form, and emulates an Ajax submission on it, including
|
||||
// adding markup to the HEAD and BODY for any lazy loaded JS/CSS files.
|
||||
$this->drupalPostAJAX('ajax_forms_test_lazy_load_form', array('add_files' => TRUE), array('op' => t('Submit')));
|
||||
|
||||
// Verify that the resulting HTML does not load the overridden CSS file.
|
||||
// We add a "?" to the assertion, because Drupal.settings may include
|
||||
// information about the file; we only really care about whether it appears
|
||||
// in a LINK or STYLE tag, for which Drupal always adds a query string for
|
||||
// cache control.
|
||||
$this->assertNoText('system.base.css?', 'Ajax lazy loading does not add overridden CSS files.');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests Ajax framework commands.
|
||||
*/
|
||||
class AJAXCommandsTestCase extends AJAXTestCase {
|
||||
public static function getInfo() {
|
||||
return array(
|
||||
'name' => 'AJAX commands',
|
||||
'description' => 'Performs tests on AJAX framework commands.',
|
||||
'group' => 'AJAX',
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test the various Ajax Commands.
|
||||
*/
|
||||
function testAJAXCommands() {
|
||||
$form_path = 'ajax_forms_test_ajax_commands_form';
|
||||
$web_user = $this->drupalCreateUser(array('access content'));
|
||||
$this->drupalLogin($web_user);
|
||||
|
||||
$edit = array();
|
||||
|
||||
// Tests the 'after' command.
|
||||
$commands = $this->drupalPostAJAX($form_path, $edit, array('op' => t("AJAX 'After': Click to put something after the div")));
|
||||
$expected = array(
|
||||
'command' => 'insert',
|
||||
'method' => 'after',
|
||||
'data' => 'This will be placed after',
|
||||
);
|
||||
$this->assertCommand($commands, $expected, "'after' AJAX command issued with correct data");
|
||||
|
||||
// Tests the 'alert' command.
|
||||
$commands = $this->drupalPostAJAX($form_path, $edit, array('op' => t("AJAX 'Alert': Click to alert")));
|
||||
$expected = array(
|
||||
'command' => 'alert',
|
||||
'text' => 'Alert',
|
||||
);
|
||||
$this->assertCommand($commands, $expected, "'alert' AJAX Command issued with correct text");
|
||||
|
||||
// Tests the 'append' command.
|
||||
$commands = $this->drupalPostAJAX($form_path, $edit, array('op' => t("AJAX 'Append': Click to append something")));
|
||||
$expected = array(
|
||||
'command' => 'insert',
|
||||
'method' => 'append',
|
||||
'data' => 'Appended text',
|
||||
);
|
||||
$this->assertCommand($commands, $expected, "'append' AJAX command issued with correct data");
|
||||
|
||||
// Tests the 'before' command.
|
||||
$commands = $this->drupalPostAJAX($form_path, $edit, array('op' => t("AJAX 'before': Click to put something before the div")));
|
||||
$expected = array(
|
||||
'command' => 'insert',
|
||||
'method' => 'before',
|
||||
'data' => 'Before text',
|
||||
);
|
||||
$this->assertCommand($commands, $expected, "'before' AJAX command issued with correct data");
|
||||
|
||||
// Tests the 'changed' command.
|
||||
$commands = $this->drupalPostAJAX($form_path, $edit, array('op' => t("AJAX changed: Click to mark div changed.")));
|
||||
$expected = array(
|
||||
'command' => 'changed',
|
||||
'selector' => '#changed_div',
|
||||
);
|
||||
$this->assertCommand($commands, $expected, "'changed' AJAX command issued with correct selector");
|
||||
|
||||
// Tests the 'changed' command using the second argument.
|
||||
$commands = $this->drupalPostAJAX($form_path, $edit, array('op' => t("AJAX changed: Click to mark div changed with asterisk.")));
|
||||
$expected = array(
|
||||
'command' => 'changed',
|
||||
'selector' => '#changed_div',
|
||||
'asterisk' => '#changed_div_mark_this',
|
||||
);
|
||||
$this->assertCommand($commands, $expected, "'changed' AJAX command (with asterisk) issued with correct selector");
|
||||
|
||||
// Tests the 'css' command.
|
||||
$commands = $this->drupalPostAJAX($form_path, $edit, array('op' => t("Set the '#box' div to be blue.")));
|
||||
$expected = array(
|
||||
'command' => 'css',
|
||||
'selector' => '#css_div',
|
||||
'argument' => array('background-color' => 'blue'),
|
||||
);
|
||||
$this->assertCommand($commands, $expected, "'css' AJAX command issued with correct selector");
|
||||
|
||||
// Tests the 'data' command.
|
||||
$commands = $this->drupalPostAJAX($form_path, $edit, array('op' => t("AJAX data command: Issue command.")));
|
||||
$expected = array(
|
||||
'command' => 'data',
|
||||
'name' => 'testkey',
|
||||
'value' => 'testvalue',
|
||||
);
|
||||
$this->assertCommand($commands, $expected, "'data' AJAX command issued with correct key and value");
|
||||
|
||||
// Tests the 'invoke' command.
|
||||
$commands = $this->drupalPostAJAX($form_path, $edit, array('op' => t("AJAX invoke command: Invoke addClass() method.")));
|
||||
$expected = array(
|
||||
'command' => 'invoke',
|
||||
'method' => 'addClass',
|
||||
'arguments' => array('error'),
|
||||
);
|
||||
$this->assertCommand($commands, $expected, "'invoke' AJAX command issued with correct method and argument");
|
||||
|
||||
// Tests the 'html' command.
|
||||
$commands = $this->drupalPostAJAX($form_path, $edit, array('op' => t("AJAX html: Replace the HTML in a selector.")));
|
||||
$expected = array(
|
||||
'command' => 'insert',
|
||||
'method' => 'html',
|
||||
'data' => 'replacement text',
|
||||
);
|
||||
$this->assertCommand($commands, $expected, "'html' AJAX command issued with correct data");
|
||||
|
||||
// Tests the 'insert' command.
|
||||
$commands = $this->drupalPostAJAX($form_path, $edit, array('op' => t("AJAX insert: Let client insert based on #ajax['method'].")));
|
||||
$expected = array(
|
||||
'command' => 'insert',
|
||||
'data' => 'insert replacement text',
|
||||
);
|
||||
$this->assertCommand($commands, $expected, "'insert' AJAX command issued with correct data");
|
||||
|
||||
// Tests the 'prepend' command.
|
||||
$commands = $this->drupalPostAJAX($form_path, $edit, array('op' => t("AJAX 'prepend': Click to prepend something")));
|
||||
$expected = array(
|
||||
'command' => 'insert',
|
||||
'method' => 'prepend',
|
||||
'data' => 'prepended text',
|
||||
);
|
||||
$this->assertCommand($commands, $expected, "'prepend' AJAX command issued with correct data");
|
||||
|
||||
// Tests the 'remove' command.
|
||||
$commands = $this->drupalPostAJAX($form_path, $edit, array('op' => t("AJAX 'remove': Click to remove text")));
|
||||
$expected = array(
|
||||
'command' => 'remove',
|
||||
'selector' => '#remove_text',
|
||||
);
|
||||
$this->assertCommand($commands, $expected, "'remove' AJAX command issued with correct command and selector");
|
||||
|
||||
// Tests the 'restripe' command.
|
||||
$commands = $this->drupalPostAJAX($form_path, $edit, array('op' => t("AJAX 'restripe' command")));
|
||||
$expected = array(
|
||||
'command' => 'restripe',
|
||||
'selector' => '#restripe_table',
|
||||
);
|
||||
$this->assertCommand($commands, $expected, "'restripe' AJAX command issued with correct selector");
|
||||
|
||||
// Tests the 'settings' command.
|
||||
$commands = $this->drupalPostAJAX($form_path, $edit, array('op' => t("AJAX 'settings' command")));
|
||||
$expected = array(
|
||||
'command' => 'settings',
|
||||
'settings' => array('ajax_forms_test' => array('foo' => 42)),
|
||||
);
|
||||
$this->assertCommand($commands, $expected, "'settings' AJAX command issued with correct data");
|
||||
|
||||
// Tests the 'add_css' command.
|
||||
$commands = $this->drupalPostAJAX($form_path, $edit, array('op' => t("AJAX 'add_css' command")));
|
||||
$expected = array(
|
||||
'command' => 'add_css',
|
||||
'data' => 'my/file.css',
|
||||
);
|
||||
$this->assertCommand($commands, $expected, "'add_css' AJAX command issued with correct data");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Test that $form_state['values'] is properly delivered to $ajax['callback'].
|
||||
*/
|
||||
class AJAXFormValuesTestCase extends AJAXTestCase {
|
||||
public static function getInfo() {
|
||||
return array(
|
||||
'name' => 'AJAX command form values',
|
||||
'description' => 'Tests that form values are properly delivered to AJAX callbacks.',
|
||||
'group' => 'AJAX',
|
||||
);
|
||||
}
|
||||
|
||||
function setUp() {
|
||||
parent::setUp();
|
||||
|
||||
$this->web_user = $this->drupalCreateUser(array('access content'));
|
||||
$this->drupalLogin($this->web_user);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a simple form, then POST to system/ajax to change to it.
|
||||
*/
|
||||
function testSimpleAJAXFormValue() {
|
||||
// Verify form values of a select element.
|
||||
foreach (array('red', 'green', 'blue') as $item) {
|
||||
$edit = array(
|
||||
'select' => $item,
|
||||
);
|
||||
$commands = $this->drupalPostAJAX('ajax_forms_test_get_form', $edit, 'select');
|
||||
$expected = array(
|
||||
'command' => 'data',
|
||||
'value' => $item,
|
||||
);
|
||||
$this->assertCommand($commands, $expected, "verification of AJAX form values from a selectbox issued with a correct value");
|
||||
}
|
||||
|
||||
// Verify form values of a checkbox element.
|
||||
foreach (array(FALSE, TRUE) as $item) {
|
||||
$edit = array(
|
||||
'checkbox' => $item,
|
||||
);
|
||||
$commands = $this->drupalPostAJAX('ajax_forms_test_get_form', $edit, 'checkbox');
|
||||
$expected = array(
|
||||
'command' => 'data',
|
||||
'value' => (int) $item,
|
||||
);
|
||||
$this->assertCommand($commands, $expected, "verification of AJAX form values from a checkbox issued with a correct value");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests that Ajax-enabled forms work when multiple instances of the same form are on a page.
|
||||
*/
|
||||
class AJAXMultiFormTestCase extends AJAXTestCase {
|
||||
public static function getInfo() {
|
||||
return array(
|
||||
'name' => 'AJAX multi form',
|
||||
'description' => 'Tests that AJAX-enabled forms work when multiple instances of the same form are on a page.',
|
||||
'group' => 'AJAX',
|
||||
);
|
||||
}
|
||||
|
||||
function setUp() {
|
||||
parent::setUp(array('form_test'));
|
||||
|
||||
// Create a multi-valued field for 'page' nodes to use for Ajax testing.
|
||||
$field_name = 'field_ajax_test';
|
||||
$field = array(
|
||||
'field_name' => $field_name,
|
||||
'type' => 'text',
|
||||
'cardinality' => FIELD_CARDINALITY_UNLIMITED,
|
||||
);
|
||||
field_create_field($field);
|
||||
$instance = array(
|
||||
'field_name' => $field_name,
|
||||
'entity_type' => 'node',
|
||||
'bundle' => 'page',
|
||||
);
|
||||
field_create_instance($instance);
|
||||
|
||||
// Login a user who can create 'page' nodes.
|
||||
$this->web_user = $this->drupalCreateUser(array('create page content'));
|
||||
$this->drupalLogin($this->web_user);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test that a page with the 'page_node_form' included twice works correctly.
|
||||
*/
|
||||
function testMultiForm() {
|
||||
// HTML IDs for elements within the field are potentially modified with
|
||||
// each Ajax submission, but these variables are stable and help target the
|
||||
// desired elements.
|
||||
$field_name = 'field_ajax_test';
|
||||
$field_xpaths = array(
|
||||
'page-node-form' => '//form[@id="page-node-form"]//div[contains(@class, "field-name-field-ajax-test")]',
|
||||
'page-node-form--2' => '//form[@id="page-node-form--2"]//div[contains(@class, "field-name-field-ajax-test")]',
|
||||
);
|
||||
$button_name = $field_name . '_add_more';
|
||||
$button_value = t('Add another item');
|
||||
$button_xpath_suffix = '//input[@name="' . $button_name . '"]';
|
||||
$field_items_xpath_suffix = '//input[@type="text"]';
|
||||
|
||||
// Ensure the initial page contains both node forms and the correct number
|
||||
// of field items and "add more" button for the multi-valued field within
|
||||
// each form.
|
||||
$this->drupalGet('form-test/two-instances-of-same-form');
|
||||
foreach ($field_xpaths as $form_html_id => $field_xpath) {
|
||||
$this->assert(count($this->xpath($field_xpath . $field_items_xpath_suffix)) == 1, t('Found the correct number of field items on the initial page.'));
|
||||
$this->assertFieldByXPath($field_xpath . $button_xpath_suffix, NULL, t('Found the "add more" button on the initial page.'));
|
||||
}
|
||||
$this->assertNoDuplicateIds(t('Initial page contains unique IDs'), 'Other');
|
||||
|
||||
// Submit the "add more" button of each form twice. After each corresponding
|
||||
// page update, ensure the same as above.
|
||||
foreach ($field_xpaths as $form_html_id => $field_xpath) {
|
||||
for ($i = 0; $i < 2; $i++) {
|
||||
$this->drupalPostAJAX(NULL, array(), array($button_name => $button_value), 'system/ajax', array(), array(), $form_html_id);
|
||||
$this->assert(count($this->xpath($field_xpath . $field_items_xpath_suffix)) == $i+2, t('Found the correct number of field items after an AJAX submission.'));
|
||||
$this->assertFieldByXPath($field_xpath . $button_xpath_suffix, NULL, t('Found the "add more" button after an AJAX submission.'));
|
||||
$this->assertNoDuplicateIds(t('Updated page contains unique IDs'), 'Other');
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Test Ajax forms when page caching for anonymous users is turned on.
|
||||
*/
|
||||
class AJAXFormPageCacheTestCase extends AJAXTestCase {
|
||||
protected $profile = 'testing';
|
||||
|
||||
public static function getInfo() {
|
||||
return array(
|
||||
'name' => 'AJAX forms on cached pages',
|
||||
'description' => 'Tests that AJAX forms work properly for anonymous users on cached pages.',
|
||||
'group' => 'AJAX',
|
||||
);
|
||||
}
|
||||
|
||||
public function setUp() {
|
||||
parent::setUp();
|
||||
|
||||
variable_set('cache', TRUE);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the build id of the current form.
|
||||
*/
|
||||
protected function getFormBuildId() {
|
||||
$build_id_fields = $this->xpath('//input[@name="form_build_id"]');
|
||||
$this->assertEqual(count($build_id_fields), 1, 'One form build id field on the page');
|
||||
return (string) $build_id_fields[0]['value'];
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a simple form, then POST to system/ajax to change to it.
|
||||
*/
|
||||
public function testSimpleAJAXFormValue() {
|
||||
$this->drupalGet('ajax_forms_test_get_form');
|
||||
$this->assertEqual($this->drupalGetHeader('X-Drupal-Cache'), 'MISS', 'Page was not cached.');
|
||||
$build_id_initial = $this->getFormBuildId();
|
||||
|
||||
$edit = array('select' => 'green');
|
||||
$commands = $this->drupalPostAJAX(NULL, $edit, 'select');
|
||||
$build_id_first_ajax = $this->getFormBuildId();
|
||||
$this->assertNotEqual($build_id_initial, $build_id_first_ajax, 'Build id is changed in the simpletest-DOM on first AJAX submission');
|
||||
$expected = array(
|
||||
'command' => 'updateBuildId',
|
||||
'old' => $build_id_initial,
|
||||
'new' => $build_id_first_ajax,
|
||||
);
|
||||
$this->assertCommand($commands, $expected, 'Build id change command issued on first AJAX submission');
|
||||
|
||||
$edit = array('select' => 'red');
|
||||
$commands = $this->drupalPostAJAX(NULL, $edit, 'select');
|
||||
$build_id_second_ajax = $this->getFormBuildId();
|
||||
$this->assertEqual($build_id_first_ajax, $build_id_second_ajax, 'Build id remains the same on subsequent AJAX submissions');
|
||||
|
||||
// Repeat the test sequence but this time with a page loaded from the cache.
|
||||
$this->drupalGet('ajax_forms_test_get_form');
|
||||
$this->assertEqual($this->drupalGetHeader('X-Drupal-Cache'), 'HIT', 'Page was cached.');
|
||||
$build_id_from_cache_initial = $this->getFormBuildId();
|
||||
$this->assertEqual($build_id_initial, $build_id_from_cache_initial, 'Build id is the same as on the first request');
|
||||
|
||||
$edit = array('select' => 'green');
|
||||
$commands = $this->drupalPostAJAX(NULL, $edit, 'select');
|
||||
$build_id_from_cache_first_ajax = $this->getFormBuildId();
|
||||
$this->assertNotEqual($build_id_from_cache_initial, $build_id_from_cache_first_ajax, 'Build id is changed in the simpletest-DOM on first AJAX submission');
|
||||
$this->assertNotEqual($build_id_first_ajax, $build_id_from_cache_first_ajax, 'Build id from first user is not reused');
|
||||
$expected = array(
|
||||
'command' => 'updateBuildId',
|
||||
'old' => $build_id_from_cache_initial,
|
||||
'new' => $build_id_from_cache_first_ajax,
|
||||
);
|
||||
$this->assertCommand($commands, $expected, 'Build id change command issued on first AJAX submission');
|
||||
|
||||
$edit = array('select' => 'red');
|
||||
$commands = $this->drupalPostAJAX(NULL, $edit, 'select');
|
||||
$build_id_from_cache_second_ajax = $this->getFormBuildId();
|
||||
$this->assertEqual($build_id_from_cache_first_ajax, $build_id_from_cache_second_ajax, 'Build id remains the same on subsequent AJAX submissions');
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Miscellaneous Ajax tests using ajax_test module.
|
||||
*/
|
||||
class AJAXElementValidation extends AJAXTestCase {
|
||||
public static function getInfo() {
|
||||
return array(
|
||||
'name' => 'Miscellaneous AJAX tests',
|
||||
'description' => 'Various tests of AJAX behavior',
|
||||
'group' => 'AJAX',
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Try to post an Ajax change to a form that has a validated element.
|
||||
*
|
||||
* The drivertext field is Ajax-enabled. An additional field is not, but
|
||||
* is set to be a required field. In this test the required field is not
|
||||
* filled in, and we want to see if the activation of the "drivertext"
|
||||
* Ajax-enabled field fails due to the required field being empty.
|
||||
*/
|
||||
function testAJAXElementValidation() {
|
||||
$web_user = $this->drupalCreateUser();
|
||||
$edit = array('drivertext' => t('some dumb text'));
|
||||
|
||||
// Post with 'drivertext' as the triggering element.
|
||||
$post_result = $this->drupalPostAJAX('ajax_validation_test', $edit, 'drivertext');
|
||||
// Look for a validation failure in the resultant JSON.
|
||||
$this->assertNoText(t('Error message'), "No error message in resultant JSON");
|
||||
$this->assertText('ajax_forms_test_validation_form_callback invoked', 'The correct callback was invoked');
|
||||
}
|
||||
}
|
12
modules/simpletest/tests/ajax_forms_test.info
Normal file
12
modules/simpletest/tests/ajax_forms_test.info
Normal file
|
@ -0,0 +1,12 @@
|
|||
name = "AJAX form test mock module"
|
||||
description = "Test for AJAX form calls."
|
||||
core = 7.x
|
||||
package = Testing
|
||||
version = VERSION
|
||||
hidden = TRUE
|
||||
|
||||
; Information added by Drupal.org packaging script on 2017-06-21
|
||||
version = "7.56"
|
||||
project = "drupal"
|
||||
datestamp = "1498069849"
|
||||
|
520
modules/simpletest/tests/ajax_forms_test.module
Normal file
520
modules/simpletest/tests/ajax_forms_test.module
Normal file
|
@ -0,0 +1,520 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Simpletest mock module for Ajax forms testing.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Implements hook_menu().
|
||||
*/
|
||||
function ajax_forms_test_menu() {
|
||||
$items = array();
|
||||
$items['ajax_forms_test_get_form'] = array(
|
||||
'title' => 'AJAX forms simple form test',
|
||||
'page callback' => 'drupal_get_form',
|
||||
'page arguments' => array('ajax_forms_test_simple_form'),
|
||||
'access callback' => TRUE,
|
||||
);
|
||||
$items['ajax_forms_test_ajax_commands_form'] = array(
|
||||
'title' => 'AJAX forms AJAX commands test',
|
||||
'page callback' => 'drupal_get_form',
|
||||
'page arguments' => array('ajax_forms_test_ajax_commands_form'),
|
||||
'access callback' => TRUE,
|
||||
);
|
||||
$items['ajax_validation_test'] = array(
|
||||
'title' => 'AJAX Validation Test',
|
||||
'page callback' => 'drupal_get_form',
|
||||
'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;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* A basic form used to test form_state['values'] during callback.
|
||||
*/
|
||||
function ajax_forms_test_simple_form($form, &$form_state) {
|
||||
$form = array();
|
||||
$form['select'] = array(
|
||||
'#type' => 'select',
|
||||
'#options' => array(
|
||||
'red' => 'red',
|
||||
'green' => 'green',
|
||||
'blue' => 'blue'),
|
||||
'#ajax' => array(
|
||||
'callback' => 'ajax_forms_test_simple_form_select_callback',
|
||||
),
|
||||
'#suffix' => '<div id="ajax_selected_color">No color yet selected</div>',
|
||||
);
|
||||
|
||||
$form['checkbox'] = array(
|
||||
'#type' => 'checkbox',
|
||||
'#title' => t('Test checkbox'),
|
||||
'#ajax' => array(
|
||||
'callback' => 'ajax_forms_test_simple_form_checkbox_callback',
|
||||
),
|
||||
'#suffix' => '<div id="ajax_checkbox_value">No action yet</div>',
|
||||
);
|
||||
$form['submit'] = array(
|
||||
'#type' => 'submit',
|
||||
'#value' => t('submit'),
|
||||
);
|
||||
return $form;
|
||||
}
|
||||
|
||||
/**
|
||||
* Ajax callback triggered by select.
|
||||
*/
|
||||
function ajax_forms_test_simple_form_select_callback($form, $form_state) {
|
||||
$commands = array();
|
||||
$commands[] = ajax_command_html('#ajax_selected_color', $form_state['values']['select']);
|
||||
$commands[] = ajax_command_data('#ajax_selected_color', 'form_state_value_select', $form_state['values']['select']);
|
||||
return array('#type' => 'ajax', '#commands' => $commands);
|
||||
}
|
||||
|
||||
/**
|
||||
* Ajax callback triggered by checkbox.
|
||||
*/
|
||||
function ajax_forms_test_simple_form_checkbox_callback($form, $form_state) {
|
||||
$commands = array();
|
||||
$commands[] = ajax_command_html('#ajax_checkbox_value', (int) $form_state['values']['checkbox']);
|
||||
$commands[] = ajax_command_data('#ajax_checkbox_value', 'form_state_value_select', (int) $form_state['values']['checkbox']);
|
||||
return array('#type' => 'ajax', '#commands' => $commands);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Form to display the Ajax Commands.
|
||||
*/
|
||||
function ajax_forms_test_ajax_commands_form($form, &$form_state) {
|
||||
$form = array();
|
||||
|
||||
// Shows the 'after' command with a callback generating commands.
|
||||
$form['after_command_example'] = array(
|
||||
'#value' => t("AJAX 'After': Click to put something after the div"),
|
||||
'#type' => 'submit',
|
||||
'#ajax' => array(
|
||||
'callback' => 'ajax_forms_test_advanced_commands_after_callback',
|
||||
),
|
||||
'#suffix' => '<div id="after_div">Something can be inserted after this</div>',
|
||||
);
|
||||
|
||||
// Shows the 'alert' command.
|
||||
$form['alert_command_example'] = array(
|
||||
'#value' => t("AJAX 'Alert': Click to alert"),
|
||||
'#type' => 'submit',
|
||||
'#ajax' => array(
|
||||
'callback' => 'ajax_forms_test_advanced_commands_alert_callback',
|
||||
),
|
||||
);
|
||||
|
||||
// Shows the 'append' command.
|
||||
$form['append_command_example'] = array(
|
||||
'#value' => t("AJAX 'Append': Click to append something"),
|
||||
'#type' => 'submit',
|
||||
'#ajax' => array(
|
||||
'callback' => 'ajax_forms_test_advanced_commands_append_callback',
|
||||
),
|
||||
'#suffix' => '<div id="append_div">Append inside this div</div>',
|
||||
);
|
||||
|
||||
|
||||
// Shows the 'before' command.
|
||||
$form['before_command_example'] = array(
|
||||
'#value' => t("AJAX 'before': Click to put something before the div"),
|
||||
'#type' => 'submit',
|
||||
'#ajax' => array(
|
||||
'callback' => 'ajax_forms_test_advanced_commands_before_callback',
|
||||
),
|
||||
'#suffix' => '<div id="before_div">Insert something before this.</div>',
|
||||
);
|
||||
|
||||
// Shows the 'changed' command without asterisk.
|
||||
$form['changed_command_example'] = array(
|
||||
'#value' => t("AJAX changed: Click to mark div changed."),
|
||||
'#type' => 'submit',
|
||||
'#ajax' => array(
|
||||
'callback' => 'ajax_forms_test_advanced_commands_changed_callback',
|
||||
),
|
||||
'#suffix' => '<div id="changed_div"> <div id="changed_div_mark_this">This div can be marked as changed or not.</div></div>',
|
||||
);
|
||||
// Shows the 'changed' command adding the asterisk.
|
||||
$form['changed_command_asterisk_example'] = array(
|
||||
'#value' => t("AJAX changed: Click to mark div changed with asterisk."),
|
||||
'#type' => 'submit',
|
||||
'#ajax' => array(
|
||||
'callback' => 'ajax_forms_test_advanced_commands_changed_asterisk_callback',
|
||||
),
|
||||
);
|
||||
|
||||
// Shows the Ajax 'css' command.
|
||||
$form['css_command_example'] = array(
|
||||
'#value' => t("Set the '#box' div to be blue."),
|
||||
'#type' => 'submit',
|
||||
'#ajax' => array(
|
||||
'callback' => 'ajax_forms_test_advanced_commands_css_callback',
|
||||
),
|
||||
'#suffix' => '<div id="css_div" style="height: 50px; width: 50px; border: 1px solid black"> box</div>',
|
||||
);
|
||||
|
||||
|
||||
// Shows the Ajax 'data' command. But there is no use of this information,
|
||||
// as this would require a javascript client to use the data.
|
||||
$form['data_command_example'] = array(
|
||||
'#value' => t("AJAX data command: Issue command."),
|
||||
'#type' => 'submit',
|
||||
'#ajax' => array(
|
||||
'callback' => 'ajax_forms_test_advanced_commands_data_callback',
|
||||
),
|
||||
'#suffix' => '<div id="data_div">Data attached to this div.</div>',
|
||||
);
|
||||
|
||||
// Shows the Ajax 'invoke' command.
|
||||
$form['invoke_command_example'] = array(
|
||||
'#value' => t("AJAX invoke command: Invoke addClass() method."),
|
||||
'#type' => 'submit',
|
||||
'#ajax' => array(
|
||||
'callback' => 'ajax_forms_test_advanced_commands_invoke_callback',
|
||||
),
|
||||
'#suffix' => '<div id="invoke_div">Original contents</div>',
|
||||
);
|
||||
|
||||
// Shows the Ajax 'html' command.
|
||||
$form['html_command_example'] = array(
|
||||
'#value' => t("AJAX html: Replace the HTML in a selector."),
|
||||
'#type' => 'submit',
|
||||
'#ajax' => array(
|
||||
'callback' => 'ajax_forms_test_advanced_commands_html_callback',
|
||||
),
|
||||
'#suffix' => '<div id="html_div">Original contents</div>',
|
||||
);
|
||||
|
||||
// Shows the Ajax 'insert' command.
|
||||
$form['insert_command_example'] = array(
|
||||
'#value' => t("AJAX insert: Let client insert based on #ajax['method']."),
|
||||
'#type' => 'submit',
|
||||
'#ajax' => array(
|
||||
'callback' => 'ajax_forms_test_advanced_commands_insert_callback',
|
||||
'method' => 'prepend',
|
||||
),
|
||||
'#suffix' => '<div id="insert_div">Original contents</div>',
|
||||
);
|
||||
|
||||
// Shows the Ajax 'prepend' command.
|
||||
$form['prepend_command_example'] = array(
|
||||
'#value' => t("AJAX 'prepend': Click to prepend something"),
|
||||
'#type' => 'submit',
|
||||
'#ajax' => array(
|
||||
'callback' => 'ajax_forms_test_advanced_commands_prepend_callback',
|
||||
),
|
||||
'#suffix' => '<div id="prepend_div">Something will be prepended to this div. </div>',
|
||||
);
|
||||
|
||||
// Shows the Ajax 'remove' command.
|
||||
$form['remove_command_example'] = array(
|
||||
'#value' => t("AJAX 'remove': Click to remove text"),
|
||||
'#type' => 'submit',
|
||||
'#ajax' => array(
|
||||
'callback' => 'ajax_forms_test_advanced_commands_remove_callback',
|
||||
),
|
||||
'#suffix' => '<div id="remove_div"><div id="remove_text">text to be removed</div></div>',
|
||||
);
|
||||
|
||||
// Shows the Ajax 'restripe' command.
|
||||
$form['restripe_command_example'] = array(
|
||||
'#type' => 'submit',
|
||||
'#value' => t("AJAX 'restripe' command"),
|
||||
'#ajax' => array(
|
||||
'callback' => 'ajax_forms_test_advanced_commands_restripe_callback',
|
||||
),
|
||||
'#suffix' => '<div id="restripe_div">
|
||||
<table id="restripe_table" style="border: 1px solid black" >
|
||||
<tr id="table-first"><td>first row</td></tr>
|
||||
<tr ><td>second row</td></tr>
|
||||
</table>
|
||||
</div>',
|
||||
);
|
||||
|
||||
// Demonstrates the Ajax 'settings' command. The 'settings' command has
|
||||
// nothing visual to "show", but it can be tested via SimpleTest and via
|
||||
// Firebug.
|
||||
$form['settings_command_example'] = array(
|
||||
'#type' => 'submit',
|
||||
'#value' => t("AJAX 'settings' command"),
|
||||
'#ajax' => array(
|
||||
'callback' => 'ajax_forms_test_advanced_commands_settings_callback',
|
||||
),
|
||||
);
|
||||
|
||||
// Shows the Ajax 'add_css' command.
|
||||
$form['add_css_command_example'] = array(
|
||||
'#type' => 'submit',
|
||||
'#value' => t("AJAX 'add_css' command"),
|
||||
'#ajax' => array(
|
||||
'callback' => 'ajax_forms_test_advanced_commands_add_css_callback',
|
||||
),
|
||||
);
|
||||
|
||||
$form['submit'] = array(
|
||||
'#type' => 'submit',
|
||||
'#value' => t('Submit'),
|
||||
);
|
||||
|
||||
return $form;
|
||||
}
|
||||
|
||||
/**
|
||||
* Ajax callback for 'after'.
|
||||
*/
|
||||
function ajax_forms_test_advanced_commands_after_callback($form, $form_state) {
|
||||
$selector = '#after_div';
|
||||
|
||||
$commands = array();
|
||||
$commands[] = ajax_command_after($selector, "This will be placed after");
|
||||
return array('#type' => 'ajax', '#commands' => $commands);
|
||||
}
|
||||
|
||||
/**
|
||||
* Ajax callback for 'alert'.
|
||||
*/
|
||||
function ajax_forms_test_advanced_commands_alert_callback($form, $form_state) {
|
||||
$commands = array();
|
||||
$commands[] = ajax_command_alert("Alert");
|
||||
return array('#type' => 'ajax', '#commands' => $commands);
|
||||
}
|
||||
|
||||
/**
|
||||
* Ajax callback for 'append'.
|
||||
*/
|
||||
function ajax_forms_test_advanced_commands_append_callback($form, $form_state) {
|
||||
$selector = '#append_div';
|
||||
$commands = array();
|
||||
$commands[] = ajax_command_append($selector, "Appended text");
|
||||
return array('#type' => 'ajax', '#commands' => $commands);
|
||||
}
|
||||
|
||||
/**
|
||||
* Ajax callback for 'before'.
|
||||
*/
|
||||
function ajax_forms_test_advanced_commands_before_callback($form, $form_state) {
|
||||
$selector = '#before_div';
|
||||
|
||||
$commands = array();
|
||||
$commands[] = ajax_command_before($selector, "Before text");
|
||||
return array('#type' => 'ajax', '#commands' => $commands);
|
||||
}
|
||||
|
||||
/**
|
||||
* Ajax callback for 'changed'.
|
||||
*/
|
||||
function ajax_forms_test_advanced_commands_changed_callback($form, $form_state) {
|
||||
$commands[] = ajax_command_changed('#changed_div');
|
||||
return array('#type' => 'ajax', '#commands' => $commands);
|
||||
}
|
||||
/**
|
||||
* Ajax callback for 'changed' with asterisk marking inner div.
|
||||
*/
|
||||
function ajax_forms_test_advanced_commands_changed_asterisk_callback($form, $form_state) {
|
||||
$commands = array();
|
||||
$commands[] = ajax_command_changed('#changed_div', '#changed_div_mark_this');
|
||||
return array('#type' => 'ajax', '#commands' => $commands);
|
||||
}
|
||||
|
||||
/**
|
||||
* Ajax callback for 'css'.
|
||||
*/
|
||||
function ajax_forms_test_advanced_commands_css_callback($form, $form_state) {
|
||||
$selector = '#css_div';
|
||||
$color = 'blue';
|
||||
|
||||
$commands = array();
|
||||
$commands[] = ajax_command_css($selector, array('background-color' => $color));
|
||||
return array('#type' => 'ajax', '#commands' => $commands);
|
||||
}
|
||||
|
||||
/**
|
||||
* Ajax callback for 'data'.
|
||||
*/
|
||||
function ajax_forms_test_advanced_commands_data_callback($form, $form_state) {
|
||||
$selector = '#data_div';
|
||||
|
||||
$commands = array();
|
||||
$commands[] = ajax_command_data($selector, 'testkey', 'testvalue');
|
||||
return array('#type' => 'ajax', '#commands' => $commands);
|
||||
}
|
||||
|
||||
/**
|
||||
* Ajax callback for 'invoke'.
|
||||
*/
|
||||
function ajax_forms_test_advanced_commands_invoke_callback($form, $form_state) {
|
||||
$commands = array();
|
||||
$commands[] = ajax_command_invoke('#invoke_div', 'addClass', array('error'));
|
||||
return array('#type' => 'ajax', '#commands' => $commands);
|
||||
}
|
||||
|
||||
/**
|
||||
* Ajax callback for 'html'.
|
||||
*/
|
||||
function ajax_forms_test_advanced_commands_html_callback($form, $form_state) {
|
||||
$commands = array();
|
||||
$commands[] = ajax_command_html('#html_div', 'replacement text');
|
||||
return array('#type' => 'ajax', '#commands' => $commands);
|
||||
}
|
||||
|
||||
/**
|
||||
* Ajax callback for 'insert'.
|
||||
*/
|
||||
function ajax_forms_test_advanced_commands_insert_callback($form, $form_state) {
|
||||
$commands = array();
|
||||
$commands[] = ajax_command_insert('#insert_div', 'insert replacement text');
|
||||
return array('#type' => 'ajax', '#commands' => $commands);
|
||||
}
|
||||
|
||||
/**
|
||||
* Ajax callback for 'prepend'.
|
||||
*/
|
||||
function ajax_forms_test_advanced_commands_prepend_callback($form, $form_state) {
|
||||
$commands = array();
|
||||
$commands[] = ajax_command_prepend('#prepend_div', "prepended text");
|
||||
return array('#type' => 'ajax', '#commands' => $commands);
|
||||
}
|
||||
|
||||
/**
|
||||
* Ajax callback for 'remove'.
|
||||
*/
|
||||
function ajax_forms_test_advanced_commands_remove_callback($form, $form_state) {
|
||||
$commands = array();
|
||||
$commands[] = ajax_command_remove('#remove_text');
|
||||
return array('#type' => 'ajax', '#commands' => $commands);
|
||||
}
|
||||
|
||||
/**
|
||||
* Ajax callback for 'restripe'.
|
||||
*/
|
||||
function ajax_forms_test_advanced_commands_restripe_callback($form, $form_state) {
|
||||
$commands = array();
|
||||
$commands[] = ajax_command_restripe('#restripe_table');
|
||||
return array('#type' => 'ajax', '#commands' => $commands);
|
||||
}
|
||||
|
||||
/**
|
||||
* Ajax callback for 'settings'.
|
||||
*/
|
||||
function ajax_forms_test_advanced_commands_settings_callback($form, $form_state) {
|
||||
$commands = array();
|
||||
$setting['ajax_forms_test']['foo'] = 42;
|
||||
$commands[] = ajax_command_settings($setting);
|
||||
return array('#type' => 'ajax', '#commands' => $commands);
|
||||
}
|
||||
|
||||
/**
|
||||
* Ajax callback for 'add_css'.
|
||||
*/
|
||||
function ajax_forms_test_advanced_commands_add_css_callback($form, $form_state) {
|
||||
$commands = array();
|
||||
$commands[] = ajax_command_add_css('my/file.css');
|
||||
return array('#type' => 'ajax', '#commands' => $commands);
|
||||
}
|
||||
|
||||
/**
|
||||
* This form and its related submit and callback functions demonstrate
|
||||
* not validating another form element when a single Ajax element is triggered.
|
||||
*
|
||||
* The "drivertext" element is an Ajax-enabled textfield, free-form.
|
||||
* The "required_field" element is a textfield marked required.
|
||||
*
|
||||
* The correct behavior is that the Ajax-enabled drivertext element should
|
||||
* be able to trigger without causing validation of the "required_field".
|
||||
*/
|
||||
function ajax_forms_test_validation_form($form, &$form_state) {
|
||||
|
||||
$form['drivertext'] = array(
|
||||
'#title' => t('AJAX-enabled textfield.'),
|
||||
'#description' => t("When this one AJAX-triggers and the spare required field is empty, you should not get an error."),
|
||||
'#type' => 'textfield',
|
||||
'#default_value' => !empty($form_state['values']['drivertext']) ? $form_state['values']['drivertext'] : "",
|
||||
'#ajax' => array(
|
||||
'callback' => 'ajax_forms_test_validation_form_callback',
|
||||
'wrapper' => 'message_area',
|
||||
'method' => 'replace',
|
||||
),
|
||||
'#suffix' => '<div id="message_area"></div>',
|
||||
);
|
||||
|
||||
$form['spare_required_field'] = array(
|
||||
'#title' => t("Spare Required Field"),
|
||||
'#type' => 'textfield',
|
||||
'#required' => TRUE,
|
||||
);
|
||||
|
||||
$form['submit'] = array(
|
||||
'#type' => 'submit',
|
||||
'#value' => t('Submit'),
|
||||
);
|
||||
|
||||
return $form;
|
||||
}
|
||||
/**
|
||||
* Submit handler for the validation form.
|
||||
*/
|
||||
function ajax_forms_test_validation_form_submit($form, $form_state) {
|
||||
drupal_set_message(t("Validation form submitted"));
|
||||
}
|
||||
|
||||
/**
|
||||
* Ajax callback for the 'drivertext' element of the validation form.
|
||||
*/
|
||||
function ajax_forms_test_validation_form_callback($form, $form_state) {
|
||||
drupal_set_message("ajax_forms_test_validation_form_callback invoked");
|
||||
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['add_files'] = array(
|
||||
'#type' => 'checkbox',
|
||||
'#default_value' => FALSE,
|
||||
);
|
||||
$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) {
|
||||
if ($form_state['values']['add_files']) {
|
||||
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;
|
||||
}
|
12
modules/simpletest/tests/ajax_test.info
Normal file
12
modules/simpletest/tests/ajax_test.info
Normal file
|
@ -0,0 +1,12 @@
|
|||
name = AJAX Test
|
||||
description = Support module for AJAX framework tests.
|
||||
package = Testing
|
||||
version = VERSION
|
||||
core = 7.x
|
||||
hidden = TRUE
|
||||
|
||||
; Information added by Drupal.org packaging script on 2017-06-21
|
||||
version = "7.56"
|
||||
project = "drupal"
|
||||
datestamp = "1498069849"
|
||||
|
79
modules/simpletest/tests/ajax_test.module
Normal file
79
modules/simpletest/tests/ajax_test.module
Normal file
|
@ -0,0 +1,79 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Helper module for Ajax framework tests.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Implements hook_menu().
|
||||
*/
|
||||
function ajax_test_menu() {
|
||||
$items['ajax-test/render'] = array(
|
||||
'title' => 'ajax_render',
|
||||
'page callback' => 'ajax_test_render',
|
||||
'delivery callback' => 'ajax_deliver',
|
||||
'access callback' => TRUE,
|
||||
'type' => MENU_CALLBACK,
|
||||
);
|
||||
$items['ajax-test/render-error'] = array(
|
||||
'title' => 'ajax_render_error',
|
||||
'page callback' => 'ajax_test_error',
|
||||
'delivery callback' => 'ajax_deliver',
|
||||
'access callback' => TRUE,
|
||||
'type' => MENU_CALLBACK,
|
||||
);
|
||||
$items['ajax-test/link'] = array(
|
||||
'title' => 'AJAX Link',
|
||||
'page callback' => 'ajax_test_link',
|
||||
'access callback' => TRUE,
|
||||
);
|
||||
return $items;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements hook_system_theme_info().
|
||||
*/
|
||||
function ajax_test_system_theme_info() {
|
||||
$themes['test_theme'] = drupal_get_path('module', 'ajax_test') . '/themes/test_theme/test_theme.info';
|
||||
return $themes;
|
||||
}
|
||||
|
||||
/**
|
||||
* Menu callback; Return an element suitable for use by ajax_deliver().
|
||||
*
|
||||
* Additionally ensures that ajax_render() incorporates JavaScript settings
|
||||
* generated during the page request by invoking drupal_add_js() with a dummy
|
||||
* setting.
|
||||
*/
|
||||
function ajax_test_render() {
|
||||
drupal_add_js(array('ajax' => 'test'), 'setting');
|
||||
return array('#type' => 'ajax', '#commands' => array());
|
||||
}
|
||||
|
||||
/**
|
||||
* Menu callback; Returns Ajax element with #error property set.
|
||||
*/
|
||||
function ajax_test_error() {
|
||||
$message = '';
|
||||
if (!empty($_GET['message'])) {
|
||||
$message = $_GET['message'];
|
||||
}
|
||||
return array('#type' => 'ajax', '#error' => $message);
|
||||
}
|
||||
|
||||
/**
|
||||
* Menu callback; Renders a #type link with #ajax.
|
||||
*/
|
||||
function ajax_test_link() {
|
||||
$build['link'] = array(
|
||||
'#type' => 'link',
|
||||
'#title' => 'Show help',
|
||||
'#href' => 'filter/tips',
|
||||
'#ajax' => array(
|
||||
'wrapper' => 'block-system-main',
|
||||
),
|
||||
);
|
||||
return $build;
|
||||
}
|
||||
|
403
modules/simpletest/tests/batch.test
Normal file
403
modules/simpletest/tests/batch.test
Normal file
|
@ -0,0 +1,403 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Tests for the Batch API.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Tests for the Batch API.
|
||||
*/
|
||||
class BatchProcessingTestCase extends DrupalWebTestCase {
|
||||
public static function getInfo() {
|
||||
return array(
|
||||
'name' => 'Batch processing',
|
||||
'description' => 'Test batch processing in form and non-form workflow.',
|
||||
'group' => 'Batch API',
|
||||
);
|
||||
}
|
||||
|
||||
function setUp() {
|
||||
parent::setUp('batch_test');
|
||||
}
|
||||
|
||||
/**
|
||||
* Test batches triggered outside of form submission.
|
||||
*/
|
||||
function testBatchNoForm() {
|
||||
// Displaying the page triggers batch 1.
|
||||
$this->drupalGet('batch-test/no-form');
|
||||
$this->assertBatchMessages($this->_resultMessages(1), t('Batch for step 2 performed successfully.'));
|
||||
$this->assertEqual(batch_test_stack(), $this->_resultStack('batch_1'), t('Execution order was correct.'));
|
||||
$this->assertText('Redirection successful.', t('Redirection after batch execution is correct.'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Test batches defined in a form submit handler.
|
||||
*/
|
||||
function testBatchForm() {
|
||||
// Batch 0: no operation.
|
||||
$edit = array('batch' => 'batch_0');
|
||||
$this->drupalPost('batch-test/simple', $edit, 'Submit');
|
||||
$this->assertBatchMessages($this->_resultMessages('batch_0'), t('Batch with no operation performed successfully.'));
|
||||
$this->assertText('Redirection successful.', t('Redirection after batch execution is correct.'));
|
||||
|
||||
// Batch 1: several simple operations.
|
||||
$edit = array('batch' => 'batch_1');
|
||||
$this->drupalPost('batch-test/simple', $edit, 'Submit');
|
||||
$this->assertBatchMessages($this->_resultMessages('batch_1'), t('Batch with simple operations performed successfully.'));
|
||||
$this->assertEqual(batch_test_stack(), $this->_resultStack('batch_1'), t('Execution order was correct.'));
|
||||
$this->assertText('Redirection successful.', t('Redirection after batch execution is correct.'));
|
||||
|
||||
// Batch 2: one multistep operation.
|
||||
$edit = array('batch' => 'batch_2');
|
||||
$this->drupalPost('batch-test/simple', $edit, 'Submit');
|
||||
$this->assertBatchMessages($this->_resultMessages('batch_2'), t('Batch with multistep operation performed successfully.'));
|
||||
$this->assertEqual(batch_test_stack(), $this->_resultStack('batch_2'), t('Execution order was correct.'));
|
||||
$this->assertText('Redirection successful.', t('Redirection after batch execution is correct.'));
|
||||
|
||||
// Batch 3: simple + multistep combined.
|
||||
$edit = array('batch' => 'batch_3');
|
||||
$this->drupalPost('batch-test/simple', $edit, 'Submit');
|
||||
$this->assertBatchMessages($this->_resultMessages('batch_3'), t('Batch with simple and multistep operations performed successfully.'));
|
||||
$this->assertEqual(batch_test_stack(), $this->_resultStack('batch_3'), t('Execution order was correct.'));
|
||||
$this->assertText('Redirection successful.', t('Redirection after batch execution is correct.'));
|
||||
|
||||
// Batch 4: nested batch.
|
||||
$edit = array('batch' => 'batch_4');
|
||||
$this->drupalPost('batch-test/simple', $edit, 'Submit');
|
||||
$this->assertBatchMessages($this->_resultMessages('batch_4'), t('Nested batch performed successfully.'));
|
||||
$this->assertEqual(batch_test_stack(), $this->_resultStack('batch_4'), t('Execution order was correct.'));
|
||||
$this->assertText('Redirection successful.', t('Redirection after batch execution is correct.'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Test batches defined in a multistep form.
|
||||
*/
|
||||
function testBatchFormMultistep() {
|
||||
$this->drupalGet('batch-test/multistep');
|
||||
$this->assertText('step 1', t('Form is displayed in step 1.'));
|
||||
|
||||
// First step triggers batch 1.
|
||||
$this->drupalPost(NULL, array(), 'Submit');
|
||||
$this->assertBatchMessages($this->_resultMessages('batch_1'), t('Batch for step 1 performed successfully.'));
|
||||
$this->assertEqual(batch_test_stack(), $this->_resultStack('batch_1'), t('Execution order was correct.'));
|
||||
$this->assertText('step 2', t('Form is displayed in step 2.'));
|
||||
|
||||
// Second step triggers batch 2.
|
||||
$this->drupalPost(NULL, array(), 'Submit');
|
||||
$this->assertBatchMessages($this->_resultMessages('batch_2'), t('Batch for step 2 performed successfully.'));
|
||||
$this->assertEqual(batch_test_stack(), $this->_resultStack('batch_2'), t('Execution order was correct.'));
|
||||
$this->assertText('Redirection successful.', t('Redirection after batch execution is correct.'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Test batches defined in different submit handlers on the same form.
|
||||
*/
|
||||
function testBatchFormMultipleBatches() {
|
||||
// Batches 1, 2 and 3 are triggered in sequence by different submit
|
||||
// handlers. Each submit handler modify the submitted 'value'.
|
||||
$value = rand(0, 255);
|
||||
$edit = array('value' => $value);
|
||||
$this->drupalPost('batch-test/chained', $edit, 'Submit');
|
||||
// Check that result messages are present and in the correct order.
|
||||
$this->assertBatchMessages($this->_resultMessages('chained'), t('Batches defined in separate submit handlers performed successfully.'));
|
||||
// The stack contains execution order of batch callbacks and submit
|
||||
// hanlders and logging of corresponding $form_state[{values'].
|
||||
$this->assertEqual(batch_test_stack(), $this->_resultStack('chained', $value), t('Execution order was correct, and $form_state is correctly persisted.'));
|
||||
$this->assertText('Redirection successful.', t('Redirection after batch execution is correct.'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Test batches defined in a programmatically submitted form.
|
||||
*
|
||||
* Same as above, but the form is submitted through drupal_form_execute().
|
||||
*/
|
||||
function testBatchFormProgrammatic() {
|
||||
// Batches 1, 2 and 3 are triggered in sequence by different submit
|
||||
// handlers. Each submit handler modify the submitted 'value'.
|
||||
$value = rand(0, 255);
|
||||
$this->drupalGet('batch-test/programmatic/' . $value);
|
||||
// Check that result messages are present and in the correct order.
|
||||
$this->assertBatchMessages($this->_resultMessages('chained'), t('Batches defined in separate submit handlers performed successfully.'));
|
||||
// The stack contains execution order of batch callbacks and submit
|
||||
// hanlders and logging of corresponding $form_state[{values'].
|
||||
$this->assertEqual(batch_test_stack(), $this->_resultStack('chained', $value), t('Execution order was correct, and $form_state is correctly persisted.'));
|
||||
$this->assertText('Got out of a programmatic batched form.', t('Page execution continues normally.'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Test that drupal_form_submit() can run within a batch operation.
|
||||
*/
|
||||
function testDrupalFormSubmitInBatch() {
|
||||
// Displaying the page triggers a batch that programmatically submits a
|
||||
// form.
|
||||
$value = rand(0, 255);
|
||||
$this->drupalGet('batch-test/nested-programmatic/' . $value);
|
||||
$this->assertEqual(batch_test_stack(), array('mock form submitted with value = ' . $value), t('drupal_form_submit() ran successfully within a batch operation.'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Test batches that return $context['finished'] > 1 do in fact complete.
|
||||
* See http://drupal.org/node/600836
|
||||
*/
|
||||
function testBatchLargePercentage() {
|
||||
// Displaying the page triggers batch 5.
|
||||
$this->drupalGet('batch-test/large-percentage');
|
||||
$this->assertBatchMessages($this->_resultMessages(1), t('Batch for step 2 performed successfully.'));
|
||||
$this->assertEqual(batch_test_stack(), $this->_resultStack('batch_5'), t('Execution order was correct.'));
|
||||
$this->assertText('Redirection successful.', t('Redirection after batch execution is correct.'));
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Will trigger a pass if the texts were found in order in the raw content.
|
||||
*
|
||||
* @param $texts
|
||||
* Array of raw strings to look for .
|
||||
* @param $message
|
||||
* Message to display.
|
||||
* @return
|
||||
* TRUE on pass, FALSE on fail.
|
||||
*/
|
||||
function assertBatchMessages($texts, $message) {
|
||||
$pattern = '|' . implode('.*', $texts) .'|s';
|
||||
return $this->assertPattern($pattern, $message);
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper function: return expected execution stacks for the test batches.
|
||||
*/
|
||||
function _resultStack($id, $value = 0) {
|
||||
$stack = array();
|
||||
switch ($id) {
|
||||
case 'batch_1':
|
||||
for ($i = 1; $i <= 10; $i++) {
|
||||
$stack[] = "op 1 id $i";
|
||||
}
|
||||
break;
|
||||
|
||||
case 'batch_2':
|
||||
for ($i = 1; $i <= 10; $i++) {
|
||||
$stack[] = "op 2 id $i";
|
||||
}
|
||||
break;
|
||||
|
||||
case 'batch_3':
|
||||
for ($i = 1; $i <= 5; $i++) {
|
||||
$stack[] = "op 1 id $i";
|
||||
}
|
||||
for ($i = 1; $i <= 5; $i++) {
|
||||
$stack[] = "op 2 id $i";
|
||||
}
|
||||
for ($i = 6; $i <= 10; $i++) {
|
||||
$stack[] = "op 1 id $i";
|
||||
}
|
||||
for ($i = 6; $i <= 10; $i++) {
|
||||
$stack[] = "op 2 id $i";
|
||||
}
|
||||
break;
|
||||
|
||||
case 'batch_4':
|
||||
for ($i = 1; $i <= 5; $i++) {
|
||||
$stack[] = "op 1 id $i";
|
||||
}
|
||||
$stack[] = 'setting up batch 2';
|
||||
for ($i = 6; $i <= 10; $i++) {
|
||||
$stack[] = "op 1 id $i";
|
||||
}
|
||||
$stack = array_merge($stack, $this->_resultStack('batch_2'));
|
||||
break;
|
||||
|
||||
case 'batch_5':
|
||||
for ($i = 1; $i <= 10; $i++) {
|
||||
$stack[] = "op 5 id $i";
|
||||
}
|
||||
break;
|
||||
|
||||
case 'chained':
|
||||
$stack[] = 'submit handler 1';
|
||||
$stack[] = 'value = ' . $value;
|
||||
$stack = array_merge($stack, $this->_resultStack('batch_1'));
|
||||
$stack[] = 'submit handler 2';
|
||||
$stack[] = 'value = ' . ($value + 1);
|
||||
$stack = array_merge($stack, $this->_resultStack('batch_2'));
|
||||
$stack[] = 'submit handler 3';
|
||||
$stack[] = 'value = ' . ($value + 2);
|
||||
$stack[] = 'submit handler 4';
|
||||
$stack[] = 'value = ' . ($value + 3);
|
||||
$stack = array_merge($stack, $this->_resultStack('batch_3'));
|
||||
break;
|
||||
}
|
||||
return $stack;
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper function: return expected result messages for the test batches.
|
||||
*/
|
||||
function _resultMessages($id) {
|
||||
$messages = array();
|
||||
|
||||
switch ($id) {
|
||||
case 'batch_0':
|
||||
$messages[] = 'results for batch 0<br />none';
|
||||
break;
|
||||
|
||||
case 'batch_1':
|
||||
$messages[] = 'results for batch 1<br />op 1: processed 10 elements';
|
||||
break;
|
||||
|
||||
case 'batch_2':
|
||||
$messages[] = 'results for batch 2<br />op 2: processed 10 elements';
|
||||
break;
|
||||
|
||||
case 'batch_3':
|
||||
$messages[] = 'results for batch 3<br />op 1: processed 10 elements<br />op 2: processed 10 elements';
|
||||
break;
|
||||
|
||||
case 'batch_4':
|
||||
$messages[] = 'results for batch 4<br />op 1: processed 10 elements';
|
||||
$messages = array_merge($messages, $this->_resultMessages('batch_2'));
|
||||
break;
|
||||
|
||||
case 'batch_5':
|
||||
$messages[] = 'results for batch 5<br />op 1: processed 10 elements. $context[\'finished\'] > 1 returned from batch process, with success.';
|
||||
break;
|
||||
|
||||
case 'chained':
|
||||
$messages = array_merge($messages, $this->_resultMessages('batch_1'));
|
||||
$messages = array_merge($messages, $this->_resultMessages('batch_2'));
|
||||
$messages = array_merge($messages, $this->_resultMessages('batch_3'));
|
||||
break;
|
||||
}
|
||||
return $messages;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests for the Batch API Progress page.
|
||||
*/
|
||||
class BatchPageTestCase extends DrupalWebTestCase {
|
||||
public static function getInfo() {
|
||||
return array(
|
||||
'name' => 'Batch progress page',
|
||||
'description' => 'Test the content of the progress page.',
|
||||
'group' => 'Batch API',
|
||||
);
|
||||
}
|
||||
|
||||
function setUp() {
|
||||
parent::setUp('batch_test');
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests that the batch API progress page uses the correct theme.
|
||||
*/
|
||||
function testBatchProgressPageTheme() {
|
||||
// Make sure that the page which starts the batch (an administrative page)
|
||||
// is using a different theme than would normally be used by the batch API.
|
||||
variable_set('theme_default', 'bartik');
|
||||
variable_set('admin_theme', 'seven');
|
||||
// Log in as an administrator who can see the administrative theme.
|
||||
$admin_user = $this->drupalCreateUser(array('view the administration theme'));
|
||||
$this->drupalLogin($admin_user);
|
||||
// Visit an administrative page that runs a test batch, and check that the
|
||||
// theme that was used during batch execution (which the batch callback
|
||||
// function saved as a variable) matches the theme used on the
|
||||
// administrative page.
|
||||
$this->drupalGet('admin/batch-test/test-theme');
|
||||
// The stack should contain the name of the theme used on the progress
|
||||
// page.
|
||||
$this->assertEqual(batch_test_stack(), array('seven'), t('A progressive batch correctly uses the theme of the page that started the batch.'));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests the function _batch_api_percentage() to make sure that the rounding
|
||||
* works properly in all cases.
|
||||
*/
|
||||
class BatchPercentagesUnitTestCase extends DrupalUnitTestCase {
|
||||
protected $testCases = array();
|
||||
|
||||
public static function getInfo() {
|
||||
return array(
|
||||
'name' => 'Batch percentages',
|
||||
'description' => 'Unit tests of progress percentage rounding.',
|
||||
'group' => 'Batch API',
|
||||
);
|
||||
}
|
||||
|
||||
function setUp() {
|
||||
// Set up an array of test cases, where the expected values are the keys,
|
||||
// and the values are arrays with the keys 'total' and 'current',
|
||||
// corresponding with the function parameters of _batch_api_percentage().
|
||||
$this->testCases = array(
|
||||
// 1/2 is 50%.
|
||||
'50' => array('total' => 2, 'current' => 1),
|
||||
// Though we should never encounter a case where the current set is set
|
||||
// 0, if we did, we should get 0%.
|
||||
'0' => array('total' => 3, 'current' => 0),
|
||||
// 1/3 is closer to 33% than to 34%.
|
||||
'33' => array('total' => 3, 'current' => 1),
|
||||
// 2/3 is closer to 67% than to 66%.
|
||||
'67' => array('total' => 3, 'current' => 2),
|
||||
// 1/199 should round up to 1%.
|
||||
'1' => array('total' => 199, 'current' => 1),
|
||||
// 198/199 should round down to 99%.
|
||||
'99' => array('total' => 199, 'current' => 198),
|
||||
// 199/200 would have rounded up to 100%, which would give the false
|
||||
// impression of being finished, so we add another digit and should get
|
||||
// 99.5%.
|
||||
'99.5' => array('total' => 200, 'current' => 199),
|
||||
// The same logic holds for 1/200: we should get 0.5%.
|
||||
'0.5' => array('total' => 200, 'current' => 1),
|
||||
// Numbers that come out evenly, such as 50/200, should be forced to have
|
||||
// extra digits for consistancy.
|
||||
'25.0' => array('total' => 200, 'current' => 50),
|
||||
// Regardless of number of digits we're using, 100% should always just be
|
||||
// 100%.
|
||||
'100' => array('total' => 200, 'current' => 200),
|
||||
// 1998/1999 should similarly round down to 99.9%.
|
||||
'99.9' => array('total' => 1999, 'current' => 1998),
|
||||
// 1999/2000 should add another digit and go to 99.95%.
|
||||
'99.95' => array('total' => 2000, 'current' => 1999),
|
||||
// 19999/20000 should add yet another digit and go to 99.995%.
|
||||
'99.995' => array('total' => 20000, 'current' => 19999),
|
||||
// The next five test cases simulate a batch with a single operation
|
||||
// ('total' equals 1) that takes several steps to complete. Within the
|
||||
// operation, we imagine that there are 501 items to process, and 100 are
|
||||
// completed during each step. The percentages we get back should be
|
||||
// rounded the usual way for the first few passes (i.e., 20%, 40%, etc.),
|
||||
// but for the last pass through, when 500 out of 501 items have been
|
||||
// processed, we do not want to round up to 100%, since that would
|
||||
// erroneously indicate that the processing is complete.
|
||||
'20' => array('total' => 1, 'current' => 100/501),
|
||||
'40' => array('total' => 1, 'current' => 200/501),
|
||||
'60' => array('total' => 1, 'current' => 300/501),
|
||||
'80' => array('total' => 1, 'current' => 400/501),
|
||||
'99.8' => array('total' => 1, 'current' => 500/501),
|
||||
);
|
||||
require_once DRUPAL_ROOT . '/includes/batch.inc';
|
||||
parent::setUp();
|
||||
}
|
||||
|
||||
/**
|
||||
* Test the _batch_api_percentage() function.
|
||||
*/
|
||||
function testBatchPercentages() {
|
||||
foreach ($this->testCases as $expected_result => $arguments) {
|
||||
// PHP sometimes casts numeric strings that are array keys to integers,
|
||||
// cast them back here.
|
||||
$expected_result = (string) $expected_result;
|
||||
$total = $arguments['total'];
|
||||
$current = $arguments['current'];
|
||||
$actual_result = _batch_api_percentage($total, $current);
|
||||
if ($actual_result === $expected_result) {
|
||||
$this->pass(t('Expected the batch api percentage at the state @numerator/@denominator to be @expected%, and got @actual%.', array('@numerator' => $current, '@denominator' => $total, '@expected' => $expected_result, '@actual' => $actual_result)));
|
||||
}
|
||||
else {
|
||||
$this->fail(t('Expected the batch api percentage at the state @numerator/@denominator to be @expected%, but got @actual%.', array('@numerator' => $current, '@denominator' => $total, '@expected' => $expected_result, '@actual' => $actual_result)));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
163
modules/simpletest/tests/batch_test.callbacks.inc
Normal file
163
modules/simpletest/tests/batch_test.callbacks.inc
Normal file
|
@ -0,0 +1,163 @@
|
|||
<?php
|
||||
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Batch callbacks for the Batch API tests.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Implements callback_batch_operation().
|
||||
*
|
||||
* Simple batch operation.
|
||||
*/
|
||||
function _batch_test_callback_1($id, $sleep, &$context) {
|
||||
// No-op, but ensure the batch take a couple iterations.
|
||||
// Batch needs time to run for the test, so sleep a bit.
|
||||
usleep($sleep);
|
||||
// Track execution, and store some result for post-processing in the
|
||||
// 'finished' callback.
|
||||
batch_test_stack("op 1 id $id");
|
||||
$context['results'][1][] = $id;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements callback_batch_operation().
|
||||
*
|
||||
* Multistep batch operation.
|
||||
*/
|
||||
function _batch_test_callback_2($start, $total, $sleep, &$context) {
|
||||
// Initialize context with progress information.
|
||||
if (!isset($context['sandbox']['current'])) {
|
||||
$context['sandbox']['current'] = $start;
|
||||
$context['sandbox']['count'] = 0;
|
||||
}
|
||||
|
||||
// Process by groups of 5 (arbitrary value).
|
||||
$limit = 5;
|
||||
for ($i = 0; $i < $limit && $context['sandbox']['count'] < $total; $i++) {
|
||||
// No-op, but ensure the batch take a couple iterations.
|
||||
// Batch needs time to run for the test, so sleep a bit.
|
||||
usleep($sleep);
|
||||
// Track execution, and store some result for post-processing in the
|
||||
// 'finished' callback.
|
||||
$id = $context['sandbox']['current'] + $i;
|
||||
batch_test_stack("op 2 id $id");
|
||||
$context['results'][2][] = $id;
|
||||
|
||||
// Update progress information.
|
||||
$context['sandbox']['count']++;
|
||||
}
|
||||
$context['sandbox']['current'] += $i;
|
||||
|
||||
// Inform batch engine about progress.
|
||||
if ($context['sandbox']['count'] != $total) {
|
||||
$context['finished'] = $context['sandbox']['count'] / $total;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements callback_batch_operation().
|
||||
*
|
||||
* Simple batch operation.
|
||||
*/
|
||||
function _batch_test_callback_5($id, $sleep, &$context) {
|
||||
// No-op, but ensure the batch take a couple iterations.
|
||||
// Batch needs time to run for the test, so sleep a bit.
|
||||
usleep($sleep);
|
||||
// Track execution, and store some result for post-processing in the
|
||||
// 'finished' callback.
|
||||
batch_test_stack("op 5 id $id");
|
||||
$context['results'][5][] = $id;
|
||||
// This test is to test finished > 1
|
||||
$context['finished'] = 3.14;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements callback_batch_operation().
|
||||
*
|
||||
* Batch operation setting up its own batch.
|
||||
*/
|
||||
function _batch_test_nested_batch_callback() {
|
||||
batch_test_stack('setting up batch 2');
|
||||
batch_set(_batch_test_batch_2());
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements callback_batch_finished().
|
||||
*
|
||||
* Common 'finished' callbacks for batches 1 to 4.
|
||||
*/
|
||||
function _batch_test_finished_helper($batch_id, $success, $results, $operations) {
|
||||
$messages = array("results for batch $batch_id");
|
||||
if ($results) {
|
||||
foreach ($results as $op => $op_results) {
|
||||
$messages[] = 'op '. $op . ': processed ' . count($op_results) . ' elements';
|
||||
}
|
||||
}
|
||||
else {
|
||||
$messages[] = 'none';
|
||||
}
|
||||
|
||||
if (!$success) {
|
||||
// A fatal error occurred during the processing.
|
||||
$error_operation = reset($operations);
|
||||
$messages[] = t('An error occurred while processing @op with arguments:<br/>@args', array('@op' => $error_operation[0], '@args' => print_r($error_operation[1], TRUE)));
|
||||
}
|
||||
|
||||
drupal_set_message(implode('<br />', $messages));
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements callback_batch_finished().
|
||||
*
|
||||
* 'finished' callback for batch 0.
|
||||
*/
|
||||
function _batch_test_finished_0($success, $results, $operations) {
|
||||
_batch_test_finished_helper(0, $success, $results, $operations);
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements callback_batch_finished().
|
||||
*
|
||||
* 'finished' callback for batch 1.
|
||||
*/
|
||||
function _batch_test_finished_1($success, $results, $operations) {
|
||||
_batch_test_finished_helper(1, $success, $results, $operations);
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements callback_batch_finished().
|
||||
*
|
||||
* 'finished' callback for batch 2.
|
||||
*/
|
||||
function _batch_test_finished_2($success, $results, $operations) {
|
||||
_batch_test_finished_helper(2, $success, $results, $operations);
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements callback_batch_finished().
|
||||
*
|
||||
* 'finished' callback for batch 3.
|
||||
*/
|
||||
function _batch_test_finished_3($success, $results, $operations) {
|
||||
_batch_test_finished_helper(3, $success, $results, $operations);
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements callback_batch_finished().
|
||||
*
|
||||
* 'finished' callback for batch 4.
|
||||
*/
|
||||
function _batch_test_finished_4($success, $results, $operations) {
|
||||
_batch_test_finished_helper(4, $success, $results, $operations);
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements callback_batch_finished().
|
||||
*
|
||||
* 'finished' callback for batch 5.
|
||||
*/
|
||||
function _batch_test_finished_5($success, $results, $operations) {
|
||||
_batch_test_finished_helper(5, $success, $results, $operations);
|
||||
}
|
12
modules/simpletest/tests/batch_test.info
Normal file
12
modules/simpletest/tests/batch_test.info
Normal file
|
@ -0,0 +1,12 @@
|
|||
name = "Batch API test"
|
||||
description = "Support module for Batch API tests."
|
||||
package = Testing
|
||||
version = VERSION
|
||||
core = 7.x
|
||||
hidden = TRUE
|
||||
|
||||
; Information added by Drupal.org packaging script on 2017-06-21
|
||||
version = "7.56"
|
||||
project = "drupal"
|
||||
datestamp = "1498069849"
|
||||
|
513
modules/simpletest/tests/batch_test.module
Normal file
513
modules/simpletest/tests/batch_test.module
Normal file
|
@ -0,0 +1,513 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Helper module for the Batch API tests.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Implement hook_menu().
|
||||
*/
|
||||
function batch_test_menu() {
|
||||
$items = array();
|
||||
|
||||
$items['batch-test'] = array(
|
||||
'title' => 'Batch test',
|
||||
'page callback' => 'drupal_get_form',
|
||||
'page arguments' => array('batch_test_simple_form'),
|
||||
'access callback' => TRUE,
|
||||
);
|
||||
// Simple form: one submit handler, setting a batch.
|
||||
$items['batch-test/simple'] = array(
|
||||
'title' => 'Simple',
|
||||
'type' => MENU_DEFAULT_LOCAL_TASK,
|
||||
'weight' => 0,
|
||||
);
|
||||
// Multistep form: two steps, each setting a batch.
|
||||
$items['batch-test/multistep'] = array(
|
||||
'title' => 'Multistep',
|
||||
'page callback' => 'drupal_get_form',
|
||||
'page arguments' => array('batch_test_multistep_form'),
|
||||
'access callback' => TRUE,
|
||||
'type' => MENU_LOCAL_TASK,
|
||||
'weight' => 1,
|
||||
);
|
||||
// Chained form: four submit handlers, several of which set a batch.
|
||||
$items['batch-test/chained'] = array(
|
||||
'title' => 'Chained',
|
||||
'page callback' => 'drupal_get_form',
|
||||
'page arguments' => array('batch_test_chained_form'),
|
||||
'access callback' => TRUE,
|
||||
'type' => MENU_LOCAL_TASK,
|
||||
'weight' => 2,
|
||||
);
|
||||
// Programmatic form: the page submits the 'Chained' form through
|
||||
// drupal_form_submit().
|
||||
$items['batch-test/programmatic'] = array(
|
||||
'title' => 'Programmatic',
|
||||
'page callback' => 'batch_test_programmatic',
|
||||
'access callback' => TRUE,
|
||||
'type' => MENU_LOCAL_TASK,
|
||||
'weight' => 3,
|
||||
);
|
||||
// No form: fire a batch simply by accessing a page.
|
||||
$items['batch-test/no-form'] = array(
|
||||
'title' => 'Simple page',
|
||||
'page callback' => 'batch_test_no_form',
|
||||
'access callback' => TRUE,
|
||||
'type' => MENU_LOCAL_TASK,
|
||||
'weight' => 4,
|
||||
);
|
||||
// No form: fire a batch; return > 100% complete
|
||||
$items['batch-test/large-percentage'] = array(
|
||||
'title' => 'Simple page with batch over 100% complete',
|
||||
'page callback' => 'batch_test_large_percentage',
|
||||
'access callback' => TRUE,
|
||||
'type' => MENU_LOCAL_TASK,
|
||||
'weight' => 5,
|
||||
);
|
||||
// Tests programmatic form submission within a batch operation.
|
||||
$items['batch-test/nested-programmatic'] = array(
|
||||
'title' => 'Nested programmatic',
|
||||
'page callback' => 'batch_test_nested_drupal_form_submit',
|
||||
'access callback' => TRUE,
|
||||
'type' => MENU_LOCAL_TASK,
|
||||
'weight' => 6,
|
||||
);
|
||||
// Landing page to test redirects.
|
||||
$items['batch-test/redirect'] = array(
|
||||
'title' => 'Redirect',
|
||||
'page callback' => 'batch_test_redirect_page',
|
||||
'access callback' => TRUE,
|
||||
'type' => MENU_LOCAL_TASK,
|
||||
'weight' => 7,
|
||||
);
|
||||
// This item lives under 'admin' so that the page uses the admin theme.
|
||||
$items['admin/batch-test/test-theme'] = array(
|
||||
'page callback' => 'batch_test_theme_batch',
|
||||
'access callback' => TRUE,
|
||||
'type' => MENU_CALLBACK,
|
||||
);
|
||||
|
||||
return $items;
|
||||
}
|
||||
|
||||
/**
|
||||
* Simple form.
|
||||
*/
|
||||
function batch_test_simple_form() {
|
||||
$form['batch'] = array(
|
||||
'#type' => 'select',
|
||||
'#title' => 'Choose batch',
|
||||
'#options' => array(
|
||||
'batch_0' => 'batch 0',
|
||||
'batch_1' => 'batch 1',
|
||||
'batch_2' => 'batch 2',
|
||||
'batch_3' => 'batch 3',
|
||||
'batch_4' => 'batch 4',
|
||||
),
|
||||
);
|
||||
$form['submit'] = array(
|
||||
'#type' => 'submit',
|
||||
'#value' => 'Submit',
|
||||
);
|
||||
|
||||
return $form;
|
||||
}
|
||||
|
||||
/**
|
||||
* Submit handler for the simple form.
|
||||
*/
|
||||
function batch_test_simple_form_submit($form, &$form_state) {
|
||||
batch_test_stack(NULL, TRUE);
|
||||
|
||||
$function = '_batch_test_' . $form_state['values']['batch'];
|
||||
batch_set($function());
|
||||
|
||||
$form_state['redirect'] = 'batch-test/redirect';
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Multistep form.
|
||||
*/
|
||||
function batch_test_multistep_form($form, &$form_state) {
|
||||
if (empty($form_state['storage']['step'])) {
|
||||
$form_state['storage']['step'] = 1;
|
||||
}
|
||||
|
||||
$form['step_display'] = array(
|
||||
'#markup' => 'step ' . $form_state['storage']['step'] . '<br/>',
|
||||
);
|
||||
$form['submit'] = array(
|
||||
'#type' => 'submit',
|
||||
'#value' => 'Submit',
|
||||
);
|
||||
|
||||
return $form;
|
||||
}
|
||||
|
||||
/**
|
||||
* Submit handler for the multistep form.
|
||||
*/
|
||||
function batch_test_multistep_form_submit($form, &$form_state) {
|
||||
batch_test_stack(NULL, TRUE);
|
||||
|
||||
switch ($form_state['storage']['step']) {
|
||||
case 1:
|
||||
batch_set(_batch_test_batch_1());
|
||||
break;
|
||||
case 2:
|
||||
batch_set(_batch_test_batch_2());
|
||||
break;
|
||||
}
|
||||
|
||||
if ($form_state['storage']['step'] < 2) {
|
||||
$form_state['storage']['step']++;
|
||||
$form_state['rebuild'] = TRUE;
|
||||
}
|
||||
|
||||
// This will only be effective on the last step.
|
||||
$form_state['redirect'] = 'batch-test/redirect';
|
||||
}
|
||||
|
||||
/**
|
||||
* Form with chained submit callbacks.
|
||||
*/
|
||||
function batch_test_chained_form() {
|
||||
// This value is used to test that $form_state persists through batched
|
||||
// submit handlers.
|
||||
$form['value'] = array(
|
||||
'#type' => 'textfield',
|
||||
'#title' => 'Value',
|
||||
'#default_value' => 1,
|
||||
);
|
||||
$form['submit'] = array(
|
||||
'#type' => 'submit',
|
||||
'#value' => 'Submit',
|
||||
);
|
||||
$form['#submit'] = array(
|
||||
'batch_test_chained_form_submit_1',
|
||||
'batch_test_chained_form_submit_2',
|
||||
'batch_test_chained_form_submit_3',
|
||||
'batch_test_chained_form_submit_4',
|
||||
);
|
||||
|
||||
return $form;
|
||||
}
|
||||
|
||||
/**
|
||||
* Submit handler #1 for the chained form.
|
||||
*/
|
||||
function batch_test_chained_form_submit_1($form, &$form_state) {
|
||||
batch_test_stack(NULL, TRUE);
|
||||
|
||||
batch_test_stack('submit handler 1');
|
||||
batch_test_stack('value = ' . $form_state['values']['value']);
|
||||
|
||||
$form_state['values']['value']++;
|
||||
batch_set(_batch_test_batch_1());
|
||||
|
||||
// This redirect should not be taken into account.
|
||||
$form_state['redirect'] = 'should/be/discarded';
|
||||
}
|
||||
|
||||
/**
|
||||
* Submit handler #2 for the chained form.
|
||||
*/
|
||||
function batch_test_chained_form_submit_2($form, &$form_state) {
|
||||
batch_test_stack('submit handler 2');
|
||||
batch_test_stack('value = ' . $form_state['values']['value']);
|
||||
|
||||
$form_state['values']['value']++;
|
||||
batch_set(_batch_test_batch_2());
|
||||
|
||||
// This redirect should not be taken into account.
|
||||
$form_state['redirect'] = 'should/be/discarded';
|
||||
}
|
||||
|
||||
/**
|
||||
* Submit handler #3 for the chained form.
|
||||
*/
|
||||
function batch_test_chained_form_submit_3($form, &$form_state) {
|
||||
batch_test_stack('submit handler 3');
|
||||
batch_test_stack('value = ' . $form_state['values']['value']);
|
||||
|
||||
$form_state['values']['value']++;
|
||||
|
||||
// This redirect should not be taken into account.
|
||||
$form_state['redirect'] = 'should/be/discarded';
|
||||
}
|
||||
|
||||
/**
|
||||
* Submit handler #4 for the chained form.
|
||||
*/
|
||||
function batch_test_chained_form_submit_4($form, &$form_state) {
|
||||
batch_test_stack('submit handler 4');
|
||||
batch_test_stack('value = ' . $form_state['values']['value']);
|
||||
|
||||
$form_state['values']['value']++;
|
||||
batch_set(_batch_test_batch_3());
|
||||
|
||||
// This is the redirect that should prevail.
|
||||
$form_state['redirect'] = 'batch-test/redirect';
|
||||
}
|
||||
|
||||
/**
|
||||
* Menu callback: programmatically submits the 'Chained' form.
|
||||
*/
|
||||
function batch_test_programmatic($value = 1) {
|
||||
$form_state = array(
|
||||
'values' => array('value' => $value)
|
||||
);
|
||||
drupal_form_submit('batch_test_chained_form', $form_state);
|
||||
return 'Got out of a programmatic batched form.';
|
||||
}
|
||||
|
||||
/**
|
||||
* Menu callback: programmatically submits a form within a batch.
|
||||
*/
|
||||
function batch_test_nested_drupal_form_submit($value = 1) {
|
||||
// Set the batch and process it.
|
||||
$batch['operations'] = array(
|
||||
array('_batch_test_nested_drupal_form_submit_callback', array($value)),
|
||||
);
|
||||
batch_set($batch);
|
||||
batch_process('batch-test/redirect');
|
||||
}
|
||||
|
||||
/**
|
||||
* Batch operation: submits form_test_mock_form using drupal_form_submit().
|
||||
*/
|
||||
function _batch_test_nested_drupal_form_submit_callback($value) {
|
||||
$state['values']['test_value'] = $value;
|
||||
drupal_form_submit('batch_test_mock_form', $state);
|
||||
}
|
||||
|
||||
/**
|
||||
* A simple form with a textfield and submit button.
|
||||
*/
|
||||
function batch_test_mock_form($form, $form_state) {
|
||||
$form['test_value'] = array(
|
||||
'#type' => 'textfield',
|
||||
);
|
||||
$form['submit'] = array(
|
||||
'#type' => 'submit',
|
||||
'#value' => t('Submit'),
|
||||
);
|
||||
|
||||
return $form;
|
||||
}
|
||||
|
||||
/**
|
||||
* Submit handler for the batch_test_mock form.
|
||||
*/
|
||||
function batch_test_mock_form_submit($form, &$form_state) {
|
||||
batch_test_stack('mock form submitted with value = ' . $form_state['values']['test_value']);
|
||||
}
|
||||
|
||||
/**
|
||||
* Menu callback: fire a batch process without a form submission.
|
||||
*/
|
||||
function batch_test_no_form() {
|
||||
batch_test_stack(NULL, TRUE);
|
||||
|
||||
batch_set(_batch_test_batch_1());
|
||||
batch_process('batch-test/redirect');
|
||||
}
|
||||
|
||||
/**
|
||||
* Menu callback: fire a batch process without a form submission.
|
||||
*/
|
||||
function batch_test_large_percentage() {
|
||||
batch_test_stack(NULL, TRUE);
|
||||
|
||||
batch_set(_batch_test_batch_5());
|
||||
batch_process('batch-test/redirect');
|
||||
}
|
||||
|
||||
/**
|
||||
* Menu callback: successful redirection.
|
||||
*/
|
||||
function batch_test_redirect_page() {
|
||||
return 'Redirection successful.';
|
||||
}
|
||||
|
||||
/**
|
||||
* Batch 0: no operation.
|
||||
*/
|
||||
function _batch_test_batch_0() {
|
||||
$batch = array(
|
||||
'operations' => array(),
|
||||
'finished' => '_batch_test_finished_0',
|
||||
'file' => drupal_get_path('module', 'batch_test'). '/batch_test.callbacks.inc',
|
||||
);
|
||||
return $batch;
|
||||
}
|
||||
|
||||
/**
|
||||
* Batch 1: repeats a simple operation.
|
||||
*
|
||||
* Operations: op 1 from 1 to 10.
|
||||
*/
|
||||
function _batch_test_batch_1() {
|
||||
// Ensure the batch takes at least two iterations.
|
||||
$total = 10;
|
||||
$sleep = (1000000 / $total) * 2;
|
||||
|
||||
$operations = array();
|
||||
for ($i = 1; $i <= $total; $i++) {
|
||||
$operations[] = array('_batch_test_callback_1', array($i, $sleep));
|
||||
}
|
||||
$batch = array(
|
||||
'operations' => $operations,
|
||||
'finished' => '_batch_test_finished_1',
|
||||
'file' => drupal_get_path('module', 'batch_test'). '/batch_test.callbacks.inc',
|
||||
);
|
||||
return $batch;
|
||||
}
|
||||
|
||||
/**
|
||||
* Batch 2: single multistep operation.
|
||||
*
|
||||
* Operations: op 2 from 1 to 10.
|
||||
*/
|
||||
function _batch_test_batch_2() {
|
||||
// Ensure the batch takes at least two iterations.
|
||||
$total = 10;
|
||||
$sleep = (1000000 / $total) * 2;
|
||||
|
||||
$operations = array(
|
||||
array('_batch_test_callback_2', array(1, $total, $sleep)),
|
||||
);
|
||||
$batch = array(
|
||||
'operations' => $operations,
|
||||
'finished' => '_batch_test_finished_2',
|
||||
'file' => drupal_get_path('module', 'batch_test') . '/batch_test.callbacks.inc',
|
||||
);
|
||||
return $batch;
|
||||
}
|
||||
|
||||
/**
|
||||
* Batch 3: both single and multistep operations.
|
||||
*
|
||||
* Operations:
|
||||
* - op 1 from 1 to 5,
|
||||
* - op 2 from 1 to 5,
|
||||
* - op 1 from 6 to 10,
|
||||
* - op 2 from 6 to 10.
|
||||
*/
|
||||
function _batch_test_batch_3() {
|
||||
// Ensure the batch takes at least two iterations.
|
||||
$total = 10;
|
||||
$sleep = (1000000 / $total) * 2;
|
||||
|
||||
$operations = array();
|
||||
for ($i = 1; $i <= round($total / 2); $i++) {
|
||||
$operations[] = array('_batch_test_callback_1', array($i, $sleep));
|
||||
}
|
||||
$operations[] = array('_batch_test_callback_2', array(1, $total / 2, $sleep));
|
||||
for ($i = round($total / 2) + 1; $i <= $total; $i++) {
|
||||
$operations[] = array('_batch_test_callback_1', array($i, $sleep));
|
||||
}
|
||||
$operations[] = array('_batch_test_callback_2', array(6, $total / 2, $sleep));
|
||||
$batch = array(
|
||||
'operations' => $operations,
|
||||
'finished' => '_batch_test_finished_3',
|
||||
'file' => drupal_get_path('module', 'batch_test') . '/batch_test.callbacks.inc',
|
||||
);
|
||||
return $batch;
|
||||
}
|
||||
|
||||
/**
|
||||
* Batch 4: batch within a batch.
|
||||
*
|
||||
* Operations:
|
||||
* - op 1 from 1 to 5,
|
||||
* - set batch 2 (op 2 from 1 to 10, should run at the end)
|
||||
* - op 1 from 6 to 10,
|
||||
*/
|
||||
function _batch_test_batch_4() {
|
||||
// Ensure the batch takes at least two iterations.
|
||||
$total = 10;
|
||||
$sleep = (1000000 / $total) * 2;
|
||||
|
||||
$operations = array();
|
||||
for ($i = 1; $i <= round($total / 2); $i++) {
|
||||
$operations[] = array('_batch_test_callback_1', array($i, $sleep));
|
||||
}
|
||||
$operations[] = array('_batch_test_nested_batch_callback', array());
|
||||
for ($i = round($total / 2) + 1; $i <= $total; $i++) {
|
||||
$operations[] = array('_batch_test_callback_1', array($i, $sleep));
|
||||
}
|
||||
$batch = array(
|
||||
'operations' => $operations,
|
||||
'finished' => '_batch_test_finished_4',
|
||||
'file' => drupal_get_path('module', 'batch_test') . '/batch_test.callbacks.inc',
|
||||
);
|
||||
return $batch;
|
||||
}
|
||||
|
||||
/**
|
||||
* Batch 5: repeats a simple operation.
|
||||
*
|
||||
* Operations: op 1 from 1 to 10.
|
||||
*/
|
||||
function _batch_test_batch_5() {
|
||||
// Ensure the batch takes at least two iterations.
|
||||
$total = 10;
|
||||
$sleep = (1000000 / $total) * 2;
|
||||
|
||||
$operations = array();
|
||||
for ($i = 1; $i <= $total; $i++) {
|
||||
$operations[] = array('_batch_test_callback_5', array($i, $sleep));
|
||||
}
|
||||
$batch = array(
|
||||
'operations' => $operations,
|
||||
'finished' => '_batch_test_finished_5',
|
||||
'file' => drupal_get_path('module', 'batch_test'). '/batch_test.callbacks.inc',
|
||||
);
|
||||
return $batch;
|
||||
}
|
||||
|
||||
/**
|
||||
* Menu callback: run a batch for testing theme used on the progress page.
|
||||
*/
|
||||
function batch_test_theme_batch() {
|
||||
batch_test_stack(NULL, TRUE);
|
||||
$batch = array(
|
||||
'operations' => array(
|
||||
array('_batch_test_theme_callback', array()),
|
||||
),
|
||||
);
|
||||
batch_set($batch);
|
||||
batch_process('batch-test/redirect');
|
||||
}
|
||||
|
||||
/**
|
||||
* Batch callback function for testing the theme used on the progress page.
|
||||
*/
|
||||
function _batch_test_theme_callback() {
|
||||
// Because drupalGet() steps through the full progressive batch before
|
||||
// returning control to the test function, we cannot test that the correct
|
||||
// theme is being used on the batch processing page by viewing that page
|
||||
// directly. Instead, we save the theme being used in a variable here, so
|
||||
// that it can be loaded and inspected in the thread running the test.
|
||||
global $theme;
|
||||
batch_test_stack($theme);
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper function: store or retrieve traced execution data.
|
||||
*/
|
||||
function batch_test_stack($data = NULL, $reset = FALSE) {
|
||||
if ($reset) {
|
||||
variable_del('batch_test_stack');
|
||||
}
|
||||
if (!isset($data)) {
|
||||
return variable_get('batch_test_stack', array());
|
||||
}
|
||||
$stack = variable_get('batch_test_stack', array());
|
||||
$stack[] = $data;
|
||||
variable_set('batch_test_stack', $stack);
|
||||
}
|
38
modules/simpletest/tests/boot.test
Normal file
38
modules/simpletest/tests/boot.test
Normal file
|
@ -0,0 +1,38 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* Perform early bootstrap tests.
|
||||
*/
|
||||
class EarlyBootstrapTestCase extends DrupalWebTestCase {
|
||||
public static function getInfo() {
|
||||
return array(
|
||||
'name' => 'Early bootstrap test',
|
||||
'description' => 'Confirm that calling module_implements() during early bootstrap does not pollute the module_implements() cache.',
|
||||
'group' => 'System',
|
||||
);
|
||||
}
|
||||
|
||||
function setUp() {
|
||||
parent::setUp('boot_test_1', 'boot_test_2');
|
||||
}
|
||||
|
||||
/**
|
||||
* Test hook_boot() on both regular and "early exit" pages.
|
||||
*/
|
||||
public function testHookBoot() {
|
||||
$paths = array('', 'early_exit');
|
||||
foreach ($paths as $path) {
|
||||
// Empty the module_implements() caches.
|
||||
module_implements(NULL, FALSE, TRUE);
|
||||
// Do a request to the front page, which will call module_implements()
|
||||
// during hook_boot().
|
||||
$this->drupalGet($path);
|
||||
// Reset the static cache so we get implementation data from the persistent
|
||||
// cache.
|
||||
drupal_static_reset();
|
||||
// Make sure we get a full list of all modules implementing hook_help().
|
||||
$modules = module_implements('help');
|
||||
$this->assertTrue(in_array('boot_test_2', $modules));
|
||||
}
|
||||
}
|
||||
}
|
12
modules/simpletest/tests/boot_test_1.info
Normal file
12
modules/simpletest/tests/boot_test_1.info
Normal file
|
@ -0,0 +1,12 @@
|
|||
name = Early bootstrap tests
|
||||
description = A support module for hook_boot testing.
|
||||
core = 7.x
|
||||
package = Testing
|
||||
version = VERSION
|
||||
hidden = TRUE
|
||||
|
||||
; Information added by Drupal.org packaging script on 2017-06-21
|
||||
version = "7.56"
|
||||
project = "drupal"
|
||||
datestamp = "1498069849"
|
||||
|
21
modules/simpletest/tests/boot_test_1.module
Normal file
21
modules/simpletest/tests/boot_test_1.module
Normal file
|
@ -0,0 +1,21 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Tests calling module_implements() during hook_boot() invocation.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Implements hook_boot().
|
||||
*/
|
||||
function boot_test_1_boot() {
|
||||
// Calling module_implements during hook_boot() will return "vital" modules
|
||||
// only, and this list of modules will be statically cached.
|
||||
module_implements('help');
|
||||
// Define a special path to test that the static cache isn't written away
|
||||
// if we exit before having completed the bootstrap.
|
||||
if ($_GET['q'] == 'early_exit') {
|
||||
module_implements_write_cache();
|
||||
exit();
|
||||
}
|
||||
}
|
12
modules/simpletest/tests/boot_test_2.info
Normal file
12
modules/simpletest/tests/boot_test_2.info
Normal file
|
@ -0,0 +1,12 @@
|
|||
name = Early bootstrap tests
|
||||
description = A support module for hook_boot hook testing.
|
||||
core = 7.x
|
||||
package = Testing
|
||||
version = VERSION
|
||||
hidden = TRUE
|
||||
|
||||
; Information added by Drupal.org packaging script on 2017-06-21
|
||||
version = "7.56"
|
||||
project = "drupal"
|
||||
datestamp = "1498069849"
|
||||
|
13
modules/simpletest/tests/boot_test_2.module
Normal file
13
modules/simpletest/tests/boot_test_2.module
Normal file
|
@ -0,0 +1,13 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Defines a hook_help() implementation in a non-"bootstrap" module.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Implements hook_help().
|
||||
*/
|
||||
function boot_test_2_help($path, $arg) {
|
||||
// Empty hook.
|
||||
}
|
878
modules/simpletest/tests/bootstrap.test
Normal file
878
modules/simpletest/tests/bootstrap.test
Normal file
|
@ -0,0 +1,878 @@
|
|||
<?php
|
||||
|
||||
class BootstrapIPAddressTestCase extends DrupalWebTestCase {
|
||||
|
||||
public static function getInfo() {
|
||||
return array(
|
||||
'name' => 'IP address and HTTP_HOST test',
|
||||
'description' => 'Get the IP address from the current visitor from the server variables, check hostname validation.',
|
||||
'group' => 'Bootstrap'
|
||||
);
|
||||
}
|
||||
|
||||
function setUp() {
|
||||
$this->oldserver = $_SERVER;
|
||||
|
||||
$this->remote_ip = '127.0.0.1';
|
||||
$this->proxy_ip = '127.0.0.2';
|
||||
$this->proxy2_ip = '127.0.0.3';
|
||||
$this->forwarded_ip = '127.0.0.4';
|
||||
$this->cluster_ip = '127.0.0.5';
|
||||
$this->untrusted_ip = '0.0.0.0';
|
||||
|
||||
drupal_static_reset('ip_address');
|
||||
|
||||
$_SERVER['REMOTE_ADDR'] = $this->remote_ip;
|
||||
unset($_SERVER['HTTP_X_FORWARDED_FOR']);
|
||||
unset($_SERVER['HTTP_X_CLUSTER_CLIENT_IP']);
|
||||
|
||||
parent::setUp();
|
||||
}
|
||||
|
||||
function tearDown() {
|
||||
$_SERVER = $this->oldserver;
|
||||
drupal_static_reset('ip_address');
|
||||
parent::tearDown();
|
||||
}
|
||||
|
||||
/**
|
||||
* test IP Address and hostname
|
||||
*/
|
||||
function testIPAddressHost() {
|
||||
// Test the normal IP address.
|
||||
$this->assertTrue(
|
||||
ip_address() == $this->remote_ip,
|
||||
'Got remote IP address.'
|
||||
);
|
||||
|
||||
// Proxy forwarding on but no proxy addresses defined.
|
||||
variable_set('reverse_proxy', 1);
|
||||
$this->assertTrue(
|
||||
ip_address() == $this->remote_ip,
|
||||
'Proxy forwarding without trusted proxies got remote IP address.'
|
||||
);
|
||||
|
||||
// Proxy forwarding on and proxy address not trusted.
|
||||
variable_set('reverse_proxy_addresses', array($this->proxy_ip, $this->proxy2_ip));
|
||||
drupal_static_reset('ip_address');
|
||||
$_SERVER['REMOTE_ADDR'] = $this->untrusted_ip;
|
||||
$this->assertTrue(
|
||||
ip_address() == $this->untrusted_ip,
|
||||
'Proxy forwarding with untrusted proxy got remote IP address.'
|
||||
);
|
||||
|
||||
// Proxy forwarding on and proxy address trusted.
|
||||
$_SERVER['REMOTE_ADDR'] = $this->proxy_ip;
|
||||
$_SERVER['HTTP_X_FORWARDED_FOR'] = $this->forwarded_ip;
|
||||
drupal_static_reset('ip_address');
|
||||
$this->assertTrue(
|
||||
ip_address() == $this->forwarded_ip,
|
||||
'Proxy forwarding with trusted proxy got forwarded IP address.'
|
||||
);
|
||||
|
||||
// Proxy forwarding on and proxy address trusted and visiting from proxy.
|
||||
$_SERVER['REMOTE_ADDR'] = $this->proxy_ip;
|
||||
$_SERVER['HTTP_X_FORWARDED_FOR'] = $this->proxy_ip;
|
||||
drupal_static_reset('ip_address');
|
||||
$this->assertTrue(
|
||||
ip_address() == $this->proxy_ip,
|
||||
'Visiting from trusted proxy got proxy IP address.'
|
||||
);
|
||||
|
||||
// Multi-tier architecture with comma separated values in header.
|
||||
$_SERVER['REMOTE_ADDR'] = $this->proxy_ip;
|
||||
$_SERVER['HTTP_X_FORWARDED_FOR'] = implode(', ', array($this->untrusted_ip, $this->forwarded_ip, $this->proxy2_ip));
|
||||
drupal_static_reset('ip_address');
|
||||
$this->assertTrue(
|
||||
ip_address() == $this->forwarded_ip,
|
||||
'Proxy forwarding with trusted 2-tier proxy got forwarded IP address.'
|
||||
);
|
||||
|
||||
// Custom client-IP header.
|
||||
variable_set('reverse_proxy_header', 'HTTP_X_CLUSTER_CLIENT_IP');
|
||||
$_SERVER['HTTP_X_CLUSTER_CLIENT_IP'] = $this->cluster_ip;
|
||||
drupal_static_reset('ip_address');
|
||||
$this->assertTrue(
|
||||
ip_address() == $this->cluster_ip,
|
||||
'Cluster environment got cluster client IP.'
|
||||
);
|
||||
|
||||
// Verifies that drupal_valid_http_host() prevents invalid characters.
|
||||
$this->assertFalse(drupal_valid_http_host('security/.drupal.org:80'), 'HTTP_HOST with / is invalid');
|
||||
$this->assertFalse(drupal_valid_http_host('security\\.drupal.org:80'), 'HTTP_HOST with \\ is invalid');
|
||||
$this->assertFalse(drupal_valid_http_host('security<.drupal.org:80'), 'HTTP_HOST with < is invalid');
|
||||
$this->assertFalse(drupal_valid_http_host('security..drupal.org:80'), 'HTTP_HOST with .. is invalid');
|
||||
// Verifies that host names are shorter than 1000 characters.
|
||||
$this->assertFalse(drupal_valid_http_host(str_repeat('x', 1001)), 'HTTP_HOST with more than 1000 characters is invalid.');
|
||||
$this->assertFalse(drupal_valid_http_host(str_repeat('.', 101)), 'HTTP_HOST with more than 100 subdomains is invalid.');
|
||||
$this->assertFalse(drupal_valid_http_host(str_repeat(':', 101)), 'HTTP_HOST with more than 100 portseparators is invalid.');
|
||||
|
||||
// IPv6 loopback address
|
||||
$this->assertTrue(drupal_valid_http_host('[::1]:80'), 'HTTP_HOST containing IPv6 loopback is valid');
|
||||
}
|
||||
}
|
||||
|
||||
class BootstrapPageCacheTestCase extends DrupalWebTestCase {
|
||||
|
||||
public static function getInfo() {
|
||||
return array(
|
||||
'name' => 'Page cache test',
|
||||
'description' => 'Enable the page cache and test it with various HTTP requests.',
|
||||
'group' => 'Bootstrap'
|
||||
);
|
||||
}
|
||||
|
||||
function setUp() {
|
||||
parent::setUp('system_test');
|
||||
}
|
||||
|
||||
/**
|
||||
* Test support for requests containing If-Modified-Since and If-None-Match headers.
|
||||
*/
|
||||
function testConditionalRequests() {
|
||||
variable_set('cache', 1);
|
||||
|
||||
// Fill the cache.
|
||||
$this->drupalGet('');
|
||||
|
||||
$this->drupalHead('');
|
||||
$this->assertEqual($this->drupalGetHeader('X-Drupal-Cache'), 'HIT', 'Page was cached.');
|
||||
$etag = $this->drupalGetHeader('ETag');
|
||||
$last_modified = $this->drupalGetHeader('Last-Modified');
|
||||
|
||||
$this->drupalGet('', array(), array('If-Modified-Since: ' . $last_modified, 'If-None-Match: ' . $etag));
|
||||
$this->assertResponse(304, 'Conditional request returned 304 Not Modified.');
|
||||
|
||||
$this->drupalGet('', array(), array('If-Modified-Since: ' . gmdate(DATE_RFC822, strtotime($last_modified)), 'If-None-Match: ' . $etag));
|
||||
$this->assertResponse(304, 'Conditional request with obsolete If-Modified-Since date returned 304 Not Modified.');
|
||||
|
||||
$this->drupalGet('', array(), array('If-Modified-Since: ' . gmdate(DATE_RFC850, strtotime($last_modified)), 'If-None-Match: ' . $etag));
|
||||
$this->assertResponse(304, 'Conditional request with obsolete If-Modified-Since date returned 304 Not Modified.');
|
||||
|
||||
$this->drupalGet('', array(), array('If-Modified-Since: ' . $last_modified));
|
||||
$this->assertResponse(200, 'Conditional request without If-None-Match returned 200 OK.');
|
||||
$this->assertEqual($this->drupalGetHeader('X-Drupal-Cache'), 'HIT', 'Page was cached.');
|
||||
|
||||
$this->drupalGet('', array(), array('If-Modified-Since: ' . gmdate(DATE_RFC7231, strtotime($last_modified) + 1), 'If-None-Match: ' . $etag));
|
||||
$this->assertResponse(200, 'Conditional request with new a If-Modified-Since date newer than Last-Modified returned 200 OK.');
|
||||
$this->assertEqual($this->drupalGetHeader('X-Drupal-Cache'), 'HIT', 'Page was cached.');
|
||||
|
||||
$user = $this->drupalCreateUser();
|
||||
$this->drupalLogin($user);
|
||||
$this->drupalGet('', array(), array('If-Modified-Since: ' . $last_modified, 'If-None-Match: ' . $etag));
|
||||
$this->assertResponse(200, 'Conditional request returned 200 OK for authenticated user.');
|
||||
$this->assertFalse($this->drupalGetHeader('X-Drupal-Cache'), 'Absence of Page was not cached.');
|
||||
$this->assertFalse($this->drupalGetHeader('ETag'), 'ETag HTTP headers are not present for logged in users.');
|
||||
$this->assertFalse($this->drupalGetHeader('Last-Modified'), 'Last-Modified HTTP headers are not present for logged in users.');
|
||||
}
|
||||
|
||||
/**
|
||||
* Test cache headers.
|
||||
*/
|
||||
function testPageCache() {
|
||||
variable_set('cache', 1);
|
||||
|
||||
// Fill the cache.
|
||||
$this->drupalGet('system-test/set-header', array('query' => array('name' => 'Foo', 'value' => 'bar')));
|
||||
$this->assertEqual($this->drupalGetHeader('X-Drupal-Cache'), 'MISS', 'Page was not cached.');
|
||||
$this->assertEqual($this->drupalGetHeader('Vary'), 'Cookie,Accept-Encoding', 'Vary header was sent.');
|
||||
$this->assertEqual($this->drupalGetHeader('Cache-Control'), 'public, max-age=0', 'Cache-Control header was sent.');
|
||||
$this->assertEqual($this->drupalGetHeader('Expires'), 'Sun, 19 Nov 1978 05:00:00 GMT', 'Expires header was sent.');
|
||||
$this->assertEqual($this->drupalGetHeader('Foo'), 'bar', 'Custom header was sent.');
|
||||
|
||||
// Check cache.
|
||||
$this->drupalGet('system-test/set-header', array('query' => array('name' => 'Foo', 'value' => 'bar')));
|
||||
$this->assertEqual($this->drupalGetHeader('X-Drupal-Cache'), 'HIT', 'Page was cached.');
|
||||
$this->assertEqual($this->drupalGetHeader('Vary'), 'Cookie,Accept-Encoding', 'Vary: Cookie header was sent.');
|
||||
$this->assertEqual($this->drupalGetHeader('Cache-Control'), 'public, max-age=0', 'Cache-Control header was sent.');
|
||||
$this->assertEqual($this->drupalGetHeader('Expires'), 'Sun, 19 Nov 1978 05:00:00 GMT', 'Expires header was sent.');
|
||||
$this->assertEqual($this->drupalGetHeader('Foo'), 'bar', 'Custom header was sent.');
|
||||
|
||||
// Check replacing default headers.
|
||||
$this->drupalGet('system-test/set-header', array('query' => array('name' => 'Expires', 'value' => 'Fri, 19 Nov 2008 05:00:00 GMT')));
|
||||
$this->assertEqual($this->drupalGetHeader('Expires'), 'Fri, 19 Nov 2008 05:00:00 GMT', 'Default header was replaced.');
|
||||
$this->drupalGet('system-test/set-header', array('query' => array('name' => 'Vary', 'value' => 'User-Agent')));
|
||||
$this->assertEqual($this->drupalGetHeader('Vary'), 'User-Agent,Accept-Encoding', 'Default header was replaced.');
|
||||
|
||||
// Check that authenticated users bypass the cache.
|
||||
$user = $this->drupalCreateUser();
|
||||
$this->drupalLogin($user);
|
||||
$this->drupalGet('system-test/set-header', array('query' => array('name' => 'Foo', 'value' => 'bar')));
|
||||
$this->assertFalse($this->drupalGetHeader('X-Drupal-Cache'), 'Caching was bypassed.');
|
||||
$this->assertTrue(strpos($this->drupalGetHeader('Vary'), 'Cookie') === FALSE, 'Vary: Cookie header was not sent.');
|
||||
$this->assertEqual($this->drupalGetHeader('Cache-Control'), 'no-cache, must-revalidate', 'Cache-Control header was sent.');
|
||||
$this->assertEqual($this->drupalGetHeader('Expires'), 'Sun, 19 Nov 1978 05:00:00 GMT', 'Expires header was sent.');
|
||||
$this->assertEqual($this->drupalGetHeader('Foo'), 'bar', 'Custom header was sent.');
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Test page compression.
|
||||
*
|
||||
* The test should pass even if zlib.output_compression is enabled in php.ini,
|
||||
* .htaccess or similar, or if compression is done outside PHP, e.g. by the
|
||||
* mod_deflate Apache module.
|
||||
*/
|
||||
function testPageCompression() {
|
||||
variable_set('cache', 1);
|
||||
|
||||
// Fill the cache and verify that output is compressed.
|
||||
$this->drupalGet('', array(), array('Accept-Encoding: gzip,deflate'));
|
||||
$this->assertEqual($this->drupalGetHeader('X-Drupal-Cache'), 'MISS', 'Page was not cached.');
|
||||
$this->drupalSetContent(gzinflate(substr($this->drupalGetContent(), 10, -8)));
|
||||
$this->assertRaw('</html>', 'Page was gzip compressed.');
|
||||
|
||||
// Verify that cached output is compressed.
|
||||
$this->drupalGet('', array(), array('Accept-Encoding: gzip,deflate'));
|
||||
$this->assertEqual($this->drupalGetHeader('X-Drupal-Cache'), 'HIT', 'Page was cached.');
|
||||
$this->assertEqual($this->drupalGetHeader('Content-Encoding'), 'gzip', 'A Content-Encoding header was sent.');
|
||||
$this->drupalSetContent(gzinflate(substr($this->drupalGetContent(), 10, -8)));
|
||||
$this->assertRaw('</html>', 'Page was gzip compressed.');
|
||||
|
||||
// Verify that a client without compression support gets an uncompressed page.
|
||||
$this->drupalGet('');
|
||||
$this->assertEqual($this->drupalGetHeader('X-Drupal-Cache'), 'HIT', 'Page was cached.');
|
||||
$this->assertFalse($this->drupalGetHeader('Content-Encoding'), 'A Content-Encoding header was not sent.');
|
||||
$this->assertTitle(t('Welcome to @site-name | @site-name', array('@site-name' => variable_get('site_name', 'Drupal'))), 'Site title matches.');
|
||||
$this->assertRaw('</html>', 'Page was not compressed.');
|
||||
|
||||
// Disable compression mode.
|
||||
variable_set('page_compression', FALSE);
|
||||
|
||||
// Verify if cached page is still available for a client with compression support.
|
||||
$this->drupalGet('', array(), array('Accept-Encoding: gzip,deflate'));
|
||||
$this->drupalSetContent(gzinflate(substr($this->drupalGetContent(), 10, -8)));
|
||||
$this->assertRaw('</html>', 'Page was delivered after compression mode is changed (compression support enabled).');
|
||||
|
||||
// Verify if cached page is still available for a client without compression support.
|
||||
$this->drupalGet('');
|
||||
$this->assertRaw('</html>', 'Page was delivered after compression mode is changed (compression support disabled).');
|
||||
}
|
||||
}
|
||||
|
||||
class BootstrapVariableTestCase extends DrupalWebTestCase {
|
||||
|
||||
function setUp() {
|
||||
parent::setUp('system_test');
|
||||
}
|
||||
|
||||
public static function getInfo() {
|
||||
return array(
|
||||
'name' => 'Variable test',
|
||||
'description' => 'Make sure the variable system functions correctly.',
|
||||
'group' => 'Bootstrap'
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* testVariable
|
||||
*/
|
||||
function testVariable() {
|
||||
// Setting and retrieving values.
|
||||
$variable = $this->randomName();
|
||||
variable_set('simpletest_bootstrap_variable_test', $variable);
|
||||
$this->assertIdentical($variable, variable_get('simpletest_bootstrap_variable_test'), 'Setting and retrieving values');
|
||||
|
||||
// Make sure the variable persists across multiple requests.
|
||||
$this->drupalGet('system-test/variable-get');
|
||||
$this->assertText($variable, 'Variable persists across multiple requests');
|
||||
|
||||
// Deleting variables.
|
||||
$default_value = $this->randomName();
|
||||
variable_del('simpletest_bootstrap_variable_test');
|
||||
$variable = variable_get('simpletest_bootstrap_variable_test', $default_value);
|
||||
$this->assertIdentical($variable, $default_value, 'Deleting variables');
|
||||
}
|
||||
|
||||
/**
|
||||
* Makes sure that the default variable parameter is passed through okay.
|
||||
*/
|
||||
function testVariableDefaults() {
|
||||
// Tests passing nothing through to the default.
|
||||
$this->assertIdentical(NULL, variable_get('simpletest_bootstrap_variable_test'), 'Variables are correctly defaulting to NULL.');
|
||||
|
||||
// Tests passing 5 to the default parameter.
|
||||
$this->assertIdentical(5, variable_get('simpletest_bootstrap_variable_test', 5), 'The default variable parameter is passed through correctly.');
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests the auto-loading behavior of the code registry.
|
||||
*/
|
||||
class BootstrapAutoloadTestCase extends DrupalWebTestCase {
|
||||
|
||||
public static function getInfo() {
|
||||
return array(
|
||||
'name' => 'Code registry',
|
||||
'description' => 'Test that the code registry functions correctly.',
|
||||
'group' => 'Bootstrap',
|
||||
);
|
||||
}
|
||||
|
||||
function setUp() {
|
||||
parent::setUp('drupal_autoload_test');
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests that autoloader name matching is not case sensitive.
|
||||
*/
|
||||
function testAutoloadCase() {
|
||||
// Test interface autoloader.
|
||||
$this->assertTrue(drupal_autoload_interface('drupalautoloadtestinterface'), 'drupal_autoload_interface() recognizes <em>DrupalAutoloadTestInterface</em> in lower case.');
|
||||
// Test class autoloader.
|
||||
$this->assertTrue(drupal_autoload_class('drupalautoloadtestclass'), 'drupal_autoload_class() recognizes <em>DrupalAutoloadTestClass</em> in lower case.');
|
||||
// Test trait autoloader.
|
||||
if (version_compare(PHP_VERSION, '5.4') >= 0) {
|
||||
$this->assertTrue(drupal_autoload_trait('drupalautoloadtesttrait'), 'drupal_autoload_trait() recognizes <em>DrupalAutoloadTestTrait</em> in lower case.');
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Test hook_boot() and hook_exit().
|
||||
*/
|
||||
class HookBootExitTestCase extends DrupalWebTestCase {
|
||||
|
||||
public static function getInfo() {
|
||||
return array(
|
||||
'name' => 'Boot and exit hook invocation',
|
||||
'description' => 'Test that hook_boot() and hook_exit() are called correctly.',
|
||||
'group' => 'Bootstrap',
|
||||
);
|
||||
}
|
||||
|
||||
function setUp() {
|
||||
parent::setUp('system_test', 'dblog');
|
||||
}
|
||||
|
||||
/**
|
||||
* Test calling of hook_boot() and hook_exit().
|
||||
*/
|
||||
function testHookBootExit() {
|
||||
// Test with cache disabled. Boot and exit should always fire.
|
||||
variable_set('cache', 0);
|
||||
$this->drupalGet('');
|
||||
$calls = 1;
|
||||
$this->assertEqual(db_query('SELECT COUNT(*) FROM {watchdog} WHERE type = :type AND message = :message', array(':type' => 'system_test', ':message' => 'hook_boot'))->fetchField(), $calls, t('hook_boot called with disabled cache.'));
|
||||
$this->assertEqual(db_query('SELECT COUNT(*) FROM {watchdog} WHERE type = :type AND message = :message', array(':type' => 'system_test', ':message' => 'hook_exit'))->fetchField(), $calls, t('hook_exit called with disabled cache.'));
|
||||
|
||||
// Test with normal cache. Boot and exit should be called.
|
||||
variable_set('cache', 1);
|
||||
$this->drupalGet('');
|
||||
$calls++;
|
||||
$this->assertEqual(db_query('SELECT COUNT(*) FROM {watchdog} WHERE type = :type AND message = :message', array(':type' => 'system_test', ':message' => 'hook_boot'))->fetchField(), $calls, t('hook_boot called with normal cache.'));
|
||||
$this->assertEqual(db_query('SELECT COUNT(*) FROM {watchdog} WHERE type = :type AND message = :message', array(':type' => 'system_test', ':message' => 'hook_exit'))->fetchField(), $calls, t('hook_exit called with normal cache.'));
|
||||
|
||||
// Boot and exit should not fire since the page is cached.
|
||||
variable_set('page_cache_invoke_hooks', FALSE);
|
||||
$this->assertTrue(cache_get(url('', array('absolute' => TRUE)), 'cache_page'), t('Page has been cached.'));
|
||||
$this->drupalGet('');
|
||||
$this->assertEqual(db_query('SELECT COUNT(*) FROM {watchdog} WHERE type = :type AND message = :message', array(':type' => 'system_test', ':message' => 'hook_boot'))->fetchField(), $calls, t('hook_boot not called with aggressive cache and a cached page.'));
|
||||
$this->assertEqual(db_query('SELECT COUNT(*) FROM {watchdog} WHERE type = :type AND message = :message', array(':type' => 'system_test', ':message' => 'hook_exit'))->fetchField(), $calls, t('hook_exit not called with aggressive cache and a cached page.'));
|
||||
|
||||
// Test with page cache cleared, boot and exit should be called.
|
||||
$this->assertTrue(db_delete('cache_page')->execute(), t('Page cache cleared.'));
|
||||
$this->drupalGet('');
|
||||
$calls++;
|
||||
$this->assertEqual(db_query('SELECT COUNT(*) FROM {watchdog} WHERE type = :type AND message = :message', array(':type' => 'system_test', ':message' => 'hook_boot'))->fetchField(), $calls, t('hook_boot called with aggressive cache and no cached page.'));
|
||||
$this->assertEqual(db_query('SELECT COUNT(*) FROM {watchdog} WHERE type = :type AND message = :message', array(':type' => 'system_test', ':message' => 'hook_exit'))->fetchField(), $calls, t('hook_exit called with aggressive cache and no cached page.'));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Test drupal_get_filename()'s availability.
|
||||
*/
|
||||
class BootstrapGetFilenameTestCase extends DrupalUnitTestCase {
|
||||
|
||||
public static function getInfo() {
|
||||
return array(
|
||||
'name' => 'Get filename test (without the system table)',
|
||||
'description' => 'Test that drupal_get_filename() works correctly when the database is not available.',
|
||||
'group' => 'Bootstrap',
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* The last file-related error message triggered by the filename test.
|
||||
*
|
||||
* Used by BootstrapGetFilenameTestCase::testDrupalGetFilename().
|
||||
*/
|
||||
protected $getFilenameTestTriggeredError;
|
||||
|
||||
/**
|
||||
* Test that drupal_get_filename() works correctly when the file is not found in the database.
|
||||
*/
|
||||
function testDrupalGetFilename() {
|
||||
// Reset the static cache so we can test the "db is not active" code of
|
||||
// drupal_get_filename().
|
||||
drupal_static_reset('drupal_get_filename');
|
||||
|
||||
// Retrieving the location of a module.
|
||||
$this->assertIdentical(drupal_get_filename('module', 'php'), 'modules/php/php.module', t('Retrieve module location.'));
|
||||
|
||||
// Retrieving the location of a theme.
|
||||
$this->assertIdentical(drupal_get_filename('theme', 'stark'), 'themes/stark/stark.info', t('Retrieve theme location.'));
|
||||
|
||||
// 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 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.'));
|
||||
|
||||
// When searching for a module that does not exist, drupal_get_filename()
|
||||
// should return NULL and trigger an appropriate error message.
|
||||
$this->getFilenameTestTriggeredError = NULL;
|
||||
set_error_handler(array($this, 'fileNotFoundErrorHandler'));
|
||||
$non_existing_module = $this->randomName();
|
||||
$this->assertNull(drupal_get_filename('module', $non_existing_module), 'Searching for a module that does not exist returns NULL.');
|
||||
$this->assertTrue(strpos($this->getFilenameTestTriggeredError, format_string('The following module is missing from the file system: %name', array('%name' => $non_existing_module))) === 0, 'Searching for an item that does not exist triggers the correct error.');
|
||||
restore_error_handler();
|
||||
|
||||
// Check that the result is stored in the file system scan cache.
|
||||
$file_scans = _drupal_file_scan_cache();
|
||||
$this->assertIdentical($file_scans['module'][$non_existing_module], FALSE, 'Searching for a module that does not exist creates a record in the missing and moved files static variable.');
|
||||
|
||||
// Performing the search again in the same request still should not find
|
||||
// the file, but the error message should not be repeated (therefore we do
|
||||
// not override the error handler here).
|
||||
$this->assertNull(drupal_get_filename('module', $non_existing_module), 'Searching for a module that does not exist returns NULL during the second search.');
|
||||
}
|
||||
|
||||
/**
|
||||
* Skips handling of "file not found" errors.
|
||||
*/
|
||||
public function fileNotFoundErrorHandler($error_level, $message, $filename, $line, $context) {
|
||||
// Skip error handling if this is a "file not found" error.
|
||||
if (strpos($message, 'is missing from the file system:') !== FALSE || strpos($message, 'has moved within the file system:') !== FALSE) {
|
||||
$this->getFilenameTestTriggeredError = $message;
|
||||
return;
|
||||
}
|
||||
_drupal_error_handler($error_level, $message, $filename, $line, $context);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Test drupal_get_filename() in the context of a full Drupal installation.
|
||||
*/
|
||||
class BootstrapGetFilenameWebTestCase extends DrupalWebTestCase {
|
||||
|
||||
public static function getInfo() {
|
||||
return array(
|
||||
'name' => 'Get filename test (full installation)',
|
||||
'description' => 'Test that drupal_get_filename() works correctly in the context of a full Drupal installation.',
|
||||
'group' => 'Bootstrap',
|
||||
);
|
||||
}
|
||||
|
||||
function setUp() {
|
||||
parent::setUp('system_test');
|
||||
}
|
||||
|
||||
/**
|
||||
* The last file-related error message triggered by the filename test.
|
||||
*
|
||||
* Used by BootstrapGetFilenameWebTestCase::testDrupalGetFilename().
|
||||
*/
|
||||
protected $getFilenameTestTriggeredError;
|
||||
|
||||
/**
|
||||
* Test that drupal_get_filename() works correctly with a full Drupal site.
|
||||
*/
|
||||
function testDrupalGetFilename() {
|
||||
// Search for a module that exists in the file system and the {system}
|
||||
// table and make sure that it is found.
|
||||
$this->assertIdentical(drupal_get_filename('module', 'node'), 'modules/node/node.module', 'Module found at expected location.');
|
||||
|
||||
// Search for a module that does not exist in either the file system or the
|
||||
// {system} table. Make sure that an appropriate error is triggered and
|
||||
// that the module winds up in the static and persistent cache.
|
||||
$this->getFilenameTestTriggeredError = NULL;
|
||||
set_error_handler(array($this, 'fileNotFoundErrorHandler'));
|
||||
$non_existing_module = $this->randomName();
|
||||
$this->assertNull(drupal_get_filename('module', $non_existing_module), 'Searching for a module that does not exist returns NULL.');
|
||||
$this->assertTrue(strpos($this->getFilenameTestTriggeredError, format_string('The following module is missing from the file system: %name', array('%name' => $non_existing_module))) === 0, 'Searching for a module that does not exist triggers the correct error.');
|
||||
restore_error_handler();
|
||||
$file_scans = _drupal_file_scan_cache();
|
||||
$this->assertIdentical($file_scans['module'][$non_existing_module], FALSE, 'Searching for a module that does not exist creates a record in the missing and moved files static variable.');
|
||||
drupal_file_scan_write_cache();
|
||||
$cache = cache_get('_drupal_file_scan_cache', 'cache_bootstrap');
|
||||
$this->assertIdentical($cache->data['module'][$non_existing_module], FALSE, 'Searching for a module that does not exist creates a record in the missing and moved files persistent cache.');
|
||||
|
||||
// Simulate moving a module to a location that does not match the location
|
||||
// in the {system} table and perform similar tests as above.
|
||||
db_update('system')
|
||||
->fields(array('filename' => 'modules/simpletest/tests/fake_location/module_test.module'))
|
||||
->condition('name', 'module_test')
|
||||
->condition('type', 'module')
|
||||
->execute();
|
||||
$this->getFilenameTestTriggeredError = NULL;
|
||||
set_error_handler(array($this, 'fileNotFoundErrorHandler'));
|
||||
$this->assertIdentical(drupal_get_filename('module', 'module_test'), 'modules/simpletest/tests/module_test.module', 'Searching for a module that has moved finds the module at its new location.');
|
||||
$this->assertTrue(strpos($this->getFilenameTestTriggeredError, format_string('The following module has moved within the file system: %name', array('%name' => 'module_test'))) === 0, 'Searching for a module that has moved triggers the correct error.');
|
||||
restore_error_handler();
|
||||
$file_scans = _drupal_file_scan_cache();
|
||||
$this->assertIdentical($file_scans['module']['module_test'], 'modules/simpletest/tests/module_test.module', 'Searching for a module that has moved creates a record in the missing and moved files static variable.');
|
||||
drupal_file_scan_write_cache();
|
||||
$cache = cache_get('_drupal_file_scan_cache', 'cache_bootstrap');
|
||||
$this->assertIdentical($cache->data['module']['module_test'], 'modules/simpletest/tests/module_test.module', 'Searching for a module that has moved creates a record in the missing and moved files persistent cache.');
|
||||
|
||||
// Simulate a module that exists in the {system} table but does not exist
|
||||
// in the file system and perform similar tests as above.
|
||||
$non_existing_module = $this->randomName();
|
||||
db_update('system')
|
||||
->fields(array('name' => $non_existing_module))
|
||||
->condition('name', 'module_test')
|
||||
->condition('type', 'module')
|
||||
->execute();
|
||||
$this->getFilenameTestTriggeredError = NULL;
|
||||
set_error_handler(array($this, 'fileNotFoundErrorHandler'));
|
||||
$this->assertNull(drupal_get_filename('module', $non_existing_module), 'Searching for a module that exists in the system table but not in the file system returns NULL.');
|
||||
$this->assertTrue(strpos($this->getFilenameTestTriggeredError, format_string('The following module is missing from the file system: %name', array('%name' => $non_existing_module))) === 0, 'Searching for a module that exists in the system table but not in the file system triggers the correct error.');
|
||||
restore_error_handler();
|
||||
$file_scans = _drupal_file_scan_cache();
|
||||
$this->assertIdentical($file_scans['module'][$non_existing_module], FALSE, 'Searching for a module that exists in the system table but not in the file system creates a record in the missing and moved files static variable.');
|
||||
drupal_file_scan_write_cache();
|
||||
$cache = cache_get('_drupal_file_scan_cache', 'cache_bootstrap');
|
||||
$this->assertIdentical($cache->data['module'][$non_existing_module], FALSE, 'Searching for a module that exists in the system table but not in the file system creates a record in the missing and moved files persistent cache.');
|
||||
|
||||
// Simulate a module that exists in the file system but not in the {system}
|
||||
// table and perform similar tests as above.
|
||||
db_delete('system')
|
||||
->condition('name', 'common_test')
|
||||
->condition('type', 'module')
|
||||
->execute();
|
||||
system_list_reset();
|
||||
$this->getFilenameTestTriggeredError = NULL;
|
||||
set_error_handler(array($this, 'fileNotFoundErrorHandler'));
|
||||
$this->assertIdentical(drupal_get_filename('module', 'common_test'), 'modules/simpletest/tests/common_test.module', 'Searching for a module that does not exist in the system table finds the module at its actual location.');
|
||||
$this->assertTrue(strpos($this->getFilenameTestTriggeredError, format_string('The following module has moved within the file system: %name', array('%name' => 'common_test'))) === 0, 'Searching for a module that does not exist in the system table triggers the correct error.');
|
||||
restore_error_handler();
|
||||
$file_scans = _drupal_file_scan_cache();
|
||||
$this->assertIdentical($file_scans['module']['common_test'], 'modules/simpletest/tests/common_test.module', 'Searching for a module that does not exist in the system table creates a record in the missing and moved files static variable.');
|
||||
drupal_file_scan_write_cache();
|
||||
$cache = cache_get('_drupal_file_scan_cache', 'cache_bootstrap');
|
||||
$this->assertIdentical($cache->data['module']['common_test'], 'modules/simpletest/tests/common_test.module', 'Searching for a module that does not exist in the system table creates a record in the missing and moved files persistent cache.');
|
||||
}
|
||||
|
||||
/**
|
||||
* Skips handling of "file not found" errors.
|
||||
*/
|
||||
public function fileNotFoundErrorHandler($error_level, $message, $filename, $line, $context) {
|
||||
// Skip error handling if this is a "file not found" error.
|
||||
if (strpos($message, 'is missing from the file system:') !== FALSE || strpos($message, 'has moved within the file system:') !== FALSE) {
|
||||
$this->getFilenameTestTriggeredError = $message;
|
||||
return;
|
||||
}
|
||||
_drupal_error_handler($error_level, $message, $filename, $line, $context);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test that watchdog messages about missing files are correctly recorded.
|
||||
*/
|
||||
public function testWatchdog() {
|
||||
// Search for a module that does not exist in either the file system or the
|
||||
// {system} table. Make sure that an appropriate warning is recorded in the
|
||||
// logs.
|
||||
$non_existing_module = $this->randomName();
|
||||
$query_parameters = array(
|
||||
':type' => 'php',
|
||||
':severity' => WATCHDOG_WARNING,
|
||||
);
|
||||
$this->assertEqual(db_query('SELECT COUNT(*) FROM {watchdog} WHERE type = :type AND severity = :severity', $query_parameters)->fetchField(), 0, 'No warning message appears in the logs before searching for a module that does not exist.');
|
||||
// Trigger the drupal_get_filename() call. This must be done via a request
|
||||
// to a separate URL since the watchdog() will happen in a shutdown
|
||||
// function, and so that SimpleTest can be told to ignore (and not fail as
|
||||
// a result of) the expected PHP warnings generated during this process.
|
||||
variable_set('system_test_drupal_get_filename_test_module_name', $non_existing_module);
|
||||
$this->drupalGet('system-test/drupal-get-filename');
|
||||
$message_variables = db_query('SELECT variables FROM {watchdog} WHERE type = :type AND severity = :severity', $query_parameters)->fetchCol();
|
||||
$this->assertEqual(count($message_variables), 1, 'A single warning message appears in the logs after searching for a module that does not exist.');
|
||||
$variables = reset($message_variables);
|
||||
$variables = unserialize($variables);
|
||||
$this->assertTrue(isset($variables['!message']) && strpos($variables['!message'], format_string('The following module is missing from the file system: %name', array('%name' => $non_existing_module))) !== FALSE, 'The warning message that appears in the logs after searching for a module that does not exist contains the expected text.');
|
||||
}
|
||||
|
||||
/**
|
||||
* Test that drupal_get_filename() does not break recursive rebuilds.
|
||||
*/
|
||||
public function testRecursiveRebuilds() {
|
||||
// Ensure that the drupal_get_filename() call due to a missing module does
|
||||
// not break the data returned by an attempted recursive rebuild. The code
|
||||
// path which is tested is as follows:
|
||||
// - Call drupal_get_schema().
|
||||
// - Within a hook_schema() implementation, trigger a drupal_get_filename()
|
||||
// search for a nonexistent module.
|
||||
// - In the watchdog() call that results from that, trigger
|
||||
// drupal_get_schema() again.
|
||||
// Without some kind of recursion protection, this could cause the second
|
||||
// drupal_get_schema() call to return incomplete results. This test ensures
|
||||
// that does not happen.
|
||||
$non_existing_module = $this->randomName();
|
||||
variable_set('system_test_drupal_get_filename_test_module_name', $non_existing_module);
|
||||
$this->drupalGet('system-test/drupal-get-filename-with-schema-rebuild');
|
||||
$original_drupal_get_schema_tables = variable_get('system_test_drupal_get_filename_with_schema_rebuild_original_tables');
|
||||
$final_drupal_get_schema_tables = variable_get('system_test_drupal_get_filename_with_schema_rebuild_final_tables');
|
||||
$this->assertTrue(!empty($original_drupal_get_schema_tables));
|
||||
$this->assertTrue(!empty($final_drupal_get_schema_tables));
|
||||
$this->assertEqual($original_drupal_get_schema_tables, $final_drupal_get_schema_tables);
|
||||
}
|
||||
}
|
||||
|
||||
class BootstrapTimerTestCase extends DrupalUnitTestCase {
|
||||
|
||||
public static function getInfo() {
|
||||
return array(
|
||||
'name' => 'Timer test',
|
||||
'description' => 'Test that timer_read() works both when a timer is running and when a timer is stopped.',
|
||||
'group' => 'Bootstrap',
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test timer_read() to ensure it properly accumulates time when the timer
|
||||
* started and stopped multiple times.
|
||||
* @return
|
||||
*/
|
||||
function testTimer() {
|
||||
timer_start('test');
|
||||
sleep(1);
|
||||
$this->assertTrue(timer_read('test') >= 1000, 'Timer measured 1 second of sleeping while running.');
|
||||
sleep(1);
|
||||
timer_stop('test');
|
||||
$this->assertTrue(timer_read('test') >= 2000, 'Timer measured 2 seconds of sleeping after being stopped.');
|
||||
timer_start('test');
|
||||
sleep(1);
|
||||
$this->assertTrue(timer_read('test') >= 3000, 'Timer measured 3 seconds of sleeping after being restarted.');
|
||||
sleep(1);
|
||||
$timer = timer_stop('test');
|
||||
$this->assertTrue(timer_read('test') >= 4000, 'Timer measured 4 seconds of sleeping after being stopped for a second time.');
|
||||
$this->assertEqual($timer['count'], 2, 'Timer counted 2 instances of being started.');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Test that resetting static variables works.
|
||||
*/
|
||||
class BootstrapResettableStaticTestCase extends DrupalUnitTestCase {
|
||||
|
||||
public static function getInfo() {
|
||||
return array(
|
||||
'name' => 'Resettable static variables test',
|
||||
'description' => 'Test that drupal_static() and drupal_static_reset() work.',
|
||||
'group' => 'Bootstrap',
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test that a variable reference returned by drupal_static() gets reset when
|
||||
* drupal_static_reset() is called.
|
||||
*/
|
||||
function testDrupalStatic() {
|
||||
$name = __CLASS__ . '_' . __METHOD__;
|
||||
$var = &drupal_static($name, 'foo');
|
||||
$this->assertEqual($var, 'foo', 'Variable returned by drupal_static() was set to its default.');
|
||||
|
||||
// Call the specific reset and the global reset each twice to ensure that
|
||||
// multiple resets can be issued without odd side effects.
|
||||
$var = 'bar';
|
||||
drupal_static_reset($name);
|
||||
$this->assertEqual($var, 'foo', 'Variable was reset after first invocation of name-specific reset.');
|
||||
$var = 'bar';
|
||||
drupal_static_reset($name);
|
||||
$this->assertEqual($var, 'foo', 'Variable was reset after second invocation of name-specific reset.');
|
||||
$var = 'bar';
|
||||
drupal_static_reset();
|
||||
$this->assertEqual($var, 'foo', 'Variable was reset after first invocation of global reset.');
|
||||
$var = 'bar';
|
||||
drupal_static_reset();
|
||||
$this->assertEqual($var, 'foo', 'Variable was reset after second invocation of global reset.');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Test miscellaneous functions in bootstrap.inc.
|
||||
*/
|
||||
class BootstrapMiscTestCase extends DrupalUnitTestCase {
|
||||
|
||||
public static function getInfo() {
|
||||
return array(
|
||||
'name' => 'Miscellaneous bootstrap unit tests',
|
||||
'description' => 'Test miscellaneous functions in bootstrap.inc.',
|
||||
'group' => 'Bootstrap',
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test miscellaneous functions in bootstrap.inc.
|
||||
*/
|
||||
function testMisc() {
|
||||
// Test drupal_array_merge_deep().
|
||||
$link_options_1 = array('fragment' => 'x', 'attributes' => array('title' => 'X', 'class' => array('a', 'b')), 'language' => 'en');
|
||||
$link_options_2 = array('fragment' => 'y', 'attributes' => array('title' => 'Y', 'class' => array('c', 'd')), 'html' => TRUE);
|
||||
$expected = array('fragment' => 'y', 'attributes' => array('title' => 'Y', 'class' => array('a', 'b', 'c', 'd')), 'language' => 'en', 'html' => TRUE);
|
||||
$this->assertIdentical(drupal_array_merge_deep($link_options_1, $link_options_2), $expected, 'drupal_array_merge_deep() returned a properly merged array.');
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests that the drupal_check_memory_limit() function works as expected.
|
||||
*/
|
||||
function testCheckMemoryLimit() {
|
||||
$memory_limit = ini_get('memory_limit');
|
||||
// Test that a very reasonable amount of memory is available.
|
||||
$this->assertTrue(drupal_check_memory_limit('30MB'), '30MB of memory tested available.');
|
||||
|
||||
// Get the available memory and multiply it by two to make it unreasonably
|
||||
// high.
|
||||
$twice_avail_memory = ($memory_limit * 2) . 'MB';
|
||||
|
||||
// The function should always return true if the memory limit is set to -1.
|
||||
$this->assertTrue(drupal_check_memory_limit($twice_avail_memory, -1), 'drupal_check_memory_limit() returns TRUE when a limit of -1 (none) is supplied');
|
||||
|
||||
// Test that even though we have 30MB of memory available - the function
|
||||
// returns FALSE when given an upper limit for how much memory can be used.
|
||||
$this->assertFalse(drupal_check_memory_limit('30MB', '16MB'), 'drupal_check_memory_limit() returns FALSE with a 16MB upper limit on a 30MB requirement.');
|
||||
|
||||
// Test that an equal amount of memory to the amount requested returns TRUE.
|
||||
$this->assertTrue(drupal_check_memory_limit('30MB', '30MB'), 'drupal_check_memory_limit() returns TRUE when requesting 30MB on a 30MB requirement.');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests for overriding server variables via the API.
|
||||
*/
|
||||
class BootstrapOverrideServerVariablesTestCase extends DrupalUnitTestCase {
|
||||
public static function getInfo() {
|
||||
return array(
|
||||
'name' => 'Overriding server variables',
|
||||
'description' => 'Test that drupal_override_server_variables() works correctly.',
|
||||
'group' => 'Bootstrap',
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test providing a direct URL to to drupal_override_server_variables().
|
||||
*/
|
||||
function testDrupalOverrideServerVariablesProvidedURL() {
|
||||
$tests = array(
|
||||
'http://example.com' => array(
|
||||
'HTTP_HOST' => 'example.com',
|
||||
'SCRIPT_NAME' => isset($_SERVER['SCRIPT_NAME']) ? $_SERVER['SCRIPT_NAME'] : NULL,
|
||||
),
|
||||
'http://example.com/index.php' => array(
|
||||
'HTTP_HOST' => 'example.com',
|
||||
'SCRIPT_NAME' => '/index.php',
|
||||
),
|
||||
'http://example.com/subdirectory/index.php' => array(
|
||||
'HTTP_HOST' => 'example.com',
|
||||
'SCRIPT_NAME' => '/subdirectory/index.php',
|
||||
),
|
||||
);
|
||||
foreach ($tests as $url => $expected_server_values) {
|
||||
// Remember the original value of $_SERVER, since the function call below
|
||||
// will modify it.
|
||||
$original_server = $_SERVER;
|
||||
// Call drupal_override_server_variables() and ensure that all expected
|
||||
// $_SERVER variables were modified correctly.
|
||||
drupal_override_server_variables(array('url' => $url));
|
||||
foreach ($expected_server_values as $key => $value) {
|
||||
$this->assertIdentical($_SERVER[$key], $value);
|
||||
}
|
||||
// Restore the original value of $_SERVER.
|
||||
$_SERVER = $original_server;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests for $_GET['destination'] and $_REQUEST['destination'] validation.
|
||||
*/
|
||||
class BootstrapDestinationTestCase extends DrupalWebTestCase {
|
||||
|
||||
public static function getInfo() {
|
||||
return array(
|
||||
'name' => 'URL destination validation',
|
||||
'description' => 'Test that $_GET[\'destination\'] and $_REQUEST[\'destination\'] cannot contain external URLs.',
|
||||
'group' => 'Bootstrap',
|
||||
);
|
||||
}
|
||||
|
||||
function setUp() {
|
||||
parent::setUp('system_test');
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests that $_GET/$_REQUEST['destination'] only contain internal URLs.
|
||||
*
|
||||
* @see _drupal_bootstrap_variables()
|
||||
* @see system_test_get_destination()
|
||||
* @see system_test_request_destination()
|
||||
*/
|
||||
public function testDestination() {
|
||||
$test_cases = array(
|
||||
array(
|
||||
'input' => 'node',
|
||||
'output' => 'node',
|
||||
'message' => "Standard internal example node path is present in the 'destination' parameter.",
|
||||
),
|
||||
array(
|
||||
'input' => '/example.com',
|
||||
'output' => '/example.com',
|
||||
'message' => 'Internal path with one leading slash is allowed.',
|
||||
),
|
||||
array(
|
||||
'input' => '//example.com/test',
|
||||
'output' => '',
|
||||
'message' => 'External URL without scheme is not allowed.',
|
||||
),
|
||||
array(
|
||||
'input' => 'example:test',
|
||||
'output' => 'example:test',
|
||||
'message' => 'Internal URL using a colon is allowed.',
|
||||
),
|
||||
array(
|
||||
'input' => 'http://example.com',
|
||||
'output' => '',
|
||||
'message' => 'External URL is not allowed.',
|
||||
),
|
||||
array(
|
||||
'input' => 'javascript:alert(0)',
|
||||
'output' => 'javascript:alert(0)',
|
||||
'message' => 'Javascript URL is allowed because it is treated as an internal URL.',
|
||||
),
|
||||
);
|
||||
foreach ($test_cases as $test_case) {
|
||||
// Test $_GET['destination'].
|
||||
$this->drupalGet('system-test/get-destination', array('query' => array('destination' => $test_case['input'])));
|
||||
$this->assertIdentical($test_case['output'], $this->drupalGetContent(), $test_case['message']);
|
||||
// Test $_REQUEST['destination']. There's no form to submit to, so
|
||||
// drupalPost() won't work here; this just tests a direct $_POST request
|
||||
// instead.
|
||||
$curl_parameters = array(
|
||||
CURLOPT_URL => $this->getAbsoluteUrl('system-test/request-destination'),
|
||||
CURLOPT_POST => TRUE,
|
||||
CURLOPT_POSTFIELDS => 'destination=' . urlencode($test_case['input']),
|
||||
CURLOPT_HTTPHEADER => array(),
|
||||
);
|
||||
$post_output = $this->curlExec($curl_parameters);
|
||||
$this->assertIdentical($test_case['output'], $post_output, $test_case['message']);
|
||||
}
|
||||
|
||||
// Make sure that 404 pages do not populate $_GET['destination'] with
|
||||
// external URLs.
|
||||
variable_set('site_404', 'system-test/get-destination');
|
||||
$this->drupalGet('http://example.com', array('external' => FALSE));
|
||||
$this->assertIdentical('', $this->drupalGetContent(), 'External URL is not allowed on 404 pages.');
|
||||
}
|
||||
}
|
437
modules/simpletest/tests/cache.test
Normal file
437
modules/simpletest/tests/cache.test
Normal file
|
@ -0,0 +1,437 @@
|
|||
<?php
|
||||
|
||||
class CacheTestCase extends DrupalWebTestCase {
|
||||
protected $default_bin = 'cache';
|
||||
protected $default_cid = 'test_temporary';
|
||||
protected $default_value = 'CacheTest';
|
||||
|
||||
/**
|
||||
* Check whether or not a cache entry exists.
|
||||
*
|
||||
* @param $cid
|
||||
* The cache id.
|
||||
* @param $var
|
||||
* The variable the cache should contain.
|
||||
* @param $bin
|
||||
* The bin the cache item was stored in.
|
||||
* @return
|
||||
* TRUE on pass, FALSE on fail.
|
||||
*/
|
||||
protected function checkCacheExists($cid, $var, $bin = NULL) {
|
||||
if ($bin == NULL) {
|
||||
$bin = $this->default_bin;
|
||||
}
|
||||
|
||||
$cache = cache_get($cid, $bin);
|
||||
|
||||
return isset($cache->data) && $cache->data == $var;
|
||||
}
|
||||
|
||||
/**
|
||||
* Assert or a cache entry exists.
|
||||
*
|
||||
* @param $message
|
||||
* Message to display.
|
||||
* @param $var
|
||||
* The variable the cache should contain.
|
||||
* @param $cid
|
||||
* The cache id.
|
||||
* @param $bin
|
||||
* The bin the cache item was stored in.
|
||||
*/
|
||||
protected function assertCacheExists($message, $var = NULL, $cid = NULL, $bin = NULL) {
|
||||
if ($bin == NULL) {
|
||||
$bin = $this->default_bin;
|
||||
}
|
||||
if ($cid == NULL) {
|
||||
$cid = $this->default_cid;
|
||||
}
|
||||
if ($var == NULL) {
|
||||
$var = $this->default_value;
|
||||
}
|
||||
|
||||
$this->assertTrue($this->checkCacheExists($cid, $var, $bin), $message);
|
||||
}
|
||||
|
||||
/**
|
||||
* Assert or a cache entry has been removed.
|
||||
*
|
||||
* @param $message
|
||||
* Message to display.
|
||||
* @param $cid
|
||||
* The cache id.
|
||||
* @param $bin
|
||||
* The bin the cache item was stored in.
|
||||
*/
|
||||
function assertCacheRemoved($message, $cid = NULL, $bin = NULL) {
|
||||
if ($bin == NULL) {
|
||||
$bin = $this->default_bin;
|
||||
}
|
||||
if ($cid == NULL) {
|
||||
$cid = $this->default_cid;
|
||||
}
|
||||
|
||||
$cache = cache_get($cid, $bin);
|
||||
$this->assertFalse($cache, $message);
|
||||
}
|
||||
|
||||
/**
|
||||
* Perform the general wipe.
|
||||
* @param $bin
|
||||
* The bin to perform the wipe on.
|
||||
*/
|
||||
protected function generalWipe($bin = NULL) {
|
||||
if ($bin == NULL) {
|
||||
$bin = $this->default_bin;
|
||||
}
|
||||
|
||||
cache_clear_all(NULL, $bin);
|
||||
}
|
||||
|
||||
/**
|
||||
* Setup the lifetime settings for caching.
|
||||
*
|
||||
* @param $time
|
||||
* The time in seconds the cache should minimal live.
|
||||
*/
|
||||
protected function setupLifetime($time) {
|
||||
variable_set('cache_lifetime', $time);
|
||||
variable_set('cache_flush', 0);
|
||||
}
|
||||
}
|
||||
|
||||
class CacheSavingCase extends CacheTestCase {
|
||||
public static function getInfo() {
|
||||
return array(
|
||||
'name' => 'Cache saving test',
|
||||
'description' => 'Check our variables are saved and restored the right way.',
|
||||
'group' => 'Cache'
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test the saving and restoring of a string.
|
||||
*/
|
||||
function testString() {
|
||||
$this->checkVariable($this->randomName(100));
|
||||
}
|
||||
|
||||
/**
|
||||
* Test the saving and restoring of an integer.
|
||||
*/
|
||||
function testInteger() {
|
||||
$this->checkVariable(100);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test the saving and restoring of a double.
|
||||
*/
|
||||
function testDouble() {
|
||||
$this->checkVariable(1.29);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test the saving and restoring of an array.
|
||||
*/
|
||||
function testArray() {
|
||||
$this->checkVariable(array('drupal1', 'drupal2' => 'drupal3', 'drupal4' => array('drupal5', 'drupal6')));
|
||||
}
|
||||
|
||||
/**
|
||||
* Test the saving and restoring of an object.
|
||||
*/
|
||||
function testObject() {
|
||||
$test_object = new stdClass();
|
||||
$test_object->test1 = $this->randomName(100);
|
||||
$test_object->test2 = 100;
|
||||
$test_object->test3 = array('drupal1', 'drupal2' => 'drupal3', 'drupal4' => array('drupal5', 'drupal6'));
|
||||
|
||||
cache_set('test_object', $test_object, 'cache');
|
||||
$cache = cache_get('test_object', 'cache');
|
||||
$this->assertTrue(isset($cache->data) && $cache->data == $test_object, 'Object is saved and restored properly.');
|
||||
}
|
||||
|
||||
/**
|
||||
* Check or a variable is stored and restored properly.
|
||||
*/
|
||||
function checkVariable($var) {
|
||||
cache_set('test_var', $var, 'cache');
|
||||
$cache = cache_get('test_var', 'cache');
|
||||
$this->assertTrue(isset($cache->data) && $cache->data === $var, format_string('@type is saved and restored properly.', array('@type' => ucfirst(gettype($var)))));
|
||||
}
|
||||
|
||||
/**
|
||||
* Test no empty cids are written in cache table.
|
||||
*/
|
||||
function testNoEmptyCids() {
|
||||
$this->drupalGet('user/register');
|
||||
$this->assertFalse(cache_get(''), 'No cache entry is written with an empty cid.');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Test cache_get_multiple().
|
||||
*/
|
||||
class CacheGetMultipleUnitTest extends CacheTestCase {
|
||||
|
||||
public static function getInfo() {
|
||||
return array(
|
||||
'name' => 'Fetching multiple cache items',
|
||||
'description' => 'Confirm that multiple records are fetched correctly.',
|
||||
'group' => 'Cache',
|
||||
);
|
||||
}
|
||||
|
||||
function setUp() {
|
||||
$this->default_bin = 'cache_page';
|
||||
parent::setUp();
|
||||
}
|
||||
|
||||
/**
|
||||
* Test cache_get_multiple().
|
||||
*/
|
||||
function testCacheMultiple() {
|
||||
$item1 = $this->randomName(10);
|
||||
$item2 = $this->randomName(10);
|
||||
cache_set('item1', $item1, $this->default_bin);
|
||||
cache_set('item2', $item2, $this->default_bin);
|
||||
$this->assertTrue($this->checkCacheExists('item1', $item1), 'Item 1 is cached.');
|
||||
$this->assertTrue($this->checkCacheExists('item2', $item2), 'Item 2 is cached.');
|
||||
|
||||
// Fetch both records from the database with cache_get_multiple().
|
||||
$item_ids = array('item1', 'item2');
|
||||
$items = cache_get_multiple($item_ids, $this->default_bin);
|
||||
$this->assertEqual($items['item1']->data, $item1, 'Item was returned from cache successfully.');
|
||||
$this->assertEqual($items['item2']->data, $item2, 'Item was returned from cache successfully.');
|
||||
|
||||
// Remove one item from the cache.
|
||||
cache_clear_all('item2', $this->default_bin);
|
||||
|
||||
// Confirm that only one item is returned by cache_get_multiple().
|
||||
$item_ids = array('item1', 'item2');
|
||||
$items = cache_get_multiple($item_ids, $this->default_bin);
|
||||
$this->assertEqual($items['item1']->data, $item1, 'Item was returned from cache successfully.');
|
||||
$this->assertFalse(isset($items['item2']), 'Item was not returned from the cache.');
|
||||
$this->assertTrue(count($items) == 1, 'Only valid cache entries returned.');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Test cache clearing methods.
|
||||
*/
|
||||
class CacheClearCase extends CacheTestCase {
|
||||
public static function getInfo() {
|
||||
return array(
|
||||
'name' => 'Cache clear test',
|
||||
'description' => 'Check our clearing is done the proper way.',
|
||||
'group' => 'Cache'
|
||||
);
|
||||
}
|
||||
|
||||
function setUp() {
|
||||
$this->default_bin = 'cache_page';
|
||||
$this->default_value = $this->randomName(10);
|
||||
|
||||
parent::setUp();
|
||||
}
|
||||
|
||||
/**
|
||||
* Test clearing using a cid.
|
||||
*/
|
||||
function testClearCid() {
|
||||
cache_set('test_cid_clear', $this->default_value, $this->default_bin);
|
||||
|
||||
$this->assertCacheExists(t('Cache was set for clearing cid.'), $this->default_value, 'test_cid_clear');
|
||||
cache_clear_all('test_cid_clear', $this->default_bin);
|
||||
|
||||
$this->assertCacheRemoved(t('Cache was removed after clearing cid.'), 'test_cid_clear');
|
||||
|
||||
cache_set('test_cid_clear1', $this->default_value, $this->default_bin);
|
||||
cache_set('test_cid_clear2', $this->default_value, $this->default_bin);
|
||||
$this->assertTrue($this->checkCacheExists('test_cid_clear1', $this->default_value)
|
||||
&& $this->checkCacheExists('test_cid_clear2', $this->default_value),
|
||||
'Two caches were created for checking cid "*" with wildcard false.');
|
||||
cache_clear_all('*', $this->default_bin);
|
||||
$this->assertTrue($this->checkCacheExists('test_cid_clear1', $this->default_value)
|
||||
&& $this->checkCacheExists('test_cid_clear2', $this->default_value),
|
||||
'Two caches still exists after clearing cid "*" with wildcard false.');
|
||||
}
|
||||
|
||||
/**
|
||||
* Test clearing using wildcard.
|
||||
*/
|
||||
function testClearWildcard() {
|
||||
cache_set('test_cid_clear1', $this->default_value, $this->default_bin);
|
||||
cache_set('test_cid_clear2', $this->default_value, $this->default_bin);
|
||||
$this->assertTrue($this->checkCacheExists('test_cid_clear1', $this->default_value)
|
||||
&& $this->checkCacheExists('test_cid_clear2', $this->default_value),
|
||||
'Two caches were created for checking cid "*" with wildcard true.');
|
||||
cache_clear_all('*', $this->default_bin, TRUE);
|
||||
$this->assertFalse($this->checkCacheExists('test_cid_clear1', $this->default_value)
|
||||
|| $this->checkCacheExists('test_cid_clear2', $this->default_value),
|
||||
'Two caches removed after clearing cid "*" with wildcard true.');
|
||||
|
||||
cache_set('test_cid_clear1', $this->default_value, $this->default_bin);
|
||||
cache_set('test_cid_clear2', $this->default_value, $this->default_bin);
|
||||
$this->assertTrue($this->checkCacheExists('test_cid_clear1', $this->default_value)
|
||||
&& $this->checkCacheExists('test_cid_clear2', $this->default_value),
|
||||
'Two caches were created for checking cid substring with wildcard true.');
|
||||
cache_clear_all('test_', $this->default_bin, TRUE);
|
||||
$this->assertFalse($this->checkCacheExists('test_cid_clear1', $this->default_value)
|
||||
|| $this->checkCacheExists('test_cid_clear2', $this->default_value),
|
||||
'Two caches removed after clearing cid substring with wildcard true.');
|
||||
}
|
||||
|
||||
/**
|
||||
* Test clearing using an array.
|
||||
*/
|
||||
function testClearArray() {
|
||||
// Create three cache entries.
|
||||
cache_set('test_cid_clear1', $this->default_value, $this->default_bin);
|
||||
cache_set('test_cid_clear2', $this->default_value, $this->default_bin);
|
||||
cache_set('test_cid_clear3', $this->default_value, $this->default_bin);
|
||||
$this->assertTrue($this->checkCacheExists('test_cid_clear1', $this->default_value)
|
||||
&& $this->checkCacheExists('test_cid_clear2', $this->default_value)
|
||||
&& $this->checkCacheExists('test_cid_clear3', $this->default_value),
|
||||
'Three cache entries were created.');
|
||||
|
||||
// Clear two entries using an array.
|
||||
cache_clear_all(array('test_cid_clear1', 'test_cid_clear2'), $this->default_bin);
|
||||
$this->assertFalse($this->checkCacheExists('test_cid_clear1', $this->default_value)
|
||||
|| $this->checkCacheExists('test_cid_clear2', $this->default_value),
|
||||
'Two cache entries removed after clearing with an array.');
|
||||
|
||||
$this->assertTrue($this->checkCacheExists('test_cid_clear3', $this->default_value),
|
||||
'Entry was not cleared from the cache');
|
||||
|
||||
// Set the cache clear threshold to 2 to confirm that the full bin is cleared
|
||||
// when the threshold is exceeded.
|
||||
variable_set('cache_clear_threshold', 2);
|
||||
cache_set('test_cid_clear1', $this->default_value, $this->default_bin);
|
||||
cache_set('test_cid_clear2', $this->default_value, $this->default_bin);
|
||||
$this->assertTrue($this->checkCacheExists('test_cid_clear1', $this->default_value)
|
||||
&& $this->checkCacheExists('test_cid_clear2', $this->default_value),
|
||||
'Two cache entries were created.');
|
||||
cache_clear_all(array('test_cid_clear1', 'test_cid_clear2', 'test_cid_clear3'), $this->default_bin);
|
||||
$this->assertFalse($this->checkCacheExists('test_cid_clear1', $this->default_value)
|
||||
|| $this->checkCacheExists('test_cid_clear2', $this->default_value)
|
||||
|| $this->checkCacheExists('test_cid_clear3', $this->default_value),
|
||||
'All cache entries removed when the array exceeded the cache clear threshold.');
|
||||
}
|
||||
|
||||
/**
|
||||
* Test drupal_flush_all_caches().
|
||||
*/
|
||||
function testFlushAllCaches() {
|
||||
// Create cache entries for each flushed cache bin.
|
||||
$bins = array('cache', 'cache_filter', 'cache_page', 'cache_boostrap', 'cache_path');
|
||||
$bins = array_merge(module_invoke_all('flush_caches'), $bins);
|
||||
foreach ($bins as $id => $bin) {
|
||||
$id = 'test_cid_clear' . $id;
|
||||
cache_set($id, $this->default_value, $bin);
|
||||
}
|
||||
|
||||
// Remove all caches then make sure that they are cleared.
|
||||
drupal_flush_all_caches();
|
||||
|
||||
foreach ($bins as $id => $bin) {
|
||||
$id = 'test_cid_clear' . $id;
|
||||
$this->assertFalse($this->checkCacheExists($id, $this->default_value, $bin), format_string('All cache entries removed from @bin.', array('@bin' => $bin)));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Test DrupalDatabaseCache::isValidBin().
|
||||
*/
|
||||
function testIsValidBin() {
|
||||
// Retrieve existing cache bins.
|
||||
$valid_bins = array('cache', 'cache_filter', 'cache_page', 'cache_boostrap', 'cache_path');
|
||||
$valid_bins = array_merge(module_invoke_all('flush_caches'), $valid_bins);
|
||||
foreach ($valid_bins as $id => $bin) {
|
||||
$cache = _cache_get_object($bin);
|
||||
if ($cache instanceof DrupalDatabaseCache) {
|
||||
$this->assertTrue($cache->isValidBin(), format_string('Cache bin @bin is valid.', array('@bin' => $bin)));
|
||||
}
|
||||
}
|
||||
|
||||
// Check for non-cache tables and invalid bins.
|
||||
$invalid_bins = array('block', 'filter', 'missing_table', $this->randomName());
|
||||
foreach ($invalid_bins as $id => $bin) {
|
||||
$cache = _cache_get_object($bin);
|
||||
if ($cache instanceof DrupalDatabaseCache) {
|
||||
$this->assertFalse($cache->isValidBin(), format_string('Cache bin @bin is not valid.', array('@bin' => $bin)));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Test minimum cache lifetime.
|
||||
*/
|
||||
function testMinimumCacheLifetime() {
|
||||
// Set a minimum/maximum cache lifetime.
|
||||
$this->setupLifetime(300);
|
||||
// Login as a newly-created user.
|
||||
$account = $this->drupalCreateUser(array());
|
||||
$this->drupalLogin($account);
|
||||
|
||||
// Set two cache objects in different bins.
|
||||
$data = $this->randomName(100);
|
||||
cache_set($data, $data, 'cache', CACHE_TEMPORARY);
|
||||
$cached = cache_get($data);
|
||||
$this->assertTrue(isset($cached->data) && $cached->data === $data, 'Cached item retrieved.');
|
||||
cache_set($data, $data, 'cache_page', CACHE_TEMPORARY);
|
||||
|
||||
// Expire temporary items in the 'page' bin.
|
||||
cache_clear_all(NULL, 'cache_page');
|
||||
|
||||
// Since the database cache uses REQUEST_TIME, set the $_SESSION variable
|
||||
// manually to force it to the current time.
|
||||
$_SESSION['cache_expiration']['cache_page'] = time();
|
||||
|
||||
// Items in the default cache bin should not be expired.
|
||||
$cached = cache_get($data);
|
||||
$this->assertTrue(isset($cached->data) && $cached->data == $data, 'Cached item retrieved');
|
||||
|
||||
// Despite the minimum cache lifetime, the item in the 'page' bin should
|
||||
// be invalidated for the current user.
|
||||
$cached = cache_get($data, 'cache_page');
|
||||
$this->assertFalse($cached, 'Cached item was invalidated');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Test cache_is_empty() function.
|
||||
*/
|
||||
class CacheIsEmptyCase extends CacheTestCase {
|
||||
public static function getInfo() {
|
||||
return array(
|
||||
'name' => 'Cache emptiness test',
|
||||
'description' => 'Check if a cache bin is empty after performing clear operations.',
|
||||
'group' => 'Cache'
|
||||
);
|
||||
}
|
||||
|
||||
function setUp() {
|
||||
$this->default_bin = 'cache_page';
|
||||
$this->default_value = $this->randomName(10);
|
||||
|
||||
parent::setUp();
|
||||
}
|
||||
|
||||
/**
|
||||
* Test clearing using a cid.
|
||||
*/
|
||||
function testIsEmpty() {
|
||||
// Clear the cache bin.
|
||||
cache_clear_all('*', $this->default_bin);
|
||||
$this->assertTrue(cache_is_empty($this->default_bin), 'The cache bin is empty');
|
||||
// Add some data to the cache bin.
|
||||
cache_set($this->default_cid, $this->default_value, $this->default_bin);
|
||||
$this->assertCacheExists(t('Cache was set.'), $this->default_value, $this->default_cid);
|
||||
$this->assertFalse(cache_is_empty($this->default_bin), 'The cache bin is not empty');
|
||||
// Remove the cached data.
|
||||
cache_clear_all($this->default_cid, $this->default_bin);
|
||||
$this->assertCacheRemoved(t('Cache was removed.'), $this->default_cid);
|
||||
$this->assertTrue(cache_is_empty($this->default_bin), 'The cache bin is empty');
|
||||
}
|
||||
}
|
3182
modules/simpletest/tests/common.test
Normal file
3182
modules/simpletest/tests/common.test
Normal file
File diff suppressed because it is too large
Load diff
2
modules/simpletest/tests/common_test.css
Normal file
2
modules/simpletest/tests/common_test.css
Normal file
|
@ -0,0 +1,2 @@
|
|||
|
||||
/* This file is for testing CSS file inclusion, no contents are necessary. */
|
14
modules/simpletest/tests/common_test.info
Normal file
14
modules/simpletest/tests/common_test.info
Normal file
|
@ -0,0 +1,14 @@
|
|||
name = "Common Test"
|
||||
description = "Support module for Common tests."
|
||||
package = Testing
|
||||
version = VERSION
|
||||
core = 7.x
|
||||
stylesheets[all][] = common_test.css
|
||||
stylesheets[print][] = common_test.print.css
|
||||
hidden = TRUE
|
||||
|
||||
; Information added by Drupal.org packaging script on 2017-06-21
|
||||
version = "7.56"
|
||||
project = "drupal"
|
||||
datestamp = "1498069849"
|
||||
|
285
modules/simpletest/tests/common_test.module
Normal file
285
modules/simpletest/tests/common_test.module
Normal file
|
@ -0,0 +1,285 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Helper module for the Common tests.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Implements hook_menu().
|
||||
*/
|
||||
function common_test_menu() {
|
||||
$items['common-test/drupal_goto'] = array(
|
||||
'title' => 'Drupal Goto',
|
||||
'page callback' => 'common_test_drupal_goto_land',
|
||||
'access arguments' => array('access content'),
|
||||
'type' => MENU_CALLBACK,
|
||||
);
|
||||
$items['common-test/drupal_goto/fail'] = array(
|
||||
'title' => 'Drupal Goto',
|
||||
'page callback' => 'common_test_drupal_goto_land_fail',
|
||||
'access arguments' => array('access content'),
|
||||
'type' => MENU_CALLBACK,
|
||||
);
|
||||
$items['common-test/drupal_goto/redirect'] = array(
|
||||
'title' => 'Drupal Goto',
|
||||
'page callback' => 'common_test_drupal_goto_redirect',
|
||||
'access arguments' => array('access content'),
|
||||
'type' => MENU_CALLBACK,
|
||||
);
|
||||
$items['common-test/drupal_goto/redirect_advanced'] = array(
|
||||
'title' => 'Drupal Goto',
|
||||
'page callback' => 'common_test_drupal_goto_redirect_advanced',
|
||||
'access arguments' => array('access content'),
|
||||
'type' => MENU_CALLBACK,
|
||||
);
|
||||
$items['common-test/drupal_goto/redirect_fail'] = array(
|
||||
'title' => 'Drupal Goto Failure',
|
||||
'page callback' => 'drupal_goto',
|
||||
'page arguments' => array('common-test/drupal_goto/fail'),
|
||||
'access arguments' => array('access content'),
|
||||
'type' => MENU_CALLBACK,
|
||||
);
|
||||
$items['common-test/destination'] = array(
|
||||
'title' => 'Drupal Get Destination',
|
||||
'page callback' => 'common_test_destination',
|
||||
'access arguments' => array('access content'),
|
||||
'type' => MENU_CALLBACK,
|
||||
);
|
||||
$items['common-test/query-string'] = array(
|
||||
'title' => 'Test querystring',
|
||||
'page callback' => 'common_test_js_and_css_querystring',
|
||||
'access arguments' => array('access content'),
|
||||
'type' => MENU_CALLBACK,
|
||||
);
|
||||
return $items;
|
||||
}
|
||||
|
||||
/**
|
||||
* Redirect using drupal_goto().
|
||||
*/
|
||||
function common_test_drupal_goto_redirect() {
|
||||
drupal_goto('common-test/drupal_goto');
|
||||
}
|
||||
|
||||
/**
|
||||
* Redirect using drupal_goto().
|
||||
*/
|
||||
function common_test_drupal_goto_redirect_advanced() {
|
||||
drupal_goto('common-test/drupal_goto', array('query' => array('foo' => '123')), 301);
|
||||
}
|
||||
|
||||
/**
|
||||
* Landing page for drupal_goto().
|
||||
*/
|
||||
function common_test_drupal_goto_land() {
|
||||
print "drupal_goto";
|
||||
}
|
||||
|
||||
/**
|
||||
* Fail landing page for drupal_goto().
|
||||
*/
|
||||
function common_test_drupal_goto_land_fail() {
|
||||
print "drupal_goto_fail";
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements hook_drupal_goto_alter().
|
||||
*/
|
||||
function common_test_drupal_goto_alter(&$path, &$options, &$http_response_code) {
|
||||
if ($path == 'common-test/drupal_goto/fail') {
|
||||
$path = 'common-test/drupal_goto/redirect';
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements hook_init().
|
||||
*/
|
||||
function common_test_init() {
|
||||
if (variable_get('common_test_redirect_current_path', FALSE)) {
|
||||
drupal_goto(current_path());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Print destination query parameter.
|
||||
*/
|
||||
function common_test_destination() {
|
||||
$destination = drupal_get_destination();
|
||||
print "The destination: " . check_plain($destination['destination']);
|
||||
}
|
||||
|
||||
/**
|
||||
* Applies #printed to an element to help test #pre_render.
|
||||
*/
|
||||
function common_test_drupal_render_printing_pre_render($elements) {
|
||||
$elements['#printed'] = TRUE;
|
||||
return $elements;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements hook_TYPE_alter().
|
||||
*/
|
||||
function common_test_drupal_alter_alter(&$data, &$arg2 = NULL, &$arg3 = NULL) {
|
||||
// Alter first argument.
|
||||
if (is_array($data)) {
|
||||
$data['foo'] = 'Drupal';
|
||||
}
|
||||
elseif (is_object($data)) {
|
||||
$data->foo = 'Drupal';
|
||||
}
|
||||
// Alter second argument, if present.
|
||||
if (isset($arg2)) {
|
||||
if (is_array($arg2)) {
|
||||
$arg2['foo'] = 'Drupal';
|
||||
}
|
||||
elseif (is_object($arg2)) {
|
||||
$arg2->foo = 'Drupal';
|
||||
}
|
||||
}
|
||||
// Try to alter third argument, if present.
|
||||
if (isset($arg3)) {
|
||||
if (is_array($arg3)) {
|
||||
$arg3['foo'] = 'Drupal';
|
||||
}
|
||||
elseif (is_object($arg3)) {
|
||||
$arg3->foo = 'Drupal';
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements hook_TYPE_alter() on behalf of Bartik theme.
|
||||
*
|
||||
* Same as common_test_drupal_alter_alter(), but here, we verify that themes
|
||||
* can also alter and come last.
|
||||
*/
|
||||
function bartik_drupal_alter_alter(&$data, &$arg2 = NULL, &$arg3 = NULL) {
|
||||
// Alter first argument.
|
||||
if (is_array($data)) {
|
||||
$data['foo'] .= ' theme';
|
||||
}
|
||||
elseif (is_object($data)) {
|
||||
$data->foo .= ' theme';
|
||||
}
|
||||
// Alter second argument, if present.
|
||||
if (isset($arg2)) {
|
||||
if (is_array($arg2)) {
|
||||
$arg2['foo'] .= ' theme';
|
||||
}
|
||||
elseif (is_object($arg2)) {
|
||||
$arg2->foo .= ' theme';
|
||||
}
|
||||
}
|
||||
// Try to alter third argument, if present.
|
||||
if (isset($arg3)) {
|
||||
if (is_array($arg3)) {
|
||||
$arg3['foo'] .= ' theme';
|
||||
}
|
||||
elseif (is_object($arg3)) {
|
||||
$arg3->foo .= ' theme';
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 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() {
|
||||
return array(
|
||||
'common_test_foo' => array(
|
||||
'variables' => array('foo' => 'foo', 'bar' => 'bar'),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Theme function for testing drupal_render() theming.
|
||||
*/
|
||||
function theme_common_test_foo($variables) {
|
||||
return $variables['foo'] . $variables['bar'];
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements hook_library_alter().
|
||||
*/
|
||||
function common_test_library_alter(&$libraries, $module) {
|
||||
if ($module == 'system' && isset($libraries['farbtastic'])) {
|
||||
// Change the title of Farbtastic to "Farbtastic: Altered Library".
|
||||
$libraries['farbtastic']['title'] = 'Farbtastic: Altered Library';
|
||||
// Make Farbtastic depend on jQuery Form to test library dependencies.
|
||||
$libraries['farbtastic']['dependencies'][] = array('system', 'form');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements hook_library().
|
||||
*
|
||||
* Adds Farbtastic in a different version.
|
||||
*/
|
||||
function common_test_library() {
|
||||
$libraries['farbtastic'] = array(
|
||||
'title' => 'Custom Farbtastic Library',
|
||||
'website' => 'http://code.google.com/p/farbtastic/',
|
||||
'version' => '5.3',
|
||||
'js' => array(
|
||||
'misc/farbtastic/farbtastic.js' => array(),
|
||||
),
|
||||
'css' => array(
|
||||
'misc/farbtastic/farbtastic.css' => array(),
|
||||
),
|
||||
);
|
||||
return $libraries;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a JavaScript file and a CSS file with a query string appended.
|
||||
*/
|
||||
function common_test_js_and_css_querystring() {
|
||||
drupal_add_js(drupal_get_path('module', 'node') . '/node.js');
|
||||
drupal_add_css(drupal_get_path('module', 'node') . '/node.css');
|
||||
// A relative URI may have a query string.
|
||||
drupal_add_css('/' . drupal_get_path('module', 'node') . '/node-fake.css?arg1=value1&arg2=value2');
|
||||
return '';
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements hook_cron().
|
||||
*
|
||||
* System module should handle if a module does not catch an exception and keep
|
||||
* cron going.
|
||||
*
|
||||
* @see common_test_cron_helper()
|
||||
*
|
||||
*/
|
||||
function common_test_cron() {
|
||||
throw new Exception(t('Uncaught exception'));
|
||||
}
|
2
modules/simpletest/tests/common_test.print.css
Normal file
2
modules/simpletest/tests/common_test.print.css
Normal file
|
@ -0,0 +1,2 @@
|
|||
|
||||
/* This file is for testing CSS file inclusion, no contents are necessary. */
|
12
modules/simpletest/tests/common_test_cron_helper.info
Normal file
12
modules/simpletest/tests/common_test_cron_helper.info
Normal file
|
@ -0,0 +1,12 @@
|
|||
name = "Common Test Cron Helper"
|
||||
description = "Helper module for CronRunTestCase::testCronExceptions()."
|
||||
package = Testing
|
||||
version = VERSION
|
||||
core = 7.x
|
||||
hidden = TRUE
|
||||
|
||||
; Information added by Drupal.org packaging script on 2017-06-21
|
||||
version = "7.56"
|
||||
project = "drupal"
|
||||
datestamp = "1498069849"
|
||||
|
17
modules/simpletest/tests/common_test_cron_helper.module
Normal file
17
modules/simpletest/tests/common_test_cron_helper.module
Normal file
|
@ -0,0 +1,17 @@
|
|||
<?php
|
||||
/**
|
||||
* @file
|
||||
* Helper module for the testCronExceptions in addition to common_test module.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Implements hook_cron().
|
||||
*
|
||||
* common_test_cron() throws an exception, but the execution should reach this
|
||||
* function as well.
|
||||
*
|
||||
* @see common_test_cron()
|
||||
*/
|
||||
function common_test_cron_helper_cron() {
|
||||
variable_set('common_test_cron', 'success');
|
||||
}
|
9
modules/simpletest/tests/common_test_info.txt
Normal file
9
modules/simpletest/tests/common_test_info.txt
Normal file
|
@ -0,0 +1,9 @@
|
|||
; Test parsing with a simple string.
|
||||
simple_string = A simple string
|
||||
|
||||
; Test that constants can be used as values.
|
||||
simple_constant = WATCHDOG_INFO
|
||||
|
||||
; After parsing the .info file, 'double_colon' should hold the literal value.
|
||||
; Parsing should not throw a fatal error or try to access a class constant.
|
||||
double_colon = dummyClassName::
|
12
modules/simpletest/tests/database_test.info
Normal file
12
modules/simpletest/tests/database_test.info
Normal file
|
@ -0,0 +1,12 @@
|
|||
name = "Database Test"
|
||||
description = "Support module for Database layer tests."
|
||||
core = 7.x
|
||||
package = Testing
|
||||
version = VERSION
|
||||
hidden = TRUE
|
||||
|
||||
; Information added by Drupal.org packaging script on 2017-06-21
|
||||
version = "7.56"
|
||||
project = "drupal"
|
||||
datestamp = "1498069849"
|
||||
|
221
modules/simpletest/tests/database_test.install
Normal file
221
modules/simpletest/tests/database_test.install
Normal file
|
@ -0,0 +1,221 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Install, update and uninstall functions for the database_test module.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Implements hook_schema().
|
||||
*
|
||||
* The database tests use the database API which depends on schema
|
||||
* information for certain operations on certain databases.
|
||||
* Therefore, the schema must actually be declared in a normal module
|
||||
* like any other, not directly in the test file.
|
||||
*/
|
||||
function database_test_schema() {
|
||||
$schema['test'] = array(
|
||||
'description' => 'Basic test table for the database unit tests.',
|
||||
'fields' => array(
|
||||
'id' => array(
|
||||
'type' => 'serial',
|
||||
'unsigned' => TRUE,
|
||||
'not null' => TRUE,
|
||||
),
|
||||
'name' => array(
|
||||
'description' => "A person's name",
|
||||
'type' => 'varchar',
|
||||
'length' => 255,
|
||||
'not null' => TRUE,
|
||||
'default' => '',
|
||||
'binary' => TRUE,
|
||||
),
|
||||
'age' => array(
|
||||
'description' => "The person's age",
|
||||
'type' => 'int',
|
||||
'unsigned' => TRUE,
|
||||
'not null' => TRUE,
|
||||
'default' => 0,
|
||||
),
|
||||
'job' => array(
|
||||
'description' => "The person's job",
|
||||
'type' => 'varchar',
|
||||
'length' => 255,
|
||||
'not null' => TRUE,
|
||||
'default' => 'Undefined',
|
||||
),
|
||||
),
|
||||
'primary key' => array('id'),
|
||||
'unique keys' => array(
|
||||
'name' => array('name')
|
||||
),
|
||||
'indexes' => array(
|
||||
'ages' => array('age'),
|
||||
),
|
||||
);
|
||||
|
||||
// This is an alternate version of the same table that is structured the same
|
||||
// but has a non-serial Primary Key.
|
||||
$schema['test_people'] = array(
|
||||
'description' => 'A duplicate version of the test table, used for additional tests.',
|
||||
'fields' => array(
|
||||
'name' => array(
|
||||
'description' => "A person's name",
|
||||
'type' => 'varchar',
|
||||
'length' => 255,
|
||||
'not null' => TRUE,
|
||||
'default' => '',
|
||||
),
|
||||
'age' => array(
|
||||
'description' => "The person's age",
|
||||
'type' => 'int',
|
||||
'unsigned' => TRUE,
|
||||
'not null' => TRUE,
|
||||
'default' => 0,
|
||||
),
|
||||
'job' => array(
|
||||
'description' => "The person's job",
|
||||
'type' => 'varchar',
|
||||
'length' => 255,
|
||||
'not null' => TRUE,
|
||||
'default' => '',
|
||||
),
|
||||
),
|
||||
'primary key' => array('job'),
|
||||
'indexes' => array(
|
||||
'ages' => array('age'),
|
||||
),
|
||||
);
|
||||
|
||||
$schema['test_people_copy'] = $schema['test_people'];
|
||||
$schema['test_people_copy']['description'] = 'A duplicate version of the test_people table, used for additional tests.';
|
||||
|
||||
$schema['test_one_blob'] = array(
|
||||
'description' => 'A simple table including a BLOB field for testing BLOB behavior.',
|
||||
'fields' => array(
|
||||
'id' => array(
|
||||
'description' => 'Simple unique ID.',
|
||||
'type' => 'serial',
|
||||
'not null' => TRUE,
|
||||
),
|
||||
'blob1' => array(
|
||||
'description' => 'A BLOB field.',
|
||||
'type' => 'blob',
|
||||
),
|
||||
),
|
||||
'primary key' => array('id'),
|
||||
);
|
||||
|
||||
$schema['test_two_blobs'] = array(
|
||||
'description' => 'A simple test table with two BLOB fields.',
|
||||
'fields' => array(
|
||||
'id' => array(
|
||||
'description' => 'Simple unique ID.',
|
||||
'type' => 'serial',
|
||||
'not null' => TRUE,
|
||||
),
|
||||
'blob1' => array(
|
||||
'description' => 'A dummy BLOB field.',
|
||||
'type' => 'blob',
|
||||
),
|
||||
'blob2' => array(
|
||||
'description' => 'A second BLOB field.',
|
||||
'type' => 'blob'
|
||||
),
|
||||
),
|
||||
'primary key' => array('id'),
|
||||
);
|
||||
|
||||
$schema['test_task'] = array(
|
||||
'description' => 'A task list for people in the test table.',
|
||||
'fields' => array(
|
||||
'tid' => array(
|
||||
'description' => 'Task ID, primary key.',
|
||||
'type' => 'serial',
|
||||
'not null' => TRUE,
|
||||
),
|
||||
'pid' => array(
|
||||
'description' => 'The {test_people}.pid, foreign key for the test table.',
|
||||
'type' => 'int',
|
||||
'unsigned' => TRUE,
|
||||
'not null' => TRUE,
|
||||
'default' => 0,
|
||||
),
|
||||
'task' => array(
|
||||
'description' => 'The task to be completed.',
|
||||
'type' => 'varchar',
|
||||
'length' => 255,
|
||||
'not null' => TRUE,
|
||||
'default' => '',
|
||||
),
|
||||
'priority' => array(
|
||||
'description' => 'The priority of the task.',
|
||||
'type' => 'int',
|
||||
'unsigned' => TRUE,
|
||||
'not null' => TRUE,
|
||||
'default' => 0,
|
||||
),
|
||||
),
|
||||
'primary key' => array('tid'),
|
||||
);
|
||||
|
||||
$schema['test_null'] = array(
|
||||
'description' => 'Basic test table for NULL value handling.',
|
||||
'fields' => array(
|
||||
'id' => array(
|
||||
'type' => 'serial',
|
||||
'unsigned' => TRUE,
|
||||
'not null' => TRUE,
|
||||
),
|
||||
'name' => array(
|
||||
'description' => "A person's name.",
|
||||
'type' => 'varchar',
|
||||
'length' => 255,
|
||||
'not null' => FALSE,
|
||||
'default' => '',
|
||||
),
|
||||
'age' => array(
|
||||
'description' => "The person's age.",
|
||||
'type' => 'int',
|
||||
'unsigned' => TRUE,
|
||||
'not null' => FALSE,
|
||||
'default' => 0),
|
||||
),
|
||||
'primary key' => array('id'),
|
||||
'unique keys' => array(
|
||||
'name' => array('name')
|
||||
),
|
||||
'indexes' => array(
|
||||
'ages' => array('age'),
|
||||
),
|
||||
);
|
||||
|
||||
$schema['test_serialized'] = array(
|
||||
'description' => 'Basic test table for NULL value handling.',
|
||||
'fields' => array(
|
||||
'id' => array(
|
||||
'type' => 'serial',
|
||||
'unsigned' => TRUE,
|
||||
'not null' => TRUE,
|
||||
),
|
||||
'name' => array(
|
||||
'description' => "A person's name.",
|
||||
'type' => 'varchar',
|
||||
'length' => 255,
|
||||
'not null' => FALSE,
|
||||
'default' => '',
|
||||
),
|
||||
'info' => array(
|
||||
'description' => "The person's data in serialized form.",
|
||||
'type' => 'blob',
|
||||
'serialize' => TRUE,
|
||||
),
|
||||
),
|
||||
'primary key' => array('id'),
|
||||
'unique keys' => array(
|
||||
'name' => array('name')
|
||||
),
|
||||
);
|
||||
|
||||
return $schema;
|
||||
}
|
241
modules/simpletest/tests/database_test.module
Normal file
241
modules/simpletest/tests/database_test.module
Normal file
|
@ -0,0 +1,241 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* Implements hook_query_alter().
|
||||
*/
|
||||
function database_test_query_alter(QueryAlterableInterface $query) {
|
||||
|
||||
if ($query->hasTag('database_test_alter_add_range')) {
|
||||
$query->range(0, 2);
|
||||
}
|
||||
|
||||
if ($query->hasTag('database_test_alter_add_join')) {
|
||||
$people_alias = $query->join('test', 'people', "test_task.pid = %alias.id");
|
||||
$name_field = $query->addField($people_alias, 'name', 'name');
|
||||
$query->condition($people_alias . '.id', 2);
|
||||
}
|
||||
|
||||
if ($query->hasTag('database_test_alter_change_conditional')) {
|
||||
$conditions =& $query->conditions();
|
||||
$conditions[0]['value'] = 2;
|
||||
}
|
||||
|
||||
if ($query->hasTag('database_test_alter_change_fields')) {
|
||||
$fields =& $query->getFields();
|
||||
unset($fields['age']);
|
||||
}
|
||||
|
||||
if ($query->hasTag('database_test_alter_change_expressions')) {
|
||||
$expressions =& $query->getExpressions();
|
||||
$expressions['double_age']['expression'] = 'age*3';
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Implements hook_query_TAG_alter().
|
||||
*
|
||||
* Called by DatabaseTestCase::testAlterRemoveRange.
|
||||
*/
|
||||
function database_test_query_database_test_alter_remove_range_alter(QueryAlterableInterface $query) {
|
||||
$query->range();
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements hook_menu().
|
||||
*/
|
||||
function database_test_menu() {
|
||||
$items['database_test/db_query_temporary'] = array(
|
||||
'access callback' => TRUE,
|
||||
'page callback' => 'database_test_db_query_temporary',
|
||||
);
|
||||
$items['database_test/pager_query_even'] = array(
|
||||
'access callback' => TRUE,
|
||||
'page callback' => 'database_test_even_pager_query',
|
||||
);
|
||||
$items['database_test/pager_query_odd'] = array(
|
||||
'access callback' => TRUE,
|
||||
'page callback' => 'database_test_odd_pager_query',
|
||||
);
|
||||
$items['database_test/tablesort'] = array(
|
||||
'access callback' => TRUE,
|
||||
'page callback' => 'database_test_tablesort',
|
||||
);
|
||||
$items['database_test/tablesort_first'] = array(
|
||||
'access callback' => TRUE,
|
||||
'page callback' => 'database_test_tablesort_first',
|
||||
);
|
||||
$items['database_test/tablesort_default_sort'] = array(
|
||||
'access callback' => TRUE,
|
||||
'page callback' => 'drupal_get_form',
|
||||
'page arguments' => array('database_test_theme_tablesort'),
|
||||
);
|
||||
return $items;
|
||||
}
|
||||
|
||||
/**
|
||||
* Run a db_query_temporary and output the table name and its number of rows.
|
||||
*
|
||||
* We need to test that the table created is temporary, so we run it here, in a
|
||||
* separate menu callback request; After this request is done, the temporary
|
||||
* table should automatically dropped.
|
||||
*/
|
||||
function database_test_db_query_temporary() {
|
||||
$table_name = db_query_temporary('SELECT status FROM {system}', array());
|
||||
drupal_json_output(array(
|
||||
'table_name' => $table_name,
|
||||
'row_count' => db_select($table_name)->countQuery()->execute()->fetchField(),
|
||||
));
|
||||
exit;
|
||||
}
|
||||
|
||||
/**
|
||||
* Run a pager query and return the results.
|
||||
*
|
||||
* This function does care about the page GET parameter, as set by the
|
||||
* simpletest HTTP call.
|
||||
*/
|
||||
function database_test_even_pager_query($limit) {
|
||||
|
||||
$query = db_select('test', 't');
|
||||
$query
|
||||
->fields('t', array('name'))
|
||||
->orderBy('age');
|
||||
|
||||
// This should result in 2 pages of results.
|
||||
$query = $query->extend('PagerDefault')->limit($limit);
|
||||
|
||||
$names = $query->execute()->fetchCol();
|
||||
|
||||
drupal_json_output(array(
|
||||
'names' => $names,
|
||||
));
|
||||
exit;
|
||||
}
|
||||
|
||||
/**
|
||||
* Run a pager query and return the results.
|
||||
*
|
||||
* This function does care about the page GET parameter, as set by the
|
||||
* simpletest HTTP call.
|
||||
*/
|
||||
function database_test_odd_pager_query($limit) {
|
||||
|
||||
$query = db_select('test_task', 't');
|
||||
$query
|
||||
->fields('t', array('task'))
|
||||
->orderBy('pid');
|
||||
|
||||
// This should result in 4 pages of results.
|
||||
$query = $query->extend('PagerDefault')->limit($limit);
|
||||
|
||||
$names = $query->execute()->fetchCol();
|
||||
|
||||
drupal_json_output(array(
|
||||
'names' => $names,
|
||||
));
|
||||
exit;
|
||||
}
|
||||
|
||||
/**
|
||||
* Run a tablesort query and return the results.
|
||||
*
|
||||
* This function does care about the page GET parameter, as set by the
|
||||
* simpletest HTTP call.
|
||||
*/
|
||||
function database_test_tablesort() {
|
||||
$header = array(
|
||||
'tid' => array('data' => t('Task ID'), 'field' => 'tid', 'sort' => 'desc'),
|
||||
'pid' => array('data' => t('Person ID'), 'field' => 'pid'),
|
||||
'task' => array('data' => t('Task'), 'field' => 'task'),
|
||||
'priority' => array('data' => t('Priority'), 'field' => 'priority', ),
|
||||
);
|
||||
|
||||
$query = db_select('test_task', 't');
|
||||
$query
|
||||
->fields('t', array('tid', 'pid', 'task', 'priority'));
|
||||
|
||||
$query = $query->extend('TableSort')->orderByHeader($header);
|
||||
|
||||
// We need all the results at once to check the sort.
|
||||
$tasks = $query->execute()->fetchAll();
|
||||
|
||||
drupal_json_output(array(
|
||||
'tasks' => $tasks,
|
||||
));
|
||||
exit;
|
||||
}
|
||||
|
||||
/**
|
||||
* Run a tablesort query with a second order_by after and return the results.
|
||||
*
|
||||
* This function does care about the page GET parameter, as set by the
|
||||
* simpletest HTTP call.
|
||||
*/
|
||||
function database_test_tablesort_first() {
|
||||
$header = array(
|
||||
'tid' => array('data' => t('Task ID'), 'field' => 'tid', 'sort' => 'desc'),
|
||||
'pid' => array('data' => t('Person ID'), 'field' => 'pid'),
|
||||
'task' => array('data' => t('Task'), 'field' => 'task'),
|
||||
'priority' => array('data' => t('Priority'), 'field' => 'priority', ),
|
||||
);
|
||||
|
||||
$query = db_select('test_task', 't');
|
||||
$query
|
||||
->fields('t', array('tid', 'pid', 'task', 'priority'));
|
||||
|
||||
$query = $query->extend('TableSort')->orderByHeader($header)->orderBy('priority');
|
||||
|
||||
// We need all the results at once to check the sort.
|
||||
$tasks = $query->execute()->fetchAll();
|
||||
|
||||
drupal_json_output(array(
|
||||
'tasks' => $tasks,
|
||||
));
|
||||
exit;
|
||||
}
|
||||
|
||||
/**
|
||||
* Output a form without setting a header sort.
|
||||
*/
|
||||
function database_test_theme_tablesort($form, &$form_state) {
|
||||
$header = array(
|
||||
'username' => array('data' => t('Username'), 'field' => 'u.name'),
|
||||
'status' => array('data' => t('Status'), 'field' => 'u.status'),
|
||||
);
|
||||
|
||||
$query = db_select('users', 'u');
|
||||
$query->condition('u.uid', 0, '<>');
|
||||
user_build_filter_query($query);
|
||||
|
||||
$count_query = clone $query;
|
||||
$count_query->addExpression('COUNT(u.uid)');
|
||||
|
||||
$query = $query->extend('PagerDefault')->extend('TableSort');
|
||||
$query
|
||||
->fields('u', array('uid', 'name', 'status', 'created', 'access'))
|
||||
->limit(50)
|
||||
->orderByHeader($header)
|
||||
->setCountQuery($count_query);
|
||||
$result = $query->execute();
|
||||
|
||||
$options = array();
|
||||
|
||||
$status = array(t('blocked'), t('active'));
|
||||
$accounts = array();
|
||||
foreach ($result as $account) {
|
||||
$options[$account->uid] = array(
|
||||
'username' => check_plain($account->name),
|
||||
'status' => $status[$account->status],
|
||||
);
|
||||
}
|
||||
|
||||
$form['accounts'] = array(
|
||||
'#type' => 'tableselect',
|
||||
'#header' => $header,
|
||||
'#options' => $options,
|
||||
'#empty' => t('No people available.'),
|
||||
);
|
||||
|
||||
return $form;
|
||||
}
|
4242
modules/simpletest/tests/database_test.test
Normal file
4242
modules/simpletest/tests/database_test.test
Normal file
File diff suppressed because it is too large
Load diff
|
@ -0,0 +1,14 @@
|
|||
name = "Drupal code registry test"
|
||||
description = "Support module for testing the code registry."
|
||||
files[] = drupal_autoload_test_interface.inc
|
||||
files[] = drupal_autoload_test_class.inc
|
||||
package = Testing
|
||||
version = VERSION
|
||||
core = 7.x
|
||||
hidden = TRUE
|
||||
|
||||
; Information added by Drupal.org packaging script on 2017-06-21
|
||||
version = "7.56"
|
||||
project = "drupal"
|
||||
datestamp = "1498069849"
|
||||
|
|
@ -0,0 +1,22 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Test module to check code registry.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Implements hook_registry_files_alter().
|
||||
*/
|
||||
function drupal_autoload_test_registry_files_alter(&$files, $modules) {
|
||||
foreach ($modules as $module) {
|
||||
// Add the drupal_autoload_test_trait.sh file to the registry when PHP 5.4+
|
||||
// is being used.
|
||||
if ($module->name == 'drupal_autoload_test' && version_compare(PHP_VERSION, '5.4') >= 0) {
|
||||
$files["$module->dir/drupal_autoload_test_trait.sh"] = array(
|
||||
'module' => $module->name,
|
||||
'weight' => $module->weight,
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Test classes for code registry testing.
|
||||
*/
|
||||
|
||||
/**
|
||||
* This class is empty because we only care if Drupal can find it.
|
||||
*/
|
||||
class DrupalAutoloadTestClass implements DrupalAutoloadTestInterface {}
|
|
@ -0,0 +1,11 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Test interfaces for code registry testing.
|
||||
*/
|
||||
|
||||
/**
|
||||
* This interface is empty because we only care if Drupal can find it.
|
||||
*/
|
||||
interface DrupalAutoloadTestInterface {}
|
|
@ -0,0 +1,16 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Test traits for code registry testing.
|
||||
*
|
||||
* This file has a non-standard extension to prevent PHP < 5.4 testbots from
|
||||
* trying to run a syntax check on it.
|
||||
* @todo Use a standard extension once the testbots allow it. See
|
||||
* https://www.drupal.org/node/2589649.
|
||||
*/
|
||||
|
||||
/**
|
||||
* This trait is empty because we only care if Drupal can find it.
|
||||
*/
|
||||
trait DrupalAutoloadTestTrait {}
|
|
@ -0,0 +1,12 @@
|
|||
name = "Drupal system listing compatible test"
|
||||
description = "Support module for testing the drupal_system_listing function."
|
||||
package = Testing
|
||||
version = VERSION
|
||||
core = 7.x
|
||||
hidden = TRUE
|
||||
|
||||
; Information added by Drupal.org packaging script on 2017-06-21
|
||||
version = "7.56"
|
||||
project = "drupal"
|
||||
datestamp = "1498069849"
|
||||
|
|
@ -0,0 +1 @@
|
|||
<?php
|
|
@ -0,0 +1,12 @@
|
|||
name = "Drupal system listing incompatible test"
|
||||
description = "Support module for testing the drupal_system_listing function."
|
||||
package = Testing
|
||||
version = VERSION
|
||||
core = 7.x
|
||||
hidden = TRUE
|
||||
|
||||
; Information added by Drupal.org packaging script on 2017-06-21
|
||||
version = "7.56"
|
||||
project = "drupal"
|
||||
datestamp = "1498069849"
|
||||
|
|
@ -0,0 +1 @@
|
|||
<?php
|
13
modules/simpletest/tests/entity_cache_test.info
Normal file
13
modules/simpletest/tests/entity_cache_test.info
Normal file
|
@ -0,0 +1,13 @@
|
|||
name = "Entity cache test"
|
||||
description = "Support module for testing entity cache."
|
||||
package = Testing
|
||||
version = VERSION
|
||||
core = 7.x
|
||||
dependencies[] = entity_cache_test_dependency
|
||||
hidden = TRUE
|
||||
|
||||
; Information added by Drupal.org packaging script on 2017-06-21
|
||||
version = "7.56"
|
||||
project = "drupal"
|
||||
datestamp = "1498069849"
|
||||
|
27
modules/simpletest/tests/entity_cache_test.module
Normal file
27
modules/simpletest/tests/entity_cache_test.module
Normal file
|
@ -0,0 +1,27 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Helper module for entity cache tests.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Implements hook_watchdog().
|
||||
*
|
||||
* This hook is called during module_enable() and since this hook
|
||||
* implementation is invoked, we have to expect that this module and dependent
|
||||
* modules have been properly installed already. So we expect to be able to
|
||||
* retrieve the entity information that has been registered by the required
|
||||
* dependency module.
|
||||
*
|
||||
* @see EnableDisableTestCase::testEntityCache()
|
||||
* @see entity_cache_test_dependency_entity_info()
|
||||
*/
|
||||
function entity_cache_test_watchdog($log_entry) {
|
||||
if ($log_entry['type'] == 'system' && $log_entry['message'] == '%module module installed.') {
|
||||
$info = entity_get_info('entity_cache_test');
|
||||
// Store the information in a system variable to analyze it later in the
|
||||
// test case.
|
||||
variable_set('entity_cache_test', $info);
|
||||
}
|
||||
}
|
12
modules/simpletest/tests/entity_cache_test_dependency.info
Normal file
12
modules/simpletest/tests/entity_cache_test_dependency.info
Normal file
|
@ -0,0 +1,12 @@
|
|||
name = "Entity cache test dependency"
|
||||
description = "Support dependency module for testing entity cache."
|
||||
package = Testing
|
||||
version = VERSION
|
||||
core = 7.x
|
||||
hidden = TRUE
|
||||
|
||||
; Information added by Drupal.org packaging script on 2017-06-21
|
||||
version = "7.56"
|
||||
project = "drupal"
|
||||
datestamp = "1498069849"
|
||||
|
17
modules/simpletest/tests/entity_cache_test_dependency.module
Normal file
17
modules/simpletest/tests/entity_cache_test_dependency.module
Normal file
|
@ -0,0 +1,17 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Helper module for entity cache tests.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Implements hook_entity_info().
|
||||
*/
|
||||
function entity_cache_test_dependency_entity_info() {
|
||||
return array(
|
||||
'entity_cache_test' => array(
|
||||
'label' => variable_get('entity_cache_test_label', 'Entity Cache Test'),
|
||||
),
|
||||
);
|
||||
}
|
49
modules/simpletest/tests/entity_crud.test
Normal file
49
modules/simpletest/tests/entity_crud.test
Normal file
|
@ -0,0 +1,49 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Tests for the Entity CRUD API.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Tests the entity_load() function.
|
||||
*/
|
||||
class EntityLoadTestCase extends DrupalWebTestCase {
|
||||
protected $profile = 'testing';
|
||||
|
||||
public static function getInfo() {
|
||||
return array(
|
||||
'name' => 'Entity loading',
|
||||
'description' => 'Tests the entity_load() function.',
|
||||
'group' => 'Entity API',
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests the functionality for loading entities matching certain conditions.
|
||||
*/
|
||||
public function testEntityLoadConditions() {
|
||||
// Create a few nodes. One of them is given an edge-case title of "Array",
|
||||
// because loading entities by an array of conditions is subject to PHP
|
||||
// array-to-string conversion issues and we want to test those.
|
||||
$node_1 = $this->drupalCreateNode(array('title' => 'Array'));
|
||||
$node_2 = $this->drupalCreateNode(array('title' => 'Node 2'));
|
||||
$node_3 = $this->drupalCreateNode(array('title' => 'Node 3'));
|
||||
|
||||
// Load all entities so that they are statically cached.
|
||||
$all_nodes = entity_load('node', FALSE);
|
||||
|
||||
// Check that the first node can be loaded by title.
|
||||
$nodes_loaded = entity_load('node', FALSE, array('title' => 'Array'));
|
||||
$this->assertEqual(array_keys($nodes_loaded), array($node_1->nid));
|
||||
|
||||
// Check that the second and third nodes can be loaded by title using an
|
||||
// array of conditions, and that the first node is not loaded from the
|
||||
// cache along with them.
|
||||
$nodes_loaded = entity_load('node', FALSE, array('title' => array('Node 2', 'Node 3')));
|
||||
ksort($nodes_loaded);
|
||||
$this->assertEqual(array_keys($nodes_loaded), array($node_2->nid, $node_3->nid));
|
||||
$this->assertIdentical($nodes_loaded[$node_2->nid], $all_nodes[$node_2->nid], 'Loaded node 2 is identical to cached node.');
|
||||
$this->assertIdentical($nodes_loaded[$node_3->nid], $all_nodes[$node_3->nid], 'Loaded node 3 is identical to cached node.');
|
||||
}
|
||||
}
|
12
modules/simpletest/tests/entity_crud_hook_test.info
Normal file
12
modules/simpletest/tests/entity_crud_hook_test.info
Normal file
|
@ -0,0 +1,12 @@
|
|||
name = "Entity CRUD Hooks Test"
|
||||
description = "Support module for CRUD hook tests."
|
||||
core = 7.x
|
||||
package = Testing
|
||||
version = VERSION
|
||||
hidden = TRUE
|
||||
|
||||
; Information added by Drupal.org packaging script on 2017-06-21
|
||||
version = "7.56"
|
||||
project = "drupal"
|
||||
datestamp = "1498069849"
|
||||
|
251
modules/simpletest/tests/entity_crud_hook_test.module
Normal file
251
modules/simpletest/tests/entity_crud_hook_test.module
Normal file
|
@ -0,0 +1,251 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Test module for the Entity CRUD API.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Implements hook_entity_presave().
|
||||
*/
|
||||
function entity_crud_hook_test_entity_presave($entity, $type) {
|
||||
$_SESSION['entity_crud_hook_test'][] = (__FUNCTION__ . ' called for type ' . $type);
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements hook_comment_presave().
|
||||
*/
|
||||
function entity_crud_hook_test_comment_presave() {
|
||||
$_SESSION['entity_crud_hook_test'][] = (__FUNCTION__ . ' called');
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements hook_file_presave().
|
||||
*/
|
||||
function entity_crud_hook_test_file_presave() {
|
||||
$_SESSION['entity_crud_hook_test'][] = (__FUNCTION__ . ' called');
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements hook_node_presave().
|
||||
*/
|
||||
function entity_crud_hook_test_node_presave() {
|
||||
$_SESSION['entity_crud_hook_test'][] = (__FUNCTION__ . ' called');
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements hook_taxonomy_term_presave().
|
||||
*/
|
||||
function entity_crud_hook_test_taxonomy_term_presave() {
|
||||
$_SESSION['entity_crud_hook_test'][] = (__FUNCTION__ . ' called');
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements hook_taxonomy_vocabulary_presave().
|
||||
*/
|
||||
function entity_crud_hook_test_taxonomy_vocabulary_presave() {
|
||||
$_SESSION['entity_crud_hook_test'][] = (__FUNCTION__ . ' called');
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements hook_user_presave().
|
||||
*/
|
||||
function entity_crud_hook_test_user_presave() {
|
||||
$_SESSION['entity_crud_hook_test'][] = (__FUNCTION__ . ' called');
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements hook_entity_insert().
|
||||
*/
|
||||
function entity_crud_hook_test_entity_insert($entity, $type) {
|
||||
$_SESSION['entity_crud_hook_test'][] = (__FUNCTION__ . ' called for type ' . $type);
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements hook_comment_insert().
|
||||
*/
|
||||
function entity_crud_hook_test_comment_insert() {
|
||||
$_SESSION['entity_crud_hook_test'][] = (__FUNCTION__ . ' called');
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements hook_file_insert().
|
||||
*/
|
||||
function entity_crud_hook_test_file_insert() {
|
||||
$_SESSION['entity_crud_hook_test'][] = (__FUNCTION__ . ' called');
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements hook_node_insert().
|
||||
*/
|
||||
function entity_crud_hook_test_node_insert() {
|
||||
$_SESSION['entity_crud_hook_test'][] = (__FUNCTION__ . ' called');
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements hook_taxonomy_term_insert().
|
||||
*/
|
||||
function entity_crud_hook_test_taxonomy_term_insert() {
|
||||
$_SESSION['entity_crud_hook_test'][] = (__FUNCTION__ . ' called');
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements hook_taxonomy_vocabulary_insert().
|
||||
*/
|
||||
function entity_crud_hook_test_taxonomy_vocabulary_insert() {
|
||||
$_SESSION['entity_crud_hook_test'][] = (__FUNCTION__ . ' called');
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements hook_user_insert().
|
||||
*/
|
||||
function entity_crud_hook_test_user_insert() {
|
||||
$_SESSION['entity_crud_hook_test'][] = (__FUNCTION__ . ' called');
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements hook_entity_load().
|
||||
*/
|
||||
function entity_crud_hook_test_entity_load(array $entities, $type) {
|
||||
$_SESSION['entity_crud_hook_test'][] = (__FUNCTION__ . ' called for type ' . $type);
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements hook_comment_load().
|
||||
*/
|
||||
function entity_crud_hook_test_comment_load() {
|
||||
$_SESSION['entity_crud_hook_test'][] = (__FUNCTION__ . ' called');
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements hook_file_load().
|
||||
*/
|
||||
function entity_crud_hook_test_file_load() {
|
||||
$_SESSION['entity_crud_hook_test'][] = (__FUNCTION__ . ' called');
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements hook_node_load().
|
||||
*/
|
||||
function entity_crud_hook_test_node_load() {
|
||||
$_SESSION['entity_crud_hook_test'][] = (__FUNCTION__ . ' called');
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements hook_taxonomy_term_load().
|
||||
*/
|
||||
function entity_crud_hook_test_taxonomy_term_load() {
|
||||
$_SESSION['entity_crud_hook_test'][] = (__FUNCTION__ . ' called');
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements hook_taxonomy_vocabulary_load().
|
||||
*/
|
||||
function entity_crud_hook_test_taxonomy_vocabulary_load() {
|
||||
$_SESSION['entity_crud_hook_test'][] = (__FUNCTION__ . ' called');
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements hook_user_load().
|
||||
*/
|
||||
function entity_crud_hook_test_user_load() {
|
||||
$_SESSION['entity_crud_hook_test'][] = (__FUNCTION__ . ' called');
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements hook_entity_update().
|
||||
*/
|
||||
function entity_crud_hook_test_entity_update($entity, $type) {
|
||||
$_SESSION['entity_crud_hook_test'][] = (__FUNCTION__ . ' called for type ' . $type);
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements hook_comment_update().
|
||||
*/
|
||||
function entity_crud_hook_test_comment_update() {
|
||||
$_SESSION['entity_crud_hook_test'][] = (__FUNCTION__ . ' called');
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements hook_file_update().
|
||||
*/
|
||||
function entity_crud_hook_test_file_update() {
|
||||
$_SESSION['entity_crud_hook_test'][] = (__FUNCTION__ . ' called');
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements hook_node_update().
|
||||
*/
|
||||
function entity_crud_hook_test_node_update() {
|
||||
$_SESSION['entity_crud_hook_test'][] = (__FUNCTION__ . ' called');
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements hook_taxonomy_term_update().
|
||||
*/
|
||||
function entity_crud_hook_test_taxonomy_term_update() {
|
||||
$_SESSION['entity_crud_hook_test'][] = (__FUNCTION__ . ' called');
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements hook_taxonomy_vocabulary_update().
|
||||
*/
|
||||
function entity_crud_hook_test_taxonomy_vocabulary_update() {
|
||||
$_SESSION['entity_crud_hook_test'][] = (__FUNCTION__ . ' called');
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements hook_user_update().
|
||||
*/
|
||||
function entity_crud_hook_test_user_update() {
|
||||
$_SESSION['entity_crud_hook_test'][] = (__FUNCTION__ . ' called');
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements hook_entity_delete().
|
||||
*/
|
||||
function entity_crud_hook_test_entity_delete($entity, $type) {
|
||||
$_SESSION['entity_crud_hook_test'][] = (__FUNCTION__ . ' called for type ' . $type);
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements hook_comment_delete().
|
||||
*/
|
||||
function entity_crud_hook_test_comment_delete() {
|
||||
$_SESSION['entity_crud_hook_test'][] = (__FUNCTION__ . ' called');
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements hook_file_delete().
|
||||
*/
|
||||
function entity_crud_hook_test_file_delete() {
|
||||
$_SESSION['entity_crud_hook_test'][] = (__FUNCTION__ . ' called');
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements hook_node_delete().
|
||||
*/
|
||||
function entity_crud_hook_test_node_delete() {
|
||||
$_SESSION['entity_crud_hook_test'][] = (__FUNCTION__ . ' called');
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements hook_taxonomy_term_delete().
|
||||
*/
|
||||
function entity_crud_hook_test_taxonomy_term_delete() {
|
||||
$_SESSION['entity_crud_hook_test'][] = (__FUNCTION__ . ' called');
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements hook_taxonomy_vocabulary_delete().
|
||||
*/
|
||||
function entity_crud_hook_test_taxonomy_vocabulary_delete() {
|
||||
$_SESSION['entity_crud_hook_test'][] = (__FUNCTION__ . ' called');
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements hook_user_delete().
|
||||
*/
|
||||
function entity_crud_hook_test_user_delete() {
|
||||
$_SESSION['entity_crud_hook_test'][] = (__FUNCTION__ . ' called');
|
||||
}
|
338
modules/simpletest/tests/entity_crud_hook_test.test
Normal file
338
modules/simpletest/tests/entity_crud_hook_test.test
Normal file
|
@ -0,0 +1,338 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* CRUD hook tests for the Entity CRUD API.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Tests invocation of hooks when performing an action.
|
||||
*
|
||||
* Tested hooks are:
|
||||
* - hook_entity_insert()
|
||||
* - hook_entity_load()
|
||||
* - hook_entity_update()
|
||||
* - hook_entity_delete()
|
||||
* As well as all type-specific hooks, like hook_node_insert(),
|
||||
* hook_comment_update(), etc.
|
||||
*/
|
||||
class EntityCrudHookTestCase extends DrupalWebTestCase {
|
||||
|
||||
protected $ids = array();
|
||||
|
||||
public static function getInfo() {
|
||||
return array(
|
||||
'name' => 'Entity CRUD hooks',
|
||||
'description' => 'Tests the invocation of hooks when inserting, loading, updating or deleting an entity.',
|
||||
'group' => 'Entity API',
|
||||
);
|
||||
}
|
||||
|
||||
public function setUp() {
|
||||
parent::setUp('entity_crud_hook_test', 'taxonomy', 'comment');
|
||||
}
|
||||
|
||||
/**
|
||||
* Pass if the message $text was set by one of the CRUD hooks in
|
||||
* entity_crud_hook_test.module, i.e., if the $text is an element of
|
||||
* $_SESSION['entity_crud_hook_test'].
|
||||
*
|
||||
* @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.
|
||||
*/
|
||||
protected function assertHookMessage($text, $message = NULL, $group = 'Other') {
|
||||
if (!isset($message)) {
|
||||
$message = $text;
|
||||
}
|
||||
return $this->assertTrue(array_search($text, $_SESSION['entity_crud_hook_test']) !== FALSE, $message, $group);
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests hook invocations for CRUD operations on comments.
|
||||
*/
|
||||
public function testCommentHooks() {
|
||||
$node = (object) array(
|
||||
'uid' => 1,
|
||||
'type' => 'article',
|
||||
'title' => 'Test node',
|
||||
'status' => 1,
|
||||
'comment' => 2,
|
||||
'promote' => 0,
|
||||
'sticky' => 0,
|
||||
'language' => LANGUAGE_NONE,
|
||||
'created' => REQUEST_TIME,
|
||||
'changed' => REQUEST_TIME,
|
||||
);
|
||||
node_save($node);
|
||||
$nid = $node->nid;
|
||||
|
||||
$comment = (object) array(
|
||||
'cid' => NULL,
|
||||
'pid' => 0,
|
||||
'nid' => $nid,
|
||||
'uid' => 1,
|
||||
'subject' => 'Test comment',
|
||||
'created' => REQUEST_TIME,
|
||||
'changed' => REQUEST_TIME,
|
||||
'status' => 1,
|
||||
'language' => LANGUAGE_NONE,
|
||||
);
|
||||
$_SESSION['entity_crud_hook_test'] = array();
|
||||
comment_save($comment);
|
||||
|
||||
$this->assertHookMessage('entity_crud_hook_test_entity_presave called for type comment');
|
||||
$this->assertHookMessage('entity_crud_hook_test_comment_presave called');
|
||||
$this->assertHookMessage('entity_crud_hook_test_entity_insert called for type comment');
|
||||
$this->assertHookMessage('entity_crud_hook_test_comment_insert called');
|
||||
|
||||
$_SESSION['entity_crud_hook_test'] = array();
|
||||
$comment = comment_load($comment->cid);
|
||||
|
||||
$this->assertHookMessage('entity_crud_hook_test_entity_load called for type comment');
|
||||
$this->assertHookMessage('entity_crud_hook_test_comment_load called');
|
||||
|
||||
$_SESSION['entity_crud_hook_test'] = array();
|
||||
$comment->subject = 'New subject';
|
||||
comment_save($comment);
|
||||
|
||||
$this->assertHookMessage('entity_crud_hook_test_entity_presave called for type comment');
|
||||
$this->assertHookMessage('entity_crud_hook_test_comment_presave called');
|
||||
$this->assertHookMessage('entity_crud_hook_test_entity_update called for type comment');
|
||||
$this->assertHookMessage('entity_crud_hook_test_comment_update called');
|
||||
|
||||
$_SESSION['entity_crud_hook_test'] = array();
|
||||
comment_delete($comment->cid);
|
||||
|
||||
$this->assertHookMessage('entity_crud_hook_test_entity_delete called for type comment');
|
||||
$this->assertHookMessage('entity_crud_hook_test_comment_delete called');
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests hook invocations for CRUD operations on files.
|
||||
*/
|
||||
public function testFileHooks() {
|
||||
$url = 'public://entity_crud_hook_test.file';
|
||||
file_put_contents($url, 'Test test test');
|
||||
$file = (object) array(
|
||||
'fid' => NULL,
|
||||
'uid' => 1,
|
||||
'filename' => 'entity_crud_hook_test.file',
|
||||
'uri' => $url,
|
||||
'filemime' => 'text/plain',
|
||||
'filesize' => filesize($url),
|
||||
'status' => 1,
|
||||
'timestamp' => REQUEST_TIME,
|
||||
);
|
||||
$_SESSION['entity_crud_hook_test'] = array();
|
||||
file_save($file);
|
||||
|
||||
$this->assertHookMessage('entity_crud_hook_test_entity_presave called for type file');
|
||||
$this->assertHookMessage('entity_crud_hook_test_file_presave called');
|
||||
$this->assertHookMessage('entity_crud_hook_test_entity_insert called for type file');
|
||||
$this->assertHookMessage('entity_crud_hook_test_file_insert called');
|
||||
|
||||
$_SESSION['entity_crud_hook_test'] = array();
|
||||
$file = file_load($file->fid);
|
||||
|
||||
$this->assertHookMessage('entity_crud_hook_test_entity_load called for type file');
|
||||
$this->assertHookMessage('entity_crud_hook_test_file_load called');
|
||||
|
||||
$_SESSION['entity_crud_hook_test'] = array();
|
||||
$file->filename = 'new.entity_crud_hook_test.file';
|
||||
file_save($file);
|
||||
|
||||
$this->assertHookMessage('entity_crud_hook_test_entity_presave called for type file');
|
||||
$this->assertHookMessage('entity_crud_hook_test_file_presave called');
|
||||
$this->assertHookMessage('entity_crud_hook_test_entity_update called for type file');
|
||||
$this->assertHookMessage('entity_crud_hook_test_file_update called');
|
||||
|
||||
$_SESSION['entity_crud_hook_test'] = array();
|
||||
file_delete($file);
|
||||
|
||||
$this->assertHookMessage('entity_crud_hook_test_entity_delete called for type file');
|
||||
$this->assertHookMessage('entity_crud_hook_test_file_delete called');
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests hook invocations for CRUD operations on nodes.
|
||||
*/
|
||||
public function testNodeHooks() {
|
||||
$node = (object) array(
|
||||
'uid' => 1,
|
||||
'type' => 'article',
|
||||
'title' => 'Test node',
|
||||
'status' => 1,
|
||||
'comment' => 2,
|
||||
'promote' => 0,
|
||||
'sticky' => 0,
|
||||
'language' => LANGUAGE_NONE,
|
||||
'created' => REQUEST_TIME,
|
||||
'changed' => REQUEST_TIME,
|
||||
);
|
||||
$_SESSION['entity_crud_hook_test'] = array();
|
||||
node_save($node);
|
||||
|
||||
$this->assertHookMessage('entity_crud_hook_test_entity_presave called for type node');
|
||||
$this->assertHookMessage('entity_crud_hook_test_node_presave called');
|
||||
$this->assertHookMessage('entity_crud_hook_test_entity_insert called for type node');
|
||||
$this->assertHookMessage('entity_crud_hook_test_node_insert called');
|
||||
|
||||
$_SESSION['entity_crud_hook_test'] = array();
|
||||
$node = node_load($node->nid);
|
||||
|
||||
$this->assertHookMessage('entity_crud_hook_test_entity_load called for type node');
|
||||
$this->assertHookMessage('entity_crud_hook_test_node_load called');
|
||||
|
||||
$_SESSION['entity_crud_hook_test'] = array();
|
||||
$node->title = 'New title';
|
||||
node_save($node);
|
||||
|
||||
$this->assertHookMessage('entity_crud_hook_test_entity_presave called for type node');
|
||||
$this->assertHookMessage('entity_crud_hook_test_node_presave called');
|
||||
$this->assertHookMessage('entity_crud_hook_test_entity_update called for type node');
|
||||
$this->assertHookMessage('entity_crud_hook_test_node_update called');
|
||||
|
||||
$_SESSION['entity_crud_hook_test'] = array();
|
||||
node_delete($node->nid);
|
||||
|
||||
$this->assertHookMessage('entity_crud_hook_test_entity_delete called for type node');
|
||||
$this->assertHookMessage('entity_crud_hook_test_node_delete called');
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests hook invocations for CRUD operations on taxonomy terms.
|
||||
*/
|
||||
public function testTaxonomyTermHooks() {
|
||||
$vocabulary = (object) array(
|
||||
'name' => 'Test vocabulary',
|
||||
'machine_name' => 'test',
|
||||
'description' => NULL,
|
||||
'module' => 'entity_crud_hook_test',
|
||||
);
|
||||
taxonomy_vocabulary_save($vocabulary);
|
||||
|
||||
$term = (object) array(
|
||||
'vid' => $vocabulary->vid,
|
||||
'name' => 'Test term',
|
||||
'description' => NULL,
|
||||
'format' => 1,
|
||||
);
|
||||
$_SESSION['entity_crud_hook_test'] = array();
|
||||
taxonomy_term_save($term);
|
||||
|
||||
$this->assertHookMessage('entity_crud_hook_test_entity_presave called for type taxonomy_term');
|
||||
$this->assertHookMessage('entity_crud_hook_test_taxonomy_term_presave called');
|
||||
$this->assertHookMessage('entity_crud_hook_test_entity_insert called for type taxonomy_term');
|
||||
$this->assertHookMessage('entity_crud_hook_test_taxonomy_term_insert called');
|
||||
|
||||
$_SESSION['entity_crud_hook_test'] = array();
|
||||
$term = taxonomy_term_load($term->tid);
|
||||
|
||||
$this->assertHookMessage('entity_crud_hook_test_entity_load called for type taxonomy_term');
|
||||
$this->assertHookMessage('entity_crud_hook_test_taxonomy_term_load called');
|
||||
|
||||
$_SESSION['entity_crud_hook_test'] = array();
|
||||
$term->name = 'New name';
|
||||
taxonomy_term_save($term);
|
||||
|
||||
$this->assertHookMessage('entity_crud_hook_test_entity_presave called for type taxonomy_term');
|
||||
$this->assertHookMessage('entity_crud_hook_test_taxonomy_term_presave called');
|
||||
$this->assertHookMessage('entity_crud_hook_test_entity_update called for type taxonomy_term');
|
||||
$this->assertHookMessage('entity_crud_hook_test_taxonomy_term_update called');
|
||||
|
||||
$_SESSION['entity_crud_hook_test'] = array();
|
||||
taxonomy_term_delete($term->tid);
|
||||
|
||||
$this->assertHookMessage('entity_crud_hook_test_entity_delete called for type taxonomy_term');
|
||||
$this->assertHookMessage('entity_crud_hook_test_taxonomy_term_delete called');
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests hook invocations for CRUD operations on taxonomy vocabularies.
|
||||
*/
|
||||
public function testTaxonomyVocabularyHooks() {
|
||||
$vocabulary = (object) array(
|
||||
'name' => 'Test vocabulary',
|
||||
'machine_name' => 'test',
|
||||
'description' => NULL,
|
||||
'module' => 'entity_crud_hook_test',
|
||||
);
|
||||
$_SESSION['entity_crud_hook_test'] = array();
|
||||
taxonomy_vocabulary_save($vocabulary);
|
||||
|
||||
$this->assertHookMessage('entity_crud_hook_test_entity_presave called for type taxonomy_vocabulary');
|
||||
$this->assertHookMessage('entity_crud_hook_test_taxonomy_vocabulary_presave called');
|
||||
$this->assertHookMessage('entity_crud_hook_test_entity_insert called for type taxonomy_vocabulary');
|
||||
$this->assertHookMessage('entity_crud_hook_test_taxonomy_vocabulary_insert called');
|
||||
|
||||
$_SESSION['entity_crud_hook_test'] = array();
|
||||
$vocabulary = taxonomy_vocabulary_load($vocabulary->vid);
|
||||
|
||||
$this->assertHookMessage('entity_crud_hook_test_entity_load called for type taxonomy_vocabulary');
|
||||
$this->assertHookMessage('entity_crud_hook_test_taxonomy_vocabulary_load called');
|
||||
|
||||
$_SESSION['entity_crud_hook_test'] = array();
|
||||
$vocabulary->name = 'New name';
|
||||
taxonomy_vocabulary_save($vocabulary);
|
||||
|
||||
$this->assertHookMessage('entity_crud_hook_test_entity_presave called for type taxonomy_vocabulary');
|
||||
$this->assertHookMessage('entity_crud_hook_test_taxonomy_vocabulary_presave called');
|
||||
$this->assertHookMessage('entity_crud_hook_test_entity_update called for type taxonomy_vocabulary');
|
||||
$this->assertHookMessage('entity_crud_hook_test_taxonomy_vocabulary_update called');
|
||||
|
||||
$_SESSION['entity_crud_hook_test'] = array();
|
||||
taxonomy_vocabulary_delete($vocabulary->vid);
|
||||
|
||||
$this->assertHookMessage('entity_crud_hook_test_entity_delete called for type taxonomy_vocabulary');
|
||||
$this->assertHookMessage('entity_crud_hook_test_taxonomy_vocabulary_delete called');
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests hook invocations for CRUD operations on users.
|
||||
*/
|
||||
public function testUserHooks() {
|
||||
$edit = array(
|
||||
'name' => 'Test user',
|
||||
'mail' => 'test@example.com',
|
||||
'created' => REQUEST_TIME,
|
||||
'status' => 1,
|
||||
'language' => 'en',
|
||||
);
|
||||
$account = (object) $edit;
|
||||
$_SESSION['entity_crud_hook_test'] = array();
|
||||
$account = user_save($account, $edit);
|
||||
|
||||
$this->assertHookMessage('entity_crud_hook_test_entity_presave called for type user');
|
||||
$this->assertHookMessage('entity_crud_hook_test_user_presave called');
|
||||
$this->assertHookMessage('entity_crud_hook_test_entity_insert called for type user');
|
||||
$this->assertHookMessage('entity_crud_hook_test_user_insert called');
|
||||
|
||||
$_SESSION['entity_crud_hook_test'] = array();
|
||||
$account = user_load($account->uid);
|
||||
|
||||
$this->assertHookMessage('entity_crud_hook_test_entity_load called for type user');
|
||||
$this->assertHookMessage('entity_crud_hook_test_user_load called');
|
||||
|
||||
$_SESSION['entity_crud_hook_test'] = array();
|
||||
$edit['name'] = 'New name';
|
||||
$account = user_save($account, $edit);
|
||||
|
||||
$this->assertHookMessage('entity_crud_hook_test_entity_presave called for type user');
|
||||
$this->assertHookMessage('entity_crud_hook_test_user_presave called');
|
||||
$this->assertHookMessage('entity_crud_hook_test_entity_update called for type user');
|
||||
$this->assertHookMessage('entity_crud_hook_test_user_update called');
|
||||
|
||||
$_SESSION['entity_crud_hook_test'] = array();
|
||||
user_delete($account->uid);
|
||||
|
||||
$this->assertHookMessage('entity_crud_hook_test_entity_delete called for type user');
|
||||
$this->assertHookMessage('entity_crud_hook_test_user_delete called');
|
||||
}
|
||||
|
||||
}
|
1681
modules/simpletest/tests/entity_query.test
Normal file
1681
modules/simpletest/tests/entity_query.test
Normal file
File diff suppressed because it is too large
Load diff
12
modules/simpletest/tests/entity_query_access_test.info
Normal file
12
modules/simpletest/tests/entity_query_access_test.info
Normal file
|
@ -0,0 +1,12 @@
|
|||
name = "Entity query access test"
|
||||
description = "Support module for checking entity query results."
|
||||
package = Testing
|
||||
version = VERSION
|
||||
core = 7.x
|
||||
hidden = TRUE
|
||||
|
||||
; Information added by Drupal.org packaging script on 2017-06-21
|
||||
version = "7.56"
|
||||
project = "drupal"
|
||||
datestamp = "1498069849"
|
||||
|
54
modules/simpletest/tests/entity_query_access_test.module
Normal file
54
modules/simpletest/tests/entity_query_access_test.module
Normal file
|
@ -0,0 +1,54 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Helper module for testing EntityFieldQuery access on any type of entity.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Implements hook_menu().
|
||||
*/
|
||||
function entity_query_access_test_menu() {
|
||||
$items['entity-query-access/test/%'] = array(
|
||||
'title' => "Retrieve a sample of entity query access data",
|
||||
'page callback' => 'entity_query_access_test_sample_query',
|
||||
'page arguments' => array(2),
|
||||
'access callback' => TRUE,
|
||||
'type' => MENU_CALLBACK,
|
||||
);
|
||||
|
||||
return $items;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the results from an example EntityFieldQuery.
|
||||
*/
|
||||
function entity_query_access_test_sample_query($field_name) {
|
||||
global $user;
|
||||
|
||||
// Simulate user does not have access to view all nodes.
|
||||
$access = &drupal_static('node_access_view_all_nodes');
|
||||
$access[$user->uid] = FALSE;
|
||||
|
||||
$query = new EntityFieldQuery();
|
||||
$query
|
||||
->entityCondition('entity_type', 'test_entity_bundle_key')
|
||||
->fieldCondition($field_name, 'value', 0, '>')
|
||||
->entityOrderBy('entity_id', 'ASC');
|
||||
$results = array(
|
||||
'items' => array(),
|
||||
'title' => t('EntityFieldQuery results'),
|
||||
);
|
||||
foreach ($query->execute() as $entity_type => $entity_ids) {
|
||||
foreach ($entity_ids as $entity_id => $entity_stub) {
|
||||
$results['items'][] = format_string('Found entity of type @entity_type with id @entity_id', array('@entity_type' => $entity_type, '@entity_id' => $entity_id));
|
||||
}
|
||||
}
|
||||
if (count($results['items']) > 0) {
|
||||
$output = theme('item_list', $results);
|
||||
}
|
||||
else {
|
||||
$output = 'No results found with EntityFieldQuery.';
|
||||
}
|
||||
return $output;
|
||||
}
|
116
modules/simpletest/tests/error.test
Normal file
116
modules/simpletest/tests/error.test
Normal file
|
@ -0,0 +1,116 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* Tests Drupal error and exception handlers.
|
||||
*/
|
||||
class DrupalErrorHandlerTestCase extends DrupalWebTestCase {
|
||||
public static function getInfo() {
|
||||
return array(
|
||||
'name' => 'Drupal error handlers',
|
||||
'description' => 'Performs tests on the Drupal error and exception handler.',
|
||||
'group' => 'System',
|
||||
);
|
||||
}
|
||||
|
||||
function setUp() {
|
||||
parent::setUp('error_test');
|
||||
}
|
||||
|
||||
/**
|
||||
* Test the error handler.
|
||||
*/
|
||||
function testErrorHandler() {
|
||||
$error_notice = array(
|
||||
'%type' => 'Notice',
|
||||
'!message' => 'Undefined variable: bananas',
|
||||
'%function' => 'error_test_generate_warnings()',
|
||||
'%file' => drupal_realpath('modules/simpletest/tests/error_test.module'),
|
||||
);
|
||||
$error_warning = array(
|
||||
'%type' => 'Warning',
|
||||
'!message' => 'Division by zero',
|
||||
'%function' => 'error_test_generate_warnings()',
|
||||
'%file' => drupal_realpath('modules/simpletest/tests/error_test.module'),
|
||||
);
|
||||
$error_user_notice = array(
|
||||
'%type' => 'User warning',
|
||||
'!message' => 'Drupal is awesome',
|
||||
'%function' => 'error_test_generate_warnings()',
|
||||
'%file' => drupal_realpath('modules/simpletest/tests/error_test.module'),
|
||||
);
|
||||
|
||||
// Set error reporting to collect notices.
|
||||
variable_set('error_level', ERROR_REPORTING_DISPLAY_ALL);
|
||||
$this->drupalGet('error-test/generate-warnings');
|
||||
$this->assertResponse(200, 'Received expected HTTP status code.');
|
||||
$this->assertErrorMessage($error_notice);
|
||||
$this->assertErrorMessage($error_warning);
|
||||
$this->assertErrorMessage($error_user_notice);
|
||||
|
||||
// Set error reporting to not collect notices.
|
||||
variable_set('error_level', ERROR_REPORTING_DISPLAY_SOME);
|
||||
$this->drupalGet('error-test/generate-warnings');
|
||||
$this->assertResponse(200, 'Received expected HTTP status code.');
|
||||
$this->assertNoErrorMessage($error_notice);
|
||||
$this->assertErrorMessage($error_warning);
|
||||
$this->assertErrorMessage($error_user_notice);
|
||||
|
||||
// Set error reporting to not show any errors.
|
||||
variable_set('error_level', ERROR_REPORTING_HIDE);
|
||||
$this->drupalGet('error-test/generate-warnings');
|
||||
$this->assertResponse(200, 'Received expected HTTP status code.');
|
||||
$this->assertNoErrorMessage($error_notice);
|
||||
$this->assertNoErrorMessage($error_warning);
|
||||
$this->assertNoErrorMessage($error_user_notice);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test the exception handler.
|
||||
*/
|
||||
function testExceptionHandler() {
|
||||
$error_exception = array(
|
||||
'%type' => 'Exception',
|
||||
'!message' => 'Drupal is awesome',
|
||||
'%function' => 'error_test_trigger_exception()',
|
||||
'%line' => 57,
|
||||
'%file' => drupal_realpath('modules/simpletest/tests/error_test.module'),
|
||||
);
|
||||
$error_pdo_exception = array(
|
||||
'%type' => 'PDOException',
|
||||
'!message' => 'SELECT * FROM bananas_are_awesome',
|
||||
'%function' => 'error_test_trigger_pdo_exception()',
|
||||
'%line' => 65,
|
||||
'%file' => drupal_realpath('modules/simpletest/tests/error_test.module'),
|
||||
);
|
||||
|
||||
$this->drupalGet('error-test/trigger-exception');
|
||||
$this->assertTrue(strpos($this->drupalGetHeader(':status'), '500 Service unavailable (with message)'), 'Received expected HTTP status line.');
|
||||
$this->assertErrorMessage($error_exception);
|
||||
|
||||
$this->drupalGet('error-test/trigger-pdo-exception');
|
||||
$this->assertTrue(strpos($this->drupalGetHeader(':status'), '500 Service unavailable (with message)'), 'Received expected HTTP status line.');
|
||||
// We cannot use assertErrorMessage() since the extact error reported
|
||||
// varies from database to database. Check that the SQL string is displayed.
|
||||
$this->assertText($error_pdo_exception['%type'], format_string('Found %type in error page.', $error_pdo_exception));
|
||||
$this->assertText($error_pdo_exception['!message'], format_string('Found !message in error page.', $error_pdo_exception));
|
||||
$error_details = format_string('in %function (line ', $error_pdo_exception);
|
||||
$this->assertRaw($error_details, format_string("Found '!message' in error page.", array('!message' => $error_details)));
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper function: assert that the error message is found.
|
||||
*/
|
||||
function assertErrorMessage(array $error) {
|
||||
$message = t('%type: !message in %function (line ', $error);
|
||||
$this->assertRaw($message, format_string('Found error message: !message.', array('!message' => $message)));
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper function: assert that the error message is not found.
|
||||
*/
|
||||
function assertNoErrorMessage(array $error) {
|
||||
$message = t('%type: !message in %function (line ', $error);
|
||||
$this->assertNoRaw($message, format_string('Did not find error message: !message.', array('!message' => $message)));
|
||||
}
|
||||
}
|
||||
|
12
modules/simpletest/tests/error_test.info
Normal file
12
modules/simpletest/tests/error_test.info
Normal file
|
@ -0,0 +1,12 @@
|
|||
name = "Error test"
|
||||
description = "Support module for error and exception testing."
|
||||
package = Testing
|
||||
version = VERSION
|
||||
core = 7.x
|
||||
hidden = TRUE
|
||||
|
||||
; Information added by Drupal.org packaging script on 2017-06-21
|
||||
version = "7.56"
|
||||
project = "drupal"
|
||||
datestamp = "1498069849"
|
||||
|
65
modules/simpletest/tests/error_test.module
Normal file
65
modules/simpletest/tests/error_test.module
Normal file
|
@ -0,0 +1,65 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* Implements hook_menu().
|
||||
*/
|
||||
function error_test_menu() {
|
||||
$items['error-test/generate-warnings'] = array(
|
||||
'title' => 'Generate warnings',
|
||||
'page callback' => 'error_test_generate_warnings',
|
||||
'access callback' => TRUE,
|
||||
'type' => MENU_CALLBACK,
|
||||
);
|
||||
$items['error-test/generate-warnings-with-report'] = array(
|
||||
'title' => 'Generate warnings with Simpletest reporting',
|
||||
'page callback' => 'error_test_generate_warnings',
|
||||
'page arguments' => array(TRUE),
|
||||
'access callback' => TRUE,
|
||||
'type' => MENU_CALLBACK,
|
||||
);
|
||||
$items['error-test/trigger-exception'] = array(
|
||||
'title' => 'Trigger an exception',
|
||||
'page callback' => 'error_test_trigger_exception',
|
||||
'access callback' => TRUE,
|
||||
'type' => MENU_CALLBACK,
|
||||
);
|
||||
$items['error-test/trigger-pdo-exception'] = array(
|
||||
'title' => 'Trigger a PDO exception',
|
||||
'page callback' => 'error_test_trigger_pdo_exception',
|
||||
'access callback' => TRUE,
|
||||
'type' => MENU_CALLBACK,
|
||||
);
|
||||
|
||||
return $items;
|
||||
}
|
||||
|
||||
/**
|
||||
* Menu callback; generate warnings to test the error handler.
|
||||
*/
|
||||
function error_test_generate_warnings($collect_errors = FALSE) {
|
||||
// Tell Drupal error reporter to send errors to Simpletest or not.
|
||||
define('SIMPLETEST_COLLECT_ERRORS', $collect_errors);
|
||||
// This will generate a notice.
|
||||
$monkey_love = $bananas;
|
||||
// This will generate a warning.
|
||||
$awesomely_big = 1/0;
|
||||
// This will generate a user error.
|
||||
trigger_error("Drupal is awesome", E_USER_WARNING);
|
||||
return "";
|
||||
}
|
||||
|
||||
/**
|
||||
* Menu callback; trigger an exception to test the exception handler.
|
||||
*/
|
||||
function error_test_trigger_exception() {
|
||||
define('SIMPLETEST_COLLECT_ERRORS', FALSE);
|
||||
throw new Exception("Drupal is awesome");
|
||||
}
|
||||
|
||||
/**
|
||||
* Menu callback; trigger an exception to test the exception handler.
|
||||
*/
|
||||
function error_test_trigger_pdo_exception() {
|
||||
define('SIMPLETEST_COLLECT_ERRORS', FALSE);
|
||||
db_query('SELECT * FROM bananas_are_awesome');
|
||||
}
|
2769
modules/simpletest/tests/file.test
Normal file
2769
modules/simpletest/tests/file.test
Normal file
File diff suppressed because it is too large
Load diff
13
modules/simpletest/tests/file_test.info
Normal file
13
modules/simpletest/tests/file_test.info
Normal file
|
@ -0,0 +1,13 @@
|
|||
name = "File test"
|
||||
description = "Support module for file handling tests."
|
||||
package = Testing
|
||||
version = VERSION
|
||||
core = 7.x
|
||||
files[] = file_test.module
|
||||
hidden = TRUE
|
||||
|
||||
; Information added by Drupal.org packaging script on 2017-06-21
|
||||
version = "7.56"
|
||||
project = "drupal"
|
||||
datestamp = "1498069849"
|
||||
|
461
modules/simpletest/tests/file_test.module
Normal file
461
modules/simpletest/tests/file_test.module
Normal file
|
@ -0,0 +1,461 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Helper module for the file tests.
|
||||
*
|
||||
* The caller is must call file_test_reset() to initializing this module before
|
||||
* calling file_test_get_calls() or file_test_set_return().
|
||||
*/
|
||||
|
||||
|
||||
define('FILE_URL_TEST_CDN_1', 'http://cdn1.example.com');
|
||||
define('FILE_URL_TEST_CDN_2', 'http://cdn2.example.com');
|
||||
|
||||
|
||||
/**
|
||||
* Implements hook_menu().
|
||||
*/
|
||||
function file_test_menu() {
|
||||
$items['file-test/upload'] = array(
|
||||
'title' => 'Upload test',
|
||||
'page callback' => 'drupal_get_form',
|
||||
'page arguments' => array('_file_test_form'),
|
||||
'access arguments' => array('access content'),
|
||||
'type' => MENU_CALLBACK,
|
||||
);
|
||||
return $items;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements hook_stream_wrappers().
|
||||
*/
|
||||
function file_test_stream_wrappers() {
|
||||
return array(
|
||||
'dummy' => array(
|
||||
'name' => t('Dummy files'),
|
||||
'class' => 'DrupalDummyStreamWrapper',
|
||||
'description' => t('Dummy wrapper for simpletest.'),
|
||||
),
|
||||
'dummy-remote' => array(
|
||||
'name' => t('Dummy files (remote)'),
|
||||
'class' => 'DrupalDummyRemoteStreamWrapper',
|
||||
'description' => t('Dummy wrapper for simpletest (remote).'),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Form to test file uploads.
|
||||
*/
|
||||
function _file_test_form($form, &$form_state) {
|
||||
$form['file_test_upload'] = array(
|
||||
'#type' => 'file',
|
||||
'#title' => t('Upload a file'),
|
||||
);
|
||||
$form['file_test_replace'] = array(
|
||||
'#type' => 'select',
|
||||
'#title' => t('Replace existing image'),
|
||||
'#options' => array(
|
||||
FILE_EXISTS_RENAME => t('Appends number until name is unique'),
|
||||
FILE_EXISTS_REPLACE => t('Replace the existing file'),
|
||||
FILE_EXISTS_ERROR => t('Fail with an error'),
|
||||
),
|
||||
'#default_value' => FILE_EXISTS_RENAME,
|
||||
);
|
||||
$form['file_subdir'] = array(
|
||||
'#type' => 'textfield',
|
||||
'#title' => t('Subdirectory for test file'),
|
||||
'#default_value' => '',
|
||||
);
|
||||
|
||||
$form['extensions'] = array(
|
||||
'#type' => 'textfield',
|
||||
'#title' => t('Allowed extensions.'),
|
||||
'#default_value' => '',
|
||||
);
|
||||
|
||||
$form['allow_all_extensions'] = array(
|
||||
'#type' => 'checkbox',
|
||||
'#title' => t('Allow all extensions?'),
|
||||
'#default_value' => FALSE,
|
||||
);
|
||||
|
||||
$form['is_image_file'] = array(
|
||||
'#type' => 'checkbox',
|
||||
'#title' => t('Is this an image file?'),
|
||||
'#default_value' => TRUE,
|
||||
);
|
||||
|
||||
$form['submit'] = array(
|
||||
'#type' => 'submit',
|
||||
'#value' => t('Submit'),
|
||||
);
|
||||
return $form;
|
||||
}
|
||||
|
||||
/**
|
||||
* Process the upload.
|
||||
*/
|
||||
function _file_test_form_submit(&$form, &$form_state) {
|
||||
// Process the upload and perform validation. Note: we're using the
|
||||
// form value for the $replace parameter.
|
||||
if (!empty($form_state['values']['file_subdir'])) {
|
||||
$destination = 'temporary://' . $form_state['values']['file_subdir'];
|
||||
file_prepare_directory($destination, FILE_CREATE_DIRECTORY);
|
||||
}
|
||||
else {
|
||||
$destination = FALSE;
|
||||
}
|
||||
|
||||
// Setup validators.
|
||||
$validators = array();
|
||||
if ($form_state['values']['is_image_file']) {
|
||||
$validators['file_validate_is_image'] = array();
|
||||
}
|
||||
|
||||
if ($form_state['values']['allow_all_extensions']) {
|
||||
$validators['file_validate_extensions'] = array();
|
||||
}
|
||||
elseif (!empty($form_state['values']['extensions'])) {
|
||||
$validators['file_validate_extensions'] = array($form_state['values']['extensions']);
|
||||
}
|
||||
|
||||
$file = file_save_upload('file_test_upload', $validators, $destination, $form_state['values']['file_test_replace']);
|
||||
if ($file) {
|
||||
$form_state['values']['file_test_upload'] = $file;
|
||||
drupal_set_message(t('File @filepath was uploaded.', array('@filepath' => $file->uri)));
|
||||
drupal_set_message(t('File name is @filename.', array('@filename' => $file->filename)));
|
||||
drupal_set_message(t('File MIME type is @mimetype.', array('@mimetype' => $file->filemime)));
|
||||
drupal_set_message(t('You WIN!'));
|
||||
}
|
||||
elseif ($file === FALSE) {
|
||||
drupal_set_message(t('Epic upload FAIL!'), 'error');
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Reset/initialize the history of calls to the file_* hooks.
|
||||
*
|
||||
* @see file_test_get_calls()
|
||||
* @see file_test_reset()
|
||||
*/
|
||||
function file_test_reset() {
|
||||
// Keep track of calls to these hooks
|
||||
$results = array(
|
||||
'load' => array(),
|
||||
'validate' => array(),
|
||||
'download' => array(),
|
||||
'insert' => array(),
|
||||
'update' => array(),
|
||||
'copy' => array(),
|
||||
'move' => array(),
|
||||
'delete' => array(),
|
||||
);
|
||||
variable_set('file_test_results', $results);
|
||||
|
||||
// These hooks will return these values, see file_test_set_return().
|
||||
$return = array(
|
||||
'validate' => array(),
|
||||
'download' => NULL,
|
||||
);
|
||||
variable_set('file_test_return', $return);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the arguments passed to invocation of a given hook since
|
||||
* file_test_reset() was last called.
|
||||
*
|
||||
* @param $op
|
||||
* One of the hook_file_* operations: 'load', 'validate', 'download',
|
||||
* 'insert', 'update', 'copy', 'move', 'delete'.
|
||||
*
|
||||
* @return
|
||||
* Array of the parameters passed to each call.
|
||||
*
|
||||
* @see _file_test_log_call()
|
||||
* @see file_test_reset()
|
||||
*/
|
||||
function file_test_get_calls($op) {
|
||||
$results = variable_get('file_test_results', array());
|
||||
return $results[$op];
|
||||
}
|
||||
|
||||
/**
|
||||
* Get an array with the calls for all hooks.
|
||||
*
|
||||
* @return
|
||||
* An array keyed by hook name ('load', 'validate', 'download', 'insert',
|
||||
* 'update', 'copy', 'move', 'delete') with values being arrays of parameters
|
||||
* passed to each call.
|
||||
*/
|
||||
function file_test_get_all_calls() {
|
||||
return variable_get('file_test_results', array());
|
||||
}
|
||||
|
||||
/**
|
||||
* Store the values passed to a hook invocation.
|
||||
*
|
||||
* @param $op
|
||||
* One of the hook_file_* operations: 'load', 'validate', 'download',
|
||||
* 'insert', 'update', 'copy', 'move', 'delete'.
|
||||
* @param $args
|
||||
* Values passed to hook.
|
||||
*
|
||||
* @see file_test_get_calls()
|
||||
* @see file_test_reset()
|
||||
*/
|
||||
function _file_test_log_call($op, $args) {
|
||||
$results = variable_get('file_test_results', array());
|
||||
$results[$op][] = $args;
|
||||
variable_set('file_test_results', $results);
|
||||
}
|
||||
|
||||
/**
|
||||
* Load the appropriate return value.
|
||||
*
|
||||
* @param $op
|
||||
* One of the hook_file_[validate,download] operations.
|
||||
*
|
||||
* @return
|
||||
* Value set by file_test_set_return().
|
||||
*
|
||||
* @see file_test_set_return()
|
||||
* @see file_test_reset()
|
||||
*/
|
||||
function _file_test_get_return($op) {
|
||||
$return = variable_get('file_test_return', array($op => NULL));
|
||||
return $return[$op];
|
||||
}
|
||||
|
||||
/**
|
||||
* Assign a return value for a given operation.
|
||||
*
|
||||
* @param $op
|
||||
* One of the hook_file_[validate,download] operations.
|
||||
* @param $value
|
||||
* Value for the hook to return.
|
||||
*
|
||||
* @see _file_test_get_return()
|
||||
* @see file_test_reset()
|
||||
*/
|
||||
function file_test_set_return($op, $value) {
|
||||
$return = variable_get('file_test_return', array());
|
||||
$return[$op] = $value;
|
||||
variable_set('file_test_return', $return);
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements hook_file_load().
|
||||
*/
|
||||
function file_test_file_load($files) {
|
||||
foreach ($files as $file) {
|
||||
_file_test_log_call('load', array($file));
|
||||
// Assign a value on the object so that we can test that the $file is passed
|
||||
// by reference.
|
||||
$file->file_test['loaded'] = TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements hook_file_validate().
|
||||
*/
|
||||
function file_test_file_validate($file) {
|
||||
_file_test_log_call('validate', array($file));
|
||||
return _file_test_get_return('validate');
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements hook_file_download().
|
||||
*/
|
||||
function file_test_file_download($uri) {
|
||||
_file_test_log_call('download', array($uri));
|
||||
return _file_test_get_return('download');
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements hook_file_insert().
|
||||
*/
|
||||
function file_test_file_insert($file) {
|
||||
_file_test_log_call('insert', array($file));
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements hook_file_update().
|
||||
*/
|
||||
function file_test_file_update($file) {
|
||||
_file_test_log_call('update', array($file));
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements hook_file_copy().
|
||||
*/
|
||||
function file_test_file_copy($file, $source) {
|
||||
_file_test_log_call('copy', array($file, $source));
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements hook_file_move().
|
||||
*/
|
||||
function file_test_file_move($file, $source) {
|
||||
_file_test_log_call('move', array($file, $source));
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements hook_file_delete().
|
||||
*/
|
||||
function file_test_file_delete($file) {
|
||||
_file_test_log_call('delete', array($file));
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements hook_file_url_alter().
|
||||
*/
|
||||
function file_test_file_url_alter(&$uri) {
|
||||
// Only run this hook when this variable is set. Otherwise, we'd have to add
|
||||
// another hidden test module just for this hook.
|
||||
$alter_mode = variable_get('file_test_hook_file_url_alter', FALSE);
|
||||
if (!$alter_mode) {
|
||||
return;
|
||||
}
|
||||
// Test alteration of file URLs to use a CDN.
|
||||
elseif ($alter_mode == 'cdn') {
|
||||
$cdn_extensions = array('css', 'js', 'gif', 'jpg', 'jpeg', 'png');
|
||||
|
||||
// Most CDNs don't support private file transfers without a lot of hassle,
|
||||
// so don't support this in the common case.
|
||||
$schemes = array('public');
|
||||
|
||||
$scheme = file_uri_scheme($uri);
|
||||
|
||||
// Only serve shipped files and public created files from the CDN.
|
||||
if (!$scheme || in_array($scheme, $schemes)) {
|
||||
// Shipped files.
|
||||
if (!$scheme) {
|
||||
$path = $uri;
|
||||
}
|
||||
// Public created files.
|
||||
else {
|
||||
$wrapper = file_stream_wrapper_get_instance_by_scheme($scheme);
|
||||
$path = $wrapper->getDirectoryPath() . '/' . file_uri_target($uri);
|
||||
}
|
||||
|
||||
// Clean up Windows paths.
|
||||
$path = str_replace('\\', '/', $path);
|
||||
|
||||
// Serve files with one of the CDN extensions from CDN 1, all others from
|
||||
// CDN 2.
|
||||
$pathinfo = pathinfo($path);
|
||||
if (array_key_exists('extension', $pathinfo) && in_array($pathinfo['extension'], $cdn_extensions)) {
|
||||
$uri = FILE_URL_TEST_CDN_1 . '/' . $path;
|
||||
}
|
||||
else {
|
||||
$uri = FILE_URL_TEST_CDN_2 . '/' . $path;
|
||||
}
|
||||
}
|
||||
}
|
||||
// Test alteration of file URLs to use root-relative URLs.
|
||||
elseif ($alter_mode == 'root-relative') {
|
||||
// Only serve shipped files and public created files with root-relative
|
||||
// URLs.
|
||||
$scheme = file_uri_scheme($uri);
|
||||
if (!$scheme || $scheme == 'public') {
|
||||
// Shipped files.
|
||||
if (!$scheme) {
|
||||
$path = $uri;
|
||||
}
|
||||
// Public created files.
|
||||
else {
|
||||
$wrapper = file_stream_wrapper_get_instance_by_scheme($scheme);
|
||||
$path = $wrapper->getDirectoryPath() . '/' . file_uri_target($uri);
|
||||
}
|
||||
|
||||
// Clean up Windows paths.
|
||||
$path = str_replace('\\', '/', $path);
|
||||
|
||||
// Generate a root-relative URL.
|
||||
$uri = base_path() . '/' . $path;
|
||||
}
|
||||
}
|
||||
// Test alteration of file URLs to use protocol-relative URLs.
|
||||
elseif ($alter_mode == 'protocol-relative') {
|
||||
// Only serve shipped files and public created files with protocol-relative
|
||||
// URLs.
|
||||
$scheme = file_uri_scheme($uri);
|
||||
if (!$scheme || $scheme == 'public') {
|
||||
// Shipped files.
|
||||
if (!$scheme) {
|
||||
$path = $uri;
|
||||
}
|
||||
// Public created files.
|
||||
else {
|
||||
$wrapper = file_stream_wrapper_get_instance_by_scheme($scheme);
|
||||
$path = $wrapper->getDirectoryPath() . '/' . file_uri_target($uri);
|
||||
}
|
||||
|
||||
// Clean up Windows paths.
|
||||
$path = str_replace('\\', '/', $path);
|
||||
|
||||
// Generate a protocol-relative URL.
|
||||
$uri = '/' . base_path() . '/' . $path;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements hook_file_mimetype_mapping_alter().
|
||||
*/
|
||||
function file_test_file_mimetype_mapping_alter(&$mapping) {
|
||||
// Add new mappings.
|
||||
$mapping['mimetypes']['file_test_mimetype_1'] = 'madeup/file_test_1';
|
||||
$mapping['mimetypes']['file_test_mimetype_2'] = 'madeup/file_test_2';
|
||||
$mapping['mimetypes']['file_test_mimetype_3'] = 'madeup/doc';
|
||||
$mapping['extensions']['file_test_1'] = 'file_test_mimetype_1';
|
||||
$mapping['extensions']['file_test_2'] = 'file_test_mimetype_2';
|
||||
$mapping['extensions']['file_test_3'] = 'file_test_mimetype_2';
|
||||
// Override existing mapping.
|
||||
$mapping['extensions']['doc'] = 'file_test_mimetype_3';
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper class for testing the stream wrapper registry.
|
||||
*
|
||||
* Dummy stream wrapper implementation (dummy://).
|
||||
*/
|
||||
class DrupalDummyStreamWrapper extends DrupalLocalStreamWrapper {
|
||||
function getDirectoryPath() {
|
||||
return variable_get('stream_public_path', 'sites/default/files');
|
||||
}
|
||||
|
||||
/**
|
||||
* Override getInternalUri().
|
||||
*
|
||||
* Return a dummy path for testing.
|
||||
*/
|
||||
function getInternalUri() {
|
||||
return '/dummy/example.txt';
|
||||
}
|
||||
|
||||
/**
|
||||
* Override getExternalUrl().
|
||||
*
|
||||
* Return the HTML URI of a public file.
|
||||
*/
|
||||
function getExternalUrl() {
|
||||
return '/dummy/example.txt';
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper class for testing the stream wrapper registry.
|
||||
*
|
||||
* Dummy remote stream wrapper implementation (dummy-remote://).
|
||||
*
|
||||
* Basically just the public scheme but not returning a local file for realpath.
|
||||
*/
|
||||
class DrupalDummyRemoteStreamWrapper extends DrupalPublicStreamWrapper {
|
||||
function realpath() {
|
||||
return FALSE;
|
||||
}
|
||||
}
|
168
modules/simpletest/tests/filetransfer.test
Normal file
168
modules/simpletest/tests/filetransfer.test
Normal file
|
@ -0,0 +1,168 @@
|
|||
<?php
|
||||
|
||||
|
||||
class FileTranferTest extends DrupalWebTestCase {
|
||||
protected $hostname = 'localhost';
|
||||
protected $username = 'drupal';
|
||||
protected $password = 'password';
|
||||
protected $port = '42';
|
||||
|
||||
public static function getInfo() {
|
||||
return array(
|
||||
'name' => 'FileTransfer unit tests',
|
||||
'description' => 'Test that the jail is respected and that protocols using recursive file move operations work.',
|
||||
'group' => 'System'
|
||||
);
|
||||
}
|
||||
|
||||
function setUp() {
|
||||
parent::setUp();
|
||||
$this->testConnection = TestFileTransfer::factory(DRUPAL_ROOT, array('hostname' => $this->hostname, 'username' => $this->username, 'password' => $this->password, 'port' => $this->port));
|
||||
}
|
||||
|
||||
function _getFakeModuleFiles() {
|
||||
$files = array(
|
||||
'fake.module',
|
||||
'fake.info',
|
||||
'theme' => array(
|
||||
'fake.tpl.php'
|
||||
),
|
||||
'inc' => array(
|
||||
'fake.inc'
|
||||
)
|
||||
);
|
||||
return $files;
|
||||
}
|
||||
|
||||
function _buildFakeModule() {
|
||||
$location = 'temporary://fake';
|
||||
if (is_dir($location)) {
|
||||
$ret = 0;
|
||||
$output = array();
|
||||
exec('rm -Rf ' . escapeshellarg($location), $output, $ret);
|
||||
if ($ret != 0) {
|
||||
throw new Exception('Error removing fake module directory.');
|
||||
}
|
||||
}
|
||||
|
||||
$files = $this->_getFakeModuleFiles();
|
||||
$this->_writeDirectory($location, $files);
|
||||
return $location;
|
||||
}
|
||||
|
||||
function _writeDirectory($base, $files = array()) {
|
||||
mkdir($base);
|
||||
foreach ($files as $key => $file) {
|
||||
if (is_array($file)) {
|
||||
$this->_writeDirectory($base . DIRECTORY_SEPARATOR . $key, $file);
|
||||
}
|
||||
else {
|
||||
//just write the filename into the file
|
||||
file_put_contents($base . DIRECTORY_SEPARATOR . $file, $file);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function testJail() {
|
||||
$source = $this->_buildFakeModule();
|
||||
|
||||
// This convoluted piece of code is here because our testing framework does
|
||||
// not support expecting exceptions.
|
||||
$gotit = FALSE;
|
||||
try {
|
||||
$this->testConnection->copyDirectory($source, '/tmp');
|
||||
}
|
||||
catch (FileTransferException $e) {
|
||||
$gotit = TRUE;
|
||||
}
|
||||
$this->assertTrue($gotit, 'Was not able to copy a directory outside of the jailed area.');
|
||||
|
||||
$gotit = TRUE;
|
||||
try {
|
||||
$this->testConnection->copyDirectory($source, DRUPAL_ROOT . '/'. variable_get('file_public_path', conf_path() . '/files'));
|
||||
}
|
||||
catch (FileTransferException $e) {
|
||||
$gotit = FALSE;
|
||||
}
|
||||
$this->assertTrue($gotit, 'Was able to copy a directory inside of the jailed area');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Mock FileTransfer object for test case.
|
||||
*/
|
||||
class TestFileTransfer extends FileTransfer {
|
||||
protected $host = NULL;
|
||||
protected $username = NULL;
|
||||
protected $password = NULL;
|
||||
protected $port = NULL;
|
||||
|
||||
/**
|
||||
* This is for testing the CopyRecursive logic.
|
||||
*/
|
||||
public $shouldIsDirectoryReturnTrue = FALSE;
|
||||
|
||||
function __construct($jail, $username, $password, $hostname = 'localhost', $port = 9999) {
|
||||
parent::__construct($jail, $username, $password, $hostname, $port);
|
||||
}
|
||||
|
||||
static function factory($jail, $settings) {
|
||||
return new TestFileTransfer($jail, $settings['username'], $settings['password'], $settings['hostname'], $settings['port']);
|
||||
}
|
||||
|
||||
function connect() {
|
||||
$parts = explode(':', $this->hostname);
|
||||
$port = (count($parts) == 2) ? $parts[1] : $this->port;
|
||||
$this->connection = new MockTestConnection();
|
||||
$this->connection->connectionString = 'test://' . urlencode($this->username) . ':' . urlencode($this->password) . "@$this->host:$this->port/";
|
||||
}
|
||||
|
||||
function copyFileJailed($source, $destination) {
|
||||
$this->connection->run("copyFile $source $destination");
|
||||
}
|
||||
|
||||
protected function removeDirectoryJailed($directory) {
|
||||
$this->connection->run("rmdir $directory");
|
||||
}
|
||||
|
||||
function createDirectoryJailed($directory) {
|
||||
$this->connection->run("mkdir $directory");
|
||||
}
|
||||
|
||||
function removeFileJailed($destination) {
|
||||
if (!ftp_delete($this->connection, $item)) {
|
||||
throw new FileTransferException('Unable to remove to file @file.', NULL, array('@file' => $item));
|
||||
}
|
||||
}
|
||||
|
||||
function isDirectory($path) {
|
||||
return $this->shouldIsDirectoryReturnTrue;
|
||||
}
|
||||
|
||||
function isFile($path) {
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
function chmodJailed($path, $mode, $recursive) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Mock connection object for test case.
|
||||
*/
|
||||
class MockTestConnection {
|
||||
|
||||
var $commandsRun = array();
|
||||
var $connectionString;
|
||||
|
||||
function run($cmd) {
|
||||
$this->commandsRun[] = $cmd;
|
||||
}
|
||||
|
||||
function flushCommands() {
|
||||
$out = $this->commandsRun;
|
||||
$this->commandsRun = array();
|
||||
return $out;
|
||||
}
|
||||
}
|
12
modules/simpletest/tests/filter_test.info
Normal file
12
modules/simpletest/tests/filter_test.info
Normal file
|
@ -0,0 +1,12 @@
|
|||
name = Filter test module
|
||||
description = Tests filter hooks and functions.
|
||||
package = Testing
|
||||
version = VERSION
|
||||
core = 7.x
|
||||
hidden = TRUE
|
||||
|
||||
; Information added by Drupal.org packaging script on 2017-06-21
|
||||
version = "7.56"
|
||||
project = "drupal"
|
||||
datestamp = "1498069849"
|
||||
|
64
modules/simpletest/tests/filter_test.module
Normal file
64
modules/simpletest/tests/filter_test.module
Normal file
|
@ -0,0 +1,64 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Test module for Filter module hooks and functions not used in core.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Implements hook_filter_format_insert().
|
||||
*/
|
||||
function filter_test_filter_format_insert($format) {
|
||||
drupal_set_message('hook_filter_format_insert invoked.');
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements hook_filter_format_update().
|
||||
*/
|
||||
function filter_test_filter_format_update($format) {
|
||||
drupal_set_message('hook_filter_format_update invoked.');
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements hook_filter_format_disable().
|
||||
*/
|
||||
function filter_test_filter_format_disable($format) {
|
||||
drupal_set_message('hook_filter_format_disable invoked.');
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements hook_filter_info().
|
||||
*/
|
||||
function filter_test_filter_info() {
|
||||
$filters['filter_test_uncacheable'] = array(
|
||||
'title' => 'Uncacheable filter',
|
||||
'description' => 'Does nothing, but makes a text format uncacheable.',
|
||||
'cache' => FALSE,
|
||||
);
|
||||
$filters['filter_test_replace'] = array(
|
||||
'title' => 'Testing filter',
|
||||
'description' => 'Replaces all content with filter and text format information.',
|
||||
'process callback' => 'filter_test_replace',
|
||||
);
|
||||
return $filters;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements callback_filter_process().
|
||||
*
|
||||
* Process handler for filter_test_replace filter.
|
||||
*
|
||||
* Replaces all text with filter and text format information.
|
||||
*/
|
||||
function filter_test_replace($text, $filter, $format, $langcode, $cache, $cache_id) {
|
||||
$text = array();
|
||||
$text[] = 'Filter: ' . $filter->title . ' (' . $filter->name . ')';
|
||||
$text[] = 'Format: ' . $format->name . ' (' . $format->format . ')';
|
||||
$text[] = 'Language: ' . $langcode;
|
||||
$text[] = 'Cache: ' . ($cache ? 'Enabled' : 'Disabled');
|
||||
if ($cache_id) {
|
||||
$text[] = 'Cache ID: ' . $cache_id;
|
||||
}
|
||||
return implode("<br />\n", $text);
|
||||
}
|
||||
|
2162
modules/simpletest/tests/form.test
Normal file
2162
modules/simpletest/tests/form.test
Normal file
File diff suppressed because it is too large
Load diff
48
modules/simpletest/tests/form_test.file.inc
Normal file
48
modules/simpletest/tests/form_test.file.inc
Normal file
|
@ -0,0 +1,48 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* An include file to test loading it with the form API.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Form constructor for testing FAPI file inclusion of the file specified in
|
||||
* hook_menu().
|
||||
*/
|
||||
function form_test_load_include_menu($form, &$form_state) {
|
||||
// Submit the form via Ajax. That way the FAPI has to care about including
|
||||
// the file specified in hook_menu().
|
||||
$ajax_wrapper_id = drupal_html_id('form-test-load-include-menu-ajax-wrapper');
|
||||
$form['ajax_wrapper'] = array(
|
||||
'#markup' => '<div id="' . $ajax_wrapper_id . '"></div>',
|
||||
);
|
||||
$form['button'] = array(
|
||||
'#type' => 'submit',
|
||||
'#value' => t('Save'),
|
||||
'#submit' => array('form_test_load_include_submit'),
|
||||
'#ajax' => array(
|
||||
'wrapper' => $ajax_wrapper_id,
|
||||
'method' => 'append',
|
||||
'callback' => 'form_test_load_include_menu_ajax',
|
||||
),
|
||||
);
|
||||
return $form;
|
||||
}
|
||||
|
||||
/**
|
||||
* Submit callback for the form API file inclusion test forms.
|
||||
*/
|
||||
function form_test_load_include_submit($form, $form_state) {
|
||||
drupal_set_message('Submit callback called.');
|
||||
}
|
||||
|
||||
/**
|
||||
* Ajax callback for the file inclusion via menu test.
|
||||
*/
|
||||
function form_test_load_include_menu_ajax($form) {
|
||||
// We don't need to return anything, since #ajax['method'] is 'append', which
|
||||
// does not remove the original #ajax['wrapper'] element, and status messages
|
||||
// are automatically added by the Ajax framework as long as there's a wrapper
|
||||
// element to add them to.
|
||||
return '';
|
||||
}
|
12
modules/simpletest/tests/form_test.info
Normal file
12
modules/simpletest/tests/form_test.info
Normal file
|
@ -0,0 +1,12 @@
|
|||
name = "FormAPI Test"
|
||||
description = "Support module for Form API tests."
|
||||
package = Testing
|
||||
version = VERSION
|
||||
core = 7.x
|
||||
hidden = TRUE
|
||||
|
||||
; Information added by Drupal.org packaging script on 2017-06-21
|
||||
version = "7.56"
|
||||
project = "drupal"
|
||||
datestamp = "1498069849"
|
||||
|
1990
modules/simpletest/tests/form_test.module
Normal file
1990
modules/simpletest/tests/form_test.module
Normal file
File diff suppressed because it is too large
Load diff
195
modules/simpletest/tests/graph.test
Normal file
195
modules/simpletest/tests/graph.test
Normal file
|
@ -0,0 +1,195 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Provides unit tests for graph.inc.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Unit tests for the graph handling features.
|
||||
*/
|
||||
class GraphUnitTest extends DrupalUnitTestCase {
|
||||
public static function getInfo() {
|
||||
return array(
|
||||
'name' => 'Graph',
|
||||
'description' => 'Graph handling unit tests.',
|
||||
'group' => 'System',
|
||||
);
|
||||
}
|
||||
|
||||
function setUp() {
|
||||
require_once DRUPAL_ROOT . '/includes/graph.inc';
|
||||
parent::setUp();
|
||||
}
|
||||
|
||||
/**
|
||||
* Test depth-first-search features.
|
||||
*/
|
||||
function testDepthFirstSearch() {
|
||||
// The sample graph used is:
|
||||
// 1 --> 2 --> 3 5 ---> 6
|
||||
// | ^ ^
|
||||
// | | |
|
||||
// | | |
|
||||
// +---> 4 <-- 7 8 ---> 9
|
||||
$graph = $this->normalizeGraph(array(
|
||||
1 => array(2),
|
||||
2 => array(3, 4),
|
||||
3 => array(),
|
||||
4 => array(3),
|
||||
5 => array(6),
|
||||
7 => array(4, 5),
|
||||
8 => array(9),
|
||||
9 => array(),
|
||||
));
|
||||
drupal_depth_first_search($graph);
|
||||
|
||||
$expected_paths = array(
|
||||
1 => array(2, 3, 4),
|
||||
2 => array(3, 4),
|
||||
3 => array(),
|
||||
4 => array(3),
|
||||
5 => array(6),
|
||||
7 => array(4, 3, 5, 6),
|
||||
8 => array(9),
|
||||
9 => array(),
|
||||
);
|
||||
$this->assertPaths($graph, $expected_paths);
|
||||
|
||||
$expected_reverse_paths = array(
|
||||
1 => array(),
|
||||
2 => array(1),
|
||||
3 => array(2, 1, 4, 7),
|
||||
4 => array(2, 1, 7),
|
||||
5 => array(7),
|
||||
7 => array(),
|
||||
8 => array(),
|
||||
9 => array(8),
|
||||
);
|
||||
$this->assertReversePaths($graph, $expected_reverse_paths);
|
||||
|
||||
// Assert that DFS didn't created "missing" vertexes automatically.
|
||||
$this->assertFALSE(isset($graph[6]), 'Vertex 6 has not been created');
|
||||
|
||||
$expected_components = array(
|
||||
array(1, 2, 3, 4, 5, 7),
|
||||
array(8, 9),
|
||||
);
|
||||
$this->assertComponents($graph, $expected_components);
|
||||
|
||||
$expected_weights = array(
|
||||
array(1, 2, 3),
|
||||
array(2, 4, 3),
|
||||
array(7, 4, 3),
|
||||
array(7, 5),
|
||||
array(8, 9),
|
||||
);
|
||||
$this->assertWeights($graph, $expected_weights);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a normalized version of a graph.
|
||||
*/
|
||||
function normalizeGraph($graph) {
|
||||
$normalized_graph = array();
|
||||
foreach ($graph as $vertex => $edges) {
|
||||
// Create vertex even if it hasn't any edges.
|
||||
$normalized_graph[$vertex] = array();
|
||||
foreach ($edges as $edge) {
|
||||
$normalized_graph[$vertex]['edges'][$edge] = TRUE;
|
||||
}
|
||||
}
|
||||
return $normalized_graph;
|
||||
}
|
||||
|
||||
/**
|
||||
* Verify expected paths in a graph.
|
||||
*
|
||||
* @param $graph
|
||||
* A graph array processed by drupal_depth_first_search().
|
||||
* @param $expected_paths
|
||||
* An associative array containing vertices with their expected paths.
|
||||
*/
|
||||
function assertPaths($graph, $expected_paths) {
|
||||
foreach ($expected_paths as $vertex => $paths) {
|
||||
// Build an array with keys = $paths and values = TRUE.
|
||||
$expected = array_fill_keys($paths, TRUE);
|
||||
$result = isset($graph[$vertex]['paths']) ? $graph[$vertex]['paths'] : array();
|
||||
$this->assertEqual($expected, $result, format_string('Expected paths for vertex @vertex: @expected-paths, got @paths', array('@vertex' => $vertex, '@expected-paths' => $this->displayArray($expected, TRUE), '@paths' => $this->displayArray($result, TRUE))));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Verify expected reverse paths in a graph.
|
||||
*
|
||||
* @param $graph
|
||||
* A graph array processed by drupal_depth_first_search().
|
||||
* @param $expected_reverse_paths
|
||||
* An associative array containing vertices with their expected reverse
|
||||
* paths.
|
||||
*/
|
||||
function assertReversePaths($graph, $expected_reverse_paths) {
|
||||
foreach ($expected_reverse_paths as $vertex => $paths) {
|
||||
// Build an array with keys = $paths and values = TRUE.
|
||||
$expected = array_fill_keys($paths, TRUE);
|
||||
$result = isset($graph[$vertex]['reverse_paths']) ? $graph[$vertex]['reverse_paths'] : array();
|
||||
$this->assertEqual($expected, $result, format_string('Expected reverse paths for vertex @vertex: @expected-paths, got @paths', array('@vertex' => $vertex, '@expected-paths' => $this->displayArray($expected, TRUE), '@paths' => $this->displayArray($result, TRUE))));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Verify expected components in a graph.
|
||||
*
|
||||
* @param $graph
|
||||
* A graph array processed by drupal_depth_first_search().
|
||||
* @param $expected_components
|
||||
* An array containing of components defined as a list of their vertices.
|
||||
*/
|
||||
function assertComponents($graph, $expected_components) {
|
||||
$unassigned_vertices = array_fill_keys(array_keys($graph), TRUE);
|
||||
foreach ($expected_components as $component) {
|
||||
$result_components = array();
|
||||
foreach ($component as $vertex) {
|
||||
$result_components[] = $graph[$vertex]['component'];
|
||||
unset($unassigned_vertices[$vertex]);
|
||||
}
|
||||
$this->assertEqual(1, count(array_unique($result_components)), format_string('Expected one unique component for vertices @vertices, got @components', array('@vertices' => $this->displayArray($component), '@components' => $this->displayArray($result_components))));
|
||||
}
|
||||
$this->assertEqual(array(), $unassigned_vertices, format_string('Vertices not assigned to a component: @vertices', array('@vertices' => $this->displayArray($unassigned_vertices, TRUE))));
|
||||
}
|
||||
|
||||
/**
|
||||
* Verify expected order in a graph.
|
||||
*
|
||||
* @param $graph
|
||||
* A graph array processed by drupal_depth_first_search().
|
||||
* @param $expected_orders
|
||||
* An array containing lists of vertices in their expected order.
|
||||
*/
|
||||
function assertWeights($graph, $expected_orders) {
|
||||
foreach ($expected_orders as $order) {
|
||||
$previous_vertex = array_shift($order);
|
||||
foreach ($order as $vertex) {
|
||||
$this->assertTrue($graph[$previous_vertex]['weight'] < $graph[$vertex]['weight'], format_string('Weights of @previous-vertex and @vertex are correct relative to each other', array('@previous-vertex' => $previous_vertex, '@vertex' => $vertex)));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper function to output vertices as comma-separated list.
|
||||
*
|
||||
* @param $paths
|
||||
* An array containing a list of vertices.
|
||||
* @param $keys
|
||||
* (optional) Whether to output the keys of $paths instead of the values.
|
||||
*/
|
||||
function displayArray($paths, $keys = FALSE) {
|
||||
if (!empty($paths)) {
|
||||
return implode(', ', $keys ? array_keys($paths) : $paths);
|
||||
}
|
||||
else {
|
||||
return '(empty)';
|
||||
}
|
||||
}
|
||||
}
|
||||
|
32
modules/simpletest/tests/http.php
Normal file
32
modules/simpletest/tests/http.php
Normal file
|
@ -0,0 +1,32 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Fake an HTTP request, for use during testing.
|
||||
*/
|
||||
|
||||
// Set a global variable to indicate a mock HTTP request.
|
||||
$is_http_mock = !empty($_SERVER['HTTPS']);
|
||||
|
||||
// Change to HTTP.
|
||||
$_SERVER['HTTPS'] = NULL;
|
||||
ini_set('session.cookie_secure', FALSE);
|
||||
foreach ($_SERVER as $key => $value) {
|
||||
$_SERVER[$key] = str_replace('modules/simpletest/tests/http.php', 'index.php', $value);
|
||||
$_SERVER[$key] = str_replace('https://', 'http://', $_SERVER[$key]);
|
||||
}
|
||||
|
||||
// Change current directory to the Drupal root.
|
||||
chdir('../../..');
|
||||
define('DRUPAL_ROOT', getcwd());
|
||||
require_once DRUPAL_ROOT . '/includes/bootstrap.inc';
|
||||
|
||||
// Make sure this file can only be used by simpletest.
|
||||
drupal_bootstrap(DRUPAL_BOOTSTRAP_CONFIGURATION);
|
||||
if (!drupal_valid_test_ua()) {
|
||||
header($_SERVER['SERVER_PROTOCOL'] . ' 403 Forbidden');
|
||||
exit;
|
||||
}
|
||||
|
||||
drupal_bootstrap(DRUPAL_BOOTSTRAP_FULL);
|
||||
menu_execute_active_handler();
|
31
modules/simpletest/tests/https.php
Normal file
31
modules/simpletest/tests/https.php
Normal file
|
@ -0,0 +1,31 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Fake an HTTPS request, for use during testing.
|
||||
*/
|
||||
|
||||
// Set a global variable to indicate a mock HTTPS request.
|
||||
$is_https_mock = empty($_SERVER['HTTPS']);
|
||||
|
||||
// Change to HTTPS.
|
||||
$_SERVER['HTTPS'] = 'on';
|
||||
foreach ($_SERVER as $key => $value) {
|
||||
$_SERVER[$key] = str_replace('modules/simpletest/tests/https.php', 'index.php', $value);
|
||||
$_SERVER[$key] = str_replace('http://', 'https://', $_SERVER[$key]);
|
||||
}
|
||||
|
||||
// Change current directory to the Drupal root.
|
||||
chdir('../../..');
|
||||
define('DRUPAL_ROOT', getcwd());
|
||||
require_once DRUPAL_ROOT . '/includes/bootstrap.inc';
|
||||
|
||||
// Make sure this file can only be used by simpletest.
|
||||
drupal_bootstrap(DRUPAL_BOOTSTRAP_CONFIGURATION);
|
||||
if (!drupal_valid_test_ua()) {
|
||||
header($_SERVER['SERVER_PROTOCOL'] . ' 403 Forbidden');
|
||||
exit;
|
||||
}
|
||||
|
||||
drupal_bootstrap(DRUPAL_BOOTSTRAP_FULL);
|
||||
menu_execute_active_handler();
|
578
modules/simpletest/tests/image.test
Normal file
578
modules/simpletest/tests/image.test
Normal file
|
@ -0,0 +1,578 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Tests for core image handling API.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Base class for image manipulation testing.
|
||||
*/
|
||||
class ImageToolkitTestCase extends DrupalWebTestCase {
|
||||
protected $toolkit;
|
||||
protected $file;
|
||||
protected $image;
|
||||
|
||||
function setUp() {
|
||||
$modules = func_get_args();
|
||||
if (isset($modules[0]) && is_array($modules[0])) {
|
||||
$modules = $modules[0];
|
||||
}
|
||||
$modules[] = 'image_test';
|
||||
|
||||
parent::setUp($modules);
|
||||
|
||||
// Use the image_test.module's test toolkit.
|
||||
$this->toolkit = 'test';
|
||||
|
||||
// Pick a file for testing.
|
||||
$file = current($this->drupalGetTestFiles('image'));
|
||||
$this->file = $file->uri;
|
||||
|
||||
// Setup a dummy image to work with, this replicate image_load() so we
|
||||
// can avoid calling it.
|
||||
$this->image = new stdClass();
|
||||
$this->image->source = $this->file;
|
||||
$this->image->info = image_get_info($this->file);
|
||||
$this->image->toolkit = $this->toolkit;
|
||||
|
||||
// Clear out any hook calls.
|
||||
image_test_reset();
|
||||
}
|
||||
|
||||
/**
|
||||
* Assert that all of the specified image toolkit operations were called
|
||||
* exactly once once, other values result in failure.
|
||||
*
|
||||
* @param $expected
|
||||
* Array with string containing with the operation name, e.g. 'load',
|
||||
* 'save', 'crop', etc.
|
||||
*/
|
||||
function assertToolkitOperationsCalled(array $expected) {
|
||||
// Determine which operations were called.
|
||||
$actual = array_keys(array_filter(image_test_get_all_calls()));
|
||||
|
||||
// Determine if there were any expected that were not called.
|
||||
$uncalled = array_diff($expected, $actual);
|
||||
if (count($uncalled)) {
|
||||
$this->assertTrue(FALSE, format_string('Expected operations %expected to be called but %uncalled was not called.', array('%expected' => implode(', ', $expected), '%uncalled' => implode(', ', $uncalled))));
|
||||
}
|
||||
else {
|
||||
$this->assertTrue(TRUE, format_string('All the expected operations were called: %expected', array('%expected' => implode(', ', $expected))));
|
||||
}
|
||||
|
||||
// Determine if there were any unexpected calls.
|
||||
$unexpected = array_diff($actual, $expected);
|
||||
if (count($unexpected)) {
|
||||
$this->assertTrue(FALSE, format_string('Unexpected operations were called: %unexpected.', array('%unexpected' => implode(', ', $unexpected))));
|
||||
}
|
||||
else {
|
||||
$this->assertTrue(TRUE, 'No unexpected operations were called.');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Test that the functions in image.inc correctly pass data to the toolkit.
|
||||
*/
|
||||
class ImageToolkitUnitTest extends ImageToolkitTestCase {
|
||||
public static function getInfo() {
|
||||
return array(
|
||||
'name' => 'Image toolkit tests',
|
||||
'description' => 'Check image toolkit functions.',
|
||||
'group' => 'Image',
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Check that hook_image_toolkits() is called and only available toolkits are
|
||||
* returned.
|
||||
*/
|
||||
function testGetAvailableToolkits() {
|
||||
$toolkits = image_get_available_toolkits();
|
||||
$this->assertTrue(isset($toolkits['test']), 'The working toolkit was returned.');
|
||||
$this->assertFalse(isset($toolkits['broken']), 'The toolkit marked unavailable was not returned');
|
||||
$this->assertToolkitOperationsCalled(array());
|
||||
}
|
||||
|
||||
/**
|
||||
* Test the image_load() function.
|
||||
*/
|
||||
function testLoad() {
|
||||
$image = image_load($this->file, $this->toolkit);
|
||||
$this->assertTrue(is_object($image), 'Returned an object.');
|
||||
$this->assertEqual($this->toolkit, $image->toolkit, 'Image had toolkit set.');
|
||||
$this->assertToolkitOperationsCalled(array('load', 'get_info'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Test the image_save() function.
|
||||
*/
|
||||
function testSave() {
|
||||
$this->assertFalse(image_save($this->image), 'Function returned the expected value.');
|
||||
$this->assertToolkitOperationsCalled(array('save'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Test the image_resize() function.
|
||||
*/
|
||||
function testResize() {
|
||||
$this->assertTrue(image_resize($this->image, 1, 2), 'Function returned the expected value.');
|
||||
$this->assertToolkitOperationsCalled(array('resize'));
|
||||
|
||||
// Check the parameters.
|
||||
$calls = image_test_get_all_calls();
|
||||
$this->assertEqual($calls['resize'][0][1], 1, 'Width was passed correctly');
|
||||
$this->assertEqual($calls['resize'][0][2], 2, 'Height was passed correctly');
|
||||
}
|
||||
|
||||
/**
|
||||
* Test the image_scale() function.
|
||||
*/
|
||||
function testScale() {
|
||||
// TODO: need to test upscaling
|
||||
$this->assertTrue(image_scale($this->image, 10, 10), 'Function returned the expected value.');
|
||||
$this->assertToolkitOperationsCalled(array('resize'));
|
||||
|
||||
// Check the parameters.
|
||||
$calls = image_test_get_all_calls();
|
||||
$this->assertEqual($calls['resize'][0][1], 10, 'Width was passed correctly');
|
||||
$this->assertEqual($calls['resize'][0][2], 5, 'Height was based off aspect ratio and passed correctly');
|
||||
}
|
||||
|
||||
/**
|
||||
* Test the image_scale_and_crop() function.
|
||||
*/
|
||||
function testScaleAndCrop() {
|
||||
$this->assertTrue(image_scale_and_crop($this->image, 5, 10), 'Function returned the expected value.');
|
||||
$this->assertToolkitOperationsCalled(array('resize', 'crop'));
|
||||
|
||||
// Check the parameters.
|
||||
$calls = image_test_get_all_calls();
|
||||
|
||||
$this->assertEqual($calls['crop'][0][1], 7.5, 'X was computed and passed correctly');
|
||||
$this->assertEqual($calls['crop'][0][2], 0, 'Y was computed and passed correctly');
|
||||
$this->assertEqual($calls['crop'][0][3], 5, 'Width was computed and passed correctly');
|
||||
$this->assertEqual($calls['crop'][0][4], 10, 'Height was computed and passed correctly');
|
||||
}
|
||||
|
||||
/**
|
||||
* Test the image_rotate() function.
|
||||
*/
|
||||
function testRotate() {
|
||||
$this->assertTrue(image_rotate($this->image, 90, 1), 'Function returned the expected value.');
|
||||
$this->assertToolkitOperationsCalled(array('rotate'));
|
||||
|
||||
// Check the parameters.
|
||||
$calls = image_test_get_all_calls();
|
||||
$this->assertEqual($calls['rotate'][0][1], 90, 'Degrees were passed correctly');
|
||||
$this->assertEqual($calls['rotate'][0][2], 1, 'Background color was passed correctly');
|
||||
}
|
||||
|
||||
/**
|
||||
* Test the image_crop() function.
|
||||
*/
|
||||
function testCrop() {
|
||||
$this->assertTrue(image_crop($this->image, 1, 2, 3, 4), 'Function returned the expected value.');
|
||||
$this->assertToolkitOperationsCalled(array('crop'));
|
||||
|
||||
// Check the parameters.
|
||||
$calls = image_test_get_all_calls();
|
||||
$this->assertEqual($calls['crop'][0][1], 1, 'X was passed correctly');
|
||||
$this->assertEqual($calls['crop'][0][2], 2, 'Y was passed correctly');
|
||||
$this->assertEqual($calls['crop'][0][3], 3, 'Width was passed correctly');
|
||||
$this->assertEqual($calls['crop'][0][4], 4, 'Height was passed correctly');
|
||||
}
|
||||
|
||||
/**
|
||||
* Test the image_desaturate() function.
|
||||
*/
|
||||
function testDesaturate() {
|
||||
$this->assertTrue(image_desaturate($this->image), 'Function returned the expected value.');
|
||||
$this->assertToolkitOperationsCalled(array('desaturate'));
|
||||
|
||||
// Check the parameters.
|
||||
$calls = image_test_get_all_calls();
|
||||
$this->assertEqual(count($calls['desaturate'][0]), 1, 'Only the image was passed.');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Test the core GD image manipulation functions.
|
||||
*/
|
||||
class ImageToolkitGdTestCase extends DrupalWebTestCase {
|
||||
// Colors that are used in testing.
|
||||
protected $black = array(0, 0, 0, 0);
|
||||
protected $red = array(255, 0, 0, 0);
|
||||
protected $green = array(0, 255, 0, 0);
|
||||
protected $blue = array(0, 0, 255, 0);
|
||||
protected $yellow = array(255, 255, 0, 0);
|
||||
protected $white = array(255, 255, 255, 0);
|
||||
protected $transparent = array(0, 0, 0, 127);
|
||||
// Used as rotate background colors.
|
||||
protected $fuchsia = array(255, 0, 255, 0);
|
||||
protected $rotate_transparent = array(255, 255, 255, 127);
|
||||
|
||||
protected $width = 40;
|
||||
protected $height = 20;
|
||||
|
||||
public static function getInfo() {
|
||||
return array(
|
||||
'name' => 'Image GD manipulation tests',
|
||||
'description' => 'Check that core image manipulations work properly: scale, resize, rotate, crop, scale and crop, and desaturate.',
|
||||
'group' => 'Image',
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Function to compare two colors by RGBa.
|
||||
*/
|
||||
function colorsAreEqual($color_a, $color_b) {
|
||||
// Fully transparent pixels are equal, regardless of RGB.
|
||||
if ($color_a[3] == 127 && $color_b[3] == 127) {
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
foreach ($color_a as $key => $value) {
|
||||
if ($color_b[$key] != $value) {
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Function for finding a pixel's RGBa values.
|
||||
*/
|
||||
function getPixelColor($image, $x, $y) {
|
||||
$color_index = imagecolorat($image->resource, $x, $y);
|
||||
|
||||
$transparent_index = imagecolortransparent($image->resource);
|
||||
if ($color_index == $transparent_index) {
|
||||
return array(0, 0, 0, 127);
|
||||
}
|
||||
|
||||
return array_values(imagecolorsforindex($image->resource, $color_index));
|
||||
}
|
||||
|
||||
/**
|
||||
* Since PHP can't visually check that our images have been manipulated
|
||||
* properly, build a list of expected color values for each of the corners and
|
||||
* the expected height and widths for the final images.
|
||||
*/
|
||||
function testManipulations() {
|
||||
// If GD isn't available don't bother testing this.
|
||||
module_load_include('inc', 'system', 'image.gd');
|
||||
if (!function_exists('image_gd_check_settings') || !image_gd_check_settings()) {
|
||||
$this->pass(t('Image manipulations for the GD toolkit were skipped because the GD toolkit is not available.'));
|
||||
return;
|
||||
}
|
||||
|
||||
// Typically the corner colors will be unchanged. These colors are in the
|
||||
// order of top-left, top-right, bottom-right, bottom-left.
|
||||
$default_corners = array($this->red, $this->green, $this->blue, $this->transparent);
|
||||
|
||||
// A list of files that will be tested.
|
||||
$files = array(
|
||||
'image-test.png',
|
||||
'image-test.gif',
|
||||
'image-test-no-transparency.gif',
|
||||
'image-test.jpg',
|
||||
);
|
||||
|
||||
// Setup a list of tests to perform on each type.
|
||||
$operations = array(
|
||||
'resize' => array(
|
||||
'function' => 'resize',
|
||||
'arguments' => array(20, 10),
|
||||
'width' => 20,
|
||||
'height' => 10,
|
||||
'corners' => $default_corners,
|
||||
),
|
||||
'scale_x' => array(
|
||||
'function' => 'scale',
|
||||
'arguments' => array(20, NULL),
|
||||
'width' => 20,
|
||||
'height' => 10,
|
||||
'corners' => $default_corners,
|
||||
),
|
||||
'scale_y' => array(
|
||||
'function' => 'scale',
|
||||
'arguments' => array(NULL, 10),
|
||||
'width' => 20,
|
||||
'height' => 10,
|
||||
'corners' => $default_corners,
|
||||
),
|
||||
'upscale_x' => array(
|
||||
'function' => 'scale',
|
||||
'arguments' => array(80, NULL, TRUE),
|
||||
'width' => 80,
|
||||
'height' => 40,
|
||||
'corners' => $default_corners,
|
||||
),
|
||||
'upscale_y' => array(
|
||||
'function' => 'scale',
|
||||
'arguments' => array(NULL, 40, TRUE),
|
||||
'width' => 80,
|
||||
'height' => 40,
|
||||
'corners' => $default_corners,
|
||||
),
|
||||
'crop' => array(
|
||||
'function' => 'crop',
|
||||
'arguments' => array(12, 4, 16, 12),
|
||||
'width' => 16,
|
||||
'height' => 12,
|
||||
'corners' => array_fill(0, 4, $this->white),
|
||||
),
|
||||
'scale_and_crop' => array(
|
||||
'function' => 'scale_and_crop',
|
||||
'arguments' => array(10, 8),
|
||||
'width' => 10,
|
||||
'height' => 8,
|
||||
'corners' => array_fill(0, 4, $this->black),
|
||||
),
|
||||
);
|
||||
|
||||
// Systems using non-bundled GD2 don't have imagerotate. Test if available.
|
||||
if (function_exists('imagerotate')) {
|
||||
$operations += array(
|
||||
'rotate_90' => array(
|
||||
'function' => 'rotate',
|
||||
'arguments' => array(90, 0xFF00FF), // Fuchsia background.
|
||||
'width' => 20,
|
||||
'height' => 40,
|
||||
'corners' => array($this->fuchsia, $this->red, $this->green, $this->blue),
|
||||
),
|
||||
'rotate_transparent_90' => array(
|
||||
'function' => 'rotate',
|
||||
'arguments' => array(90),
|
||||
'width' => 20,
|
||||
'height' => 40,
|
||||
'corners' => array($this->transparent, $this->red, $this->green, $this->blue),
|
||||
),
|
||||
);
|
||||
// As of PHP version 5.5, GD uses a different algorithm to rotate images
|
||||
// than version 5.4 and below, resulting in different dimensions.
|
||||
// See https://bugs.php.net/bug.php?id=65148.
|
||||
// For the 40x20 test images, the dimensions resulting from rotation will
|
||||
// be 1 pixel smaller in both width and height in PHP 5.5 and above.
|
||||
// @todo: If and when the PHP bug gets solved, add an upper limit
|
||||
// version check.
|
||||
if (version_compare(PHP_VERSION, '5.5', '>=')) {
|
||||
$operations += array(
|
||||
'rotate_5' => array(
|
||||
'function' => 'rotate',
|
||||
'arguments' => array(5, 0xFF00FF), // Fuchsia background.
|
||||
'width' => 41,
|
||||
'height' => 23,
|
||||
'corners' => array_fill(0, 4, $this->fuchsia),
|
||||
),
|
||||
'rotate_transparent_5' => array(
|
||||
'function' => 'rotate',
|
||||
'arguments' => array(5),
|
||||
'width' => 41,
|
||||
'height' => 23,
|
||||
'corners' => array_fill(0, 4, $this->rotate_transparent),
|
||||
),
|
||||
);
|
||||
}
|
||||
else {
|
||||
$operations += array(
|
||||
'rotate_5' => array(
|
||||
'function' => 'rotate',
|
||||
'arguments' => array(5, 0xFF00FF), // Fuchsia background.
|
||||
'width' => 42,
|
||||
'height' => 24,
|
||||
'corners' => array_fill(0, 4, $this->fuchsia),
|
||||
),
|
||||
'rotate_transparent_5' => array(
|
||||
'function' => 'rotate',
|
||||
'arguments' => array(5),
|
||||
'width' => 42,
|
||||
'height' => 24,
|
||||
'corners' => array_fill(0, 4, $this->rotate_transparent),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
// Systems using non-bundled GD2 don't have imagefilter. Test if available.
|
||||
if (function_exists('imagefilter')) {
|
||||
$operations += array(
|
||||
'desaturate' => array(
|
||||
'function' => 'desaturate',
|
||||
'arguments' => array(),
|
||||
'height' => 20,
|
||||
'width' => 40,
|
||||
// Grayscale corners are a bit funky. Each of the corners are a shade of
|
||||
// gray. The values of these were determined simply by looking at the
|
||||
// final image to see what desaturated colors end up being.
|
||||
'corners' => array(
|
||||
array_fill(0, 3, 76) + array(3 => 0),
|
||||
array_fill(0, 3, 149) + array(3 => 0),
|
||||
array_fill(0, 3, 29) + array(3 => 0),
|
||||
array_fill(0, 3, 225) + array(3 => 127)
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
foreach ($files as $file) {
|
||||
foreach ($operations as $op => $values) {
|
||||
// Load up a fresh image.
|
||||
$image = image_load(drupal_get_path('module', 'simpletest') . '/files/' . $file, 'gd');
|
||||
if (!$image) {
|
||||
$this->fail(t('Could not load image %file.', array('%file' => $file)));
|
||||
continue 2;
|
||||
}
|
||||
|
||||
// All images should be converted to truecolor when loaded.
|
||||
$image_truecolor = imageistruecolor($image->resource);
|
||||
$this->assertTrue($image_truecolor, format_string('Image %file after load is a truecolor image.', array('%file' => $file)));
|
||||
|
||||
if ($image->info['extension'] == 'gif') {
|
||||
if ($op == 'desaturate') {
|
||||
// Transparent GIFs and the imagefilter function don't work together.
|
||||
$values['corners'][3][3] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
// Perform our operation.
|
||||
$function = 'image_' . $values['function'];
|
||||
$arguments = array();
|
||||
$arguments[] = &$image;
|
||||
$arguments = array_merge($arguments, $values['arguments']);
|
||||
call_user_func_array($function, $arguments);
|
||||
|
||||
// To keep from flooding the test with assert values, make a general
|
||||
// value for whether each group of values fail.
|
||||
$correct_dimensions_real = TRUE;
|
||||
$correct_dimensions_object = TRUE;
|
||||
$correct_colors = TRUE;
|
||||
|
||||
// Check the real dimensions of the image first.
|
||||
if (imagesy($image->resource) != $values['height'] || imagesx($image->resource) != $values['width']) {
|
||||
$correct_dimensions_real = FALSE;
|
||||
}
|
||||
|
||||
// Check that the image object has an accurate record of the dimensions.
|
||||
if ($image->info['width'] != $values['width'] || $image->info['height'] != $values['height']) {
|
||||
$correct_dimensions_object = FALSE;
|
||||
}
|
||||
// Now check each of the corners to ensure color correctness.
|
||||
foreach ($values['corners'] as $key => $corner) {
|
||||
// The test gif that does not have transparency has yellow where the
|
||||
// others have transparent.
|
||||
if ($file === 'image-test-no-transparency.gif' && $corner === $this->transparent) {
|
||||
$corner = $this->yellow;
|
||||
}
|
||||
// Get the location of the corner.
|
||||
switch ($key) {
|
||||
case 0:
|
||||
$x = 0;
|
||||
$y = 0;
|
||||
break;
|
||||
case 1:
|
||||
$x = $values['width'] - 1;
|
||||
$y = 0;
|
||||
break;
|
||||
case 2:
|
||||
$x = $values['width'] - 1;
|
||||
$y = $values['height'] - 1;
|
||||
break;
|
||||
case 3:
|
||||
$x = 0;
|
||||
$y = $values['height'] - 1;
|
||||
break;
|
||||
}
|
||||
$color = $this->getPixelColor($image, $x, $y);
|
||||
$correct_colors = $this->colorsAreEqual($color, $corner);
|
||||
}
|
||||
|
||||
$directory = file_default_scheme() . '://imagetests';
|
||||
file_prepare_directory($directory, FILE_CREATE_DIRECTORY);
|
||||
$file_path = $directory . '/' . $op . '.' . $image->info['extension'];
|
||||
image_save($image, $file_path);
|
||||
|
||||
$this->assertTrue($correct_dimensions_real, format_string('Image %file after %action action has proper dimensions.', array('%file' => $file, '%action' => $op)));
|
||||
$this->assertTrue($correct_dimensions_object, format_string('Image %file object after %action action is reporting the proper height and width values.', array('%file' => $file, '%action' => $op)));
|
||||
// JPEG colors will always be messed up due to compression.
|
||||
if ($image->info['extension'] != 'jpg') {
|
||||
$this->assertTrue($correct_colors, format_string('Image %file object after %action action has the correct color placement.', array('%file' => $file, '%action' => $op)));
|
||||
}
|
||||
}
|
||||
|
||||
// Check that saved image reloads without raising PHP errors.
|
||||
$image_reloaded = image_load($file_path);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests loading an image whose transparent color index is out of range.
|
||||
*/
|
||||
function testTransparentColorOutOfRange() {
|
||||
// This image was generated by taking an initial image with a palette size
|
||||
// of 6 colors, and setting the transparent color index to 6 (one higher
|
||||
// than the largest allowed index), as follows:
|
||||
// @code
|
||||
// $image = imagecreatefromgif('modules/simpletest/files/image-test.gif');
|
||||
// imagecolortransparent($image, 6);
|
||||
// imagegif($image, 'modules/simpletest/files/image-test-transparent-out-of-range.gif');
|
||||
// @endcode
|
||||
// This allows us to test that an image with an out-of-range color index
|
||||
// can be loaded correctly.
|
||||
$file = 'image-test-transparent-out-of-range.gif';
|
||||
$image = image_load(drupal_get_path('module', 'simpletest') . '/files/' . $file);
|
||||
|
||||
if (!$image) {
|
||||
$this->fail(format_string('Could not load image %file.', array('%file' => $file)));
|
||||
}
|
||||
else {
|
||||
// All images should be converted to truecolor when loaded.
|
||||
$image_truecolor = imageistruecolor($image->resource);
|
||||
$this->assertTrue($image_truecolor, format_string('Image %file after load is a truecolor image.', array('%file' => $file)));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests the file move function for managed files.
|
||||
*/
|
||||
class ImageFileMoveTest extends ImageToolkitTestCase {
|
||||
public static function getInfo() {
|
||||
return array(
|
||||
'name' => 'Image moving',
|
||||
'description' => 'Tests the file move function for managed files.',
|
||||
'group' => 'Image',
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests moving a randomly generated image.
|
||||
*/
|
||||
function testNormal() {
|
||||
// Pick a file for testing.
|
||||
$file = current($this->drupalGetTestFiles('image'));
|
||||
|
||||
// Create derivative image.
|
||||
$style = image_style_load(key(image_styles()));
|
||||
$derivative_uri = image_style_path($style['name'], $file->uri);
|
||||
image_style_create_derivative($style, $file->uri, $derivative_uri);
|
||||
|
||||
// Check if derivative image exists.
|
||||
$this->assertTrue(file_exists($derivative_uri), 'Make sure derivative image is generated successfully.');
|
||||
|
||||
// Clone the object so we don't have to worry about the function changing
|
||||
// our reference copy.
|
||||
$desired_filepath = 'public://' . $this->randomName();
|
||||
$result = file_move(clone $file, $desired_filepath, FILE_EXISTS_ERROR);
|
||||
|
||||
// Check if image has been moved.
|
||||
$this->assertTrue(file_exists($result->uri), 'Make sure image is moved successfully.');
|
||||
|
||||
// Check if derivative image has been flushed.
|
||||
$this->assertFalse(file_exists($derivative_uri), 'Make sure derivative image has been flushed.');
|
||||
}
|
||||
}
|
||||
|
12
modules/simpletest/tests/image_test.info
Normal file
12
modules/simpletest/tests/image_test.info
Normal file
|
@ -0,0 +1,12 @@
|
|||
name = "Image test"
|
||||
description = "Support module for image toolkit tests."
|
||||
package = Testing
|
||||
version = VERSION
|
||||
core = 7.x
|
||||
hidden = TRUE
|
||||
|
||||
; Information added by Drupal.org packaging script on 2017-06-21
|
||||
version = "7.56"
|
||||
project = "drupal"
|
||||
datestamp = "1498069849"
|
||||
|
138
modules/simpletest/tests/image_test.module
Normal file
138
modules/simpletest/tests/image_test.module
Normal file
|
@ -0,0 +1,138 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Helper module for the image tests.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Implements hook_image_toolkits().
|
||||
*/
|
||||
function image_test_image_toolkits() {
|
||||
return array(
|
||||
'test' => array(
|
||||
'title' => t('A dummy toolkit that works'),
|
||||
'available' => TRUE,
|
||||
),
|
||||
'broken' => array(
|
||||
'title' => t('A dummy toolkit that is "broken"'),
|
||||
'available' => FALSE,
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Reset/initialize the history of calls to the toolkit functions.
|
||||
*
|
||||
* @see image_test_get_all_calls()
|
||||
*/
|
||||
function image_test_reset() {
|
||||
// Keep track of calls to these operations
|
||||
$results = array(
|
||||
'load' => array(),
|
||||
'save' => array(),
|
||||
'settings' => array(),
|
||||
'resize' => array(),
|
||||
'rotate' => array(),
|
||||
'crop' => array(),
|
||||
'desaturate' => array(),
|
||||
);
|
||||
variable_set('image_test_results', $results);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get an array with the all the calls to the toolkits since image_test_reset()
|
||||
* was called.
|
||||
*
|
||||
* @return
|
||||
* An array keyed by operation name ('load', 'save', 'settings', 'resize',
|
||||
* 'rotate', 'crop', 'desaturate') with values being arrays of parameters
|
||||
* passed to each call.
|
||||
*/
|
||||
function image_test_get_all_calls() {
|
||||
return variable_get('image_test_results', array());
|
||||
}
|
||||
|
||||
/**
|
||||
* Store the values passed to a toolkit call.
|
||||
*
|
||||
* @param $op
|
||||
* One of the image toolkit operations: 'get_info', 'load', 'save',
|
||||
* 'settings', 'resize', 'rotate', 'crop', 'desaturate'.
|
||||
* @param $args
|
||||
* Values passed to hook.
|
||||
*
|
||||
* @see image_test_get_all_calls()
|
||||
* @see image_test_reset()
|
||||
*/
|
||||
function _image_test_log_call($op, $args) {
|
||||
$results = variable_get('image_test_results', array());
|
||||
$results[$op][] = $args;
|
||||
variable_set('image_test_results', $results);
|
||||
}
|
||||
|
||||
/**
|
||||
* Image tookit's settings operation.
|
||||
*/
|
||||
function image_test_settings() {
|
||||
_image_test_log_call('settings', array());
|
||||
return array();
|
||||
}
|
||||
|
||||
/**
|
||||
* Image toolkit's get_info operation.
|
||||
*/
|
||||
function image_test_get_info(stdClass $image) {
|
||||
_image_test_log_call('get_info', array($image));
|
||||
return array();
|
||||
}
|
||||
|
||||
/**
|
||||
* Image tookit's load operation.
|
||||
*/
|
||||
function image_test_load(stdClass $image) {
|
||||
_image_test_log_call('load', array($image));
|
||||
return $image;
|
||||
}
|
||||
|
||||
/**
|
||||
* Image tookit's save operation.
|
||||
*/
|
||||
function image_test_save(stdClass $image, $destination) {
|
||||
_image_test_log_call('save', array($image, $destination));
|
||||
// Return false so that image_save() doesn't try to chmod the destination
|
||||
// file that we didn't bother to create.
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Image tookit's crop operation.
|
||||
*/
|
||||
function image_test_crop(stdClass $image, $x, $y, $width, $height) {
|
||||
_image_test_log_call('crop', array($image, $x, $y, $width, $height));
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Image tookit's resize operation.
|
||||
*/
|
||||
function image_test_resize(stdClass $image, $width, $height) {
|
||||
_image_test_log_call('resize', array($image, $width, $height));
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Image tookit's rotate operation.
|
||||
*/
|
||||
function image_test_rotate(stdClass $image, $degrees, $background = NULL) {
|
||||
_image_test_log_call('rotate', array($image, $degrees, $background));
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Image tookit's desaturate operation.
|
||||
*/
|
||||
function image_test_desaturate(stdClass $image) {
|
||||
_image_test_log_call('desaturate', array($image));
|
||||
return TRUE;
|
||||
}
|
57
modules/simpletest/tests/lock.test
Normal file
57
modules/simpletest/tests/lock.test
Normal file
|
@ -0,0 +1,57 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* Tests for the lock system.
|
||||
*/
|
||||
class LockFunctionalTest extends DrupalWebTestCase {
|
||||
|
||||
public static function getInfo() {
|
||||
return array(
|
||||
'name' => 'Locking framework tests',
|
||||
'description' => 'Confirm locking works between two separate requests.',
|
||||
'group' => 'System',
|
||||
);
|
||||
}
|
||||
|
||||
function setUp() {
|
||||
parent::setUp('system_test');
|
||||
}
|
||||
|
||||
/**
|
||||
* Confirm that we can acquire and release locks in two parallel requests.
|
||||
*/
|
||||
function testLockAcquire() {
|
||||
$lock_acquired = 'TRUE: Lock successfully acquired in system_test_lock_acquire()';
|
||||
$lock_not_acquired = 'FALSE: Lock not acquired in system_test_lock_acquire()';
|
||||
$this->assertTrue(lock_acquire('system_test_lock_acquire'), 'Lock acquired by this request.', 'Lock');
|
||||
$this->assertTrue(lock_acquire('system_test_lock_acquire'), 'Lock extended by this request.', 'Lock');
|
||||
lock_release('system_test_lock_acquire');
|
||||
|
||||
// Cause another request to acquire the lock.
|
||||
$this->drupalGet('system-test/lock-acquire');
|
||||
$this->assertText($lock_acquired, 'Lock acquired by the other request.', 'Lock');
|
||||
// The other request has finished, thus it should have released its lock.
|
||||
$this->assertTrue(lock_acquire('system_test_lock_acquire'), 'Lock acquired by this request.', 'Lock');
|
||||
// This request holds the lock, so the other request cannot acquire it.
|
||||
$this->drupalGet('system-test/lock-acquire');
|
||||
$this->assertText($lock_not_acquired, 'Lock not acquired by the other request.', 'Lock');
|
||||
lock_release('system_test_lock_acquire');
|
||||
|
||||
// Try a very short timeout and lock breaking.
|
||||
$this->assertTrue(lock_acquire('system_test_lock_acquire', 0.5), 'Lock acquired by this request.', 'Lock');
|
||||
sleep(1);
|
||||
// The other request should break our lock.
|
||||
$this->drupalGet('system-test/lock-acquire');
|
||||
$this->assertText($lock_acquired, 'Lock acquired by the other request, breaking our lock.', 'Lock');
|
||||
// We cannot renew it, since the other thread took it.
|
||||
$this->assertFalse(lock_acquire('system_test_lock_acquire'), 'Lock cannot be extended by this request.', 'Lock');
|
||||
|
||||
// Check the shut-down function.
|
||||
$lock_acquired_exit = 'TRUE: Lock successfully acquired in system_test_lock_exit()';
|
||||
$lock_not_acquired_exit = 'FALSE: Lock not acquired in system_test_lock_exit()';
|
||||
$this->drupalGet('system-test/lock-exit');
|
||||
$this->assertText($lock_acquired_exit, 'Lock acquired by the other request before exit.', 'Lock');
|
||||
$this->assertTrue(lock_acquire('system_test_lock_exit'), 'Lock acquired by this request after the other request exits.', 'Lock');
|
||||
}
|
||||
}
|
||||
|
460
modules/simpletest/tests/mail.test
Normal file
460
modules/simpletest/tests/mail.test
Normal file
|
@ -0,0 +1,460 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Test the Drupal mailing system.
|
||||
*/
|
||||
class MailTestCase extends DrupalWebTestCase implements MailSystemInterface {
|
||||
/**
|
||||
* The most recent message that was sent through the test case.
|
||||
*
|
||||
* We take advantage here of the fact that static variables are shared among
|
||||
* all instance of the same class.
|
||||
*/
|
||||
private static $sent_message;
|
||||
|
||||
public static function getInfo() {
|
||||
return array(
|
||||
'name' => 'Mail system',
|
||||
'description' => 'Performs tests on the pluggable mailing framework.',
|
||||
'group' => 'System',
|
||||
);
|
||||
}
|
||||
|
||||
function setUp() {
|
||||
parent::setUp(array('simpletest'));
|
||||
|
||||
// Set MailTestCase (i.e. this class) as the SMTP library
|
||||
variable_set('mail_system', array('default-system' => 'MailTestCase'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Assert that the pluggable mail system is functional.
|
||||
*/
|
||||
function testPluggableFramework() {
|
||||
global $language;
|
||||
|
||||
// Use MailTestCase for sending a message.
|
||||
$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@example.com', '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.');
|
||||
}
|
||||
|
||||
/**
|
||||
* Concatenate and wrap the e-mail body for plain-text mails.
|
||||
*
|
||||
* @see DefaultMailSystem
|
||||
*/
|
||||
public function format(array $message) {
|
||||
// Join the body array into one string.
|
||||
$message['body'] = implode("\n\n", $message['body']);
|
||||
// Convert any HTML to plain-text.
|
||||
$message['body'] = drupal_html_to_text($message['body']);
|
||||
// Wrap the mail body for sending.
|
||||
$message['body'] = drupal_wrap_mail($message['body']);
|
||||
return $message;
|
||||
}
|
||||
|
||||
/**
|
||||
* Send function that is called through the mail system.
|
||||
*/
|
||||
public function mail(array $message) {
|
||||
self::$sent_message = $message;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Unit tests for drupal_html_to_text().
|
||||
*/
|
||||
class DrupalHtmlToTextTestCase extends DrupalWebTestCase {
|
||||
public static function getInfo() {
|
||||
return array(
|
||||
'name' => 'HTML to text conversion',
|
||||
'description' => 'Tests drupal_html_to_text().',
|
||||
'group' => 'Mail',
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts a string to its PHP source equivalent for display in test messages.
|
||||
*
|
||||
* @param $text
|
||||
* The text string to convert.
|
||||
*
|
||||
* @return
|
||||
* An HTML representation of the text string that, when displayed in a
|
||||
* browser, represents the PHP source code equivalent of $text.
|
||||
*/
|
||||
function stringToHtml($text) {
|
||||
return '"' .
|
||||
str_replace(
|
||||
array("\n", ' '),
|
||||
array('\n', ' '),
|
||||
check_plain($text)
|
||||
) . '"';
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper function for testing drupal_html_to_text().
|
||||
*
|
||||
* @param $html
|
||||
* The source HTML string to be converted.
|
||||
* @param $text
|
||||
* The expected result of converting $html to text.
|
||||
* @param $message
|
||||
* A text message to display in the assertion message.
|
||||
* @param $allowed_tags
|
||||
* (optional) An array of allowed tags, or NULL to default to the full
|
||||
* set of tags supported by drupal_html_to_text().
|
||||
*/
|
||||
function assertHtmlToText($html, $text, $message, $allowed_tags = NULL) {
|
||||
preg_match_all('/<([a-z0-6]+)/', drupal_strtolower($html), $matches);
|
||||
$tested_tags = implode(', ', array_unique($matches[1]));
|
||||
$message .= ' (' . $tested_tags . ')';
|
||||
$result = drupal_html_to_text($html, $allowed_tags);
|
||||
$pass = $this->assertEqual($result, $text, check_plain($message));
|
||||
$verbose = 'html = <pre>' . $this->stringToHtml($html)
|
||||
. '</pre><br />' . 'result = <pre>' . $this->stringToHtml($result)
|
||||
. '</pre><br />' . 'expected = <pre>' . $this->stringToHtml($text)
|
||||
. '</pre>';
|
||||
$this->verbose($verbose);
|
||||
if (!$pass) {
|
||||
$this->pass("Previous test verbose info:<br />$verbose");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Test all supported tags of drupal_html_to_text().
|
||||
*/
|
||||
function testTags() {
|
||||
global $base_path, $base_url;
|
||||
$tests = array(
|
||||
// @todo Trailing linefeeds should be trimmed.
|
||||
'<a href = "http://drupal.org">Drupal.org</a>' => "Drupal.org [1]\n\n[1] http://drupal.org\n",
|
||||
// @todo Footer URLs should be absolute.
|
||||
"<a href = \"$base_path\">Homepage</a>" => "Homepage [1]\n\n[1] $base_url/\n",
|
||||
'<address>Drupal</address>' => "Drupal\n",
|
||||
// @todo The <address> tag is currently not supported.
|
||||
'<address>Drupal</address><address>Drupal</address>' => "DrupalDrupal\n",
|
||||
'<b>Drupal</b>' => "*Drupal*\n",
|
||||
// @todo There should be a space between the '>' and the text.
|
||||
'<blockquote>Drupal</blockquote>' => ">Drupal\n",
|
||||
'<blockquote>Drupal</blockquote><blockquote>Drupal</blockquote>' => ">Drupal\n>Drupal\n",
|
||||
'<br />Drupal<br />Drupal<br /><br />Drupal' => "Drupal\nDrupal\nDrupal\n",
|
||||
'<br/>Drupal<br/>Drupal<br/><br/>Drupal' => "Drupal\nDrupal\nDrupal\n",
|
||||
// @todo There should be two line breaks before the paragraph.
|
||||
'<br/>Drupal<br/>Drupal<br/><br/>Drupal<p>Drupal</p>' => "Drupal\nDrupal\nDrupal\nDrupal\n\n",
|
||||
'<div>Drupal</div>' => "Drupal\n",
|
||||
// @todo The <div> tag is currently not supported.
|
||||
'<div>Drupal</div><div>Drupal</div>' => "DrupalDrupal\n",
|
||||
'<em>Drupal</em>' => "/Drupal/\n",
|
||||
'<h1>Drupal</h1>' => "======== DRUPAL ==============================================================\n\n",
|
||||
'<h1>Drupal</h1><p>Drupal</p>' => "======== DRUPAL ==============================================================\n\nDrupal\n\n",
|
||||
'<h2>Drupal</h2>' => "-------- DRUPAL --------------------------------------------------------------\n\n",
|
||||
'<h2>Drupal</h2><p>Drupal</p>' => "-------- DRUPAL --------------------------------------------------------------\n\nDrupal\n\n",
|
||||
'<h3>Drupal</h3>' => ".... Drupal\n\n",
|
||||
'<h3>Drupal</h3><p>Drupal</p>' => ".... Drupal\n\nDrupal\n\n",
|
||||
'<h4>Drupal</h4>' => ".. Drupal\n\n",
|
||||
'<h4>Drupal</h4><p>Drupal</p>' => ".. Drupal\n\nDrupal\n\n",
|
||||
'<h5>Drupal</h5>' => "Drupal\n\n",
|
||||
'<h5>Drupal</h5><p>Drupal</p>' => "Drupal\n\nDrupal\n\n",
|
||||
'<h6>Drupal</h6>' => "Drupal\n\n",
|
||||
'<h6>Drupal</h6><p>Drupal</p>' => "Drupal\n\nDrupal\n\n",
|
||||
'<hr />Drupal<hr />' => "------------------------------------------------------------------------------\nDrupal\n------------------------------------------------------------------------------\n",
|
||||
'<hr/>Drupal<hr/>' => "------------------------------------------------------------------------------\nDrupal\n------------------------------------------------------------------------------\n",
|
||||
'<hr/>Drupal<hr/><p>Drupal</p>' => "------------------------------------------------------------------------------\nDrupal\n------------------------------------------------------------------------------\nDrupal\n\n",
|
||||
'<i>Drupal</i>' => "/Drupal/\n",
|
||||
'<p>Drupal</p>' => "Drupal\n\n",
|
||||
'<p>Drupal</p><p>Drupal</p>' => "Drupal\n\nDrupal\n\n",
|
||||
'<strong>Drupal</strong>' => "*Drupal*\n",
|
||||
// @todo Tables are currently not supported.
|
||||
'<table><tr><td>Drupal</td><td>Drupal</td></tr><tr><td>Drupal</td><td>Drupal</td></tr></table>' => "DrupalDrupalDrupalDrupal\n",
|
||||
'<table><tr><td>Drupal</td></tr></table><p>Drupal</p>' => "Drupal\nDrupal\n\n",
|
||||
// @todo The <u> tag is currently not supported.
|
||||
'<u>Drupal</u>' => "Drupal\n",
|
||||
'<ul><li>Drupal</li></ul>' => " * Drupal\n\n",
|
||||
'<ul><li>Drupal <em>Drupal</em> Drupal</li></ul>' => " * Drupal /Drupal/ Drupal\n\n",
|
||||
// @todo Lines containing nothing but spaces should be trimmed.
|
||||
'<ul><li>Drupal</li><li><ol><li>Drupal</li><li>Drupal</li></ol></li></ul>' => " * Drupal\n * 1) Drupal\n 2) Drupal\n \n\n",
|
||||
'<ul><li>Drupal</li><li><ol><li>Drupal</li></ol></li><li>Drupal</li></ul>' => " * Drupal\n * 1) Drupal\n \n * Drupal\n\n",
|
||||
'<ul><li>Drupal</li><li>Drupal</li></ul>' => " * Drupal\n * Drupal\n\n",
|
||||
'<ul><li>Drupal</li></ul><p>Drupal</p>' => " * Drupal\n\nDrupal\n\n",
|
||||
'<ol><li>Drupal</li></ol>' => " 1) Drupal\n\n",
|
||||
'<ol><li>Drupal</li><li><ul><li>Drupal</li><li>Drupal</li></ul></li></ol>' => " 1) Drupal\n 2) * Drupal\n * Drupal\n \n\n",
|
||||
'<ol><li>Drupal</li><li>Drupal</li></ol>' => " 1) Drupal\n 2) Drupal\n\n",
|
||||
'<ol>Drupal</ol>' => "Drupal\n\n",
|
||||
'<ol><li>Drupal</li></ol><p>Drupal</p>' => " 1) Drupal\n\nDrupal\n\n",
|
||||
'<dl><dt>Drupal</dt></dl>' => "Drupal\n\n",
|
||||
'<dl><dt>Drupal</dt><dd>Drupal</dd></dl>' => "Drupal\n Drupal\n\n",
|
||||
'<dl><dt>Drupal</dt><dd>Drupal</dd><dt>Drupal</dt><dd>Drupal</dd></dl>' => "Drupal\n Drupal\nDrupal\n Drupal\n\n",
|
||||
'<dl><dt>Drupal</dt><dd>Drupal</dd></dl><p>Drupal</p>' => "Drupal\n Drupal\n\nDrupal\n\n",
|
||||
'<dl><dt>Drupal<dd>Drupal</dl>' => "Drupal\n Drupal\n\n",
|
||||
'<dl><dt>Drupal</dt></dl><p>Drupal</p>' => "Drupal\n\nDrupal\n\n",
|
||||
// @todo Again, lines containing only spaces should be trimmed.
|
||||
'<ul><li>Drupal</li><li><dl><dt>Drupal</dt><dd>Drupal</dd><dt>Drupal</dt><dd>Drupal</dd></dl></li><li>Drupal</li></ul>' => " * Drupal\n * Drupal\n Drupal\n Drupal\n Drupal\n \n * Drupal\n\n",
|
||||
// Tests malformed HTML tags.
|
||||
'<br>Drupal<br>Drupal' => "Drupal\nDrupal\n",
|
||||
'<hr>Drupal<hr>Drupal' => "------------------------------------------------------------------------------\nDrupal\n------------------------------------------------------------------------------\nDrupal\n",
|
||||
'<ol><li>Drupal<li>Drupal</ol>' => " 1) Drupal\n 2) Drupal\n\n",
|
||||
'<ul><li>Drupal <em>Drupal</em> Drupal</ul></ul>' => " * Drupal /Drupal/ Drupal\n\n",
|
||||
'<ul><li>Drupal<li>Drupal</ol>' => " * Drupal\n * Drupal\n\n",
|
||||
'<ul><li>Drupal<li>Drupal</ul>' => " * Drupal\n * Drupal\n\n",
|
||||
'<ul>Drupal</ul>' => "Drupal\n\n",
|
||||
'Drupal</ul></ol></dl><li>Drupal' => "Drupal\n * Drupal\n",
|
||||
'<dl>Drupal</dl>' => "Drupal\n\n",
|
||||
'<dl>Drupal</dl><p>Drupal</p>' => "Drupal\n\nDrupal\n\n",
|
||||
'<dt>Drupal</dt>' => "Drupal\n",
|
||||
// Tests some unsupported HTML tags.
|
||||
'<html>Drupal</html>' => "Drupal\n",
|
||||
// @todo Perhaps the contents of <script> tags should be dropped.
|
||||
'<script type="text/javascript">Drupal</script>' => "Drupal\n",
|
||||
);
|
||||
|
||||
foreach ($tests as $html => $text) {
|
||||
$this->assertHtmlToText($html, $text, 'Supported tags');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Test $allowed_tags argument of drupal_html_to_text().
|
||||
*/
|
||||
function testDrupalHtmlToTextArgs() {
|
||||
// The second parameter of drupal_html_to_text() overrules the allowed tags.
|
||||
$this->assertHtmlToText(
|
||||
'Drupal <b>Drupal</b> Drupal',
|
||||
"Drupal *Drupal* Drupal\n",
|
||||
'Allowed <b> tag found',
|
||||
array('b')
|
||||
);
|
||||
$this->assertHtmlToText(
|
||||
'Drupal <h1>Drupal</h1> Drupal',
|
||||
"Drupal Drupal Drupal\n",
|
||||
'Disallowed <h1> tag not found',
|
||||
array('b')
|
||||
);
|
||||
|
||||
$this->assertHtmlToText(
|
||||
'Drupal <p><em><b>Drupal</b></em><p> Drupal',
|
||||
"Drupal Drupal Drupal\n",
|
||||
'Disallowed <p>, <em>, and <b> tags not found',
|
||||
array('a', 'br', 'h1')
|
||||
);
|
||||
|
||||
$this->assertHtmlToText(
|
||||
'<html><body>Drupal</body></html>',
|
||||
"Drupal\n",
|
||||
'Unsupported <html> and <body> tags not found',
|
||||
array('html', 'body')
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests that drupal_wrap_mail() removes trailing whitespace before newlines.
|
||||
*/
|
||||
function testDrupalHtmltoTextRemoveTrailingWhitespace() {
|
||||
$text = "Hi there! \nHerp Derp";
|
||||
$mail_lines = explode("\n", drupal_wrap_mail($text));
|
||||
$this->assertNotEqual(" ", substr($mail_lines[0], -1), 'Trailing whitespace removed.');
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests drupal_wrap_mail() retains whitespace from Usenet style signatures.
|
||||
*
|
||||
* RFC 3676 says, "This is a special case; an (optionally quoted or quoted and
|
||||
* stuffed) line consisting of DASH DASH SP is neither fixed nor flowed."
|
||||
*/
|
||||
function testDrupalHtmltoTextUsenetSignature() {
|
||||
$text = "Hi there!\n-- \nHerp Derp";
|
||||
$mail_lines = explode("\n", drupal_wrap_mail($text));
|
||||
$this->assertEqual("-- ", $mail_lines[1], 'Trailing whitespace not removed for dash-dash-space signatures.');
|
||||
|
||||
$text = "Hi there!\n-- \nHerp Derp";
|
||||
$mail_lines = explode("\n", drupal_wrap_mail($text));
|
||||
$this->assertEqual("--", $mail_lines[1], 'Trailing whitespace removed for incorrect dash-dash-space signatures.');
|
||||
}
|
||||
|
||||
/**
|
||||
* Test that whitespace is collapsed.
|
||||
*/
|
||||
function testDrupalHtmltoTextCollapsesWhitespace() {
|
||||
$input = "<p>Drupal Drupal\n\nDrupal<pre>Drupal Drupal\n\nDrupal</pre>Drupal Drupal\n\nDrupal</p>";
|
||||
// @todo The whitespace should be collapsed.
|
||||
$collapsed = "Drupal Drupal\n\nDrupalDrupal Drupal\n\nDrupalDrupal Drupal\n\nDrupal\n\n";
|
||||
$this->assertHtmlToText(
|
||||
$input,
|
||||
$collapsed,
|
||||
'Whitespace is collapsed',
|
||||
array('p')
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test that text separated by block-level tags in HTML get separated by
|
||||
* (at least) a newline in the plaintext version.
|
||||
*/
|
||||
function testDrupalHtmlToTextBlockTagToNewline() {
|
||||
$input = '[text]'
|
||||
. '<blockquote>[blockquote]</blockquote>'
|
||||
. '<br />[br]'
|
||||
. '<dl><dt>[dl-dt]</dt>'
|
||||
. '<dt>[dt]</dt>'
|
||||
. '<dd>[dd]</dd>'
|
||||
. '<dd>[dd-dl]</dd></dl>'
|
||||
. '<h1>[h1]</h1>'
|
||||
. '<h2>[h2]</h2>'
|
||||
. '<h3>[h3]</h3>'
|
||||
. '<h4>[h4]</h4>'
|
||||
. '<h5>[h5]</h5>'
|
||||
. '<h6>[h6]</h6>'
|
||||
. '<hr />[hr]'
|
||||
. '<ol><li>[ol-li]</li>'
|
||||
. '<li>[li]</li>'
|
||||
. '<li>[li-ol]</li></ol>'
|
||||
. '<p>[p]</p>'
|
||||
. '<ul><li>[ul-li]</li>'
|
||||
. '<li>[li-ul]</li></ul>'
|
||||
. '[text]';
|
||||
$output = drupal_html_to_text($input);
|
||||
$pass = $this->assertFalse(
|
||||
preg_match('/\][^\n]*\[/s', $output),
|
||||
'Block-level HTML tags should force newlines'
|
||||
);
|
||||
if (!$pass) {
|
||||
$this->verbose($this->stringToHtml($output));
|
||||
}
|
||||
$output_upper = drupal_strtoupper($output);
|
||||
$upper_input = drupal_strtoupper($input);
|
||||
$upper_output = drupal_html_to_text($upper_input);
|
||||
$pass = $this->assertEqual(
|
||||
$upper_output,
|
||||
$output_upper,
|
||||
'Tag recognition should be case-insensitive'
|
||||
);
|
||||
if (!$pass) {
|
||||
$this->verbose(
|
||||
$upper_output
|
||||
. '<br />should be equal to <br />'
|
||||
. $output_upper
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Test that headers are properly separated from surrounding text.
|
||||
*/
|
||||
function testHeaderSeparation() {
|
||||
$html = 'Drupal<h1>Drupal</h1>Drupal';
|
||||
// @todo There should be more space above the header than below it.
|
||||
$text = "Drupal\n======== DRUPAL ==============================================================\n\nDrupal\n";
|
||||
$this->assertHtmlToText($html, $text,
|
||||
'Text before and after <h1> tag');
|
||||
$html = '<p>Drupal</p><h1>Drupal</h1>Drupal';
|
||||
// @todo There should be more space above the header than below it.
|
||||
$text = "Drupal\n\n======== DRUPAL ==============================================================\n\nDrupal\n";
|
||||
$this->assertHtmlToText($html, $text,
|
||||
'Paragraph before and text after <h1> tag');
|
||||
$html = 'Drupal<h1>Drupal</h1><p>Drupal</p>';
|
||||
// @todo There should be more space above the header than below it.
|
||||
$text = "Drupal\n======== DRUPAL ==============================================================\n\nDrupal\n\n";
|
||||
$this->assertHtmlToText($html, $text,
|
||||
'Text before and paragraph after <h1> tag');
|
||||
$html = '<p>Drupal</p><h1>Drupal</h1><p>Drupal</p>';
|
||||
$text = "Drupal\n\n======== DRUPAL ==============================================================\n\nDrupal\n\n";
|
||||
$this->assertHtmlToText($html, $text,
|
||||
'Paragraph before and after <h1> tag');
|
||||
}
|
||||
|
||||
/**
|
||||
* Test that footnote references are properly generated.
|
||||
*/
|
||||
function testFootnoteReferences() {
|
||||
global $base_path, $base_url;
|
||||
$source = '<a href="http://www.example.com/node/1">Host and path</a>'
|
||||
. '<br /><a href="http://www.example.com">Host, no path</a>'
|
||||
. '<br /><a href="' . $base_path . 'node/1">Path, no host</a>'
|
||||
. '<br /><a href="node/1">Relative path</a>';
|
||||
// @todo Footnote URLs should be absolute.
|
||||
$tt = "Host and path [1]"
|
||||
. "\nHost, no path [2]"
|
||||
// @todo The following two references should be combined.
|
||||
. "\nPath, no host [3]"
|
||||
. "\nRelative path [4]"
|
||||
. "\n"
|
||||
. "\n[1] http://www.example.com/node/1"
|
||||
. "\n[2] http://www.example.com"
|
||||
// @todo The following two references should be combined.
|
||||
. "\n[3] $base_url/node/1"
|
||||
. "\n[4] node/1\n";
|
||||
$this->assertHtmlToText($source, $tt, 'Footnotes');
|
||||
}
|
||||
|
||||
/**
|
||||
* Test that combinations of paragraph breaks, line breaks, linefeeds,
|
||||
* and spaces are properly handled.
|
||||
*/
|
||||
function testDrupalHtmlToTextParagraphs() {
|
||||
$tests = array();
|
||||
$tests[] = array(
|
||||
'html' => "<p>line 1<br />\nline 2<br />line 3\n<br />line 4</p><p>paragraph</p>",
|
||||
// @todo Trailing line breaks should be trimmed.
|
||||
'text' => "line 1\nline 2\nline 3\nline 4\n\nparagraph\n\n",
|
||||
);
|
||||
$tests[] = array(
|
||||
'html' => "<p>line 1<br /> line 2</p> <p>line 4<br /> line 5</p> <p>0</p>",
|
||||
// @todo Trailing line breaks should be trimmed.
|
||||
'text' => "line 1\nline 2\n\nline 4\nline 5\n\n0\n\n",
|
||||
);
|
||||
foreach ($tests as $test) {
|
||||
$this->assertHtmlToText($test['html'], $test['text'], 'Paragraph breaks');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests that drupal_html_to_text() wraps before 1000 characters.
|
||||
*
|
||||
* RFC 3676 says, "The Text/Plain media type is the lowest common
|
||||
* denominator of Internet email, with lines of no more than 998 characters."
|
||||
*
|
||||
* RFC 2046 says, "SMTP [RFC-821] allows a maximum of 998 octets before the
|
||||
* next CRLF sequence."
|
||||
*
|
||||
* RFC 821 says, "The maximum total length of a text line including the
|
||||
* <CRLF> is 1000 characters."
|
||||
*/
|
||||
function testVeryLongLineWrap() {
|
||||
$input = 'Drupal<br /><p>' . str_repeat('x', 2100) . '</p><br />Drupal';
|
||||
$output = drupal_html_to_text($input);
|
||||
// This awkward construct comes from includes/mail.inc lines 8-13.
|
||||
$eol = variable_get('mail_line_endings', MAIL_LINE_ENDINGS);
|
||||
// We must use strlen() rather than drupal_strlen() in order to count
|
||||
// octets rather than characters.
|
||||
$line_length_limit = 1000 - drupal_strlen($eol);
|
||||
$maximum_line_length = 0;
|
||||
foreach (explode($eol, $output) as $line) {
|
||||
// We must use strlen() rather than drupal_strlen() in order to count
|
||||
// octets rather than characters.
|
||||
$maximum_line_length = max($maximum_line_length, strlen($line . $eol));
|
||||
}
|
||||
$verbose = 'Maximum line length found was ' . $maximum_line_length . ' octets.';
|
||||
$this->assertTrue($maximum_line_length <= 1000, $verbose);
|
||||
}
|
||||
}
|
1740
modules/simpletest/tests/menu.test
Normal file
1740
modules/simpletest/tests/menu.test
Normal file
File diff suppressed because it is too large
Load diff
12
modules/simpletest/tests/menu_test.info
Normal file
12
modules/simpletest/tests/menu_test.info
Normal file
|
@ -0,0 +1,12 @@
|
|||
name = "Hook menu tests"
|
||||
description = "Support module for menu hook testing."
|
||||
package = Testing
|
||||
version = VERSION
|
||||
core = 7.x
|
||||
hidden = TRUE
|
||||
|
||||
; Information added by Drupal.org packaging script on 2017-06-21
|
||||
version = "7.56"
|
||||
project = "drupal"
|
||||
datestamp = "1498069849"
|
||||
|
563
modules/simpletest/tests/menu_test.module
Normal file
563
modules/simpletest/tests/menu_test.module
Normal file
|
@ -0,0 +1,563 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Dummy module implementing hook menu.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Implements hook_menu().
|
||||
*/
|
||||
function menu_test_menu() {
|
||||
// The name of the menu changes during the course of the test. Using a $_GET.
|
||||
$items['menu_name_test'] = array(
|
||||
'title' => 'Test menu_name router item',
|
||||
'page callback' => 'node_save',
|
||||
'menu_name' => menu_test_menu_name(),
|
||||
);
|
||||
// This item is of type MENU_CALLBACK with no parents to test title.
|
||||
$items['menu_callback_title'] = array(
|
||||
'title' => 'Menu Callback Title',
|
||||
'page callback' => 'menu_test_callback',
|
||||
'type' => MENU_CALLBACK,
|
||||
'access arguments' => array('access content'),
|
||||
);
|
||||
// Use FALSE as 'title callback' to bypass t().
|
||||
$items['menu_no_title_callback'] = array(
|
||||
'title' => 'A title with @placeholder',
|
||||
'title callback' => FALSE,
|
||||
'title arguments' => array('@placeholder' => 'some other text'),
|
||||
'page callback' => 'menu_test_callback',
|
||||
'access arguments' => array('access content'),
|
||||
);
|
||||
|
||||
// Hidden link for menu_link_maintain tests
|
||||
$items['menu_test_maintain/%'] = array(
|
||||
'title' => 'Menu maintain test',
|
||||
'page callback' => 'node_page_default',
|
||||
'access arguments' => array('access content'),
|
||||
);
|
||||
// Hierarchical tests.
|
||||
$items['menu-test/hierarchy/parent'] = array(
|
||||
'title' => 'Parent menu router',
|
||||
'page callback' => 'node_page_default',
|
||||
);
|
||||
$items['menu-test/hierarchy/parent/child'] = array(
|
||||
'title' => 'Child menu router',
|
||||
'page callback' => 'node_page_default',
|
||||
);
|
||||
$items['menu-test/hierarchy/parent/child2/child'] = array(
|
||||
'title' => 'Unattached subchild router',
|
||||
'page callback' => 'node_page_default',
|
||||
);
|
||||
// Theme callback tests.
|
||||
$items['menu-test/theme-callback/%'] = array(
|
||||
'title' => 'Page that displays different themes',
|
||||
'page callback' => 'menu_test_theme_page_callback',
|
||||
'access arguments' => array('access content'),
|
||||
'theme callback' => 'menu_test_theme_callback',
|
||||
'theme arguments' => array(2),
|
||||
);
|
||||
$items['menu-test/theme-callback/%/inheritance'] = array(
|
||||
'title' => 'Page that tests theme callback inheritance.',
|
||||
'page callback' => 'menu_test_theme_page_callback',
|
||||
'page arguments' => array(TRUE),
|
||||
'access arguments' => array('access content'),
|
||||
);
|
||||
$items['menu-test/no-theme-callback'] = array(
|
||||
'title' => 'Page that displays different themes without using a theme callback.',
|
||||
'page callback' => 'menu_test_theme_page_callback',
|
||||
'access arguments' => array('access content'),
|
||||
);
|
||||
// Path containing "exotic" characters.
|
||||
$path = "menu-test/ -._~!$'\"()*@[]?&+%#,;=:" . // "Special" ASCII characters.
|
||||
"%23%25%26%2B%2F%3F" . // Characters that look like a percent-escaped string.
|
||||
"éøïвβ中國書۞"; // Characters from various non-ASCII alphabets.
|
||||
$items[$path] = array(
|
||||
'title' => '"Exotic" path',
|
||||
'page callback' => 'menu_test_callback',
|
||||
'access arguments' => array('access content'),
|
||||
);
|
||||
|
||||
// Hidden tests; base parents.
|
||||
// Same structure as in Menu and Block modules. Since those structures can
|
||||
// change, we need to simulate our own in here.
|
||||
$items['menu-test'] = array(
|
||||
'title' => 'Menu test root',
|
||||
'page callback' => 'node_page_default',
|
||||
'access arguments' => array('access content'),
|
||||
);
|
||||
$items['menu-test/hidden'] = array(
|
||||
'title' => 'Hidden test root',
|
||||
'page callback' => 'node_page_default',
|
||||
'access arguments' => array('access content'),
|
||||
);
|
||||
|
||||
// Hidden tests; one dynamic argument.
|
||||
$items['menu-test/hidden/menu'] = array(
|
||||
'title' => 'Menus',
|
||||
'page callback' => 'node_page_default',
|
||||
'access arguments' => array('access content'),
|
||||
);
|
||||
$items['menu-test/hidden/menu/list'] = array(
|
||||
'title' => 'List menus',
|
||||
'type' => MENU_DEFAULT_LOCAL_TASK,
|
||||
'weight' => -10,
|
||||
);
|
||||
$items['menu-test/hidden/menu/add'] = array(
|
||||
'title' => 'Add menu',
|
||||
'page callback' => 'node_page_default',
|
||||
'access arguments' => array('access content'),
|
||||
'type' => MENU_LOCAL_ACTION,
|
||||
);
|
||||
$items['menu-test/hidden/menu/settings'] = array(
|
||||
'title' => 'Settings',
|
||||
'page callback' => 'node_page_default',
|
||||
'access arguments' => array('access content'),
|
||||
'type' => MENU_LOCAL_TASK,
|
||||
'weight' => 5,
|
||||
);
|
||||
$items['menu-test/hidden/menu/manage/%menu'] = array(
|
||||
'title' => 'Customize menu',
|
||||
'page callback' => 'node_page_default',
|
||||
'access arguments' => array('access content'),
|
||||
);
|
||||
$items['menu-test/hidden/menu/manage/%menu/list'] = array(
|
||||
'title' => 'List links',
|
||||
'weight' => -10,
|
||||
'type' => MENU_DEFAULT_LOCAL_TASK,
|
||||
'context' => MENU_CONTEXT_PAGE | MENU_CONTEXT_INLINE,
|
||||
);
|
||||
$items['menu-test/hidden/menu/manage/%menu/add'] = array(
|
||||
'title' => 'Add link',
|
||||
'page callback' => 'node_page_default',
|
||||
'access arguments' => array('access content'),
|
||||
'type' => MENU_LOCAL_ACTION,
|
||||
);
|
||||
$items['menu-test/hidden/menu/manage/%menu/edit'] = array(
|
||||
'title' => 'Edit menu',
|
||||
'page callback' => 'node_page_default',
|
||||
'access arguments' => array('access content'),
|
||||
'type' => MENU_LOCAL_TASK,
|
||||
'context' => MENU_CONTEXT_PAGE | MENU_CONTEXT_INLINE,
|
||||
);
|
||||
$items['menu-test/hidden/menu/manage/%menu/delete'] = array(
|
||||
'title' => 'Delete menu',
|
||||
'page callback' => 'node_page_default',
|
||||
'access arguments' => array('access content'),
|
||||
);
|
||||
|
||||
// Hidden tests; two dynamic arguments.
|
||||
$items['menu-test/hidden/block'] = array(
|
||||
'title' => 'Blocks',
|
||||
'page callback' => 'node_page_default',
|
||||
'access arguments' => array('access content'),
|
||||
);
|
||||
$items['menu-test/hidden/block/list'] = array(
|
||||
'title' => 'List',
|
||||
'type' => MENU_DEFAULT_LOCAL_TASK,
|
||||
'weight' => -10,
|
||||
);
|
||||
$items['menu-test/hidden/block/add'] = array(
|
||||
'title' => 'Add block',
|
||||
'page callback' => 'node_page_default',
|
||||
'access arguments' => array('access content'),
|
||||
'type' => MENU_LOCAL_ACTION,
|
||||
);
|
||||
$items['menu-test/hidden/block/manage/%/%'] = array(
|
||||
'title' => 'Configure block',
|
||||
'page callback' => 'node_page_default',
|
||||
'access arguments' => array('access content'),
|
||||
);
|
||||
$items['menu-test/hidden/block/manage/%/%/configure'] = array(
|
||||
'title' => 'Configure block',
|
||||
'type' => MENU_DEFAULT_LOCAL_TASK,
|
||||
'context' => MENU_CONTEXT_INLINE,
|
||||
);
|
||||
$items['menu-test/hidden/block/manage/%/%/delete'] = array(
|
||||
'title' => 'Delete block',
|
||||
'page callback' => 'node_page_default',
|
||||
'access arguments' => array('access content'),
|
||||
'type' => MENU_LOCAL_TASK,
|
||||
'context' => MENU_CONTEXT_NONE,
|
||||
);
|
||||
|
||||
// Breadcrumbs tests.
|
||||
// @see MenuBreadcrumbTestCase
|
||||
$base = array(
|
||||
'page callback' => 'menu_test_callback',
|
||||
'access callback' => TRUE,
|
||||
);
|
||||
// Local tasks: Second level below default local task.
|
||||
$items['menu-test/breadcrumb/tasks'] = array(
|
||||
'title' => 'Breadcrumbs test: Local tasks',
|
||||
) + $base;
|
||||
$items['menu-test/breadcrumb/tasks/first'] = array(
|
||||
'title' => 'First',
|
||||
'type' => MENU_DEFAULT_LOCAL_TASK,
|
||||
) + $base;
|
||||
$items['menu-test/breadcrumb/tasks/second'] = array(
|
||||
'title' => 'Second',
|
||||
'type' => MENU_LOCAL_TASK,
|
||||
) + $base;
|
||||
$items['menu-test/breadcrumb/tasks/first/first'] = array(
|
||||
'title' => 'First first',
|
||||
'type' => MENU_DEFAULT_LOCAL_TASK,
|
||||
) + $base;
|
||||
$items['menu-test/breadcrumb/tasks/first/second'] = array(
|
||||
'title' => 'First second',
|
||||
'type' => MENU_LOCAL_TASK,
|
||||
) + $base;
|
||||
$items['menu-test/breadcrumb/tasks/second/first'] = array(
|
||||
'title' => 'Second first',
|
||||
'type' => MENU_DEFAULT_LOCAL_TASK,
|
||||
) + $base;
|
||||
$items['menu-test/breadcrumb/tasks/second/second'] = array(
|
||||
'title' => 'Second second',
|
||||
'type' => MENU_LOCAL_TASK,
|
||||
) + $base;
|
||||
|
||||
// Menu trail tests.
|
||||
// @see MenuTrailTestCase
|
||||
$items['menu-test/menu-trail'] = array(
|
||||
'title' => 'Menu trail - Case 1',
|
||||
'page callback' => 'menu_test_menu_trail_callback',
|
||||
'access arguments' => array('access content'),
|
||||
);
|
||||
$items['admin/config/development/menu-trail'] = array(
|
||||
'title' => 'Menu trail - Case 2',
|
||||
'description' => 'Tests menu_tree_set_path()',
|
||||
'page callback' => 'menu_test_menu_trail_callback',
|
||||
'access arguments' => array('access administration pages'),
|
||||
);
|
||||
$items['menu-test/custom-403-page'] = array(
|
||||
'title' => 'Custom 403 page',
|
||||
'page callback' => 'menu_test_custom_403_404_callback',
|
||||
'access arguments' => array('access content'),
|
||||
);
|
||||
$items['menu-test/custom-404-page'] = array(
|
||||
'title' => 'Custom 404 page',
|
||||
'page callback' => 'menu_test_custom_403_404_callback',
|
||||
'access arguments' => array('access content'),
|
||||
);
|
||||
|
||||
// File inheritance tests. This menu item should inherit the page callback
|
||||
// system_admin_menu_block_page() and therefore render its children as links
|
||||
// on the page.
|
||||
$items['admin/config/development/file-inheritance'] = array(
|
||||
'title' => 'File inheritance',
|
||||
'description' => 'Test file inheritance',
|
||||
'access arguments' => array('access content'),
|
||||
);
|
||||
$items['admin/config/development/file-inheritance/inherit'] = array(
|
||||
'title' => 'Inherit',
|
||||
'description' => 'File inheritance test description',
|
||||
'page callback' => 'menu_test_callback',
|
||||
'access arguments' => array('access content'),
|
||||
);
|
||||
|
||||
$items['menu_login_callback'] = array(
|
||||
'title' => 'Used as a login path',
|
||||
'page callback' => 'menu_login_callback',
|
||||
'access callback' => TRUE,
|
||||
);
|
||||
|
||||
$items['menu-title-test/case1'] = array(
|
||||
'title' => 'Example title - Case 1',
|
||||
'access callback' => TRUE,
|
||||
'page callback' => 'menu_test_callback',
|
||||
);
|
||||
$items['menu-title-test/case2'] = array(
|
||||
'title' => 'Example @sub1 - Case @op2',
|
||||
// If '2' is not in quotes, the argument becomes arg(2).
|
||||
'title arguments' => array('@sub1' => 'title', '@op2' => '2'),
|
||||
'access callback' => TRUE,
|
||||
'page callback' => 'menu_test_callback',
|
||||
);
|
||||
$items['menu-title-test/case3'] = array(
|
||||
'title' => 'Example title',
|
||||
'title callback' => 'menu_test_title_callback',
|
||||
'access callback' => TRUE,
|
||||
'page callback' => 'menu_test_callback',
|
||||
);
|
||||
$items['menu-title-test/case4'] = array(
|
||||
// Title gets completely ignored. Good thing, too.
|
||||
'title' => 'Bike sheds full of blue smurfs',
|
||||
'title callback' => 'menu_test_title_callback',
|
||||
// If '4' is not in quotes, the argument becomes arg(4).
|
||||
'title arguments' => array('Example title', '4'),
|
||||
'access callback' => TRUE,
|
||||
'page callback' => 'menu_test_callback',
|
||||
);
|
||||
|
||||
// Load arguments inheritance test.
|
||||
$items['menu-test/arguments/%menu_test_argument/%'] = array(
|
||||
'title' => 'Load arguments inheritance test',
|
||||
'load arguments' => array(3),
|
||||
'page callback' => 'menu_test_callback',
|
||||
'access callback' => TRUE,
|
||||
);
|
||||
$items['menu-test/arguments/%menu_test_argument/%/default'] = array(
|
||||
'title' => 'Default local task',
|
||||
'type' => MENU_DEFAULT_LOCAL_TASK,
|
||||
);
|
||||
$items['menu-test/arguments/%menu_test_argument/%/task'] = array(
|
||||
'title' => 'Local task',
|
||||
'page callback' => 'menu_test_callback',
|
||||
'access callback' => TRUE,
|
||||
'type' => MENU_LOCAL_TASK,
|
||||
);
|
||||
// For this path, load arguments should be inherited for the first loader only.
|
||||
$items['menu-test/arguments/%menu_test_argument/%menu_test_other_argument/common-loader'] = array(
|
||||
'title' => 'Local task',
|
||||
'page callback' => 'menu_test_callback',
|
||||
'access callback' => TRUE,
|
||||
'type' => MENU_LOCAL_TASK,
|
||||
);
|
||||
// For these paths, no load arguments should be inherited.
|
||||
// Not on the same position.
|
||||
$items['menu-test/arguments/%/%menu_test_argument/different-loaders-1'] = array(
|
||||
'title' => 'An item not sharing the same loader',
|
||||
'page callback' => 'menu_test_callback',
|
||||
'access callback' => TRUE,
|
||||
);
|
||||
// Not the same loader.
|
||||
$items['menu-test/arguments/%menu_test_other_argument/%/different-loaders-2'] = array(
|
||||
'title' => 'An item not sharing the same loader',
|
||||
'page callback' => 'menu_test_callback',
|
||||
'access callback' => TRUE,
|
||||
);
|
||||
// Not the same loader.
|
||||
$items['menu-test/arguments/%/%/different-loaders-3'] = array(
|
||||
'title' => 'An item not sharing the same loader',
|
||||
'page callback' => 'menu_test_callback',
|
||||
'access callback' => TRUE,
|
||||
);
|
||||
// Explict load arguments should not be overriden (even if empty).
|
||||
$items['menu-test/arguments/%menu_test_argument/%/explicit-arguments'] = array(
|
||||
'title' => 'An item defining explicit load arguments',
|
||||
'load arguments' => array(),
|
||||
'page callback' => 'menu_test_callback',
|
||||
'access callback' => TRUE,
|
||||
);
|
||||
|
||||
return $items;
|
||||
}
|
||||
|
||||
/**
|
||||
* Dummy argument loader for hook_menu() to point to.
|
||||
*/
|
||||
function menu_test_argument_load($arg1) {
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Dummy argument loader for hook_menu() to point to.
|
||||
*/
|
||||
function menu_test_other_argument_load($arg1) {
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Dummy callback for hook_menu() to point to.
|
||||
*
|
||||
* @return
|
||||
* A random string.
|
||||
*/
|
||||
function menu_test_callback() {
|
||||
return 'This is menu_test_callback().';
|
||||
}
|
||||
|
||||
/**
|
||||
* Callback that test menu_test_menu_tree_set_path().
|
||||
*/
|
||||
function menu_test_menu_trail_callback() {
|
||||
$menu_path = variable_get('menu_test_menu_tree_set_path', array());
|
||||
if (!empty($menu_path)) {
|
||||
menu_tree_set_path($menu_path['menu_name'], $menu_path['path']);
|
||||
}
|
||||
return 'This is menu_test_menu_trail_callback().';
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements hook_init().
|
||||
*/
|
||||
function menu_test_init() {
|
||||
// When requested by one of the MenuTrailTestCase tests, record the initial
|
||||
// active trail during Drupal's bootstrap (before the user is redirected to a
|
||||
// custom 403 or 404 page). See menu_test_custom_403_404_callback().
|
||||
if (variable_get('menu_test_record_active_trail', FALSE)) {
|
||||
variable_set('menu_test_active_trail_initial', menu_get_active_trail());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Callback for our custom 403 and 404 pages.
|
||||
*/
|
||||
function menu_test_custom_403_404_callback() {
|
||||
// When requested by one of the MenuTrailTestCase tests, record the final
|
||||
// active trail now that the user has been redirected to the custom 403 or
|
||||
// 404 page. See menu_test_init().
|
||||
if (variable_get('menu_test_record_active_trail', FALSE)) {
|
||||
variable_set('menu_test_active_trail_final', menu_get_active_trail());
|
||||
}
|
||||
|
||||
return 'This is menu_test_custom_403_404_callback().';
|
||||
}
|
||||
|
||||
/**
|
||||
* Page callback to use when testing the theme callback functionality.
|
||||
*
|
||||
* @param $inherited
|
||||
* An optional boolean to set to TRUE when the requested page is intended to
|
||||
* inherit the theme of its parent.
|
||||
* @return
|
||||
* A string describing the requested custom theme and actual theme being used
|
||||
* for the current page request.
|
||||
*/
|
||||
function menu_test_theme_page_callback($inherited = FALSE) {
|
||||
global $theme_key;
|
||||
// Initialize the theme system so that $theme_key will be populated.
|
||||
drupal_theme_initialize();
|
||||
// Now check both the requested custom theme and the actual theme being used.
|
||||
$custom_theme = menu_get_custom_theme();
|
||||
$requested_theme = empty($custom_theme) ? 'NONE' : $custom_theme;
|
||||
$output = "Custom theme: $requested_theme. Actual theme: $theme_key.";
|
||||
if ($inherited) {
|
||||
$output .= ' Theme callback inheritance is being tested.';
|
||||
}
|
||||
return $output;
|
||||
}
|
||||
|
||||
/**
|
||||
* Theme callback to use when testing the theme callback functionality.
|
||||
*
|
||||
* @param $argument
|
||||
* The argument passed in from the URL.
|
||||
* @return
|
||||
* The name of the custom theme to request for the current page.
|
||||
*/
|
||||
function menu_test_theme_callback($argument) {
|
||||
// Test using the variable administrative theme.
|
||||
if ($argument == 'use-admin-theme') {
|
||||
return variable_get('admin_theme');
|
||||
}
|
||||
// Test using a theme that exists, but may or may not be enabled.
|
||||
elseif ($argument == 'use-stark-theme') {
|
||||
return 'stark';
|
||||
}
|
||||
// Test using a theme that does not exist.
|
||||
elseif ($argument == 'use-fake-theme') {
|
||||
return 'fake_theme';
|
||||
}
|
||||
// For any other value of the URL argument, do not return anything. This
|
||||
// allows us to test that returning nothing from a theme callback function
|
||||
// causes the page to correctly fall back on using the main site theme.
|
||||
}
|
||||
|
||||
/**
|
||||
* Implement hook_custom_theme().
|
||||
*
|
||||
* @return
|
||||
* The name of the custom theme to use for the current page.
|
||||
*/
|
||||
function menu_test_custom_theme() {
|
||||
// If an appropriate variable has been set in the database, request the theme
|
||||
// that is stored there. Otherwise, do not attempt to dynamically set the
|
||||
// theme.
|
||||
if ($theme = variable_get('menu_test_hook_custom_theme_name', FALSE)) {
|
||||
return $theme;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper function for the testMenuName() test. Used to change the menu_name
|
||||
* parameter of a menu.
|
||||
*
|
||||
* @param $new_name
|
||||
* If set, will change the menu_name value.
|
||||
* @return
|
||||
* The menu_name value to use.
|
||||
*/
|
||||
function menu_test_menu_name($new_name = '') {
|
||||
static $name = 'original';
|
||||
if ($new_name) {
|
||||
$name = $new_name;
|
||||
}
|
||||
return $name;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements hook_menu_link_insert().
|
||||
*
|
||||
* @return
|
||||
* A random string.
|
||||
*/
|
||||
function menu_test_menu_link_insert($item) {
|
||||
menu_test_static_variable('insert');
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements hook_menu_link_update().
|
||||
*
|
||||
* @return
|
||||
* A random string.
|
||||
*/
|
||||
function menu_test_menu_link_update($item) {
|
||||
menu_test_static_variable('update');
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements hook_menu_link_delete().
|
||||
*
|
||||
* @return
|
||||
* A random string.
|
||||
*/
|
||||
function menu_test_menu_link_delete($item) {
|
||||
menu_test_static_variable('delete');
|
||||
}
|
||||
|
||||
/**
|
||||
* Static function for testing hook results.
|
||||
*
|
||||
* @param $value
|
||||
* The value to set or NULL to return the current value.
|
||||
* @return
|
||||
* A text string for comparison to test assertions.
|
||||
*/
|
||||
function menu_test_static_variable($value = NULL) {
|
||||
static $variable;
|
||||
if (!empty($value)) {
|
||||
$variable = $value;
|
||||
}
|
||||
return $variable;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements hook_menu_site_status_alter().
|
||||
*/
|
||||
function menu_test_menu_site_status_alter(&$menu_site_status, $path) {
|
||||
// Allow access to ?q=menu_login_callback even if in maintenance mode.
|
||||
if ($menu_site_status == MENU_SITE_OFFLINE && $path == 'menu_login_callback') {
|
||||
$menu_site_status = MENU_SITE_ONLINE;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Menu callback to be used as a login path.
|
||||
*/
|
||||
function menu_login_callback() {
|
||||
return 'This is menu_login_callback().';
|
||||
}
|
||||
|
||||
/**
|
||||
* Concatenates a string, by using the t() function and a case number.
|
||||
*
|
||||
* @param $title
|
||||
* Title string.
|
||||
* @param $case_number
|
||||
* The current case number which is tests (defaults to 3).
|
||||
*/
|
||||
function menu_test_title_callback($title, $case_no = 3) {
|
||||
return t($title) . ' - Case ' . $case_no;
|
||||
}
|
346
modules/simpletest/tests/module.test
Normal file
346
modules/simpletest/tests/module.test
Normal file
|
@ -0,0 +1,346 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Tests for the module API.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Unit tests for the module API.
|
||||
*/
|
||||
class ModuleUnitTest extends DrupalWebTestCase {
|
||||
public static function getInfo() {
|
||||
return array(
|
||||
'name' => 'Module API',
|
||||
'description' => 'Test low-level module functions.',
|
||||
'group' => 'Module',
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* The basic functionality of module_list().
|
||||
*/
|
||||
function testModuleList() {
|
||||
// Build a list of modules, sorted alphabetically.
|
||||
$profile_info = install_profile_info('standard', 'en');
|
||||
$module_list = $profile_info['dependencies'];
|
||||
|
||||
// Installation profile is a module that is expected to be loaded.
|
||||
$module_list[] = 'standard';
|
||||
|
||||
sort($module_list);
|
||||
// Compare this list to the one returned by module_list(). We expect them
|
||||
// to match, since all default profile modules have a weight equal to 0
|
||||
// (except for block.module, which has a lower weight but comes first in
|
||||
// the alphabet anyway).
|
||||
$this->assertModuleList($module_list, t('Standard profile'));
|
||||
|
||||
// Try to install a new module.
|
||||
module_enable(array('contact'));
|
||||
$module_list[] = 'contact';
|
||||
sort($module_list);
|
||||
$this->assertModuleList($module_list, t('After adding a module'));
|
||||
|
||||
// Try to mess with the module weights.
|
||||
db_update('system')
|
||||
->fields(array('weight' => 20))
|
||||
->condition('name', 'contact')
|
||||
->condition('type', 'module')
|
||||
->execute();
|
||||
// Reset the module list.
|
||||
module_list(TRUE);
|
||||
// Move contact to the end of the array.
|
||||
unset($module_list[array_search('contact', $module_list)]);
|
||||
$module_list[] = 'contact';
|
||||
$this->assertModuleList($module_list, t('After changing weights'));
|
||||
|
||||
// Test the fixed list feature.
|
||||
$fixed_list = array(
|
||||
'system' => array('filename' => drupal_get_path('module', 'system')),
|
||||
'menu' => array('filename' => drupal_get_path('module', 'menu')),
|
||||
);
|
||||
module_list(FALSE, FALSE, FALSE, $fixed_list);
|
||||
$new_module_list = array_combine(array_keys($fixed_list), array_keys($fixed_list));
|
||||
$this->assertModuleList($new_module_list, t('When using a fixed list'));
|
||||
|
||||
// Reset the module list.
|
||||
module_list(TRUE);
|
||||
$this->assertModuleList($module_list, t('After reset'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Assert that module_list() return the expected values.
|
||||
*
|
||||
* @param $expected_values
|
||||
* The expected values, sorted by weight and module name.
|
||||
*/
|
||||
protected function assertModuleList(Array $expected_values, $condition) {
|
||||
$expected_values = array_combine($expected_values, $expected_values);
|
||||
$this->assertEqual($expected_values, module_list(), format_string('@condition: module_list() returns correct results', array('@condition' => $condition)));
|
||||
ksort($expected_values);
|
||||
$this->assertIdentical($expected_values, module_list(FALSE, FALSE, TRUE), format_string('@condition: module_list() returns correctly sorted results', array('@condition' => $condition)));
|
||||
}
|
||||
|
||||
/**
|
||||
* Test module_implements() caching.
|
||||
*/
|
||||
function testModuleImplements() {
|
||||
// Clear the cache.
|
||||
cache_clear_all('module_implements', 'cache_bootstrap');
|
||||
$this->assertFalse(cache_get('module_implements', 'cache_bootstrap'), 'The module implements cache is empty.');
|
||||
$this->drupalGet('');
|
||||
$this->assertTrue(cache_get('module_implements', 'cache_bootstrap'), 'The module implements cache is populated after requesting a page.');
|
||||
|
||||
// Test again with an authenticated user.
|
||||
$this->user = $this->drupalCreateUser();
|
||||
$this->drupalLogin($this->user);
|
||||
cache_clear_all('module_implements', 'cache_bootstrap');
|
||||
$this->drupalGet('');
|
||||
$this->assertTrue(cache_get('module_implements', 'cache_bootstrap'), 'The module implements cache is populated after requesting a page.');
|
||||
|
||||
// Make sure group include files are detected properly even when the file is
|
||||
// already loaded when the cache is rebuilt.
|
||||
// For that activate the module_test which provides the file to load.
|
||||
module_enable(array('module_test'));
|
||||
|
||||
module_load_include('inc', 'module_test', 'module_test.file');
|
||||
$modules = module_implements('test_hook');
|
||||
$static = drupal_static('module_implements');
|
||||
$this->assertTrue(in_array('module_test', $modules), 'Hook found.');
|
||||
$this->assertEqual($static['test_hook']['module_test'], 'file', 'Include file detected.');
|
||||
}
|
||||
|
||||
/**
|
||||
* Test that module_invoke() can load a hook defined in hook_hook_info().
|
||||
*/
|
||||
function testModuleInvoke() {
|
||||
module_enable(array('module_test'), FALSE);
|
||||
$this->resetAll();
|
||||
$this->drupalGet('module-test/hook-dynamic-loading-invoke');
|
||||
$this->assertText('success!', 'module_invoke() dynamically loads a hook defined in hook_hook_info().');
|
||||
}
|
||||
|
||||
/**
|
||||
* Test that module_invoke_all() can load a hook defined in hook_hook_info().
|
||||
*/
|
||||
function testModuleInvokeAll() {
|
||||
module_enable(array('module_test'), FALSE);
|
||||
$this->resetAll();
|
||||
$this->drupalGet('module-test/hook-dynamic-loading-invoke-all');
|
||||
$this->assertText('success!', 'module_invoke_all() dynamically loads a hook defined in hook_hook_info().');
|
||||
}
|
||||
|
||||
/**
|
||||
* Test dependency resolution.
|
||||
*/
|
||||
function testDependencyResolution() {
|
||||
// Enable the test module, and make sure that other modules we are testing
|
||||
// are not already enabled. (If they were, the tests below would not work
|
||||
// correctly.)
|
||||
module_enable(array('module_test'), FALSE);
|
||||
$this->assertTrue(module_exists('module_test'), 'Test module is enabled.');
|
||||
$this->assertFalse(module_exists('forum'), 'Forum module is disabled.');
|
||||
$this->assertFalse(module_exists('poll'), 'Poll module is disabled.');
|
||||
$this->assertFalse(module_exists('php'), 'PHP module is disabled.');
|
||||
|
||||
// First, create a fake missing dependency. Forum depends on poll, which
|
||||
// depends on a made-up module, foo. Nothing should be installed.
|
||||
variable_set('dependency_test', 'missing dependency');
|
||||
drupal_static_reset('system_rebuild_module_data');
|
||||
$result = module_enable(array('forum'));
|
||||
$this->assertFalse($result, 'module_enable() returns FALSE if dependencies are missing.');
|
||||
$this->assertFalse(module_exists('forum'), 'module_enable() aborts if dependencies are missing.');
|
||||
|
||||
// Now, fix the missing dependency. Forum module depends on poll, but poll
|
||||
// depends on the PHP module. module_enable() should work.
|
||||
variable_set('dependency_test', 'dependency');
|
||||
drupal_static_reset('system_rebuild_module_data');
|
||||
$result = module_enable(array('forum'));
|
||||
$this->assertTrue($result, 'module_enable() returns the correct value.');
|
||||
// Verify that the fake dependency chain was installed.
|
||||
$this->assertTrue(module_exists('poll') && module_exists('php'), 'Dependency chain was installed by module_enable().');
|
||||
// Verify that the original module was installed.
|
||||
$this->assertTrue(module_exists('forum'), 'Module installation with unlisted dependencies succeeded.');
|
||||
// Finally, verify that the modules were enabled in the correct order.
|
||||
$this->assertEqual(variable_get('test_module_enable_order', array()), array('php', 'poll', 'forum'), 'Modules were enabled in the correct order by module_enable().');
|
||||
|
||||
// Now, disable the PHP module. Both forum and poll should be disabled as
|
||||
// well, in the correct order.
|
||||
module_disable(array('php'));
|
||||
$this->assertTrue(!module_exists('forum') && !module_exists('poll'), 'Depedency chain was disabled by module_disable().');
|
||||
$this->assertFalse(module_exists('php'), 'Disabling a module with unlisted dependents succeeded.');
|
||||
$this->assertEqual(variable_get('test_module_disable_order', array()), array('forum', 'poll', 'php'), 'Modules were disabled in the correct order by module_disable().');
|
||||
|
||||
// Disable a module that is listed as a dependency by the installation
|
||||
// profile. Make sure that the profile itself is not on the list of
|
||||
// dependent modules to be disabled.
|
||||
$profile = drupal_get_profile();
|
||||
$info = install_profile_info($profile);
|
||||
$this->assertTrue(in_array('comment', $info['dependencies']), 'Comment module is listed as a dependency of the installation profile.');
|
||||
$this->assertTrue(module_exists('comment'), 'Comment module is enabled.');
|
||||
module_disable(array('comment'));
|
||||
$this->assertFalse(module_exists('comment'), 'Comment module was disabled.');
|
||||
$disabled_modules = variable_get('test_module_disable_order', array());
|
||||
$this->assertTrue(in_array('comment', $disabled_modules), 'Comment module is in the list of disabled modules.');
|
||||
$this->assertFalse(in_array($profile, $disabled_modules), 'The installation profile is not in the list of disabled modules.');
|
||||
|
||||
// Try to uninstall the PHP module by itself. This should be rejected,
|
||||
// since the modules which it depends on need to be uninstalled first, and
|
||||
// that is too destructive to perform automatically.
|
||||
$result = drupal_uninstall_modules(array('php'));
|
||||
$this->assertFalse($result, 'Calling drupal_uninstall_modules() on a module whose dependents are not uninstalled fails.');
|
||||
foreach (array('forum', 'poll', 'php') as $module) {
|
||||
$this->assertNotEqual(drupal_get_installed_schema_version($module), SCHEMA_UNINSTALLED, format_string('The @module module was not uninstalled.', array('@module' => $module)));
|
||||
}
|
||||
|
||||
// Now uninstall all three modules explicitly, but in the incorrect order,
|
||||
// and make sure that drupal_uninstal_modules() uninstalled them in the
|
||||
// correct sequence.
|
||||
$result = drupal_uninstall_modules(array('poll', 'php', 'forum'));
|
||||
$this->assertTrue($result, 'drupal_uninstall_modules() returns the correct value.');
|
||||
foreach (array('forum', 'poll', 'php') as $module) {
|
||||
$this->assertEqual(drupal_get_installed_schema_version($module), SCHEMA_UNINSTALLED, format_string('The @module module was uninstalled.', array('@module' => $module)));
|
||||
}
|
||||
$this->assertEqual(variable_get('test_module_uninstall_order', array()), array('forum', 'poll', 'php'), 'Modules were uninstalled in the correct order by drupal_uninstall_modules().');
|
||||
|
||||
// Uninstall the profile module from above, and make sure that the profile
|
||||
// itself is not on the list of dependent modules to be uninstalled.
|
||||
$result = drupal_uninstall_modules(array('comment'));
|
||||
$this->assertTrue($result, 'drupal_uninstall_modules() returns the correct value.');
|
||||
$this->assertEqual(drupal_get_installed_schema_version('comment'), SCHEMA_UNINSTALLED, 'Comment module was uninstalled.');
|
||||
$uninstalled_modules = variable_get('test_module_uninstall_order', array());
|
||||
$this->assertTrue(in_array('comment', $uninstalled_modules), 'Comment module is in the list of uninstalled modules.');
|
||||
$this->assertFalse(in_array($profile, $uninstalled_modules), 'The installation profile is not in the list of uninstalled modules.');
|
||||
|
||||
// Enable forum module again, which should enable both the poll module and
|
||||
// php module. But, this time do it with poll module declaring a dependency
|
||||
// on a specific version of php module in its info file. Make sure that
|
||||
// module_enable() still works.
|
||||
variable_set('dependency_test', 'version dependency');
|
||||
drupal_static_reset('system_rebuild_module_data');
|
||||
$result = module_enable(array('forum'));
|
||||
$this->assertTrue($result, 'module_enable() returns the correct value.');
|
||||
// Verify that the fake dependency chain was installed.
|
||||
$this->assertTrue(module_exists('poll') && module_exists('php'), 'Dependency chain was installed by module_enable().');
|
||||
// Verify that the original module was installed.
|
||||
$this->assertTrue(module_exists('forum'), 'Module installation with version dependencies succeeded.');
|
||||
// Finally, verify that the modules were enabled in the correct order.
|
||||
$enable_order = variable_get('test_module_enable_order', array());
|
||||
$php_position = array_search('php', $enable_order);
|
||||
$poll_position = array_search('poll', $enable_order);
|
||||
$forum_position = array_search('forum', $enable_order);
|
||||
$php_before_poll = $php_position !== FALSE && $poll_position !== FALSE && $php_position < $poll_position;
|
||||
$poll_before_forum = $poll_position !== FALSE && $forum_position !== FALSE && $poll_position < $forum_position;
|
||||
$this->assertTrue($php_before_poll && $poll_before_forum, 'Modules were enabled in the correct order by module_enable().');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Unit tests for module installation.
|
||||
*/
|
||||
class ModuleInstallTestCase extends DrupalWebTestCase {
|
||||
public static function getInfo() {
|
||||
return array(
|
||||
'name' => 'Module installation',
|
||||
'description' => 'Tests the installation of modules.',
|
||||
'group' => 'Module',
|
||||
);
|
||||
}
|
||||
|
||||
function setUp() {
|
||||
parent::setUp('module_test');
|
||||
}
|
||||
|
||||
/**
|
||||
* Test that calls to drupal_write_record() work during module installation.
|
||||
*
|
||||
* This is a useful function to test because modules often use it to insert
|
||||
* initial data in their database tables when they are being installed or
|
||||
* enabled. Furthermore, drupal_write_record() relies on the module schema
|
||||
* information being available, so this also checks that the data from one of
|
||||
* the module's hook implementations, in particular hook_schema(), is
|
||||
* properly available during this time. Therefore, this test helps ensure
|
||||
* that modules are fully functional while Drupal is installing and enabling
|
||||
* them.
|
||||
*/
|
||||
function testDrupalWriteRecord() {
|
||||
// Check for data that was inserted using drupal_write_record() while the
|
||||
// 'module_test' module was being installed and enabled.
|
||||
$data = db_query("SELECT data FROM {module_test}")->fetchCol();
|
||||
$this->assertTrue(in_array('Data inserted in hook_install()', $data), 'Data inserted using drupal_write_record() in hook_install() is correctly saved.');
|
||||
$this->assertTrue(in_array('Data inserted in hook_enable()', $data), 'Data inserted using drupal_write_record() in hook_enable() is correctly saved.');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Unit tests for module uninstallation and related hooks.
|
||||
*/
|
||||
class ModuleUninstallTestCase extends DrupalWebTestCase {
|
||||
public static function getInfo() {
|
||||
return array(
|
||||
'name' => 'Module uninstallation',
|
||||
'description' => 'Tests the uninstallation of modules.',
|
||||
'group' => 'Module',
|
||||
);
|
||||
}
|
||||
|
||||
function setUp() {
|
||||
parent::setUp('module_test', 'user');
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests the hook_modules_uninstalled() of the user module.
|
||||
*/
|
||||
function testUserPermsUninstalled() {
|
||||
// Uninstalls the module_test module, so hook_modules_uninstalled()
|
||||
// is executed.
|
||||
module_disable(array('module_test'));
|
||||
drupal_uninstall_modules(array('module_test'));
|
||||
|
||||
// Are the perms defined by module_test removed from {role_permission}.
|
||||
$count = db_query("SELECT COUNT(rid) FROM {role_permission} WHERE permission = :perm", array(':perm' => 'module_test perm'))->fetchField();
|
||||
$this->assertEqual(0, $count, 'Permissions were all removed.');
|
||||
}
|
||||
}
|
||||
|
||||
class ModuleImplementsAlterTestCase extends DrupalWebTestCase {
|
||||
public static function getInfo() {
|
||||
return array(
|
||||
'name' => 'Module implements alter',
|
||||
'description' => 'Tests hook_module_implements_alter().',
|
||||
'group' => 'Module',
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests hook_module_implements_alter() adding an implementation.
|
||||
*/
|
||||
function testModuleImplementsAlter() {
|
||||
module_enable(array('module_test'), FALSE);
|
||||
$this->assertTrue(module_exists('module_test'), 'Test module is enabled.');
|
||||
|
||||
// Assert that module_test.module is now included.
|
||||
$this->assertTrue(function_exists('module_test_permission'),
|
||||
'The file module_test.module was successfully included.');
|
||||
|
||||
$modules = module_implements('permission');
|
||||
$this->assertTrue(in_array('module_test', $modules), 'module_test implements hook_permission.');
|
||||
|
||||
$modules = module_implements('module_implements_alter');
|
||||
$this->assertTrue(in_array('module_test', $modules), 'module_test implements hook_module_implements_alter().');
|
||||
|
||||
// Assert that module_test.implementations.inc is not included yet.
|
||||
$this->assertFalse(function_exists('module_test_altered_test_hook'),
|
||||
'The file module_test.implementations.inc is not included yet.');
|
||||
|
||||
// Assert that module_test_module_implements_alter(*, 'altered_test_hook')
|
||||
// has added an implementation
|
||||
$this->assertTrue(in_array('module_test', module_implements('altered_test_hook')),
|
||||
'module_test implements hook_altered_test_hook().');
|
||||
|
||||
// Assert that module_test.implementations.inc was included as part of the process.
|
||||
$this->assertTrue(function_exists('module_test_altered_test_hook'),
|
||||
'The file module_test.implementations.inc was included.');
|
||||
}
|
||||
|
||||
}
|
13
modules/simpletest/tests/module_test.file.inc
Normal file
13
modules/simpletest/tests/module_test.file.inc
Normal file
|
@ -0,0 +1,13 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* A file to test module_implements() loading includes.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Implements hook_test_hook().
|
||||
*/
|
||||
function module_test_test_hook() {
|
||||
return array('module_test' => 'success!');
|
||||
}
|
10
modules/simpletest/tests/module_test.implementations.inc
Normal file
10
modules/simpletest/tests/module_test.implementations.inc
Normal file
|
@ -0,0 +1,10 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* Implements hook_altered_test_hook()
|
||||
*
|
||||
* @see module_test_module_implements_alter()
|
||||
*/
|
||||
function module_test_altered_test_hook() {
|
||||
return __FUNCTION__;
|
||||
}
|
12
modules/simpletest/tests/module_test.info
Normal file
12
modules/simpletest/tests/module_test.info
Normal file
|
@ -0,0 +1,12 @@
|
|||
name = "Module test"
|
||||
description = "Support module for module system testing."
|
||||
package = Testing
|
||||
version = VERSION
|
||||
core = 7.x
|
||||
hidden = TRUE
|
||||
|
||||
; Information added by Drupal.org packaging script on 2017-06-21
|
||||
version = "7.56"
|
||||
project = "drupal"
|
||||
datestamp = "1498069849"
|
||||
|
42
modules/simpletest/tests/module_test.install
Normal file
42
modules/simpletest/tests/module_test.install
Normal file
|
@ -0,0 +1,42 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Install, update and uninstall functions for the module_test module.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Implements hook_schema().
|
||||
*/
|
||||
function module_test_schema() {
|
||||
$schema['module_test'] = array(
|
||||
'description' => 'Dummy table to test the behavior of hook_schema() during module installation.',
|
||||
'fields' => array(
|
||||
'data' => array(
|
||||
'type' => 'varchar',
|
||||
'length' => 255,
|
||||
'not null' => TRUE,
|
||||
'default' => '',
|
||||
'description' => 'An example data column for the module.',
|
||||
),
|
||||
),
|
||||
);
|
||||
return $schema;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements hook_install().
|
||||
*/
|
||||
function module_test_install() {
|
||||
$record = array('data' => 'Data inserted in hook_install()');
|
||||
drupal_write_record('module_test', $record);
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements hook_enable().
|
||||
*/
|
||||
function module_test_enable() {
|
||||
$record = array('data' => 'Data inserted in hook_enable()');
|
||||
drupal_write_record('module_test', $record);
|
||||
}
|
||||
|
142
modules/simpletest/tests/module_test.module
Normal file
142
modules/simpletest/tests/module_test.module
Normal file
|
@ -0,0 +1,142 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* Implements hook_permission().
|
||||
*/
|
||||
function module_test_permission() {
|
||||
return array(
|
||||
'module_test perm' => t('example perm for module_test module'),
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements hook_system_info_alter().
|
||||
*
|
||||
* Manipulate module dependencies to test dependency chains.
|
||||
*/
|
||||
function module_test_system_info_alter(&$info, $file, $type) {
|
||||
if (variable_get('dependency_test', FALSE) == 'missing dependency') {
|
||||
if ($file->name == 'forum') {
|
||||
// Make forum module depend on poll.
|
||||
$info['dependencies'][] = 'poll';
|
||||
}
|
||||
elseif ($file->name == 'poll') {
|
||||
// Make poll depend on a made-up module.
|
||||
$info['dependencies'][] = 'foo';
|
||||
}
|
||||
}
|
||||
elseif (variable_get('dependency_test', FALSE) == 'dependency') {
|
||||
if ($file->name == 'forum') {
|
||||
// Make the forum module depend on poll.
|
||||
$info['dependencies'][] = 'poll';
|
||||
}
|
||||
elseif ($file->name == 'poll') {
|
||||
// Make poll depend on php module.
|
||||
$info['dependencies'][] = 'php';
|
||||
}
|
||||
}
|
||||
elseif (variable_get('dependency_test', FALSE) == 'version dependency') {
|
||||
if ($file->name == 'forum') {
|
||||
// Make the forum module depend on poll.
|
||||
$info['dependencies'][] = 'poll';
|
||||
}
|
||||
elseif ($file->name == 'poll') {
|
||||
// Make poll depend on a specific version of php module.
|
||||
$info['dependencies'][] = 'php (1.x)';
|
||||
}
|
||||
elseif ($file->name == 'php') {
|
||||
// Set php module to a version compatible with the above.
|
||||
$info['version'] = '7.x-1.0';
|
||||
}
|
||||
}
|
||||
if ($file->name == 'seven' && $type == 'theme') {
|
||||
$info['regions']['test_region'] = t('Test region');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements hook_hook_info().
|
||||
*/
|
||||
function module_test_hook_info() {
|
||||
$hooks['test_hook'] = array(
|
||||
'group' => 'file',
|
||||
);
|
||||
return $hooks;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements hook_menu().
|
||||
*/
|
||||
function module_test_menu() {
|
||||
$items['module-test/hook-dynamic-loading-invoke'] = array(
|
||||
'title' => 'Test hook dynamic loading (invoke)',
|
||||
'page callback' => 'module_test_hook_dynamic_loading_invoke',
|
||||
'access arguments' => array('access content'),
|
||||
);
|
||||
$items['module-test/hook-dynamic-loading-invoke-all'] = array(
|
||||
'title' => 'Test hook dynamic loading (invoke_all)',
|
||||
'page callback' => 'module_test_hook_dynamic_loading_invoke_all',
|
||||
'access arguments' => array('access content'),
|
||||
);
|
||||
return $items;
|
||||
}
|
||||
|
||||
/**
|
||||
* Page callback for 'hook dynamic loading' test.
|
||||
*
|
||||
* If the hook is dynamically loaded correctly, the menu callback should
|
||||
* return 'success!'.
|
||||
*/
|
||||
function module_test_hook_dynamic_loading_invoke() {
|
||||
$result = module_invoke('module_test', 'test_hook');
|
||||
return $result['module_test'];
|
||||
}
|
||||
|
||||
/**
|
||||
* Page callback for 'hook dynamic loading' test.
|
||||
*
|
||||
* If the hook is dynamically loaded correctly, the menu callback should
|
||||
* return 'success!'.
|
||||
*/
|
||||
function module_test_hook_dynamic_loading_invoke_all() {
|
||||
$result = module_invoke_all('test_hook');
|
||||
return $result['module_test'];
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements hook_modules_enabled().
|
||||
*/
|
||||
function module_test_modules_enabled($modules) {
|
||||
// Record the ordered list of modules that were passed in to this hook so we
|
||||
// can check that the modules were enabled in the correct sequence.
|
||||
variable_set('test_module_enable_order', $modules);
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements hook_modules_disabled().
|
||||
*/
|
||||
function module_test_modules_disabled($modules) {
|
||||
// Record the ordered list of modules that were passed in to this hook so we
|
||||
// can check that the modules were disabled in the correct sequence.
|
||||
variable_set('test_module_disable_order', $modules);
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements hook_modules_uninstalled().
|
||||
*/
|
||||
function module_test_modules_uninstalled($modules) {
|
||||
// Record the ordered list of modules that were passed in to this hook so we
|
||||
// can check that the modules were uninstalled in the correct sequence.
|
||||
variable_set('test_module_uninstall_order', $modules);
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements hook_module_implements_alter()
|
||||
*/
|
||||
function module_test_module_implements_alter(&$implementations, $hook) {
|
||||
if ($hook === 'altered_test_hook') {
|
||||
// Add a hook implementation, that will be found in
|
||||
// module_test.implementations.inc.
|
||||
$implementations['module_test'] = 'implementations';
|
||||
}
|
||||
}
|
159
modules/simpletest/tests/pager.test
Normal file
159
modules/simpletest/tests/pager.test
Normal file
|
@ -0,0 +1,159 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Tests for pager functionality.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Tests pager functionality.
|
||||
*/
|
||||
class PagerFunctionalWebTestCase extends DrupalWebTestCase {
|
||||
protected $profile = 'testing';
|
||||
|
||||
public static function getInfo() {
|
||||
return array(
|
||||
'name' => 'Pager functionality',
|
||||
'description' => 'Tests pager functionality.',
|
||||
'group' => 'Pager',
|
||||
);
|
||||
}
|
||||
|
||||
function setUp() {
|
||||
parent::setUp(array('dblog'));
|
||||
|
||||
// Insert 300 log messages.
|
||||
for ($i = 0; $i < 300; $i++) {
|
||||
watchdog('pager_test', $this->randomString(), NULL, WATCHDOG_DEBUG);
|
||||
}
|
||||
|
||||
$this->admin_user = $this->drupalCreateUser(array(
|
||||
'access site reports',
|
||||
));
|
||||
$this->drupalLogin($this->admin_user);
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests markup and CSS classes of pager links.
|
||||
*/
|
||||
function testActiveClass() {
|
||||
// Verify first page.
|
||||
$this->drupalGet('admin/reports/dblog');
|
||||
$current_page = 0;
|
||||
$this->assertPagerItems($current_page);
|
||||
|
||||
// Verify any page but first/last.
|
||||
$current_page++;
|
||||
$this->drupalGet('admin/reports/dblog', array('query' => array('page' => $current_page)));
|
||||
$this->assertPagerItems($current_page);
|
||||
|
||||
// Verify last page.
|
||||
$elements = $this->xpath('//li[contains(@class, :class)]/a', array(':class' => 'pager-last'));
|
||||
preg_match('@page=(\d+)@', $elements[0]['href'], $matches);
|
||||
$current_page = (int) $matches[1];
|
||||
$this->drupalGet($GLOBALS['base_root'] . $elements[0]['href'], array('external' => TRUE));
|
||||
$this->assertPagerItems($current_page);
|
||||
}
|
||||
|
||||
/**
|
||||
* Asserts pager items and links.
|
||||
*
|
||||
* @param int $current_page
|
||||
* The current pager page the internal browser is on.
|
||||
*/
|
||||
protected function assertPagerItems($current_page) {
|
||||
$elements = $this->xpath('//ul[@class=:class]/li', array(':class' => 'pager'));
|
||||
$this->assertTrue(!empty($elements), 'Pager found.');
|
||||
|
||||
// Make current page 1-based.
|
||||
$current_page++;
|
||||
|
||||
// Extract first/previous and next/last items.
|
||||
// first/previous only exist, if the current page is not the first.
|
||||
if ($current_page > 1) {
|
||||
$first = array_shift($elements);
|
||||
$previous = array_shift($elements);
|
||||
}
|
||||
// next/last always exist, unless the current page is the last.
|
||||
if ($current_page != count($elements)) {
|
||||
$last = array_pop($elements);
|
||||
$next = array_pop($elements);
|
||||
}
|
||||
|
||||
// Verify items and links to pages.
|
||||
foreach ($elements as $page => $element) {
|
||||
// Make item/page index 1-based.
|
||||
$page++;
|
||||
if ($current_page == $page) {
|
||||
$this->assertClass($element, 'pager-current', 'Item for current page has .pager-current class.');
|
||||
$this->assertFalse(isset($element->a), 'Item for current page has no link.');
|
||||
}
|
||||
else {
|
||||
$this->assertNoClass($element, 'pager-current', "Item for page $page has no .pager-current class.");
|
||||
$this->assertClass($element, 'pager-item', "Item for page $page has .pager-item class.");
|
||||
$this->assertTrue($element->a, "Link to page $page found.");
|
||||
$this->assertNoClass($element->a, 'active', "Link to page $page is not active.");
|
||||
}
|
||||
unset($elements[--$page]);
|
||||
}
|
||||
// Verify that no other items remain untested.
|
||||
$this->assertTrue(empty($elements), 'All expected items found.');
|
||||
|
||||
// Verify first/previous and next/last items and links.
|
||||
if (isset($first)) {
|
||||
$this->assertClass($first, 'pager-first', 'Item for first page has .pager-first class.');
|
||||
$this->assertTrue($first->a, 'Link to first page found.');
|
||||
$this->assertNoClass($first->a, 'active', 'Link to first page is not active.');
|
||||
}
|
||||
if (isset($previous)) {
|
||||
$this->assertClass($previous, 'pager-previous', 'Item for first page has .pager-previous class.');
|
||||
$this->assertTrue($previous->a, 'Link to previous page found.');
|
||||
$this->assertNoClass($previous->a, 'active', 'Link to previous page is not active.');
|
||||
}
|
||||
if (isset($next)) {
|
||||
$this->assertClass($next, 'pager-next', 'Item for next page has .pager-next class.');
|
||||
$this->assertTrue($next->a, 'Link to next page found.');
|
||||
$this->assertNoClass($next->a, 'active', 'Link to next page is not active.');
|
||||
}
|
||||
if (isset($last)) {
|
||||
$this->assertClass($last, 'pager-last', 'Item for last page has .pager-last class.');
|
||||
$this->assertTrue($last->a, 'Link to last page found.');
|
||||
$this->assertNoClass($last->a, 'active', 'Link to last page is not active.');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Asserts that an element has a given class.
|
||||
*
|
||||
* @param SimpleXMLElement $element
|
||||
* The element to test.
|
||||
* @param string $class
|
||||
* The class to assert.
|
||||
* @param string $message
|
||||
* (optional) A verbose message to output.
|
||||
*/
|
||||
protected function assertClass(SimpleXMLElement $element, $class, $message = NULL) {
|
||||
if (!isset($message)) {
|
||||
$message = "Class .$class found.";
|
||||
}
|
||||
$this->assertTrue(strpos($element['class'], $class) !== FALSE, $message);
|
||||
}
|
||||
|
||||
/**
|
||||
* Asserts that an element does not have a given class.
|
||||
*
|
||||
* @param SimpleXMLElement $element
|
||||
* The element to test.
|
||||
* @param string $class
|
||||
* The class to assert.
|
||||
* @param string $message
|
||||
* (optional) A verbose message to output.
|
||||
*/
|
||||
protected function assertNoClass(SimpleXMLElement $element, $class, $message = NULL) {
|
||||
if (!isset($message)) {
|
||||
$message = "Class .$class not found.";
|
||||
}
|
||||
$this->assertTrue(strpos($element['class'], $class) === FALSE, $message);
|
||||
}
|
||||
}
|
||||
|
81
modules/simpletest/tests/password.test
Normal file
81
modules/simpletest/tests/password.test
Normal file
|
@ -0,0 +1,81 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Provides unit tests for password.inc.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Unit tests for password hashing API.
|
||||
*/
|
||||
class PasswordHashingTest extends DrupalWebTestCase {
|
||||
protected $profile = 'testing';
|
||||
|
||||
public static function getInfo() {
|
||||
return array(
|
||||
'name' => 'Password hashing',
|
||||
'description' => 'Password hashing unit tests.',
|
||||
'group' => 'System',
|
||||
);
|
||||
}
|
||||
|
||||
function setUp() {
|
||||
require_once DRUPAL_ROOT . '/' . variable_get('password_inc', 'includes/password.inc');
|
||||
parent::setUp();
|
||||
}
|
||||
|
||||
/**
|
||||
* Test password hashing.
|
||||
*/
|
||||
function testPasswordHashing() {
|
||||
// Set a log2 iteration count that is deliberately out of bounds to test
|
||||
// that it is corrected to be within bounds.
|
||||
variable_set('password_count_log2', 1);
|
||||
// Set up a fake $account with a password 'baz', hashed with md5.
|
||||
$password = 'baz';
|
||||
$account = (object) array('name' => 'foo', 'pass' => md5($password));
|
||||
// The md5 password should be flagged as needing an update.
|
||||
$this->assertTrue(user_needs_new_hash($account), 'User with md5 password needs a new hash.');
|
||||
// Re-hash the password.
|
||||
$old_hash = $account->pass;
|
||||
$account->pass = user_hash_password($password);
|
||||
$this->assertIdentical(_password_get_count_log2($account->pass), DRUPAL_MIN_HASH_COUNT, 'Re-hashed password has the minimum number of log2 iterations.');
|
||||
$this->assertTrue($account->pass != $old_hash, 'Password hash changed.');
|
||||
$this->assertTrue(user_check_password($password, $account), 'Password check succeeds.');
|
||||
// Since the log2 setting hasn't changed and the user has a valid password,
|
||||
// user_needs_new_hash() should return FALSE.
|
||||
$this->assertFalse(user_needs_new_hash($account), 'User does not need a new hash.');
|
||||
// Increment the log2 iteration to MIN + 1.
|
||||
variable_set('password_count_log2', DRUPAL_MIN_HASH_COUNT + 1);
|
||||
$this->assertTrue(user_needs_new_hash($account), 'User needs a new hash after incrementing the log2 count.');
|
||||
// Re-hash the password.
|
||||
$old_hash = $account->pass;
|
||||
$account->pass = user_hash_password($password);
|
||||
$this->assertIdentical(_password_get_count_log2($account->pass), DRUPAL_MIN_HASH_COUNT + 1, 'Re-hashed password has the correct number of log2 iterations.');
|
||||
$this->assertTrue($account->pass != $old_hash, 'Password hash changed again.');
|
||||
// Now the hash should be OK.
|
||||
$this->assertFalse(user_needs_new_hash($account), 'Re-hashed password does not need a new hash.');
|
||||
$this->assertTrue(user_check_password($password, $account), 'Password check succeeds with re-hashed password.');
|
||||
}
|
||||
|
||||
/**
|
||||
* Verifies that passwords longer than 512 bytes are not hashed.
|
||||
*/
|
||||
public function testLongPassword() {
|
||||
$password = str_repeat('x', 512);
|
||||
$result = user_hash_password($password);
|
||||
$this->assertFalse(empty($result), '512 byte long password is allowed.');
|
||||
$password = str_repeat('x', 513);
|
||||
$result = user_hash_password($password);
|
||||
$this->assertFalse($result, '513 byte long password is not allowed.');
|
||||
// Check a string of 3-byte UTF-8 characters.
|
||||
$password = str_repeat('€', 170);
|
||||
$result = user_hash_password($password);
|
||||
$this->assertFalse(empty($result), '510 byte long password is allowed.');
|
||||
$password .= 'xx';
|
||||
$this->assertFalse(empty($result), '512 byte long password is allowed.');
|
||||
$password = str_repeat('€', 171);
|
||||
$result = user_hash_password($password);
|
||||
$this->assertFalse($result, '513 byte long password is not allowed.');
|
||||
}
|
||||
}
|
381
modules/simpletest/tests/path.test
Normal file
381
modules/simpletest/tests/path.test
Normal file
|
@ -0,0 +1,381 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Tests for path.inc.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Unit tests for the drupal_match_path() function in path.inc.
|
||||
*
|
||||
* @see drupal_match_path().
|
||||
*/
|
||||
class DrupalMatchPathTestCase extends DrupalWebTestCase {
|
||||
protected $front;
|
||||
|
||||
public static function getInfo() {
|
||||
return array(
|
||||
'name' => 'Drupal match path',
|
||||
'description' => 'Tests the drupal_match_path() function to make sure it works properly.',
|
||||
'group' => 'Path API',
|
||||
);
|
||||
}
|
||||
|
||||
function setUp() {
|
||||
// Set up the database and testing environment.
|
||||
parent::setUp();
|
||||
|
||||
// Set up a random site front page to test the '<front>' placeholder.
|
||||
$this->front = $this->randomName();
|
||||
variable_set('site_frontpage', $this->front);
|
||||
// Refresh our static variables from the database.
|
||||
$this->refreshVariables();
|
||||
}
|
||||
|
||||
/**
|
||||
* Run through our test cases, making sure each one works as expected.
|
||||
*/
|
||||
function testDrupalMatchPath() {
|
||||
// Set up our test cases.
|
||||
$tests = $this->drupalMatchPathTests();
|
||||
foreach ($tests as $patterns => $cases) {
|
||||
foreach ($cases as $path => $expected_result) {
|
||||
$actual_result = drupal_match_path($path, $patterns);
|
||||
$this->assertIdentical($actual_result, $expected_result, format_string('Tried matching the path <code>@path</code> to the pattern <pre>@patterns</pre> - expected @expected, got @actual.', array('@path' => $path, '@patterns' => $patterns, '@expected' => var_export($expected_result, TRUE), '@actual' => var_export($actual_result, TRUE))));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper function for testDrupalMatchPath(): set up an array of test cases.
|
||||
*
|
||||
* @return
|
||||
* An array of test cases to cycle through.
|
||||
*/
|
||||
private function drupalMatchPathTests() {
|
||||
return array(
|
||||
// Single absolute paths.
|
||||
'blog/1' => array(
|
||||
'blog/1' => TRUE,
|
||||
'blog/2' => FALSE,
|
||||
'test' => FALSE,
|
||||
),
|
||||
// Single paths with wildcards.
|
||||
'blog/*' => array(
|
||||
'blog/1' => TRUE,
|
||||
'blog/2' => TRUE,
|
||||
'blog/3/edit' => TRUE,
|
||||
'blog/' => TRUE,
|
||||
'blog' => FALSE,
|
||||
'test' => FALSE,
|
||||
),
|
||||
// Single paths with multiple wildcards.
|
||||
'node/*/revisions/*' => array(
|
||||
'node/1/revisions/3' => TRUE,
|
||||
'node/345/revisions/test' => TRUE,
|
||||
'node/23/edit' => FALSE,
|
||||
'test' => FALSE,
|
||||
),
|
||||
// Single paths with '<front>'.
|
||||
'<front>' => array(
|
||||
$this->front => TRUE,
|
||||
"$this->front/" => FALSE,
|
||||
"$this->front/edit" => FALSE,
|
||||
'node' => FALSE,
|
||||
'' => FALSE,
|
||||
),
|
||||
// Paths with both '<front>' and wildcards (should not work).
|
||||
'<front>/*' => array(
|
||||
$this->front => FALSE,
|
||||
"$this->front/" => FALSE,
|
||||
"$this->front/edit" => FALSE,
|
||||
'node/12' => FALSE,
|
||||
'' => FALSE,
|
||||
),
|
||||
// Multiple paths with the \n delimiter.
|
||||
"node/*\nnode/*/edit" => array(
|
||||
'node/1' => TRUE,
|
||||
'node/view' => TRUE,
|
||||
'node/32/edit' => TRUE,
|
||||
'node/delete/edit' => TRUE,
|
||||
'node/50/delete' => TRUE,
|
||||
'test/example' => FALSE,
|
||||
),
|
||||
// Multiple paths with the \r delimiter.
|
||||
"user/*\rblog/*" => array(
|
||||
'user/1' => TRUE,
|
||||
'blog/1' => TRUE,
|
||||
'user/1/blog/1' => TRUE,
|
||||
'user/blog' => TRUE,
|
||||
'test/example' => FALSE,
|
||||
'user' => FALSE,
|
||||
'blog' => FALSE,
|
||||
),
|
||||
// Multiple paths with the \r\n delimiter.
|
||||
"test\r\n<front>" => array(
|
||||
'test' => TRUE,
|
||||
$this->front => TRUE,
|
||||
'example' => FALSE,
|
||||
),
|
||||
// Test existing regular expressions (should be escaped).
|
||||
'[^/]+?/[0-9]' => array(
|
||||
'test/1' => FALSE,
|
||||
'[^/]+?/[0-9]' => TRUE,
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests hook_url_alter functions.
|
||||
*/
|
||||
class UrlAlterFunctionalTest extends DrupalWebTestCase {
|
||||
public static function getInfo() {
|
||||
return array(
|
||||
'name' => t('URL altering'),
|
||||
'description' => t('Tests hook_url_inbound_alter() and hook_url_outbound_alter().'),
|
||||
'group' => t('Path API'),
|
||||
);
|
||||
}
|
||||
|
||||
function setUp() {
|
||||
parent::setUp('path', 'forum', 'url_alter_test');
|
||||
}
|
||||
|
||||
/**
|
||||
* Test that URL altering works and that it occurs in the correct order.
|
||||
*/
|
||||
function testUrlAlter() {
|
||||
$account = $this->drupalCreateUser(array('administer url aliases'));
|
||||
$this->drupalLogin($account);
|
||||
|
||||
$uid = $account->uid;
|
||||
$name = $account->name;
|
||||
|
||||
// Test a single altered path.
|
||||
$this->assertUrlInboundAlter("user/$name", "user/$uid");
|
||||
$this->assertUrlOutboundAlter("user/$uid", "user/$name");
|
||||
|
||||
// Test that a path always uses its alias.
|
||||
$path = array('source' => "user/$uid/test1", 'alias' => 'alias/test1');
|
||||
path_save($path);
|
||||
$this->assertUrlInboundAlter('alias/test1', "user/$uid/test1");
|
||||
$this->assertUrlOutboundAlter("user/$uid/test1", 'alias/test1');
|
||||
|
||||
// Test that alias source paths are normalized in the interface.
|
||||
$edit = array('source' => "user/$name/edit", 'alias' => 'alias/test2');
|
||||
$this->drupalPost('admin/config/search/path/add', $edit, t('Save'));
|
||||
$this->assertText(t('The alias has been saved.'));
|
||||
|
||||
// Test that a path always uses its alias.
|
||||
$this->assertUrlInboundAlter('alias/test2', "user/$uid/edit");
|
||||
$this->assertUrlOutboundAlter("user/$uid/edit", 'alias/test2');
|
||||
|
||||
// Test a non-existent user is not altered.
|
||||
$uid++;
|
||||
$this->assertUrlInboundAlter("user/$uid", "user/$uid");
|
||||
$this->assertUrlOutboundAlter("user/$uid", "user/$uid");
|
||||
|
||||
// Test that 'forum' is altered to 'community' correctly, both at the root
|
||||
// level and for a specific existing forum.
|
||||
$this->assertUrlInboundAlter('community', 'forum');
|
||||
$this->assertUrlOutboundAlter('forum', 'community');
|
||||
$forum_vid = db_query("SELECT vid FROM {taxonomy_vocabulary} WHERE module = 'forum'")->fetchField();
|
||||
$tid = db_insert('taxonomy_term_data')
|
||||
->fields(array(
|
||||
'name' => $this->randomName(),
|
||||
'vid' => $forum_vid,
|
||||
))
|
||||
->execute();
|
||||
$this->assertUrlInboundAlter("community/$tid", "forum/$tid");
|
||||
$this->assertUrlOutboundAlter("forum/$tid", "community/$tid");
|
||||
}
|
||||
|
||||
/**
|
||||
* Test current_path() and request_path().
|
||||
*/
|
||||
function testCurrentUrlRequestedPath() {
|
||||
$this->drupalGet('url-alter-test/bar');
|
||||
$this->assertRaw('request_path=url-alter-test/bar', 'request_path() returns the requested path.');
|
||||
$this->assertRaw('current_path=url-alter-test/foo', 'current_path() returns the internal path.');
|
||||
}
|
||||
|
||||
/**
|
||||
* 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
|
||||
* A string with the original path that is run through url().
|
||||
* @param $final
|
||||
* A string with the expected result after url().
|
||||
* @return
|
||||
* TRUE if $original was correctly altered to $final, FALSE otherwise.
|
||||
*/
|
||||
protected function assertUrlOutboundAlter($original, $final) {
|
||||
// Test outbound altering.
|
||||
$result = url($original);
|
||||
$base_path = base_path() . (variable_get('clean_url', '0') ? '' : '?q=');
|
||||
$result = substr($result, strlen($base_path));
|
||||
$this->assertIdentical($result, $final, format_string('Altered outbound URL %original, expected %final, and got %result.', array('%original' => $original, '%final' => $final, '%result' => $result)));
|
||||
}
|
||||
|
||||
/**
|
||||
* Assert that a inbound path is altered to an expected value.
|
||||
*
|
||||
* @param $original
|
||||
* A string with the aliased or un-normal path that is run through
|
||||
* drupal_get_normal_path().
|
||||
* @param $final
|
||||
* A string with the expected result after url().
|
||||
* @return
|
||||
* TRUE if $original was correctly altered to $final, FALSE otherwise.
|
||||
*/
|
||||
protected function assertUrlInboundAlter($original, $final) {
|
||||
// Test inbound altering.
|
||||
$result = drupal_get_normal_path($original);
|
||||
$this->assertIdentical($result, $final, format_string('Altered inbound URL %original, expected %final, and got %result.', array('%original' => $original, '%final' => $final, '%result' => $result)));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Unit test for drupal_lookup_path().
|
||||
*/
|
||||
class PathLookupTest extends DrupalWebTestCase {
|
||||
public static function getInfo() {
|
||||
return array(
|
||||
'name' => t('Path lookup'),
|
||||
'description' => t('Tests that drupal_lookup_path() returns correct paths.'),
|
||||
'group' => t('Path API'),
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test that drupal_lookup_path() returns the correct path.
|
||||
*/
|
||||
function testDrupalLookupPath() {
|
||||
$account = $this->drupalCreateUser();
|
||||
$uid = $account->uid;
|
||||
$name = $account->name;
|
||||
|
||||
// Test the situation where the source is the same for multiple aliases.
|
||||
// Start with a language-neutral alias, which we will override.
|
||||
$path = array(
|
||||
'source' => "user/$uid",
|
||||
'alias' => 'foo',
|
||||
);
|
||||
path_save($path);
|
||||
$this->assertEqual(drupal_lookup_path('alias', $path['source']), $path['alias'], 'Basic alias lookup works.');
|
||||
$this->assertEqual(drupal_lookup_path('source', $path['alias']), $path['source'], 'Basic source lookup works.');
|
||||
|
||||
// Create a language specific alias for the default language (English).
|
||||
$path = array(
|
||||
'source' => "user/$uid",
|
||||
'alias' => "users/$name",
|
||||
'language' => 'en',
|
||||
);
|
||||
path_save($path);
|
||||
$this->assertEqual(drupal_lookup_path('alias', $path['source']), $path['alias'], 'English alias overrides language-neutral alias.');
|
||||
$this->assertEqual(drupal_lookup_path('source', $path['alias']), $path['source'], 'English source overrides language-neutral source.');
|
||||
|
||||
// Create a language-neutral alias for the same path, again.
|
||||
$path = array(
|
||||
'source' => "user/$uid",
|
||||
'alias' => 'bar',
|
||||
);
|
||||
path_save($path);
|
||||
$this->assertEqual(drupal_lookup_path('alias', $path['source']), "users/$name", 'English alias still returned after entering a language-neutral alias.');
|
||||
|
||||
// Create a language-specific (xx-lolspeak) alias for the same path.
|
||||
$path = array(
|
||||
'source' => "user/$uid",
|
||||
'alias' => 'LOL',
|
||||
'language' => 'xx-lolspeak',
|
||||
);
|
||||
path_save($path);
|
||||
$this->assertEqual(drupal_lookup_path('alias', $path['source']), "users/$name", 'English alias still returned after entering a LOLspeak alias.');
|
||||
// The LOLspeak alias should be returned if we really want LOLspeak.
|
||||
$this->assertEqual(drupal_lookup_path('alias', $path['source'], 'xx-lolspeak'), 'LOL', 'LOLspeak alias returned if we specify xx-lolspeak to drupal_lookup_path().');
|
||||
|
||||
// Create a new alias for this path in English, which should override the
|
||||
// previous alias for "user/$uid".
|
||||
$path = array(
|
||||
'source' => "user/$uid",
|
||||
'alias' => 'users/my-new-path',
|
||||
'language' => 'en',
|
||||
);
|
||||
path_save($path);
|
||||
$this->assertEqual(drupal_lookup_path('alias', $path['source']), $path['alias'], 'Recently created English alias returned.');
|
||||
$this->assertEqual(drupal_lookup_path('source', $path['alias']), $path['source'], 'Recently created English source returned.');
|
||||
|
||||
// Remove the English aliases, which should cause a fallback to the most
|
||||
// recently created language-neutral alias, 'bar'.
|
||||
db_delete('url_alias')
|
||||
->condition('language', 'en')
|
||||
->execute();
|
||||
drupal_clear_path_cache();
|
||||
$this->assertEqual(drupal_lookup_path('alias', $path['source']), 'bar', 'Path lookup falls back to recently created language-neutral alias.');
|
||||
|
||||
// Test the situation where the alias and language are the same, but
|
||||
// the source differs. The newer alias record should be returned.
|
||||
$account2 = $this->drupalCreateUser();
|
||||
$path = array(
|
||||
'source' => 'user/' . $account2->uid,
|
||||
'alias' => 'bar',
|
||||
);
|
||||
path_save($path);
|
||||
$this->assertEqual(drupal_lookup_path('source', $path['alias']), $path['source'], 'Newer alias record is returned when comparing two LANGUAGE_NONE paths with the same alias.');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests the path_save() function.
|
||||
*/
|
||||
class PathSaveTest extends DrupalWebTestCase {
|
||||
public static function getInfo() {
|
||||
return array(
|
||||
'name' => t('Path save'),
|
||||
'description' => t('Tests that path_save() exposes the previous alias value.'),
|
||||
'group' => t('Path API'),
|
||||
);
|
||||
}
|
||||
|
||||
function setUp() {
|
||||
// Enable a helper module that implements hook_path_update().
|
||||
parent::setUp('path_test');
|
||||
path_test_reset();
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests that path_save() makes the original path available to modules.
|
||||
*/
|
||||
function testDrupalSaveOriginalPath() {
|
||||
$account = $this->drupalCreateUser();
|
||||
$uid = $account->uid;
|
||||
$name = $account->name;
|
||||
|
||||
// Create a language-neutral alias.
|
||||
$path = array(
|
||||
'source' => "user/$uid",
|
||||
'alias' => 'foo',
|
||||
);
|
||||
$path_original = $path;
|
||||
path_save($path);
|
||||
|
||||
// Alter the path.
|
||||
$path['alias'] = 'bar';
|
||||
path_save($path);
|
||||
|
||||
// Test to see if the original alias is available to modules during
|
||||
// hook_path_update().
|
||||
$results = variable_get('path_test_results', array());
|
||||
$this->assertIdentical($results['hook_path_update']['original']['alias'], $path_original['alias'], 'Old path alias available to modules during hook_path_update.');
|
||||
$this->assertIdentical($results['hook_path_update']['original']['source'], $path_original['source'], 'Old path alias available to modules during hook_path_update.');
|
||||
}
|
||||
}
|
12
modules/simpletest/tests/path_test.info
Normal file
12
modules/simpletest/tests/path_test.info
Normal file
|
@ -0,0 +1,12 @@
|
|||
name = "Hook path tests"
|
||||
description = "Support module for path hook testing."
|
||||
package = Testing
|
||||
version = VERSION
|
||||
core = 7.x
|
||||
hidden = TRUE
|
||||
|
||||
; Information added by Drupal.org packaging script on 2017-06-21
|
||||
version = "7.56"
|
||||
project = "drupal"
|
||||
datestamp = "1498069849"
|
||||
|
23
modules/simpletest/tests/path_test.module
Normal file
23
modules/simpletest/tests/path_test.module
Normal file
|
@ -0,0 +1,23 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Helper module for the path tests.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Resets the path test results.
|
||||
*/
|
||||
function path_test_reset() {
|
||||
variable_set('path_test_results', array());
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements hook_path_update().
|
||||
*/
|
||||
function path_test_path_update($path) {
|
||||
$results = variable_get('path_test_results', array());
|
||||
$results['hook_path_update'] = $path;
|
||||
variable_set('path_test_results', $results);
|
||||
}
|
||||
|
|
@ -0,0 +1,18 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\psr_0_test\Tests;
|
||||
|
||||
class ExampleTest extends \DrupalWebTestCase {
|
||||
|
||||
public static function getInfo() {
|
||||
return array(
|
||||
'name' => 'PSR0 example test: PSR-0 in disabled modules.',
|
||||
'description' => 'We want to assert that this test case is being discovered.',
|
||||
'group' => 'SimpleTest',
|
||||
);
|
||||
}
|
||||
|
||||
function testArithmetics() {
|
||||
$this->assert(1 + 1 == 2, '1 + 1 == 2');
|
||||
}
|
||||
}
|
|
@ -0,0 +1,18 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\psr_0_test\Tests\Nested;
|
||||
|
||||
class NestedExampleTest extends \DrupalWebTestCase {
|
||||
|
||||
public static function getInfo() {
|
||||
return array(
|
||||
'name' => 'PSR0 example test: PSR-0 in nested subfolders.',
|
||||
'description' => 'We want to assert that this PSR-0 test case is being discovered.',
|
||||
'group' => 'SimpleTest',
|
||||
);
|
||||
}
|
||||
|
||||
function testArithmetics() {
|
||||
$this->assert(1 + 1 == 2, '1 + 1 == 2');
|
||||
}
|
||||
}
|
12
modules/simpletest/tests/psr_0_test/psr_0_test.info
Normal file
12
modules/simpletest/tests/psr_0_test/psr_0_test.info
Normal file
|
@ -0,0 +1,12 @@
|
|||
name = PSR-0 Test cases
|
||||
description = Test classes to be discovered by simpletest.
|
||||
core = 7.x
|
||||
|
||||
hidden = TRUE
|
||||
package = Testing
|
||||
|
||||
; Information added by Drupal.org packaging script on 2017-06-21
|
||||
version = "7.56"
|
||||
project = "drupal"
|
||||
datestamp = "1498069849"
|
||||
|
1
modules/simpletest/tests/psr_0_test/psr_0_test.module
Normal file
1
modules/simpletest/tests/psr_0_test/psr_0_test.module
Normal file
|
@ -0,0 +1 @@
|
|||
<?php
|
12
modules/simpletest/tests/psr_4_test/psr_4_test.info
Normal file
12
modules/simpletest/tests/psr_4_test/psr_4_test.info
Normal file
|
@ -0,0 +1,12 @@
|
|||
name = PSR-4 Test cases
|
||||
description = Test classes to be discovered by simpletest.
|
||||
core = 7.x
|
||||
|
||||
hidden = TRUE
|
||||
package = Testing
|
||||
|
||||
; Information added by Drupal.org packaging script on 2017-06-21
|
||||
version = "7.56"
|
||||
project = "drupal"
|
||||
datestamp = "1498069849"
|
||||
|
1
modules/simpletest/tests/psr_4_test/psr_4_test.module
Normal file
1
modules/simpletest/tests/psr_4_test/psr_4_test.module
Normal file
|
@ -0,0 +1 @@
|
|||
<?php
|
|
@ -0,0 +1,18 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\psr_4_test\Tests;
|
||||
|
||||
class ExampleTest extends \DrupalWebTestCase {
|
||||
|
||||
public static function getInfo() {
|
||||
return array(
|
||||
'name' => 'PSR4 example test: PSR-4 in disabled modules.',
|
||||
'description' => 'We want to assert that this test case is being discovered.',
|
||||
'group' => 'SimpleTest',
|
||||
);
|
||||
}
|
||||
|
||||
function testArithmetics() {
|
||||
$this->assert(1 + 1 == 2, '1 + 1 == 2');
|
||||
}
|
||||
}
|
|
@ -0,0 +1,18 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\psr_4_test\Tests\Nested;
|
||||
|
||||
class NestedExampleTest extends \DrupalWebTestCase {
|
||||
|
||||
public static function getInfo() {
|
||||
return array(
|
||||
'name' => 'PSR4 example test: PSR-4 in nested subfolders.',
|
||||
'description' => 'We want to assert that this PSR-4 test case is being discovered.',
|
||||
'group' => 'SimpleTest',
|
||||
);
|
||||
}
|
||||
|
||||
function testArithmetics() {
|
||||
$this->assert(1 + 1 == 2, '1 + 1 == 2');
|
||||
}
|
||||
}
|
142
modules/simpletest/tests/registry.test
Normal file
142
modules/simpletest/tests/registry.test
Normal file
|
@ -0,0 +1,142 @@
|
|||
<?php
|
||||
|
||||
class RegistryParseFileTestCase extends DrupalWebTestCase {
|
||||
public static function getInfo() {
|
||||
return array(
|
||||
'name' => 'Registry parse file test',
|
||||
'description' => 'Parse a simple file and check that its resources are saved to the database.',
|
||||
'group' => 'System'
|
||||
);
|
||||
}
|
||||
|
||||
function setUp() {
|
||||
$chrs = hash('sha256', microtime() . mt_rand());
|
||||
$this->fileName = 'registry_test_' . substr($chrs, 0, 16);
|
||||
$this->className = 'registry_test_class' . substr($chrs, 16, 16);
|
||||
$this->interfaceName = 'registry_test_interface' . substr($chrs, 32, 16);
|
||||
parent::setUp();
|
||||
}
|
||||
|
||||
/**
|
||||
* testRegistryParseFile
|
||||
*/
|
||||
function testRegistryParseFile() {
|
||||
_registry_parse_file($this->fileName, $this->getFileContents());
|
||||
foreach (array('className', 'interfaceName') as $resource) {
|
||||
$foundName = db_query('SELECT name FROM {registry} WHERE name = :name', array(':name' => $this->$resource))->fetchField();
|
||||
$this->assertTrue($this->$resource == $foundName, t('Resource "@resource" found.', array('@resource' => $this->$resource)));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* getFileContents
|
||||
*/
|
||||
function getFileContents() {
|
||||
$file_contents = <<<CONTENTS
|
||||
<?php
|
||||
|
||||
class {$this->className} {}
|
||||
|
||||
interface {$this->interfaceName} {}
|
||||
|
||||
CONTENTS;
|
||||
return $file_contents;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
class RegistryParseFilesTestCase extends DrupalWebTestCase {
|
||||
protected $fileTypes = array('new', 'existing_changed');
|
||||
|
||||
public static function getInfo() {
|
||||
return array(
|
||||
'name' => 'Registry parse files test',
|
||||
'description' => 'Read two a simple files from disc, and check that their resources are saved to the database.',
|
||||
'group' => 'System'
|
||||
);
|
||||
}
|
||||
|
||||
function setUp() {
|
||||
parent::setUp();
|
||||
// Create files with some php to parse - one 'new', one 'existing' so
|
||||
// we test all the important code paths in _registry_parse_files.
|
||||
foreach ($this->fileTypes as $fileType) {
|
||||
$chrs = hash('sha256', microtime() . mt_rand());
|
||||
$this->$fileType = new stdClass();
|
||||
$this->$fileType->fileName = 'public://registry_test_' . substr($chrs, 0, 16);
|
||||
$this->$fileType->className = 'registry_test_class' . substr($chrs, 16, 16);
|
||||
$this->$fileType->interfaceName = 'registry_test_interface' . substr($chrs, 32, 16);
|
||||
$this->$fileType->contents = $this->getFileContents($fileType);
|
||||
file_save_data($this->$fileType->contents, $this->$fileType->fileName);
|
||||
|
||||
if ($fileType == 'existing_changed') {
|
||||
// Add a record with an incorrect hash.
|
||||
$this->$fileType->fakeHash = hash('sha256', mt_rand());
|
||||
db_insert('registry_file')
|
||||
->fields(array(
|
||||
'hash' => $this->$fileType->fakeHash,
|
||||
'filename' => $this->$fileType->fileName,
|
||||
))
|
||||
->execute();
|
||||
|
||||
// Insert some fake resource records.
|
||||
foreach (array('class', 'interface') as $type) {
|
||||
db_insert('registry')
|
||||
->fields(array(
|
||||
'name' => $type . hash('sha256', microtime() . mt_rand()),
|
||||
'type' => $type,
|
||||
'filename' => $this->$fileType->fileName,
|
||||
))
|
||||
->execute();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* testRegistryParseFiles
|
||||
*/
|
||||
function testRegistryParseFiles() {
|
||||
_registry_parse_files($this->getFiles());
|
||||
foreach ($this->fileTypes as $fileType) {
|
||||
// Test that we have all the right resources.
|
||||
foreach (array('className', 'interfaceName') as $resource) {
|
||||
$foundName = db_query('SELECT name FROM {registry} WHERE name = :name', array(':name' => $this->$fileType->$resource))->fetchField();
|
||||
$this->assertTrue($this->$fileType->$resource == $foundName, t('Resource "@resource" found.', array('@resource' => $this->$fileType->$resource)));
|
||||
}
|
||||
// Test that we have the right hash.
|
||||
$hash = db_query('SELECT hash FROM {registry_file} WHERE filename = :filename', array(':filename' => $this->$fileType->fileName))->fetchField();
|
||||
$this->assertTrue(hash('sha256', $this->$fileType->contents) == $hash, t('sha-256 for "@filename" matched.' . $fileType . $hash, array('@filename' => $this->$fileType->fileName)));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* getFiles
|
||||
*/
|
||||
function getFiles() {
|
||||
$files = array();
|
||||
foreach ($this->fileTypes as $fileType) {
|
||||
$files[$this->$fileType->fileName] = array('module' => '', 'weight' => 0);
|
||||
if ($fileType == 'existing_changed') {
|
||||
$files[$this->$fileType->fileName]['hash'] = $this->$fileType->fakeHash;
|
||||
}
|
||||
}
|
||||
return $files;
|
||||
}
|
||||
|
||||
/**
|
||||
* getFileContents
|
||||
*/
|
||||
function getFileContents($fileType) {
|
||||
$file_contents = <<<CONTENTS
|
||||
<?php
|
||||
|
||||
class {$this->$fileType->className} {}
|
||||
|
||||
interface {$this->$fileType->interfaceName} {}
|
||||
|
||||
CONTENTS;
|
||||
return $file_contents;
|
||||
}
|
||||
|
||||
}
|
12
modules/simpletest/tests/requirements1_test.info
Normal file
12
modules/simpletest/tests/requirements1_test.info
Normal file
|
@ -0,0 +1,12 @@
|
|||
name = Requirements 1 Test
|
||||
description = "Tests that a module is not installed when it fails hook_requirements('install')."
|
||||
package = Testing
|
||||
version = VERSION
|
||||
core = 7.x
|
||||
hidden = TRUE
|
||||
|
||||
; Information added by Drupal.org packaging script on 2017-06-21
|
||||
version = "7.56"
|
||||
project = "drupal"
|
||||
datestamp = "1498069849"
|
||||
|
21
modules/simpletest/tests/requirements1_test.install
Normal file
21
modules/simpletest/tests/requirements1_test.install
Normal file
|
@ -0,0 +1,21 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* Implements hook_requirements().
|
||||
*/
|
||||
function requirements1_test_requirements($phase) {
|
||||
$requirements = array();
|
||||
// Ensure translations don't break during installation.
|
||||
$t = get_t();
|
||||
|
||||
// Always fails requirements.
|
||||
if ('install' == $phase) {
|
||||
$requirements['requirements1_test'] = array(
|
||||
'title' => $t('Requirements 1 Test'),
|
||||
'severity' => REQUIREMENT_ERROR,
|
||||
'description' => $t('Requirements 1 Test failed requirements.'),
|
||||
);
|
||||
}
|
||||
|
||||
return $requirements;
|
||||
}
|
7
modules/simpletest/tests/requirements1_test.module
Normal file
7
modules/simpletest/tests/requirements1_test.module
Normal file
|
@ -0,0 +1,7 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Tests that a module is not installed when it fails
|
||||
* hook_requirements('install').
|
||||
*/
|
14
modules/simpletest/tests/requirements2_test.info
Normal file
14
modules/simpletest/tests/requirements2_test.info
Normal file
|
@ -0,0 +1,14 @@
|
|||
name = Requirements 2 Test
|
||||
description = "Tests that a module is not installed when the one it depends on fails hook_requirements('install)."
|
||||
dependencies[] = requirements1_test
|
||||
dependencies[] = comment
|
||||
package = Testing
|
||||
version = VERSION
|
||||
core = 7.x
|
||||
hidden = TRUE
|
||||
|
||||
; Information added by Drupal.org packaging script on 2017-06-21
|
||||
version = "7.56"
|
||||
project = "drupal"
|
||||
datestamp = "1498069849"
|
||||
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue