'
. '' . $this->drupalGetContent()
);
// @see DrupalWebTestCase::xpath()
$xpath = $this->buildXPathQuery($xpath, $xpath_args);
$element += array('#value' => NULL);
$this->assertFieldByXPath($xpath, $element['#value'], t('#type @type was properly rendered.', array(
'@type' => var_export($element['#type'], TRUE),
)));
}
/**
* Tests caching of an empty render item.
*/
function testDrupalRenderCache() {
// Force a request via GET.
$request_method = $_SERVER['REQUEST_METHOD'];
$_SERVER['REQUEST_METHOD'] = 'GET';
// Create an empty element.
$test_element = array(
'#cache' => array(
'cid' => 'render_cache_test',
),
'#markup' => '',
);
// Render the element and confirm that it goes through the rendering
// process (which will set $element['#printed']).
$element = $test_element;
drupal_render($element);
$this->assertTrue(isset($element['#printed']), t('No cache hit'));
// Render the element again and confirm that it is retrieved from the cache
// instead (so $element['#printed'] will not be set).
$element = $test_element;
drupal_render($element);
$this->assertFalse(isset($element['#printed']), t('Cache hit'));
// Restore the previous request method.
$_SERVER['REQUEST_METHOD'] = $request_method;
}
}
/**
* Tests URL validation by valid_url().
*/
class CommonValidUrlUnitTestCase extends DrupalUnitTestCase {
public static function getInfo() {
return array(
'name' => 'URL validation',
'description' => 'Tests URL validation by valid_url()',
'group' => 'Common',
);
}
/**
* Test valid absolute urls.
*/
function testValidAbsolute() {
$url_schemes = array('http', 'https', 'ftp');
$valid_absolute_urls = array(
'example.com',
'www.example.com',
'ex-ample.com',
'3xampl3.com',
'example.com/paren(the)sis',
'example.com/index.html#pagetop',
'example.com:8080',
'subdomain.example.com',
'example.com/index.php?q=node',
'example.com/index.php?q=node¶m=false',
'user@www.example.com',
'user:pass@www.example.com:8080/login.php?do=login&style=%23#pagetop',
'127.0.0.1',
'example.org?',
'john%20doe:secret:foo@example.org/',
'example.org/~,$\'*;',
'caf%C3%A9.example.org',
'[FEDC:BA98:7654:3210:FEDC:BA98:7654:3210]:80/index.html',
);
foreach ($url_schemes as $scheme) {
foreach ($valid_absolute_urls as $url) {
$test_url = $scheme . '://' . $url;
$valid_url = valid_url($test_url, TRUE);
$this->assertTrue($valid_url, t('@url is a valid url.', array('@url' => $test_url)));
}
}
}
/**
* Test invalid absolute urls.
*/
function testInvalidAbsolute() {
$url_schemes = array('http', 'https', 'ftp');
$invalid_ablosule_urls = array(
'',
'ex!ample.com',
'ex%ample.com',
);
foreach ($url_schemes as $scheme) {
foreach ($invalid_ablosule_urls as $url) {
$test_url = $scheme . '://' . $url;
$valid_url = valid_url($test_url, TRUE);
$this->assertFalse($valid_url, t('@url is NOT a valid url.', array('@url' => $test_url)));
}
}
}
/**
* Test valid relative urls.
*/
function testValidRelative() {
$valid_relative_urls = array(
'paren(the)sis',
'index.html#pagetop',
'index.php?q=node',
'index.php?q=node¶m=false',
'login.php?do=login&style=%23#pagetop',
);
foreach (array('', '/') as $front) {
foreach ($valid_relative_urls as $url) {
$test_url = $front . $url;
$valid_url = valid_url($test_url);
$this->assertTrue($valid_url, t('@url is a valid url.', array('@url' => $test_url)));
}
}
}
/**
* Test invalid relative urls.
*/
function testInvalidRelative() {
$invalid_relative_urls = array(
'ex^mple',
'example<>',
'ex%ample',
);
foreach (array('', '/') as $front) {
foreach ($invalid_relative_urls as $url) {
$test_url = $front . $url;
$valid_url = valid_url($test_url);
$this->assertFALSE($valid_url, t('@url is NOT a valid url.', array('@url' => $test_url)));
}
}
}
}
/**
* Tests writing of data records with drupal_write_record().
*/
class CommonDrupalWriteRecordTestCase extends DrupalWebTestCase {
public static function getInfo() {
return array(
'name' => 'Data record write functionality',
'description' => 'Tests writing of data records with drupal_write_record().',
'group' => 'Common',
);
}
function setUp() {
parent::setUp('database_test');
}
/**
* Test the drupal_write_record() API function.
*/
function testDrupalWriteRecord() {
// Insert a record with no columns populated.
$record = array();
$insert_result = drupal_write_record('test', $record);
$this->assertTrue($insert_result == SAVED_NEW, t('Correct value returned when an empty record is inserted with drupal_write_record().'));
// Insert a record - no columns allow NULL values.
$person = new stdClass();
$person->name = 'John';
$person->unknown_column = 123;
$insert_result = drupal_write_record('test', $person);
$this->assertTrue($insert_result == SAVED_NEW, t('Correct value returned when a record is inserted with drupal_write_record() for a table with a single-field primary key.'));
$this->assertTrue(isset($person->id), t('Primary key is set on record created with drupal_write_record().'));
$this->assertIdentical($person->age, 0, t('Age field set to default value.'));
$this->assertIdentical($person->job, 'Undefined', t('Job field set to default value.'));
// Verify that the record was inserted.
$result = db_query("SELECT * FROM {test} WHERE id = :id", array(':id' => $person->id))->fetchObject();
$this->assertIdentical($result->name, 'John', t('Name field set.'));
$this->assertIdentical($result->age, '0', t('Age field set to default value.'));
$this->assertIdentical($result->job, 'Undefined', t('Job field set to default value.'));
$this->assertFalse(isset($result->unknown_column), t('Unknown column was ignored.'));
// Update the newly created record.
$person->name = 'Peter';
$person->age = 27;
$person->job = NULL;
$update_result = drupal_write_record('test', $person, array('id'));
$this->assertTrue($update_result == SAVED_UPDATED, t('Correct value returned when a record updated with drupal_write_record() for table with single-field primary key.'));
// Verify that the record was updated.
$result = db_query("SELECT * FROM {test} WHERE id = :id", array(':id' => $person->id))->fetchObject();
$this->assertIdentical($result->name, 'Peter', t('Name field set.'));
$this->assertIdentical($result->age, '27', t('Age field set.'));
$this->assertIdentical($result->job, '', t('Job field set and cast to string.'));
// Try to insert NULL in columns that does not allow this.
$person = new stdClass();
$person->name = 'Ringo';
$person->age = NULL;
$person->job = NULL;
$insert_result = drupal_write_record('test', $person);
$this->assertTrue(isset($person->id), t('Primary key is set on record created with drupal_write_record().'));
$result = db_query("SELECT * FROM {test} WHERE id = :id", array(':id' => $person->id))->fetchObject();
$this->assertIdentical($result->name, 'Ringo', t('Name field set.'));
$this->assertIdentical($result->age, '0', t('Age field set.'));
$this->assertIdentical($result->job, '', t('Job field set.'));
// Insert a record - the "age" column allows NULL.
$person = new stdClass();
$person->name = 'Paul';
$person->age = NULL;
$insert_result = drupal_write_record('test_null', $person);
$this->assertTrue(isset($person->id), t('Primary key is set on record created with drupal_write_record().'));
$result = db_query("SELECT * FROM {test_null} WHERE id = :id", array(':id' => $person->id))->fetchObject();
$this->assertIdentical($result->name, 'Paul', t('Name field set.'));
$this->assertIdentical($result->age, NULL, t('Age field set.'));
// Insert a record - do not specify the value of a column that allows NULL.
$person = new stdClass();
$person->name = 'Meredith';
$insert_result = drupal_write_record('test_null', $person);
$this->assertTrue(isset($person->id), t('Primary key is set on record created with drupal_write_record().'));
$this->assertIdentical($person->age, 0, t('Age field set to default value.'));
$result = db_query("SELECT * FROM {test_null} WHERE id = :id", array(':id' => $person->id))->fetchObject();
$this->assertIdentical($result->name, 'Meredith', t('Name field set.'));
$this->assertIdentical($result->age, '0', t('Age field set to default value.'));
// Update the newly created record.
$person->name = 'Mary';
$person->age = NULL;
$update_result = drupal_write_record('test_null', $person, array('id'));
$result = db_query("SELECT * FROM {test_null} WHERE id = :id", array(':id' => $person->id))->fetchObject();
$this->assertIdentical($result->name, 'Mary', t('Name field set.'));
$this->assertIdentical($result->age, NULL, t('Age field set.'));
// Insert a record - the "data" column should be serialized.
$person = new stdClass();
$person->name = 'Dave';
$update_result = drupal_write_record('test_serialized', $person);
$result = db_query("SELECT * FROM {test_serialized} WHERE id = :id", array(':id' => $person->id))->fetchObject();
$this->assertIdentical($result->name, 'Dave', t('Name field set.'));
$this->assertIdentical($result->info, NULL, t('Info field set.'));
$person->info = array();
$update_result = drupal_write_record('test_serialized', $person, array('id'));
$result = db_query("SELECT * FROM {test_serialized} WHERE id = :id", array(':id' => $person->id))->fetchObject();
$this->assertIdentical(unserialize($result->info), array(), t('Info field updated.'));
// Update the serialized record.
$data = array('foo' => 'bar', 1 => 2, 'empty' => '', 'null' => NULL);
$person->info = $data;
$update_result = drupal_write_record('test_serialized', $person, array('id'));
$result = db_query("SELECT * FROM {test_serialized} WHERE id = :id", array(':id' => $person->id))->fetchObject();
$this->assertIdentical(unserialize($result->info), $data, t('Info field updated.'));
// Run an update query where no field values are changed. The database
// layer should return zero for number of affected rows, but
// db_write_record() should still return SAVED_UPDATED.
$update_result = drupal_write_record('test_null', $person, array('id'));
$this->assertTrue($update_result == SAVED_UPDATED, t('Correct value returned when a valid update is run without changing any values.'));
// Insert an object record for a table with a multi-field primary key.
$node_access = new stdClass();
$node_access->nid = mt_rand();
$node_access->gid = mt_rand();
$node_access->realm = $this->randomName();
$insert_result = drupal_write_record('node_access', $node_access);
$this->assertTrue($insert_result == SAVED_NEW, t('Correct value returned when a record is inserted with drupal_write_record() for a table with a multi-field primary key.'));
// Update the record.
$update_result = drupal_write_record('node_access', $node_access, array('nid', 'gid', 'realm'));
$this->assertTrue($update_result == SAVED_UPDATED, t('Correct value returned when a record is updated with drupal_write_record() for a table with a multi-field primary key.'));
}
}
/**
* Tests SimpleTest error and exception collector.
*/
class CommonSimpleTestErrorCollectorTestCase extends DrupalWebTestCase {
/**
* Errors triggered during the test.
*
* Errors are intercepted by the overriden implementation
* of DrupalWebTestCase::error below.
*
* @var Array
*/
protected $collectedErrors = array();
public static function getInfo() {
return array(
'name' => 'SimpleTest error collector',
'description' => 'Performs tests on the Simpletest error and exception collector.',
'group' => 'Common',
);
}
function setUp() {
parent::setUp('system_test', 'error_test');
}
/**
* Test that simpletest collects errors from the tested site.
*/
function testErrorCollect() {
$this->collectedErrors = array();
$this->drupalGet('error-test/generate-warnings-with-report');
$this->assertEqual(count($this->collectedErrors), 3, t('Three errors were collected'));
if (count($this->collectedErrors) == 3) {
$this->assertError($this->collectedErrors[0], 'Notice', 'error_test_generate_warnings()', 'error_test.module', 'Undefined variable: bananas');
$this->assertError($this->collectedErrors[1], 'Warning', 'error_test_generate_warnings()', 'error_test.module', 'Division by zero');
$this->assertError($this->collectedErrors[2], 'User warning', 'error_test_generate_warnings()', 'error_test.module', 'Drupal is awesome');
}
else {
// Give back the errors to the log report.
foreach ($this->collectedErrors as $error) {
parent::error($error['message'], $error['group'], $error['caller']);
}
}
}
/**
* Error handler that collects errors in an array.
*
* This test class is trying to verify that simpletest correctly sees errors
* and warnings. However, it can't generate errors and warnings that
* propagate up to the testing framework itself, or these tests would always
* fail. So, this special copy of error() doesn't propagate the errors up
* the class hierarchy. It just stuffs them into a protected collectedErrors
* array for various assertions to inspect.
*/
protected function error($message = '', $group = 'Other', array $caller = NULL) {
// Due to a WTF elsewhere, simpletest treats debug() and verbose()
// messages as if they were an 'error'. But, we don't want to collect
// those here. This function just wants to collect the real errors (PHP
// notices, PHP fatal errors, etc.), and let all the 'errors' from the
// 'User notice' group bubble up to the parent classes to be handled (and
// eventually displayed) as normal.
if ($group == 'User notice') {
parent::error($message, $group, $caller);
}
// Everything else should be collected but not propagated.
else {
$this->collectedErrors[] = array(
'message' => $message,
'group' => $group,
'caller' => $caller
);
}
}
/**
* Assert that a collected error matches what we are expecting.
*/
function assertError($error, $group, $function, $file, $message = NULL) {
$this->assertEqual($error['group'], $group, t("Group was %group", array('%group' => $group)));
$this->assertEqual($error['caller']['function'], $function, t("Function was %function", array('%function' => $function)));
$this->assertEqual(drupal_basename($error['caller']['file']), $file, t("File was %file", array('%file' => $file)));
if (isset($message)) {
$this->assertEqual($error['message'], $message, t("Message was %message", array('%message' => $message)));
}
}
}
/**
* Tests the drupal_parse_info_file() API function.
*/
class CommonDrupalParseInfoFileTestCase extends DrupalUnitTestCase {
public static function getInfo() {
return array(
'name' => 'Parsing .info files',
'description' => 'Tests the drupal_parse_info_file() API function.',
'group' => 'Common',
);
}
/**
* Parse an example .info file an verify the results.
*/
function testParseInfoFile() {
$info_values = drupal_parse_info_file(drupal_get_path('module', 'simpletest') . '/tests/common_test_info.txt');
$this->assertEqual($info_values['simple_string'], 'A simple string', t('Simple string value was parsed correctly.'), t('System'));
$this->assertEqual($info_values['simple_constant'], WATCHDOG_INFO, t('Constant value was parsed correctly.'), t('System'));
$this->assertEqual($info_values['double_colon'], 'dummyClassName::', t('Value containing double-colon was parsed correctly.'), t('System'));
}
}
/**
* Tests scanning system directories in drupal_system_listing().
*/
class CommonDrupalSystemListingTestCase extends DrupalWebTestCase {
/**
* Use the testing profile; this is needed for testDirectoryPrecedence().
*/
protected $profile = 'testing';
public static function getInfo() {
return array(
'name' => 'Drupal system listing',
'description' => 'Tests scanning system directories in drupal_system_listing().',
'group' => 'Common',
);
}
/**
* Test that files in different directories take precedence as expected.
*/
function testDirectoryPrecedence() {
// Define the module files we will search for, and the directory precedence
// we expect.
$expected_directories = array(
// When the copy of the module in the profile directory is incompatible
// with Drupal core, the copy in the core modules directory takes
// precedence.
'drupal_system_listing_incompatible_test' => array(
'core/modules/simpletest/tests',
'profiles/testing/modules',
),
// When both copies of the module are compatible with Drupal core, the
// copy in the profile directory takes precedence.
'drupal_system_listing_compatible_test' => array(
'profiles/testing/modules',
'core/modules/simpletest/tests',
),
);
// This test relies on two versions of the same module existing in
// different places in the filesystem. Without that, the test has no
// meaning, so assert their presence first.
foreach ($expected_directories as $module => $directories) {
foreach ($directories as $directory) {
$filename = "$directory/$module/$module.module";
$this->assertTrue(file_exists(DRUPAL_ROOT . '/' . $filename), t('@filename exists.', array('@filename' => $filename)));
}
}
// Now scan the directories and check that the files take precedence as
// expected.
$files = drupal_system_listing('/\.module$/', 'modules', 'name', 1);
foreach ($expected_directories as $module => $directories) {
$expected_directory = array_shift($directories);
$expected_filename = "$expected_directory/$module/$module.module";
$this->assertEqual($files[$module]->uri, $expected_filename, t('Module @module was found at @filename.', array('@module' => $module, '@filename' => $expected_filename)));
}
}
}
/**
* Tests the format_date() function.
*/
class CommonFormatDateTestCase extends DrupalWebTestCase {
/**
* Arbitrary langcode for a custom language.
*/
const LANGCODE = 'xx';
public static function getInfo() {
return array(
'name' => 'Format date',
'description' => 'Test the format_date() function.',
'group' => 'Common',
);
}
function setUp() {
parent::setUp('locale');
variable_set('configurable_timezones', 1);
variable_set('date_format_long', 'l, j. F Y - G:i');
variable_set('date_format_medium', 'j. F Y - G:i');
variable_set('date_format_short', 'Y M j - g:ia');
variable_set('locale_custom_strings_' . self::LANGCODE, array(
'' => array('Sunday' => 'domingo'),
'Long month name' => array('March' => 'marzo'),
));
$this->refreshVariables();
}
/**
* Test admin-defined formats in format_date().
*/
function testAdminDefinedFormatDate() {
// Create an admin user.
$this->admin_user = $this->drupalCreateUser(array('administer site configuration'));
$this->drupalLogin($this->admin_user);
// Add new date format.
$admin_date_format = 'j M y';
$edit = array('date_format' => $admin_date_format);
$this->drupalPost('admin/config/regional/date-time/formats/add', $edit, t('Add format'));
// Add new date type.
$edit = array(
'date_type' => 'Example Style',
'machine_name' => 'example_style',
'date_format' => $admin_date_format,
);
$this->drupalPost('admin/config/regional/date-time/types/add', $edit, t('Add date type'));
$timestamp = strtotime('2007-03-10T00:00:00+00:00');
$this->assertIdentical(format_date($timestamp, 'example_style', '', 'America/Los_Angeles'), '9 Mar 07', t('Test format_date() using an admin-defined date type.'));
$this->assertIdentical(format_date($timestamp, 'undefined_style'), format_date($timestamp, 'medium'), t('Test format_date() defaulting to medium when $type not found.'));
}
/**
* Tests for the format_date() function.
*/
function testFormatDate() {
global $user, $language;
$timestamp = strtotime('2007-03-26T00:00:00+00:00');
$this->assertIdentical(format_date($timestamp, 'custom', 'l, d-M-y H:i:s T', 'America/Los_Angeles', 'en'), 'Sunday, 25-Mar-07 17:00:00 PDT', t('Test all parameters.'));
$this->assertIdentical(format_date($timestamp, 'custom', 'l, d-M-y H:i:s T', 'America/Los_Angeles', self::LANGCODE), 'domingo, 25-Mar-07 17:00:00 PDT', t('Test translated format.'));
$this->assertIdentical(format_date($timestamp, 'custom', '\\l, d-M-y H:i:s T', 'America/Los_Angeles', self::LANGCODE), 'l, 25-Mar-07 17:00:00 PDT', t('Test an escaped format string.'));
$this->assertIdentical(format_date($timestamp, 'custom', '\\\\l, d-M-y H:i:s T', 'America/Los_Angeles', self::LANGCODE), '\\domingo, 25-Mar-07 17:00:00 PDT', t('Test format containing backslash character.'));
$this->assertIdentical(format_date($timestamp, 'custom', '\\\\\\l, d-M-y H:i:s T', 'America/Los_Angeles', self::LANGCODE), '\\l, 25-Mar-07 17:00:00 PDT', t('Test format containing backslash followed by escaped format string.'));
$this->assertIdentical(format_date($timestamp, 'custom', 'l, d-M-y H:i:s T', 'Europe/London', 'en'), 'Monday, 26-Mar-07 01:00:00 BST', t('Test a different time zone.'));
// Create an admin user and add Spanish language.
$admin_user = $this->drupalCreateUser(array('administer languages'));
$this->drupalLogin($admin_user);
$edit = array(
'predefined_langcode' => 'custom',
'langcode' => self::LANGCODE,
'name' => self::LANGCODE,
'direction' => LANGUAGE_LTR,
);
$this->drupalPost('admin/config/regional/language/add', $edit, t('Add custom language'));
// Set language prefix.
$edit = array('prefix[' . self::LANGCODE . ']' => self::LANGCODE);
$this->drupalPost('admin/config/regional/language/configure/url', $edit, t('Save configuration'));
// Create a test user to carry out the tests.
$test_user = $this->drupalCreateUser();
$this->drupalLogin($test_user);
$edit = array('language' => self::LANGCODE, 'mail' => $test_user->mail, 'timezone' => 'America/Los_Angeles');
$this->drupalPost('user/' . $test_user->uid . '/edit', $edit, t('Save'));
// Disable session saving as we are about to modify the global $user.
drupal_save_session(FALSE);
// Save the original user and language and then replace it with the test user and language.
$real_user = $user;
$user = user_load($test_user->uid, TRUE);
$real_language = $language->langcode;
$language->langcode = $user->language;
// Simulate a Drupal bootstrap with the logged-in user.
date_default_timezone_set(drupal_get_user_timezone());
$this->assertIdentical(format_date($timestamp, 'custom', 'l, d-M-y H:i:s T', 'America/Los_Angeles', 'en'), 'Sunday, 25-Mar-07 17:00:00 PDT', t('Test a different language.'));
$this->assertIdentical(format_date($timestamp, 'custom', 'l, d-M-y H:i:s T', 'Europe/London'), 'Monday, 26-Mar-07 01:00:00 BST', t('Test a different time zone.'));
$this->assertIdentical(format_date($timestamp, 'custom', 'l, d-M-y H:i:s T'), 'domingo, 25-Mar-07 17:00:00 PDT', t('Test custom date format.'));
$this->assertIdentical(format_date($timestamp, 'long'), 'domingo, 25. marzo 2007 - 17:00', t('Test long date format.'));
$this->assertIdentical(format_date($timestamp, 'medium'), '25. marzo 2007 - 17:00', t('Test medium date format.'));
$this->assertIdentical(format_date($timestamp, 'short'), '2007 Mar 25 - 5:00pm', t('Test short date format.'));
$this->assertIdentical(format_date($timestamp), '25. marzo 2007 - 17:00', t('Test default date format.'));
// Test HTML time element formats.
$this->assertIdentical(format_date($timestamp, 'html_datetime'), '2007-03-25T17:00:00-0700', t('Test html_datetime date format.'));
$this->assertIdentical(format_date($timestamp, 'html_date'), '2007-03-25', t('Test html_date date format.'));
$this->assertIdentical(format_date($timestamp, 'html_time'), '17:00:00', t('Test html_time date format.'));
$this->assertIdentical(format_date($timestamp, 'html_yearless_date'), '03-25', t('Test html_yearless_date date format.'));
$this->assertIdentical(format_date($timestamp, 'html_week'), '2007-W12', t('Test html_week date format.'));
$this->assertIdentical(format_date($timestamp, 'html_month'), '2007-03', t('Test html_month date format.'));
$this->assertIdentical(format_date($timestamp, 'html_year'), '2007', t('Test html_year date format.'));
// Restore the original user and language, and enable session saving.
$user = $real_user;
$language->langcode = $real_language;
// Restore default time zone.
date_default_timezone_set(drupal_get_user_timezone());
drupal_save_session(TRUE);
}
}
/**
* Tests the drupal_attributes() functionality.
*/
class CommonDrupalAttributesUnitTestCase extends DrupalUnitTestCase {
public static function getInfo() {
return array(
'name' => 'HTML Attributes',
'description' => 'Tests the drupal_attributes() functionality.',
'group' => 'Common',
);
}
/**
* Tests that drupal_html_class() cleans the class name properly.
*/
function testDrupalAttributes() {
// Verify that special characters are HTML encoded.
$this->assertIdentical(drupal_attributes(array('title' => '&"\'<>')), ' title="&"'<>"', t('HTML encode attribute values.'));
// Verify multi-value attributes are concatenated with spaces.
$attributes = array('class' => array('first', 'last'));
$this->assertIdentical(drupal_attributes(array('class' => array('first', 'last'))), ' class="first last"', t('Concatenate multi-value attributes.'));
// Verify empty attribute values are rendered.
$this->assertIdentical(drupal_attributes(array('alt' => '')), ' alt=""', t('Empty attribute value #1.'));
$this->assertIdentical(drupal_attributes(array('alt' => NULL)), ' alt=""', t('Empty attribute value #2.'));
// Verify multiple attributes are rendered.
$attributes = array(
'id' => 'id-test',
'class' => array('first', 'last'),
'alt' => 'Alternate',
);
$this->assertIdentical(drupal_attributes($attributes), ' id="id-test" class="first last" alt="Alternate"', t('Multiple attributes.'));
// Verify empty attributes array is rendered.
$this->assertIdentical(drupal_attributes(array()), '', t('Empty attributes array.'));
}
}
/**
* Tests the various drupal_array_* helper functions.
*/
class CommonDrupalArrayUnitTest extends DrupalUnitTestCase {
/**
* Form array to check.
*/
protected $form;
/**
* Array of parents for the nested element.
*/
protected $parents;
public static function getInfo() {
return array(
'name' => 'drupal_array_*() tests',
'description' => 'Tests the various drupal_array_* helper functions.',
'group' => 'System',
);
}
function setUp() {
parent::setUp();
// Create a form structure with a nested element.
$this->form['fieldset']['element'] = array(
'#value' => 'Nested element',
);
// Set up parent array.
$this->parents = array('fieldset', 'element');
}
/**
* Tests getting nested array values.
*/
function testGet() {
// Verify getting a value of a nested element.
$value = drupal_array_get_nested_value($this->form, $this->parents);
$this->assertEqual($value['#value'], 'Nested element', 'Nested element value found.');
// Verify changing a value of a nested element by reference.
$value = &drupal_array_get_nested_value($this->form, $this->parents);
$value['#value'] = 'New value';
$value = drupal_array_get_nested_value($this->form, $this->parents);
$this->assertEqual($value['#value'], 'New value', 'Nested element value was changed by reference.');
$this->assertEqual($this->form['fieldset']['element']['#value'], 'New value', 'Nested element value was changed by reference.');
// Verify that an existing key is reported back.
$key_exists = NULL;
drupal_array_get_nested_value($this->form, $this->parents, $key_exists);
$this->assertIdentical($key_exists, TRUE, 'Existing key found.');
// Verify that a non-existing key is reported back and throws no errors.
$key_exists = NULL;
$parents = $this->parents;
$parents[] = 'foo';
drupal_array_get_nested_value($this->form, $parents, $key_exists);
$this->assertIdentical($key_exists, FALSE, 'Non-existing key not found.');
}
/**
* Tests setting nested array values.
*/
function testSet() {
$new_value = array(
'#value' => 'New value',
'#required' => TRUE,
);
// Verify setting the value of a nested element.
drupal_array_set_nested_value($this->form, $this->parents, $new_value);
$this->assertEqual($this->form['fieldset']['element']['#value'], 'New value', 'Changed nested element value found.');
$this->assertIdentical($this->form['fieldset']['element']['#required'], TRUE, 'New nested element value found.');
}
/**
* Tests unsetting nested array values.
*/
function testUnset() {
// Verify unsetting a non-existing nested element throws no errors and the
// non-existing key is properly reported.
$key_existed = NULL;
$parents = $this->parents;
$parents[] = 'foo';
drupal_array_unset_nested_value($this->form, $parents, $key_existed);
$this->assertTrue(isset($this->form['fieldset']['element']['#value']), 'Outermost nested element key still exists.');
$this->assertIdentical($key_existed, FALSE, 'Non-existing key not found.');
// Verify unsetting a nested element.
$key_existed = NULL;
drupal_array_unset_nested_value($this->form, $this->parents, $key_existed);
$this->assertFalse(isset($this->form['fieldset']['element']), 'Removed nested element not found.');
$this->assertIdentical($key_existed, TRUE, 'Existing key was found.');
}
/**
* Tests existence of array key.
*/
function testKeyExists() {
// Verify that existing key is found.
$this->assertIdentical(drupal_array_nested_key_exists($this->form, $this->parents), TRUE, 'Nested key found.');
// Verify that non-existing keys are not found.
$parents = $this->parents;
$parents[] = 'foo';
$this->assertIdentical(drupal_array_nested_key_exists($this->form, $parents), FALSE, 'Non-existing nested key not found.');
}
}
/**
* Tests the drupal_json_encode() and drupal_json_decode() functions.
*/
class CommonJSONUnitTestCase extends DrupalUnitTestCase {
public static function getInfo() {
return array(
'name' => 'JSON',
'description' => 'Tests the drupal_json_encode() and drupal_json_decode() functions to convert PHP variables to JSON strings and back.',
'group' => 'Common',
);
}
/**
* Tests converting PHP variables to JSON strings and back.
*/
function testJSON() {
// Setup a string with the full ASCII table.
// @todo: Add tests for non-ASCII characters and Unicode.
$str = '';
for ($i=0; $i < 128; $i++) {
$str .= chr($i);
}
// Characters that must be escaped.
// We check for unescaped " separately.
$html_unsafe = array('<', '>', '\'', '&');
// The following are the encoded forms of: < > ' & "
$html_unsafe_escaped = array('\u003C', '\u003E', '\u0027', '\u0026', '\u0022');
// Verify there aren't character encoding problems with the source string.
$this->assertIdentical(strlen($str), 128, t('A string with the full ASCII table has the correct length.'));
foreach ($html_unsafe as $char) {
$this->assertTrue(strpos($str, $char) > 0, t('A string with the full ASCII table includes @s.', array('@s' => $char)));
}
// Verify that JSON encoding produces a string with all of the characters.
$json = drupal_json_encode($str);
$this->assertTrue(strlen($json) > strlen($str), t('A JSON encoded string is larger than the source string.'));
// The first and last characters should be ", and no others.
$this->assertTrue($json[0] == '"', t('A JSON encoded string begins with ".'));
$this->assertTrue($json[strlen($json) - 1] == '"', t('A JSON encoded string ends with ".'));
$this->assertTrue(substr_count($json, '"') == 2, t('A JSON encoded string contains exactly two ".'));
// Verify that encoding/decoding is reversible.
$json_decoded = drupal_json_decode($json);
$this->assertIdentical($str, $json_decoded, t('Encoding a string to JSON and decoding back results in the original string.'));
// Verify reversibility for structured data. Also verify that necessary
// characters are escaped.
$source = array(TRUE, FALSE, 0, 1, '0', '1', $str, array('key1' => $str, 'key2' => array('nested' => TRUE)));
$json = drupal_json_encode($source);
foreach ($html_unsafe as $char) {
$this->assertTrue(strpos($json, $char) === FALSE, t('A JSON encoded string does not contain @s.', array('@s' => $char)));
}
// Verify that JSON encoding escapes the HTML unsafe characters
foreach ($html_unsafe_escaped as $char) {
$this->assertTrue(strpos($json, $char) > 0, t('A JSON encoded string contains @s.', array('@s' => $char)));
}
$json_decoded = drupal_json_decode($json);
$this->assertNotIdentical($source, $json, t('An array encoded in JSON is not identical to the source.'));
$this->assertIdentical($source, $json_decoded, t('Encoding structured data to JSON and decoding back results in the original data.'));
}
}
/**
* Basic tests for drupal_add_feed().
*/
class CommonDrupalAddFeedTestCase extends DrupalWebTestCase {
public static function getInfo() {
return array(
'name' => 'drupal_add_feed() tests',
'description' => 'Make sure that drupal_add_feed() works correctly with various constructs.',
'group' => 'Common',
);
}
/**
* Test drupal_add_feed() with paths, URLs, and titles.
*/
function testBasicFeedAddNoTitle() {
$path = $this->randomName(12);
$external_url = 'http://' . $this->randomName(12) . '/' . $this->randomName(12);
$fully_qualified_local_url = url($this->randomName(12), array('absolute' => TRUE));
$path_for_title = $this->randomName(12);
$external_for_title = 'http://' . $this->randomName(12) . '/' . $this->randomName(12);
$fully_qualified_for_title = url($this->randomName(12), array('absolute' => TRUE));
// Possible permutations of drupal_add_feed() to test.
// - 'input_url': the path passed to drupal_add_feed(),
// - 'output_url': the expected URL to be found in the header.
// - 'title' == the title of the feed as passed into drupal_add_feed().
$urls = array(
'path without title' => array(
'input_url' => $path,
'output_url' => url($path, array('absolute' => TRUE)),
'title' => '',
),
'external url without title' => array(
'input_url' => $external_url,
'output_url' => $external_url,
'title' => '',
),
'local url without title' => array(
'input_url' => $fully_qualified_local_url,
'output_url' => $fully_qualified_local_url,
'title' => '',
),
'path with title' => array(
'input_url' => $path_for_title,
'output_url' => url($path_for_title, array('absolute' => TRUE)),
'title' => $this->randomName(12),
),
'external url with title' => array(
'input_url' => $external_for_title,
'output_url' => $external_for_title,
'title' => $this->randomName(12),
),
'local url with title' => array(
'input_url' => $fully_qualified_for_title,
'output_url' => $fully_qualified_for_title,
'title' => $this->randomName(12),
),
);
foreach ($urls as $description => $feed_info) {
drupal_add_feed($feed_info['input_url'], $feed_info['title']);
}
$this->drupalSetContent(drupal_get_html_head());
foreach ($urls as $description => $feed_info) {
$this->assertPattern($this->urlToRSSLinkPattern($feed_info['output_url'], $feed_info['title']), t('Found correct feed header for %description', array('%description' => $description)));
}
}
/**
* Create a pattern representing the RSS feed in the page.
*/
function urlToRSSLinkPattern($url, $title = '') {
// Escape any regular expression characters in the url ('?' is the worst).
$url = preg_replace('/([+?.*])/', '[$0]', $url);
$generated_pattern = '%%';
return $generated_pattern;
}
}