Newer
Older
<?php
// $Id$
/**
Dries Buytaert
committed
* Base class for Drupal tests.
*
* Do not extend this class, use one of the subclasses in this file.
*/
Dries Buytaert
committed
abstract class DrupalTestCase {
/**
* The test run ID.
*
* @var string
*/
protected $testId;
/**
* The original database prefix, before it was changed for testing purposes.
*
* @var string
*/
protected $originalPrefix = NULL;
/**
* The original file directory, before it was changed for testing purposes.
*
* @var string
*/
protected $originalFileDirectory = NULL;
Angie Byron
committed
/**
Dries Buytaert
committed
* Time limit for the test.
Angie Byron
committed
*/
protected $timeLimit = 500;
Angie Byron
committed
/**
* Current results of this test case.
*
* @var Array
*/
public $results = array(
'#pass' => 0,
'#fail' => 0,
'#exception' => 0,
Angie Byron
committed
'#debug' => 0,
);
/**
* Assertions thrown in that test case.
*
* @var Array
*/
protected $assertions = array();
Dries Buytaert
committed
Dries Buytaert
committed
* This class is skipped when looking for the source of an assertion.
*
* When displaying which function an assert comes from, it's not too useful
* to see "drupalWebTestCase->drupalLogin()', we would like to see the test
* that called it. So we need to skip the classes defining these helper
* methods.
Angie Byron
committed
*/
Dries Buytaert
committed
protected $skipClasses = array(__CLASS__ => TRUE);
Dries Buytaert
committed
/**
* Constructor for DrupalWebTestCase.
*
* @param $test_id
Dries Buytaert
committed
* Tests with the same id are reported together.
*/
public function __construct($test_id = NULL) {
$this->testId = $test_id;
Dries Buytaert
committed
}
/**
* Internal helper: stores the assert.
Dries Buytaert
committed
*
* @param $status
* Can be 'pass', 'fail', 'exception'.
* TRUE is a synonym for 'pass', FALSE for 'fail'.
Dries Buytaert
committed
* @param $message
* The message string.
* @param $group
Dries Buytaert
committed
* Which group this assert belongs to.
* @param $caller
Dries Buytaert
committed
* By default, the assert comes from a function whose name starts with
Dries Buytaert
committed
* 'test'. Instead, you can specify where this assert originates from
* by passing in an associative array as $caller. Key 'file' is
Dries Buytaert
committed
* the name of the source file, 'line' is the line number and 'function'
* is the caller function itself.
*/
Dries Buytaert
committed
protected function assert($status, $message = '', $group = 'Other', array $caller = NULL) {
Dries Buytaert
committed
global $db_prefix;
// Convert boolean status to string status.
Dries Buytaert
committed
if (is_bool($status)) {
$status = $status ? 'pass' : 'fail';
}
// Increment summary result counter.
$this->results['#' . $status]++;
// Get the function information about the call to the assertion method.
if (!$caller) {
$caller = $this->getAssertionCall();
Dries Buytaert
committed
}
// Switch to non-testing database to store results in.
Dries Buytaert
committed
$current_db_prefix = $db_prefix;
$db_prefix = $this->originalPrefix;
// Creation assertion array that can be displayed while tests are running.
$this->assertions[] = $assertion = array(
'test_id' => $this->testId,
'test_class' => get_class($this),
'status' => $status,
'message' => $message,
'message_group' => $group,
'function' => $caller['function'],
'line' => $caller['line'],
'file' => $caller['file'],
);
// Store assertion for display after the test has completed.
Dries Buytaert
committed
db_insert('simpletest')
->fields($assertion)
->execute();
// Return to testing prefix.
Dries Buytaert
committed
$db_prefix = $current_db_prefix;
Angie Byron
committed
// We do not use a ternary operator here to allow a breakpoint on
// test failure.
if ($status == 'pass') {
return TRUE;
}
else {
return FALSE;
}
Dries Buytaert
committed
}
Dries Buytaert
committed
/**
Dries Buytaert
committed
* Store an assertion from outside the testing context.
*
* This is useful for inserting assertions that can only be recorded after
* the test case has been destroyed, such as PHP fatal errors. The caller
* information is not automatically gathered since the caller is most likely
* inserting the assertion on behalf of other code. In all other respects
* the method behaves just like DrupalTestCase::assert() in terms of storing
* the assertion.
Dries Buytaert
committed
*
* @return
* Message ID of the stored assertion.
*
Dries Buytaert
committed
* @see DrupalTestCase::assert()
* @see DrupalTestCase::deleteAssert()
Dries Buytaert
committed
*/
Dries Buytaert
committed
public static function insertAssert($test_id, $test_class, $status, $message = '', $group = 'Other', array $caller = array()) {
Dries Buytaert
committed
// Convert boolean status to string status.
if (is_bool($status)) {
$status = $status ? 'pass' : 'fail';
}
$caller += array(
Dries Buytaert
committed
'function' => t('Unknown'),
'line' => 0,
'file' => t('Unknown'),
Dries Buytaert
committed
);
$assertion = array(
'test_id' => $test_id,
'test_class' => $test_class,
'status' => $status,
'message' => $message,
'message_group' => $group,
'function' => $caller['function'],
'line' => $caller['line'],
'file' => $caller['file'],
);
return db_insert('simpletest')
Dries Buytaert
committed
->fields($assertion)
->execute();
}
/**
* Delete an assertion record by message ID.
Angie Byron
committed
*
* @param $message_id
* Message ID of the assertion to delete.
* @return
* TRUE if the assertion was deleted, FALSE otherwise.
Angie Byron
committed
*
* @see DrupalTestCase::insertAssert()
*/
public static function deleteAssert($message_id) {
return (bool) db_delete('simpletest')
->condition('message_id', $message_id)
->execute();
}
/**
* Cycles through backtrace until the first non-assertion method is found.
*
* @return
* Array representing the true caller.
*/
protected function getAssertionCall() {
$backtrace = debug_backtrace();
// The first element is the call. The second element is the caller.
Dries Buytaert
committed
// We skip calls that occurred in one of the methods of our base classes
// or in an assertion function.
Dries Buytaert
committed
while (($caller = $backtrace[1]) &&
((isset($caller['class']) && isset($this->skipClasses[$caller['class']])) ||
substr($caller['function'], 0, 6) == 'assert')) {
// We remove that call.
array_shift($backtrace);
}
return _drupal_get_last_caller($backtrace);
}
Dries Buytaert
committed
/**
* Check to see if a value is not false (not an empty string, 0, NULL, or FALSE).
*
* @param $value
* The value on which the assertion is to be done.
* @param $message
* The message to display along with the assertion.
* @param $group
* The type of assertion - examples are "Browser", "PHP".
* @return
* TRUE if the assertion succeeded, FALSE otherwise.
Dries Buytaert
committed
*/
protected function assertTrue($value, $message = '', $group = 'Other') {
return $this->assert((bool) $value, $message ? $message : t('Value @value is TRUE.', array('@value' => var_export($value, TRUE))), $group);
Dries Buytaert
committed
}
/**
* Check to see if a value is false (an empty string, 0, NULL, or FALSE).
*
* @param $value
* The value on which the assertion is to be done.
* @param $message
* The message to display along with the assertion.
* @param $group
* The type of assertion - examples are "Browser", "PHP".
* @return
* TRUE if the assertion succeeded, FALSE otherwise.
Dries Buytaert
committed
*/
protected function assertFalse($value, $message = '', $group = 'Other') {
return $this->assert(!$value, $message ? $message : t('Value @value is FALSE.', array('@value' => var_export($value, TRUE))), $group);
Dries Buytaert
committed
}
/**
* Check to see if a value is NULL.
*
* @param $value
* The value on which the assertion is to be done.
* @param $message
* The message to display along with the assertion.
* @param $group
* The type of assertion - examples are "Browser", "PHP".
* @return
* TRUE if the assertion succeeded, FALSE otherwise.
Dries Buytaert
committed
*/
protected function assertNull($value, $message = '', $group = 'Other') {
return $this->assert(!isset($value), $message ? $message : t('Value @value is NULL.', array('@value' => var_export($value, TRUE))), $group);
Dries Buytaert
committed
}
/**
* Check to see if a value is not NULL.
*
* @param $value
* The value on which the assertion is to be done.
* @param $message
* The message to display along with the assertion.
* @param $group
* The type of assertion - examples are "Browser", "PHP".
* @return
* TRUE if the assertion succeeded, FALSE otherwise.
Dries Buytaert
committed
*/
protected function assertNotNull($value, $message = '', $group = 'Other') {
return $this->assert(isset($value), $message ? $message : t('Value @value is not NULL.', array('@value' => var_export($value, TRUE))), $group);
Dries Buytaert
committed
}
/**
* Check to see if two values are equal.
*
* @param $first
* The first value to check.
* @param $second
* The second value to check.
* @param $message
* The message to display along with the assertion.
* @param $group
* The type of assertion - examples are "Browser", "PHP".
* @return
* TRUE if the assertion succeeded, FALSE otherwise.
Dries Buytaert
committed
*/
protected function assertEqual($first, $second, $message = '', $group = 'Other') {
return $this->assert($first == $second, $message ? $message : t('Value @first is equal to value @second.', array('@first' => var_export($first, TRUE), '@second' => var_export($second, TRUE))), $group);
Dries Buytaert
committed
}
/**
* Check to see if two values are not equal.
*
* @param $first
* The first value to check.
* @param $second
* The second value to check.
* @param $message
* The message to display along with the assertion.
* @param $group
* The type of assertion - examples are "Browser", "PHP".
* @return
* TRUE if the assertion succeeded, FALSE otherwise.
Dries Buytaert
committed
*/
protected function assertNotEqual($first, $second, $message = '', $group = 'Other') {
return $this->assert($first != $second, $message ? $message : t('Value @first is not equal to value @second.', array('@first' => var_export($first, TRUE), '@second' => var_export($second, TRUE))), $group);
Dries Buytaert
committed
}
/**
* Check to see if two values are identical.
*
* @param $first
* The first value to check.
* @param $second
* The second value to check.
* @param $message
* The message to display along with the assertion.
* @param $group
* The type of assertion - examples are "Browser", "PHP".
* @return
* TRUE if the assertion succeeded, FALSE otherwise.
Dries Buytaert
committed
*/
protected function assertIdentical($first, $second, $message = '', $group = 'Other') {
return $this->assert($first === $second, $message ? $message : t('Value @first is identical to value @second.', array('@first' => var_export($first, TRUE), '@second' => var_export($second, TRUE))), $group);
Dries Buytaert
committed
}
/**
* Check to see if two values are not identical.
*
* @param $first
* The first value to check.
* @param $second
* The second value to check.
* @param $message
* The message to display along with the assertion.
* @param $group
* The type of assertion - examples are "Browser", "PHP".
* @return
* TRUE if the assertion succeeded, FALSE otherwise.
Dries Buytaert
committed
*/
protected function assertNotIdentical($first, $second, $message = '', $group = 'Other') {
return $this->assert($first !== $second, $message ? $message : t('Value @first is not identical to value @second.', array('@first' => var_export($first, TRUE), '@second' => var_export($second, TRUE))), $group);
Dries Buytaert
committed
}
/**
* Fire an assertion that is always positive.
*
* @param $message
* The message to display along with the assertion.
* @param $group
* The type of assertion - examples are "Browser", "PHP".
* @return
* TRUE.
*/
protected function pass($message = NULL, $group = 'Other') {
return $this->assert(TRUE, $message, $group);
Dries Buytaert
committed
}
/**
Dries Buytaert
committed
* Fire an assertion that is always negative.
*
Dries Buytaert
committed
* @param $message
* The message to display along with the assertion.
* @param $group
* The type of assertion - examples are "Browser", "PHP".
* @return
* FALSE.
*/
protected function fail($message = NULL, $group = 'Other') {
return $this->assert(FALSE, $message, $group);
Dries Buytaert
committed
}
/**
* Fire an error assertion.
*
* @param $message
* The message to display along with the assertion.
* @param $group
* The type of assertion - examples are "Browser", "PHP".
* @param $caller
Dries Buytaert
committed
* The caller of the error.
* @return
* FALSE.
Dries Buytaert
committed
*/
Dries Buytaert
committed
protected function error($message = '', $group = 'Other', array $caller = NULL) {
Angie Byron
committed
if ($group == 'User notice') {
// Since 'User notice' is set by trigger_error() which is used for debug
// set the message to a status of 'debug'.
return $this->assert('debug', $message, 'Debug', $caller);
}
return $this->assert('exception', $message, $group, $caller);
Dries Buytaert
committed
}
/**
* Run all tests in this class.
*/
public function run() {
// Initialize verbose debugging.
Angie Byron
committed
simpletest_verbose(NULL, file_directory_path(), get_class($this));
Angie Byron
committed
// HTTP auth settings (<username>:<password>) for the simpletest browser
// when sending requests to the test site.
Dries Buytaert
committed
$this->httpauth_method = variable_get('simpletest_httpauth_method', CURLAUTH_BASIC);
$username = variable_get('simpletest_httpauth_username', NULL);
$password = variable_get('simpletest_httpauth_password', NULL);
Dries Buytaert
committed
if ($username && $password) {
$this->httpauth_credentials = $username . ':' . $password;
}
Angie Byron
committed
Dries Buytaert
committed
set_error_handler(array($this, 'errorHandler'));
$class = get_class($this);
Dries Buytaert
committed
// Iterate through all the methods in this class.
foreach (get_class_methods($class) as $method) {
Dries Buytaert
committed
// If the current method starts with "test", run it - it's a test.
if (strtolower(substr($method, 0, 4)) == 'test') {
// Insert a fail record. This will be deleted on completion to ensure
// that testing completed.
$method_info = new ReflectionMethod($class, $method);
$caller = array(
'file' => $method_info->getFileName(),
'line' => $method_info->getStartLine(),
'function' => $class . '->' . $method . '()',
);
$completion_check_id = DrupalTestCase::insertAssert($this->testId, $class, FALSE, t('The test did not complete due to a fatal error.'), 'Completion check', $caller);
$this->setUp();
try {
$this->$method();
// Finish up.
}
catch (Exception $e) {
$this->exceptionHandler($e);
}
$this->tearDown();
// Remove the completion check record.
DrupalTestCase::deleteAssert($completion_check_id);
}
}
// Clear out the error messages and restore error handler.
drupal_get_messages();
Dries Buytaert
committed
restore_error_handler();
}
/**
* Handle errors during test runs.
Dries Buytaert
committed
*
* Because this is registered in set_error_handler(), it has to be public.
Dries Buytaert
committed
* @see set_error_handler
*/
public function errorHandler($severity, $message, $file = NULL, $line = NULL) {
Angie Byron
committed
if ($severity & error_reporting()) {
$error_map = array(
E_STRICT => 'Run-time notice',
E_WARNING => 'Warning',
E_NOTICE => 'Notice',
E_CORE_ERROR => 'Core error',
E_CORE_WARNING => 'Core warning',
E_USER_ERROR => 'User error',
E_USER_WARNING => 'User warning',
E_USER_NOTICE => 'User notice',
E_RECOVERABLE_ERROR => 'Recoverable error',
);
$backtrace = debug_backtrace();
$this->error($message, $error_map[$severity], _drupal_get_last_caller($backtrace));
}
Dries Buytaert
committed
return TRUE;
}
/**
* Handle exceptions.
*
* @see set_exception_handler
*/
protected function exceptionHandler($exception) {
$backtrace = $exception->getTrace();
// Push on top of the backtrace the call that generated the exception.
array_unshift($backtrace, array(
'line' => $exception->getLine(),
'file' => $exception->getFile(),
));
Dries Buytaert
committed
require_once DRUPAL_ROOT . '/includes/errors.inc';
$this->error(t('%type: %message in %function (line %line of %file).', _drupal_decode_exception($exception)), 'Uncaught exception', _drupal_get_last_caller($backtrace));
}
Dries Buytaert
committed
/**
* Generates a random string of ASCII characters of codes 32 to 126.
*
* The generated string includes alpha-numeric characters and common misc
* characters. Use this method when testing general input where the content
* is not restricted.
*
* @param $length
Dries Buytaert
committed
* Length of random string to generate.
Dries Buytaert
committed
* @return
* Randomly generated string.
*/
public static function randomString($length = 8) {
$str = '';
for ($i = 0; $i < $length; $i++) {
$str .= chr(mt_rand(32, 126));
}
Dries Buytaert
committed
return $str;
Dries Buytaert
committed
}
/**
* Generates a random string containing letters and numbers.
*
Dries Buytaert
committed
* The string will always start with a letter. The letters may be upper or
* lower case. This method is better for restricted inputs that do not
* accept certain characters. For example, when testing input fields that
* require machine readable values (i.e. without spaces and non-standard
* characters) this method is best.
Dries Buytaert
committed
*
* @param $length
Dries Buytaert
committed
* Length of random string to generate.
Dries Buytaert
committed
* @return
* Randomly generated string.
*/
public static function randomName($length = 8) {
$values = array_merge(range(65, 90), range(97, 122), range(48, 57));
$max = count($values) - 1;
Dries Buytaert
committed
$str = chr(mt_rand(97, 122));
for ($i = 1; $i < $length; $i++) {
Dries Buytaert
committed
$str .= chr($values[mt_rand(0, $max)]);
}
Dries Buytaert
committed
return $str;
Dries Buytaert
committed
}
}
/**
* Test case for Drupal unit tests.
*
* These tests can not access the database nor files. Calling any Drupal
* function that needs the database will throw exceptions. These include
* watchdog(), module_implements(), module_invoke_all() etc.
Dries Buytaert
committed
*/
class DrupalUnitTestCase extends DrupalTestCase {
/**
* Constructor for DrupalUnitTestCase.
*/
function __construct($test_id = NULL) {
parent::__construct($test_id);
$this->skipClasses[__CLASS__] = TRUE;
}
Dries Buytaert
committed
protected function setUp() {
Dries Buytaert
committed
global $db_prefix, $conf;
// Store necessary current values before switching to prefixed database.
$this->originalPrefix = $db_prefix;
$this->originalFileDirectory = file_directory_path();
Dries Buytaert
committed
spl_autoload_register('db_autoload');
Dries Buytaert
committed
// Reset all statics so that test is performed with a clean environment.
drupal_static_reset();
Dries Buytaert
committed
// Generate temporary prefixed database to ensure that tests have a clean starting point.
$db_prefix = Database::getConnection()->prefixTables('{simpletest' . mt_rand(1000, 1000000) . '}');
$conf['file_public_path'] = $this->originalFileDirectory . '/' . $db_prefix;
Dries Buytaert
committed
// If locale is enabled then t() will try to access the database and
// subsequently will fail as the database is not accessible.
$module_list = module_list();
if (isset($module_list['locale'])) {
$this->originalModuleList = $module_list;
unset($module_list['locale']);
module_list(TRUE, FALSE, FALSE, $module_list);
Dries Buytaert
committed
}
}
protected function tearDown() {
Dries Buytaert
committed
global $db_prefix, $conf;
if (preg_match('/simpletest\d+/', $db_prefix)) {
$conf['file_public_path'] = $this->originalFileDirectory;
Dries Buytaert
committed
// Return the database prefix to the original.
$db_prefix = $this->originalPrefix;
// Restore modules if necessary.
if (isset($this->originalModuleList)) {
module_list(TRUE, FALSE, FALSE, $this->originalModuleList);
Dries Buytaert
committed
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
}
}
}
}
/**
* Test case for typical Drupal tests.
*/
class DrupalWebTestCase extends DrupalTestCase {
/**
* The URL currently loaded in the internal browser.
*
* @var string
*/
protected $url;
/**
* The handle of the current cURL connection.
*
* @var resource
*/
protected $curlHandle;
/**
* The headers of the page currently loaded in the internal browser.
*
* @var Array
*/
protected $headers;
/**
* The content of the page currently loaded in the internal browser.
*
* @var string
*/
protected $content;
/**
* The content of the page currently loaded in the internal browser (plain text version).
*
* @var string
*/
protected $plainTextContent;
/**
* The parsed version of the page.
*
* @var SimpleXMLElement
*/
protected $elements = NULL;
/**
* The current user logged in using the internal browser.
*
* @var bool
*/
protected $loggedInUser = FALSE;
/**
* The current cookie file used by cURL.
*
* We do not reuse the cookies in further runs, so we do not need a file
* but we still need cookie handling, so we set the jar to NULL.
*/
protected $cookieFile = NULL;
/**
* Additional cURL options.
*
* DrupalWebTestCase itself never sets this but always obeys what is set.
*/
protected $additionalCurlOptions = array();
/**
* The original user, before it was changed to a clean uid = 1 for testing purposes.
*
* @var object
*/
protected $originalUser = NULL;
/**
* The original shutdown handlers array, before it was cleaned for testing purposes.
*
* @var array
*/
protected $originalShutdownCallbacks = array();
Dries Buytaert
committed
/**
* HTTP authentication method
*/
protected $httpauth_method = CURLAUTH_BASIC;
Dries Buytaert
committed
/**
* HTTP authentication credentials (<username>:<password>).
*/
protected $httpauth_credentials = NULL;
/**
* The current session name, if available.
*/
protected $session_name = NULL;
/**
* The current session ID, if available.
*/
protected $session_id = NULL;
Dries Buytaert
committed
/**
* Whether the files were copied to the test files directory.
*/
protected $generatedTestFiles = FALSE;
Dries Buytaert
committed
/**
* The number of redirects followed during the handling of a request.
*/
protected $redirect_count;
Dries Buytaert
committed
/**
* Constructor for DrupalWebTestCase.
*/
function __construct($test_id = NULL) {
parent::__construct($test_id);
$this->skipClasses[__CLASS__] = TRUE;
}
/**
* Get a node from the database based on its title.
*
* @param title
* A node title, usually generated by $this->randomName().
*
* @return
* A node object matching $title.
*/
function drupalGetNodeByTitle($title) {
$nodes = node_load_multiple(array(), array('title' => $title));
// Load the first node returned from the database.
$returned_node = reset($nodes);
return $returned_node;
}
/**
* Creates a node based on default settings.
*
Dries Buytaert
committed
* @param $settings
* An associative array of settings to change from the defaults, keys are
Dries Buytaert
committed
* node properties, for example 'title' => 'Hello, world!'.
* @return
* Created node object.
*/
protected function drupalCreateNode($settings = array()) {
// Populate defaults array.
Dries Buytaert
committed
$settings += array(
'body' => array(LANGUAGE_NONE => array(array())),
'title' => $this->randomName(8),
'comment' => 2,
Dries Buytaert
committed
'changed' => REQUEST_TIME,
'moderate' => 0,
'promote' => 0,
'revision' => 1,
'log' => '',
'status' => 1,
'sticky' => 0,
'type' => 'page',
'revisions' => NULL,
'language' => LANGUAGE_NONE,
);
Dries Buytaert
committed
// Use the original node's created time for existing nodes.
if (isset($settings['created']) && !isset($settings['date'])) {
$settings['date'] = format_date($settings['created'], 'custom', 'Y-m-d H:i:s O');
}
Dries Buytaert
committed
// If the node's user uid is not specified manually, use the currently
// logged in user if available, or else the user running the test.
if (!isset($settings['uid'])) {
if ($this->loggedInUser) {
$settings['uid'] = $this->loggedInUser->uid;
}
else {
global $user;
$settings['uid'] = $user->uid;
}
}
Dries Buytaert
committed
// Merge body field value and format separately.
$body = array(
'value' => $this->randomName(32),
'format' => filter_default_format(),
Dries Buytaert
committed
);
$settings['body'][$settings['language']][0] += $body;
Dries Buytaert
committed
Dries Buytaert
committed
$node = (object) $settings;
node_save($node);
// Small hack to link revisions to our test user.
Dries Buytaert
committed
db_update('node_revision')
->fields(array('uid' => $node->uid))
->condition('vid', $node->vid)
->execute();
return $node;
}
/**
* Creates a custom content type based on default settings.
*
Dries Buytaert
committed
* @param $settings
* An array of settings to change from the defaults.
* Example: 'type' => 'foo'.
Dries Buytaert
committed
* @return
* Created content type.
*/
protected function drupalCreateContentType($settings = array()) {
// Find a non-existent random type name.
do {
Dries Buytaert
committed
$name = strtolower($this->randomName(8));
Angie Byron
committed
} while (node_type_get_type($name));
// Populate defaults array.
$defaults = array(
'type' => $name,
'name' => $name,
Dries Buytaert
committed
'base' => 'node_content',
'description' => '',
'help' => '',
'title_label' => 'Title',
'body_label' => 'Body',
'has_title' => 1,
'has_body' => 1,
);
// Imposed values for a custom type.
$forced = array(
'orig_type' => '',
'old_type' => '',
'module' => 'node',
'custom' => 1,
'modified' => 1,
'locked' => 0,
);
$type = $forced + $settings + $defaults;
$type = (object)$type;
Dries Buytaert
committed
$saved_type = node_type_save($type);
node_types_rebuild();
Dries Buytaert
committed
menu_rebuild();
Dries Buytaert
committed
$this->assertEqual($saved_type, SAVED_NEW, t('Created content type %type.', array('%type' => $type->type)));
Dries Buytaert
committed
// Reset permissions so that permissions for this content type are available.
$this->checkPermissions(array(), TRUE);
return $type;
}
/**
* Get a list files that can be used in tests.
*
Dries Buytaert
committed
* @param $type
* File type, possible values: 'binary', 'html', 'image', 'javascript', 'php', 'sql', 'text'.
* @param $size
* File size in bytes to match. Please check the tests/files folder.
* @return
* List of files that match filter.
*/
protected function drupalGetTestFiles($type, $size = NULL) {
Dries Buytaert
committed
if (empty($this->generatedTestFiles)) {
// Generate binary test files.
$lines = array(64, 1024);
$count = 0;
foreach ($lines as $line) {
simpletest_generate_file('binary-' . $count++, 64, $line, 'binary');
}
// Generate text test files.
$lines = array(16, 256, 1024, 2048, 20480);
$count = 0;
foreach ($lines as $line) {
simpletest_generate_file('text-' . $count++, 64, $line);
}
// Copy other test files from simpletest.
$original = drupal_get_path('module', 'simpletest') . '/files';
$files = file_scan_directory($original, '/(html|image|javascript|php|sql)-.*/');
$destination_path = file_directory_path('public');
foreach ($files as $file) {
file_unmanaged_copy($file->uri, $destination_path);
}
Dries Buytaert
committed
$this->generatedTestFiles = TRUE;
}
$files = array();
// Make sure type is valid.
if (in_array($type, array('binary', 'html', 'image', 'javascript', 'php', 'sql', 'text'))) {
Dries Buytaert
committed
$files = file_scan_directory(file_directory_path('public'), '/' . $type . '\-.*/');
// If size is set then remove any files that are not of that size.
if ($size !== NULL) {
foreach ($files as $file) {
$stats = stat($file->uri);
if ($stats['size'] != $size) {
unset($files[$file->uri]);
}
}
}
}
usort($files, array($this, 'drupalCompareFiles'));
return $files;
}
/**
* Compare two files based on size and file name.
*/
protected function drupalCompareFiles($file1, $file2) {
$compare_size = filesize($file1->uri) - filesize($file2->uri);
if ($compare_size) {
// Sort by file size.
return $compare_size;
}
else {
// The files were the same size, so sort alphabetically.
return strnatcmp($file1->name, $file2->name);
}
}
/**
* Create a user with a given set of permissions. The permissions correspond to the
* names given on the privileges page.
*
Dries Buytaert
committed
* @param $permissions
* Array of permission names to assign to user.
* @return
* A fully loaded user object with pass_raw property, or FALSE if account
* creation fails.
*/
protected function drupalCreateUser($permissions = array('access comments', 'access content', 'post comments', 'post comments without approval')) {
// Create a role with the given permission set.
if (!($rid = $this->drupalCreateRole($permissions))) {
return FALSE;
}
// Create a user assigned to that role.
$edit = array();
$edit['name'] = $this->randomName();
$edit['mail'] = $edit['name'] . '@example.com';
$edit['roles'] = array($rid => $rid);
$edit['pass'] = user_password();
$edit['status'] = 1;
$account = user_save(drupal_anonymous_user(), $edit);
$this->assertTrue(!empty($account->uid), t('User created with name %name and pass %pass', array('%name' => $edit['name'], '%pass' => $edit['pass'])), t('User login'));
if (empty($account->uid)) {
return FALSE;
}
// Add the raw password so that we can log in as this user.
$account->pass_raw = $edit['pass'];
return $account;
}
/**
* Internal helper function; Create a role with specified permissions.
*
Dries Buytaert
committed
* @param $permissions
* Array of permission names to assign to role.
Dries Buytaert
committed
* @param $name
* (optional) String for the name of the role. Defaults to a random string.
Dries Buytaert
committed
* @return
* Role ID of newly created role, or FALSE if role creation failed.
*/
Dries Buytaert
committed
protected function drupalCreateRole(array $permissions, $name = NULL) {
// Generate random name if it was not passed.
if (!$name) {
$name = $this->randomName();
}
Dries Buytaert
committed
// Check the all the permissions strings are valid.
Dries Buytaert
committed
if (!$this->checkPermissions($permissions)) {
return FALSE;
}
// Create new role.
Dries Buytaert
committed
$role = new stdClass();
$role->name = $name;
user_role_save($role);
Dries Buytaert
committed
user_role_grant_permissions($role->rid, $permissions);
Dries Buytaert
committed
$this->assertTrue(isset($role->rid), t('Created role of name: @name, id: @rid', array('@name' => $name, '@rid' => (isset($role->rid) ? $role->rid : t('-n/a-')))), t('Role'));
if ($role && !empty($role->rid)) {
Dries Buytaert
committed
$count = db_query('SELECT COUNT(*) FROM {role_permission} WHERE rid = :rid', array(':rid' => $role->rid))->fetchField();
$this->assertTrue($count == count($permissions), t('Created permissions: @perms', array('@perms' => implode(', ', $permissions))), t('Role'));
return $role->rid;
}
else {
return FALSE;
}
}
Dries Buytaert
committed
/**
* Check to make sure that the array of permissions are valid.
*
Dries Buytaert
committed
* @param $permissions
* Permissions to check.