diff --git a/CHANGELOG.txt b/CHANGELOG.txt index e76bb1b198a..953c7bf9d59 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 145290ab08d..41116091bb7 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 00000000000..49bab141ad9 --- /dev/null +++ b/includes/xmlrpc.inc.test @@ -0,0 +1,117 @@ + 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">>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 00000000000..e94c23af3f8 --- /dev/null +++ b/modules/aggregator/aggregator.test @@ -0,0 +1,314 @@ +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 00000000000..85a95e60347 --- /dev/null +++ b/modules/block/block.test @@ -0,0 +1,111 @@ + 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 00000000000..a3a6c144131 --- /dev/null +++ b/modules/blog/blog.test @@ -0,0 +1,171 @@ + 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 = '''; + + $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 00000000000..ea6accf0b64 --- /dev/null +++ b/modules/blogapi/blogapi.test @@ -0,0 +1,159 @@ + 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 00000000000..7961bda8bd5 --- /dev/null +++ b/modules/book/book.test @@ -0,0 +1,154 @@ + 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('', '', $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 '/
/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 00000000000..c309769f242 --- /dev/null +++ b/modules/comment/comment.test @@ -0,0 +1,372 @@ + 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 ? '
(.*?)' : ''); + $regex .= '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 00000000000..2372ad95b69 --- /dev/null +++ b/modules/contact/contact.test @@ -0,0 +1,266 @@ + 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 00000000000..75faadd8262 --- /dev/null +++ b/modules/dblog/dblog.test @@ -0,0 +1,370 @@ + 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 = '''; + + // 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 00000000000..a18582ac40e --- /dev/null +++ b/modules/filter/filter.test @@ -0,0 +1,182 @@ + 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'] = '