summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDries Buytaert <dries@buytaert.net>2008-04-20 18:24:07 +0000
committerDries Buytaert <dries@buytaert.net>2008-04-20 18:24:07 +0000
commitaf474609e3e80db9ba1d16b9ad2eae89775f51c8 (patch)
treee525479dd6381b94d21943c3d2decf1c749c028c
parentfe7b9baff62379f5a0c901d27cbb677345791bd0 (diff)
downloadbrdo-af474609e3e80db9ba1d16b9ad2eae89775f51c8.tar.gz
brdo-af474609e3e80db9ba1d16b9ad2eae89775f51c8.tar.bz2
- Added a test framework to Drupal along with a first batch of tests for
Drupal core! This is an important milestone for the project so enable the module and check it out ... :) Thanks to Rok Žlender, Károly Négyesi, Jimmy Berry, Kevin Bridges, Charlie Gordon, Douglas Hubler, Miglius Alaburda, Andy Kirkham, Dimitri13, Kieran Lal, Moshe Weitzman, and the many other people that helped with testing over the past years and that drove this home. It all works but it is still rough around the edges (i.e. documentation is still being written, the coding style is not 100% yet, a number of tests still fail) but we spent the entire weekend working on it in Paris and made a ton of progress. The best way to help and to get up to speed, is to start writing and contributing some tests ... as well as fixing some of the failures. For those willing to help with improving the test framework, here are some next steps and issues to resolve: - How to best approach unit tests and mock functions? - How to test drupal_mail() and drupal_http_request()? - How to improve the admin UI so we have a nice progress bar? - How best to do code coverage? - See http://g.d.o/node/10099 for more ...
-rw-r--r--CHANGELOG.txt2
-rw-r--r--includes/database.inc8
-rw-r--r--includes/xmlrpc.inc.test117
-rw-r--r--modules/aggregator/aggregator.test314
-rw-r--r--modules/block/block.test111
-rw-r--r--modules/blog/blog.test171
-rw-r--r--modules/blogapi/blogapi.test159
-rw-r--r--modules/book/book.test154
-rw-r--r--modules/comment/comment.test372
-rw-r--r--modules/contact/contact.test266
-rw-r--r--modules/dblog/dblog.test370
-rw-r--r--modules/filter/filter.test182
-rw-r--r--modules/forum/forum.test398
-rw-r--r--modules/help/help.module1
-rw-r--r--modules/help/help.test87
-rw-r--r--modules/locale/locale.test116
-rw-r--r--modules/menu/menu.test435
-rw-r--r--modules/node/node.test403
-rw-r--r--modules/path/path.test139
-rw-r--r--modules/php/php.test93
-rw-r--r--modules/poll/poll.test92
-rw-r--r--modules/profile/profile.test975
-rw-r--r--modules/search/search.test162
-rw-r--r--modules/simpletest/files/README.txt5
-rw-r--r--modules/simpletest/files/html-1.txt1
-rw-r--r--modules/simpletest/files/html-2.html1
-rw-r--r--modules/simpletest/files/image-1.pngbin0 -> 64027 bytes
-rw-r--r--modules/simpletest/files/image-2.jpgbin0 -> 6218 bytes
-rw-r--r--modules/simpletest/files/javascript-1.txt3
-rw-r--r--modules/simpletest/files/javascript-2.script3
-rw-r--r--modules/simpletest/files/php-1.txt3
-rw-r--r--modules/simpletest/files/php-2.php3
-rw-r--r--modules/simpletest/files/sql-1.txt1
-rw-r--r--modules/simpletest/files/sql-2.sql1
-rw-r--r--modules/simpletest/simpletest.css62
-rw-r--r--modules/simpletest/simpletest.info6
-rw-r--r--modules/simpletest/simpletest.install98
-rw-r--r--modules/simpletest/simpletest.js58
-rw-r--r--modules/simpletest/simpletest.module478
-rw-r--r--modules/simpletest/simpletest.php369
-rw-r--r--modules/syslog/syslog.test41
-rw-r--r--modules/system/system.test128
-rw-r--r--modules/taxonomy/taxonomy.test394
-rw-r--r--modules/translation/translation.test151
-rw-r--r--modules/trigger/trigger.test114
-rw-r--r--modules/upload/upload.test550
-rw-r--r--modules/user/upload.test522
-rw-r--r--modules/user/user.test205
-rwxr-xr-xscripts/run-functional-tests.php58
49 files changed, 8381 insertions, 1 deletions
diff --git a/CHANGELOG.txt b/CHANGELOG.txt
index e76bb1b19..953c7bf9d 100644
--- a/CHANGELOG.txt
+++ b/CHANGELOG.txt
@@ -14,6 +14,8 @@ Drupal 7.0, xxxx-xx-xx (development version)
* Provide descriptions for permissions on the administration page.
- Search:
* Made it possible to language-aware searches.
+- Testing:
+ * Added test framework and tests.
- Removed ping module:
* This module has been removed from the core download. Contributed
alternatives are available.
diff --git a/includes/database.inc b/includes/database.inc
index 145290ab0..41116091b 100644
--- a/includes/database.inc
+++ b/includes/database.inc
@@ -122,7 +122,7 @@ function db_prefix_tables($sql) {
* @return the name of the previously active database or FALSE if non was found.
*/
function db_set_active($name = 'default') {
- global $db_url, $db_type, $active_db;
+ global $db_url, $db_type, $active_db, $db_prefix;
static $db_conns, $active_name = FALSE;
if (empty($db_url)) {
@@ -150,6 +150,12 @@ function db_set_active($name = 'default') {
}
$db_conns[$name] = db_connect($connect_url);
+ // We need to pass around the simpletest database prefix in the request
+ // and we put that in the user_agent header.
+ if (preg_match("/^simpletest\d+$/", $_SERVER['HTTP_USER_AGENT'])) {
+ $db_prefix = $_SERVER['HTTP_USER_AGENT'];
+ }
+
}
$previous_name = $active_name;
diff --git a/includes/xmlrpc.inc.test b/includes/xmlrpc.inc.test
new file mode 100644
index 000000000..49bab141a
--- /dev/null
+++ b/includes/xmlrpc.inc.test
@@ -0,0 +1,117 @@
+<?php
+// $Id$
+
+class XMLRPCValidator1Test extends DrupalUnitTestCase {
+ function getInfo() {
+ return array('name' => t('XML-RPC validator1'),
+ 'description' => t('See !validator-link. note: simpletest_xmlrpc.module must be enabled', array('!validator-link' => l('the xmlrpc validator1 specification', 'http://www.xmlrpc.com/validator1Docs'))),
+ 'group' => t('XML-RPC'));
+ }
+
+ function test_run_all_tests() {
+ if (!$this->drupalModuleEnable('simpletest_xmlrpc')) {
+ return FALSE;
+ }
+ $xml_url = url(NULL, array('absolute' => TRUE)) . 'xmlrpc.php';
+ srand();
+ mt_srand();
+
+
+ $array_1 = array(array('curly' => mt_rand(-100,100)),
+ array('curly' => mt_rand(-100,100)),
+ array('larry' => mt_rand(-100,100)),
+ array('larry' => mt_rand(-100,100)),
+ array('moe' => mt_rand(-100,100)),
+ array('moe' => mt_rand(-100,100)),
+ array('larry' => mt_rand(-100,100)));
+ shuffle($array_1);
+ $l_res_1 = simpletest_xmlrpc_arrayOfStructsTest($array_1);
+ $r_res_1 = xmlrpc($xml_url, 'validator1.arrayOfStructsTest', $array_1);
+ $this->assertIdentical($l_res_1, $r_res_1, 'array of structs test: %s');
+
+
+ $string_2 = 't\'&>>zf"md>yr>xlcev<h<"k&j<og"w&&>">>uai"np&s>>q\'&b<>"&&&';
+ $l_res_2 = simpletest_xmlrpc_countTheEntities($string_2);
+ $r_res_2 = xmlrpc($xml_url, 'validator1.countTheEntities', $string_2);
+ $this->assertIdentical($l_res_2, $r_res_2, 'count the entities test: %s');
+
+
+ $struct_3 = array('moe' => mt_rand(-100,100), 'larry' => mt_rand(-100,100), 'curly' => mt_rand(-100,100), 'homer' => mt_rand(-100,100));
+ $l_res_3 = simpletest_xmlrpc_easyStructTest($struct_3);
+ $r_res_3 = xmlrpc($xml_url, 'validator1.easyStructTest', $struct_3);
+ $this->assertIdentical($l_res_3, $r_res_3, 'easy struct test: %s');
+
+
+ $struct_4 = array('sub1' => array('bar' => 13),
+ 'sub2' => 14,
+ 'sub3' => array('foo' => 1, 'baz' => 2),
+ 'sub4' => array('ss' => array('sss' => array('ssss' => 'sssss'))));
+ $l_res_4 = simpletest_xmlrpc_echoStructTest($struct_4);
+ $r_res_4 = xmlrpc($xml_url, 'validator1.echoStructTest', $struct_4);
+ $this->assertIdentical($l_res_4, $r_res_4, 'echo struct test: %s');
+
+ $int_5 = mt_rand(-100,100);
+ $bool_5 = (($int_5 % 2) == 0);
+ $string_5 = $this->randomName();
+ $double_5 = (double)(mt_rand(-1000,1000) / 100);
+ $time_5 = time();
+ $base64_5 = $this->randomName(100);
+ $l_res_5 = simpletest_xmlrpc_manyTypesTest($int_5, $bool_5, $string_5, $double_5, xmlrpc_date($time_5), $base64_5);
+ $l_res_5[5] = $l_res_5[5]->data; /* override warpping */
+ $r_res_5 = xmlrpc($xml_url, 'validator1.manyTypesTest', $int_5, $bool_5, $string_5, $double_5, xmlrpc_date($time_5), xmlrpc_base64($base64_5));
+ /* Contains objects, objects are not equal */
+ // See http://drupal.org/node/37766 why this currnetly fails
+ $this->assertEqual($l_res_5, $r_res_5, 'many types test: %s');
+
+
+ $size = mt_rand(100,200);
+ $array_6 = array();
+ for ($i = 0; $i < $size; $i++) {
+ $array_6[] = $this->randomName(mt_rand(8,12));
+ }
+
+ $l_res_6 = simpletest_xmlrpc_moderateSizeArrayCheck($array_6);
+ $r_res_6 = xmlrpc($xml_url, 'validator1.moderateSizeArrayCheck', $array_6);
+ $this->assertIdentical($l_res_6, $r_res_6, 'moderate size array check: %s');
+
+
+ $struct_7 = array();
+ for ($y = 2000; $y < 2002; $y++) {
+ for ($m = 3; $m < 5; $m++) {
+ for ($d = 1; $d < 6; $d++) {
+ $ys = (string)$y;
+ $ms = sprintf('%02d', $m);
+ $ds = sprintf('%02d', $d);
+ $struct_7[$ys][$ms][$ds]['moe'] = mt_rand(-100,100);
+ $struct_7[$ys][$ms][$ds]['larry'] = mt_rand(-100,100);
+ $struct_7[$ys][$ms][$ds]['curly'] = mt_rand(-100,100);
+ }
+ }
+ }
+ $l_res_7 = simpletest_xmlrpc_nestedStructTest($struct_7);
+ $r_res_7 = xmlrpc($xml_url, 'validator1.nestedStructTest', $struct_7);
+ $this->assertIdentical($l_res_7, $r_res_7, 'nested struct test: %s');
+
+
+ $int_8 = mt_rand(-100,100);
+ $l_res_8 = simpletest_xmlrpc_simpleStructReturnTest($int_8);
+ $r_res_8 = xmlrpc($xml_url, 'validator1.simpleStructReturnTest', $int_8);
+ $this->assertIdentical($l_res_8, $r_res_8, 'nested struct test: %s');
+
+ /* Now test multicall */
+ $x = array();
+ $x[] = array('validator1.arrayOfStructsTest', $array_1);
+ $x[] = array('validator1.countTheEntities', $string_2);
+ $x[] = array('validator1.easyStructTest', $struct_3);
+ $x[] = array('validator1.echoStructTest', $struct_4);
+ $x[] = array('validator1.manyTypesTest', $int_5, $bool_5, $string_5, $double_5, xmlrpc_date($time_5), xmlrpc_base64($base64_5));
+ $x[] = array('validator1.moderateSizeArrayCheck', $array_6);
+ $x[] = array('validator1.nestedStructTest', $struct_7);
+ $x[] = array('validator1.simpleStructReturnTest', $int_8);
+
+ $a_l_res = array($l_res_1, $l_res_2, $l_res_3, $l_res_4, $l_res_5, $l_res_6, $l_res_7, $l_res_8);
+ $a_r_res = xmlrpc($xml_url, $x);
+ $this->assertEqual($a_l_res, $a_r_res, 'multicall equals result');
+ }
+}
+?> \ No newline at end of file
diff --git a/modules/aggregator/aggregator.test b/modules/aggregator/aggregator.test
new file mode 100644
index 000000000..e94c23af3
--- /dev/null
+++ b/modules/aggregator/aggregator.test
@@ -0,0 +1,314 @@
+<?php
+// $Id$
+
+class AggregatorTestCase extends DrupalWebTestCase {
+ private static $prefix = 'simpletest_aggregator_';
+
+ /**
+ * Implementation of setUp().
+ */
+ function setUp() {
+ parent::setUp('aggregator');
+ $web_user = $this->drupalCreateUser(array('administer news feeds', 'access news feeds'));
+ $this->drupalLogin($web_user);
+ }
+
+ /**
+ * Create an aggregator feed (simulate form submission on admin/content/aggregator/add/feed).
+ *
+ * @return $feed Full feed object if possible.
+ */
+ function createFeed() {
+ $edit = $this->getFeedEditArray();
+ $this->drupalPost('admin/content/aggregator/add/feed', $edit, t('Save'));
+ $this->assertRaw(t('The feed %name has been added.', array('%name' => $edit['title'])), t('The feed !name has been added.', array('!name' => $edit['title'])));
+
+ $feed = db_fetch_object(db_query("SELECT * FROM {aggregator_feed} WHERE title = '%s' AND url='%s'", $edit['title'], $edit['url']));
+ $this->assertTrue(!empty($feed), t('The feed found in database.'));
+ return $feed;
+ }
+
+ /**
+ * Delete an aggregator feed.
+ *
+ * @param object $feed Feed object representing the feed.
+ */
+ function deleteFeed($feed) {
+ $this->drupalPost('admin/content/aggregator/edit/feed/'. $feed->fid, array(), t('Delete'));
+ $this->assertRaw(t('The feed %title has been deleted.', array('%title' => $feed->title)), t('Feed deleted successfully.'));
+ }
+
+ /**
+ * Return a randomly generated feed edit array.
+ *
+ * @return array Feed array.
+ */
+ function getFeedEditArray() {
+ $feed_name = $this->randomName(10, self::$prefix);
+ $feed_url = url(NULL, array('absolute' => TRUE)) .'rss.xml?feed='. $feed_name;
+ $edit = array(
+ 'title' => $feed_name,
+ 'url' => $feed_url,
+ 'refresh' => '900',
+ );
+ return $edit;
+ }
+
+ /**
+ * Update feed items (simulate click to admin/content/aggregator/update/$fid).
+ *
+ * @param object $feed Feed object representing the feed.
+ */
+ function updateFeedItems(&$feed) {
+ // First, let's ensure we could get to the rss xml
+ $this->drupalGet('rss.xml');
+ $this->assertResponse(200, t('rss.xml is reachable.'));
+
+ // our tests are based off of rss.xml, so let's find out how many elements should be related
+ $feed_count = db_result(db_query_range(db_rewrite_sql('SELECT COUNT(*) FROM {node} n WHERE n.promote = 1 AND n.status = 1'), 0, variable_get('feed_default_items', 10)));
+ $feed_count = $feed_count > 10 ? 10 : $feed_count;
+
+ // refresh the feed (simulated link click)
+ $this->drupalGet('admin/content/aggregator/update/'. $feed->fid);
+
+ // ensure we have the right number of items
+ $result = db_query('SELECT iid FROM {aggregator_item} WHERE fid = %d', $feed->fid);
+ $items = array();
+ $feed->items = array();
+ while ($item = db_fetch_object($result)) {
+ $feed->items[] = $item->iid;
+ }
+ $feed->item_count = count($feed->items);
+ $this->assertEqual($feed_count, $feed->item_count, t('Total items in feed equal to the total items in database (!val1 != !val2)', array('!val1' => $feed_count, '!val2' => $feed->item_count)));
+ }
+
+ /**
+ * Confirm item removal from a feed.
+ *
+ * @param object $feed Feed object representing the feed.
+ */
+ function removeFeedItems($feed) {
+ $this->drupalPost('admin/content/aggregator/remove/' . $feed->fid, array(), t('Remove items'));
+ $this->assertRaw(t('The news items from %title have been removed.', array('%title' => $feed->title)), t('Feed items removed.'));
+ }
+
+ /**
+ * Pull feed categories from aggregator_category_feed table.
+ *
+ * @param object $feed Feed object representing the feed.
+ */
+ function getFeedCategories($feed) {
+ // add the categories to the feed so we can use them
+ $result = db_query('SELECT cid FROM {aggregator_category_feed} WHERE fid = %d', $feed->fid);
+ while ($category = db_fetch_object($result)) {
+ $feed->categories[] = $category->cid;
+ }
+ }
+
+ /**
+ * Check if the feed name and url is unique.
+ *
+ * @param string $feed_name Feed name to check.
+ * @param string $feed_url Feed url to check.
+ * @return boolean Feed is unique.
+ */
+ function uniqueFeed($feed_name, $feed_url) {
+ $result = db_result(db_query("SELECT count(*) FROM {aggregator_feed} WHERE title = '%s' AND url='%s'", $feed_name, $feed_url));
+ return (1 == $result);
+ }
+}
+
+class AddFeedTestCase extends AggregatorTestCase {
+ /**
+ * Implementation of getInfo().
+ */
+ function getInfo() {
+ return array(
+ 'name' => t('Add feed functionality'),
+ 'description' => t('Add feed test.'),
+ 'group' => t('Aggregator')
+ );
+ }
+
+ /**
+ * Create a feed, ensure that it is unique, check the source, and delete the feed.
+ */
+ function testAddFeed() {
+ $feed = $this->createFeed();
+
+ // Check feed data.
+ $this->assertEqual($this->getUrl(), url('admin/content/aggregator/add/feed', array('absolute' => TRUE)), t('Directed to correct url.'));
+ $this->assertTrue($this->uniqueFeed($feed->title, $feed->url), t('The feed is unique.'));
+
+ // Check feed source.
+ $this->drupalGet('aggregator/sources/'. $feed->fid);
+ $this->assertResponse(200, t('Feed source exists.'));
+ $this->assertText($feed->title, t('Page title'));
+
+ // Delete feed.
+ $this->deleteFeed($feed);
+ }
+}
+
+class UpdateFeedTestCase extends AggregatorTestCase {
+ /**
+ * Implementation of getInfo().
+ */
+ function getInfo() {
+ return array(
+ 'name' => t('Update feed functionality'),
+ 'description' => t('Update feed test.'),
+ 'group' => t('Aggregator')
+ );
+ }
+
+ /**
+ * Create a feed and attempt to update it.
+ */
+ function testUpdateFeed() {
+ $feed = $this->createFeed();
+
+ // Get new feed data array and modify newly created feed.
+ $edit = $this->getFeedEditArray();
+ $edit['refresh'] = 1800; // Change refresh value.
+ $this->drupalPost('admin/content/aggregator/edit/feed/'. $feed->fid, $edit, t('Save'));
+ $this->assertRaw(t('The feed %name has been updated.', array('%name' => $edit['title'])), t('The feed %name has been updated.', array('%name' => $edit['title'])));
+
+ // Check feed data.
+ $this->assertEqual($this->getUrl(), url('admin/content/aggregator/', array('absolute' => TRUE)));
+ $this->assertTrue($this->uniqueFeed($edit['title'], $edit['url']), t('The feed is unique.'));
+
+ // Check feed source.
+ $this->drupalGet('aggregator/sources/'. $feed->fid);
+ $this->assertResponse(200, t('Feed source exists.'));
+ $this->assertText($edit['title'], t('Page title'));
+
+ // Delete feed.
+ $feed->title = $edit['title']; // Set correct title so deleteFeed() will work.
+ $this->deleteFeed($feed);
+ }
+}
+
+class RemoveFeedTestCase extends AggregatorTestCase {
+ /**
+ * Implementation of getInfo().
+ */
+ function getInfo() {
+ return array(
+ 'name' => t('Remove feed functionality'),
+ 'description' => t('Remove feed test.'),
+ 'group' => t('Aggregator')
+ );
+ }
+
+ /**
+ * Remove a feed and ensure that all it services are removed.
+ */
+ function testRemoveFeed() {
+ $feed = $this->createFeed();
+
+ // Delete feed.
+ $this->deleteFeed($feed);
+
+ // Check feed source.
+ $this->drupalGet('aggregator/sources/'. $feed->fid);
+ $this->assertResponse(404, t('Deleted feed source does not exists.'));
+
+ // Check database for feed.
+ $result = db_result(db_query("SELECT count(*) FROM {aggregator_feed} WHERE title = '%s' AND url='%s'", $feed->title, $feed->url));
+ $this->assertFalse($result, t('Feed not found in database'));
+ }
+}
+
+class UpdateFeedItemTestCase extends AggregatorTestCase {
+ /**
+ * Implementation of getInfo().
+ */
+ function getInfo() {
+ return array(
+ 'name' => t('Update feed item functionality'),
+ 'description' => t('Update feed items from a feed.'),
+ 'group' => t('Aggregator')
+ );
+ }
+
+ /**
+ * Test running "update items" from the 'admin/content/aggregator' page.
+ */
+ function testUpdateFeedItem() {
+ // Create a feed and test updating feed items if possible.
+ $feed = $this->createFeed();
+ if (!empty($feed)) {
+ $this->updateFeedItems($feed);
+ $this->removeFeedItems($feed);
+ }
+
+ // Delete feed.
+ $this->deleteFeed($feed);
+ }
+}
+
+class RemoveFeedItemTestCase extends AggregatorTestCase {
+ /**
+ * Implementation of getInfo().
+ */
+ function getInfo() {
+ return array(
+ 'name' => t('Remove feed item functionality'),
+ 'description' => t('Remove feed items from a feed.'),
+ 'group' => t('Aggregator')
+ );
+ }
+
+ /**
+ * Test running "remove items" from the 'admin/content/aggregator' page.
+ */
+ function testRemoveFeedItem() {
+ $feed = $this->createFeed();
+
+ // Add and remove feed items and ensure that the count is zero.
+ $this->updateFeedItems($feed);
+ $this->removeFeedItems($feed);
+ $count = db_result(db_query('SELECT COUNT(*) FROM {aggregator_item} WHERE fid = %d', $feed->fid));
+ $this->assertTrue($count == 0);
+
+ // Delete feed.
+ $this->deleteFeed($feed);
+ }
+}
+
+class CategorizeFeedItemTestCase extends AggregatorTestCase {
+ /**
+ * Implementation of getInfo().
+ */
+ function getInfo() {
+ return array(
+ 'name' => t('Categorize feed item functionality'),
+ 'description' => t('Test feed item categorization.'),
+ 'group' => t('Aggregator')
+ );
+ }
+
+ /**
+ * If a feed has a category, make sure that the children inherit that
+ * categorization.
+ */
+ function testCategorizeFeedItem() {
+ // TODO: Need to add categories to the feed on creation.
+ $feed = $this->createFeed();
+ $this->updateFeedItems($feed);
+ $this->getFeedCategories($feed);
+
+ // For each category of a feed, ensure feed items have that category, too.
+ if (!empty($feed->categories) && !empty($feed->items)) {
+ foreach ($feed->categories as $category) {
+ $items_str = implode(', ', $feed->items);
+ $categorized_count = db_result(db_query('SELECT COUNT(*) FROM {aggregator_category_item} WHERE iid IN (' . $items_str . ')'));
+ $this->assertEqual($feed->item_count, $categorized_count, t('Total items in feed equal to the total categorized feed items in database'));
+ }
+ }
+
+ // Delete feed.
+ $this->deleteFeed($feed);
+ }
+}
diff --git a/modules/block/block.test b/modules/block/block.test
new file mode 100644
index 000000000..85a95e603
--- /dev/null
+++ b/modules/block/block.test
@@ -0,0 +1,111 @@
+<?php
+// $Id$
+
+class BlockTestCase extends DrupalWebTestCase {
+ /**
+ * Implementation of getInfo().
+ */
+ function getInfo() {
+ return array(
+ 'name' => t('Block functionality'),
+ 'description' => t('Add, edit and delete custom block. Configure and move a module-defined block.'),
+ 'group' => t('Block'),
+ );
+ }
+
+ /**
+ * Implementation of setUp().
+ */
+ function setUp() {
+ parent::setUp();
+
+ // Create and login user
+ $admin_user = $this->drupalCreateUser(array('administer blocks'));
+ $this->drupalLogin($admin_user);
+ }
+
+ /**
+ * Test creating custom block (i.e. box), moving it to a specific region and then deleting it.
+ */
+ function testBox() {
+ // Add a new box by filling out the input form on the admin/build/block/add page.
+ $box = array();
+ $box['info'] = $this->randomName(8);
+ $box['title'] = $this->randomName(8);
+ $box['body'] = $this->randomName(32);
+ $this->drupalPost('admin/build/block/add', $box, t('Save block'));
+
+ // Confirm that the box has been created, and then query the created bid.
+ $this->assertText(t('The block has been created.'), t('Box successfully created.'));
+ $bid = db_result(db_query("SELECT bid FROM {boxes} WHERE info = '%s'", array($box['info'])));
+
+ // Check to see if the box was created by checking that it's in the database..
+ $this->assertNotNull($bid, t('Box found in database'));
+
+ // Set the created box to a specific region.
+ // TODO: Implement full region checking.
+ $edit = array();
+ $edit['block_'. $bid .'[region]'] = 'left';
+ $this->drupalPost('admin/build/block', $edit, t('Save blocks'));
+
+ // Confirm that the box was moved to the proper region.
+ $this->assertText(t('The block settings have been updated.'), t('Box successfully moved to left region.'));
+
+ // Confirm that the box is being displayed.
+ $this->assertText(t($box['title']), t('Box successfully being displayed on the page.'));
+
+ // Delete the created box & verify that it's been deleted and no longer appearing on the page.
+ $this->drupalPost('admin/build/block/delete/'. $bid, array(), t('Delete'));
+ $this->assertRaw(t('The block %title has been removed.', array('%title' => $box['info'])), t('Box successfully deleted.'));
+ $this->assertNoText(t($box['title']), t('Box no longer appears on page.'));
+ }
+
+ /**
+ * Test configuring and moving a module-define block to specific regions.
+ */
+ function testBlock() {
+ // Select the Navigation block to be configured and moved.
+ $block = array();
+ $block['module'] = 'user';
+ $block['delta'] = 'navigation';
+ $block['title'] = $this->randomName(8);
+
+ // Set block title to confirm that interface works and override any custom titles.
+ $this->drupalPost('admin/build/block/configure/'. $block['module'] .'/'. $block['delta'], array('title' => $block['title']), t('Save block'));
+ $this->assertText(t('The block configuration has been saved.'), t('Block title set.'));
+ $bid = db_result(db_query("SELECT bid FROM {blocks} WHERE module = '%s' AND delta = %d", array($block['module'], $block['delta'])));
+
+ // Check to see if the block was created by checking that it's in the database.
+ $this->assertNotNull($bid, t('Block found in database'));
+
+ // Set the created block to a specific region.
+ $edit = array();
+ $edit[$block['module'] .'_'. $block['delta'] .'[region]'] = 'left';
+ $this->drupalPost('admin/build/block', $edit, t('Save blocks'));
+
+ // Confirm that the block was moved to the proper region.
+ // TODO: Implement full region checking.
+ $this->assertText(t('The block settings have been updated.'), t('Block successfully moved to left region.'));
+
+ // Confirm that the block is being displayed.
+ $this->assertText(t($block['title']), t('Block successfully being displayed on the page.'));
+
+ // Set the block to the disabled region.
+ $edit = array();
+ $edit[$block['module'] .'_'. $block['delta'] .'[region]'] = '-1';
+ $this->drupalPost('admin/build/block', $edit, t('Save blocks'));
+
+ // Confirm that the block was moved to the proper region.
+ $this->assertText(t('The block settings have been updated.'), t('Block successfully move to disabled region.'));
+ $this->assertNoText(t($block['title']), t('Block no longer appears on page.'));
+
+ // For convenience of developers, put the navigation block back.
+ $edit = array();
+ $edit[$block['module'] .'_'. $block['delta'] .'[region]'] = 'left';
+ $this->drupalPost('admin/build/block', $edit, t('Save blocks'));
+ $this->assertText(t('The block settings have been updated.'), t('Block successfully move to disabled region.'));
+
+ $this->drupalPost('admin/build/block/configure/'. $block['module'] .'/'. $block['delta'], array('title' => 'Navigation'), t('Save block'));
+ $this->assertText(t('The block configuration has been saved.'), t('Block title set.'));
+ }
+}
diff --git a/modules/blog/blog.test b/modules/blog/blog.test
new file mode 100644
index 000000000..a3a6c1441
--- /dev/null
+++ b/modules/blog/blog.test
@@ -0,0 +1,171 @@
+<?php
+// $Id$
+
+class BlogTestCase extends DrupalWebTestCase {
+ protected $big_user;
+ protected $own_user;
+ protected $any_user;
+
+ /**
+ * Implementation of getInfo().
+ */
+ function getInfo() {
+ return array(
+ 'name' => t('Blog functionality'),
+ 'description' => t('Create, view, edit, delete, and change blog entries and verify its consistency in the database.'),
+ 'group' => t('Blog'),
+ );
+ }
+
+ /**
+ * Enable modules and create users with specific permissions.
+ */
+ function setUp() {
+ parent::setUp('blog');
+ // Create users.
+ $this->big_user = $this->drupalCreateUser(array('administer blocks'));
+ $this->own_user = $this->drupalCreateUser(array('create blog content', 'edit own blog content', 'delete own blog content'));
+ $this->any_user = $this->drupalCreateUser(array('create blog content', 'edit any blog content', 'delete any blog content', 'access administration pages'));
+ }
+
+ /**
+ * Login users, create blog nodes, and test blog functionality through the admin and user interfaces.
+ */
+ function testBlog() {
+ // Login the admin user.
+ $this->drupalLogin($this->big_user);
+ // Enable the recent blog block.
+ $edit = array();
+ $edit['blog_recent[region]'] = 'right';
+ $this->drupalPost('admin/build/block', $edit, t('Save blocks'));
+ $this->assertResponse(200);
+
+ // Do basic tests for each user.
+ $this->doBasicTests($this->any_user, TRUE);
+ $this->doBasicTests($this->own_user, FALSE);
+
+ // Create another blog node for the any blog user.
+ $node = $this->drupalCreateNode(array('type' => 'blog', 'uid' => $this->any_user->uid));
+ // Verify the own blog user only has access to the blog view node.
+ $this->verifyBlogs($this->any_user, $node, FALSE, 403);
+
+ // Create another blog node for the own blog user.
+ $node = $this->drupalCreateNode(array('type' => 'blog', 'uid' => $this->own_user->uid));
+ // Login the any blog user.
+ $this->drupalLogin($this->any_user);
+ // Verify the any blog user has access to all the blog nodes.
+ $this->verifyBlogs($this->own_user, $node, TRUE);
+ }
+
+ /**
+ * Run basic tests on the indicated user.
+ *
+ * @param object $user The logged in user.
+ * @param boolean $admin User has 'access administration pages' privilege.
+ */
+ private function doBasicTests($user, $admin) {
+ // Login the user.
+ $this->drupalLogin($user);
+ // Create blog node.
+ $node = $this->drupalCreateNode(array('type' => 'blog', 'uid' => $user->uid));
+ // Verify the user has access to all the blog nodes.
+ $this->verifyBlogs($user, $node, $admin);
+ // Verify the blog links are displayed.
+ $this->verifyBlogLinks($user);
+ }
+
+ /**
+ * Verify the logged in user has the desired access to the various blog nodes.
+ *
+ * @param object $node_user The user who creates the node.
+ * @param object $node Node.
+ * @param boolean $admin User has 'access administration pages' privilege.
+ * @param integer $response HTTP response code.
+ */
+ private function verifyBlogs($node_user, $node, $admin, $response = 200) {
+ $crumb = '›';
+ $quote = '&#039;';
+
+ $response2 = ($admin) ? 200 : 403;
+
+ // View blog help node.
+ $this->drupalGet('admin/help/blog');
+ $this->assertResponse($response2);
+ // NOTE: The two commented asserts fail because the get returns the 'admin/help' node instead of the indicated node???
+ if ($response2 == 200) {
+// $this->assertTitle(t('Blog | Drupal'), t('Blog help node was displayed'));
+ $this->assertText(t('Blog'), t('Blog help node was displayed'));
+// $this->assertText(t('Home '. $crumb .' Administer '. $crumb .' Help'), t('Breadcrumbs were displayed'));
+ }
+
+ // Verify the blog block was displayed.
+ $this->drupalGet('');
+ $this->assertResponse(200);
+ $this->assertText(t('Recent blog posts'), t('Blog block was displayed'));
+
+ // View blog node.
+ $this->drupalGet('node/'. $node->nid);
+ $this->assertResponse(200);
+ $this->assertTitle($node->title. ' | Drupal', t('Blog node was displayed'));
+ $this->assertText(t('Home '. $crumb .' Blogs '. $crumb .' @name'. $quote .'s blog', array('@name' => $node_user->name)), t('Breadcrumbs were displayed'));
+
+ // View blog edit node.
+ $this->drupalGet('node/'. $node->nid .'/edit');
+ $this->assertResponse($response);
+ if ($response == 200) {
+ $this->assertTitle($node->title. ' | Drupal', t('Blog edit node was displayed'));
+ $this->assertText(t('Home '. $crumb .' @title', array('@title' => $node->title)), t('Breadcrumbs were displayed'));
+ }
+
+ if ($response == 200) {
+ // Edit blog node.
+ $edit = array();
+ $edit['title'] = 'node/' . $node->nid;
+ $edit['body'] = $this->randomName(256);
+ $this->drupalPost('node/'. $node->nid .'/edit', $edit, t('Save'));
+ $this->assertRaw(t('Blog entry %title has been updated.', array('%title' => $edit['title'])), t('Blog node was edited'));
+
+ // Delete blog node.
+ $this->drupalPost('node/'. $node->nid .'/delete', array(), t('Delete'));
+ $this->assertResponse($response);
+ $this->assertRaw(t('Blog entry %title has been deleted.', array('%title' => $edit['title'])), t('Blog node was deleted'));
+ }
+ }
+
+ /**
+ * Verify the blog links are displayed to the logged in user.
+ *
+ * @param object $user The logged in user.
+ */
+ private function verifyBlogLinks($user) {
+ $crumb = '›';
+
+ // Confirm blog entries link exists on the user page.
+ $this->drupalGet('user/'. $user->uid);
+ $this->assertResponse(200);
+ $this->assertText(t('View recent blog entries'), t('View recent blog entries link was displayed'));
+
+ // Confirm the recent blog entries link links to the user's blog page.
+ $this->clickLink('View recent blog entries');
+ $this->assertTitle(t("@name's blog | Drupal", array('@name' => $user->name)), t('View recent blog entries link target was correct'));
+
+ // Confirm a blog page was displayed.
+ $this->drupalGet('blog');
+ $this->assertResponse(200);
+ $this->assertTitle('Blogs | Drupal', t('Blog page was displayed'));
+ $this->assertText(t('Home'), t('Breadcrumbs were displayed'));
+
+ // Confirm a blog page was displayed per user.
+ $this->drupalGet('blog/'. $user->uid);
+ $this->assertTitle(t("@name's blog | Drupal", array('@name' => $user->name)), t('User blog node was displayed'));
+ $this->assertText(t('Home '. $crumb .' Blogs'), t('Breadcrumbs were displayed'));
+
+ // Confirm a blog feed was displayed.
+ $this->drupalGet('blog/feed');
+ $this->assertTitle(t('Drupal blogs'), t('Blog feed was displayed'));
+
+ // Confirm a blog feed was displayed per user.
+ $this->drupalGet('blog/'. $user->uid .'/feed');
+ $this->assertTitle(t("@name's blog", array('@name' => $user->name)), t('User blog feed was displayed'));
+ }
+}
diff --git a/modules/blogapi/blogapi.test b/modules/blogapi/blogapi.test
new file mode 100644
index 000000000..ea6accf0b
--- /dev/null
+++ b/modules/blogapi/blogapi.test
@@ -0,0 +1,159 @@
+<?php
+// $Id$
+
+class BlogAPITestCase extends DrupalWebTestCase {
+ /**
+ * Implementation of getInfo().
+ */
+ function getInfo() {
+ return array(
+ 'name' => t('Blog API functionality'),
+ 'description' => t('Create, edit, and delete post; upload file; and set/get categories.'),
+ 'group' => t('Blog API'),
+ );
+ }
+
+ /**
+ * Implementation of setUp().
+ */
+ function setUp() {
+ parent::setUp('blog', 'blogapi', 'taxonomy');
+ }
+
+ /**
+ * Create, edit, and delete post; upload file; and set/get categories.
+ */
+ function testBlogAPI() {
+ // Create admin user and taxononmy for later use.
+ $admin_user = $this->drupalCreateUser(array('administer taxonomy'));
+ $this->drupalLogin($admin_user);
+ $vid = $this->addVocabulary('simpletest_vocab');
+ $term = $this->addTerm($vid, 'simpletest_term1');
+ $this->drupalLogout();
+
+ // Create user.
+ $web_user = $this->drupalCreateUser(array('create blog content', 'delete own blog content', 'edit own blog content', 'administer content with blog api'));
+ $this->drupalLogin($web_user);
+
+ // Init common variables.
+ $local = url('xmlrpc.php', array('absolute' => TRUE));
+ $appid = 'simpletest';
+
+ // Get user's blog.
+ $result = xmlrpc($local, 'blogger.getUsersBlogs', $appid, $web_user->name, $web_user->pass_raw);
+ $this->assertTrue($result, t('Request for user\'s blogs returned correctly.'));
+
+ if ($result !== FALSE) {
+ if ($this->assertTrue(array_key_exists('blogid', $result[0]), t('Blog found.'))) {
+ $blog_id = $result[0]['blogid'];
+ }
+ }
+
+ // Create post.
+ $content = $this->randomName(32);
+ $result = xmlrpc($local, 'blogger.newPost', $appid, $blog_id, $web_user->name, $web_user->pass_raw, $content, TRUE);
+ $this->assertTrue($result, t('Post created.'));
+
+ $nid = $result;
+
+ // Check recent posts.
+ $result = xmlrpc($local, 'blogger.getRecentPosts', $appid, $blog_id, $web_user->name, $web_user->pass_raw, 5);
+ $this->assertTrue($result, t('Recent post list retreived.'));
+
+ if ($result !== FALSE && array_key_exists('title', $result[0])) {
+ $this->assertEqual($content, $result[0]['title'], t('Post found.'));
+ }
+ else
+ $this->assertTrue(false, 'Post found.');
+
+ // Edit post.
+ $content_new = $this->randomName(10);
+ $result = xmlrpc($local, 'blogger.editPost', $appid, $nid, $web_user->name, $web_user->pass_raw, $content_new, TRUE);
+ $this->assertTrue($result, t('Post successfully modified.'));
+
+ // Upload file.
+ $file = current($this->drupalGetTestFiles('text'));
+ $file_contents = file_get_contents($file->filename);
+ $file = array();
+ $file['name'] = $this->randomName() .'.txt';
+ $file['type'] = 'text';
+ $file['bits'] = xmlrpc_base64($file_contents);
+ $result = xmlrpc($local, 'metaWeblog.newMediaObject', $blog_id, $web_user->name, $web_user->pass_raw, $file);
+ $this->assertTrue($result, t('File successfully uploaded.'));
+
+ $url = (array_key_exists('url', $result) ? $result['url'] : '');
+
+ // Check uploaded file.
+ $this->drupalGet($url);
+ $this->assertEqual($this->drupalGetContent(), $file_contents, t('Uploaded contents verified.'));
+
+ // Set post categories.
+ $categories = array(array('categoryId' => $term));
+ $result = xmlrpc($local, 'mt.setPostCategories', $nid, $web_user->name, $web_user->pass_raw, $categories);
+ $this->assertTrue($result, t('Post categories set.'));
+
+ // Get post categories.
+ $result = xmlrpc($local, 'mt.getPostCategories', $nid, $web_user->name, $web_user->pass_raw);
+ $this->assertTrue($result, t('Category list successfully retreived.'));
+
+ if ($result !== FALSE && array_key_exists('categoryId', $result[0])) {
+ $this->assertEqual($term, $result[0]['categoryId'], t('Category list verified.'));
+ }
+
+ // Delete post.
+ $result = xmlrpc($local, 'blogger.deletePost', $appid, $nid, $web_user->name, $web_user->pass_raw, TRUE);
+ $this->assertTrue($result, t('Post successfully deleted.'));
+ }
+
+ /**
+ * Add taxonomy vocabulary.
+ *
+ * @param string $vocab Vocabulary name.
+ * @return interger Vocab id.
+ */
+ function addVocabulary($vocab) {
+ $edit = array();
+ $edit['name'] = $vocab;
+ $edit['nodes[blog]'] = TRUE;
+ $this->drupalPost('admin/content/taxonomy/add/vocabulary', $edit, t('Save'));
+ $this->assertRaw(t('Created new vocabulary %vocab.', array('%vocab' => $edit['name'])), t('Taxonomy vocabulary added.'));
+
+ $vocab_arr = taxonomy_get_vocabularies();
+ $vid = NULL;
+ foreach ($vocab_arr as $vocab_item) {
+ if ($vocab_item->name == $vocab) {
+ $vid = $vocab_item->vid;
+ break;
+ }
+ }
+
+ $this->assertNotNull($vid, t('Vocabulary found in database.'));
+ return $vid;
+ }
+
+ /**
+ * Add a taxonomy term to vocabulary.
+ *
+ * @param integer $vid Vocabulary id.
+ * @param string $term Term name.
+ * @return interger Term id.
+ */
+ function addTerm($vid, $term) {
+ $edit = array();
+ $edit['name'] = $term;
+ $this->drupalPost('admin/content/taxonomy/'. $vid .'/add/term', $edit, t('Save'));
+ $this->assertRaw(t('Created new term %term.', array('%term' => $edit['name'])), t('Taxonomy term added.'));
+
+ $tree = taxonomy_get_tree($vid);
+ $tid = NULL;
+ foreach ($tree as $tree_term) {
+ if ($tree_term->name == $term) {
+ $tid = $tree_term->tid;
+ break;
+ }
+ }
+
+ $this->assertNotNull($tid, t('Term found in database.'));
+ return $tid;
+ }
+}
diff --git a/modules/book/book.test b/modules/book/book.test
new file mode 100644
index 000000000..7961bda8b
--- /dev/null
+++ b/modules/book/book.test
@@ -0,0 +1,154 @@
+<?php
+// $Id$
+
+class BookTestCase extends DrupalWebTestCase {
+ protected $book;
+
+ /**
+ * Implementation of getInfo().
+ */
+ function getInfo() {
+ return array(
+ 'name' => t('Book functionality'),
+ 'description' => t('Create a book, add pages, and test book interface.'),
+ 'group' => t('Book'),
+ );
+ }
+
+ /**
+ * Implementation of setUp().
+ */
+ function setUp() {
+ parent::setUp('book');
+ }
+
+ /**
+ * Test book funcitonality through node interfaces.
+ */
+ function testBook() {
+ // Create users.
+ $book_author = $this->drupalCreateUser(array('create new books', 'create book content', 'add content to books'));
+ $web_user = $this->drupalCreateUser(array('access printer-friendly version'));
+
+ // Create new book.
+ $this->drupalLogin($book_author);
+
+ $this->book = $this->createBookNode('new');
+ $book = $this->book;
+
+ /*
+ * Add page hiearchy to book.
+ * Book
+ * |- Node 0
+ * |- Node 1
+ * |- Node 2
+ * |- Node 3
+ * |- Node 4
+ */
+ $nodes = array();
+ $nodes[] = $this->createBookNode($book->nid); // Node 0.
+ $nodes[] = $this->createBookNode($book->nid, $nodes[0]->book['mlid']); // Node 1.
+ $nodes[] = $this->createBookNode($book->nid, $nodes[0]->book['mlid']); // Node 2.
+ $nodes[] = $this->createBookNode($book->nid); // Node 3.
+ $nodes[] = $this->createBookNode($book->nid); // Node 4.
+
+ $this->drupalLogout();
+
+ // Check to make sure that book pages display properly.
+ $this->drupalLogin($web_user);
+
+ $this->checkBookNode($book, array($nodes[0], $nodes[3], $nodes[4]), false, false, $nodes[0]);
+ $this->checkBookNode($nodes[0], array($nodes[1], $nodes[2]), $book, $book, $nodes[1]);
+ $this->checkBookNode($nodes[1], NULL, $nodes[0], $nodes[0], $nodes[2]);
+ $this->checkBookNode($nodes[2], NULL, $nodes[1], $nodes[0], $nodes[3]);
+ $this->checkBookNode($nodes[3], NULL, $nodes[2], $book, $nodes[4]);
+ $this->checkBookNode($nodes[4], NULL, $nodes[3], $book, false);
+ }
+
+ /**
+ * Checks the outline of sub-pages; previous, up, and next; and check printer friendly version.
+ *
+ * @param Node $node Node to check.
+ * @param array $nodes Nodes that should be in outline.
+ * @param Node $previous Previous link node.
+ * @param Node $up Up link node.
+ * @param Node $next Next link node.
+ */
+ function checkBookNode($node, $nodes, $previous = false, $up = false, $next = false) {
+ static $number = 0;
+ $this->drupalGet('node/' . $node->nid);
+
+ // Check outline structure.
+ if ($nodes !== NULL) {
+ $this->assertPattern($this->generateOutlinePattern($nodes), t('Node ' . $number . ' outline confirmed.'));
+ }
+ else {
+ $this->pass(t('Node ' . $number . ' doesn\'t have outline.'));
+ }
+
+ // Check previous, up, and next links.
+ if ($previous) {
+ $this->assertRaw(l('‹ ' . $previous->title, 'node/' . $previous->nid, array('attributes' => array('class' => 'page-previous', 'title' => t('Go to previous page')))), t('Prevoius page link found.'));
+ }
+ if ($up) {
+ $this->assertRaw(l('up', 'node/' . $up->nid, array('attributes' => array('class' => 'page-up', 'title' => t('Go to parent page')))), t('Up page link found.'));
+ }
+ if ($next) {
+ $this->assertRaw(l($next->title . ' ›', 'node/' . $next->nid, array('attributes' => array('class' => 'page-next', 'title' => t('Go to next page')))), t('Next page link found.'));
+ }
+
+ // Check printer friendly version.
+ $this->drupalGet('book/export/html/' . $node->nid);
+ $this->assertText($node->title, t('Printer friendly title found.'));
+ $node->body = str_replace('<!--break-->', '', $node->body);
+ $this->assertRaw(check_markup($node->body, $node->format), t('Printer friendly body found.'));
+
+ $number++;
+ }
+
+ /**
+ * Create a regular expression to check for the sub-nodes in the outline.
+ *
+ * @param array $nodes Nodes to check in outline.
+ */
+ function generateOutlinePattern($nodes) {
+ $outline = '';
+ foreach ($nodes as $node) {
+ $outline .= '(node\/' . $node->nid . ')(.*?)(' . $node->title . ')(.*?)';
+ }
+
+ return '/<div id="book-navigation-' . $this->book->nid . '"(.*?)<ul(.*?)' . $outline . '<\/ul>/s';
+ }
+
+ /**
+ * Create book node.
+ *
+ * @param integer $book_nid Book node id or set to 'new' to create new book.
+ * @param integer $parent Parent book reference id.
+ */
+ function createBookNode($book_nid, $parent = NULL) {
+ static $number = 0; // Used to ensure that when sorted nodes stay in same order.
+
+ $edit = array();
+ $edit['title'] = $number . ' - SimpleTest test node ' . $this->randomName(10);
+ $edit['body'] = 'SimpleTest test body ' . $this->randomName(32) . ' ' . $this->randomName(32);
+ $edit['book[bid]'] = $book_nid;
+
+ if ($parent !== NULL) {
+ $this->drupalPost('node/add/book', $edit, t('Change book (update list of parents)'));
+
+ $edit['book[plid]'] = $parent;
+ $this->drupalPost(NULL, $edit, t('Save'));
+ }
+ else {
+ $this->drupalPost('node/add/book', $edit, t('Save'));
+ }
+
+ // Check to make sure the book node was created.
+ $node = node_load(array('title' => $edit['title']));
+ $this->assertNotNull(($node === FALSE ? NULL : $node), t('Book node found in database.'));
+ $number++;
+
+ return $node;
+ }
+}
diff --git a/modules/comment/comment.test b/modules/comment/comment.test
new file mode 100644
index 000000000..c309769f2
--- /dev/null
+++ b/modules/comment/comment.test
@@ -0,0 +1,372 @@
+<?php
+// $Id$
+
+class CommentTestCase extends DrupalWebTestCase {
+ protected $admin_user;
+ protected $web_user;
+ protected $node;
+
+ /**
+ * Implementation of getInfo().
+ */
+ function getInfo() {
+ return array(
+ 'name' => t('Comment functionality'),
+ 'description' => t('Thoroughly test comment administration and user interfaces.'),
+ 'group' => t('Comment'),
+ );
+ }
+
+ /**
+ * Implementation of setUp().
+ */
+ function setUp() {
+ parent::setUp('comment');
+ // Create users.
+ $this->admin_user = $this->drupalCreateUser(array('administer content types', 'administer comments', 'administer permissions'));
+ $this->web_user = $this->drupalCreateUser(array('access comments', 'post comments', 'create story content'));
+
+ $this->drupalLogin($this->web_user);
+ $this->node = $this->drupalCreateNode(array('type' => 'story'));
+ $this->assertTrue($this->node, t('Story node created.'));
+ $this->drupalLogout();
+ }
+
+ /**
+ * Test comment interface.
+ */
+ function testCommentInterface() {
+ // Set comments to not have subject.
+ $this->drupalLogin($this->admin_user);
+ $this->setCommentPreview(TRUE);
+ $this->setCommentSubject(FALSE);
+ $this->drupalLogout();
+
+ // Post comment without subject.
+ $this->drupalLogin($this->web_user);
+ $this->drupalGet('comment/reply/'. $this->node->nid);
+ $this->assertNoFieldByName('subject', '', t('Subject field not found.'));
+
+ // Set comments to have subject and preview to required.
+ $this->drupalLogout();
+ $this->drupalLogin($this->admin_user);
+ $this->setCommentSubject(TRUE);
+ $this->setCommentPreview(TRUE);
+ $this->drupalLogout();
+
+ // Create comment that requires preview.
+ $this->drupalLogin($this->web_user);
+ $comment = $this->postComment($this->node, $this->randomName(), $this->randomName());
+ $this->assertTrue($this->commentExists($comment), t('Comment found.'));
+
+ // Reply to comment.
+ $this->drupalGet('comment/reply/'. $this->node->nid .'/'. $comment->id);
+ $reply = $this->postComment(NULL, $this->randomName(), $this->randomName());
+ $this->assertTrue($this->commentExists($reply, TRUE), t('Reply found.'));
+
+ // Edit reply.
+ $this->drupalGet('comment/edit/'. $reply->id);
+ $reply = $this->postComment(NULL, $this->randomName(), $this->randomName());
+ $this->assertTrue($this->commentExists($reply, TRUE), t('Modified reply found.'));
+
+ // Delete comment and make sure that reply is also removed.
+ $this->drupalLogout();
+ $this->drupalLogin($this->admin_user);
+ $this->deleteComment($comment);
+
+ $this->drupalGet('node/'. $this->node->nid);
+ $this->assertFalse($this->commentExists($comment), t('Comment not found.'));
+ $this->assertFalse($this->commentExists($reply, TRUE), t('Reply not found.'));
+ }
+
+ /**
+ * Test comment form on node page.
+ */
+ function testFormOnPage() {
+ // Enabled comment form on node page.
+ $this->drupalLogin($this->admin_user);
+ $this->setCommentForm(TRUE);
+ $this->drupalLogout();
+
+ // Submit comment through node form.
+ $this->drupalLogin($this->web_user);
+ $this->drupalGet('node/'. $this->node->nid);
+ $form_comment = $this->postComment(NULL, $this->randomName(), $this->randomName());
+ $this->assertTrue($this->commentExists($form_comment), t('Form comment found.'));
+
+ // Disable comment form on node page.
+ $this->drupalLogout();
+ $this->drupalLogin($this->admin_user);
+ $this->setCommentForm(FALSE);
+ }
+
+ /**
+ * Test anonymous comment functionality.
+ */
+ function testAnonymous() {
+ $this->drupalLogin($this->admin_user);
+ // Enabled anonymous user comments.
+ $this->setAnonymousUserComment(TRUE, TRUE);
+ $this->setCommentAnonymous('0'); // Ensure that doesn't require contact info.
+ $this->drupalLogout();
+
+ // Post anonymous comment without contact info.
+ $anonymous_comment1 = $this->postComment($this->node, $this->randomName(), $this->randomName());
+ $this->assertTrue($this->commentExists($anonymous_comment1), t('Anonymous comment without contact info found.'));
+
+ // Allow contact info.
+ $this->drupalLogin($this->admin_user);
+ $this->setCommentAnonymous('1');
+ $this->drupalLogout();
+
+ // Post anonymous comment with contact info (optional).
+ $this->drupalGet('comment/reply/'. $this->node->nid);
+ $this->assertTrue($this->commentContactInfoAvailable(), t('Contact information available.'));
+
+ $anonymous_comment2 = $this->postComment($this->node, $this->randomName(), $this->randomName());
+ $this->assertTrue($this->commentExists($anonymous_comment2), t('Anonymous comment with contact info (optional) found.'));
+
+ // Require contact info.
+ $this->drupalLogin($this->admin_user);
+ $this->setCommentAnonymous('2');
+ $this->drupalLogout();
+
+ // Try to post comment with contact info (required).
+ $this->drupalGet('comment/reply/'. $this->node->nid);
+ $this->assertTrue($this->commentContactInfoAvailable(), t('Contact information available.'));
+
+ $anonymous_comment3 = $this->postComment($this->node, $this->randomName(), $this->randomName(), TRUE, TRUE);
+ $this->assertText(t('E-mail field is required.'), t('E-mail required.')); // Name should have 'Anonymous' for value by default.
+ $this->assertFalse($this->commentExists($anonymous_comment3), t('Anonymous comment with contact info (required) not found.'));
+
+ // Post comment with contact info (required).
+ $anonymous_comment3 = $this->postComment($this->node, $this->randomName(), $this->randomName(), FALSE, array('mail' => 'tester@simpletest.org'));
+ $this->assertTrue($this->commentExists($anonymous_comment3), t('Anonymous comment with contact info (required) found.'));
+
+ // Unpublish comment.
+ $this->drupalLogin($this->admin_user);
+ $this->performCommentOperation($anonymous_comment3, 'unpublish');
+
+ $this->drupalGet('admin/content/comment/approval');
+ $this->assertRaw('comments['. $anonymous_comment3->id .']', t('Comment was unpublished.'));
+
+ // Publish comment.
+ $this->performCommentOperation($anonymous_comment3, 'publish', TRUE);
+
+ $this->drupalGet('admin/content/comment');
+ $this->assertRaw('comments['. $anonymous_comment3->id .']', t('Comment was published.'));
+
+ // Delete comment.
+ $this->performCommentOperation($anonymous_comment3, 'delete');
+
+ $this->drupalGet('admin/content/comment');
+ $this->assertNoRaw('comments['. $anonymous_comment3->id .']', t('Comment was deleted.'));
+
+ // Set anonymouse comments to require approval.
+ $this->setAnonymousUserComment(TRUE, FALSE);
+ $this->setCommentAnonymous('0'); // Ensure that doesn't require contact info.
+ $this->drupalLogout();
+
+ // Post anonymous comment without contact info.
+ $subject = $this->randomName();
+ $body = $this->randomName();
+ $this->postComment($this->node, $subject, $body, TRUE, TRUE); // Set $contact to true so that it won't check for id and message.
+ $this->assertText(t('Your comment has been queued for moderation by site administrators and will be published after approval.'), t('Comment requires approval.'));
+
+ // Get unaproved comment id.
+ $this->drupalLogin($this->admin_user);
+ $anonymous_comment4 = $this->getUnaprovedComment($subject);
+ $anonymous_comment4 = (object) array('id' => $anonymous_comment4, 'subject' => $subject, 'comment' => $body);
+ $this->drupalLogout();
+
+ $this->assertFalse($this->commentExists($anonymous_comment4), t('Anonymous comment was not published.'));
+
+ // Approve comment.
+ $this->drupalLogin($this->admin_user);
+ $this->performCommentOperation($anonymous_comment4, 'publish', TRUE);
+ $this->drupalLogout();
+
+ $this->drupalGet('node/'. $this->node->nid);
+ $this->assertTrue($this->commentExists($anonymous_comment4), t('Anonymous comment visible.'));
+
+ // Reset.
+ $this->drupalLogin($this->admin_user);
+ $this->setAnonymousUserComment(FALSE, FALSE);
+ }
+
+ /**
+ * Post comment.
+ *
+ * @param object $node Node to post comment on.
+ * @param string $subject Comment subject.
+ * @param string $comment Comment body.
+ * @param boolean $preview Should preview be required.
+ * @param mixed $contact Set to NULL for no contact info, TRUE to ignore success checking, and array of values to set contact info.
+ */
+ function postComment($node, $subject, $comment, $preview = TRUE, $contact = NULL) {
+ $edit = array();
+ $edit['subject'] = $subject;
+ $edit['comment'] = $comment;
+ if ($contact !== NULL && is_array($contact)) {
+ $edit += $contact;
+ }
+ if ($node !== NULL) {
+ $this->drupalGet('comment/reply/'. $node->nid);
+ }
+ if ($preview) {
+ $this->assertNoFieldByName('op', t('Save'), t('Save button not found.')); // Preview required so no save button should be found.
+ $this->drupalPost(NULL, $edit, t('Preview'));
+ }
+ $this->drupalPost(NULL, $edit, t('Save'));
+
+ $match = array();
+ // Get comment ID
+ preg_match('/#comment-([^"]+)/', $this->getURL(), $match);
+ // get comment
+ if ($contact !== TRUE) { // If true then attempting to find error message.
+ $this->assertText($subject, 'Comment posted.');
+ $this->assertTrue((!empty($match) && !empty($match[1])), t('Comment id found.'));
+ }
+ if (isset($match[1])) {
+ return (object) array('id' => $match[1], 'subject' => $subject, 'comment' => $comment);
+ }
+ }
+
+ /**
+ * Checks current pag for specified comment.
+ *
+ * @param object $comment Comment object.
+ * @param boolean $reply The comment is a reply to another comment.
+ * @return boolean Comment found.
+ */
+ function commentExists($comment, $reply = FALSE) {
+ if ($comment && is_object($comment)) {
+ $regex = '/'. ($reply ? '<div class="indented">(.*?)' : '');
+ $regex .= '<a id="comment-'. $comment->id .'"(.*?)'; // Comment anchor.
+ $regex .= '<div(.*?)'; // Begin in comment div.
+ $regex .= $comment->subject .'(.*?)'; // Match subject.
+ $regex .= $comment->comment .'(.*?)'; // Match comment.
+ $regex .= '<\/div>/s'; // Dot matches newlines and ensure that match doesn't bleed outside comment div.
+ return preg_match($regex, $this->drupalGetContent());
+ }
+ else {
+ return FALSE;
+ }
+ }
+
+ /**
+ * Delete comment.
+ *
+ * @param object $comment Comment to delete.
+ */
+ function deleteComment($comment) {
+ $this->drupalPost('comment/delete/'. $comment->id, array(), t('Delete'));
+ $this->assertText(t('The comment and all its replies have been deleted.'), t('Comment deleted.'));
+ }
+
+ /**
+ * Set comment subject setting.
+ *
+ * @param boolean $enabled Subject value.
+ */
+ function setCommentSubject($enabled) {
+ $this->setCommentSettings('comment_subject_field', ($enabled ? '1' : '0'), 'Comment subject '. ($enabled ? 'enabled' : 'disabled') .'.');
+ }
+
+ /**
+ * Set comment preview setting.
+ *
+ * @param boolean $required Preview value.
+ */
+ function setCommentPreview($required) {
+ $this->setCommentSettings('comment_preview', ($required ? '1' : '0'), 'Comment preview '. ($required ? 'required' : 'optional') .'.');
+ }
+
+ /**
+ * Set comment form setting.
+ *
+ * @param boolean $enabled Form value.
+ */
+ function setCommentForm($enabled) {
+ $this->setCommentSettings('comment_form_location', ($enabled ? '1' : '3'), 'Comment controls '. ($enabled ? 'enabled' : 'disabled') .'.');
+ }
+
+ /**
+ * Set comment anonymous level setting.
+ *
+ * @param integer $level Anonymous level.
+ */
+ function setCommentAnonymous($level) {
+ $this->setCommentSettings('comment_anonymous', $level, 'Anonymous commenting set to level '. $level .'.');
+ }
+
+ /**
+ * Set comment setting for story content type.
+ *
+ * @param string $name Name of variable.
+ * @param string $vale Value of variable.
+ * @param string $message Status message to display.
+ */
+ function setCommentSettings($name, $value, $message) {
+ variable_set($name .'_story', $value);
+ $this->assertTrue(TRUE, t($message)); // Display status message.
+ }
+
+ /**
+ * Set anonymous comment setting.
+ *
+ * @param boolean $enabled Allow anonymous commenting.
+ * @param boolean $without_approval Allow anonymous commenting without approval.
+ */
+ function setAnonymousUserComment($enabled, $without_approval) {
+ $edit = array();
+ $edit['1[access comments]'] = $enabled;
+ $edit['1[post comments]'] = $enabled;
+ $edit['1[post comments without approval]'] = $without_approval;
+ $this->drupalPost('admin/user/permissions', $edit, t('Save permissions'));
+ $this->assertText(t('The changes have been saved.'), t('Anonymous user comments '. ($enabled ? 'enabled' : 'disabled') .'.'));
+ }
+
+ /**
+ * Check for contact info.
+ *
+ * @return boolean Contact info is avialable.
+ */
+ function commentContactInfoAvailable() {
+ return preg_match('/(input).*?(name="name").*?(input).*?(name="mail").*?(input).*?(name="homepage")/s', $this->drupalGetContent());
+ }
+
+ /**
+ * Perform the specified operation on the specified comment.
+ *
+ * @param object $comment Comment to perform operation on.
+ * @param string $operation Operation to perform.
+ * @param boolean $aproval Operation is found on approval page.
+ */
+ function performCommentOperation($comment, $operation, $approval = FALSE) {
+ $edit = array();
+ $edit['operation'] = $operation;
+ $edit['comments['. $comment->id .']'] = TRUE;
+ $this->drupalPost('admin/content/comment'. ($approval ? '/approval' : ''), $edit, t('Update'));
+
+ if ($operation == 'delete') {
+ $this->drupalPost(NULL, array(), t('Delete comments'));
+ $this->assertText(t('The comments have been deleted.'), t('Operation "'. $operation .'" was performed on comment.'));
+ }
+ else {
+ $this->assertText(t('The update has been performed.'), t('Operation "'. $operation .'" was performed on comment.'));
+ }
+ }
+
+ /**
+ * Get the comment id for an unaproved comment.
+ *
+ * @param string $subject Comment subject to find.
+ * @return integer Comment id.
+ */
+ function getUnaprovedComment($subject) {
+ $this->drupalGet('admin/content/comment/approval');
+ preg_match('/href="(.*?)#comment-([^"]+)"(.*?)>('. $subject .')/', $this->drupalGetContent(), $match);
+ return $match[2];
+ }
+}
diff --git a/modules/contact/contact.test b/modules/contact/contact.test
new file mode 100644
index 000000000..2372ad95b
--- /dev/null
+++ b/modules/contact/contact.test
@@ -0,0 +1,266 @@
+<?php
+// $Id$
+
+class ContactTestCase extends DrupalWebTestCase {
+ /**
+ * Implementation of getInfo().
+ */
+ function getInfo() {
+ return array(
+ 'name' => t('Contact functionality'),
+ 'description' => t('Test site-wide contact form and personal contact form functionality.'),
+ 'group' => t('Contact'),
+ );
+ }
+
+ /**
+ * Implementation of setUp().
+ */
+ function setUp() {
+ parent::setUp('contact');
+ }
+
+ /**
+ * Test configuration options and site-wide contact form.
+ */
+ function testSiteWideContact() {
+ // Create and login administative user.
+ $admin_user = $this->drupalCreateUser(array('administer site-wide contact form', 'administer permissions'));
+ $this->drupalLogin($admin_user);
+
+ // Set settings.
+ $edit = array();
+ $edit['contact_form_information'] = $this->randomName(100);
+ $edit['contact_hourly_threshold'] = 3;
+ $edit['contact_default_status'] = TRUE;
+ $this->drupalPost('admin/build/contact/settings', $edit, t('Save configuration'));
+ $this->assertText(t('The configuration options have been saved.'), t('Setting successfully saved.'));
+
+ $this->reloadVariables();
+
+ // Delete old categories to ensure that new categories are used.
+ $this->deleteCategories();
+
+ // Add categories.
+ // Test invalid recipients.
+ $invalid_recipients = array('invalid', 'invalid@', /*'invalid@site', 'invalid@site.',*/ '@site.', '@site.com');
+ foreach ($invalid_recipients as $invalid_recipient) {
+ $this->addCategory($this->randomName(16), $invalid_recipient, '', FALSE);
+ $this->assertRaw(t('%recipient is an invalid e-mail address.', array('%recipient' => $invalid_recipient)), t('Caught invalid recipient ('. $invalid_recipient .').'));
+ }
+
+ // Create valid categories.
+ $recipients = array('simpletest@test.com', 'simpletest2@test.com', 'simpletest3@test.com');
+ $this->addCategory($category = $this->randomName(16), implode(',', array($recipients[0])), '', TRUE);
+ $this->assertRaw(t('Category %category has been added.', array('%category' => $category)), t('Category successfully added.'));
+
+ $this->addCategory($category = $this->randomName(16), implode(',', array($recipients[0], $recipients[1])), '', FALSE);
+ $this->assertRaw(t('Category %category has been added.', array('%category' => $category)), t('Category successfully added.'));
+
+ $this->addCategory($category = $this->randomName(16), implode(',', array($recipients[0], $recipients[1], $recipients[2])), '', FALSE);
+ $this->assertRaw(t('Category %category has been added.', array('%category' => $category)), t('Category successfully added.'));
+
+ // Clear food table in preparation for flood test and allow other checks to complete.
+ $this->assertTrue(db_query('DELETE FROM {flood}'), t('Flood table emptied.'));
+
+ // Check to see that anonymous user cannot see contact page without permission.
+ $this->setPermission('anonymous user', array('access site-wide contact form' => FALSE));
+ $this->drupalLogout();
+
+ $this->drupalGet('contact');
+ $this->assertResponse(403, t('Access denied to anonymous user without permission.'));
+
+ // Give anonymous user permission and see that page is viewable.
+ $this->drupalLogin($admin_user);
+ $this->setPermission('anonymous user', array('access site-wide contact form' => TRUE));
+ $this->drupalLogout();
+
+ $this->drupalGet('contact');
+ $this->assertResponse(200, t('Access granted to anonymous user with permission.'));
+
+ // Check that "Additional information" is displayed on the page.
+ $this->assertText($edit['contact_form_information'], t('Contact information displayed.'));
+
+ // Submit contact form with invalid values.
+ $categories = $this->getCategories();
+ $this->submitContact('', $recipients[0], $this->randomName(16), $categories[0], $this->randomName(64));
+ $this->assertText(t('Your name field is required.'), t('Name required.'));
+
+ $this->submitContact($this->randomName(16), '', $this->randomName(16), $categories[0], $this->randomName(64));
+ $this->assertText(t('Your e-mail address field is required.'), t('E-mail required.'));
+
+ $this->submitContact($this->randomName(16), $invalid_recipients[0], $this->randomName(16), $categories[0], $this->randomName(64));
+ $this->assertText(t('You must enter a valid e-mail address.'), t('Valid e-mail required.'));
+
+ $this->submitContact($this->randomName(16), $recipients[0], '', $categories[0], $this->randomName(64));
+ $this->assertText(t('Subject field is required.'), t('Subject required.'));
+
+ $this->submitContact($this->randomName(16), $recipients[0], $this->randomName(16), $categories[0], '');
+ $this->assertText(t('Message field is required.'), t('Message required.'));
+
+ // Submit contact form with correct values and check flood interval.
+ for ($i = 0; $i < $edit['contact_hourly_threshold']; $i++) {
+ $this->submitContact($this->randomName(16), $recipients[0], $this->randomName(16), $categories[0], $this->randomName(64));
+ $this->assertText(t('Your message has been sent.'), t('Message sent.'));
+ }
+ // Submit contact form one over limit.
+ $this->drupalGet('contact');
+ $this->assertRaw(t('You cannot send more than %number messages per hour. Please try again later.', array('%number' => $edit['contact_hourly_threshold'])), t('Message threshold reached.'));
+
+ // Delete created categories.
+ $this->drupalLogin($admin_user);
+ $this->deleteCategories();
+ }
+
+ /**
+ * Test personal contact form.
+ */
+ function testPersonalContact() {
+ $admin_user = $this->drupalCreateUser(array('administer site-wide contact form'));
+ $this->drupalLogin($admin_user);
+
+ // Enable the personal contact form.
+ $edit = array();
+ $edit['contact_default_status'] = TRUE;
+ $this->drupalPost('admin/build/contact/settings', $edit, t('Save configuration'));
+ $this->assertText(t('The configuration options have been saved.'), t('Setting successfully saved.'));
+
+ // Reload variables.
+ $this->drupalLogout();
+ $this->reloadVariables();
+
+ // Create web users and attempt to use personal contact forms with default set to true.
+ $web_user1 = $this->drupalCreateUser(array());
+ $web_user2 = $this->drupalCreateUser(array());
+
+ $this->drupalLogin($web_user1);
+
+ $this->drupalGet('user/'. $web_user2->uid .'/contact');
+ $this->assertResponse(200, t('Access to personal contact form granted.'));
+
+ $edit = array();
+ $edit['subject'] = $this->randomName(16);
+ $edit['message'] = $this->randomName(64);
+ $this->drupalPost(NULL, $edit, t('Send e-mail'));
+ $this->assertText(t('The message has been sent.'), t('Message sent.'));
+
+ $this->drupalLogout();
+
+ $this->drupalLogin($admin_user);
+
+ // Disable the personal contact form.
+ $edit = array();
+ $edit['contact_default_status'] = FALSE;
+ $this->drupalPost('admin/build/contact/settings', $edit, t('Save configuration'));
+ $this->assertText(t('The configuration options have been saved.'), t('Setting successfully saved.'));
+
+ // Reload variables.
+ $this->drupalLogout();
+ $this->reloadVariables();
+
+ // Create web users and attempt to use personal contact forms with default set to false.
+ $web_user3 = $this->drupalCreateUser(array());
+ $web_user4 = $this->drupalCreateUser(array());
+
+ $this->drupalLogin($web_user3);
+
+ $this->drupalGet('user/'. $web_user4->uid .'/contact');
+ $this->assertResponse(403, t('Access to personal contact form denied.'));
+ }
+
+ /**
+ * Add a category.
+ *
+ * @param string $category Name of category.
+ * @param string $recipients List of recipient e-mail addresses.
+ * @param string $reply Auto-reply text.
+ * @param boolean $selected Defautly selected.
+ */
+ function addCategory($category, $recipients, $reply, $selected) {
+ $edit = array();
+ $edit['category'] = $category;
+ $edit['recipients'] = $recipients;
+ $edit['reply'] = $reply;
+ $edit['selected'] = ($selected ? '1' : '0');
+ $this->drupalPost('admin/build/contact/add', $edit, t('Save'));
+ }
+
+ /**
+ * Submit contact form.
+ *
+ * @param string $name Name.
+ * @param string $mail E-mail address.
+ * @param string $subject Subject.
+ * @param integer $cid Category id.
+ * @param string $message Message.
+ */
+ function submitContact($name, $mail, $subject, $cid, $message) {
+ $edit = array();
+ $edit['name'] = $name;
+ $edit['mail'] = $mail;
+ $edit['subject'] = $subject;
+ $edit['cid'] = $cid;
+ $edit['message'] = $message;
+ $this->drupalPost('contact', $edit, t('Send e-mail'));
+ }
+
+ /**
+ * Delete all categories.
+ */
+ function deleteCategories() {
+ $categories = $this->getCategories();
+ foreach ($categories as $category) {
+ $category_name = db_result(db_query('SELECT category FROM {contact} WHERE cid = %d', array($category)));
+ $this->drupalPost('admin/build/contact/delete/'. $category, array(), t('Delete'));
+ $this->assertRaw(t('Category %category has been deleted.', array('%category' => $category_name)), t('Category deleted sucessfully.'));
+ }
+ }
+
+ /**
+ * Get list category ids.
+ *
+ * @return array Category ids.
+ */
+ function getCategories() {
+ $result = db_query('SELECT cid FROM {contact}');
+ $categories = array();
+ while ($category = db_result($result)) {
+ $categories[] = $category;
+ }
+ return $categories;
+ }
+
+ /**
+ * Set permission.
+ *
+ * @param string $role User role to set permissions for.
+ * @param array $permissions Key-value array of permissions to set.
+ */
+ function setPermission($role, $permissions) {
+ // Get role id (rid) for specified role.
+ $rid = db_result(db_query("SELECT rid FROM {role} WHERE name = '%s'", array($role)));
+ if ($rid === FALSE) {
+ $this->fail(t(' [permission] Role "'. $role .'" not found.'));
+ }
+
+ // Create edit array from permission.
+ $edit = array();
+ foreach ($permissions as $name => $value) {
+ $edit[$rid .'['. $name .']'] = $value;
+ }
+
+ $this->drupalPost('admin/user/permissions', $edit, t('Save permissions'));
+ $this->assertText(t('The changes have been saved.'), t(' [permission] Saved changes.'));
+ }
+
+ /**
+ * Reload variables table.
+ */
+ function reloadVariables() {
+ global $conf;
+
+ cache_clear_all('variables', 'cache');
+ $conf = variable_init();
+ $this->assertTrue($conf, t('Variables reloaded.'));
+ }
+}
diff --git a/modules/dblog/dblog.test b/modules/dblog/dblog.test
new file mode 100644
index 000000000..75faadd82
--- /dev/null
+++ b/modules/dblog/dblog.test
@@ -0,0 +1,370 @@
+<?php
+// $Id$
+
+class DBLogTestCase extends DrupalWebTestCase {
+ protected $big_user;
+ protected $any_user;
+
+ /**
+ * Implementation of getInfo().
+ */
+ function getInfo() {
+ return array(
+ 'name' => t('DBLog functionality'),
+ 'description' => t('Generate events and verify dblog entries; verify user access to log reports based on persmissions.'),
+ 'group' => t('DBLog'),
+ );
+ }
+
+ /**
+ * Enable modules and create users with specific permissions.
+ */
+ function setUp() {
+ parent::setUp('dblog', 'blog', 'poll');
+ // Create users.
+ $this->big_user = $this->drupalCreateUser(array('administer site configuration', 'access administration pages', 'access site reports', 'administer users'));
+ $this->any_user = $this->drupalCreateUser(array());
+ }
+
+ /**
+ * Login users, create dblog events, and test dblog functionality through the admin and user interfaces.
+ */
+ function testDBLog() {
+ // Login the admin user.
+ $this->drupalLogin($this->big_user);
+
+ $row_limit = 100;
+ $this->verifyRowLimit($row_limit);
+ $this->verifyCron($row_limit);
+ $this->verifyEvents();
+ $this->verifyReports();
+
+ // Login the regular user.
+ $user = $this->drupalLogin($this->any_user);
+ $this->verifyReports(403);
+ }
+
+ /**
+ * Verify setting of the dblog row limit.
+ *
+ * @param integer $count Log row limit.
+ */
+ private function verifyRowLimit($row_limit) {
+ // Change the dblog row limit.
+ $edit = array();
+ $edit['dblog_row_limit'] = $row_limit;
+ $this->drupalPost('admin/settings/logging/dblog', $edit, t('Save configuration'));
+ $this->assertResponse(200);
+ // Reload variable cache (since the global $conf array was changed in another "process" when the settings page above was posted).
+ $this->reloadVariables();
+ // Check row limit variable.
+ $current_limit = variable_get('dblog_row_limit', 1000);
+ $this->assertTrue($current_limit == $row_limit, t('[Cache] Row limit variable of @count equals row limit of @limit', array('@count' => $current_limit, '@limit' => $row_limit)));
+ // Verify dblog row limit equals specified row limit.
+ $current_limit = unserialize(db_result(db_query("SELECT value FROM {variable} WHERE name = '%s'", 'dblog_row_limit')));
+ $this->assertTrue($current_limit == $row_limit, t('[Variable table] Row limit variable of @count equals row limit of @limit', array('@count' => $current_limit, '@limit' => $row_limit)));
+ }
+
+ /**
+ * Verify cron applies the dblog row limit.
+ *
+ * @param integer $count Log row limit.
+ */
+ private function verifyCron($row_limit) {
+ // Generate additional log entries.
+ $this->generateLogEntries($row_limit + 10);
+ // Verify dblog row count exceeds row limit.
+ $count = db_result(db_query('SELECT COUNT(wid) FROM {watchdog}'));
+ $this->assertTrue($count > $row_limit, t('Dblog row count of @count exceeds row limit of @limit', array('@count' => $count, '@limit' => $row_limit)));
+
+ // Run cron job.
+ $this->drupalGet('admin/reports/status/run-cron');
+ $this->assertResponse(200);
+ $this->assertText(t('Cron ran successfully'), t('Cron ran successfully'));
+ // Verify dblog row count equals row limit plus one because cron adds a record after it runs.
+ $count = db_result(db_query('SELECT COUNT(wid) FROM {watchdog}'));
+ $this->assertTrue($count == $row_limit + 1, t('Dblog row count of @count equals row limit of @limit plus one', array('@count' => $count, '@limit' => $row_limit)));
+ }
+
+ /**
+ * Generate dblog entries.
+ *
+ * @param integer $count Log row limit.
+ */
+ private function generateLogEntries($count) {
+ global $base_root;
+
+ // Prepare the fields to be logged
+ $log = array(
+ 'type' => 'custom',
+ 'message' => 'Log entry added to test the dblog row limit.',
+ 'variables' => array(),
+ 'severity' => WATCHDOG_NOTICE,
+ 'link' => NULL,
+ 'user' => $this->big_user,
+ 'request_uri' => $base_root . request_uri(),
+ 'referer' => referer_uri(),
+ 'ip' => ip_address(),
+ 'timestamp' => time(),
+ );
+ $message = 'Log entry added to test the dblog row limit.';
+ for ($i = 0; $i < $count; $i++) {
+ $log['message'] = $i. ' => ' .$message;
+ dblog_watchdog($log);
+ }
+ }
+
+ /**
+ * Verify the logged in user has the desired access to the various dblog nodes.
+ *
+ * @param integer $response HTTP response code.
+ */
+ private function verifyReports($response = 200) {
+ $quote = '&#039;';
+
+ // View dblog help node.
+ $this->drupalGet('admin/help/dblog');
+ $this->assertResponse($response);
+ if ($response == 200) {
+ $this->assertText(t('Database logging'), t('DBLog help was displayed'));
+ }
+
+ // View dblog report node.
+ $this->drupalGet('admin/reports/dblog');
+ $this->assertResponse($response);
+ if ($response == 200) {
+ $this->assertText(t('Recent log entries'), t('DBLog report was displayed'));
+ }
+
+ // View dblog page-not-found report node.
+ $this->drupalGet('admin/reports/page-not-found');
+ $this->assertResponse($response);
+ if ($response == 200) {
+ $this->assertText(t('Top '. $quote .'page not found'. $quote .' errors'), t('DBLog page-not-found report was displayed'));
+ }
+
+ // View dblog access-denied report node.
+ $this->drupalGet('admin/reports/access-denied');
+ $this->assertResponse($response);
+ if ($response == 200) {
+ $this->assertText(t('Top '. $quote .'access denied'. $quote .' errors'), t('DBLog access-denied report was displayed'));
+ }
+
+ // View dblog event node.
+ $this->drupalGet('admin/reports/event/1');
+ $this->assertResponse($response);
+ if ($response == 200) {
+ $this->assertText(t('Details'), t('DBLog event node was displayed'));
+ }
+ }
+
+ /**
+ * Verify events.
+ */
+ private function verifyEvents() {
+ // Invoke events.
+ $this->doUser();
+ $this->doNode('article');
+ $this->doNode('blog');
+ $this->doNode('page');
+ $this->doNode('poll');
+
+ // When a user is deleted, any content they created remains but the uid = 0. Their blog entry shows as "'s blog" on the home page.
+ // Records in the watchdog table related to that user have the uid set to zero.
+ }
+
+ /**
+ * Generate and verify user events.
+ *
+ */
+ private function doUser()
+ {
+ // Set user variables.
+ $name = $this->randomName();
+ $pass = user_password();
+ // Add user using form to generate add user event (which is not triggered by drupalCreateUser).
+ $edit = array();
+ $edit['name'] = $name;
+ $edit['mail'] = $name .'@example.com';
+ $edit['pass[pass1]'] = $pass;
+ $edit['pass[pass2]'] = $pass;
+ $edit['status'] = 1;
+ $this->drupalPost('admin/user/user/create', $edit, t('Create new account'));
+ $this->assertResponse(200);
+ // Retrieve user object.
+ $user = user_load(array('name' => $name)); //, 'pass' => $pass, 'status' => 1));
+ $this->assertTrue($user != null, t('User @name was loaded', array('@name' => $name)));
+ $user->pass_raw = $pass; // Needed by drupalLogin.
+ // Login user.
+ $this->drupalLogin($user);
+ // Logout user.
+ $this->drupalLogout();
+ // Fetch row ids in watchdog that relate to the user.
+ $result = db_query('SELECT wid FROM {watchdog} WHERE uid = %d', $user->uid);
+ while ($row = db_fetch_array($result)) {
+ $ids[] = $row['wid'];
+ }
+ $count_before = (isset($ids)) ? count($ids) : 0;
+ $this->assertTrue($count_before > 0, t('DBLog contains @count records for @name', array('@count' => $count_before, '@name' => $user->name)));
+ // Delete user.
+ user_delete(array(), $user->uid);
+ // Count rows that have uids for the user.
+ $count = db_result(db_query('SELECT COUNT(wid) FROM {watchdog} WHERE uid = %d', $user->uid));
+ $this->assertTrue($count == 0, t('DBLog contains @count records for @name', array('@count' => $count, '@name' => $user->name)));
+ // Fetch row ids in watchdog that previously related to the deleted user.
+ $result = db_query('SELECT wid FROM {watchdog} WHERE uid = 0 AND wid IN (%s)', implode(', ', $ids));
+ unset($ids);
+ while ($row = db_fetch_array($result)) {
+ $ids[] = $row['wid'];
+ }
+ $count_after = (isset($ids)) ? count($ids) : 0;
+ $this->assertTrue($count_after == $count_before, t('DBLog contains @count records for @name that now have uid = 0', array('@count' => $count_before, '@name' => $user->name)));
+ unset($ids);
+ // Fetch row ids in watchdog that relate to the user.
+ $result = db_query('SELECT wid FROM {watchdog} WHERE uid = %d', $user->uid);
+ while ($row = db_fetch_array($result)) {
+ $ids[] = $row['wid'];
+ }
+ $this->assertTrue(!isset($ids), t('DBLog contains no records for @name', array('@name' => $user->name)));
+
+ // Login the admin user.
+ $this->drupalLogin($this->big_user);
+ // View the dblog report.
+ $this->drupalGet('admin/reports/dblog');
+ $this->assertResponse(200);
+
+ // Verify events were recorded.
+ // Add user.
+ // Default display includes name and email address; if too long then email is replaced by three periods.
+ // $this->assertRaw(t('New user: %name (%mail)', array('%name' => $edit['name'], '%mail' => $edit['mail'])), t('DBLog event was recorded: [add user]'));
+ $this->assertRaw(t('New user: %name', array('%name' => $name)), t('DBLog event was recorded: [add user]'));
+ // Login user.
+ $this->assertRaw(t('Session opened for %name', array('%name' => $name)), t('DBLog event was recorded: [login user]'));
+ // Logout user.
+ $this->assertRaw(t('Session closed for %name', array('%name' => $name)), t('DBLog event was recorded: [logout user]'));
+ // Delete user.
+ $this->assertRaw(t('Deleted user: %name', array('%name' => $name)), t('DBLog event was recorded: [delete user]'));
+ }
+
+ /**
+ * Generate and verify node events.
+ *
+ * @param string $type Content type.
+ */
+ private function doNode($type) {
+ // Create user.
+ $perm = array('create '. $type .' content', 'edit own '. $type .' content', 'delete own '. $type .' content');
+ $user = $this->drupalCreateUser($perm);
+ // Login user.
+ $this->drupalLogin($user);
+
+ // Create node using form to generate add content event (which is not triggered by drupalCreateNode).
+ $edit = $this->getContent($type);
+ $title = $edit['title'];
+ $this->drupalPost('node/add/'. $type, $edit, t('Save'));
+ $this->assertResponse(200);
+ // Retrieve node object.
+ $node = node_load(array('title' => $title));
+ $this->assertTrue($node != null, t('Node @title was loaded', array('@title' => $title)));
+ // Edit node.
+ $edit = $this->getContentUpdate($type);
+ $this->drupalPost('node/'. $node->nid .'/edit', $edit, t('Save'));
+ $this->assertResponse(200);
+ // Delete node.
+ $this->drupalPost('node/'. $node->nid .'/delete', array(), t('Delete'));
+ $this->assertResponse(200);
+ // View node (to generate page not found event).
+ $this->drupalGet('node/'. $node->nid);
+ $this->assertResponse(404);
+ // View the dblog report (to generate access denied event).
+ $this->drupalGet('admin/reports/dblog');
+ $this->assertResponse(403);
+
+ // Login the admin user.
+ $this->drupalLogin($this->big_user);
+ // View the dblog report.
+ $this->drupalGet('admin/reports/dblog');
+ $this->assertResponse(200);
+
+ // Verify events were recorded.
+ // Content added.
+ $this->assertRaw(t('@type: added %title', array('@type' => $type, '%title' => $title)), t('DBLog event was recorded: [content added]'));
+ // Content updated.
+ $this->assertRaw(t('@type: updated %title', array('@type' => $type, '%title' => $title)), t('DBLog event was recorded: [content updated]'));
+ // Content deleted.
+ $this->assertRaw(t('@type: deleted %title', array('@type' => $type, '%title' => $title)), t('DBLog event was recorded: [content deleted]'));
+
+ // View dblog access-denied report node.
+ $this->drupalGet('admin/reports/access-denied');
+ $this->assertResponse(200);
+ // Access denied.
+ $this->assertText(t('admin/reports/dblog'), t('DBLog event was recorded: [access denied]'));
+
+ // View dblog page-not-found report node.
+ $this->drupalGet('admin/reports/page-not-found');
+ $this->assertResponse(200);
+ // Page not found.
+ $this->assertText(t('node/@nid', array('@nid' => $node->nid)), t('DBLog event was recorded: [page not found]'));
+ }
+
+ /**
+ * Create content based on content type.
+ *
+ * @param string $type Content type.
+ * @return array Content.
+ */
+ private function getContent($type) {
+ switch ($type) {
+ case 'poll':
+ $content = array(
+ 'title' => $this->randomName(8),
+ 'choice[0][chtext]' => $this->randomName(32),
+ 'choice[1][chtext]' => $this->randomName(32),
+ );
+ break;
+
+ default:
+ $content = array(
+ 'title' => $this->randomName(8),
+ 'body' => $this->randomName(32),
+ );
+ break;
+ }
+ return $content;
+ }
+
+ /**
+ * Create content update based on content type.
+ *
+ * @param string $type Content type.
+ * @return array Content.
+ */
+ private function getContentUpdate($type) {
+ switch ($type) {
+ case 'poll':
+ $content = array(
+ 'choice[0][chtext]' => $this->randomName(32),
+ 'choice[1][chtext]' => $this->randomName(32),
+ );
+ break;
+
+ default:
+ $content = array(
+ 'body' => $this->randomName(32),
+ );
+ break;
+ }
+ return $content;
+ }
+
+ /**
+ * Reload variables table.
+ */
+ private function reloadVariables() {
+ global $conf;
+
+ cache_clear_all('variables', 'cache');
+ $conf = variable_init();
+ $this->assertTrue($conf, t('Variables reloaded'));
+ }
+}
diff --git a/modules/filter/filter.test b/modules/filter/filter.test
new file mode 100644
index 000000000..a18582ac4
--- /dev/null
+++ b/modules/filter/filter.test
@@ -0,0 +1,182 @@
+<?php
+// $Id$
+
+class FilterTestCase extends DrupalWebTestCase {
+ /**
+ * Implementation of getInfo().
+ */
+ function getInfo() {
+ return array(
+ 'name' => t('Filter administration functionality'),
+ 'description' => t('Thoroughly test the administrative interface of the filter module.'),
+ 'group' => t('Filter'),
+ );
+ }
+
+ /**
+ * Test filter administration functionality.
+ */
+ function testFilter() {
+ $first_filter = 2; // URL filter.
+ $second_filter = 1; // Line filter.
+
+ // Create users.
+ $admin_user = $this->drupalCreateUser(array('administer filters'));
+ $web_user = $this->drupalCreateUser(array('create page content'));
+
+ $this->drupalLogin($admin_user);
+
+ list($filtered, $full) = $this->checkFilterFormats();
+
+ // Change default filter.
+ $edit = array();
+ $edit['default'] = $full;
+ $this->drupalPost('admin/settings/filters', $edit, t('Save changes'));
+ $this->assertText(t('Default format updated.'), t('Default filter updated successfully.'));
+
+ $this->assertNoRaw('admin/settings/filters/delete/'. $full, t('Delete link not found.'));
+
+ // Add an additional tag.
+ $edit = array();
+ $edit['allowed_html_1'] = '<a> <em> <strong> <cite> <code> <ul> <ol> <li> <dl> <dt> <dd>'.' <quote>'; // Adding <quote> tag.
+ $this->drupalPost('admin/settings/filters/'. $filtered .'/configure', $edit, t('Save configuration'));
+ $this->assertText(t('The configuration options have been saved.'), t('Allowed HTML tag added.'));
+
+ $this->assertRaw(htmlentities($edit['allowed_html_1']), t('Tag displayed.'));
+
+ $result = db_fetch_object(db_query('SELECT * FROM {cache_filter}'));
+ $this->assertFalse($result, t('Cache cleared.'));
+
+ // Reorder filters.
+ $edit = array();
+ $edit['weights[filter/'. $second_filter .']'] = 1;
+ $edit['weights[filter/'. $first_filter .']'] = 2;
+ $this->drupalPost('admin/settings/filters/'. $filtered .'/order', $edit, t('Save configuration'));
+ $this->assertText(t('The filter ordering has been saved.'), t('Order saved successfully.'));
+
+ $result = db_query('SELECT * FROM {filters} WHERE format = %d ORDER BY weight ASC', $filtered);
+ $filters = array();
+ while ($filter = db_fetch_object($result)) {
+ if ($filter->delta == $second_filter || $filter->delta == $first_filter) {
+ $filters[] = $filter;
+ }
+ }
+ $this->assertTrue(($filters[0]->delta == $second_filter && $filters[1]->delta == $first_filter), t('Order confirmed.'));
+
+ // Add filter.
+ $edit = array();
+ $edit['name'] = $this->randomName();
+ $edit['roles[2]'] = TRUE;
+ $edit['filters[filter/'. $second_filter .']'] = TRUE;
+ $edit['filters[filter/'. $first_filter .']'] = TRUE;
+ $this->drupalPost('admin/settings/filters/add', $edit, t('Save configuration'));
+ $this->assertRaw(t('Added input format %format.', array('%format' => $edit['name'])), t('New filter created.'));
+
+ $format = $this->getFilter($edit['name']);
+ $this->assertNotNull($format, t('Format found in database.'));
+
+ if ($format !== NULL) {
+ $this->assertFieldByName('roles[2]', '', t('Role found.'));
+ $this->assertFieldByName('filters[filter/'. $second_filter .']', '', t('Line break filter found.'));
+ $this->assertFieldByName('filters[filter/'. $first_filter .']', '', t('Url filter found.'));
+
+ // Delete new filter.
+ $this->drupalPost('admin/settings/filters/delete/'. $format->format, array(), t('Delete'));
+ $this->assertRaw(t('Deleted input format %format.', array('%format' => $edit['name'])), t('Format successfully deleted.'));
+ }
+
+ // Change default filter back.
+ $edit = array();
+ $edit['default'] = $filtered;
+ $this->drupalPost('admin/settings/filters', $edit, t('Save changes'));
+ $this->assertText(t('Default format updated.'), t('Default filter updated successfully.'));
+
+ $this->assertNoRaw('admin/settings/filters/delete/'. $filtered, t('Delete link not found.'));
+
+ // Allow authenticated users on full HTML.
+ $edit = array();
+ $edit['roles[2]'] = TRUE;
+ $this->drupalPost('admin/settings/filters/'. $full, $edit, t('Save configuration'));
+ $this->assertText(t('The input format settings have been updated.'), t('Full HTML format successfully updated.'));
+
+ // Switch user.
+ $this->drupalLogout();
+ $this->drupalLogin($web_user);
+
+ $this->drupalGet('node/add/page');
+ $this->assertFieldByName('format', $full, t('Full HTML filter accessible.'));
+
+ // Use filtered HTML and see if it removes tags that arn't allowed.
+ $body = $this->randomName();
+ $extra_text = 'text';
+
+ $edit = array();
+ $edit['title'] = $this->randomName();
+ $edit['body'] = $body .'<random>'. $extra_text .'</random>';
+ $edit['format'] = $filtered;
+ $this->drupalPost('node/add/page', $edit, t('Save'));
+ $this->assertRaw(t('Page %title has been created.', array('%title' => $edit['title'])), t('Filtered node created.'));
+
+ $node = node_load(array('title' => $edit['title']));
+ $this->assertTrue($node, t('Node found in database.'));
+
+ $this->drupalGet('node/'. $node->nid);
+ $this->assertText($body . $extra_text, t('Filter removed invalid tag.'));
+
+ // Switch user.
+ $this->drupalLogout();
+ $this->drupalLogin($admin_user);
+
+ // Clean up.
+ // Allowed tags
+ $edit = array();
+ $edit['allowed_html_1'] = '<a> <em> <strong> <cite> <code> <ul> <ol> <li> <dl> <dt> <dd>';
+ $this->drupalPost('admin/settings/filters/'. $filtered .'/configure', $edit, t('Save configuration'));
+ $this->assertText(t('The configuration options have been saved.'), t('Changes reverted.'));
+
+ // Full HTML
+ $edit = array();
+ $edit['roles[2]'] = FALSE;
+ $this->drupalPost('admin/settings/filters/'. $full, $edit, t('Save configuration'));
+ $this->assertText(t('The input format settings have been updated.'), t('Full HTML format successfully reverted.'));
+
+ // Filter order
+ $edit = array();
+ $edit['weights[filter/'. $second_filter .']'] = 2;
+ $edit['weights[filter/'. $first_filter .']'] = 1;
+ $this->drupalPost('admin/settings/filters/'. $filtered .'/order', $edit, t('Save configuration'));
+ $this->assertText(t('The filter ordering has been saved.'), t('Order successfully reverted.'));
+ }
+
+ /**
+ * Query the database to get the two basic formats.
+ *
+ * @return Array Array containing filtered and full filter ids.
+ */
+ function checkFilterFormats() {
+ $result = db_query('SELECT format, name FROM {filter_formats}');
+
+ $filtered = -1;
+ $full = -1;
+ while ($format = db_fetch_object($result)) {
+ if ($format->name == 'Filtered HTML') {
+ $filtered = $format->format;
+ }
+ else if ($format->name == 'Full HTML') {
+ $full = $format->format;
+ }
+ }
+
+ return array($filtered, $full);
+ }
+
+ /**
+ * Get filter by name.
+ *
+ * @param string $name Name of filter to find.
+ * @return object Filter object.
+ */
+ function getFilter($name) {
+ return db_fetch_object(db_query("SELECT * FROM {filter_formats} WHERE name = '%s'", $name));
+ }
+}
diff --git a/modules/forum/forum.test b/modules/forum/forum.test
new file mode 100644
index 000000000..a92fa190a
--- /dev/null
+++ b/modules/forum/forum.test
@@ -0,0 +1,398 @@
+<?php
+// $Id$
+
+class ForumTestCase extends DrupalWebTestCase {
+ protected $big_user;
+ protected $own_user;
+ protected $any_user;
+ protected $nid_user;
+ protected $container;
+ protected $forum;
+ protected $root_forum;
+ protected $nids;
+
+ /**
+ * Implementation of getInfo().
+ */
+ function getInfo() {
+ return array(
+ 'name' => t('Forum functionality'),
+ 'description' => t('Create, view, edit, delete, and change forum entries and verify its consistency in the database.'),
+ 'group' => t('Forum'),
+ );
+ }
+
+ /**
+ * Enable modules and create users with specific permissions.
+ */
+ function setUp() {
+ parent::setUp('taxonomy', 'comment', 'forum');
+ // Create users.
+ $this->big_user = $this->drupalCreateUser(array('administer blocks', 'administer forums', 'administer menu', 'administer taxonomy', 'create forum content')); // 'access administration pages'));
+ $this->own_user = $this->drupalCreateUser(array('create forum content', 'edit own forum content', 'delete own forum content'));
+ $this->any_user = $this->drupalCreateUser(array('create forum content', 'edit any forum content', 'delete any forum content', 'access administration pages'));
+ $this->nid_user = $this->drupalCreateUser(array());
+ }
+
+ /**
+ * Login users, create forum nodes, and test forum functionality through the admin and user interfaces.
+ */
+ function testForum() {
+ // Do the admin tests.
+ $this->doAdminTests($this->big_user);
+ // Generate topics to populate the active forum block.
+ $this->generateForumTopics($this->forum);
+
+ // Login the nid user to view the forum topics and generate an Active forum topics list (FAILS).
+ $this->drupalLogin($this->nid_user);
+ // View the forum topics.
+ $this->viewForumTopics($this->nids);
+
+ // Do basic tests for the any forum user.
+ $this->doBasicTests($this->any_user, TRUE);
+ // Create another forum node for the any forum user.
+// $node = $this->drupalCreateNode(array('type' => 'forum', 'uid' => $this->any_user->uid));
+ $node = $this->createForumTopic($this->forum, FALSE);
+
+ // Do basic tests for the own forum user.
+ $this->doBasicTests($this->own_user, FALSE);
+ // Verify the own forum user only has access to the forum view node.
+ $this->verifyForums($this->any_user, $node, FALSE, 403);
+ // Create another forum node for the own forum user.
+// $node = $this->drupalCreateNode(array('type' => 'forum', 'uid' => $this->own_user->uid));
+ $node = $this->createForumTopic($this->forum, FALSE);
+
+ // Login the any forum user.
+ $this->drupalLogin($this->any_user);
+ // Verify the any forum user has access to all the forum nodes.
+ $this->verifyForums($this->own_user, $node, TRUE);
+ }
+
+ /**
+ * Run admin tests on the admin user.
+ *
+ * @param object $user The logged in user.
+ */
+ private function doAdminTests($user) {
+ // Login the user.
+ $this->drupalLogin($user);
+
+ // Enable the active forum block.
+ $edit = array();
+ $edit['forum_active[region]'] = 'right';
+ $this->drupalPost('admin/build/block', $edit, t('Save blocks'));
+ $this->assertResponse(200);
+ $this->assertText(t('The block settings have been updated.'), t('[Active forum topics] Forum block was enabled'));
+
+ // Enable the new forum block.
+ $edit = array();
+ $edit['forum_new[region]'] = 'right';
+ $this->drupalPost('admin/build/block', $edit, t('Save blocks'));
+ $this->assertResponse(200);
+ $this->assertText(t('The block settings have been updated.'), t('[New forum topics] Forum block was enabled'));
+
+ // Retrieve forum menu id.
+ $mlid = db_result(db_query_range("SELECT mlid FROM {menu_links} WHERE link_path = 'forum' AND menu_name = 'navigation' AND module = 'system' ORDER BY mlid ASC", 0, 1));
+
+ // Add forum to navigation menu.
+ $edit = array();
+ $edit['mlid:'. $mlid .'[hidden]'] = TRUE;
+ $this->drupalPost('admin/build/menu-customize/navigation', $edit, t('Save configuration'));
+ $this->assertResponse(200);
+
+ // Edit forum taxonomy.
+ // Restoration of the settings fails and causes subsequent tests to fail.
+ $this->container = $this->editForumTaxonomy();
+ // Create forum container.
+ $this->container = $this->createForum('container');
+ // Create forum inside the forum container.
+ $this->forum = $this->createForum('forum', $this->container['tid']);
+ // Create forum at the top (root) level.
+ $this->root_forum = $this->createForum('forum');
+ }
+
+ /**
+ * Edit the forum taxonomy.
+ *
+ */
+ function editForumTaxonomy() {
+ // Backup forum taxonomy.
+ $vid = variable_get('forum_nav_vocabulary', '');
+ // This function returns NULL (the cache value is false).
+// $original_settings = taxonomy_vocabulary_load($vid);
+ $original_settings = db_fetch_array(db_query('SELECT v.* FROM {vocabulary} v WHERE v.vid = %d', $vid));
+
+ // Generate a random name/description.
+ $title = $this->randomName(10);
+ $description = $this->randomName(100);
+
+ $edit = array(
+ 'name' => $title,
+ 'description' => $description,
+ 'help' => '',
+ 'weight' => -10
+ );
+
+ // Edit the vocabulary.
+ $this->drupalPost('admin/content/taxonomy/edit/vocabulary/'. $vid, $edit, t('Save'));
+ $this->assertResponse(200);
+ $this->assertRaw(t('Updated vocabulary %name.', array('%name' => $title)), t('Vocabulary was edited'));
+
+ // Grab the newly edited vocabulary.
+ $cur_settings = db_fetch_array(db_query('SELECT v.* FROM {vocabulary} v WHERE v.vid = %d', $vid));
+
+ // Make sure we actually edited the vocabulary properly.
+ $this->assertTrue($cur_settings['name'] == $title, 'The name was updated');
+ $this->assertTrue($cur_settings['description'] == $description, 'The description was updated');
+
+ // Restore the name/description.
+ $title = $original_settings['name'];
+ $description = $original_settings['description'];
+ $description = ($description == NULL) ? '' : $description;
+
+ $edit = array(
+ 'name' => $title,
+ 'description' => $description,
+ 'help' => '',
+ 'weight' => -10
+ );
+
+ // Edit the vocabulary.
+ $this->drupalPost('admin/content/taxonomy/edit/vocabulary/'. $vid, $edit, t('Save'));
+ $this->assertResponse(200);
+ $this->assertRaw(t('Updated vocabulary %name.', array('%name' => $title)), t('Vocabulary was edited'));
+/*
+ // Verify original forum taxonomy.
+ $original_settings = (array) $original_settings;
+ taxonomy_save_vocabulary($original_settings); // This fails because taxonomy_vocabulary_load returns NULL.
+ $cur_settings = db_fetch_array(db_query('SELECT v.* FROM {vocabulary} v WHERE v.vid = %d', $vid));
+ $this->assertTrue($cur_settings['name'] == $original_settings['name'], 'The name was restored');
+ $this->assertTrue(!isset($cur_settings['description']), 'The description was restored');
+*/
+ }
+
+ /**
+ * Create a forum container or a forum.
+ *
+ * @param string $type Forum type (forum container or forum).
+ * @param integer $parent Forum parent (default = 0 = a root forum; >0 = a forum container or another forum).
+ * @return object Term_data created.
+ */
+ function createForum($type, $parent = 0) {
+ // Generate a random name/description.
+ $name = $this->randomName(10);
+ $description = $this->randomName(100);
+
+ $edit = array(
+ 'name' => $name,
+ 'description' => $description,
+ 'parent[0]' => $parent,
+ 'weight' => '0',
+ );
+
+ // Create forum.
+ $this->drupalPost('admin/content/forum/add/'. $type, $edit, t('Save'));
+ $this->assertResponse(200);
+ $type = ($type == 'container') ? 'forum container' : 'forum';
+ $this->assertRaw(t('Created new @type %term.', array('%term' => $name, '@type' => t($type))), t(ucfirst($type) .' was created'));
+
+ // Verify forum.
+ $term = db_fetch_array(db_query("SELECT * FROM {term_data} t WHERE t.vid = %d AND t.name = '%s' AND t.description = '%s'", variable_get('forum_nav_vocabulary', ''), $name, $description));
+ $this->assertTrue(!empty($term), 'The '. $type .' exists in the database');
+
+ // Verify forum hierarchy.
+ $tid = $term['tid'];
+ $parent_tid = db_result(db_query("SELECT t.parent FROM {term_hierarchy} t WHERE t.tid = %d", $tid));
+ $this->assertTrue($parent == $parent_tid, 'The '. $type .' is linked to its container');
+
+ return $term;
+ }
+
+ /**
+ * Run basic tests on the indicated user.
+ *
+ * @param object $user The logged in user.
+ * @param boolean $admin User has 'access administration pages' privilege.
+ */
+ private function doBasicTests($user, $admin) {
+ // Login the user.
+ $this->drupalLogin($user);
+ // Attempt to create forum topic under a container.
+ $this->createForumTopic($this->container, TRUE);
+ // Create forum node.
+ $node = $this->createForumTopic($this->forum, FALSE);
+ // Verify the user has access to all the forum nodes.
+ $this->verifyForums($user, $node, $admin);
+ }
+
+ /**
+ * Create forum topic.
+ *
+ * @param array $forum Forum array.
+ * @param boolean $container True if $forum is a container.
+ * @return object Topic node created.
+ */
+ function createForumTopic($forum, $container = FALSE) {
+ // Generate a random subject/body.
+ $title = $this->randomName(20);
+ $body = $this->randomName(200);
+ $tid = $forum['tid']; // Without this being set, post variable equals the first non-blank in select items list.
+
+ $edit = array(
+ 'title' => $title,
+ 'body' => $body,
+ 'taxonomy[1]' => $tid
+ );
+
+ // TODO The taxonomy select value is set by drupal code when the tid is part of the url.
+ // However, unless a tid is passed in the edit array, when drupalPost runs, the select value is not preserved.
+ // Instead, the post variables seem to pick up the first non-blank value in the select list.
+
+ // Create forum topic.
+// $this->drupalPost('node/add/forum/'. $forum['tid'], $edit, t('Save'));
+ $this->drupalPost('node/add/forum/', $edit, t('Save'));
+ $type = t('Forum topic');
+ if ($container) {
+ $this->assertNoRaw(t('@type %title has been created.', array('@type' => $type, '%title' => $title)), t('Forum topic was not created'));
+ $this->assertRaw(t('The item %title is only a container for forums.', array('%title' => $forum['name'])), t('Error message was shown'));
+ return;
+ }
+ else {
+ $this->assertRaw(t('@type %title has been created.', array('%title' => $title, '@type' => $type)), t('Forum topic was created'));
+ $this->assertNoRaw(t('The item %title is only a container for forums.', array('%title' => $forum['name'])), t('No error message was shown'));
+ }
+
+ // Retrieve node object.
+ $node = node_load(array('title' => $title), null, true); // Are these last two parameters necessary?
+ $this->assertTrue($node != null, t('Node @title was loaded', array('@title' => $title)));
+
+ // View forum topic.
+ $this->drupalGet('node/'. $node->nid);
+ $this->assertRaw($title, t('Subject was found'));
+ $this->assertRaw($body, t('Body was found'));
+
+ return $node;
+ }
+
+ /**
+ * Verify the logged in user has the desired access to the various forum nodes.
+ *
+ * @param object $node_user The user who creates the node.
+ * @param object $node Node.
+ * @param boolean $admin User has 'access administration pages' privilege.
+ * @param integer $response HTTP response code.
+ */
+ private function verifyForums($node_user, $node, $admin, $response = 200) {
+ $crumb = '›';
+ $quote = '&#039;';
+
+ $response2 = ($admin) ? 200 : 403;
+
+ // View forum help node.
+ $this->drupalGet('admin/help/forum');
+ $this->assertResponse($response2);
+ if ($response2 == 200) {
+ $this->assertTitle(t('Forum | Drupal'), t('Forum help node was displayed'));
+ $this->assertText(t('Forum'), t('Forum help node was displayed'));
+ $this->assertText(t('Home '. $crumb .' Administer '. $crumb .' Help'), t('Breadcrumbs were displayed'));
+ }
+
+ // Verify the forum blocks were displayed.
+ $this->drupalGet('');
+ $this->assertResponse(200);
+ // This block never seems to display?
+// $this->assertText(t('Active forum topics'), t('[Active forum topics] Forum block was displayed'));
+ $this->assertText(t('New forum topics'), t('[New forum topics] Forum block was displayed'));
+
+ // View forum container page.
+ $this->verifyForumView($this->container);
+ // View forum page.
+ $this->verifyForumView($this->forum, $this->container);
+ // View root forum page.
+ $this->verifyForumView($this->root_forum);
+
+ // View forum node.
+ $this->drupalGet('node/'. $node->nid);
+ $this->assertResponse(200);
+ $this->assertTitle($node->title .' | Drupal', t('Forum node was displayed'));
+ $this->assertText(t('Home '. $crumb .' Forums '. $crumb .' @container '. $crumb .' @forum', array('@container' => $this->container['name'], '@forum' => $this->forum['name'])), t('Breadcrumbs were displayed'));
+
+ // View forum edit node.
+ $this->drupalGet('node/'. $node->nid .'/edit');
+ $this->assertResponse($response);
+ if ($response == 200) {
+ $this->assertTitle($node->title .' | Drupal', t('Forum edit node was displayed'));
+ $this->assertText(t('Home '. $crumb .' @title', array('@title' => $node->title)), t('Breadcrumbs were displayed'));
+ }
+
+ if ($response == 200) {
+ // Edit forum node (including moving it to another forum).
+ $edit = array();
+ $edit['title'] = 'node/' . $node->nid;
+ $edit['body'] = $this->randomName(256);
+ $edit['taxonomy[1]'] = $this->root_forum['tid']; // Assumes the topic is initially associated with $forum.
+ $edit['shadow'] = TRUE;
+ $this->drupalPost('node/'. $node->nid .'/edit', $edit, t('Save'));
+ $this->assertRaw(t('Forum topic %title has been updated.', array('%title' => $edit['title'])), t('Forum node was edited'));
+
+ // Verify topic was moved to a different forum.
+ $forum_tid = db_result(db_query("SELECT tid FROM {forum} WHERE nid = %d AND vid = %d", $node->nid, $node->vid));
+ $this->assertTrue($forum_tid == $this->root_forum['tid'], 'The forum topic is linked to a different forum');
+
+ // Delete forum node.
+ $this->drupalPost('node/'. $node->nid .'/delete', array(), t('Delete'));
+ $this->assertResponse($response);
+ $this->assertRaw(t('Forum topic %title has been deleted.', array('%title' => $edit['title'])), t('Forum node was deleted'));
+ }
+ }
+
+ /**
+ * Verify display of forum page.
+ *
+ * @param array $forum Forum array (a row from term_data table).
+ */
+ private function verifyForumView($forum, $parent = NULL) {
+ $crumb = '›';
+
+ // View forum page.
+ $this->drupalGet('forum/'. $forum['tid']);
+ $this->assertResponse(200);
+ $this->assertTitle($forum['name'] .' | Drupal', t('Forum node was displayed'));
+ if (isset($parent)) {
+ $this->assertText(t('Home '. $crumb .' Forums '. $crumb .' @name', array('@name' => $parent['name'])), t('Breadcrumbs were displayed'));
+ }
+ else {
+ $this->assertText(t('Home '. $crumb .' Forums'), t('Breadcrumbs were displayed'));
+ }
+ }
+
+ /**
+ * Generate forum topics to test display of active forum block.
+ *
+ * @param array $forum Forum array (a row from term_data table).
+ */
+ private function generateForumTopics($forum) {
+ $this->nids = array();
+ for ($i = 0; $i < 5; $i++) {
+ $node = $this->createForumTopic($this->forum, FALSE);
+ $this->nids[] = $node->nid;
+ }
+ }
+
+ /**
+ * View forum topics to test display of active forum block.
+ *
+ * @param array $nids Forum node id array.
+ */
+ private function viewForumTopics($nids) {
+ $crumb = '›';
+
+ for ($i = 0; $i < 2; $i++) {
+ foreach ($nids as $nid) {
+ $this->drupalGet('node/'. $nid);
+ $this->drupalGet('node/'. $nid);
+ $this->drupalGet('node/'. $nid);
+ }
+ }
+ }
+}
diff --git a/modules/help/help.module b/modules/help/help.module
index 0b7787089..ee972498d 100644
--- a/modules/help/help.module
+++ b/modules/help/help.module
@@ -23,6 +23,7 @@ function help_menu() {
'title' => $module,
'page callback' => 'help_page',
'page arguments' => array(2),
+ 'access arguments' => array('access administration pages'),
'type' => MENU_CALLBACK,
'file' => 'help.admin.inc',
);
diff --git a/modules/help/help.test b/modules/help/help.test
new file mode 100644
index 000000000..a5f6b9271
--- /dev/null
+++ b/modules/help/help.test
@@ -0,0 +1,87 @@
+<?php
+// $Id$
+
+class HelpTestCase extends DrupalWebTestCase {
+ protected $big_user;
+ protected $any_user;
+
+ /**
+ * Implementation of getInfo().
+ */
+ function getInfo() {
+ return array(
+ 'name' => t('Help functionality'),
+ 'description' => t('Verify help display and user access to help based on persmissions.'),
+ 'group' => t('Help'),
+ );
+ }
+
+ /**
+ * Enable modules and create users with specific permissions.
+ */
+ function setUp() {
+ parent::setUp();
+
+ // Loading these (and other?) modules will result in failures?
+// $this->drupalModuleEnable('blog');
+// $this->drupalModuleEnable('poll');
+ $this->getModuleList();
+
+ // Create users.
+ $this->big_user = $this->drupalCreateUser(array('access administration pages')); // 'administer blocks', 'administer site configuration',
+ $this->any_user = $this->drupalCreateUser(array());
+ }
+
+ /**
+ * Login users, create dblog events, and test dblog functionality through the admin and user interfaces.
+ */
+ function testHelp() {
+ // Login the admin user.
+ $this->drupalLogin($this->big_user);
+ $this->verifyHelp();
+
+ // Login the regular user.
+ $user = $this->drupalLogin($this->any_user);
+ $this->verifyHelp(403);
+ }
+
+ /**
+ * Verify the logged in user has the desired access to the various help nodes and the nodes display help.
+ *
+ * @param integer $response HTTP response code.
+ */
+ private function verifyHelp($response = 200) {
+ $crumb = '›';
+
+ foreach ($this->modules as $module => $name) {
+ // View module help node.
+ $this->drupalGet('admin/help/'. $module);
+ $this->assertResponse($response);
+ if ($response == 200) {
+ // NOTE: The asserts fail on blog and poll because the get returns the 'admin/help' node instead of the indicated node???
+// if ($module == 'blog' || $module == 'poll') {
+// continue;
+// }
+ $this->assertTitle($name. ' | Drupal', t('['. $module .'] Title was displayed'));
+ $this->assertRaw('<h2>'. t($name) .'</h2>', t('['. $module .'] Heading was displayed'));
+ $this->assertText(t('Home '. $crumb .' Administer '. $crumb .' Help'), t('['. $module .'] Breadcrumbs were displayed'));
+ }
+ }
+ }
+
+ /**
+ * Get list of enabled modules.
+ *
+ * @return array Enabled modules.
+ */
+ private function getModuleList() {
+ $this->modules = array();
+ $result = db_query("SELECT name, filename, info FROM {system} WHERE type = 'module' AND status = 1 ORDER BY weight ASC, filename ASC");
+ while ($module = db_fetch_object($result)) {
+ if (file_exists($module->filename)) {
+ $fullname = unserialize($module->info);
+ $this->modules[$module->name] = $fullname['name'];
+ }
+ }
+ }
+}
diff --git a/modules/locale/locale.test b/modules/locale/locale.test
new file mode 100644
index 000000000..26c75174e
--- /dev/null
+++ b/modules/locale/locale.test
@@ -0,0 +1,116 @@
+<?php
+// $Id$
+
+class LocaleTestCase extends DrupalWebTestCase {
+ /**
+ * Implementation of getInfo() for information
+ */
+ function getInfo() {
+ return array(
+ 'name' => t('String translate'),
+ 'description' => 'Adds a new locale and translates its name',
+ 'group' => 'Locale',
+ );
+ }
+
+ function setUp() {
+ parent::setUp('locale');
+ }
+
+ function testlocaleModuleTest() {
+ global $base_url;
+
+ // User to add and remove language.
+ $admin_user = $this->drupalCreateUser(array('administer languages', 'access administration pages'));
+ // User to translate and delete string.
+ $translate_user = $this->drupalCreateUser(array('translate interface', 'access administration pages'));
+ // Code for the language.
+ $langcode = str_replace('simpletest_', 'si-', $this->randomName(6));
+ // The English name for the language. This will be translated.
+ $name = $this->randomName(16);
+ // The native name for the language.
+ $native = $this->randomName(16);
+ // The domain prefix. Not tested yet.
+ $prefix = strtolower(str_replace('si-', '', $langcode));
+ // This is the language indicator on the translation search screen for
+ // untranslated strings. Copied straight from locale.inc.
+ $language_indicator = "<em class=\"locale-untranslated\">$langcode</em> ";
+ // This will be the translation of $name.
+ $translation = $this->randomName(16);
+
+ // Add language.
+ $this->drupalLogin($admin_user);
+ $edit = array (
+ 'langcode' => $langcode,
+ 'name' => $name,
+ 'native' => $native,
+ 'prefix' => $prefix,
+ 'direction' => '0',
+ );
+ $this->drupalPost('admin/settings/language/add', $edit, t('Add custom language'));
+ // Add string.
+ t($name, array(), $langcode);
+ // Reset locale cache.
+ locale(NULL, NULL, TRUE);
+ $this->assertText($langcode, 'Language code found');
+ $this->assertText($name, 'Name found');
+ $this->assertText($native, 'Native found');
+ // No t() here, we do not want to add this string to the database and it's
+ // surely not translated yet.
+ $this->assertText($native, 'Test language added');
+ $this->drupalGet('logout');
+
+ // Search for the name and translate it.
+ $this->drupalLogin($translate_user);
+ $search = array (
+ 'string' => $name,
+ 'language' => 'all',
+ 'translation' => 'all',
+ 'group' => 'all',
+ );
+ $this->drupalPost('admin/build/translate/search', $search, t('Search'));
+ // assertText seems to remove the input field where $name always could be
+ // found, so this is not a false assert. See how assertNoText succeeds
+ // later.
+ $this->assertText($name, 'Search found the name');
+ $this->assertRaw($language_indicator, 'Name is untranslated');
+ // It's presumed that this is the only result. Given the random name, it's
+ // reasonable.
+ $this->clickLink(t('edit'));
+ // We save the lid from the path.
+ $lid = preg_replace('/\D/', '', substr($this->getUrl(), strlen($base_url)));
+ // No t() here, it's surely not translated yet.
+ $this->assertText($name, 'name found on edit screen');
+ $edit = array (
+ "translations[$langcode]" => $translation,
+ );
+ $this->drupalPost(NULL, $edit, t('Save translations'));
+ $this->assertText(t('The string has been saved.'), 'The string has been saved.');
+ $this->assertTrue($name != $translation && t($name, array(), $langcode) == $translation, 't() works');
+ $this->drupalPost('admin/build/translate/search', $search, t('Search'));
+ // The indicator should not be here.
+ $this->assertNoRaw($language_indicator, 'String is translated');
+ $this->drupalGet('logout');
+
+ // Delete the language
+ $this->drupalLogin($admin_user);
+ $path = 'admin/settings/language/delete/'. $langcode;
+ // This a confirm form, we do not need any fields changed.
+ $this->drupalPost($path, array(), t('Delete'));
+ // We need raw here because %locale will add HTML.
+ $this->assertRaw(t('The language %locale has been removed.', array('%locale' => $name)), 'The test language has been removed.');
+ // Reload to remove $name.
+ $this->drupalGet($path);
+ $this->assertNoText($langcode, 'Language code not found');
+ $this->assertNoText($name, 'Name not found');
+ $this->assertNoText($native, 'Native not found');
+ $this->drupalGet('logout');
+
+ // Delete the name string.
+ $this->drupalLogin($translate_user);
+ $this->drupalGet('admin/build/translate/delete/'. $lid);
+ $this->assertText(t('The string has been removed.'), 'The string has been removed message.');
+ $this->drupalPost('admin/build/translate/search', $search, t('Search'));
+ $this->assertNoText($name, 'Search now can not find the name');
+ }
+}
diff --git a/modules/menu/menu.test b/modules/menu/menu.test
new file mode 100644
index 000000000..d5310317d
--- /dev/null
+++ b/modules/menu/menu.test
@@ -0,0 +1,435 @@
+<?php
+// $Id$
+
+class MenuTestCase extends DrupalWebTestCase {
+ protected $big_user;
+ protected $std_user;
+ protected $menu;
+ protected $items;
+
+ /**
+ * Implementation of getInfo().
+ */
+ function getInfo() {
+ return array(
+ 'name' => t('Menu item creation/deletion'),
+ 'description' => t('Add a custom menu, add menu items to the custom menu and Navigation menu, check their data, and delete them using the menu module UI.'),
+ 'group' => t('Menu')
+ );
+ }
+
+ /**
+ * Implementation of setUp().
+ */
+ function setUp() {
+ parent::setUp('menu');
+ // Create users.
+ $this->big_user = $this->drupalCreateUser(array('administer blocks', 'administer menu', 'create article content'));
+ $this->std_user = $this->drupalCreateUser(array());
+ }
+
+ /**
+ * Login users, add menus and menu items, and test menu functionality through the admin and user interfaces.
+ */
+ function testMenu() {
+ // Login the user.
+ $this->drupalLogin($this->big_user);
+ $this->items = array();
+
+ // Do standard menu tests.
+ $this->doStandardMenuTests();
+
+ // Do custom menu tests.
+ $this->doCustomMenuTests();
+
+ // Do standard user tests.
+ // Login the user.
+ $this->drupalLogin($this->std_user);
+ $this->verifyAccess(403);
+ foreach ($this->items as $item) {
+ $node = node_load(substr($item['link_path'], 5)); // Paths were set as 'node/$nid'.
+ $this->verifyMenuItem($item, $node);
+ }
+
+ // Login the user.
+ $this->drupalLogin($this->big_user);
+
+ // Delete menu items.
+ foreach ($this->items as $item) {
+ $this->deleteMenuItem($item);
+ }
+
+ // Delete custom menu.
+ $this->deleteCustomMenu($this->menu);
+
+ // Modify and reset a standard menu item.
+ $item = $this->getStandardMenuItem();
+ $old_title = $item['link_title'];
+ $this->modifyMenuItem($item);
+ $item = menu_link_load($item['mlid']);
+ $this->resetMenuItem($item, $old_title);
+ }
+
+ /**
+ * Test standard menu functionality using navigation menu.
+ *
+ */
+ function doStandardMenuTests() {
+ $this->doMenuTests();
+ $this->addInvalidMenuItem();
+ }
+
+ /**
+ * Test custom menu functionality using navigation menu.
+ *
+ */
+ function doCustomMenuTests() {
+ $this->menu = $this->addCustomMenu();
+ $this->doMenuTests($this->menu['menu_name']);
+ $this->addInvalidMenuItem($this->menu['menu_name']);
+ }
+
+ /**
+ * Add custom menu.
+ *
+ */
+ function addCustomMenu() {
+ // Add custom menu.
+ $this->drupalGet('admin/build/menu/add');
+ $menu_name = substr(md5($this->randomName(16)), 0, 20);
+ $title = $this->randomName(16);
+ $edit = array (
+ 'menu_name' => $menu_name,
+ 'description' => '',
+ 'title' => $title,
+ );
+ $this->drupalPost('admin/build/menu/add', $edit, t('Save'));
+ // Unlike most other modules, there is no confirmation message displayed.
+// $this->assertText(t('The menu settings have been updated.'), t('Menu link was added'));
+
+ $this->drupalGet('admin/build/menu');
+ $this->assertText($title, 'Menu created');
+
+ // Enable the custom menu block.
+ $menu_name = 'menu-'. $menu_name; // Drupal prepends the name with 'menu-'.
+ $edit = array();
+ $edit['menu_'. $menu_name .'[region]'] = 'left';
+ $this->drupalPost('admin/build/block', $edit, t('Save blocks'));
+ $this->assertResponse(200);
+ $this->assertText(t('The block settings have been updated.'), t('Custom menu block was enabled'));
+
+ return menu_load($menu_name);
+ }
+
+ /**
+ * Delete custom menu.
+ *
+ * @param string $menu_name Custom menu name.
+ */
+ function deleteCustomMenu($menu) {
+ $menu_name = $this->menu['menu_name'];
+ $title = $this->menu['title'];
+
+ // Delete custom menu.
+ $this->drupalPost("admin/build/menu-customize/$menu_name/delete", array(), t('Delete'));
+ $this->assertResponse(200);
+ $this->assertRaw(t('The custom menu %title has been deleted.', array('%title' => $title)), t('Custom menu was deleted'));
+ $this->assertFalse(menu_load($menu_name), 'Custom menu was deleted');
+ }
+
+ /**
+ * Test menu functionality using navigation menu.
+ *
+ */
+ function doMenuTests($menu_name = 'navigation') {
+ // Add nodes to use as links for menu items.
+ $node1 = $this->drupalCreateNode(array('type' => 'article', 'uid' => $this->big_user->uid));
+ $node2 = $this->drupalCreateNode(array('type' => 'article', 'uid' => $this->big_user->uid));
+
+ // Add menu items.
+ $item1 = $this->addMenuItem(0, 'node/'. $node1->nid, $menu_name);
+ $item2 = $this->addMenuItem($item1['mlid'], 'node/'. $node2->nid, $menu_name);
+
+ // Verify menu items.
+ $this->verifyMenuItem($item1, $node1);
+ $this->verifyMenuItem($item2, $node2, $item1, $node1);
+
+ // Modify menu items.
+ $this->modifyMenuItem($item1);
+ $this->modifyMenuItem($item2);
+
+ // Toggle menu items.
+ $this->toggleMenuItem($item1);
+ $this->toggleMenuItem($item2);
+
+ // Save menu items for later tests.
+ $this->items[] = $item1;
+ $this->items[] = $item2;
+ }
+
+ /**
+ * Add a menu item using the menu module UI.
+ *
+ * @param integer $plid Parent menu link id.
+ * @param string $link Link path.
+ * @param string $menu_name Menu name.
+ * @return object Menu item created.
+ */
+ function addMenuItem($plid = 0, $link = '<front>', $menu_name = 'navigation') {
+ // View add menu item page.
+ $this->drupalGet("admin/build/menu-customize/$menu_name/add");
+ $this->assertResponse(200);
+
+ $title = '!link_'. $this->randomName(16);
+ $edit = array (
+ 'menu[link_path]' => $link,
+ 'menu[link_title]' => $title,
+ 'menu[description]' => '',
+ 'menu[enabled]' => TRUE, // Use this to disable the menu and test.
+ 'menu[expanded]' => TRUE, // Setting this to true should test whether it works when we do the std_user tests.
+ 'menu[parent]' => $menu_name .':'. $plid,
+ 'menu[weight]' => '0',
+ );
+
+ // Add menu item.
+ $this->drupalPost("admin/build/menu-customize/$menu_name/add", $edit, t('Save'));
+ $this->assertResponse(200);
+ // Unlike most other modules, there is no confirmation message displayed.
+// $this->assertText(t('The menu item %title has been added.', array('%title' => $title)), t('Menu item was added'));
+ $this->assertText($title, 'Menu item was added');
+
+ // Retrieve menu item.
+ $item = db_fetch_array(db_query("SELECT * FROM {menu_links} WHERE link_title = '%s'", $title));
+
+ // Check the structure in the DB of the two menu items.
+ // In general, if $n = $item['depth'] then $item['p'. $n] == $item['mlid'] and $item['p'. ($n - 1)] == $item['plid'] (unless depth == 0).
+ // All $item['p'. $n] for $n > depth must be 0.
+ // We know link1 is at the top level, so $item1['deptj'] == 1 and $item1['plid'] == 0.
+ // We know that the parent of link2 is link1, so $item2['plid'] == $item1['mlid'].
+ // Both menu items were created in the navigation menu.
+ $this->assertTrue($item['menu_name'] == $menu_name && $item['plid'] == $plid && $item['link_path'] == $link && $item['link_title'] == $title, 'Menu item has correct data');
+ if ($plid == 0) {
+ $this->assertTrue($item['depth'] == 1 && !$item['has_children'] && $item['p1'] == $item['mlid'] && $item['p2'] == 0, 'Menu item has correct data');
+ }
+ else {
+ $this->assertTrue($item['depth'] == 2 && !$item['has_children'] && $item['p1'] == $plid && $item['p2'] == $item['mlid'], 'Menu item has correct data');
+ }
+
+ return $item;
+ }
+
+ /**
+ * Attempt to add menu item with invalid path or no access permission.
+ *
+ * @param string $menu_name Menu name.
+ */
+ function addInvalidMenuItem($menu_name = 'navigation') {
+ foreach (array('-&-', 'admin/user/permissions') as $link_path) {
+ $edit = array (
+ 'menu[link_path]' => $link_path,
+ 'menu[link_title]' => 'title',
+ );
+ $this->drupalPost("admin/build/menu-customize/$menu_name/add", $edit, t('Save'));
+ $this->assertRaw(t("The path '@path' is either invalid or you do not have access to it.", array('@path' => $link_path)), 'Menu item was not created');
+ }
+ }
+
+ /**
+ * Verify a menu item using the menu module UI.
+ *
+ * @param object $item Menu item.
+ * @param object $item_node Menu item content node.
+ * @param object $parent Parent menu item.
+ * @param object $parent_node Parent menu item content node.
+ */
+ function verifyMenuItem($item, $item_node, $parent = NULL, $parent_node = NULL) {
+ // View home page.
+ $this->drupalGet('');
+ $this->assertResponse(200);
+
+ // Verify parent menu item.
+ if (isset($parent)) {
+ // Verify menu item.
+ $title = $parent['link_title'];
+ $this->assertText($title, 'Parent menu item was displayed');
+
+ // Verify menu item link.
+ $this->clickLink($title);
+ $title = $parent_node->title;
+ $this->assertTitle(t("@title | Drupal", array('@title' => $title)), t('Parent menu item link target was correct'));
+ }
+
+ // Verify menu item.
+ $title = $item['link_title'];
+ $this->assertText($title, 'Menu item was displayed');
+
+ // Verify menu item link.
+ $this->clickLink($title);
+ $title = $item_node->title;
+ $this->assertTitle(t("@title | Drupal", array('@title' => $title)), t('Menu item link target was correct'));
+ }
+
+ /**
+ * Modify a menu item using the menu module UI.
+ *
+ * @param object &$item Menu item passed by reference.
+ */
+ function modifyMenuItem(&$item) {
+ $item['link_title'] = $this->randomName(16);
+
+ $mlid = $item['mlid'];
+ $title = $item['link_title'];
+
+ // Edit menu item.
+ $edit = array();
+ $edit['menu[link_title]'] = $title;
+ $this->drupalPost("admin/build/menu/item/$mlid/edit", $edit, t('Save'));
+ $this->assertResponse(200);
+ // Unlike most other modules, there is no confirmation message displayed.
+// $this->assertRaw(t('The menu item %title has been updated.', array('%title' => $title)), t('Menu item was edited'));
+
+ // Verify menu item.
+ $this->drupalGet('admin/build/menu-customize/'. $item['menu_name']);
+ $this->assertText($title, 'Menu item was edited');
+ }
+
+ /**
+ * Reset a standard menu item using the menu module UI.
+ *
+ * @param object $item Menu item.
+ * @param string $old_title Original title for menu item.
+ */
+ function resetMenuItem($item, $old_title) {
+ $mlid = $item['mlid'];
+ $title = $item['link_title'];
+
+ // Reset menu item.
+ $this->drupalPost("admin/build/menu/item/$mlid/reset", array(), t('Reset'));
+ $this->assertResponse(200);
+ $this->assertRaw(t('The menu item was reset to its default settings.'), t('Menu item was reset'));
+
+ // Verify menu item.
+ $this->drupalGet('');
+ $this->assertNoText($title, 'Menu item was reset');
+
+ // Verify menu item.
+ $this->drupalGet('');
+ $this->assertText($old_title, 'Menu item was reset');
+ }
+
+ /**
+ * Delete a menu item using the menu module UI.
+ *
+ * @param object $item Menu item.
+ */
+ function deleteMenuItem($item) {
+ $mlid = $item['mlid'];
+ $title = $item['link_title'];
+
+ // Delete menu item.
+ $this->drupalPost("admin/build/menu/item/$mlid/delete", array(), t('Confirm'));
+ $this->assertResponse(200);
+ $this->assertRaw(t('The menu item %title has been deleted.', array('%title' => $title)), t('Menu item was deleted'));
+
+ // Verify deletion.
+ $this->drupalGet('');
+ $this->assertNoText($title, 'Menu item was deleted');
+ }
+
+ /**
+ * Alternately disable and enable a menu item.
+ *
+ * @param object $item Menu item.
+ */
+ function toggleMenuItem($item) {
+ $mlid = $item['mlid'];
+ $title = $item['link_title'];
+
+ // Edit menu item.
+ $edit = array();
+ $edit['menu[enabled]'] = FALSE;
+ $this->drupalPost("admin/build/menu/item/$mlid/edit", $edit, t('Save'));
+ $this->assertResponse(200);
+ // Unlike most other modules, there is no confirmation message displayed.
+// $this->assertRaw(t('The menu item %title has been updated.', array('%title' => $title)), t('Menu item was edited'));
+
+ // Verify menu item.
+ $this->drupalGet('');
+ $this->assertNoText($title, 'Menu item was not displayed');
+
+ // Edit menu item.
+ $edit['menu[enabled]'] = TRUE;
+ $this->drupalPost("admin/build/menu/item/$mlid/edit", $edit, t('Save'));
+ $this->assertResponse(200);
+
+ // Verify menu item.
+ $this->drupalGet('');
+ $this->assertText($title, 'Menu item was displayed');
+ }
+
+ /**
+ * Get standard menu item.
+ *
+ */
+ private function getStandardMenuItem()
+ {
+ // Retrieve menu link id (presumably the Log out menu item, but not necessary).
+ $mlid = db_result(db_query("SELECT MIN(mlid) FROM {menu_links} WHERE module = 'system' AND hidden = 0 AND has_children = 0"));
+ $this->assertTrue($mlid > 0, 'Standard menu link id was found');
+ // Load menu item.
+ // Use api function so that link is translated for rendering.
+ $item = menu_link_load($mlid);
+ $this->assertTrue((bool)$item, 'Standard menu item was loaded');
+ return $item;
+ }
+
+ /**
+ * Verify the logged in user has the desired access to the various menu nodes.
+ *
+ * @param integer $response HTTP response code.
+ */
+ private function verifyAccess($response = 200) {
+ // View menu help node.
+ $this->drupalGet('admin/help/menu');
+ $this->assertResponse($response);
+ if ($response == 200) {
+ $this->assertText(t('Menu'), t('Menu help was displayed'));
+ }
+
+ // View menu build overview node.
+ $this->drupalGet('admin/build/menu');
+ $this->assertResponse($response);
+ if ($response == 200) {
+ $this->assertText(t('Menus'), t('Menu build overview node was displayed'));
+ }
+
+ // View navigation menu customization node.
+ $this->drupalGet('admin/build/menu-customize/navigation');
+ $this->assertResponse($response);
+ if ($response == 200) {
+ $this->assertText(t('Navigation'), t('Navigation menu node was displayed'));
+ }
+
+ // View menu edit node.
+ $item = $this->getStandardMenuItem();
+ $this->drupalGet('admin/build/menu/item/'. $item['mlid'] .'/edit');
+ $this->assertResponse($response);
+ if ($response == 200) {
+ $this->assertText(t('Edit menu item'), t('Menu edit node was displayed'));
+ }
+
+ // View menu settings node.
+ $this->drupalGet('admin/build/menu/settings');
+ $this->assertResponse($response);
+ if ($response == 200) {
+ $this->assertText(t('Menus'), t('Menu settings node was displayed'));
+ }
+
+ // View add menu node.
+ $this->drupalGet('admin/build/menu/add');
+ $this->assertResponse($response);
+ if ($response == 200) {
+ $this->assertText(t('Menus'), t('Add menu node was displayed'));
+ }
+ }
+}
diff --git a/modules/node/node.test b/modules/node/node.test
new file mode 100644
index 000000000..48a23b219
--- /dev/null
+++ b/modules/node/node.test
@@ -0,0 +1,403 @@
+<?php
+// $Id$
+
+class NodeRevisionsTestCase extends DrupalWebTestCase {
+ /**
+ * Implementation of getInfo() for information
+ */
+ function getInfo() {
+ return array(
+ 'name' => t('Node revisions'),
+ 'description' => t('Creates a node of type page and then a user tries various revision actions such as viewing, reverting to, and deleting revisions.'),
+ 'group' => t('Node')
+ );
+ }
+
+ /**
+ * Setup function used by tests. Creates a node with three revisions.
+ *
+ * If $log is TRUE, then a log message will be recorded.
+ */
+ function prepareRevisions($log = FALSE) {
+
+ $return_array = array();
+ $numtimes = 3; // First, middle, last.
+ for ($i = 0; $i < $numtimes; $i++) {
+ $settings = array('revision' => 1);
+ if ($log && $i == 1) {
+ $log_message = $this->randomName(32);
+ $settings['log'] = $log_message;
+ $return_array['log'] = $log_message;
+ }
+ if ($i != 0) {
+ $settings['nid'] = $node->nid;
+ }
+ $node = $this->drupalCreateNode($settings);
+ if ($i == 1) {
+ $return_array['text'] = $node->body;
+ $return_array['vid'] = $node->vid;
+ }
+ // Avoid confusion on the revisions overview page which is sorted by r.timestamp.
+ sleep(1);
+ }
+ $return_array['node'] = $node;
+ return $return_array;
+ }
+
+ /**
+ * Simpletest test. Tests to make sure the correct revision text appears on "view revisions" page.
+ */
+ function testNodeRevisions() {
+ // Get $log, $text, $vid, $node.
+ extract( $this->prepareRevisions() );
+
+ $test_user = $this->drupalCreateUser(array('view revisions'));
+ $this->drupalLogin($test_user);
+ $this->drupalGet("node/$node->nid/revisions/$vid/view");
+ $this->assertText($text, 'Check to make sure correct revision text appears on "view revisions" page.');
+ }
+
+ /**
+ * Simpletest test. Tests to make sure the correct log message appears on "revisions overview" page.
+ */
+ function testLogMessage() {
+ // Get $log, $text, $vid, $node.
+ extract( $this->prepareRevisions(TRUE) );
+
+ $test_user = $this->drupalCreateUser(array('view revisions'));
+ $this->drupalLogin($test_user);
+ $this->drupalGet("node/$node->nid/revisions");
+ $this->assertText($log, 'Check to make sure log message is properly displayed.');
+ }
+
+ /**
+ * Simpletest test. Tests to make sure the that revisions revert properly.
+ */
+ function testRevisionRevert() {
+ // Get $log, $text, $vid, $node.
+ extract( $this->prepareRevisions() );
+
+ $test_user = $this->drupalCreateUser(array('revert revisions', 'edit any page content'));
+ $this->drupalLogin($test_user);
+ $this->drupalPost("node/$node->nid/revisions/$vid/revert", array(), t('Revert'));
+ $new_node = node_load($node->nid);
+ $this->assertTrue(($text == $new_node->body), 'Check to make sure reversions occur properly');
+ }
+
+ /**
+ * Simpletest test. Tests to make sure the revision deletes properly.
+ */
+ function testRevisionDelete() {
+ // Get $log, $text, $vid, $node.
+ extract( $this->prepareRevisions() );
+
+ $test_user = $this->drupalCreateUser(array('delete revisions', 'delete any page content'));
+ $this->drupalLogin($test_user);
+ $this->drupalPost("node/$node->nid/revisions/$vid/delete", array(), t('Delete'));
+ $this->assertTrue(db_result(db_query('SELECT COUNT(vid) FROM {node_revisions} WHERE nid = %d and VID = %d', $node->nid, $vid)) == 0, 'Check to make sure revisions delete properly');
+ }
+}
+
+
+class NodeTeaserTestCase extends DrupalWebTestCase {
+ /**
+ * Implementation of getInfo() for information
+ */
+ function getInfo() {
+ return array(
+ 'name' => t('Node teaser'),
+ 'description' => t('Calls node_teaser() with different strings and lengths.'),
+ 'group' => t('Node')
+ );
+ }
+
+ function setUp() {
+ parent::setUp();
+ }
+
+ function tearDown() {
+ parent::tearDown();
+ }
+
+ /**
+ * Simpletest test. Tests an edge case where if the first sentence is a
+ * question and subsequent sentences are not.
+ * This failed in drupal 5.
+ * Test and patch for drupal 6 (committed) from
+ * http://drupal.org/node/180425
+ */
+ function testFirstSentenceQuestion() {
+ $body = 'A question? A sentence. Another sentence.';
+ $expectedTeaser = 'A question? A sentence.';
+ $this->callNodeTeaser($body, $expectedTeaser, NULL, 30);
+ }
+
+ /**
+ * Simpletest test. A real-life example of the above edge case.
+ */
+ function testFirstSentenceQuestion2() {
+ $body = 'Are you an UberBabe? (Or an appreciator of UberBabes?) I am most definitely an UberBabe, and I\'m proud of it. Now, before anyone screams "sexism" or "bias" or "cheap" or anything more profane, let me clarify. An UberBabe is not someone who\'s playfully pierced navel protrudes from a belly bearing top. Not necessarily anyway. An UberBabe is a woman who likes being totally feminine, but is also smart as hell, brave, a rule breaker, speaks her mind, finds her own way, goes up against "the system" in a way that allows the system to evolve, and so on. UberBabes, frankly, kick booty - and they just may save the world.';
+ $expectedTeaser = 'Are you an UberBabe? (Or an appreciator of UberBabes?) I am most definitely an UberBabe, and I\'m proud of it. Now, before anyone screams "sexism" or "bias" or "cheap" or anything more profane, let me clarify.';
+ $this->callNodeTeaser($body, $expectedTeaser, NULL, 300);
+ }
+
+ /**
+ * Simpletest test. Runs a test adapted from
+ * http://drupal.org/node/180425#comment-634230
+ */
+ function testLength() {
+ // This body string tests a number of edge cases.
+ $body = "<p>\nHi\n</p>\n<p>\nfolks\n<br />\n!\n</p>";
+
+ // The teasers we expect node_teaser() to return when $size is the index
+ // of each array item.
+ // Using an input format with no line-break filter:
+ $teasers = array(
+ "<p>\nHi\n</p>\n<p>\nfolks\n<br />\n!\n</p>",
+ "<",
+ "<p",
+ "<p>",
+ "<p>\n",
+ "<p>\nH",
+ "<p>\nHi",
+ "<p>\nHi\n",
+ "<p>\nHi\n<",
+ "<p>\nHi\n</",
+ "<p>\nHi\n</p",
+ "<p>\nHi\n</p>",
+ "<p>\nHi\n</p>",
+ "<p>\nHi\n</p>",
+ "<p>\nHi\n</p>",
+ "<p>\nHi\n</p>",
+ "<p>\nHi\n</p>",
+ "<p>\nHi\n</p>",
+ "<p>\nHi\n</p>",
+ "<p>\nHi\n</p>",
+ "<p>\nHi\n</p>",
+ "<p>\nHi\n</p>",
+ "<p>\nHi\n</p>",
+ "<p>\nHi\n</p>",
+ "<p>\nHi\n</p>",
+ "<p>\nHi\n</p>",
+ "<p>\nHi\n</p>",
+ "<p>\nHi\n</p>",
+ "<p>\nHi\n</p>",
+ "<p>\nHi\n</p>",
+ "<p>\nHi\n</p>",
+ "<p>\nHi\n</p>",
+ "<p>\nHi\n</p>",
+ "<p>\nHi\n</p>",
+ "<p>\nHi\n</p>",
+ "<p>\nHi\n</p>\n<p>\nfolks\n<br />\n!\n</p>",
+ "<p>\nHi\n</p>\n<p>\nfolks\n<br />\n!\n</p>",
+ "<p>\nHi\n</p>\n<p>\nfolks\n<br />\n!\n</p>",
+ );
+ // And Using an input format WITH the line-break filter.
+ $teasers_lb = array(
+ "<p>\nHi\n</p>\n<p>\nfolks\n<br />\n!\n</p>",
+ "<",
+ "<p",
+ "<p>",
+ "<p>",
+ "<p>",
+ "<p>",
+ "<p>\nHi",
+ "<p>\nHi",
+ "<p>\nHi",
+ "<p>\nHi",
+ "<p>\nHi\n</p>",
+ "<p>\nHi\n</p>",
+ "<p>\nHi\n</p>",
+ "<p>\nHi\n</p>",
+ "<p>\nHi\n</p>",
+ "<p>\nHi\n</p>",
+ "<p>\nHi\n</p>",
+ "<p>\nHi\n</p>",
+ "<p>\nHi\n</p>",
+ "<p>\nHi\n</p>",
+ "<p>\nHi\n</p>",
+ "<p>\nHi\n</p>",
+ "<p>\nHi\n</p>",
+ "<p>\nHi\n</p>",
+ "<p>\nHi\n</p>",
+ "<p>\nHi\n</p>",
+ "<p>\nHi\n</p>",
+ "<p>\nHi\n</p>",
+ "<p>\nHi\n</p>",
+ "<p>\nHi\n</p>",
+ "<p>\nHi\n</p>",
+ "<p>\nHi\n</p>",
+ "<p>\nHi\n</p>",
+ "<p>\nHi\n</p>",
+ "<p>\nHi\n</p>\n<p>\nfolks\n<br />\n!\n</p>",
+ "<p>\nHi\n</p>\n<p>\nfolks\n<br />\n!\n</p>",
+ "<p>\nHi\n</p>\n<p>\nfolks\n<br />\n!\n</p>",
+ );
+
+ // Test node_teaser() for different sizes.
+ for ($i = 0; $i <= 37; $i++) {
+ $this->callNodeTeaser($body, $teasers[$i], NULL, $i);
+ $this->callNodeTeaser($body, $teasers_lb[$i], 1, $i);
+ $this->callNodeTeaser($body, $teasers_lb[$i], 2, $i);
+ }
+ }
+
+ /**
+ * Calls node_teaser() and asserts that the expected teaser is returned.
+ */
+ function callNodeTeaser($body, $expectedTeaser, $format = NULL, $size = NULL) {
+ $teaser = node_teaser($body, $format, $size);
+ $this->assertIdentical($teaser, $expectedTeaser);
+ }
+}
+
+class PageEditTestCase extends DrupalWebTestCase {
+ function getInfo() {
+ return array(
+ 'name' => 'Page edit test',
+ 'description' => t('We want a working edit for pages, uh?'),
+ 'group' => t('Node'));
+ }
+ function testPageEdit() {
+
+ /* Prepare settings */
+ variable_set('node_options_page', array('status', 'promote'));
+ /* Prepare a user to do the stuff */
+ $web_user = $this->drupalCreateUser(array('edit own page content', 'create page content'));
+ $this->drupalLogin($web_user);
+ $edit = array(
+ 'title' => '!SimpleTest! test title' . $this->randomName(20),
+ 'body' => '!SimpleTest! test body' . $this->randomName(200),
+ );
+
+ //Create the page to edit
+ $this->drupalPost('node/add/page', $edit, t('Save'));
+
+ $node = node_load(array('title' => $edit['title']));
+ $this->assertNotNull($node, 'Node found in database');
+
+ $this->clickLink(t('Edit'));
+ $editurl = url("node/$node->nid/edit", array('absolute' => true));
+ $acturl = $this->getURL();
+ $this->assertEqual($editurl, $acturl);
+
+ $this->assertText(t('Edit'), 'Edit text is here');
+ $this->assertText(t($edit['title']), 'Hello, the random title');
+ $this->assertText(t($edit['body']), 'test is over, the body\'s still there');
+
+ $edit = array(
+ 'title' => '!SimpleTest! test title' . $this->randomName(20),
+ 'body' => '!SimpleTest! test body' . $this->randomName(200),
+ );
+
+
+ //edit the content of the page
+ $this->drupalPost("node/$node->nid/edit", $edit, t('Save'));
+
+ $this->assertText(t($edit['title']), 'Hello, the random title');
+ $this->assertText(t($edit['body']), 'test is over, the body\'s still there');
+ }
+
+}
+
+class PagePreviewTestCase extends DrupalWebTestCase {
+ function getInfo() {
+ return array(
+ 'name' => 'Page preview test',
+ 'description' => t('We want a working preview for pages, uh?'),
+ 'group' => t('Node'));
+ }
+
+ function testPagePreview() {
+ /* Prepare settings */
+ variable_set('node_options_page', array('status', 'promote'));
+ /* Prepare a user to do the stuff */
+ $web_user = $this->drupalCreateUser(array('edit own page content', 'create page content'));
+ $this->drupalLogin($web_user);
+
+ $edit = array(
+ 'title'=>'!SimpleTest! title' . $this->randomName(20),
+ 'body'=>'!SimpleTest! body' . $this->randomName(200),
+ );
+ $this->drupalPost('node/add/page', $edit, t('Preview'));
+
+ $this->assertText(t('Preview'), 'Preview text is here');
+ $this->assertText(t($edit['title']), 'Hello, the random title');
+ $this->assertText(t($edit['body']), 'test is over, the body\'s still there');
+
+ $this->assertFieldByName('title', $edit['title'], 'The title is on it\'s place');
+
+ }
+
+}
+
+class PageCreationTestCase extends DrupalWebTestCase {
+
+ /**
+ * Implementation of getInfo() for information
+ */
+ function getInfo() {
+ return array(
+ 'name' => t('Page node creation'),
+ 'description' => t('Create a page node and verify its consistency in the database.'),
+ 'group' => t('Node'),
+ );
+ }
+
+ function testPageCreation() {
+ /* Prepare settings */
+ variable_set('node_options_page', array('status', 'promote'));
+
+ /* Prepare a user to do the stuff */
+ $web_user = $this->drupalCreateUser(array('edit own page content', 'create page content'));
+ $this->drupalLogin($web_user);
+
+ $edit = array();
+ $edit['title'] = '!SimpleTest test node! ' . $this->randomName(10);
+ $edit['body'] = '!SimpleTest test body! ' . $this->randomName(32) . ' ' . $this->randomName(32);
+ $this->drupalPost('node/add/page', $edit, t('Save'));
+
+ $this->assertRaw(t('!post %title has been created.', array ('!post' => 'Page', '%title' => $edit['title'])), 'Page created');
+
+ $node = node_load(array('title' => $edit['title']));
+ $this->assertNotNull($node, t('Node !title found in database.', array ('!title' => $edit['title'])));
+
+ }
+}
+
+class PageViewTestCase extends DrupalWebTestCase {
+ /**
+ * Implementation of getInfo() for information
+ */
+ function getInfo() {
+ return array(
+ 'name' => t('Unauthorized node view'),
+ 'description' => t('Creates a node of type page and then an unpermissioned user attempts to edit the node, '
+ . 'before tries with an anonymous user. Asserts failure.'
+ . '</ br>WARNING: This is based on default registered user permuissions (no administer nodes).')
+ , 'group' => t('Node'),
+ );
+ }
+
+ function testPageView() {
+ /* Prepare a node to view */
+ global $user;
+ $node = $this->drupalCreateNode();
+ $this->assertNotNull(node_load($node->nid), 'Node created');
+
+ /* Tries to edit with anonymous user */
+ $html = $this->drupalGet("node/$node->nid/edit");
+ $this->assertResponse(403);
+
+ /* Prepare a user to request the node view */
+ $test_user = $this->drupalCreateUser(array('access content'));
+ $this->drupalLogin($test_user);
+
+ $html = $this->drupalGet("node/$node->nid/edit");
+ $this->assertResponse(403);
+
+ $test_user = $this->drupalCreateUser(array('administer nodes'));
+ //TODO: Add edit page attempt with administer nodes user
+ node_delete($node->nid);
+ }
+}
diff --git a/modules/path/path.test b/modules/path/path.test
new file mode 100644
index 000000000..f12322966
--- /dev/null
+++ b/modules/path/path.test
@@ -0,0 +1,139 @@
+<?php
+// $Id$
+
+class PathTestCase extends DrupalWebTestCase {
+ function getInfo() {
+ return array(
+ 'name' => t('Path alias functionality'),
+ 'description' => t('Add, edit, delete, and change alias and verify its consistency in the database.'),
+ 'group' => t('Path'),
+ );
+ }
+
+ /**
+ * Create user, setup permissions, log user in, and create a node.
+ */
+ function setUp() {
+ parent::setUp('path');
+ // create and login user
+ $web_user = $this->drupalCreateUser(array('edit own page content', 'create page content', 'administer url aliases', 'create url aliases'));
+ $this->drupalLogin($web_user);
+ }
+
+ /**
+ * Test alias functionality through the admin interfaces.
+ */
+ function testAdminAlias() {
+ // create test node
+ $node1 = $this->createNode();
+
+ // create alias
+ $edit = array();
+ $edit['src'] = 'node/' . $node1->nid;
+ $edit['dst'] = $this->randomName(8);
+ $this->drupalPost('admin/build/path/add', $edit, t('Create new alias'));
+
+ // confirm that the alias works
+ $this->drupalGet($edit['dst']);
+ $this->assertText($node1->title, 'Alias works.');
+
+ // change alias
+ $pid = $this->getPID($edit['dst']);
+
+ $previous = $edit['dst'];
+ $edit['dst'] = $this->randomName(8);
+ $this->drupalPost('admin/build/path/edit/' . $pid, $edit, t('Update alias'));
+
+ // confirm that the alias works
+ $this->drupalGet($edit['dst']);
+ $this->assertText($node1->title, 'Changed alias works.');
+
+ // make sure that previous alias no longer works
+ $this->drupalGet($previous);
+ $this->assertNoText($node1->title, 'Previous alias no longer works.');
+ $this->assertResponse(404);
+
+ // create second test node
+ $node2 = $this->createNode();
+
+ // set alias to second test node
+ $edit['src'] = 'node/' . $node2->nid;
+ // leave $edit['dst'] the same
+ $this->drupalPost('admin/build/path/add', $edit, t('Create new alias'));
+
+ // confirm that the alias didn't make a duplicate
+ $this->assertRaw(t('The alias %alias is already in use in this language.', array('%alias' => $edit['dst'])), 'Attempt to move alias was rejected.');
+
+ // delete alias
+ $this->drupalPost('admin/build/path/delete/' . $pid, array(), t('Confirm'));
+
+ // confirm that the alias no longer works
+ $this->drupalGet($edit['dst']);
+ $this->assertNoText($node1->title, 'Alias was successfully deleted.');
+ }
+
+ /**
+ * Test alias functionality through the node interfaces.
+ */
+ function testNodeAlias() {
+ // create test node
+ $node1 = $this->createNode();
+
+ // create alias
+ $edit = array();
+ $edit['path'] = $this->randomName(8);
+ $this->drupalPost('node/' . $node1->nid . '/edit', $edit, t('Save'));
+
+ // confirm that the alias works
+ $this->drupalGet($edit['path']);
+ $this->assertText($node1->title, 'Alias works.');
+
+ // change alias
+ $previous = $edit['path'];
+ $edit['path'] = $this->randomName(8);
+ $this->drupalPost('node/' . $node1->nid . '/edit', $edit, t('Save'));
+
+ // confirm that the alias works
+ $this->drupalGet($edit['path']);
+ $this->assertText($node1->title, 'Changed alias works.');
+
+ // make sure that previous alias no longer works
+ $this->drupalGet($previous);
+ $this->assertNoText($node1->title, 'Previous alias no longer works.');
+ $this->assertResponse(404);
+
+ // create second test node
+ $node2 = $this->createNode();
+
+ // set alias to second test node
+ // leave $edit['path'] the same
+ $this->drupalPost('node/' . $node2->nid . '/edit', $edit, t('Save'));
+
+ // confirm that the alias didn't make a duplicate
+ $this->assertText(t('The path is already in use.'), 'Attempt to moved alias was rejected.');
+
+ // delete alias
+ $this->drupalPost('node/' . $node1->nid . '/edit', array('path' => ''), t('Save'));
+
+ // confirm that the alias no longer works
+ $this->drupalGet($edit['path']);
+ $this->assertNoText($node1->title, 'Alias was successfully deleted.');
+ }
+
+ function getPID($dst) {
+ return db_result(db_query("SELECT pid FROM {url_alias} WHERE dst = '%s'", $dst));
+ }
+
+ function createNode() {
+ $edit = array();
+ $edit['title'] = '!SimpleTest test node! ' . $this->randomName(10);
+ $edit['body'] = '!SimpleTest test body! ' . $this->randomName(32) . ' ' . $this->randomName(32);
+ $this->drupalPost('node/add/page', $edit, t('Save'));
+
+ // check to make sure the node was created
+ $node = node_load(array('title' => $edit['title']));
+ $this->assertNotNull(($node === FALSE ? NULL : $node), 'Node found in database. %s');
+
+ return $node;
+ }
+}
diff --git a/modules/php/php.test b/modules/php/php.test
new file mode 100644
index 000000000..d0293d1f3
--- /dev/null
+++ b/modules/php/php.test
@@ -0,0 +1,93 @@
+<?php
+// $Id$
+
+class PHPTestCase extends DrupalWebTestCase {
+ /**
+ * Implementation of getInfo().
+ */
+ function getInfo() {
+ return array(
+ 'name' => t('PHP filter functionality'),
+ 'description' => t('Make sure that PHP filter evaluates PHP code when enabled and that users who don\'t have access to filter can\'t see it'),
+ 'group' => t('PHP'),
+ );
+ }
+
+ /**
+ * Implementation of getInfo().
+ */
+ function setUp() {
+ parent::setUp('php');
+
+ // Create and login admin user.
+ $admin_user = $this->drupalCreateUser(array('administer filters'));
+ $this->drupalLogin($admin_user);
+
+ // Confirm that the PHP filter is #3.
+ $this->drupalGet('admin/settings/filters/3');
+ $this->assertText('PHP code', t('On PHP code filter page.'));
+ }
+
+ /**
+ * Make sure that the PHP filter evaluates PHP code when used.
+ */
+ function testPHPFilter() {
+ // Setup PHP filter.
+ $edit = array();
+ $edit['roles[2]'] = TRUE; // Set authenticated users to have permission to use filter.
+ $this->drupalPost(NULL, $edit, 'Save configuration');
+ $this->assertText(t('The input format settings have been updated.'), t('PHP format available to authenticated users.'));
+
+ // Create node with PHP filter enabled.
+ $web_user = $this->drupalCreateUser(array('access content', 'create page content', 'edit own page content'));
+ $this->drupalLogin($web_user);
+
+ $node = $this->createNodeWithCode($web_user);
+
+ // Make sure that the PHP code shows up as text.
+ $this->assertText('print', t('PHP code is displayed.'));
+
+ // Change filter to PHP filter and see that PHP code is evaluated.
+ $edit = array();
+ $edit['format'] = 3;
+ $this->drupalPost('node/'. $node->nid .'/edit', $edit, t('Save'));
+ $this->assertRaw(t('Page %title has been updated.', array('%title' => $node->title)), t('PHP code filter turned on.'));
+
+ // Make sure that the PHP code shows up as text.
+ $this->assertNoText('print', t('PHP code isn\'t displayed.'));
+ $this->assertText('SimpleTest PHP was executed!', t('PHP code has been evaluated.'));
+ }
+
+ /**
+ * Make sure that user can't use the PHP filter when not given access.
+ */
+ function testNoPrivileges() {
+ // Create node with PHP filter enabled.
+ $web_user = $this->drupalCreateUser(array('access content', 'create page content', 'edit own page content'));
+ $this->drupalLogin($web_user);
+
+ $node = $this->createNodeWithCode($web_user);
+
+ // Make sure that the PHP code shows up as text.
+ $this->assertText('print', t('PHP code is displayed.'));
+
+ // Make sure that user doesn't have access to filter.
+ $this->drupalGet('node/'. $node->nid .'/edit');
+ $this->assertNoFieldByName('format', '3', t('Format not available.'));
+ }
+
+ /**
+ * Create a test node with PHP code in the body.
+ *
+ * @param stdObject User object to create node for.
+ * @return stdObject Node object.
+ */
+ function createNodeWithCode($user) {
+ $node = $this->drupalCreateNode(array('uid' => $user->uid));
+ $edit = array();
+ $edit['body'] = '<?php print "SimpleTest PHP was executed!"; ?>';
+ $this->drupalPost('node/'. $node->nid .'/edit', $edit, t('Save'));
+ $this->assertRaw(t('Page %title has been updated.', array('%title' => $node->title)), t('PHP code inserted into node.'));
+ return $node;
+ }
+}
diff --git a/modules/poll/poll.test b/modules/poll/poll.test
new file mode 100644
index 000000000..aed2a92b1
--- /dev/null
+++ b/modules/poll/poll.test
@@ -0,0 +1,92 @@
+<?php
+// $Id$
+
+class PollTestCase extends DrupalWebTestCase {
+
+ function pollCreate($standalone = TRUE) {
+ $this->assertTrue(TRUE, 'Poll create' . $standalone);
+ $web_user = $this->drupalCreateUser(array('create poll content', 'access content'));
+ $this->drupalLogin($web_user);
+ $title = $this->randomName();
+ $edit = array (
+ 'title' => $title,
+ 'choice[0][chtext]' => 'choice 1',
+ 'choice[1][chtext]' => 'choice 2',
+ );
+ $this->drupalPost('node/add/poll', $edit, t('More choices'));
+ $edit = array(
+ 'title' => $title,
+ 'choice[0][chtext]' => 'choice 1',
+ 'choice[1][chtext]' => 'choice 2',
+ 'choice[2][chtext]' => 'choice 3',
+ 'choice[3][chtext]' => 'choice 4',
+ 'choice[4][chtext]' => 'choice 5',
+ 'choice[5][chtext]' => 'choice 6',
+ 'choice[6][chtext]' => 'choice 7',
+ );
+ if ($standalone) {
+ $this->drupalPost(NULL, $edit, t('Preview'));
+ for ($i = 0; $i <= 6; $i++) {
+ $bar = theme('poll_bar', $edit['choice['. $i .'][chtext]'], NULL, 0, FALSE, FALSE);
+ $this->assertTrue($bar, "bar $i is themed");
+ $this->assertRaw($bar, "bar $i found in preview");
+ }
+ }
+ $this->drupalPost(NULL, $edit, t('Save'));
+ $node = node_load(array('title' => $title));
+ $this->nid = $node->nid;
+ $this->assertRaw(t('@type %title has been created.', array('@type' => node_get_types('name', 'poll'), '%title' => $title)), 'Poll has been created.');
+ $this->assertTrue($this->nid, t('Poll has been found in the database'));
+ }
+
+}
+
+class PollCreateTestCase extends PollTestCase {
+
+ /**
+ * Implementation of getInfo() for information
+ */
+ function getInfo() {
+ return array('name' => t('Poll create'), 'description' => 'Adds "more choices", previews and creates a poll.', 'group' => t('Poll'));
+ }
+
+ function setUp() {
+ parent::setUp('poll');
+ }
+
+ function testPollCreate() {
+ $this->pollCreate(TRUE);
+ }
+}
+
+class PollVoteTestCase extends PollTestCase {
+ /**
+ * Implementation of getInfo() for information
+ */
+ function getInfo() {
+ return array('name' => t('Poll vote'), 'description' => 'Vote on a poll', 'group' => t('Poll'));
+ }
+
+ function setUp() {
+ parent::setUp('poll');
+ }
+
+ function tearDown() {
+ parent::tearDown();
+ }
+
+ function testPollVote() {
+ $this->pollCreate(FALSE);
+ $this->drupalGet('logout');
+ $web_user = $this->drupalCreateUser(array('cancel own vote', 'inspect all votes', 'vote on polls', 'access content'));
+ $this->drupalLogin($web_user);
+ $edit = array (
+ 'choice' => '1',
+ );
+ $this->drupalPost('node/'. $this->nid, $edit, t('Vote'));
+ $this->assertText('Your vote was recorded.', 'Your vote was recorded.');
+ $this->drupalGet("node/$this->nid/votes");
+ $this->assertText(t('This table lists all the recorded votes for this poll. If anonymous users are allowed to vote, they will be identified by the IP address of the computer they used when they voted.'), 'Vote table text.');
+ $this->assertText('choice 2', 'vote recorded');
+ }
+}
diff --git a/modules/profile/profile.test b/modules/profile/profile.test
new file mode 100644
index 000000000..33fa02e59
--- /dev/null
+++ b/modules/profile/profile.test
@@ -0,0 +1,975 @@
+<?php
+// $Id$
+
+class ProfileTestSingleTestCase extends DrupalWebTestCase {
+ function getInfo() {
+ $modules = (module_list());
+ return array('name' => 'Test single field', 'description' => "Testing profile module with add/edit/delete new fields into profile page" , 'group' => t('Profile'));
+ }
+
+ function _rolesApi($op, $edit) {
+ if ($op == 'delete') {
+ $id = $edit['rid'];
+ db_query('DELETE FROM {role} WHERE rid = %d', $id);
+ db_query('DELETE FROM {permission} WHERE rid = %d', $id);
+
+ // Update the users who have this role set:
+ $result = db_query('SELECT DISTINCT(ur1.uid) FROM {users_roles} ur1 LEFT JOIN {users_roles} ur2 ON ur2.uid = ur1.uid WHERE ur1.rid = %d AND ur2.rid != ur1.rid', $id);
+ $uid = array();
+
+ while ($u = db_fetch_object($result)) {
+ $uid[] = $u->uid;
+ }
+
+ if ($uid) {
+ db_query('DELETE FROM {users_roles} WHERE rid = %d AND uid IN (%s)', $id, implode(', ', $uid));
+ }
+
+ // Users with only the deleted role are put back in the authenticated users pool.
+ db_query('UPDATE {users_roles} SET rid = %d WHERE rid = %d', DRUPAL_AUTHENTICATED_RID, $id);
+
+ }
+ else if ($op == 'add') {
+ if (isset($edit['name'])) {
+ db_query("INSERT INTO {role} (name) VALUES ('%s')", $edit['name']);
+ $result = db_query("SELECT rid FROM {role} WHERE name = '%s'", $edit['name']);
+ $rid = db_result($result);
+ db_query("INSERT INTO {permission} (rid, perm) VALUES (%d, '%s')", $rid, $edit['perm']);
+ return $rid;
+ }
+ else {
+ return 0;
+ }
+ }
+ }
+
+ function testProfileSingle() {
+ $this->drupalModuleEnable('profile');
+ // create test user
+ $edit['name'] = 'Profile '. $this->randomName(5);
+ $edit['perm'] = 'access administration pages, administer site configuration, administer users';
+ $rid = $this->_rolesApi('add', $edit );
+ $name = $this->randomName();
+ $pass = $this->randomName();
+ $mail = "$name@example.com";
+ unset($edit);
+ $edit['roles'] = array($rid => $rid);
+ $user = user_save('', array('name' => $name, 'pass' => $pass, 'init' => $mail, 'mail' => $mail, 'roles' => $edit['roles'], 'status' => 1));
+ //log in
+ $edit = array('name' => $name, 'pass' => $pass);
+ $this->drupalPost('user', $edit, t('Log in'));
+
+ //wartosci
+ $my_category = 'Simpletest';
+ //single line textfield
+ $title = "single_" . $this->randomName(10);
+ $form_name = 'profile_' . $title;
+ $explanation = $this->randomName(50);
+ $edit = array('category' => $my_category,
+ 'title' => $title,
+ 'name' => $form_name,
+ 'explanation' => $explanation,
+ );
+ $this->drupalPost('admin/user/profile/add/textfield', $edit, t('Save field'), 0);
+ $fid = db_result(db_query('SELECT fid FROM {profile_fields} WHERE title = "%s"', $title));
+ $single_field = array('title' => $title, 'form_name' => $form_name, 'explanation' => $explanation);
+
+ // checking simple fields
+ $this->drupalGet("user/". $user->uid. "/edit/$my_category");
+
+ // checking field
+ $this->assertField($form_name , t('Found form named @name', array('@name' => $form_name)));
+ // checking name
+ $this->assertText($title, "Checking title for ". $title);
+ // checking explanation
+ $this->assertText($explanation, "Checking explanation for ". $title);
+
+ // ok, now let put some data
+ unset($edit);
+ $edit = array();
+ $checking = array();
+ $edit[$form_name] = $this->randomName(20);
+ $this->drupalPost("user/". $user->uid. "/edit/$my_category", $edit, t('Save') , 0);
+ $this->drupalGet("user/". $user->uid);
+
+ // checking profile page
+ $this->assertText($edit[$form_name], "Checking ". $edit[$form_name]);
+ $this->assertText($title, "Checking $title");
+ // update field
+ $new_title = $this->randomName(20);
+ $this->drupalPost("admin/user/profile/edit/$fid", array('title' => $new_title), t('Save field') , 0);
+ $this->drupalGet("admin/user/profile");
+ $this->assertText($new_title, "Checking updated field");
+ // deleting field
+ $this->drupalPost("admin/user/profile/delete/$fid", array(), t('Delete'), 0);
+ $this->drupalGet("admin/user/profile");
+ $this->assertNoText($new_title, "Checking deleted field $title");
+
+ // delete test user and roles
+ if ($user->uid > 0) {
+ db_query('DELETE FROM {users} WHERE uid =%d', $user->uid);
+ db_query('DELETE FROM {users_roles} WHERE uid = %d', $user->uid);
+ module_invoke_all('user', 'delete', '', $user);
+ }
+
+ //delete roles
+ $edit['rid'] = $rid;
+ $this->_rolesApi('delete', $edit);
+ }
+
+}
+
+class ProfileTestTextareaTestCase extends DrupalWebTestCase {
+ function getInfo() {
+ $modules = (module_list());
+ return array('name' => 'Test textarea field', 'description' => "Testing profile module with add/edit/delete new fields into profile page" , 'group' => t('Profile'));
+ }
+
+ function _rolesApi($op, $edit) {
+ if ($op == 'delete') {
+ $id = $edit['rid'];
+ db_query('DELETE FROM {role} WHERE rid = %d', $id);
+ db_query('DELETE FROM {permission} WHERE rid = %d', $id);
+
+ // Update the users who have this role set:
+ $result = db_query('SELECT DISTINCT(ur1.uid) FROM {users_roles} ur1 LEFT JOIN {users_roles} ur2 ON ur2.uid = ur1.uid WHERE ur1.rid = %d AND ur2.rid != ur1.rid', $id);
+ $uid = array();
+
+ while ($u = db_fetch_object($result)) {
+ $uid[] = $u->uid;
+ }
+
+ if ($uid) {
+ db_query('DELETE FROM {users_roles} WHERE rid = %d AND uid IN (%s)', $id, implode(', ', $uid));
+ }
+
+ // Users with only the deleted role are put back in the authenticated users pool.
+ db_query('UPDATE {users_roles} SET rid = %d WHERE rid = %d', DRUPAL_AUTHENTICATED_RID, $id);
+
+ }
+ else if ($op == 'add') {
+ if (isset($edit['name'])) {
+ db_query("INSERT INTO {role} (name) VALUES ('%s')", $edit['name']);
+ $result = db_query("SELECT rid FROM {role} WHERE name = '%s'", $edit['name']);
+ $rid = db_result($result);
+ db_query("INSERT INTO {permission} (rid, perm) VALUES (%d, '%s')", $rid, $edit['perm']);
+ return $rid;
+ }
+ else {
+ return 0;
+ }
+ }
+ }
+
+ function testProfileSingle() {
+ $this->drupalModuleEnable('profile');
+ // create test user
+ $edit['name'] = 'Profile '. $this->randomName(5);
+ $edit['perm'] = 'access content, administer users, administer site configuration, access administration pages, access configuration pages, access user profiles';
+ $rid = $this->_rolesApi('add', $edit );
+ $name = $this->randomName();
+ $pass = $this->randomName();
+ $mail = "$name@example.com";
+ unset($edit);
+ $edit['roles'] = array($rid => $rid);
+ $user = user_save('', array('name' => $name, 'pass' => $pass, 'init' => $mail, 'mail' => $mail, 'roles' => $edit['roles'], 'status' => 1));
+ //log in
+ $edit = array('name' => $name, 'pass' => $pass);
+ $this->drupalPost('user', $edit, t('Log in'), 0 );
+
+ //wartosci
+ $my_category = 'Simpletest';
+ //single line textfield
+ $title = "single_" . $this->randomName(10);
+ $form_name = 'profile_' . $title;
+ $explanation = $this->randomName(50);
+ $edit = array('category' => $my_category, 'title' => $title, 'name' => $form_name, 'explanation' => $explanation);
+ $this->drupalPost("admin/user/profile/add/textarea", $edit, t('Save field'), 0);
+ $fid = db_result(db_query('SELECT fid FROM {profile_fields} WHERE title = "%s"', $title));
+ $single_field = array('title' => $title, 'form_name' => $form_name, 'explanation' => $explanation);
+
+ // checking simple fields
+ $this->drupalGet("user/". $user->uid. "/edit/$my_category");
+
+ // checking field
+ $this->assertField($form_name, '');
+ // checking name
+ $this->assertText($title, "Checking title for ". $title);
+ // checking explanation
+ $this->assertText($explanation, "Checking explanation for ". $title);
+
+ // ok, now let put some data
+ unset($edit);
+ $edit = array();
+ $checking = array();
+ $edit[$form_name] = $this->randomName(20);
+ $this->drupalPost("user/". $user->uid. "/edit/$my_category", $edit, t('Save'), 0);
+ $this->drupalGet("user/". $user->uid);
+
+ // checking profile page
+ $this->assertText($edit[$form_name], "Checking ". $edit[$form_name]);
+ $this->assertText($title, "Checking $title");
+ // update field
+ $new_title = $this->randomName(20);
+ $this->drupalPost("admin/user/profile/edit/$fid", array('title' => $new_title), t('Save field'), 0);
+ $this->drupalGet("admin/user/profile");
+ $this->assertText($new_title, "Checking updated field");
+ // deleting field
+ $this->drupalPost("admin/user/profile/delete/$fid", array(), t('Delete'), 0);
+ $this->drupalGet("admin/user/profile");
+ $this->assertNoText($new_title, "Checking deleted field $title");
+
+ // delete test user and roles
+ if ($user->uid > 0) {
+ db_query('DELETE FROM {users} WHERE uid =%d', $user->uid);
+ db_query('DELETE FROM {users_roles} WHERE uid = %d', $user->uid);
+ module_invoke_all('user', 'delete', '', $user);
+ }
+
+ //delete roles
+ $edit['rid'] = $rid;
+ $this->_rolesApi('delete', $edit);
+ }
+}
+
+
+class ProfileTestFreelistTestCase extends DrupalWebTestCase {
+ function getInfo() {
+ $modules = (module_list());
+ return array('name' => 'Test freelist field', 'description' => "Testing profile module with add/edit/delete new fields into profile page" , 'group' => t('Profile'));
+ }
+
+ function _rolesApi($op, $edit) {
+ if ($op == 'delete') {
+ $id = $edit['rid'];
+ db_query('DELETE FROM {role} WHERE rid = %d', $id);
+ db_query('DELETE FROM {permission} WHERE rid = %d', $id);
+
+ // Update the users who have this role set:
+ $result = db_query('SELECT DISTINCT(ur1.uid) FROM {users_roles} ur1 LEFT JOIN {users_roles} ur2 ON ur2.uid = ur1.uid WHERE ur1.rid = %d AND ur2.rid != ur1.rid', $id);
+ $uid = array();
+
+ while ($u = db_fetch_object($result)) {
+ $uid[] = $u->uid;
+ }
+
+ if ($uid) {
+ db_query('DELETE FROM {users_roles} WHERE rid = %d AND uid IN (%s)', $id, implode(', ', $uid));
+ }
+
+ // Users with only the deleted role are put back in the authenticated users pool.
+ db_query('UPDATE {users_roles} SET rid = %d WHERE rid = %d', DRUPAL_AUTHENTICATED_RID, $id);
+
+ }
+ else if ($op == 'add') {
+ if (isset($edit['name'])) {
+ db_query("INSERT INTO {role} (name) VALUES ('%s')", $edit['name']);
+ $result = db_query("SELECT rid FROM {role} WHERE name = '%s'", $edit['name']);
+ $rid = db_result($result);
+ db_query("INSERT INTO {permission} (rid, perm) VALUES (%d, '%s')", $rid, $edit['perm']);
+ return $rid;
+ }
+ else {
+ return 0;
+ }
+ }
+ }
+
+ function testProfileSingle() {
+ $this->drupalModuleEnable('profile');
+ // create test user
+ $edit['name'] = 'Profile '. $this->randomName(5);
+ $edit['perm'] = 'access content, administer users, administer site configuration, access administration pages, access configuration pages, access user profiles';
+ $rid = $this->_rolesApi('add', $edit );
+ $name = $this->randomName();
+ $pass = $this->randomName();
+ $mail = "$name@example.com";
+ unset($edit);
+ $edit['roles'] = array($rid => $rid);
+ $user = user_save('', array('name' => $name, 'pass' => $pass, 'init' => $mail, 'mail' => $mail, 'roles' => $edit['roles'], 'status' => 1));
+ //log in
+ $edit = array('name' => $name, 'pass' => $pass);
+ $this->drupalPost('user', $edit, t('Log in'), 0 );
+
+ //wartosci
+ $my_category = 'Simpletest';
+ //single line textfield
+ $title = "single_" . $this->randomName(10);
+ $form_name = 'profile_' . $title;
+ $explanation = $this->randomName(50);
+ $edit = array('category' => $my_category, 'title' => $title, 'name' => $form_name, 'explanation' => $explanation);
+ $this->drupalPost("admin/user/profile/add/list", $edit, t('Save field'), 0);
+ $fid = db_result(db_query('SELECT fid FROM {profile_fields} WHERE title = "%s"', $title));
+ $single_field = array('title' => $title, 'form_name' => $form_name, 'explanation' => $explanation);
+
+ // checking simple fields
+ $this->drupalGet("user/". $user->uid. "/edit/$my_category");
+
+ // checking field
+ $this->assertField($form_name, '');
+ // checking name
+ $this->assertText($title, "Checking title for ". $title);
+ // checking explanation
+ $this->assertText($explanation, "Checking explanation for ". $title);
+
+ // ok, now let put some data
+ unset($edit);
+ $edit = array();
+ $checking = array();
+ $edit[$form_name] = $this->randomName(20);
+ $this->drupalPost("user/". $user->uid. "/edit/$my_category", $edit, t('Save'), 0);
+ $this->drupalGet("user/". $user->uid);
+
+ // checking profile page
+ $this->assertText($edit[$form_name], "Checking ". $edit[$form_name]);
+ $this->assertText($title, "Checking $title");
+ // update field
+ $new_title = $this->randomName(20);
+ $this->drupalPost("admin/user/profile/edit/$fid", array('title' => $new_title), t('Save field'), 0);
+ $this->drupalGet("admin/user/profile");
+ $this->assertText($new_title, "Checking updated field");
+ // deleting field
+ $this->drupalPost("admin/user/profile/delete/$fid", array(), t('Delete'), 0);
+ $this->drupalGet("admin/user/profile");
+ $this->assertNoText($new_title, "Checking deleted field $title");
+
+ // delete test user and roles
+ if ($user->uid > 0) {
+ db_query('DELETE FROM {users} WHERE uid =%d', $user->uid);
+ db_query('DELETE FROM {users_roles} WHERE uid = %d', $user->uid);
+ module_invoke_all('user', 'delete', '', $user);
+ }
+
+ //delete roles
+ $edit['rid'] = $rid;
+ $this->_rolesApi('delete', $edit);
+ }
+
+}
+
+
+class ProfileTestCheckboxTestCase extends DrupalWebTestCase {
+ function getInfo() {
+ $modules = (module_list());
+ return array('name' => 'Test checkbox field', 'description' => "Testing profile module with add/edit/delete new fields into profile page" , 'group' => t('Profile'));
+ }
+
+ function _rolesApi($op, $edit) {
+ if ($op == 'delete') {
+ $id = $edit['rid'];
+ db_query('DELETE FROM {role} WHERE rid = %d', $id);
+ db_query('DELETE FROM {permission} WHERE rid = %d', $id);
+
+ // Update the users who have this role set:
+ $result = db_query('SELECT DISTINCT(ur1.uid) FROM {users_roles} ur1 LEFT JOIN {users_roles} ur2 ON ur2.uid = ur1.uid WHERE ur1.rid = %d AND ur2.rid != ur1.rid', $id);
+ $uid = array();
+
+ while ($u = db_fetch_object($result)) {
+ $uid[] = $u->uid;
+ }
+
+ if ($uid) {
+ db_query('DELETE FROM {users_roles} WHERE rid = %d AND uid IN (%s)', $id, implode(', ', $uid));
+ }
+
+ // Users with only the deleted role are put back in the authenticated users pool.
+ db_query('UPDATE {users_roles} SET rid = %d WHERE rid = %d', DRUPAL_AUTHENTICATED_RID, $id);
+
+ }
+ else if ($op == 'add') {
+ if (isset($edit['name'])) {
+ db_query("INSERT INTO {role} (name) VALUES ('%s')", $edit['name']);
+ $result = db_query("SELECT rid FROM {role} WHERE name = '%s'", $edit['name']);
+ $rid = db_result($result);
+ db_query("INSERT INTO {permission} (rid, perm) VALUES (%d, '%s')", $rid, $edit['perm']);
+ return $rid;
+ }
+ else {
+ return 0;
+ }
+ }
+ }
+
+ function testProfileCheckbox() {
+ $this->drupalModuleEnable('profile');
+ // create test user
+ $edit['name'] = 'Profile '. $this->randomName(5);
+ $edit['perm'] = 'access content, administer users, administer site configuration, access administration pages, access configuration pages, access user profiles';
+ $rid = $this->_rolesApi('add', $edit );
+ $name = $this->randomName();
+ $pass = $this->randomName();
+ $mail = "$name@example.com";
+ unset($edit);
+ $edit['roles'] = array($rid => $rid);
+ $user = user_save('', array('name' => $name, 'pass' => $pass, 'init' => $mail, 'mail' => $mail, 'roles' => $edit['roles'], 'status' => 1));
+ //log in
+ $edit = array('name' => $name, 'pass' => $pass);
+ $this->drupalPost('user', $edit, t('Log in'), 0);
+
+ //wartosci
+ $my_category = 'Simpletest';
+ //single line textfield
+ $title = "single_" . $this->randomName(10);
+ $form_name = 'profile_' . $title;
+ $explanation = $this->randomName(50);
+ $edit = array('category' => $my_category, 'title' => $title, 'name' => $form_name, 'explanation' => $explanation);
+ $this->drupalPost("admin/user/profile/add/checkbox", $edit, t('Save field'), 0);
+ $fid = db_result(db_query('SELECT fid FROM {profile_fields} WHERE title = "%s"', $title));
+ $single_field = array('title' => $title, 'form_name' => $form_name, 'explanation' => $explanation);
+
+ // checking simple fields
+ $this->drupalGet("user/". $user->uid. "/edit/$my_category");
+
+ // checking field
+ $this->assertField($form_name, false);
+ // checking name
+ $this->assertText($title, "Checking title for ". $title);
+ // checking explanation
+ $this->assertText($explanation, "Checking explanation for ". $title);
+
+ // ok, now let put some data
+ unset($edit);
+ $edit = array();
+ $checking = array();
+ $edit[$form_name] = 1;
+ $this->drupalPost("user/". $user->uid. "/edit/$my_category", $edit, t('Save'), 0);
+ $this->drupalGet("user/". $user->uid);
+ // checking profile page
+ $this->assertText($title, "Checking checkbox");
+ $this->assertText($title, "Checking $title");
+ // update field
+ $new_title = $this->randomName(10);
+ $this->drupalPost("admin/user/profile/edit/$fid", array('title' => $new_title), t('Save field'), 0);
+ $this->drupalGet("admin/user/profile");
+ $this->assertText($new_title, "Checking updated field");
+ // deleting field
+ $this->drupalPost("admin/user/profile/delete/$fid", array(), t('Delete'), 0);
+ $this->drupalGet("admin/user/profile");
+ $this->assertNoText($new_title, "Checking deleted field $title");
+
+ // delete test user and roles
+ if ($user->uid > 0) {
+ db_query('DELETE FROM {users} WHERE uid =%d', $user->uid);
+ db_query('DELETE FROM {users_roles} WHERE uid = %d', $user->uid);
+ module_invoke_all('user', 'delete', '', $user);
+ }
+
+ //delete roles
+ $edit['rid'] = $rid;
+ $this->_rolesApi('delete', $edit);
+ }
+}
+
+class ProfileTestUrlTestCase extends DrupalWebTestCase {
+ function getInfo() {
+ $modules = (module_list());
+ return array('name' => 'Test URL field', 'description' => "Testing profile module with add/edit/delete new fields into profile page" , 'group' => t('Profile'));
+ }
+
+ function _rolesApi($op, $edit) {
+ if ($op == 'delete') {
+ $id = $edit['rid'];
+ db_query('DELETE FROM {role} WHERE rid = %d', $id);
+ db_query('DELETE FROM {permission} WHERE rid = %d', $id);
+
+ // Update the users who have this role set:
+ $result = db_query('SELECT DISTINCT(ur1.uid) FROM {users_roles} ur1 LEFT JOIN {users_roles} ur2 ON ur2.uid = ur1.uid WHERE ur1.rid = %d AND ur2.rid != ur1.rid', $id);
+ $uid = array();
+
+ while ($u = db_fetch_object($result)) {
+ $uid[] = $u->uid;
+ }
+
+ if ($uid) {
+ db_query('DELETE FROM {users_roles} WHERE rid = %d AND uid IN (%s)', $id, implode(', ', $uid));
+ }
+
+ // Users with only the deleted role are put back in the authenticated users pool.
+ db_query('UPDATE {users_roles} SET rid = %d WHERE rid = %d', DRUPAL_AUTHENTICATED_RID, $id);
+
+ }
+ else if ($op == 'add') {
+ if (isset($edit['name'])) {
+ db_query("INSERT INTO {role} (name) VALUES ('%s')", $edit['name']);
+ $result = db_query("SELECT rid FROM {role} WHERE name = '%s'", $edit['name']);
+ $rid = db_result($result);
+ db_query("INSERT INTO {permission} (rid, perm) VALUES (%d, '%s')", $rid, $edit['perm']);
+ return $rid;
+ }
+ else {
+ return 0;
+ }
+ }
+ }
+
+ function testProfileSingle() {
+ variable_set('user_register',1);
+ $this->drupalModuleEnable('profile');
+ // create test user
+ $edit['name'] = 'Profile '. $this->randomName(5);
+ $edit['perm'] = 'access content, administer users, administer site configuration, access administration pages, access configuration pages, access user profiles';
+ $rid = $this->_rolesApi('add', $edit );
+ $name = $this->randomName();
+ $pass = $this->randomName();
+ $mail = "$name@example.com";
+ unset($edit);
+ $edit['roles'] = array($rid => $rid);
+ $user = user_save('', array('name' => $name, 'pass' => $pass, 'init' => $mail, 'mail' => $mail, 'roles' => $edit['roles'], 'status' => 1));
+ //log in
+ $edit = array('name' => $name, 'pass' => $pass);
+ $this->drupalPost('user', $edit, t('Log in'), 0);
+
+ //wartosci
+ $my_category = 'Simpletest';
+ //single line textfield
+ $title = "single_" . $this->randomName(10);
+ $form_name = 'profile_' . $title;
+ $explanation = $this->randomName(50);
+ $edit = array('category' => $my_category, 'title' => $title, 'name' => $form_name, 'explanation' => $explanation);
+ $this->drupalPost("admin/user/profile/add/url", $edit, t('Save field'), 0);
+ $fid = db_result(db_query("SELECT fid FROM {profile_fields} WHERE title = '%s'", $title));
+ $single_field = array('title' => $title, 'form_name' => $form_name, 'explanation' => $explanation);
+
+ // checking simple fields
+ $this->drupalGet("user/". $user->uid. "/edit/$my_category");
+
+ // checking field
+ $this->assertField($form_name, '');
+ // checking name
+ $this->assertText($title, "Checking title for ". $title);
+ // checking explanation
+ $this->assertText($explanation, "Checking explanation for ". $title);
+
+ // ok, now let put some data
+ unset($edit);
+ $edit = array();
+ $checking = array();
+ $edit[$form_name] = 'http://www.' . $this->randomName(10). '.org';
+ $this->drupalPost("user/". $user->uid. "/edit/$my_category", $edit, t('Save'), 0);
+ $this->drupalGet("user/". $user->uid);
+
+ // checking profile page
+ $this->assertText($edit[$form_name], "Checking ". $edit[$form_name]);
+ $this->assertText($title, "Checking $title");
+ // update field
+ $new_title = $this->randomName(20);
+ $this->drupalPost("admin/user/profile/edit/$fid", array('title' => $new_title), t('Save field'), 0);
+ $this->drupalGet("admin/user/profile");
+ $this->assertText($new_title, "Checking updated field");
+ // deleting field
+ $this->drupalPost("admin/user/profile/delete/$fid", array(), t('Delete'), 0);
+ $this->drupalGet("admin/user/profile");
+ $this->assertNoText($new_title, "Checking deleted field $title");
+
+ // delete test user and roles
+ if ($user->uid > 0) {
+ db_query('DELETE FROM {users} WHERE uid =%d', $user->uid);
+ db_query('DELETE FROM {users_roles} WHERE uid = %d', $user->uid);
+ module_invoke_all('user', 'delete', '', $user);
+ }
+
+ //delete roles
+ $edit['rid'] = $rid;
+ $this->_rolesApi('delete', $edit);
+
+ }
+}
+
+class ProfileTestSelectionTestCase extends DrupalWebTestCase {
+ function getInfo() {
+ $modules = (module_list());
+ return array('name' => 'Test selection field', 'description' => "Testing profile module with add/edit/delete new fields into profile page" , 'group' => t('Profile'));
+ }
+
+ function _rolesApi($op, $edit) {
+ if ($op == 'delete') {
+ $id = $edit['rid'];
+ db_query('DELETE FROM {role} WHERE rid = %d', $id);
+ db_query('DELETE FROM {permission} WHERE rid = %d', $id);
+
+ // Update the users who have this role set:
+ $result = db_query('SELECT DISTINCT(ur1.uid) FROM {users_roles} ur1 LEFT JOIN {users_roles} ur2 ON ur2.uid = ur1.uid WHERE ur1.rid = %d AND ur2.rid != ur1.rid', $id);
+ $uid = array();
+
+ while ($u = db_fetch_object($result)) {
+ $uid[] = $u->uid;
+ }
+
+ if ($uid) {
+ db_query('DELETE FROM {users_roles} WHERE rid = %d AND uid IN (%s)', $id, implode(', ', $uid));
+ }
+
+ // Users with only the deleted role are put back in the authenticated users pool.
+ db_query('UPDATE {users_roles} SET rid = %d WHERE rid = %d', DRUPAL_AUTHENTICATED_RID, $id);
+
+ }
+ else if ($op == 'add') {
+ if (isset($edit['name'])) {
+ db_query("INSERT INTO {role} (name) VALUES ('%s')", $edit['name']);
+ $result = db_query("SELECT rid FROM {role} WHERE name = '%s'", $edit['name']);
+ $rid = db_result($result);
+ db_query("INSERT INTO {permission} (rid, perm) VALUES (%d, '%s')", $rid, $edit['perm']);
+ return $rid;
+ }
+ else {
+ return 0;
+ }
+ }
+ }
+
+ function testProfileSingle() {
+ $this->drupalModuleEnable('profile');
+ // create test user
+ $edit['name'] = 'Profile '. $this->randomName(5);
+ $edit['perm'] = 'access content, administer users, administer site configuration, access administration pages, access configuration pages, access user profiles';
+ $rid = $this->_rolesApi('add', $edit );
+ $name = $this->randomName();
+ $pass = $this->randomName();
+ $mail = "$name@example.com";
+ unset($edit);
+ $edit['roles'] = array($rid => $rid);
+ $user = user_save('', array('name' => $name, 'pass' => $pass, 'init' => $mail, 'mail' => $mail, 'roles' => $edit['roles'], 'status' => 1));
+ //log in
+ $edit = array('name' => $name, 'pass' => $pass);
+ $this->drupalPost('user', $edit, t('Log in'), 0);
+
+ //wartosci
+ $my_category = 'Simpletest';
+ //single line textfield
+ $title = "single_" . $this->randomName(10);
+ $form_name = 'profile_' . $title;
+ $explanation = $this->randomName(50);
+ $options = "";
+ for($i = 0; $i < 3; $i++)
+ $options .= $this->randomName(8) . "\n";
+ $edit = array('category' => $my_category, 'title' => $title, 'name' => $form_name, 'explanation' => $explanation, 'options' => $options);
+ $this->drupalPost("admin/user/profile/add/selection", $edit, t('Save field'), 0);
+ $fid = db_result(db_query("SELECT fid FROM {profile_fields} WHERE title = '%s'", $title));
+ $single_field = array('title' => $title, 'form_name' => $form_name, 'explanation' => $explanation);
+
+ // checking simple fields
+ $this->drupalGet("user/". $user->uid. "/edit/$my_category");
+ // checking name
+ $this->assertText($title, "Checking title for ". $title);
+ // checking explanation
+ $this->assertText($explanation, "Checking explanation for ". $title);
+ // can we choose something which doesn't come from the list ?
+ //$this->assertFalse($this->setField('edit['.$form_name .']', $this->randomName(10)));
+ // or can we choose each of our options
+ $op_tab = explode("\n", $options,3);
+ //foreach($op_tab as $option)
+ //$this->assertTrue($this->setField($form_name, $option));
+
+
+ // ok, now let put some data
+ unset($edit);
+ $edit = array();
+ $checking = array();
+ $element = rand(0,2);
+ $key = $form_name;
+ $edit[$key] = rtrim($op_tab[$element]);
+ $this->drupalPost("user/". $user->uid. "/edit/$my_category", $edit, t('Save'), 0);
+ $this->drupalGet("user/". $user->uid);
+
+ // checking profile page
+ $this->assertText($edit[$form_name], "Checking ". $edit[$form_name]);
+ $this->assertText($title, "Checking $title");
+ // update field
+ $new_title = $this->randomName(20);
+ $this->drupalPost("admin/user/profile/edit/$fid", array('title' => $new_title), t('Save field'), 0);
+ $this->drupalGet("admin/user/profile");
+ $this->assertText($new_title, "Checking updated field");
+ // deleting field
+ $this->drupalPost("admin/user/profile/delete/$fid", array(), t('Delete'), 0);
+ $this->drupalGet("admin/user/profile");
+ $this->assertNoText($new_title, "Checking deleted field $title");
+
+ // delete test user and roles
+ if ($user->uid > 0) {
+ db_query('DELETE FROM {users} WHERE uid =%d', $user->uid);
+ db_query('DELETE FROM {users_roles} WHERE uid = %d', $user->uid);
+ module_invoke_all('user', 'delete', '', $user);
+ }
+
+ //delete roles
+ $edit['rid'] = $rid;
+ $this->_rolesApi('delete', $edit);
+
+ }
+
+}
+
+
+class ProfileTestDateTestCase extends DrupalWebTestCase {
+ function getInfo() {
+ $modules = (module_list());
+ return array('name' => 'Test date field', 'description' => "Testing profile module with add/edit/delete new fields into profile page" , 'group' => t('Profile'));
+ }
+
+ function _rolesApi($op, $edit) {
+ if ($op == 'delete') {
+ $id = $edit['rid'];
+ db_query('DELETE FROM {role} WHERE rid = %d', $id);
+ db_query('DELETE FROM {permission} WHERE rid = %d', $id);
+
+ // Update the users who have this role set:
+ $result = db_query('SELECT DISTINCT(ur1.uid) FROM {users_roles} ur1 LEFT JOIN {users_roles} ur2 ON ur2.uid = ur1.uid WHERE ur1.rid = %d AND ur2.rid != ur1.rid', $id);
+ $uid = array();
+
+ while ($u = db_fetch_object($result)) {
+ $uid[] = $u->uid;
+ }
+
+ if ($uid) {
+ db_query('DELETE FROM {users_roles} WHERE rid = %d AND uid IN (%s)', $id, implode(', ', $uid));
+ }
+
+ // Users with only the deleted role are put back in the authenticated users pool.
+ db_query('UPDATE {users_roles} SET rid = %d WHERE rid = %d', DRUPAL_AUTHENTICATED_RID, $id);
+
+ }
+ else if ($op == 'add') {
+ if (isset($edit['name'])) {
+ db_query("INSERT INTO {role} (name) VALUES ('%s')", $edit['name']);
+ $result = db_query("SELECT rid FROM {role} WHERE name = '%s'", $edit['name']);
+ $rid = db_result($result);
+ db_query("INSERT INTO {permission} (rid, perm) VALUES (%d, '%s')", $rid, $edit['perm']);
+ return $rid;
+ }
+ else {
+ return 0;
+ }
+ }
+ }
+
+ function testProfileSingle() {
+ $this->drupalModuleEnable('profile');
+ // create test user
+ $edit['name'] = 'Profile '. $this->randomName(5);
+ $edit['perm'] = 'access content, administer users, administer site configuration, access administration pages, access configuration pages, access user profiles';
+ $rid = $this->_rolesApi('add', $edit );
+ $name = $this->randomName();
+ $pass = $this->randomName();
+ $mail = "$name@example.com";
+ unset($edit);
+ $edit['roles'] = array($rid => $rid);
+ $user = user_save('', array('name' => $name, 'pass' => $pass, 'init' => $mail, 'mail' => $mail, 'roles' => $edit['roles'], 'status' => 1));
+ //log in
+ $edit = array('name' => $name, 'pass' => $pass);
+ $this->drupalPost('user', $edit, t('Log in'), 0);
+
+ //wartosci
+ $my_category = 'Simpletest';
+ //single line textfield
+ $title = "single_" . $this->randomName(10);
+ $form_name = 'profile_' . $title;
+ $explanation = $this->randomName(50);
+ /* $options = "";
+ for($i = 0; $i < 3; $i++)
+ $options .= $this->randomName(8) . "\n";*/
+ $edit = array('category' => $my_category, 'title' => $title, 'name' => $form_name, 'explanation' => $explanation);
+ $this->drupalPost("admin/user/profile/add/date", $edit, t('Save field'), 0);
+ $fid = db_result(db_query("SELECT fid FROM {profile_fields} WHERE title = '%s'", $title));
+ $single_field = array('title' => $title, 'form_name' => $form_name, 'explanation' => $explanation);
+
+ // checking simple fields
+ $this->drupalGet("user/". $user->uid. "/edit/$my_category");
+ // checking name
+ $this->assertText($title, "Checking title for ". $title);
+ // checking explanation
+ $this->assertText($explanation, "Checking explanation for ". $title);
+ // checking days/month/years
+ //foreach(array('year', 'month', 'day') as $field)
+ //$this->assertFalse($this->setField('edit['.$form_name .']['. $field .']', $this->randomName(4)), 'Checking data field ['.$field.']');
+ // ok, now let put some data
+ // date 9-01-1983
+ unset($edit);
+ foreach(array('year' => 1983, 'month' => 'Jan', 'day' => 9) as $field => $v) {
+ $key = $form_name . '[' . $field . ']';
+ $edit[$key] = $v;
+ }
+
+ list($format) = explode(' - ', variable_get('date_format_short', 'm/d/Y'), 2);
+
+ $replace = array('d' => sprintf('%02d', 9),
+ 'j' => 9,
+ 'm' => sprintf('%02d', '1'),
+ 'M' => map_month(1),
+ 'Y' => 1983);
+ $data = strtr($format, $replace);
+ $this->drupalPost("user/". $user->uid. "/edit/$my_category", $edit, t('Save'), 0);
+ $this->drupalGet("user/". $user->uid);
+
+ // checking profile page
+ $this->assertText($data, "Checking date $data");
+ $this->assertText($title, "Checking $title");
+ // update field
+ $new_title = $this->randomName(20);
+ $this->drupalPost("admin/user/profile/edit/$fid", array('title' => $new_title), t('Save field'), 0);
+ $this->drupalGet("admin/user/profile");
+ $this->assertText($new_title, "Checking updated field");
+ // deleting field
+ $this->drupalPost("admin/user/profile/delete/$fid", array(), t('Delete'), 0);
+ $this->drupalGet("admin/user/profile");
+ $this->assertNoText($new_title, "Checking deleted field $title");
+
+ // delete test user and roles
+ if ($user->uid > 0) {
+ db_query('DELETE FROM {users} WHERE uid =%d', $user->uid);
+ db_query('DELETE FROM {users_roles} WHERE uid = %d', $user->uid);
+ module_invoke_all('user', 'delete', '', $user);
+ }
+
+ //delete roles
+ $edit['rid'] = $rid;
+ $this->_rolesApi('delete', $edit);
+
+ }
+
+}
+
+
+class ProfileTest2TestCase extends DrupalWebTestCase {
+ function getInfo() {
+ $modules = (module_list());
+ return array('name' => 'Test other fields', 'description' => "Testing weight, title page, required" , 'group' => t('Profile'));
+ }
+
+ function _rolesApi($op, $edit) {
+ if ($op == 'delete') {
+ $id = $edit['rid'];
+ db_query('DELETE FROM {role} WHERE rid = %d', $id);
+ db_query('DELETE FROM {permission} WHERE rid = %d', $id);
+
+ // Update the users who have this role set:
+ $result = db_query('SELECT DISTINCT(ur1.uid) FROM {users_roles} ur1 LEFT JOIN {users_roles} ur2 ON ur2.uid = ur1.uid WHERE ur1.rid = %d AND ur2.rid != ur1.rid', $id);
+ $uid = array();
+
+ while ($u = db_fetch_object($result)) {
+ $uid[] = $u->uid;
+ }
+
+ if ($uid) {
+ db_query('DELETE FROM {users_roles} WHERE rid = %d AND uid IN (%s)', $id, implode(', ', $uid));
+ }
+
+ // Users with only the deleted role are put back in the authenticated users pool.
+ db_query('UPDATE {users_roles} SET rid = %d WHERE rid = %d', DRUPAL_AUTHENTICATED_RID, $id);
+
+ }
+ else if ($op == 'add') {
+ if (isset($edit['name'])) {
+ db_query("INSERT INTO {role} (name) VALUES ('%s')", $edit['name']);
+ $result = db_query("SELECT rid FROM {role} WHERE name = '%s'", $edit['name']);
+ $rid = db_result($result);
+ db_query("INSERT INTO {permission} (rid, perm) VALUES (%d, '%s')", $rid, $edit['perm']);
+ return $rid;
+ }
+ else {
+ return 0;
+ }
+ }
+
+ }
+
+ function testProfileOtherFields() {
+ $this->drupalModuleEnable('profile');
+ // create test user
+ $edit['name'] = 'Profile '. $this->randomName(5);
+ $edit['perm'] = 'access content, administer users, access user profiles, administer site configuration, access administration pages, access configuration pages, access user profiles';
+ $rid = $this->_rolesApi('add', $edit );
+ $name = $this->randomName();
+ $pass = $this->randomName();
+ $mail = "$name@example.com";
+ unset($edit);
+ $edit['roles'] = array($rid => $rid);
+ $user = user_save('', array('name' => $name, 'pass' => $pass, 'init' => $mail, 'mail' => $mail, 'roles' => $edit['roles'], 'status' => 1));
+ //log in
+ $edit = array('name' => $name, 'pass' => $pass);
+ $this->drupalPost('user', $edit, t('Log in'), 0);
+ //wartosci
+ $my_category = $this->randomName(10);
+ //single line textfield
+ $title = "first_" . $this->randomName(10);
+ $form_name = 'profile_' . $title;
+ // weight
+ $weight = 3;
+ $edit = array('category' => $my_category, 'title' => $title, 'name' => $form_name, 'weight' => $weight, 'required' => 1);
+ $this->drupalPost("admin/user/profile/add/textfield", $edit, t('Save field'), 0);
+ $fid = db_result(db_query('SELECT fid FROM {profile_fields} WHERE title = "%s"', $title));
+ $sfield1 = array('fid'=> $fid, 'title' => $title);
+ //second one line textfield
+ $title = "second_" . $this->randomName(10);
+ $form_name = 'profile_' . $title;
+ // weight
+ $weight = -2;
+ $edit = array('category' => $my_category, 'title' => $title, 'name' => $form_name, 'weight' => $weight, 'register' => 1, 'required' => 1);
+ $this->drupalPost("admin/user/profile/add/textfield", $edit, t('Save field'), 0);
+ $fid = db_result(db_query('SELECT fid FROM {profile_fields} WHERE title = "%s"', $title));
+ $sfield2 = array('fid'=> $fid, 'title' => $title);
+ // checking
+ $this->drupalGet("user/". $user->uid. "/edit/$my_category");
+ $content = $this->drupalGetContent();
+ $pos1 = strpos($content, $sfield1['title']);
+ $pos2 = strpos($content, $sfield2['title']);
+ $this->assertTrue($pos2 < $pos1, 'Checking weight field');
+ $delete_fields = array();
+ $delete_fields[] = $sfield1['fid'];
+ $delete_fields[] = $sfield2['fid'];
+ // check if this field is visible in registration form
+ // logout
+ $this->drupalGet("logout");
+ $this->drupalGet("user/register");
+ $this->assertNoText($sfield1['title'], 'Field is not visible in registration form');
+ $this->assertText($sfield2['title'], 'Field is visible in registration form');
+ // try to register
+ $fname = $this->randomName(5, 'simpletest_');
+ $fmail = "$fname@drupaltest.example.com";
+ $edit = array('name' => $fname,
+ 'mail' => $fmail);
+ $this->drupalPost('user/register', $edit, t('Create new account'), 0);
+ //$key = t('The field %field is required.', array('%field' => $title));
+ //$this->assertText($key, 'Checking error message');
+ //log in
+ $edit = array('name' => $name, 'pass' => $pass);
+ $this->drupalPost('user', $edit, t('Log in'), 0);
+ // TITLE
+ //selection
+ $title = $this->randomName(10);
+ $form_name = 'profile_' . $title;
+ $page_title = $this->randomName(5) . " %value";
+ $options = "";
+ for($i = 0; $i < 3; $i++)
+ $options .= $this->randomName(8) . "\n";
+ $edit = array('category' => $my_category, 'title' => $title, 'name' => $form_name, 'page' => $page_title, 'options' => $options);
+ $this->drupalPost("admin/user/profile/add/selection", $edit, t('Save field'), 0);
+ $fid = db_result(db_query('SELECT fid FROM {profile_fields} WHERE title = "%s"', $title));
+ $element = rand(0,2);
+ $op_tab = explode("\n", $options,3);
+ $choice = rtrim($op_tab[$element]);
+ // checking
+ $this->drupalGet("profile/". $form_name. "/$choice");
+ $title = str_replace("%value", $choice, $page_title);
+
+ $this->assertTitle($title. ' | '. variable_get('site_name', 'Drupal'), "Checking title $title");
+ $this->assertText($title, "Checking $title in content");
+ $delete_fields[] = $fid;
+
+ foreach($delete_fields as $delfid) {
+ $this->drupalPost("admin/user/profile/delete/".$delfid, array(), t('Delete'), 0 );
+ }
+ // delete test user and roles
+ if ($user->uid > 0) {
+ db_query('DELETE FROM {users} WHERE uid =' .
+ ' %d', $user->uid);
+ db_query('DELETE FROM {users_roles} WHERE uid = %d', $user->uid);
+ module_invoke_all('user', 'delete', '', $user);
+ }
+ //delete roles
+ $edit['rid'] = $rid;
+ $this->_rolesApi('delete', $edit);
+
+ }
+}
+
+?>
diff --git a/modules/search/search.test b/modules/search/search.test
new file mode 100644
index 000000000..6ef586141
--- /dev/null
+++ b/modules/search/search.test
@@ -0,0 +1,162 @@
+<?php
+// $Id$
+
+define('SEARCH_TYPE', '_test_');
+
+class SearchMatchTestCase extends DrupalWebTestCase {
+ /**
+ * Implementation of getInfo().
+ */
+ function getInfo() {
+ return array(
+ 'name' => t('Search engine queries'),
+ 'description' => t('Indexes content and queries it.'),
+ 'group' => t('Search'),
+ );
+ }
+
+ /**
+ * Implementation setUp().
+ */
+ function setUp() {
+ parent::setUp('search');
+ }
+
+ /**
+ * Test search indexing.
+ */
+ function testMatching() {
+ $this->_setup();
+ $this->_testQueries();
+ }
+
+ /**
+ * Set up a small index of items to test against.
+ */
+ function _setup() {
+ variable_set('minimum_word_size', 3);
+
+ for ($i = 1; $i <= 7; ++$i) {
+ search_index($i, SEARCH_TYPE, $this->getText($i));
+ }
+ search_update_totals();
+ }
+
+ /**
+ * Helper method for generating snippets of content.
+ *
+ * Generated items to test against:
+ * 1 ipsum
+ * 2 dolore sit
+ * 3 sit am ut
+ * 4 am ut enim am
+ * 5 ut enim am minim veniam
+ * 6 enim am minim veniam es cillum
+ * 7 am minim veniam es cillum dolore eu
+ */
+ function getText($n) {
+ $words = explode(' ', "Ipsum dolore sit am. Ut enim am minim veniam. Es cillum dolore eu.");
+ return implode(' ', array_slice($words, $n - 1, $n));
+ }
+
+ /**
+ * Run predefine queries looking for indexed terms.
+ */
+ function _testQueries() {
+ /*
+ Note: OR queries that include short words in OR groups are only accepted
+ if the ORed terms are ANDed with at least one long word in the rest of the query.
+
+ e.g. enim dolore OR ut = enim (dolore OR ut) = (enim dolor) OR (enim ut) -> good
+ e.g. dolore OR ut = (dolore) OR (ut) -> bad
+
+ This is a design limitation to avoid full table scans.
+ */
+ $queries = array(
+ // Simple AND queries.
+ 'ipsum' => array(1),
+ 'enim' => array(4, 5, 6),
+ 'xxxxx' => array(),
+ 'enim minim' => array(5, 6),
+ 'enim xxxxx' => array(),
+ 'dolore eu' => array(7),
+ 'dolore xx' => array(),
+ 'ut minim' => array(5),
+ 'xx minim' => array(),
+ 'enim veniam am minim ut' => array(5),
+ // Simple OR queries.
+ 'dolore OR ipsum' => array(1, 2, 7),
+ 'dolore OR xxxxx' => array(2, 7),
+ 'dolore OR ipsum OR enim' => array(1, 2, 4, 5, 6, 7),
+ 'ipsum OR dolore sit OR cillum' => array(2, 7),
+ 'minim dolore OR ipsum' => array(7),
+ 'dolore OR ipsum veniam' => array(7),
+ 'minim dolore OR ipsum OR enim' => array(5, 6, 7),
+ 'dolore xx OR yy' => array(),
+ 'xxxxx dolore OR ipsum' => array(),
+ // Negative queries.
+ 'dolore -sit' => array(7),
+ 'dolore -eu' => array(2),
+ 'dolore -xxxxx' => array(2, 7),
+ 'dolore -xx' => array(2, 7),
+ // Phrase queries.
+ '"dolore sit"' => array(2),
+ '"sit dolore"' => array(),
+ '"am minim veniam es"' => array(6, 7),
+ '"minim am veniam es"' => array(),
+ // Mixed queries.
+ '"am minim veniam es" OR dolore' => array(2, 6, 7),
+ '"minim am veniam es" OR "dolore sit"' => array(2),
+ '"minim am veniam es" OR "sit dolore"' => array(),
+ '"am minim veniam es" -eu' => array(6),
+ '"am minim veniam" -"cillum dolore"' => array(5, 6),
+ '"am minim veniam" -"dolore cillum"' => array(5, 6, 7),
+ 'xxxxx "minim am veniam es" OR dolore' => array(),
+ 'xx "minim am veniam es" OR dolore' => array()
+ );
+ foreach ($queries as $query => $results) {
+ $set = do_search($query, SEARCH_TYPE);
+ $this->_testQueryMatching($query, $set, $results);
+ $this->_testQueryScores($query, $set, $results);
+ }
+ }
+
+ /**
+ * Test the matching abilities of the engine.
+ *
+ * Verify if a query produces the correct results.
+ */
+ function _testQueryMatching($query, $set, $results) {
+ // Get result IDs.
+ $found = array();
+ foreach ($set as $item) {
+ $found[] = $item->sid;
+ }
+
+ // Compare $results and $found.
+ sort($found);
+ sort($results);
+ $this->assertEqual($found, $results, "Query matching '$query'");
+ }
+
+ /**
+ * Test the scoring abilities of the engine.
+ *
+ * Verify if a query produces normalized, monotonous scores.
+ */
+ function _testQueryScores($query, $set, $results) {
+ // Get result scores.
+ $scores = array();
+ foreach ($set as $item) {
+ $scores[] = $item->score;
+ }
+
+ // Check order.
+ $sorted = $scores;
+ sort($sorted);
+ $this->assertEqual($scores, array_reverse($sorted), "Query order '$query'");
+
+ // Check range.
+ $this->assertEqual(!count($scores) || (min($scores) > 0.0 && max($scores) <= 1.0001), TRUE, "Query scoring '$query'");
+ }
+}
diff --git a/modules/simpletest/files/README.txt b/modules/simpletest/files/README.txt
new file mode 100644
index 000000000..d808510da
--- /dev/null
+++ b/modules/simpletest/files/README.txt
@@ -0,0 +1,5 @@
+$Id$
+
+These files are use in some tests that upload files or other operations were
+a file is useful. These files are copied to the files directory as specified
+in the site settings. Other tests files are generated in order to save space. \ No newline at end of file
diff --git a/modules/simpletest/files/html-1.txt b/modules/simpletest/files/html-1.txt
new file mode 100644
index 000000000..494470d17
--- /dev/null
+++ b/modules/simpletest/files/html-1.txt
@@ -0,0 +1 @@
+<h1>SimpleTest HTML</h1> \ No newline at end of file
diff --git a/modules/simpletest/files/html-2.html b/modules/simpletest/files/html-2.html
new file mode 100644
index 000000000..494470d17
--- /dev/null
+++ b/modules/simpletest/files/html-2.html
@@ -0,0 +1 @@
+<h1>SimpleTest HTML</h1> \ No newline at end of file
diff --git a/modules/simpletest/files/image-1.png b/modules/simpletest/files/image-1.png
new file mode 100644
index 000000000..f2aac9800
--- /dev/null
+++ b/modules/simpletest/files/image-1.png
Binary files differ
diff --git a/modules/simpletest/files/image-2.jpg b/modules/simpletest/files/image-2.jpg
new file mode 100644
index 000000000..645c76b50
--- /dev/null
+++ b/modules/simpletest/files/image-2.jpg
Binary files differ
diff --git a/modules/simpletest/files/javascript-1.txt b/modules/simpletest/files/javascript-1.txt
new file mode 100644
index 000000000..e0206ba83
--- /dev/null
+++ b/modules/simpletest/files/javascript-1.txt
@@ -0,0 +1,3 @@
+<script>
+alert('SimpleTest PHP was executed!');
+</script> \ No newline at end of file
diff --git a/modules/simpletest/files/javascript-2.script b/modules/simpletest/files/javascript-2.script
new file mode 100644
index 000000000..e0206ba83
--- /dev/null
+++ b/modules/simpletest/files/javascript-2.script
@@ -0,0 +1,3 @@
+<script>
+alert('SimpleTest PHP was executed!');
+</script> \ No newline at end of file
diff --git a/modules/simpletest/files/php-1.txt b/modules/simpletest/files/php-1.txt
new file mode 100644
index 000000000..dc8e64213
--- /dev/null
+++ b/modules/simpletest/files/php-1.txt
@@ -0,0 +1,3 @@
+<?php
+print 'SimpleTest PHP was executed!';
+?> \ No newline at end of file
diff --git a/modules/simpletest/files/php-2.php b/modules/simpletest/files/php-2.php
new file mode 100644
index 000000000..dc8e64213
--- /dev/null
+++ b/modules/simpletest/files/php-2.php
@@ -0,0 +1,3 @@
+<?php
+print 'SimpleTest PHP was executed!';
+?> \ No newline at end of file
diff --git a/modules/simpletest/files/sql-1.txt b/modules/simpletest/files/sql-1.txt
new file mode 100644
index 000000000..22017e972
--- /dev/null
+++ b/modules/simpletest/files/sql-1.txt
@@ -0,0 +1 @@
+SELECT invalid_field FROM {invalid_table} \ No newline at end of file
diff --git a/modules/simpletest/files/sql-2.sql b/modules/simpletest/files/sql-2.sql
new file mode 100644
index 000000000..22017e972
--- /dev/null
+++ b/modules/simpletest/files/sql-2.sql
@@ -0,0 +1 @@
+SELECT invalid_field FROM {invalid_table} \ No newline at end of file
diff --git a/modules/simpletest/simpletest.css b/modules/simpletest/simpletest.css
new file mode 100644
index 000000000..6ceda6111
--- /dev/null
+++ b/modules/simpletest/simpletest.css
@@ -0,0 +1,62 @@
+/* $Id$ */
+
+/* Addon for the simpletest module */
+#simpletest {
+}
+/* Test Table */
+th.simpletest_run {
+ width: 50px;
+}
+th.simpletest_test {
+ width: 160px;
+}
+
+table#simpletest-form-table td div.form-item,
+td.simpletest-select-all {
+ text-align: center;
+}
+
+table#simpletest-form-table tr td {
+ background-color: white !important;
+}
+
+table#simpletest-form-table tr.simpletest-group td {
+ background-color: #EDF5FA !important;
+}
+
+div.simpletest-pass {
+ background: #b6ffb6;
+}
+
+div.simpletest-fail {
+ background: #ffc9c9;
+}
+
+tr.simpletest-pass.odd {
+ background: #b6ffb6;
+}
+
+tr.simpletest-pass.even {
+ background: #9bff9b;
+}
+
+tr.simpletest-fail.odd {
+ background: #ffc9c9;
+}
+
+tr.simpletest-fail.even {
+ background: #ffacac;
+}
+
+tr.simpletest-exception.odd {
+ background: #f4ea71;
+}
+
+tr.simpletest-exception.even {
+ background: #f5e742;
+}
+
+div.simpletest-image {
+ display: inline;
+ cursor: pointer;
+}
diff --git a/modules/simpletest/simpletest.info b/modules/simpletest/simpletest.info
new file mode 100644
index 000000000..9a162e714
--- /dev/null
+++ b/modules/simpletest/simpletest.info
@@ -0,0 +1,6 @@
+; $Id$
+name = "SimpleTest"
+description = "Provides a framework for unit and functional testing."
+package = Core - optional
+version = VERSION
+core = 7.x
diff --git a/modules/simpletest/simpletest.install b/modules/simpletest/simpletest.install
new file mode 100644
index 000000000..4287b2a5d
--- /dev/null
+++ b/modules/simpletest/simpletest.install
@@ -0,0 +1,98 @@
+<?php
+// $Id$
+
+/**
+ * Implementation of hook_install().
+ */
+function simpletest_install() {
+ // Check for files directory.
+ $path = file_directory_path() . '/simpletest';
+ if (file_check_directory($path, FILE_CREATE_DIRECTORY)) {
+ // Generate binary and text test files.
+ $generated = FALSE;
+ if (simpletest_get_file_count($path, 'binary') == 0) {
+ $lines = array(64, 1024);
+ foreach ($lines as $line) {
+ simpletest_generate_file('binary', 64, $line, 'binary');
+ }
+ $generated = TRUE;
+ }
+
+ if (simpletest_get_file_count($path, 'text') == 0) {
+ $lines = array(16, 256, 1024, 2048, 20480);
+ foreach ($lines as $line) {
+ simpletest_generate_file('text', 64, $line);
+ }
+ $generated = TRUE;
+ }
+
+ // Copy other test files for consistency.
+ $files = file_scan_directory($path, '(html|image|javascript|php|sql)-.*');
+ if (count($files) == 0) {
+ $original = drupal_get_path('module', 'simpletest') .'/files';
+ $files = file_scan_directory($original, '(html|image|javascript|php|sql)-.*');
+ foreach ($files as $file) {
+ file_copy($file->filename, $path .'/'. $file->basename);
+ }
+ $generated = TRUE;
+ }
+
+ if ($generated) {
+ drupal_set_message('Extra test files generated.');
+ }
+ }
+}
+
+/**
+ * Generate test file.
+ */
+function simpletest_generate_file($filename, $width, $lines, $type = 'binary-text') {
+ $size = $width * $lines - $lines;
+
+ // Generate random text
+ $text = '';
+ for ($i = 0; $i < $size; $i++) {
+ switch ($type) {
+ case 'text':
+ $text .= chr(rand(32, 126));
+ break;
+ case 'binary':
+ $text .= chr(rand(0, 31));
+ break;
+ case 'binary-text':
+ default:
+ $text .= rand(0, 1);
+ break;
+ }
+ }
+ $text = wordwrap($text, $width - 1, "\n", TRUE) ."\n"; // Add \n for symetrical file.
+
+ // Create filename.
+ $path = file_directory_path() . '/simpletest/';
+ $count = simpletest_get_file_count($path, $filename);
+ file_put_contents($path . $filename .'-'. ($count + 1) .'.txt', $text);
+}
+
+/**
+ * Get the number of files that have the specified filename base.
+ */
+function simpletest_get_file_count($directory, $filename) {
+ $files = scandir($directory);
+ $count = 0;
+ foreach ($files as $file) {
+ if (preg_match('/'. $filename .'.*?/', $file)) {
+ $count++;
+ }
+ }
+ return $count;
+}
+
+/**
+ * Implementation of hook_uninstall().
+ */
+function simpletest_uninstall() {
+ variable_del('simpletest_httpauth');
+ variable_del('simpletest_httpauth_username');
+ variable_del('simpletest_httpauth_pass');
+ variable_del('simpletest_devel');
+}
diff --git a/modules/simpletest/simpletest.js b/modules/simpletest/simpletest.js
new file mode 100644
index 000000000..db9352a24
--- /dev/null
+++ b/modules/simpletest/simpletest.js
@@ -0,0 +1,58 @@
+// $Id$
+
+Drupal.behaviors.simpleTestMenuCollapse = function() {
+ // Adds expand-collapse functionality.
+ $('div.simpletest-image').click(function() {
+ // Toggle all of the trs.
+ if (!Drupal.settings.simpleTest[$(this).attr('id')].clickActive) {
+ Drupal.settings.simpleTest[$(this).attr('id')].clickActive = true;
+ var trs = $(this).parents('tbody').children().filter('.'+ Drupal.settings.simpleTest[$(this).attr('id')].testClass), trs_formatted = [], direction = Drupal.settings.simpleTest[$(this).attr('id')].imageDirection, self = $(this);
+ for (var i = 0; i < trs.length; i++) {
+ trs_formatted.push(trs[i]);
+ }
+ var toggleTrs = function(trs, action, action2) {
+ tr = trs[action]();
+ if (tr) {
+ $(tr)[action2](1, function() {
+ toggleTrs(trs, action, action2);
+ });
+ }
+ else {
+ Drupal.settings.simpleTest[self.attr('id')].clickActive = false;
+ }
+ }
+ toggleTrs(trs_formatted, (direction? 'pop' : 'shift'), (direction? 'fadeOut' : 'fadeIn'));
+ Drupal.settings.simpleTest[$(this).attr('id')].imageDirection = !direction;
+ $(this).html(Drupal.settings.simpleTest.images[(direction? 0 : 1)]);
+ }
+ });
+}
+Drupal.behaviors.simpleTestSelectAll = function() {
+ $('td.simpletest-select-all').each(function() {
+ var checkboxes = Drupal.settings.simpleTest['simpletest-test-group-'+ $(this).attr('id')].testNames,
+ checkbox = $('<input type="checkbox" class="form-checkbox" id="'+ $(this).attr('id') +'-select-all" />').change(function() {
+ var checked = !!($(this).attr('checked'));
+ for (var i = 0; i < checkboxes.length; i++) {
+ $('#'+ checkboxes[i]).attr('checked', checked);
+ }
+ self.data('simpletest-checked-tests', (checked? checkboxes.length : 0));
+ }).data('simpletest-checked-tests', 0);
+ var self = $(this);
+ for (var i = 0; i < checkboxes.length; i++) {
+ $('#'+ checkboxes[i]).change(function() {
+ if (checkbox.attr('checked') == 'checked') {
+ checkbox.attr('checked', '');
+ }
+ var data = (!self.data('simpletest-checked-tests') ? 0 : self.data('simpletest-checked-tests')) + (!!($(this).attr('checked')) ? 1 : -1);
+ self.data('simpletest-checked-tests', data);
+ if (data == checkboxes.length) {
+ checkbox.attr('checked', 'checked');
+ }
+ else {
+ checkbox.attr('checked', '');
+ }
+ });
+ }
+ $(this).append(checkbox);
+ });
+}; \ No newline at end of file
diff --git a/modules/simpletest/simpletest.module b/modules/simpletest/simpletest.module
new file mode 100644
index 000000000..c61c30f83
--- /dev/null
+++ b/modules/simpletest/simpletest.module
@@ -0,0 +1,478 @@
+<?php
+// $Id$
+
+/**
+ * Implementation of hook_help().
+ */
+function simpletest_help($path, $arg) {
+ switch ($path) {
+ case 'admin/help#simpletest':
+ $output = '<p>'. t('The SimpleTest module is a framework for running automated unit tests in Drupal. It can be used to verify a working state of Drupal before and after any code changes, or as a means for developers to write and execute tests for their modules.') .'</p>';
+ $output .= '<p>'. t('Visit <a href="@admin-simpletest">Administer >> Site building >> SimpleTest</a> to display a list of available tests. For comprehensive testing, select <em>all</em> tests, or individually select tests for more targeted testing. Note that it might take several minutes for all tests to complete.)', array('@admin-simpletest' => url('admin/build/testing'))) .'</p>';
+ $output .= '<p>'. t('After the tests have run, a message will be displayed next to each test group indicating whether tests within it passed, failed, or had exceptions. A pass means that a test returned the expected results, while fail means that it did not. An exception normally indicates an error outside of the test, such as a PHP warning or notice. If there were fails or exceptions, the results are expanded, and the tests that had issues will be indicated in red or pink rows. Use these results to refine your code and tests until all tests return a pass.') .'</p>';
+ $output .= '<p>'. t('For more information on creating and modifying your own tests, see the <a href="@simpletest-api">SimpleTest API Documentation</a> in the Drupal handbook.', array('@simpletest-api' => 'http://drupal.org/simpletest')) .'</p>';
+ $output .= '<p>'. t('For more information, see the online handbook entry for <a href="@simpletest">SimpleTest module</a>.', array('@simpletest' => 'http://drupal.org/handbook/modules/simpletest')) .'</p>';
+ return $output;
+ }
+}
+
+/**
+ * Implementation of hook_menu().
+ */
+function simpletest_menu() {
+ $items['admin/build/testing'] = array(
+ 'title' => 'Testing',
+ 'page callback' => 'simpletest_entrypoint',
+ 'description' => 'Run tests against Drupal core and your active modules. These tests help assure that your site code is working as designed.',
+ 'access arguments' => array('administer unit tests'),
+ );
+ $items['admin/settings/testing'] = array(
+ 'title' => 'Testing',
+ 'description' => 'Configure SimpleTest framework.',
+ 'page callback' => 'drupal_get_form',
+ 'page arguments' => array('simpletest_settings'),
+ 'access arguments' => array('access administration pages'),
+ );
+ return $items;
+}
+
+/**
+ * Implementation of hook_perm().
+ */
+function simpletest_perm() {
+ return array(
+ 'administer unit tests' => t('Manage and run automated testing. %warning', array('%warning' => t('Warning: Give to trusted roles only; this permission has security implications.'))),
+ );
+}
+
+/**
+ * Implemenation of hook_theme().
+ */
+function simpletest_theme() {
+ return array(
+ 'simpletest_overview_form' => array(
+ 'arguments' => array('form' => NULL)
+ ),
+ );
+}
+
+/**
+ * Try to load the simepletest
+ * @return boolean TRUE if the load succeeded
+ */
+function simpletest_load() {
+ global $user;
+ static $loaded;
+ if (!$loaded) {
+ $loaded = TRUE;
+ if ($user->uid != 1) {
+ drupal_set_message(t('It is strongly suggested to run the tests with the first user!'));
+ }
+ $path = drupal_get_path('module', 'simpletest') .'/';
+ foreach (array('simpletest.php', 'unit_tester.php', 'reporter.php', 'drupal_reporter.php', 'drupal_web_test_case.php', 'drupal_test_suite.php') as $file) {
+ require_once($path . $file);
+ }
+ }
+}
+
+/**
+ * Menu callback for both running tests and listing possible tests
+ */
+function simpletest_entrypoint() {
+ simpletest_load();
+ drupal_add_css(drupal_get_path('module', 'simpletest') .'/simpletest.css', 'module');
+ drupal_add_js(drupal_get_path('module', 'simpletest') .'/simpletest.js', 'module');
+ $output = drupal_get_form('simpletest_overview_form');
+
+ if (simpletest_running_output()) {
+ return simpletest_running_output() . $output;
+ }
+ else {
+ return $output;
+ }
+}
+
+function simpletest_running_output($output = NULL) {
+ static $o;
+ if ($output != NULL) {
+ $o = $output;
+ }
+ return $o;
+}
+
+/**
+ * Form callback; make the form to run tests
+ */
+function simpletest_overview_form() {
+ $output = array(
+ '#theme' => 'simpletest_overview_form'
+ );
+
+ $total_test = &simpletest_get_total_test();
+
+ $test_instances = $total_test->getTestInstances();
+ uasort($test_instances, 'simpletest_compare_instances');
+
+ foreach ($test_instances as $group_test) {
+ $group = array();
+ $tests = $group_test->getTestInstances();
+ $group_class = str_replace(' ', '-', strtolower($group_test->getLabel()));
+ $group['tests'] = array(
+ '#type' => 'fieldset',
+ '#collapsible' => TRUE,
+ '#collapsed' => TRUE,
+ '#title' => 'Tests',
+ '#attributes' => array('class' => $group_class),
+ );
+ foreach ($tests as $test) {
+ $test_info = $test->getInfo();
+ $group['tests'][get_class($test)] = array(
+ '#type' => 'checkbox',
+ '#title' => $test_info['name'],
+ '#default_value' => 0,
+ '#description' => $test_info['description'],
+ );
+ }
+ $output[] = $group + array(
+ '#type' => 'fieldset',
+ '#collapsible' => FALSE,
+ '#title' => $group_test->getLabel(),
+ '#attributes' => array('class' => 'all-tests'),
+ );
+ }
+
+ $output['run'] = array(
+ '#type' => 'fieldset',
+ '#collapsible' => FALSE,
+ '#collapsed' => FALSE,
+ '#title' => t('Run tests'),
+ );
+ $output['run']['running_options'] = array(
+ '#type' => 'radios',
+ '#default_value' => 'selected_tests',
+ '#options' => array(
+ 'all_tests' => t('Run all tests (WARNING, this may take a long time)'),
+ 'selected_tests' => t('Run selected tests'),
+ ),
+ );
+ $output['run']['op'] = array(
+ '#type' => 'submit',
+ '#value' => t('Run tests'),
+ '#submit' => array('simpletest_run_selected_tests')
+ );
+
+ $output['reset'] = array(
+ '#type' => 'fieldset',
+ '#collapsible' => FALSE,
+ '#collapsed' => FALSE,
+ '#title' => t('Clean test environment'),
+ '#description' => t('Remove tables with the prefix "simpletest" and temporary directories that are left over from tests that crashed.')
+ );
+ $output['reset']['op'] = array(
+ '#type' => 'submit',
+ '#value' => t('Clean environment'),
+ '#submit' => array('simpletest_clean_environment')
+ );
+ return $output;
+}
+
+/**
+ * Theme the SimpleTest form that provides test selection.
+ *
+ * @ingroup themeable
+ */
+function theme_simpletest_overview_form($form) {
+ $header = array(
+ array('data' => t('Run'), 'class' => 'simpletest_run checkbox'),
+ array('data' => t('Test'), 'class' => 'simpletest_test'),
+ array('data' => t('Description'), 'class' => 'simpletest_description'),
+ );
+ $js = array(
+ 'images' => array(
+ theme('image', 'misc/menu-collapsed.png', 'Expand', 'Expand'),
+ theme('image', 'misc/menu-expanded.png', 'Collapsed', 'Collapsed'),
+ ),
+ );
+
+ // Go through each test group and create a row:
+ $rows = array();
+ foreach (element_children($form) as $gid) {
+ if (isset($form[$gid]['tests'])) {
+ $element = &$form[$gid];
+ $test_class = strtolower(trim(preg_replace("/[^\w\d]/", "-",$element["#title"])));
+
+ $row = array();
+ $row[] = array('id' => $test_class, 'class' => 'simpletest-select-all');
+ $row[] = array(
+ 'data' => '<div class="simpletest-image" id="simpletest-test-group-'. $test_class .'">'. $js['images'][0] .'</div>&nbsp;<label for="'. $test_class .'-select-all" class="simpletest-group-label">'. $element['#title'] .'</label>',
+ 'style' => 'font-weight: bold;'
+ );
+ $row[] = $element['#description'];
+ $rows[] = array('data' => $row, 'class' => 'simpletest-group');
+ $current_js = array('testClass' => $test_class .'-test', 'testNames' => array(), 'imageDirection' => 0, 'clickActive' => FALSE);
+
+ // Go through each test in the group and create table rows setting them to invisible:
+ foreach (element_children($element['tests']) as $test_name) {
+ $current_js['testNames'][] = 'edit-'. $test_name;
+ $test = $element['tests'][$test_name];
+ foreach (array('title', 'description') as $key) {
+ $$key = $test['#'. $key];
+ unset($test['#'. $key]);
+ }
+ $test['#name'] = $test_name;
+ $themed_test = drupal_render($test);
+ $row = array();
+ $row[] = $themed_test;
+ $row[] = theme('indentation', 1) .'<label for="edit-'. $test_name .'">'. $title .'</label>';
+ $row[] = '<div class="description">'. $description .'</div>';
+ $rows[] = array('data' => $row, 'style' => 'display: none;', 'class' => $test_class .'-test');
+ }
+ $js['simpletest-test-group-'. $test_class] = $current_js;
+ unset($form[$gid]); // Remove test group from form.
+ }
+ }
+ drupal_add_js(array('simpleTest' => $js), 'setting');
+
+ // Output test groups:
+ $output = '';
+ if (count($rows)) {
+ $output .= theme('table', $header, $rows, array('id' => 'simpletest-form-table'));
+ }
+
+ // Output the rest of the form, excluded test groups which have been removed:
+ $output .= drupal_render($form);
+
+ return $output;
+}
+
+/**
+ * Compare two test instance objects for use in sorting.
+ */
+function simpletest_compare_instances(&$a, &$b) {
+ if (substr_compare($a->_label, $b->_label, 0) > 0) {
+ return 1;
+ }
+ return -1;
+}
+
+/**
+ * Run selected tests.
+ */
+function simpletest_run_selected_tests($form, &$form_state) {
+ $form_state['redirect'] = FALSE;
+ $output = '';
+ switch ($form_state['values']['running_options']) {
+ case 'all_tests':
+ $output = simpletest_run_tests();
+ break;
+ case 'selected_tests':
+ $tests_list = array();
+ foreach ($form_state['values'] as $item => $value) {
+ if ($value === 1 && strpos($item, 'selectall') === FALSE) {
+ $tests_list[] = $item;
+ }
+ }
+ if (count($tests_list) > 0 ) {
+ $output = simpletest_run_tests($tests_list);
+ break;
+ }
+ // Fall through
+ default:
+ drupal_set_message(t('No test has been selected.'), 'error');
+ }
+
+ simpletest_running_output($output);
+ return FALSE;
+}
+
+/**
+ * Remove all temporary database tables and directories.
+ */
+function simpletest_clean_environment() {
+ simpletest_clean_database();
+ simpletest_clean_temporary_directories();
+}
+
+/**
+ * Removed prefixed talbes from the database that are left over from crashed tests.
+ */
+function simpletest_clean_database() {
+ $tables = simpletest_get_like_tables();
+
+ $ret = array();
+ foreach ($tables as $table) {
+ db_drop_table($ret, $table);
+ }
+
+ if (count($ret) > 0) {
+ drupal_set_message(t('Removed @count left over tables.', array('@count' => count($ret))));
+ }
+ else {
+ drupal_set_message(t('No left over tables to remove.'));
+ }
+}
+
+/**
+ * Find all tables that are like the specified base table name.
+ *
+ * @param string $base_table Base table name.
+ * @param boolean $count Return the table count instead of list of tables.
+ * @return mixed Array of matching tables or count of tables.
+ */
+function simpletest_get_like_tables($base_table = 'simpletest', $count = FALSE) {
+ global $db_url, $db_prefix;
+ $url = parse_url($db_url);
+ $database = substr($url['path'], 1);
+ $select = $count ? 'COUNT(table_name)' : 'table_name';
+ $result = db_query("SELECT $select FROM information_schema.tables WHERE table_schema = '$database' AND table_name LIKE '$db_prefix$base_table%'");
+
+ if ($count) {
+ return db_result($result);
+ }
+ $tables = array();
+ while ($table = db_result($result)) {
+ $tables[] = $table;
+ }
+ return $tables;
+}
+
+/**
+ * Find all left over temporary directories and remove them.
+ */
+function simpletest_clean_temporary_directories() {
+ $files = scandir(file_directory_path());
+ $count = 0;
+ foreach ($files as $file) {
+ $path = file_directory_path() .'/'. $file;
+ if (is_dir($path) && preg_match('/^simpletest\d+/', $file)) {
+ simpletest_clean_temporary_directory($path);
+ $count++;
+ }
+ }
+
+ if ($count > 0) {
+ drupal_set_message(t('Removed @count temporary directories.', array('@count' => $count)));
+ }
+ else {
+ drupal_set_message(t('No temporary directories to remove.'));
+ }
+}
+
+/**
+ * Remove all files from specified firectory and then remove directory.
+ *
+ * @param string $path Directory path.
+ */
+function simpletest_clean_temporary_directory($path) {
+ $files = scandir($path);
+ foreach ($files as $file) {
+ if ($file != '.' && $file != '..') {
+ $file_path = "$path/$file";
+ if (is_dir($file_path)) {
+ simpletest_clean_temporary_directory($file_path);
+ }
+ else {
+ file_delete($file_path);
+ }
+ }
+ }
+ rmdir($path);
+}
+
+/**
+ * Actually runs tests
+ * @param array $test_list list of tests to run or DEFAULT NULL run all tests
+ * @param boolean $html_reporter TRUE if you want results in simple html, FALSE for full drupal page
+ */
+function simpletest_run_tests($test_list = NULL, $reporter = 'drupal') {
+ static $test_running;
+ if (!$test_running) {
+ $test_running = TRUE;
+ $test = simpletest_get_total_test($test_list);
+ switch ($reporter) {
+ case 'text':
+ $reporter = &new TextReporter();
+ break;
+ case 'xml':
+ $reporter = &new XMLReporter();
+ break;
+ case 'html':
+ $reporter = &new HtmlReporter();
+ break;
+ case 'drupal':
+ $reporter = &new DrupalReporter();
+ break;
+ }
+
+ cache_clear_all();
+ $results = $test->run($reporter);
+ $test_running = FALSE;
+
+ switch (get_class($reporter)) {
+ case 'TextReporter':
+ case 'XMLReporter':
+ case 'HtmlReporter':
+ return $results;
+ case 'DrupalReporter':
+ return $reporter->getOutput();
+ }
+ }
+}
+
+/**
+ * This function makes sure no unnecessary copies of the DrupalTests object are instantiated
+ * @param array $classes list of all classes the test should concern or
+ * DEFAULT NULL
+ * @return DrupalTests object
+ */
+function &simpletest_get_total_test($classes = NULL) {
+ static $total_test;
+ if (!$total_test) {
+ simpletest_load();
+ $total_test = &new DrupalTests();
+ }
+ if (!is_null($classes)) {
+ $dut = new DrupalTests($classes);
+ return $dut;
+ }
+ return $total_test;
+}
+
+function simpletest_settings() {
+ $form = array();
+
+ $form['http_auth'] = array(
+ '#type' => 'fieldset',
+ '#title' => t('HTTP authentication'),
+ '#description' => t('If needed, enter a username and password for reaching your web site. This is not a drupal username/password.') .
+ t('This is a login presented by your web server. Most sites may leave this section empty.'),
+ );
+ $form['http_auth']['simpletest_httpauth'] = array(
+ '#type' => 'checkbox',
+ '#title' => t('Use http authentication'),
+ '#default_value' => variable_get('simpletest_httpauth', FALSE),
+ );
+ $form['http_auth']['simpletest_httpauth_username'] = array(
+ '#type' => 'textfield',
+ '#title' => t('Username'),
+ '#default_value' => variable_get('simpletest_httpauth_username', ''),
+ );
+ $form['http_auth']['simpletest_httpauth_pass'] = array(
+ '#title' => t('Password'),
+ '#type' => 'password',
+ '#default_value' => variable_get('simpletest_httpauth_pass', ''),
+ );
+ $form['devel'] = array(
+ '#type' => 'fieldset',
+ '#title' => t('Devel module settings'),
+ '#description' => t('Devel module can cause problems if you have query log enabled. It will output a few thousand queries and crash your browser'),
+ );
+ $form['devel']['simpletest_devel'] = array(
+ '#type' => 'checkbox',
+ '#title' => t('Use devel query log on test result pages'),
+ '#default_value' => variable_get('simpletest_devel', FALSE),
+ );
+
+ return system_settings_form($form);
+
+}
diff --git a/modules/simpletest/simpletest.php b/modules/simpletest/simpletest.php
new file mode 100644
index 000000000..c5f647910
--- /dev/null
+++ b/modules/simpletest/simpletest.php
@@ -0,0 +1,369 @@
+<?php
+// $Id$
+
+require_once dirname(__FILE__) .'/test_case.php';
+require_once dirname(__FILE__) .'/unit_tester.php';
+require_once dirname(__FILE__) .'/expectation.php';
+require_once dirname(__FILE__) .'/invoker.php';
+require_once dirname(__FILE__) .'/scorer.php';
+require_once dirname(__FILE__) .'/reporter.php';
+require_once dirname(__FILE__) .'/default_reporter.php';
+require_once dirname(__FILE__) .'/dumper.php';
+require_once dirname(__FILE__) .'/errors.php';
+require_once dirname(__FILE__) .'/exceptions.php';
+require_once dirname(__FILE__) .'/xml.php';
+
+/**
+ * Registry and test context. Includes a few
+ * global options that I'm slowly getting rid of.
+ */
+class SimpleTest {
+ /**
+ * Sets the name of a test case to ignore, usually
+ * because the class is an abstract case that should
+ * not be run. Once PHP4 is dropped this will disappear
+ * as a public method and "abstract" will rule.
+ * @param string $class Add a class to ignore.
+ * @static
+ * @access public
+ */
+ function ignore($class) {
+ $registry = &SimpleTest::_getRegistry();
+ $registry['IgnoreList'][strtolower($class)] = true;
+ }
+
+ /**
+ * Scans the now complete ignore list, and adds
+ * all parent classes to the list. If a class
+ * is not a runnable test case, then it's parents
+ * wouldn't be either. This is syntactic sugar
+ * to cut down on ommissions of ignore()'s or
+ * missing abstract declarations. This cannot
+ * be done whilst loading classes wiithout forcing
+ * a particular order on the class declarations and
+ * the ignore() calls. It's just nice to have the ignore()
+ * calls at the top of the file before the actual declarations.
+ * @param array $classes Class names of interest.
+ * @static
+ * @access public
+ */
+ function ignoreParentsIfIgnored($classes) {
+ $registry = &SimpleTest::_getRegistry();
+ foreach ($classes as $class) {
+ if (SimpleTest::isIgnored($class)) {
+ $reflection = new ReflectionClass($class);
+ if ($parent = $reflection->getParentClass()) {
+ SimpleTest::ignore($parent->getName());
+ }
+ }
+ }
+ }
+
+ /**
+ * Puts the object to the global pool of 'preferred' objects
+ * which can be retrieved with SimpleTest :: preferred() method.
+ * Instances of the same class are overwritten.
+ * @param object $object Preferred object
+ * @static
+ * @access public
+ * @see preferred()
+ */
+ function prefer(&$object) {
+ $registry = &SimpleTest::_getRegistry();
+ $registry['Preferred'][] = &$object;
+ }
+
+ /**
+ * Retrieves 'preferred' objects from global pool. Class filter
+ * can be applied in order to retrieve the object of the specific
+ * class
+ * @param array|string $classes Allowed classes or interfaces.
+ * @static
+ * @access public
+ * @return array|object|null
+ * @see prefer()
+ */
+ function &preferred($classes) {
+ if (! is_array($classes)) {
+ $classes = array($classes);
+ }
+ $registry = &SimpleTest::_getRegistry();
+ for ($i = count($registry['Preferred']) - 1; $i >= 0; $i--) {
+ foreach ($classes as $class) {
+ if (is_a($registry['Preferred'][$i], $class)) {
+ return $registry['Preferred'][$i];
+ }
+ }
+ }
+ return null;
+ }
+
+ /**
+ * Test to see if a test case is in the ignore
+ * list. Quite obviously the ignore list should
+ * be a separate object and will be one day.
+ * This method is internal to SimpleTest. Don't
+ * use it.
+ * @param string $class Class name to test.
+ * @return boolean True if should not be run.
+ * @access public
+ * @static
+ */
+ function isIgnored($class) {
+ $registry = &SimpleTest::_getRegistry();
+ return isset($registry['IgnoreList'][strtolower($class)]);
+ }
+
+ /**
+ * Sets proxy to use on all requests for when
+ * testing from behind a firewall. Set host
+ * to false to disable. This will take effect
+ * if there are no other proxy settings.
+ * @param string $proxy Proxy host as URL.
+ * @param string $username Proxy username for authentication.
+ * @param string $password Proxy password for authentication.
+ * @access public
+ */
+ function useProxy($proxy, $username = false, $password = false) {
+ $registry = &SimpleTest::_getRegistry();
+ $registry['DefaultProxy'] = $proxy;
+ $registry['DefaultProxyUsername'] = $username;
+ $registry['DefaultProxyPassword'] = $password;
+ }
+
+ /**
+ * Accessor for default proxy host.
+ * @return string Proxy URL.
+ * @access public
+ */
+ function getDefaultProxy() {
+ $registry = &SimpleTest::_getRegistry();
+ return $registry['DefaultProxy'];
+ }
+
+ /**
+ * Accessor for default proxy username.
+ * @return string Proxy username for authentication.
+ * @access public
+ */
+ function getDefaultProxyUsername() {
+ $registry = &SimpleTest::_getRegistry();
+ return $registry['DefaultProxyUsername'];
+ }
+
+ /**
+ * Accessor for default proxy password.
+ * @return string Proxy password for authentication.
+ * @access public
+ */
+ function getDefaultProxyPassword() {
+ $registry = &SimpleTest::_getRegistry();
+ return $registry['DefaultProxyPassword'];
+ }
+
+ /**
+ * Accessor for global registry of options.
+ * @return hash All stored values.
+ * @access private
+ * @static
+ */
+ function &_getRegistry() {
+ static $registry = false;
+ if (! $registry) {
+ $registry = SimpleTest::_getDefaults();
+ }
+ return $registry;
+ }
+
+ /**
+ * Accessor for the context of the current
+ * test run.
+ * @return SimpleTestContext Current test run.
+ * @access public
+ * @static
+ */
+ function &getContext() {
+ static $context = false;
+ if (! $context) {
+ $context = new SimpleTestContext();
+ }
+ return $context;
+ }
+
+ /**
+ * Constant default values.
+ * @return hash All registry defaults.
+ * @access private
+ * @static
+ */
+ function _getDefaults() {
+ return array(
+ 'StubBaseClass' => 'SimpleStub',
+ 'MockBaseClass' => 'SimpleMock',
+ 'IgnoreList' => array(),
+ 'DefaultProxy' => false,
+ 'DefaultProxyUsername' => false,
+ 'DefaultProxyPassword' => false,
+ 'Preferred' => array(new HtmlReporter(), new TextReporter(), new XmlReporter()));
+ }
+}
+
+/**
+ * Container for all components for a specific
+ * test run. Makes things like error queues
+ * available to PHP event handlers, and also
+ * gets around some nasty reference issues in
+ * the mocks.
+ * @package SimpleTest
+ */
+class SimpleTestContext {
+ var $_test;
+ var $_reporter;
+ var $_resources;
+
+ /**
+ * Clears down the current context.
+ * @access public
+ */
+ function clear() {
+ $this->_resources = array();
+ }
+
+ /**
+ * Sets the current test case instance. This
+ * global instance can be used by the mock objects
+ * to send message to the test cases.
+ * @param SimpleTestCase $test Test case to register.
+ * @access public
+ */
+ function setTest(&$test) {
+ $this->clear();
+ $this->_test = &$test;
+ }
+
+ /**
+ * Accessor for currently running test case.
+ * @return SimpleTestCase Current test.
+ * @access public
+ */
+ function &getTest() {
+ return $this->_test;
+ }
+
+ /**
+ * Sets the current reporter. This
+ * global instance can be used by the mock objects
+ * to send messages.
+ * @param SimpleReporter $reporter Reporter to register.
+ * @access public
+ */
+ function setReporter(&$reporter) {
+ $this->clear();
+ $this->_reporter = &$reporter;
+ }
+
+ /**
+ * Accessor for current reporter.
+ * @return SimpleReporter Current reporter.
+ * @access public
+ */
+ function &getReporter() {
+ return $this->_reporter;
+ }
+
+ /**
+ * Accessor for the Singleton resource.
+ * @return object Global resource.
+ * @access public
+ * @static
+ */
+ function &get($resource) {
+ if (! isset($this->_resources[$resource])) {
+ $this->_resources[$resource] = &new $resource();
+ }
+ return $this->_resources[$resource];
+ }
+}
+
+/**
+ * Interrogates the stack trace to recover the
+ * failure point.
+ */
+class SimpleStackTrace {
+ var $_prefixes;
+
+ /**
+ * Stashes the list of target prefixes.
+ * @param array $prefixes List of method prefixes
+ * to search for.
+ */
+ function SimpleStackTrace($prefixes) {
+ $this->_prefixes = $prefixes;
+ }
+
+ /**
+ * Extracts the last method name that was not within
+ * Simpletest itself. Captures a stack trace if none given.
+ * @param array $stack List of stack frames.
+ * @return string Snippet of test report with line
+ * number and file.
+ * @access public
+ */
+ function traceMethod($stack = false) {
+ $stack = $stack ? $stack : $this->_captureTrace();
+ foreach ($stack as $frame) {
+ if ($this->_frameLiesWithinSimpleTestFolder($frame)) {
+ continue;
+ }
+ if ($this->_frameMatchesPrefix($frame)) {
+ return ' at [' . $frame['file'] . ' line ' . $frame['line'] . ']';
+ }
+ }
+ return '';
+ }
+
+ /**
+ * Test to see if error is generated by SimpleTest itself.
+ * @param array $frame PHP stack frame.
+ * @return boolean True if a SimpleTest file.
+ * @access private
+ */
+ function _frameLiesWithinSimpleTestFolder($frame) {
+ if (isset($frame['file'])) {
+ $path = dirname(__FILE__);
+ if (strpos($frame['file'], $path) === 0) {
+ if (dirname($frame['file']) == $path) {
+ return true;
+ }
+ }
+ }
+ return false;
+ }
+
+ /**
+ * Tries to determine if the method call is an assert, etc.
+ * @param array $frame PHP stack frame.
+ * @return boolean True if matches a target.
+ * @access private
+ */
+ function _frameMatchesPrefix($frame) {
+ foreach ($this->_prefixes as $prefix) {
+ if (strncmp($frame['function'], $prefix, strlen($prefix)) == 0) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ /**
+ * Grabs a current stack trace.
+ * @return array Fulle trace.
+ * @access private
+ */
+ function _captureTrace() {
+ if (function_exists('debug_backtrace')) {
+ return array_reverse(debug_backtrace());
+ }
+ return array();
+ }
+}
diff --git a/modules/syslog/syslog.test b/modules/syslog/syslog.test
new file mode 100644
index 000000000..1fec48c93
--- /dev/null
+++ b/modules/syslog/syslog.test
@@ -0,0 +1,41 @@
+<?php
+// $Id$
+
+class SyslogTestCase extends DrupalWebTestCase {
+ /**
+ * Implementation of getInfo().
+ */
+ function getInfo() {
+ return array(
+ 'name' => t('Syslog functionality'),
+ 'description' => t('Test syslog settings.'),
+ 'group' => t('Syslog')
+ );
+ }
+
+ /**
+ * Implementation of setUp().
+ */
+ function setUp() {
+ parent::setUp('syslog');
+ }
+
+ /**
+ * Test the syslog settings page.
+ */
+ function testSettings() {
+ $admin_user = $this->drupalCreateUser(array('administer site configuration'));
+ $this->drupalLogin($admin_user);
+
+ $edit = array();
+ $edit['syslog_facility'] = 176; // LOG_LOCAL6 - Local 6.
+ $this->drupalPost('admin/settings/logging/syslog', $edit, t('Save configuration'));
+ $this->assertText(t('The configuration options have been saved.'));
+
+ $this->drupalGet('admin/settings/logging/syslog');
+ if ($this->parse()) {
+ $field = $this->elements->xpath('//option[@value="'. $edit['syslog_facility'] .'"]'); // Should be one field.
+ $this->assertTrue($field[0]['selected'] == 'selected', t('Facility value saved.'));
+ }
+ }
+}
diff --git a/modules/system/system.test b/modules/system/system.test
new file mode 100644
index 000000000..657c4b95e
--- /dev/null
+++ b/modules/system/system.test
@@ -0,0 +1,128 @@
+<?php
+// $Id$
+
+class EnableDisableCoreTestCase extends DrupalWebTestCase {
+ /**
+ * Implementation of getInfo().
+ */
+ function getInfo() {
+ return array(
+ 'name' => t('Module list functionality'),
+ 'description' => t('Enable/disable core module and confirm table creation/deletion. Enable module without dependecy enabled.'),
+ 'group' => t('System')
+ );
+ }
+
+ /**
+ * Implementation of setUp().
+ */
+ function setUp() {
+ parent::setUp();
+
+ $admin_user = $this->drupalCreateUser(array('access administration pages', 'administer site configuration'));
+ $this->drupalLogin($admin_user);
+ }
+
+ /**
+ * Enable a module, check the database for related tables, disable module,
+ * check for related tables, unistall module, check for related tables.
+ */
+ function testEnableDisable() {
+ $admin_user = $this->drupalCreateUser(array('access administration pages', 'administer site configuration'));
+ $this->drupalLogin($admin_user);
+
+ // Enable aggregator, and check tables.
+ $this->assertModules(array('aggregator'), FALSE);
+ $this->assertTableCount('aggregator', FALSE);
+
+ $edit = array();
+ $edit['status[aggregator]'] = 'aggregator';
+ $this->drupalPost('admin/build/modules', $edit, t('Save configuration'));
+ $this->assertText(t('The configuration options have been saved.'), t('Modules status has been updated.'));
+
+ $this->assertModules(array('aggregator'), TRUE);
+ $this->assertTableCount('aggregator', TRUE);
+
+ // Disable aggregator, check tables, uninstall aggregator, check tables.
+ $edit = array();
+ $edit['status[aggregator]'] = FALSE;
+ $this->drupalPost('admin/build/modules', $edit, t('Save configuration'));
+ $this->assertText(t('The configuration options have been saved.'), t('Modules status has been updated.'));
+
+ $this->assertModules(array('aggregator'), FALSE);
+ $this->assertTableCount('aggregator', TRUE);
+
+ $edit = array();
+ $edit['uninstall[aggregator]'] = 'aggregator';
+ $this->drupalPost('admin/build/modules/uninstall', $edit, t('Uninstall'));
+
+ $this->drupalPost(NULL, NULL, t('Uninstall'));
+ $this->assertText(t('The selected modules have been uninstalled.'), t('Modules status has been updated.'));
+
+ $this->assertModules(array('aggregator'), FALSE);
+ $this->assertTableCount('aggregator', FALSE);
+ }
+
+ /**
+ * Attempt to enable translation module without locale enabled.
+ */
+ function testEnableWithoutDependency () {
+ $admin_user = $this->drupalCreateUser(array('access administration pages', 'administer site configuration'));
+ $this->drupalLogin($admin_user);
+
+ // Attempt to enable content translation without locale enabled.
+ $edit = array();
+ $edit['status[translation]'] = 'translation';
+ $this->drupalPost('admin/build/modules', $edit, t('Save configuration'));
+ $this->assertText(t('Some required modules must be enabled'), t('Dependecy required.'));
+
+ $this->assertModules(array('translation', 'locale'), FALSE);
+
+ // Assert that the locale tables weren't enabled.
+ $this->assertTableCount('languages', FALSE);
+ $this->assertTableCount('locale', FALSE);
+
+ $this->drupalPost(NULL, NULL, t('Continue'));
+ $this->assertText(t('The configuration options have been saved.'), t('Modules status has been updated.'));
+
+ $this->assertModules(array('translation', 'locale'), TRUE);
+
+ // Assert that the locale tables were enabled.
+ $this->assertTableCount('languages', TRUE);
+ $this->assertTableCount('locale', TRUE);
+ }
+
+ /**
+ * Assert tables that begin with the specified base table name.
+ *
+ * @param string $base_table Begginning of table name to look for.
+ * @param boolean $count Assert tables that match specified base table.
+ * @return boolean Tables with specified base table.
+ */
+ function assertTableCount($base_table, $count) {
+ $match_count = simpletest_get_like_tables($base_table, TRUE);
+
+ if ($count) {
+ return $this->assertTrue($match_count, t('Tables matching "@base_table" found.', array('@base_table' => $base_table)));
+ }
+ return $this->assertFalse($match_count, t('Tables matching "@base_table" not found.', array('@base_table' => $base_table)));
+ }
+
+ /**
+ * Assert the list of modules are enabled or disabled.
+ *
+ * @param array $modules Modules to check.
+ * @param boolean $enabled Module state.
+ */
+ function assertModules(array $modules, $enabled) {
+ module_list(TRUE, FALSE);
+ foreach ($modules as $module) {
+ if ($enabled) {
+ $this->assertTrue(module_exists($module) == $enabled, t('Module "@module" is enabled.', array('@module' => $module)));
+ }
+ else {
+ $this->assertTrue(module_exists($module) == $enabled, t('Module "@module" not enabled.', array('@module' => $module)));
+ }
+ }
+ }
+}
diff --git a/modules/taxonomy/taxonomy.test b/modules/taxonomy/taxonomy.test
new file mode 100644
index 000000000..65314b5e8
--- /dev/null
+++ b/modules/taxonomy/taxonomy.test
@@ -0,0 +1,394 @@
+<?php
+// $Id$
+
+class TaxonomyVocabularyFunctionsTestCase extends DrupalWebTestCase {
+ /**
+ * Implementation of getInfo().
+ */
+ function getInfo() {
+ return array(
+ 'name' => t('Vocabulary functions'),
+ 'description' => t('Create/Edit/Delete vocabulary and assert that all fields were properly saved.'),
+ 'group' => t('Taxonomy')
+ );
+ }
+
+ /**
+ * Create/Edit/Delete vocabulary and assert that all fields were properly saved.
+ */
+ function testVocabularyFunctions() {
+ //preparing data
+ $vid = 0;
+ $name = $this->randomName(200);
+ $description = $this->randomName(200);
+ $help = $this->randomName(200);
+ $hierarchy = rand(0,2); // Hierarchy 0,1,2
+ $multiple = rand(0,1); // multiple 0,1
+ $required = rand(0,1); // required 0,1
+ $relations = rand(0,1);
+ $tags = rand(0,1);
+ $weight = rand(-9,9);
+ $module = 'taxonomy';
+ $nodesList = array_keys(node_get_types());
+ $maxNodes = rand(1, count($nodesList));
+ $nodes = array();
+ for($i = 0; $i < $maxNodes; $i++) {
+ $nodes[$nodesList[$i]] = $nodesList[$i];
+ $nodesBak[$nodesList[$i]] = $nodesList[$i];
+ }
+ $_t = array('vid', 'name', 'description', 'help', 'relations', 'hierarchy', 'multiple',
+ 'required', 'tags', 'module', 'weight', 'nodes');
+ $edit = array();
+ foreach($_t as $key)
+ $edit[$key] = $$key;
+
+ // Exec save function.
+ taxonomy_save_vocabulary($edit);
+ // After save we use $nodesBak.
+ ksort($nodesBak);
+ $edit['nodes'] = $nodesBak;
+ $vocabularies = taxonomy_get_vocabularies();
+ foreach($vocabularies as $voc) {
+ if ($voc->name == $name) {
+ $vid = $voc->vid;
+ break;
+ }
+ }
+ $edit['vid'] = $vid;
+ // Get data using function.
+ $getEdit = taxonomy_vocabulary_load($vid);
+ foreach($getEdit as $key => $value ) {
+ $this->assertEqual($value, $edit[$key], t('Checking value of @key.', array('@key' => $key)));
+ }
+
+ // Delete vocabulary to avoid exception messages we create array with empty fields.
+ $deleteArray = array();
+ foreach($getEdit as $key => $v) {
+ $deleteArray[$key] = 0;
+ }
+ $deleteArray['vid'] = $vid;
+ taxonomy_save_vocabulary($deleteArray);
+ // Checking if we deleted voc.
+ $vocabularies = taxonomy_get_vocabularies();
+ $vid = 0;
+ foreach($vocabularies as $voc) {
+ if ($voc->name == $name) {
+ $vid = $voc->vid;
+ break;
+ }
+ }
+ $this->assertEqual($vid, 0, t('Deleted vocabulary (@vid)', array('@vid' => $vid)));
+ }
+}
+
+
+class TaxonomyTermFunctionsTestCase extends DrupalWebTestCase {
+ /**
+ * Implementation of getInfo().
+ */
+ function getInfo() {
+ return array(
+ 'name' => t('Term functions'),
+ 'description' => t('Testing save/update/delete terms.'),
+ 'group' => t('Taxonomy')
+ );
+ }
+
+ /**
+ * Test term related functions.
+ */
+ function testTermsFunctions() {
+ // Preparing data: vocabulary, hierarchy -> disabled, related terms = on.
+ $edit = array();
+ $_t = array('vid', 'name', 'description', 'help', 'relations', 'hierarchy', 'multiple',
+ 'required', 'tags', 'module', 'weight', 'nodes');
+ foreach($_t as $key ) {
+ $edit[$key] = 0;
+ }
+ $name = $this->randomName(20);
+ $relation = 1;
+ $edit['name'] = $name;
+ taxonomy_save_vocabulary($edit);
+
+ // Create term.
+ $termname = $this->randomName(20);
+ $termdesc = $this->randomName(200);
+ $termweight = rand(-9, 9);
+ $randSyn = rand(0, 9);
+ $synonyms = array();
+ for($i = 0; $i < $randSyn; $i++) {
+ $synonyms[] = $this->randomName(20);
+ }
+ $termsyn = implode("\n", $synonyms);
+ $data = array('name' => $termname, 'description' => $termdesc, 'weight' => $termweight, 'synonyms' => $termsyn, 'vid' => $edit['vid'], 'tid' => 0, 'relations' => 0);
+ taxonomy_save_term($data);
+
+ // Retrieve term and check all fields.
+ $_tArray = taxonomy_get_term_by_name($termname);
+ $getTerm = $_tArray[0];
+ $checkField = array('name', 'description', 'weight', 'vid');
+ foreach($checkField as $v) {
+ $this->assertEqual($data[$v], $getTerm->$v, t('Checking value of the term (@v).', array('@v' => $v)));
+ }
+ $getSynonyms = taxonomy_get_synonyms($getTerm->tid);
+ $this->assertEqual(sort($synonyms), sort($getSynonyms), 'Checking synonyms');
+
+ // Creating related terms.
+ $relations = array();
+ $staryTid = $getTerm->tid;
+ $relations[] = $staryTid;
+ $termname = $this->randomName(20);
+ $data = array('name' => $termname, 'description' => '', 'weight' => 0, 'synonyms' => 0, 'vid' => $edit['vid'], 'tid' => 0, 'relations' => array($staryTid));
+ taxonomy_save_term($data);
+ $_tArray = taxonomy_get_term_by_name($termname);
+ $getTerm = $_tArray[0];
+ $relations[] = $getTerm->tid;
+
+ // Creating another term related to 2 terms above.
+ $termname = $this->randomName(20);
+ $data = array('name' => $termname, 'description' => '', 'weight' => 0, 'synonyms' => 0, 'vid' => $edit['vid'], 'tid' => 0, 'relations' => array($staryTid, $getTerm->tid));
+ taxonomy_save_term($data);
+ $_tArray = taxonomy_get_term_by_name($termname);
+ $getTerm = $_tArray[0];
+
+ // Check related terms.
+ $related = taxonomy_get_related($getTerm->tid);
+ foreach($relations as $rTid) {
+ $this->assertTrue(array_key_exists($rTid, $related), t('Checking relations (@rTid).', array('@rTid' => $rTid)));
+ }
+
+ // Delete vocabulary.
+ $edit['name'] = 0;
+ taxonomy_save_vocabulary($edit);
+ }
+
+ /**
+ * Test single hierarchy terms.
+ */
+ function testTermsFunctionsSingleHierarchy() {
+ // Preparing data: vocabulary hierarchy->single.
+ $edit = array();
+ $_t = array('vid', 'name', 'description', 'help', 'relations', 'hierarchy', 'multiple',
+ 'required', 'tags', 'module', 'weight', 'nodes');
+ foreach($_t as $key ) {
+ $edit[$key] = 0;
+ }
+
+ // Create vocab.
+ $name = $this->randomName(20);
+ $edit['hierarchy'] = 1;
+ $edit['name'] = $name;
+ taxonomy_save_vocabulary($edit);
+
+ // Create 1st term.
+ $termname = $this->randomName(20);
+ $data = array('name' => $termname, 'description' => '', 'weight' => 0, 'synonyms' => '', 'vid' => $edit['vid'], 'tid' => 0, 'relations' => 0);
+ taxonomy_save_term($data);
+ $_tArray = taxonomy_get_term_by_name($termname);
+ $parent = $_tArray[0];
+
+ // Create 2nd term as a child.
+ $termname = $this->randomName(20);
+ $data = array('name' => $termname, 'description' => '', 'weight' => 0, 'synonyms' => '', 'vid' => $edit['vid'], 'tid' => 0, 'relations' => 0, 'parent' => array($parent->tid));
+ taxonomy_save_term($data);
+ $_tArray = taxonomy_get_term_by_name($termname);
+ $children = $_tArray[0];
+
+ // Check hierarchy.
+ $getChildren = taxonomy_get_children($parent->tid);
+ $getParent = taxonomy_get_parents($children->tid);
+ $this->assertEqual($parent,$getParent[$parent->tid], t('Checking parents.'));
+ $this->assertEqual($children,$getChildren[$children->tid], t('Checking children.'));
+
+ // Delete vocabulary.
+ $edit['name'] = 0;
+ taxonomy_save_vocabulary($edit);
+ }
+
+ /**
+ * Test multiple hierarchy terms.
+ */
+ function testTermsFunctionsMultipleHierarchy() {
+ // Preparing data: vocabulary hierarchy->single.
+ $edit = array();
+ $_t = array('vid', 'name', 'description', 'help', 'relations', 'hierarchy', 'multiple',
+ 'required', 'tags', 'module', 'weight', 'nodes');
+ foreach($_t as $key )
+ $edit[$key] = 0;
+
+ $name = $this->randomName(20);
+ $edit['hierarchy'] = 1;
+ $edit['name'] = $name;
+ taxonomy_save_vocabulary($edit);
+
+ // Create 1st term.
+ $parent = array();
+ $termname = $this->randomName(20);
+ $data = array('name' => $termname, 'description' => '', 'weight' => 0, 'synonyms' => '', 'vid' => $edit['vid'], 'tid' => 0, 'relations' => 0);
+ taxonomy_save_term($data);
+ $_tArray = taxonomy_get_term_by_name($termname);
+ $parent[] = $_tArray[0]->tid;
+
+ // Create 2nd term.
+ $termname = $this->randomName(20);
+ $data = array('name' => $termname, 'description' => '', 'weight' => 0, 'synonyms' => '', 'vid' => $edit['vid'], 'tid' => 0, 'relations' => 0);
+ taxonomy_save_term($data);
+ $_tArray = taxonomy_get_term_by_name($termname);
+ $parent[] = $_tArray[0]->tid;
+
+ // Create 3rd term as a child.
+ $termname = $this->randomName(20);
+ $data = array('name' => $termname, 'description' => '', 'weight' => 0, 'synonyms' => '', 'vid' => $edit['vid'], 'tid' => 0, 'relations' => 0, 'parent' => array($parent));
+ taxonomy_save_term($data);
+ $_tArray = taxonomy_get_term_by_name($termname);
+ $children = $_tArray[0];
+
+ $getParent = taxonomy_get_parents($children->tid);
+ foreach($parent as $p) {
+ $this->assertTrue(array_key_exists($p, $getParent), t('Checking parents (@p)', array('@p' => $p)));
+ //$this->assertEqual($parent,$getParent[$parent->tid], 'Checking parents');
+ }
+
+ // Delete vocabulary.
+ $edit['name'] = 0;
+ taxonomy_save_vocabulary($edit);
+ }
+
+}
+
+class TaxonomyTestNodeApiTestCase extends DrupalWebTestCase {
+ /**
+ * Implementation of getInfo().
+ */
+ function getInfo() {
+ return array(
+ 'name' => t('Taxonomy nodeapi'),
+ 'description' => t('Save & edit a node and assert that taxonomy terms are saved/loaded properly.'),
+ 'group' => t('Taxonomy')
+ );
+ }
+
+ /*
+ * Save & edit a node and assert that taxonomy terms are saved/loaded properly.
+ */
+ function testTaxonomyNode() {
+ // Preparing data: vocabulary hierarchy->single, multiple -> on.
+ $edit = array();
+ $_t = array('vid', 'name', 'description', 'help', 'relations', 'hierarchy', 'multiple',
+ 'required', 'tags', 'module', 'weight', 'nodes');
+ foreach($_t as $key) {
+ $edit[$key] = 0;
+ }
+
+ $name = $this->randomName(20);
+ $edit['hierarchy'] = 1;
+ $edit['multiple'] = 1;
+ $edit['name'] = $name;
+ $edit['nodes'] = array('article' => 'article');
+ taxonomy_save_vocabulary($edit);
+ $vid = $edit['vid']; // We need to persist vid after $edit is unset().
+
+ $parent = array();
+ $patternArray = array();
+
+ // Create 1st term.
+ $termname = $this->randomName(20);
+ $data = array('name' => $termname, 'description' => '', 'weight' => 0, 'synonyms' => '', 'vid' => $vid, 'tid' => 0, 'relations' => 0);
+ taxonomy_save_term($data);
+ $_tArray = taxonomy_get_term_by_name($termname);
+ $parent[$_tArray[0]->tid] = $_tArray[0]->tid;
+ $patternArray['term name 1'] = $termname;
+
+ // Create 2nd term.
+ $termname = $this->randomName(20);
+ $data = array('name' => $termname, 'description' => '', 'weight' => 0, 'synonyms' => '', 'vid' => $vid, 'tid' => 0, 'relations' => 0);
+ taxonomy_save_term($data);
+ $_tArray = taxonomy_get_term_by_name($termname);
+ $parent[$_tArray[0]->tid] = $_tArray[0]->tid;
+ $patternArray['term name 2'] = $termname;
+
+ // Create test user and login.
+ $perm = array('access content', 'create article content', 'edit own article content', 'delete own article content');
+ $account = $this->drupalCreateUser($perm);
+ $this->drupalLogin($account);
+
+ // Why is this printing out the user profile page?
+ // Go to node/add/article.
+ // Try to create article.
+ $title = $this->randomName();
+ $body = $this->randomName(100);
+ $edit = array('title' => $title, 'body' => $body, "taxonomy[$vid][]" => $parent);
+
+ $this->drupalPost('node/add/article', $edit, t('Save'));
+
+ $patternArray['body text'] = $body;
+ $patternArray['title'] = $title;
+
+ $node = node_load(array('title' => $title));
+
+ $this->drupalGet("node/$node->nid");
+ foreach($patternArray as $name => $termPattern) {
+ $this->assertText($termPattern, "Checking $name");
+ }
+
+ // Checking database fields.
+ $result = db_query('SELECT tid FROM {term_node} WHERE nid = %d', $node->nid);
+ while ($nodeRow = db_fetch_array($result)) {
+ $this->assertTrue(in_array($nodeRow['tid'], $parent), 'Checking database record');
+ }
+
+ // Ok, lets create new terms, and change this node.
+ array_pop($parent);
+
+ // create 1st term
+ $termname = $this->randomName(20);
+ $data = array('name' => $termname, 'description' => '', 'weight' => 0, 'synonyms' => '', 'vid' => $vid, 'tid' => 0, 'relations' => 0);
+ taxonomy_save_term($data);
+ $_tArray = taxonomy_get_term_by_name($termname);
+ $parent[] = $_tArray[0]->tid;
+ $patternArray['term name 2'] = $termname;
+
+ // create 2nd term
+ $termname = $this->randomName(20);
+ $data = array('name' => $termname, 'description' => '', 'weight' => 0, 'synonyms' => '', 'vid' => $vid, 'tid' => 0, 'relations' => 0);
+ taxonomy_save_term($data);
+ $_tArray = taxonomy_get_term_by_name($termname);
+ $parent[] = $_tArray[0]->tid;
+ $patternArray['term name 3'] = $termname;
+
+ $edit = array('title' => $title, 'body' => $body, "taxonomy[$vid][]" => $parent);
+
+ $this->drupalPost('node/'. $node->nid .'/edit', $edit, t('Save'));
+
+ // TODO Do a MUCH better check here of the information msg.
+ $patternArray['information message'] = 'been updated';
+ foreach($patternArray as $name => $termPattern) {
+ $this->assertText($termPattern, t('Checking @name.', array('@name' => $name)));
+ }
+
+ // Checking database fields.
+ $node = node_load(array('title' => $title));
+ $result = db_query('SELECT tid FROM {term_node} WHERE vid = %d', $node->vid);
+ while ($nodeRow = db_fetch_array($result)) {
+ $this->assertTrue(in_array($nodeRow['tid'], $parent), t('Checking database field.'));
+ }
+
+ // Delete node through browser.
+ $this->drupalPost('node/'. $node->nid .'/delete', array(), t('Delete'));
+ // Checking after delete.
+ $this->drupalGet("node/".$node->nid);
+ $this->assertNoText($termname, t('Checking if node exists'));
+ // Checking database fields.
+ $num_rows = db_result(db_query('SELECT COUNT(*) FROM {term_node} WHERE nid = %d', $node->nid));
+ $this->assertEqual($num_rows, 0, t('Checking database field after deletion'));
+
+ // Delete vocabulary to avoid exception messages create array with empty fields.
+ $edit = array();
+ foreach($_t as $key ) {
+ $edit[$key] = 0;
+ }
+ $edit['name'] = 0;
+ $edit['vid'] = $vid;
+ taxonomy_save_vocabulary($edit);
+ }
+}
diff --git a/modules/translation/translation.test b/modules/translation/translation.test
new file mode 100644
index 000000000..5152ea77d
--- /dev/null
+++ b/modules/translation/translation.test
@@ -0,0 +1,151 @@
+<?php
+// $Id$
+
+class TranslationTestCase extends DrupalWebTestCase {
+ protected $book;
+
+ /**
+ * Implementation of getInfo().
+ */
+ function getInfo() {
+ return array(
+ 'name' => t('Translation functionality'),
+ 'description' => t('Create a page with translation, modify the page outdating translation, and update translation.'),
+ 'group' => t('Translation')
+ );
+ }
+
+ /**
+ * Implementation of setUp().
+ */
+ function setUp() {
+ parent::setUp('locale', 'translation');
+ }
+
+ /**
+ * Create a page with translation, modify the page outdating translation, and update translation.
+ */
+ function testContentTranslation() {
+ // Setup users.
+ $admin_user = $this->drupalCreateUser(array('administer languages', 'administer content types', 'access administration pages'));
+ $translator = $this->drupalCreateUser(array('create page content', 'edit own page content', 'translate content'));
+
+ $this->drupalLogin($admin_user);
+
+ // Add languages.
+ $this->addLanguage('en');
+ $this->addLanguage('es');
+
+ // Set page content type to use multilingual support with translation.
+ $this->drupalGet('admin/content/node-type/page');
+ $this->drupalPost('admin/content/node-type/page', array('language_content_type' => '2'), t('Save content type'));
+ $this->assertRaw(t('The content type %type has been updated.', array('%type' => 'Page')), t('Page content type has been updated.'));
+
+ $this->drupalLogout();
+ $this->drupalLogin($translator);
+
+ // Create page in English.
+ $node_title = 'Test Translation '. $this->randomName();
+ $node = $this->createPage($node_title, 'Node body.', 'en');
+
+ // Submit translation in Spanish.
+ $node_trans_title = 'Test Traduccion '. $this->randomName();
+ $node_trans = $this->createTranslation($node->nid, $node_trans_title, 'Nodo cuerpo.', 'es');
+
+ // Update origninal and mark translation as outdated.
+ $edit = array();
+ $edit['body'] = 'Node body. Additional Text.';
+ $edit['translation[retranslate]'] = TRUE;
+ $this->drupalPost('node/'. $node->nid .'/edit', $edit, t('Save'));
+ $this->assertRaw(t('Page %title has been updated.', array('%title' => $node_title)), t('Original node updated.'));
+
+ // Check to make sure that interface shows translation as outdated
+ $this->drupalGet('node/'. $node->nid .'/translate');
+ $this->assertRaw('<span class="marker">'. t('outdated') .'</span>', t('Translation marked as outdated.'));
+
+ // Update translation and mark as updated.
+ $edit = array();
+ $edit['body'] = 'Nodo cuerpo. Texto adicional.';
+ $edit['translation[status]'] = FALSE;
+ $this->drupalPost('node/'. $node_trans->nid .'/edit', $edit, t('Save'));
+ $this->assertRaw(t('Page %title has been updated.', array('%title' => $node_trans_title)), t('Translated node updated.'));
+ }
+
+ /**
+ * Install a the specified language if it has not been already. Otherwise make sure that
+ * the language is enabled.
+ *
+ * @param string $language_code The langauge code the check.
+ */
+ function addLanguage($language_code) {
+ // Check to make sure that language has not already been installed.
+ $this->drupalGet('admin/settings/language');
+
+ if (strpos($this->drupalGetContent(), 'enabled['. $language_code .']') === FALSE) {
+ // Doesn't have language installed so add it.
+ $edit = array();
+ $edit['langcode'] = $language_code;
+ $this->drupalPost('admin/settings/language/add', $edit, t('Add language'));
+
+ $languages = language_list('language', TRUE); // make sure not using cached version
+ $this->assertTrue(array_key_exists($language_code, $languages), t('Language was installed successfully.'));
+
+ if (array_key_exists($language_code, $languages)) {
+ $this->assertRaw(t('The language %language has been created and can now be used. More information is available on the <a href="@locale-help">help screen</a>.', array('%language' => $languages[$language_code]->name, '@locale-help' => url('admin/help/locale'))), t('Language has been created.'));
+ }
+ }
+ else {
+ // Ensure that it is enabled.
+ $this->assertTrue(true, 'Language ['. $language_code .'] already installed.');
+ $this->drupalPost(NULL, array('enabled['. $language_code .']' => TRUE), t('Save configuration'));
+
+ $this->assertRaw(t('Configuration saved.'), t('Language successfully enabled.'));
+ }
+ }
+
+ /**
+ * Create a page in the specified language.
+ *
+ * @param string $title Title of page in specified language.
+ * @param string $body Body of page in specified language.
+ * @param string $language Langauge code.
+ */
+ function createPage($title, $body, $language) {
+ $edit = array();
+ $edit['title'] = $title;
+ $edit['body'] = $body;
+ $edit['language'] = $language;
+ $this->drupalPost('node/add/page', $edit, t('Save'));
+ $this->assertRaw(t('Page %title has been created.', array('%title' => $edit['title'])), t('Page created.'));
+
+ // Check to make sure the node was created.
+ $node = node_load(array('title' => $edit['title']));
+ $this->assertTrue($node, t('Node found in database.'));
+
+ return $node;
+ }
+
+ /**
+ * Create a translation for the specified page in the specified language.
+ *
+ * @param integer $nid Node id of page to create translation for.
+ * @param string $title Title of page in specified language.
+ * @param string $body Body of page in specified language.
+ * @param string $language Langauge code.
+ */
+ function createTranslation($nid, $title, $body, $language) {
+ $this->drupalGet('node/add/page', array('query' => array('translation' => $nid, 'language' => $language)));
+
+ $edit = array();
+ $edit['title'] = $title;
+ $edit['body'] = $body;
+ $this->drupalPost(NULL, $edit, t('Save'));
+ $this->assertRaw(t('Page %title has been created.', array('%title' => $edit['title'])), t('Translation created.'));
+
+ // Check to make sure that translation was successfull.
+ $node = node_load(array('title' => $edit['title']));
+ $this->assertTrue($node, t('Node found in database.'));
+
+ return $node;
+ }
+}
diff --git a/modules/trigger/trigger.test b/modules/trigger/trigger.test
new file mode 100644
index 000000000..1a6b687bc
--- /dev/null
+++ b/modules/trigger/trigger.test
@@ -0,0 +1,114 @@
+<?php
+// $Id$
+
+class TriggerContentTestCase extends DrupalWebTestCase {
+ var $_cleanup_roles = array();
+ var $_cleanup_users = array();
+
+ /**
+ * Implementation of getInfo() for information
+ */
+ function getInfo() {
+ return array(
+ 'name' => t('Trigger content (node) actions'),
+ 'description' => t('Perform various tests with content actions.') ,
+ 'group' => t('Trigger'),
+ );
+ }
+
+ function setUp() {
+ parent::setUp('trigger');
+ }
+
+ /**
+ * Various tests, all in one function to assure they happen in the right order.
+ */
+ function testActionsContent() {
+ global $user;
+ $content_actions = array('node_publish_action', 'node_unpublish_action', 'node_make_sticky_action', 'node_make_unsticky_action', 'node_promote_action', 'node_unpromote_action');
+
+ foreach ($content_actions as $action) {
+ $hash = md5($action);
+ $info = $this->actionInfo($action);
+
+ // Test 1: Assign an action to a trigger, then pull the trigger, and make sure the actions fire.
+ $test_user = $this->drupalCreateUser(array('administer actions'));
+ $this->drupalLogin($test_user);
+ $edit = array('aid' => $hash);
+ $this->drupalPost('admin/build/trigger/node', $edit, t('Assign'));
+ // Create an unpublished node.
+ $web_user = $this->drupalCreateUser(array('create page content', 'access content', 'administer nodes'));
+ $this->drupalLogin($web_user);
+ $edit = array();
+ $edit['title'] = '!SimpleTest test node! ' . $this->randomName(10);
+ $edit['body'] = '!SimpleTest test body! ' . $this->randomName(32) . ' ' . $this->randomName(32);
+ $edit[$info['property']] = !$info['expected'];
+ $this->drupalPost('node/add/page', $edit, t('Save'));
+ // Make sure the text we want appears.
+ $this->assertRaw(t('!post %title has been created.', array ('!post' => 'Page', '%title' => $edit['title'])), t('Make sure the page has actually been created'));
+ // Action should have been fired.
+ $loaded_node = node_load(array('title' => $edit['title']), NULL, TRUE);
+ $this->assertTrue($loaded_node->$info['property'] == $info['expected'], t('Make sure the @action action fired.', array('@action' => $info['name'])));
+ // Leave action assigned for next test
+
+ // Test 2: There should be an error when the action is assigned to the trigger twice.
+ $test_user = $this->drupalCreateUser(array('administer actions'));
+ $this->drupalLogin($test_user);
+ $edit = array('aid' => $hash);
+ $this->drupalPost('admin/build/trigger/node', $edit, t('Assign'));
+ $edit = array('aid' => $hash);
+ $this->drupalPost('admin/build/trigger/node', $edit, t('Assign'));
+ $this->assertRaw(t('The action you chose is already assigned to that trigger.'), t('Check to make sure an error occurs when assigning an action to a trigger twice.'));
+
+ // Test 3: The action should be able to be unassigned from a trigger.
+ $this->drupalPost('admin/build/trigger/unassign/nodeapi/presave/'. $hash, array(), t('Unassign'));
+ $this->assertRaw(t('Action %action has been unassigned.', array('%action' => 'Publish post')), t('Check to make sure the @action action can be unassigned from the trigger.', array('@action' => $info['name'])));
+ $assigned = db_result(db_query("SELECT COUNT(*) FROM {trigger_assignments} WHERE aid IN ('". implode("','", $content_actions) ."')"));
+ $this->assertFalse($assigned, t('Check to make sure unassign worked properly at the database level.'));
+ }
+ }
+
+ /**
+ * Helper function for testActionsContent(): returns some info about each of the content actions.
+ *
+ * @param $action
+ * The name of the action to return info about.
+ * @return
+ * An associative array of info about the action.
+ */
+ function actionInfo($action) {
+ $info = array(
+ 'node_publish_action' => array(
+ 'property' => 'status',
+ 'expected' => 1,
+ 'name' => t('publish post'),
+ ),
+ 'node_unpublish_action' => array(
+ 'property' => 'status',
+ 'expected' => 0,
+ 'name' => t('unpublish post'),
+ ),
+ 'node_make_sticky_action' => array(
+ 'property' => 'sticky',
+ 'expected' => 1,
+ 'name' => t('make post sticky'),
+ ),
+ 'node_make_unsticky_action' => array(
+ 'property' => 'sticky',
+ 'expected' => 0,
+ 'name' => t('make post unsticky'),
+ ),
+ 'node_promote_action' => array(
+ 'property' => 'promote',
+ 'expected' => 1,
+ 'name' => t('promote post to front page'),
+ ),
+ 'node_unpromote_action' => array(
+ 'property' => 'promote',
+ 'expected' => 0,
+ 'name' => t('remove post from front page'),
+ ),
+ );
+ return $info[$action];
+ }
+} \ No newline at end of file
diff --git a/modules/upload/upload.test b/modules/upload/upload.test
new file mode 100644
index 000000000..cc8c18c9b
--- /dev/null
+++ b/modules/upload/upload.test
@@ -0,0 +1,550 @@
+<?php
+// $Id$
+
+class UploadTestCase extends DrupalWebTestCase {
+ /**
+ * Implementation of getInfo().
+ */
+ function getInfo() {
+ return array(
+ 'name' => t('Upload functionality'),
+ 'description' => t('Check content uploaded to nodes.'),
+ 'group' => t('Upload'),
+ );
+ }
+
+ function setUp() {
+ parent::setUp('upload');
+ }
+
+ /**
+ * Create node; upload files to node; and edit, and delete uploads.
+ */
+ function testNodeUpload() {
+ $admin_user = $this->drupalCreateUser(array('administer site configuration'));
+ $web_user = $this->drupalCreateUser(array('access content', 'edit any page content', 'upload files', 'view uploaded files'));
+
+ $this->drupalLogin($admin_user);
+
+ // Setup upload settings.
+ $edit = array();
+ $edit['upload_list_default'] = '1'; // Yes.
+ $edit['upload_extensions_default'] = 'jpg jpeg gif png txt doc xls pdf ppt pps odt ods odp';
+ $edit['upload_uploadsize_default'] = '1.5';
+ $edit['upload_usersize_default'] = '1.5';
+ $this->drupalPost('admin/settings/uploads', $edit, t('Save configuration'));
+ $this->assertText('The configuration options have been saved.', 'Upload setting saved.');
+
+ $this->drupalLogout();
+ $this->drupalLogin($web_user);
+
+ // Create a node and attempt to attach files.
+ $node = $this->drupalCreateNode();
+ $text_files = $this->drupalGetTestFiles('text');
+ $files = array(current($text_files)->filename, next($text_files)->filename);
+
+ $this->uploadFile($node, $files[0]);
+ $this->uploadFile($node, $files[1]);
+
+ // Check to see that uploaded file is listed and actually accessible.
+ $this->assertText(basename($files[0]), basename($files[0]) .' found on node.');
+ $this->assertText(basename($files[1]), basename($files[1]) .' found on node.');
+
+ $this->checkUploadedFile(basename($files[0]));
+ $this->checkUploadedFile(basename($files[1]));
+
+ // Fetch db record and use fid to rename and delete file.
+ $upload = db_fetch_object(db_query('SELECT fid, description FROM {upload} WHERE nid = %d', array($node->nid)));
+ if ($upload) {
+ // Rename file.
+ $edit = array();
+ $edit['files['. $upload->fid .'][description]'] = $new_name = substr($upload->description, 1);
+ $this->drupalPost('node/'. $node->nid .'/edit', $edit, t('Save'));
+ $this->assertRaw(t('Page %title has been updated.', array('%title' => $node->title)), 'File renamed successfully.');
+
+ $this->assertText($new_name, $new_name .' found on node.');
+ $this->assertNoText($upload->description, $upload->description .' not found on node.');
+
+ // Delete a file.
+ $edit = array();
+ $edit['files['. $upload->fid .'][remove]'] = TRUE;
+ $this->drupalPost('node/'. $node->nid .'/edit', $edit, t('Save'));
+ $this->assertRaw(t('Page %title has been updated.', array('%title' => $node->title)), 'File deleted successfully.');
+
+ $this->assertNoText($new_name, $new_name .' not found on node.');
+ $this->drupalGet(file_directory_path() .'/'. $upload->description);
+ $this->assertResponse(array(404), 'Uploaded '. $upload->description .' is not accessible.');
+ }
+ else {
+ $this->fail('File upload record not found in database.');
+ }
+ }
+
+ /**
+ * Ensure the the file filter works correctly by attempting to upload a non-allowed file extension.
+ */
+ function testFilesFilter() {
+ $admin_user = $this->drupalCreateUser(array('administer site configuration'));
+ $web_user = $this->drupalCreateUser(array('access content', 'edit any page content', 'upload files', 'view uploaded files'));
+
+ $this->drupalLogin($admin_user);
+
+ // Setup upload settings.
+ $settings = array();
+ $settings['upload_list'] = '1'; // Yes.
+ $settings['upload_extensions'] = 'html';
+ $settings['upload_uploadsize'] = '1';
+ $settings['upload_usersize'] = '1';
+ $this->setUploadSettings($settings, $this->getSimpletestRoleId($web_user));
+
+ $this->drupalLogin($web_user);
+
+ $node = $this->drupalCreateNode();
+ $text_files = $this->drupalGetTestFiles('text');
+ $html_files = $this->drupalGetTestFiles('html');
+ $files = array(current($text_files)->filename, current($html_files)->filename);
+
+ // Attempt to upload .txt file when .test is only extension allowed.
+ $this->uploadFile($node, $files[0], FALSE);
+ $this->assertRaw(t('The selected file %name could not be uploaded. Only files with the following extensions are allowed: %files-allowed.', array('%name' => basename($files[0]), '%files-allowed' => $settings['upload_extensions'])), 'File '. $files[0] .' was not allowed to be uploaded');
+
+ // Attempt to upload .test file when .test is only extension allowed.
+ $this->uploadFile($node, $files[1]);
+ }
+
+ /**
+ * Attempt to upload a file that is larger than the maxsize and see that it fails.
+ */
+ function testLimit() {
+ $files = $this->drupalGetTestFiles('text', 1310720); // 1 MB.
+ $file = current($files)->filename;
+
+ $admin_user = $this->drupalCreateUser(array('administer site configuration'));
+ $web_user = $this->drupalCreateUser(array('access content', 'edit any page content', 'upload files', 'view uploaded files'));
+
+ $this->drupalLogin($admin_user);
+
+ // Setup upload settings.
+ $settings = array();
+ $settings['upload_list'] = '1'; // Yes.
+ $settings['upload_extensions'] = 'jpg jpeg gif png txt doc xls pdf ppt pps odt ods odp';
+ $settings['upload_uploadsize'] = '0.5';
+ $settings['upload_usersize'] = '1.5';
+ $this->setUploadSettings($settings, $this->getSimpletestRoleId($web_user));
+
+ $this->drupalLogin($web_user);
+
+ $node = $this->drupalCreateNode();
+
+ // Attempt to upload file which is bigger than the maximum size of 0.5 MB.
+ $this->uploadFile($node, $file, FALSE);
+
+ $info = stat($file);
+ $filename = basename($file);
+ $filesize = format_size($info['size']);
+ $maxsize = format_size(parse_size(($settings['upload_uploadsize'] * 1024) .'KB')); // Won't parse decimals.
+ $this->assertRaw(t('The selected file %name could not be uploaded. The file is %filesize exceeding the maximum file size of %maxsize.', array('%name' => $filename, '%filesize' => $filesize, '%maxsize' => $maxsize)), t('File upload was blocked since it was larger than maxsize.'));
+ }
+
+ function setUploadSettings($settings, $rid = NULL) {
+ $edit = array();
+ foreach ($settings as $key => $value) {
+ $edit[$key .'_default'] = $value;
+ if ($rid !== NULL && $key != 'upload_list' && $key != 'upload_max_resolution') {
+ $edit[$key .'_'. $rid] = $value;
+ }
+ }
+ $this->drupalPost('admin/settings/uploads', $edit, 'Save configuration');
+ $this->assertText('The configuration options have been saved.', 'Upload setting saved.');
+ }
+
+ /**
+ * Upload file to specified node.
+ *
+ * @param object $node Node object.
+ * @param string $filename Name of file to upload.
+ * @param boolean $assert Assert that the node was successfully updated.
+ */
+ function uploadFile($node, $filename, $assert = TRUE) {
+ $edit = array();
+ $edit['files[upload]'] = $filename; //edit-upload
+ $this->drupalPost('node/'. $node->nid .'/edit', $edit, t('Save'));
+ if ($assert) {
+ $this->assertRaw(t('Page %title has been updated.', array('%title' => $node->title)), 'File attached successfully.');
+ }
+ }
+
+ /**
+ * Check that uploaded file is accessible and verify the contents against the original.
+ *
+ * @param string $filename Name of file to verifiy.
+ */
+ function checkUploadedFile($filename) {
+ $file = realpath(file_directory_path() .'/'. $filename);
+ $this->drupalGet(file_directory_path() .'/'. $filename);
+ $this->assertResponse(array(200), 'Uploaded '. $filename .' is accessible.');
+ $this->assertEqual(file_get_contents($file), $this->drupalGetContent(), 'Uploaded contents of '. $filename .' verified.');
+ }
+
+ /**
+ * Get the role id of the 'simpletest' role associated with a SimpleTest test user.
+ *
+ * @param object $user User object.
+ * @return interger SimpleTest role id.
+ */
+ function getSimpletestRoleId($user) {
+ foreach ($user->roles as $rid => $role) {
+ if (strpos($role, 'simpletest') !== FALSE) {
+ return $rid;
+ }
+ }
+ return NULL;
+ }
+}
+
+class UploadPictureTestCase extends DrupalWebTestCase {
+ function getInfo() {
+ return array(
+ 'name' => t('Upload user picture'),
+ 'description' => t('Assure that dimension check, extension check and image scaling work as designed.'),
+ 'group' => t('Upload')
+ );
+ }
+
+ /*
+ * Test if directories specified in settings exist in filesystem
+ */
+ function testDirectories() {
+ // test if filepath is proper
+ $file_dir = file_directory_path();
+ $picture_dir = variable_get('user_picture_path', 'pictures');
+ $file_check = file_check_directory($file_dir, FILE_CREATE_DIRECTORY, 'file_directory_path');
+ $picture_path = $file_dir .'/'.$picture_dir;
+
+ $pic_check = file_check_directory($picture_path, FILE_CREATE_DIRECTORY, 'user_picture_path');
+ // check directories
+ //$this->assertTrue($file_check,"The directory $file_dir doesn't exist or cannot be created.");
+ //$this->assertTrue($pic_check,"The directory $picture_path doesn't exist or cannot be created.");
+ $this->_directory_test = is_writable($picture_path);
+ $this->assertTrue($this->_directory_test, "The directory $picture_path doesn't exist or is not writable. Further tests won't be made.");
+ }
+
+ function testNoPicture() {
+ $old_pic_set = variable_get('user_pictures', 0);
+ variable_set('user_pictures', 1);
+
+ /* Prepare a user to do the stuff */
+ $user = $this->drupalCreateUser(array('access content'));
+ $this->drupalLogin($user);
+
+ // not a image
+ //$img_path = realpath(drupal_get_path('module', 'simpletest'). "/tests/functional/upload.test");
+ $img_path = realpath(drupal_get_path('module', 'simpletest'). "/files/html-1.txt");
+ $edit = array('files[picture_upload]' => $img_path);
+ $this->drupalPost('user/'.$user->uid.'/edit', $edit, t('Save'));
+ $this->assertRaw(t('The selected file %file could not be uploaded. Only JPEG, PNG and GIF images are allowed.', array('%file' => basename($img_path))), 'The uploaded file was not an image.');
+ variable_set('user_pictures', $old_pic_set);
+
+ // do we have to check users roles?
+ // delete test user and roles
+
+ }
+
+ /*
+ * Do one test if ImageGDToolkit is installed
+ */
+
+ /*
+ * Do the test:
+ * GD Toolkit is installed
+ * Picture has invalid dimension
+ *
+ * results: The image should be uploaded because ImageGDToolkit resizes the picture
+ */
+
+ function testWithGDinvalidDimension() {
+ if ($this->_directory_test)
+ if (image_get_toolkit()) {
+
+ // PREPARE:
+ $old_pic_set = variable_get('user_pictures', 0);
+ variable_set('user_pictures', 1);
+
+ /* Prepare a user to do the stuff */
+ $user = $this->drupalCreateUser(array('access content'));
+ $this->drupalLogin($user);
+
+ // changing actual setting;
+ $old_dim = variable_get('user_picture_dimensions', '85x85');
+ $old_size = variable_get('user_picture_file_size', '30');
+ //$img_path = realpath(drupal_get_path('module', 'simpletest'). "/tests/files/image-2.jpg");
+ $img_path = realpath(drupal_get_path('module', 'simpletest'). "/files/image-2.jpg");
+ $info = image_get_info($img_path);
+
+ // set new variables;
+ $test_size = floor(filesize($img_path) / 1000) + 1;
+ $test_dim = ($info['width'] - 10) . 'x' . ($info['height'] - 10);
+ variable_set('user_picture_dimensions', $test_dim);
+ variable_set('user_picture_file_size', $test_size);
+
+ // Create pictures folder
+ $file_dir = file_directory_path();
+ $picture_dir = variable_get('user_picture_path', 'pictures');
+ $picture_path = $file_dir .'/'.$picture_dir;
+ $pic_check = file_check_directory($picture_path, FILE_CREATE_DIRECTORY, 'user_picture_path');
+
+ // TEST:
+ $edit = array('files[picture_upload]' => $img_path);
+ $this->drupalPost('user/'.$user->uid.'/edit', $edit, t('Save'));
+ $picture_dir = variable_get('user_picture_path', 'pictures');
+ $picture = $picture_dir .'/picture-'.$user->uid.'.jpg';
+
+ // get full url to the user's image
+ $picture_url = file_create_url($picture);
+ $picture_path = file_create_path($picture);
+
+ // check if image is displayed in user's profile page
+ $this->assertRaw($picture_url, "Image is displayed in user's profile page");
+
+ // check if file is located in proper directory
+ $this->assertTrue(is_file($picture_path), "File is located in proper directory");
+
+ // RESTORING:
+ variable_set('user_picture_file_size', $old_size);
+ variable_set('user_picture_dimensions', $old_dim);
+
+ variable_set('user_pictures', $old_pic_set);
+ }
+
+ }
+
+ /*
+ * Do the test:
+ * GD Toolkit is installed
+ * Picture has invalid size
+ *
+ * results: The image should be uploaded because ImageGDToolkit resizes the picture
+ */
+
+ function tstWithGDinvalidSize() {
+ if ($this->_directory_test)
+ if (image_get_toolkit()) {
+ // PREPARE:
+ $old_pic_set = variable_get('user_pictures', 0);
+ variable_set('user_pictures', 1);
+
+ /* Prepare a user to do the stuff */
+ $user = $this->drupalCreateUser(array('access content'));
+ $this->drupalLogin($user);
+
+ // changing actual setting;
+ $old_dim = variable_get('user_picture_dimensions', '85x85');
+ $old_size = variable_get('user_picture_file_size', '30');
+ $files = $this->drupalGetTestFiles('image');
+ $file = current($files);
+ $img_path = realpath($file->filename);
+ $info = image_get_info($img_path);
+ // set new variables;
+
+ $test_dim = ($info['width'] + 10) . 'x' . ($info['height'] + 10);
+ $test_size = filesize($img_path);
+ variable_set('user_picture_dimensions', $test_dim);
+ variable_set('user_picture_file_size', $test_size);
+
+ // Create pictures folder
+ $file_dir = file_directory_path();
+ $picture_dir = variable_get('user_picture_path', 'pictures');
+ $picture_path = $file_dir .'/'.$picture_dir;
+ $pic_check = file_check_directory($picture_path, FILE_CREATE_DIRECTORY, 'user_picture_path');
+
+ // TEST:
+ $edit = array('files[picture_upload]' => $img_path);
+ $this->drupalPost('user/'.$user->uid.'/edit', $edit, t('Save'));
+ $picture_dir = variable_get('user_picture_path', 'pictures');
+ $picture = $picture_dir .'/picture-'.$user->uid.'.png';
+
+ // get full url to the user's image
+ $picture_url = file_create_url($picture);
+ $picture_path = file_create_path($picture);
+
+ // check if image is displayed in user's profile page
+ $this->assertRaw($picture_url, "Image is displayed in user's profile page");
+
+ // check if file is located in proper directory
+ $this->assertTrue(is_file($picture_path), "File is located in proper directory");
+
+ // RESTORING:
+ variable_set('user_picture_file_size', $old_size);
+ variable_set('user_picture_dimensions', $old_dim);
+
+ variable_set('user_pictures', $old_pic_set);
+ }
+ }
+
+ /*
+ * Do the test:
+ * GD Toolkit is not installed
+ * Picture has invalid size
+ *
+ * results: The image shouldn't be uploaded
+ */
+ function tstWithoutGDinvalidDimension() {
+ if ($this->_directory_test)
+ if (!image_get_toolkit()) {
+ // PREPARE:
+ $old_pic_set = variable_get('user_pictures', 0);
+ variable_set('user_pictures', 1);
+
+ /* Prepare a user to do the stuff */
+ $user = $this->drupalCreateUser(array('access content'));
+ $this->drupalLogin($user);
+
+ // changing actual setting;
+ $old_dim = variable_get('user_picture_dimensions', '85x85');
+ $old_size = variable_get('user_picture_file_size', '30');
+ $img_path = realpath(drupal_get_path('module', 'simpletest'). "/files/image-2.jpg");
+ $info = image_get_info($img_path);
+ // set new variables;
+ $test_size = floor(filesize($img_path) / 1000) + 1;
+ $test_dim = ($info['width'] - 10) . 'x' . ($info['height'] - 10);
+ variable_set('user_picture_dimensions', $test_dim);
+ variable_set('user_picture_file_size', $test_size);
+
+ // Create pictures folder
+ $file_dir = file_directory_path();
+ $picture_dir = variable_get('user_picture_path', 'pictures');
+ $picture_path = $file_dir .'/'.$picture_dir;
+ $pic_check = file_check_directory($picture_path, FILE_CREATE_DIRECTORY, 'user_picture_path');
+
+ // TEST:
+ $edit = array('picture' => $img_path);
+ $this->drupalPost('user/'.$user->uid.'/edit', $edit, t('Save'));
+ $text = t('The uploaded image is too large; the maximum dimensions are %dimensions pixels.', array('%dimensions' => variable_get('user_picture_dimensions', '85x85')));
+ $this->assertText($text, 'Checking response on invalid image (dimensions).');
+
+ // check if file is not uploaded
+ $file_dir = variable_get('file_directory_path', 'files');
+ $picture_dir = variable_get('user_picture_path', 'pictures');
+ $pic_path = $file_dir .'/'.$picture_dir .'/picture-'.$user->uid.'.jpg';
+ $this->assertFalse(is_file($pic_path), "File is not uploaded");
+
+ // restore variables;
+ variable_set('user_picture_file_size', $old_size);
+ variable_set('user_picture_dimensions', $old_dim);
+
+ variable_set('user_pictures', $old_pic_set);
+ }
+ }
+
+ /*
+ * Do the test:
+ * GD Toolkit is not installed
+ * Picture has invalid size
+ *
+ * results: The image shouldn't be uploaded
+ */
+ function tstWithoutGDinvalidSize() {
+ if ($this->_directory_test)
+ if (!image_get_toolkit()) {
+ // PREPARE:
+ $old_pic_set = variable_get('user_pictures', 0);
+ variable_set('user_pictures', 1);
+
+ /* Prepare a user to do the stuff */
+ $user = $this->drupalCreateUser(array('access content'));
+ $this->drupalLogin($user);
+
+ // changing actual setting;
+ $old_dim = variable_get('user_picture_dimensions', '85x85');
+ $old_size = variable_get('user_picture_file_size', '30');
+ //$img_path = realpath("modules/tests/image-2.jpg");
+ $img_path = realpath(drupal_get_path('module', 'simpletest'). "/files/image-2.jpg");
+ $info = image_get_info($img_path);
+ // invalid size
+ // restore one and set another
+ $test_dim = ($info['width'] + 10) . 'x' . ($info['height'] + 10);
+ $test_size = floor(filesize($img_path) / 1000) - 1;
+ variable_set('user_picture_dimensions', $test_dim);
+ variable_set('user_picture_file_size', $test_size);
+
+ $edit = array('picture' => $img_path);
+ $this->drupalPost('user/'.$user->uid.'/edit', $edit, t('Save'));
+ $text = t('The uploaded image is too large; the maximum file size is %size kB.', array('%size' => variable_get('user_picture_file_size', '30')));
+ $this->assertText($text, 'Checking response on invalid image size.');
+
+ // check if file is not uploaded
+ $file_dir = variable_get('file_directory_path', 'files');
+ $picture_dir = variable_get('user_picture_path', 'pictures');
+ $pic_path = $file_dir .'/'.$picture_dir .'/picture-'.$user->uid.'.jpg';
+ $this->assertFalse(is_file($pic_path), "File is not uploaded");
+ // restore variables;
+ variable_set('user_picture_file_size', $old_size);
+ variable_set('user_picture_dimensions', $old_dim);
+
+ variable_set('user_pictures', $old_pic_set);
+ }
+ }
+
+ /*
+ * Do the test:
+ * Picture is valid (proper size and dimension)
+ *
+ * results: The image should be uploaded
+ */
+ function tstPictureIsValid() {
+ if ($this->_directory_test) {
+ // PREPARE:
+ $old_pic_set = variable_get('user_pictures', 0);
+ variable_set('user_pictures', 1);
+
+ /* Prepare a user to do the stuff */
+ $user = $this->drupalCreateUser(array('access content'));
+ $this->drupalLogin($user);
+
+ // changing actual setting;
+ $old_dim = variable_get('user_picture_dimensions', '85x85');
+ $old_size = variable_get('user_picture_file_size', '30');
+ $img_path = realpath(drupal_get_path('module', 'simpletest'). "/files/image-2.jpg");
+ $info = image_get_info($img_path);
+
+ // valid size & dimensions
+ // restore one and set another
+ $test_dim = ($info['width'] + 10) . 'x' . ($info['height'] + 10);
+ $test_size = floor(filesize($img_path) / 1000) + 1;
+ variable_set('user_picture_dimensions', $test_dim);
+ variable_set('user_picture_file_size', $test_size);
+
+ // Create pictures folder
+ $file_dir = file_directory_path();
+ $picture_dir = variable_get('user_picture_path', 'pictures');
+ $picture_path = $file_dir .'/'.$picture_dir;
+ $pic_check = file_check_directory($picture_path, FILE_CREATE_DIRECTORY, 'user_picture_path');
+
+ // TEST:
+ $edit = array('files[picture_upload]' => $img_path);
+ $this->drupalPost('user/'.$user->uid.'/edit', $edit, t('Save'));
+ $picture_dir = variable_get('user_picture_path', 'pictures');
+ $pic_path = file_directory_path() .'/'.$picture_dir .'/picture-'.$user->uid.'.jpg';
+
+ // get full url to the user's image
+ $picture = file_create_url($pic_path);
+
+ // check if image is displayed in user's profile page
+ $content = $this->drupalGetContent();
+
+ $this->assertTrue(strpos($content, $picture), "Image is displayed in user's profile page");
+
+ // check if file is located in proper directory
+ $this->assertTrue(is_file($pic_path), "File is located in proper directory");
+
+ // RESTORING:
+ variable_set('user_picture_file_size', $old_size);
+ variable_set('user_picture_dimensions', $old_dim);
+
+ variable_set('user_pictures', $old_pic_set);
+
+ // DELETING UPLOADED PIC
+ file_delete($pic_path);
+ }
+ }
+}
diff --git a/modules/user/upload.test b/modules/user/upload.test
new file mode 100644
index 000000000..6cb54ffad
--- /dev/null
+++ b/modules/user/upload.test
@@ -0,0 +1,522 @@
+<?php
+// $Id$
+
+class UploadTestCase extends DrupalWebTestCase {
+ /**
+ * Implementation of getInfo().
+ */
+ function getInfo() {
+ return array(
+ 'name' => t('Upload functionality'),
+ 'description' => t('Check content uploaded to nodes.'),
+ 'group' => t('Upload'),
+ );
+ }
+
+ function setUp() {
+ parent::setUp('upload');
+ }
+
+ /**
+ * Create node; upload files to node; and edit, and delete uploads.
+ */
+ function testNodeUpload() {
+ $admin_user = $this->drupalCreateUser(array('administer site configuration'));
+ $web_user = $this->drupalCreateUser(array('access content', 'edit any page content', 'upload files', 'view uploaded files'));
+
+ $this->drupalLogin($admin_user);
+
+ // Setup upload settings.
+ $edit = array();
+ $edit['upload_list_default'] = '1'; // Yes.
+ $edit['upload_extensions_default'] = 'jpg jpeg gif png txt doc xls pdf ppt pps odt ods odp';
+ $edit['upload_uploadsize_default'] = '1';
+ $edit['upload_usersize_default'] = '1';
+ $this->drupalPost('admin/settings/uploads', $edit, t('Save configuration'));
+ $this->assertText('The configuration options have been saved.', 'Upload setting saved.');
+
+ $this->drupalLogout();
+ $this->drupalLogin($web_user);
+
+ // Create a node and attempt to attach files.
+ $node = $this->drupalCreateNode();
+ $text_files = $this->drupalGetTestFiles('text');
+ $files = array(current($text_files)->filename, next($text_files)->filename);
+
+ $this->uploadFile($node, $files[0]);
+ $this->uploadFile($node, $files[1]);
+
+ // Check to see that uploaded file is listed and actually accessible.
+ $this->assertText(basename($files[0]), basename($files[0]) .' found on node.');
+ $this->assertText(basename($files[1]), basename($files[1]) .' found on node.');
+
+ $this->checkUploadedFile(basename($files[0]));
+ $this->checkUploadedFile(basename($files[1]));
+
+ // Fetch db record and use fid to rename and delete file.
+ $upload = db_fetch_object(db_query('SELECT fid, description FROM {upload} WHERE nid = %d', array($node->nid)));
+ if ($upload) {
+ // Rename file.
+ $edit = array();
+ $edit['files['. $upload->fid .'][description]'] = $new_name = substr($upload->description, 1);
+ $this->drupalPost('node/'. $node->nid .'/edit', $edit, t('Save'));
+ $this->assertRaw(t('Page %title has been updated.', array('%title' => $node->title)), 'File renamed successfully.');
+
+ $this->assertText($new_name, $new_name .' found on node.');
+ $this->assertNoText($upload->description, $upload->description .' not found on node.');
+
+ // Delete a file.
+ $edit = array();
+ $edit['files['. $upload->fid .'][remove]'] = TRUE;
+ $this->drupalPost('node/'. $node->nid .'/edit', $edit, t('Save'));
+ $this->assertRaw(t('Page %title has been updated.', array('%title' => $node->title)), 'File deleted successfully.');
+
+ $this->assertNoText($new_name, $new_name .' not found on node.');
+ $this->drupalGet(file_directory_path() .'/'. $upload->description);
+ $this->assertResponse(array(404), 'Uploaded '. $upload->description .' is not accessible.');
+ }
+ else {
+ $this->fail('File upload record not found in database.');
+ }
+ }
+
+ /**
+ * Ensure the the file filter works correctly by attempting to upload a non-allowed file extension.
+ */
+ function testFilesFilter() {
+ $admin_user = $this->drupalCreateUser(array('administer site configuration'));
+ $web_user = $this->drupalCreateUser(array('access content', 'edit any page content', 'upload files', 'view uploaded files'));
+
+ $this->drupalLogin($admin_user);
+
+ // Setup upload settings.
+ $settings = array();
+ $settings['upload_list'] = '1'; // Yes.
+ $settings['upload_extensions'] = 'html';
+ $settings['upload_uploadsize'] = '1';
+ $settings['upload_usersize'] = '1';
+ $this->setUploadSettings($settings, $this->getSimpletestRoleId($web_user));
+
+ $this->drupalLogin($web_user);
+
+ $node = $this->drupalCreateNode();
+ $text_files = $this->drupalGetTestFiles('text');
+ $html_files = $this->drupalGetTestFiles('html');
+ $files = array(current($text_files)->filename, current($html_files)->filename);
+
+ // Attempt to upload .txt file when .test is only extension allowed.
+ $this->uploadFile($node, $files[0], FALSE);
+ $this->assertRaw(t('The selected file %name could not be uploaded. Only files with the following extensions are allowed: %files-allowed.', array('%name' => basename($files[0]), '%files-allowed' => $settings['upload_extensions'])), 'File '. $files[0] .' was not allowed to be uploaded');
+
+ // Attempt to upload .test file when .test is only extension allowed.
+ $this->uploadFile($node, $files[1]);
+ }
+
+ /**
+ * Attempt to upload a file that is larger than the maxsize and see that it fails.
+ */
+ function testLimit() {
+ $files = $this->drupalGetTestFiles('text', 1310720); // 1 MB.
+ $file = current($files)->filename;
+
+ $admin_user = $this->drupalCreateUser(array('administer site configuration'));
+ $web_user = $this->drupalCreateUser(array('access content', 'edit any page content', 'upload files', 'view uploaded files'));
+
+ $this->drupalLogin($admin_user);
+
+ // Setup upload settings.
+ $settings = array();
+ $settings['upload_list'] = '1'; // Yes.
+ $settings['upload_extensions'] = 'jpg jpeg gif png txt doc xls pdf ppt pps odt ods odp';
+ $settings['upload_uploadsize'] = '0.5';
+ $settings['upload_usersize'] = '1.5';
+ $this->setUploadSettings($settings, $this->getSimpletestRoleId($web_user));
+
+ $this->drupalLogin($web_user);
+
+ $node = $this->drupalCreateNode();
+
+ // Attempt to upload file which is bigger than the maximum size of 0.5 MB.
+ $this->uploadFile($node, $file, FALSE);
+
+ $info = stat($file);
+ $filename = basename($file);
+ $filesize = format_size($info['size']);
+ $maxsize = format_size(parse_size(($settings['upload_uploadsize'] * 1024) .'KB')); // Won't parse decimals.
+ $this->assertRaw(t('The selected file %name could not be uploaded. The file is %filesize exceeding the maximum file size of %maxsize.', array('%name' => $filename, '%filesize' => $filesize, '%maxsize' => $maxsize)), t('File upload was blocked since it was larger than maxsize.'));
+ }
+
+ function setUploadSettings($settings, $rid = NULL) {
+ $edit = array();
+ foreach ($settings as $key => $value) {
+ $edit[$key .'_default'] = $value;
+ if ($rid !== NULL && $key != 'upload_list' && $key != 'upload_max_resolution') {
+ $edit[$key .'_'. $rid] = $value;
+ }
+ }
+ $this->drupalPost('admin/settings/uploads', $edit, 'Save configuration');
+ $this->assertText('The configuration options have been saved.', 'Upload setting saved.');
+ }
+
+ /**
+ * Upload file to specified node.
+ *
+ * @param object $node Node object.
+ * @param string $filename Name of file to upload.
+ * @param boolean $assert Assert that the node was successfully updated.
+ */
+ function uploadFile($node, $filename, $assert = TRUE) {
+ $edit = array();
+ $edit['files[upload]'] = $filename; //edit-upload
+ $this->drupalPost('node/'. $node->nid .'/edit', $edit, t('Save'));
+ if ($assert) {
+ $this->assertRaw(t('Page %title has been updated.', array('%title' => $node->title)), 'File attached successfully.');
+ }
+ }
+
+ /**
+ * Check that uploaded file is accessible and verify the contents against the original.
+ *
+ * @param string $filename Name of file to verifiy.
+ */
+ function checkUploadedFile($filename) {
+ $file = realpath(file_directory_path() .'/simpletest/'. $filename);
+ $this->drupalGet(file_directory_path() .'/'. $filename);
+ $this->assertResponse(array(200), 'Uploaded '. $filename .' is accessible.');
+ $this->assertEqual(file_get_contents($file), $this->drupalGetContent(), 'Uploaded contents of '. $filename .' verified.');
+ }
+
+ /**
+ * Get the role id of the 'simpletest' role associated with a SimpleTest test user.
+ *
+ * @param object $user User object.
+ * @return interger SimpleTest role id.
+ */
+ function getSimpletestRoleId($user) {
+ foreach ($user->roles as $rid => $role) {
+ if (strpos($role, 'simpletest') !== FALSE) {
+ return $rid;
+ }
+ }
+ return NULL;
+ }
+}
+
+class UploadPictureTestCase extends DrupalWebTestCase {
+ function getInfo() {
+ return array(
+ 'name' => t('Upload user picture'),
+ 'description' => t('Assure that dimension check, extension check and image scaling work as designed.'),
+ 'group' => t('Upload')
+ );
+ }
+
+ /*
+ * Test if directories specified in settings exist in filesystem
+ */
+ function testDirectories() {
+ // test if filepath is proper
+ $file_dir = file_directory_path();
+ $picture_dir = variable_get('user_picture_path', 'pictures');
+ $file_check = file_check_directory($file_dir, FILE_CREATE_DIRECTORY, 'file_directory_path');
+ $picture_path = $file_dir .'/'.$picture_dir;
+
+ $pic_check = file_check_directory($picture_path, FILE_CREATE_DIRECTORY, 'user_picture_path');
+ // check directories
+ //$this->assertTrue($file_check,"The directory $file_dir doesn't exist or cannot be created.");
+ //$this->assertTrue($pic_check,"The directory $picture_path doesn't exist or cannot be created.");
+ $this->_directory_test = is_writable($picture_path);
+ $this->assertTrue($this->_directory_test, "The directory $picture_path doesn't exist or is not writable. Further tests won't be made.");
+ }
+
+ function testNoPicture() {
+ $old_pic_set = variable_get('user_pictures', 0);
+ variable_set('user_pictures', 1);
+
+ /* Prepare a user to do the stuff */
+ $user = $this->drupalCreateUser(array('access content'));
+ $this->drupalLogin($user);
+
+ // not a image
+ $img_path = realpath(drupal_get_path('module', 'simpletest'). "/tests/functional/upload.test");
+ $edit = array('files[picture_upload]' => $img_path);
+ $this->drupalPost('user/'.$user->uid.'/edit', $edit, t('Save'));
+ $this->assertRaw(t('The selected file %file could not be uploaded. Only JPEG, PNG and GIF images are allowed.', array('%file' => 'upload.test')), 'The uploaded file was not an image.');
+ variable_set('user_pictures', $old_pic_set);
+
+ // do we have to check users roles?
+ // delete test user and roles
+
+ }
+
+ /*
+ * Do one test if ImageGDToolkit is installed
+ */
+
+ /*
+ * Do the test:
+ * GD Toolkit is installed
+ * Picture has invalid dimension
+ *
+ * results: The image should be uploaded because ImageGDToolkit resizes the picture
+ */
+ function testWithGDinvalidDimension() {
+ if ($this->_directory_test)
+ if (image_get_toolkit()) {
+
+ // PREPARE:
+ $old_pic_set = variable_get('user_pictures', 0);
+ variable_set('user_pictures', 1);
+
+ /* Prepare a user to do the stuff */
+ $user = $this->drupalCreateUser(array('access content'));
+ $this->drupalLogin($user);
+
+ // changing actual setting;
+ $old_dim = variable_get('user_picture_dimensions', '85x85');
+ $old_size = variable_get('user_picture_file_size', '30');
+ $img_path = realpath(drupal_get_path('module', 'simpletest'). "/tests/files/image-2.jpg");
+ $info = image_get_info($img_path);
+
+ // set new variables;
+ $test_size = floor(filesize($img_path) / 1000) + 1;
+ $test_dim = ($info['width'] - 10) . 'x' . ($info['height'] - 10);
+ variable_set('user_picture_dimensions', $test_dim);
+ variable_set('user_picture_file_size', $test_size);
+
+ // TEST:
+ $edit = array('files[picture_upload]' => $img_path);
+ $this->drupalPost('user/'.$user->uid.'/edit', $edit, t('Save'));
+ $picture_dir = variable_get('user_picture_path', 'pictures');
+ $picture = $picture_dir .'/picture-'.$user->uid.'.jpg';
+
+ // get full url to the user's image
+ $picture_url = file_create_url($picture);
+ $picture_path = file_create_path($picture);
+
+ // check if image is displayed in user's profile page
+ $this->assertRaw($picture_url, "Image is displayed in user's profile page");
+
+ // check if file is located in proper directory
+ $this->assertTrue(is_file($picture_path), "File is located in proper directory");
+
+ // RESTORING:
+ variable_set('user_picture_file_size', $old_size);
+ variable_set('user_picture_dimensions', $old_dim);
+
+ variable_set('user_pictures', $old_pic_set);
+ }
+
+ }
+
+ /*
+ * Do the test:
+ * GD Toolkit is installed
+ * Picture has invalid size
+ *
+ * results: The image should be uploaded because ImageGDToolkit resizes the picture
+ */
+
+ function testWithGDinvalidSize() {
+ if ($this->_directory_test)
+ if (image_get_toolkit()) {
+ // PREPARE:
+ $old_pic_set = variable_get('user_pictures', 0);
+ variable_set('user_pictures', 1);
+
+ /* Prepare a user to do the stuff */
+ $user = $this->drupalCreateUser(array('access content'));
+ $this->drupalLogin($user);
+
+ // changing actual setting;
+ $old_dim = variable_get('user_picture_dimensions', '85x85');
+ $old_size = variable_get('user_picture_file_size', '30');
+ $files = $this->drupalGetTestFiles('image');
+ $file = current($files);
+ $img_path = realpath($file->filename);
+ $info = image_get_info($img_path);
+ // set new variables;
+
+ $test_dim = ($info['width'] + 10) . 'x' . ($info['height'] + 10);
+ $test_size = filesize($img_path);
+ variable_set('user_picture_dimensions', $test_dim);
+ variable_set('user_picture_file_size', $test_size);
+
+ // TEST:
+ $edit = array('files[picture_upload]' => $img_path);
+ $this->drupalPost('user/'.$user->uid.'/edit', $edit, t('Save'));
+ $picture_dir = variable_get('user_picture_path', 'pictures');
+ $picture = $picture_dir .'/picture-'.$user->uid.'.jpg';
+
+ // get full url to the user's image
+ $picture_url = file_create_url($picture);
+ $picture_path = file_create_path($picture);
+
+ // check if image is displayed in user's profile page
+ $this->assertRaw($picture_url, "Image is displayed in user's profile page");
+
+ // check if file is located in proper directory
+ $this->assertTrue(is_file($picture_path), "File is located in proper directory");
+
+ // RESTORING:
+ variable_set('user_picture_file_size', $old_size);
+ variable_set('user_picture_dimensions', $old_dim);
+
+ variable_set('user_pictures', $old_pic_set);
+ }
+ }
+
+ /*
+ * Do the test:
+ * GD Toolkit is not installed
+ * Picture has invalid size
+ *
+ * results: The image shouldn't be uploaded
+ */
+ function testWithoutGDinvalidDimension() {
+ if ($this->_directory_test)
+ if (!image_get_toolkit()) {
+ // PREPARE:
+ $old_pic_set = variable_get('user_pictures', 0);
+ variable_set('user_pictures', 1);
+
+ /* Prepare a user to do the stuff */
+ $user = $this->drupalCreateUser(array('access content'));
+ $this->drupalLogin($user);
+
+ // changing actual setting;
+ $old_dim = variable_get('user_picture_dimensions', '85x85');
+ $old_size = variable_get('user_picture_file_size', '30');
+ $img_path = realpath(drupal_get_path('module', 'simpletest'). "/tests/files/image-2.jpg");
+ $info = image_get_info($img_path);
+ // set new variables;
+ $test_size = floor(filesize($img_path) / 1000) + 1;
+ $test_dim = ($info['width'] - 10) . 'x' . ($info['height'] - 10);
+ variable_set('user_picture_dimensions', $test_dim);
+ variable_set('user_picture_file_size', $test_size);
+
+ // TEST:
+ $edit = array('picture' => $img_path);
+ $this->drupalPost('user/'.$user->uid.'/edit', $edit, t('Save'));
+ $text = t('The uploaded image is too large; the maximum dimensions are %dimensions pixels.', array('%dimensions' => variable_get('user_picture_dimensions', '85x85')));
+ $this->assertText($text, 'Checking response on invalid image (dimensions).');
+
+ // check if file is not uploaded
+ $file_dir = variable_get('file_directory_path', 'files');
+ $picture_dir = variable_get('user_picture_path', 'pictures');
+ $pic_path = $file_dir .'/'.$picture_dir .'/picture-'.$user->uid.'.jpg';
+ $this->assertFalse(is_file($pic_path), "File is not uploaded");
+
+ // restore variables;
+ variable_set('user_picture_file_size', $old_size);
+ variable_set('user_picture_dimensions', $old_dim);
+
+ variable_set('user_pictures', $old_pic_set);
+ }
+ }
+
+ /*
+ * Do the test:
+ * GD Toolkit is not installed
+ * Picture has invalid size
+ *
+ * results: The image shouldn't be uploaded
+ */
+ function testWithoutGDinvalidSize() {
+ if ($this->_directory_test)
+ if (!image_get_toolkit()) {
+ // PREPARE:
+ $old_pic_set = variable_get('user_pictures', 0);
+ variable_set('user_pictures', 1);
+
+ /* Prepare a user to do the stuff */
+ $user = $this->drupalCreateUser(array('access content'));
+ $this->drupalLogin($user);
+
+ // changing actual setting;
+ $old_dim = variable_get('user_picture_dimensions', '85x85');
+ $old_size = variable_get('user_picture_file_size', '30');
+ $img_path = realpath("modules/tests/image-2.jpg");
+ $info = image_get_info($img_path);
+ // invalid size
+ // restore one and set another
+ $test_dim = ($info['width'] + 10) . 'x' . ($info['height'] + 10);
+ $test_size = floor(filesize($img_path) / 1000) - 1;
+ variable_set('user_picture_dimensions', $test_dim);
+ variable_set('user_picture_file_size', $test_size);
+
+ $edit = array('picture' => $img_path);
+ $this->drupalPost('user/'.$user->uid.'/edit', $edit, t('Save'));
+ $text = t('The uploaded image is too large; the maximum file size is %size kB.', array('%size' => variable_get('user_picture_file_size', '30')));
+ $this->assertText($text, 'Checking response on invalid image size.');
+
+ // check if file is not uploaded
+ $file_dir = variable_get('file_directory_path', 'files');
+ $picture_dir = variable_get('user_picture_path', 'pictures');
+ $pic_path = $file_dir .'/'.$picture_dir .'/picture-'.$user->uid.'.jpg';
+ $this->assertFalse(is_file($pic_path), "File is not uploaded");
+ // restore variables;
+ variable_set('user_picture_file_size', $old_size);
+ variable_set('user_picture_dimensions', $old_dim);
+
+ variable_set('user_pictures', $old_pic_set);
+ }
+ }
+
+ /*
+ * Do the test:
+ * Picture is valid (proper size and dimension)
+ *
+ * results: The image should be uploaded
+ */
+ function testPictureIsValid() {
+ if ($this->_directory_test) {
+ // PREPARE:
+ $old_pic_set = variable_get('user_pictures', 0);
+ variable_set('user_pictures', 1);
+
+ /* Prepare a user to do the stuff */
+ $user = $this->drupalCreateUser(array('access content'));
+ $this->drupalLogin($user);
+
+ // changing actual setting;
+ $old_dim = variable_get('user_picture_dimensions', '85x85');
+ $old_size = variable_get('user_picture_file_size', '30');
+ $img_path = realpath(drupal_get_path('module', 'simpletest'). "/tests/files/image-2.jpg");
+ $info = image_get_info($img_path);
+
+ // valid size & dimensions
+ // restore one and set another
+ $test_dim = ($info['width'] + 10) . 'x' . ($info['height'] + 10);
+ $test_size = floor(filesize($img_path) / 1000) + 1;
+ variable_set('user_picture_dimensions', $test_dim);
+ variable_set('user_picture_file_size', $test_size);
+
+ // TEST:
+ $edit = array('files[picture_upload]' => $img_path);
+ $this->drupalPost('user/'.$user->uid.'/edit', $edit, t('Save'));
+ $picture_dir = variable_get('user_picture_path', 'pictures');
+ $pic_path = file_directory_path() .'/'.$picture_dir .'/picture-'.$user->uid.'.jpg';
+
+ // get full url to the user's image
+ $picture = file_create_url($pic_path);
+
+ // check if image is displayed in user's profile page
+ $content = $this->drupalGetContent();
+
+ $this->assertTrue(strpos($content, $picture), "Image is displayed in user's profile page");
+
+ // check if file is located in proper directory
+ $this->assertTrue(is_file($pic_path), "File is located in proper directory");
+
+ // RESTORING:
+ variable_set('user_picture_file_size', $old_size);
+ variable_set('user_picture_dimensions', $old_dim);
+
+ variable_set('user_pictures', $old_pic_set);
+
+ // DELETING UPLOADED PIC
+ file_delete($pic_path);
+ }
+ }
+}
diff --git a/modules/user/user.test b/modules/user/user.test
new file mode 100644
index 000000000..6428fa17e
--- /dev/null
+++ b/modules/user/user.test
@@ -0,0 +1,205 @@
+<?php
+// $Id$
+
+class UserRegistrationTestCase extends DrupalWebTestCase {
+ /**
+ * Implementation of getInfo().
+ */
+ function getInfo() {
+ return array(
+ 'name' => t('User registration'),
+ 'description' => t('Registers a user, fails login, resets password, successfully logs in with the one time password, changes password, logs out, successfully logs in with the new password, visits profile page.'),
+ 'group' => t('User')
+ );
+ }
+
+ /**
+ * Registers a user, fails login, resets password, successfully logs in with the one time password,
+ * changes password, logs out, successfully logs in with the new password, visits profile page.
+ *
+ * Assumes that the profile module is disabled.
+ */
+ function testUserRegistration() {
+ // Set user registration to "Visitors can create accounts and no administrator approval is required."
+ variable_set('user_register', 1);
+
+ $edit = array();
+ $edit['name'] = $name = $this->randomName();
+ $edit['mail'] = $mail = $edit['name'] .'@example.com';
+ $this->drupalPost('user/register', $edit, t('Create new account'));
+ $this->assertText(t('Your password and further instructions have been sent to your e-mail address.'), t('User registered successfully.'));
+
+ // Check database for created user.
+ $user = user_load($edit);
+ $this->assertTrue($user, t('User found in database.'));
+ $this->assertTrue($user->uid > 0, t('User has valid user id.'));
+
+ // Check user fields.
+ $this->assertEqual($user->name, $name, t('Username matches.'));
+ $this->assertEqual($user->mail, $mail, t('E-mail address matches.'));
+ $this->assertEqual($user->mode, 0, t('Correct mode field.'));
+ $this->assertEqual($user->sort, 0, t('Correct sort field.'));
+ $this->assertEqual($user->threshold, 0, t('Correct treshold field.'));
+ $this->assertEqual($user->theme, '', t('Correct theme field.'));
+ $this->assertEqual($user->signature, '', t('Correct signature field.'));
+ $this->assertTrue(($user->created > time() - 20 ), 0, t('Correct creation time.'));
+ $this->assertEqual($user->status, variable_get('user_register', 1) == 1 ? 1 : 0, t('Correct status field.'));
+ $this->assertEqual($user->timezone, variable_get('date_default_timezone', NULL), t('Correct timezone field.'));
+ $this->assertEqual($user->language, '', t('Correct language field.'));
+ $this->assertEqual($user->picture, '', t('Correct picture field.'));
+ $this->assertEqual($user->init, $mail, t('Correct init field.'));
+
+ // Attempt to login with incorrect password.
+ $edit = array();
+ $edit['name'] = $name;
+ $edit['pass'] = 'foo';
+ $this->drupalPost('user', $edit, t('Log in'));
+ $this->assertText(t('Sorry, unrecognized username or password. Have you forgotten your password?'), t('Invalid login attempt failed.'));
+
+ // Login using password reset page.
+ $url = user_pass_reset_url($user);
+ sleep(1); // TODO Find better way.
+ $this->drupalGet($url);
+ $this->assertText(t('This login can be used only once.'), t('Login can be used only once.'));
+
+ $this->drupalPost(NULL, NULL, t('Log in'));
+ $this->assertText(t('You have just used your one-time login link. It is no longer necessary to use this link to login. Please change your password.'), t('This link is no longer valid.'));
+
+ // Change user password.
+ $new_pass = user_password();
+ $edit = array();
+ $edit['pass[pass1]'] = $new_pass;
+ $edit['pass[pass2]'] = $new_pass;
+ $this->drupalPost(NULL, $edit, t('Save'));
+ $this->assertText(t('The changes have been saved.'), t('Password changed to @password', array('@password' => $new_pass)));
+
+ // Make sure password changes are present in database.
+ require_once variable_get('password_inc', './includes/password.inc');
+
+ $user = user_load(array('uid' => $user->uid));
+ $this->assertTrue(user_check_password($new_pass, $user), t('Correct password in database.'));
+
+ // Logout of user account.
+ $this->clickLink(t('Log out'));
+ $this->assertNoText($user->name, t('Logged out.'));
+
+ // Login user.
+ $edit = array();
+ $edit['name'] = $user->name;
+ $edit['pass'] = $new_pass;
+ $this->drupalPost('user', $edit, t('Log in'));
+ $this->assertText(t('Log out'), t('Logged in.'));
+
+ $this->assertText($user->name, t('[logged in] Username found.'));
+ $this->assertNoText(t('Sorry. Unrecognized username or password.'), t('[logged in] No message for unrecognized username or password.'));
+ $this->assertNoText(t('User login'), t('[logged in] No user login form present.'));
+
+ $this->drupalGet('user');
+ $this->assertText($user->name, t('[user auth] Not login page.'));
+ $this->assertText(t('View'), t('[user auth] Found view tab on the profile page.'));
+ $this->assertText(t('Edit'), t('[user auth] Found edit tab on the profile page.'));
+ }
+}
+
+
+class UserValidationTestCase extends DrupalWebTestCase {
+ /**
+ * Implementation of getInfo().
+ */
+ function getInfo() {
+ return array(
+ 'name' => t('Username/e-mail validation'),
+ 'description' => t('Verify that username/email validity checks behave as designed.'),
+ 'group' => t('User')
+ );
+ }
+
+ // Username validation.
+ function testMinLengthName() {
+ $name = '';
+ $result = user_validate_name($name);
+ $this->assertNotNull($result, 'Excessively short username');
+ }
+
+ function testValidCharsName() {
+ $name = 'ab/';
+ $result = user_validate_name($name);
+ $this->assertNotNull($result, 'Invalid chars in username');
+ }
+
+ function testMaxLengthName() {
+ $name = str_repeat('a', 61);
+ $result = user_validate_name($name);
+ $this->assertNotNull($result, 'Excessively long username');
+ }
+
+ function testValidName() {
+ $name = 'abc';
+ $result = user_validate_name($name);
+ $this->assertNull($result, 'Valid username');
+ }
+
+ // Mail validation.
+ function testMinLengthMail() {
+ $name = '';
+ $result = user_validate_mail($name);
+ $this->assertNotNull($result, 'Empty mail');
+ }
+
+ function testInValidMail() {
+ $name = 'abc';
+ $result = user_validate_mail($name);
+ $this->assertNotNull($result, 'Invalid mail');
+ }
+
+ function testValidMail() {
+ $name = 'absdsdsdc@dsdsde.com';
+ $result = user_validate_mail($name);
+ $this->assertNull($result, 'Valid mail');
+ }
+}
+
+
+class UserDeleteTestCase extends DrupalWebTestCase {
+ /**
+ * Implementation of getInfo().
+ */
+ function getInfo() {
+ return array(
+ 'name' => t('User delete'),
+ 'description' => t('Registers a user and deletes it.'),
+ 'group' => t('User')
+ );
+ }
+
+ /**
+ * Registers a user and deletes it.
+ */
+ function testUserRegistration() {
+ // Set user registration to "Visitors can create accounts and no administrator approval is required."
+ variable_set('user_register', 1);
+
+ $edit = array();
+ $edit['name'] = $this->randomName();
+ $edit['mail'] = $edit['name'] .'@example.com';
+ $this->drupalPost('user/register', $edit, t('Create new account'));
+ $this->assertText(t('Your password and further instructions have been sent to your e-mail address.'), t('User registered successfully.'));
+
+ $user = user_load($edit);
+
+ // Create admin user to delete registered user.
+ $admin_user = $this->drupalCreateUser(array('administer users'));
+ $this->drupalLogin($admin_user);
+
+ // Delete user.
+ $this->drupalGet('user/'. $user->uid .'/edit');
+ $this->drupalPost(NULL, NULL, t('Delete'));
+ $this->assertRaw(t('Are you sure you want to delete the account %name?', array('%name' => $user->name)), t('[confirm deletion] Asks for confirmation.'));
+ $this->assertText(t('All submissions made by this user will be attributed to the anonymous account. This action cannot be undone.'), t('[confirm deletion] Inform that all submissions will be attributed to anonymouse account.'));
+
+ // Confirm deletion.
+ $this->drupalPost(NULL, NULL, t('Delete'));
+ $this->assertRaw(t('%name has been deleted.', array('%name' => $user->name)), t('User deleted'));
+ $this->assertFalse(user_load($edit), t('User is not found in the database'));
+ }
+}
diff --git a/scripts/run-functional-tests.php b/scripts/run-functional-tests.php
new file mode 100755
index 000000000..56a0da6d2
--- /dev/null
+++ b/scripts/run-functional-tests.php
@@ -0,0 +1,58 @@
+#!/usr/bin/php
+<?php
+// $Id$
+
+/**
+ * @file
+ * This script can be run with browser or from command line.
+ * You can provide class names of the tests you wish to run.
+ * When this script is run from browser you can select which reporter to use html or xml.
+ * For command line: php run_functional_tests.php SearchMatchTest,ProfileModuleTestSingle
+ * For browser: http://yoursite.com/sites/all/modules/simpletest/run_all_tests.php?include=SearchMatchTest,ProfileModuleTestSingle&reporter=html
+ * If none of these two options are provided all tests will be run.
+ */
+
+$tests = NULL;
+$reporter = 'text';
+$host = 'localhost';
+$path = '';
+array_shift($_SERVER['argv']); // throw away script name
+while ($param = array_shift($_SERVER['argv'])) {
+ switch ($param) {
+ case '--url':
+ $url = array_shift($_SERVER['argv']);
+ $parse = parse_url($url);
+ $host = $parse['host'];
+ $path = $parse['path'];
+ break;
+
+ default:
+ $tests = explode(',', $param);
+ break;
+ }
+}
+
+$_SERVER['HTTP_HOST'] = $host;
+$_SERVER['REMOTE_ADDR'] = '127.0.0.1';
+$_SERVER['SERVER_ADDR'] = '127.0.0.1';
+$_SERVER['SERVER_SOFTWARE'] = 'Apache';
+$_SERVER['SERVER_NAME'] = 'localhost';
+$_SERVER['REQUEST_URI'] = $path .'/';
+$_SERVER['SCRIPT_NAME'] = $path .'/index.php';
+$_SERVER['PHP_SELF'] = $path .'/index.php';
+$_SERVER['HTTP_USER_AGENT'] = 'Drupal command line';
+
+chdir(realpath(dirname(__FILE__) . '/..'));
+require_once './includes/bootstrap.inc';
+drupal_bootstrap(DRUPAL_BOOTSTRAP_FULL);
+
+//load simpletest files
+simpletest_load();
+
+// If not in 'safe mode', increase the maximum execution time:
+if (!ini_get('safe_mode')) {
+ set_time_limit(360);
+}
+
+simpletest_run_tests($tests, $reporter);
+?>