diff options
author | Dries Buytaert <dries@buytaert.net> | 2010-03-31 20:05:06 +0000 |
---|---|---|
committer | Dries Buytaert <dries@buytaert.net> | 2010-03-31 20:05:06 +0000 |
commit | 6fc055ab906c035355bfb789aed404551db5b45a (patch) | |
tree | f29650c65f8a7003ce73ebc6047f216f91e14c79 /modules | |
parent | e0871ec49bb81adff156d4bc7cf2d9f8b50d04a0 (diff) | |
download | brdo-6fc055ab906c035355bfb789aed404551db5b45a.tar.gz brdo-6fc055ab906c035355bfb789aed404551db5b45a.tar.bz2 |
- Patch #730220 by Berdir, aspilicious, Damien Tournoud, pwolanin: improved xpath tests.
Diffstat (limited to 'modules')
-rw-r--r-- | modules/block/block.test | 9 | ||||
-rw-r--r-- | modules/book/book.test | 2 | ||||
-rw-r--r-- | modules/comment/comment.test | 40 | ||||
-rw-r--r-- | modules/field/modules/options/options.test | 4 | ||||
-rw-r--r-- | modules/filter/filter.test | 10 | ||||
-rw-r--r-- | modules/locale/locale.test | 15 | ||||
-rw-r--r-- | modules/node/node.test | 3 | ||||
-rw-r--r-- | modules/rdf/rdf.test | 52 | ||||
-rw-r--r-- | modules/simpletest/drupal_web_test_case.php | 70 | ||||
-rw-r--r-- | modules/simpletest/simpletest.test | 30 | ||||
-rw-r--r-- | modules/syslog/syslog.test | 2 | ||||
-rw-r--r-- | modules/translation/translation.test | 2 |
12 files changed, 169 insertions, 70 deletions
diff --git a/modules/block/block.test b/modules/block/block.test index 19f52d970..79b6b19ef 100644 --- a/modules/block/block.test +++ b/modules/block/block.test @@ -58,7 +58,7 @@ class BlockTestCase extends DrupalWebTestCase { foreach ($themes as $key => $theme) { if ($theme->status) { foreach ($theme->info['regions_hidden'] as $hidden_region) { - $elements = $this->xpath('//select[@id="edit-regions-' . $key . '"]//option[@value="' . $hidden_region . '"]'); + $elements = $this->xpath('//select[@id=:id]//option[@value=:value]', array(':id' => 'edit-regions-' . $key, ':value' => $hidden_region)); $this->assertFalse(isset($elements[0]), t('The hidden region @region is not available for @theme.', array('@region' => $hidden_region, '@theme' => $key))); } } @@ -220,7 +220,7 @@ class BlockTestCase extends DrupalWebTestCase { $this->assertNoText(t($block['title']), t('Block no longer appears on page.')); // Confirm that the regions xpath is not availble - $xpath = '//div[@id="block-block-' . $bid . '"]/*'; + $xpath = $this->buildXPathQuery('//div[@id=:id]/*', array(':id' => 'block-block-' . $bid)); $this->assertNoFieldByXPath($xpath, FALSE, t('Custom block found in no regions.')); // For convenience of developers, put the navigation block back. @@ -252,7 +252,10 @@ class BlockTestCase extends DrupalWebTestCase { $this->assertText(t($block['title']), t('Block successfully being displayed on the page.')); // Confirm that the custom block was found at the proper region. - $xpath = '//div[@class="' . $region['class'] . '"]//div[@id="block-' . $block['module'] . '-' . $block['delta'] . '"]/*'; + $xpath = $this->buildXPathQuery('//div[@class=:region-class]//div[@id=:block-id]/*', array( + ':region-class' => $region['class'], + ':block-id' => 'block-' . $block['module'] . '-' . $block['delta'], + )); $this->assertFieldByXPath($xpath, FALSE, t('Custom block found in %region_name region.', array('%region_name' => $region['name']))); } } diff --git a/modules/book/book.test b/modules/book/book.test index d68a17ab3..9b216f38a 100644 --- a/modules/book/book.test +++ b/modules/book/book.test @@ -129,7 +129,7 @@ class BookTestCase extends DrupalWebTestCase { } // Fetch links in the current breadcrumb. - $links = $this->xpath("//div[@class='breadcrumb']/a"); + $links = $this->xpath('//div[@class="breadcrumb"]/a'); $got_breadcrumb = array(); foreach ($links as $link) { $got_breadcrumb[] = (string) $link['href']; diff --git a/modules/comment/comment.test b/modules/comment/comment.test index f9d151ea7..ab81035ff 100644 --- a/modules/comment/comment.test +++ b/modules/comment/comment.test @@ -762,7 +762,7 @@ class CommentPagerTest extends CommentHelperCase { $expected_cids[] = $comments[$key]->id; } - $comment_anchors = $this->xpath("//a[starts-with(@id,'comment-')]"); + $comment_anchors = $this->xpath('//a[starts-with(@id,"comment-")]'); $result_order = array(); foreach ($comment_anchors as $anchor) { $result_order[] = substr($anchor['id'], 8); @@ -1134,13 +1134,13 @@ class CommentRdfaTestCase extends CommentHelperCase { // Tests number of comments in teaser view. $this->drupalGet('node'); - $comment_count_teaser = $this->xpath("//div[contains(@typeof, 'sioc:Item')]//li[contains(@class, 'comment_comments')]/a[contains(@property, 'sioc:num_replies') and contains(@content, '2') and @datatype='xsd:integer']"); + $comment_count_teaser = $this->xpath('//div[contains(@typeof, "sioc:Item")]//li[contains(@class, "comment_comments")]/a[contains(@property, "sioc:num_replies") and contains(@content, "2") and @datatype="xsd:integer"]'); $this->assertTrue(!empty($comment_count_teaser), t('RDFa markup for the number of comments found on teaser view.')); // Tests number of comments in full node view. $this->drupalGet('node/' . $this->node1->nid); $node_url = url('node/' . $this->node1->nid); - $comment_count_teaser = $this->xpath("/html/head/meta[@about='$node_url' and @property='sioc:num_replies' and @content='2' and @datatype='xsd:integer']"); + $comment_count_teaser = $this->xpath('/html/head/meta[@about=:node-url and @property="sioc:num_replies" and @content="2" and @datatype="xsd:integer"]', array(':node-url' => $node_url)); $this->assertTrue(!empty($comment_count_teaser), t('RDFa markup for the number of comments found on full node view.')); } @@ -1180,10 +1180,10 @@ class CommentRdfaTestCase extends CommentHelperCase { // Tests comment #2 as anonymous user. $this->_testBasicCommentRdfaMarkup($comment2, $anonymous_user); // Tests the RDFa markup for the homepage (specific to anonymous comments). - $comment_homepage = $this->xpath("//div[contains(@class, 'comment') and contains(@typeof, 'sioct:Comment')]//span[@rel='sioc:has_creator']/a[contains(@class, 'username') and @typeof='sioc:User' and @property='foaf:name' and @href='http://example.org/' and contains(@rel, 'foaf:page')]"); + $comment_homepage = $this->xpath('//div[contains(@class, "comment") and contains(@typeof, "sioct:Comment")]//span[@rel="sioc:has_creator"]/a[contains(@class, "username") and @typeof="sioc:User" and @property="foaf:name" and @href="http://example.org/" and contains(@rel, "foaf:page")]'); $this->assertTrue(!empty($comment_homepage), t('RDFa markup for the homepage of anonymous user found.')); // There should be no about attribute on anonymous comments. - $comment_homepage = $this->xpath("//div[contains(@class, 'comment') and contains(@typeof, 'sioct:Comment')]//span[@rel='sioc:has_creator']/a[@about]"); + $comment_homepage = $this->xpath('//div[contains(@class, "comment") and contains(@typeof, "sioct:Comment")]//span[@rel="sioc:has_creator"]/a[@about]'); $this->assertTrue(empty($comment_homepage), t('No about attribute is present on anonymous user comment.')); // Tests comment #2 as logged in user. @@ -1191,11 +1191,11 @@ class CommentRdfaTestCase extends CommentHelperCase { $this->drupalGet('node/' . $this->node2->nid); $this->_testBasicCommentRdfaMarkup($comment2, $anonymous_user); // Tests the RDFa markup for the homepage (specific to anonymous comments). - $comment_homepage = $this->xpath("//div[contains(@class, 'comment') and contains(@typeof, 'sioct:Comment')]//span[@rel='sioc:has_creator']/a[contains(@class, 'username') and @typeof='sioc:User' and @property='foaf:name' and @href='http://example.org/' and contains(@rel, 'foaf:page')]"); - $this->assertTrue(!empty($comment_homepage), t('RDFa markup for the homepage of anonymous user found.')); + $comment_homepage = $this->xpath('//div[contains(@class, "comment") and contains(@typeof, "sioct:Comment")]//span[@rel="sioc:has_creator"]/a[contains(@class, "username") and @typeof="sioc:User" and @property="foaf:name" and @href="http://example.org/" and contains(@rel, "foaf:page")]'); + $this->assertTrue(!empty($comment_homepage), t("RDFa markup for the homepage of anonymous user found.")); // There should be no about attribute on anonymous comments. - $comment_homepage = $this->xpath("//div[contains(@class, 'comment') and contains(@typeof, 'sioct:Comment')]//span[@rel='sioc:has_creator']/a[@about]"); - $this->assertTrue(empty($comment_homepage), t('No about attribute is present on anonymous user comment.')); + $comment_homepage = $this->xpath('//div[contains(@class, "comment") and contains(@typeof, "sioct:Comment")]//span[@rel="sioc:has_creator"]/a[@about]'); + $this->assertTrue(empty($comment_homepage), t("No about attribute is present on anonymous user comment.")); } /** @@ -1209,18 +1209,18 @@ class CommentRdfaTestCase extends CommentHelperCase { * An array containing information about an anonymous user. */ function _testBasicCommentRdfaMarkup($comment, $account = array()) { - $comment_container = $this->xpath("//div[contains(@class, 'comment') and contains(@typeof, 'sioct:Comment')]"); - $this->assertTrue(!empty($comment_container), t('Comment RDF type for comment found.')); - $comment_title = $this->xpath("//div[contains(@class, 'comment') and contains(@typeof, 'sioct:Comment')]//h3[@property='dc:title']"); - $this->assertEqual((string)$comment_title[0]->a, $comment->subject, t('RDFa markup for the comment title found.')); - $comment_date = $this->xpath("//div[contains(@class, 'comment') and contains(@typeof, 'sioct:Comment')]//*[contains(@property, 'dc:date') and contains(@property, 'dc:created')]"); - $this->assertTrue(!empty($comment_date), t('RDFa markup for the date of the comment found.')); + $comment_container = $this->xpath('//div[contains(@class, "comment") and contains(@typeof, "sioct:Comment")]'); + $this->assertTrue(!empty($comment_container), t("Comment RDF type for comment found.")); + $comment_title = $this->xpath('//div[contains(@class, "comment") and contains(@typeof, "sioct:Comment")]//h3[@property="dc:title"]'); + $this->assertEqual((string)$comment_title[0]->a, $comment->subject, t("RDFa markup for the comment title found.")); + $comment_date = $this->xpath('//div[contains(@class, "comment") and contains(@typeof, "sioct:Comment")]//*[contains(@property, "dc:date") and contains(@property, "dc:created")]'); + $this->assertTrue(!empty($comment_date), t("RDFa markup for the date of the comment found.")); // The author tag can be either a or span - $comment_author = $this->xpath("//div[contains(@class, 'comment') and contains(@typeof, 'sioct:Comment')]//span[@rel='sioc:has_creator']/*[contains(@class, 'username') and @typeof='sioc:User' and @property='foaf:name']"); - $name = empty($account['name']) ? $this->web_user->name : $account['name'] . ' (not verified)'; - $this->assertEqual((string)$comment_author[0], $name, t('RDFa markup for the comment author found.')); - $comment_body = $this->xpath("//div[contains(@class, 'comment') and contains(@typeof, 'sioct:Comment')]//div[@class='content']//div[contains(@class, 'comment-body')]//div[@property='content:encoded']"); - $this->assertEqual((string)$comment_body[0]->p, $comment->comment, t('RDFa markup for the comment body found.')); + $comment_author = $this->xpath('//div[contains(@class, "comment") and contains(@typeof, "sioct:Comment")]//span[@rel="sioc:has_creator"]/*[contains(@class, "username") and @typeof="sioc:User" and @property="foaf:name"]'); + $name = empty($account["name"]) ? $this->web_user->name : $account["name"] . " (not verified)"; + $this->assertEqual((string)$comment_author[0], $name, t("RDFa markup for the comment author found.")); + $comment_body = $this->xpath('//div[contains(@class, "comment") and contains(@typeof, "sioct:Comment")]//div[@class="content"]//div[contains(@class, "comment-body")]//div[@property="content:encoded"]'); + $this->assertEqual((string)$comment_body[0]->p, $comment->comment, t("RDFa markup for the comment body found.")); } } diff --git a/modules/field/modules/options/options.test b/modules/field/modules/options/options.test index 2d441204a..6f3a4cd51 100644 --- a/modules/field/modules/options/options.test +++ b/modules/field/modules/options/options.test @@ -247,7 +247,7 @@ class OptionsWidgetsTestCase extends FieldTestCase { $instance['required'] = TRUE; field_update_instance($instance); $this->drupalGet('test-entity/' . $entity->ftid .'/edit'); - $this->assertFalse($this->xpath('//select[@id="edit-card-1-' . $langcode . '"]//option[@value=""]'), t('A required select list does not have an empty key.')); + $this->assertFalse($this->xpath('//select[@id=:id]//option[@value=""]', array(':id' => 'edit-card-1-' . $langcode)), t('A required select list does not have an empty key.')); // We do not have to test that a required select list with one option is // auto-selected because the browser does it for us. @@ -363,7 +363,7 @@ class OptionsWidgetsTestCase extends FieldTestCase { $instance['required'] = TRUE; field_update_instance($instance); $this->drupalGet('test-entity/' . $entity->ftid .'/edit'); - $this->assertFalse($this->xpath('//select[@id="edit-card-2-' . $langcode . '"]//option[@value=""]'), t('A required select list does not have an empty key.')); + $this->assertFalse($this->xpath('//select[@id=:id]//option[@value=""]', array(':id' => 'edit-card-2-' . $langcode)), t('A required select list does not have an empty key.')); // We do not have to test that a required select list with one option is // auto-selected because the browser does it for us. diff --git a/modules/filter/filter.test b/modules/filter/filter.test index dd10d93ef..3c4a35ee3 100644 --- a/modules/filter/filter.test +++ b/modules/filter/filter.test @@ -238,7 +238,10 @@ class FilterAdminTestCase extends DrupalWebTestCase { $result = db_query('SELECT * FROM {cache_filter}')->fetchObject(); $this->assertFalse($result, t('Cache cleared.')); - $elements = $this->xpath('//select[@name="filters[' . $first_filter . '][weight]"]/following::select[@name="filters[' . $second_filter . '][weight]"]'); + $elements = $this->xpath('//select[@name=:first]/following::select[@name=:second]', array( + ':first' => 'filters[' . $first_filter . '][weight]', + ':second' => 'filters[' . $second_filter . '][weight]', + )); $this->assertTrue(!empty($elements), t('Order confirmed in admin interface.')); // Reorder filters. @@ -249,7 +252,10 @@ class FilterAdminTestCase extends DrupalWebTestCase { $this->assertFieldByName('filters[' . $second_filter . '][weight]', 1, t('Order saved successfully.')); $this->assertFieldByName('filters[' . $first_filter . '][weight]', 2, t('Order saved successfully.')); - $elements = $this->xpath('//select[@name="filters[' . $second_filter . '][weight]"]/following::select[@name="filters[' . $first_filter . '][weight]"]'); + $elements = $this->xpath('//select[@name=:first]/following::select[@name=:second]', array( + ':first' => 'filters[' . $second_filter . '][weight]', + ':second' => 'filters[' . $first_filter . '][weight]', + )); $this->assertTrue(!empty($elements), t('Reorder confirmed in admin interface.')); $result = db_query('SELECT * FROM {filter} WHERE format = :format ORDER BY weight ASC', array(':format' => $filtered)); diff --git a/modules/locale/locale.test b/modules/locale/locale.test index fecaf1bc6..a2add4610 100644 --- a/modules/locale/locale.test +++ b/modules/locale/locale.test @@ -1151,7 +1151,7 @@ class LanguageSwitchingFunctionalTest extends DrupalWebTestCase { $this->assertText(t('Languages'), t('Language switcher block found.')); // Assert that only the current language is marked as active. - list($language_switcher) = $this->xpath("//div[@id=\"block-locale-{$language_type}\"]/div[@class=\"content\"]"); + list($language_switcher) = $this->xpath('//div[@id=:id]/div[@class="content"]', array(':id' => 'block-locale-' . $language_type)); $links = array( 'active' => array(), 'inactive' => array(), @@ -1270,7 +1270,7 @@ class LocaleUserLanguageFunctionalTest extends DrupalWebTestCase { // Ensure form was submitted successfully. $this->assertText(t('The changes have been saved.'), t('Changes were saved.')); // Check if language was changed. - $elements = $this->xpath('//input[@id="edit-language-' . $langcode . '"]'); + $elements = $this->xpath('//input[@id=:id]', array(':id' => 'edit-language-' . $langcode)); $this->assertTrue(isset($elements[0]) && !empty($elements[0]['checked']), t('Default language successfully updated.')); $this->drupalLogout(); @@ -1886,17 +1886,18 @@ class LocaleMultilingualFieldsFunctionalTest extends DrupalWebTestCase { // Check if node body is showed. $this->drupalGet("node/$node->nid"); - $body_xpath = '//div[@id="node-' . $node->nid . '"]//div[@property="content:encoded"]/p'; - $this->assertEqual(current($this->xpath($body_xpath)), $node->body['en'][0]['value'], 'Node body is correctly showed.'); + $body = $this->xpath('//div[@id=:id]//div[@property="content:encoded"]/p', array(':id' => 'node-' . $node->nid)); + $this->assertEqual(current($body), $node->body['en'][0]['value'], 'Node body is correctly showed.'); $settings['body[full][type]'] = 'hidden'; $this->drupalPost('admin/structure/types/manage/page/display', $settings, t('Save')); - $select_xpath = '//select[@id="edit-body-full-type"]/option[@selected="selected"]'; + $select = $this->xpath('//select[@id="edit-body-full-type"]/option[@selected="selected"]'); // Check if body display is actually "hidden" for the "full" view mode. - $this->assertEqual(current($this->xpath($select_xpath)), '<Hidden>', 'Body display is actually "hidden" for the "full" view mode'); + $this->assertEqual(current($select), '<Hidden>', 'Body display is actually "hidden" for the "full" view mode'); $this->drupalGet("node/$node->nid"); // Check if node body is not showed. - $this->assertFalse(is_array($this->xpath($body_xpath)), 'Body correctly not showed.'); + $body = $this->xpath('//div[@id=:id]//div[@property="content:encoded"]/p', array(':id' => 'node-' . $node->nid)); + $this->assertFalse(is_array($body), 'Body correctly not showed.'); } } diff --git a/modules/node/node.test b/modules/node/node.test index b7ae58a91..a97501f3f 100644 --- a/modules/node/node.test +++ b/modules/node/node.test @@ -1247,8 +1247,7 @@ class NodeTitleTestCase extends DrupalWebTestCase { $this->assertEqual(current($this->xpath($xpath)), $node->title, 'Node breadcrumb is equal to node title.', 'Node'); // Test node title in comment preview. - $xpath = '//div[@id="node-'. $node->nid .'"]/h2/a'; - $this->assertEqual(current($this->xpath($xpath)), $node->title, 'Node preview title is equal to node title.', 'Node'); + $this->assertEqual(current($this->xpath('//div[@id=:id]/h2/a', array(':id' => 'node-' . $node->nid))), $node->title, 'Node preview title is equal to node title.', 'Node'); } } diff --git a/modules/rdf/rdf.test b/modules/rdf/rdf.test index 85dac8970..18545a186 100644 --- a/modules/rdf/rdf.test +++ b/modules/rdf/rdf.test @@ -165,9 +165,15 @@ class RdfMarkupTestCase extends DrupalWebTestCase { // We only check to make sure that the resource attribute contains '.txt' // instead of the full file name because the filename is altered on upload. - $file_rel = $this->xpath("//div[contains(@about, 'node/$nid')]//div[contains(@rel, 'rdfs:seeAlso') and contains(@resource, '.txt')]"); + $file_rel = $this->xpath('//div[contains(@about, :node-uri)]//div[contains(@rel, "rdfs:seeAlso") and contains(@resource, ".txt")]', array( + ':node-uri' => 'node/' . $nid, + )); $this->assertTrue(!empty($file_rel), t('Attribute \'rel\' set on file field. Attribute \'resource\' is also set.')); - $image_rel = $this->xpath("//div[contains(@about, 'node/$nid')]//div[contains(@rel, 'rdfs:seeAlso') and contains(@resource, '$image_filename')]//img[contains(@typeof, 'foaf:Image')]"); + $image_rel = $this->xpath('//div[contains(@about, :node-uri)]//div[contains(@rel, "rdfs:seeAlso") and contains(@resource, :image)]//img[contains(@typeof, "foaf:Image")]', array( + ':node-uri' => 'node/' . $nid, + ':image' => $image_filename, + )); + $this->assertTrue(!empty($image_rel), t('Attribute \'rel\' set on image field. Attribute \'resource\' is also set.')); } } @@ -315,11 +321,22 @@ class RdfMappingDefinitionTestCase extends DrupalWebTestCase { // page. These attributes come from the user default bundle definition. $account_uri = url('user/' . $user2->uid); $person_uri = url('user/' . $user2->uid, array('fragment' => 'me')); - $user2_profile_about = $this->xpath("//div[@class='profile' and @typeof='sioc:User' and @about='$account_uri']"); + + $user2_profile_about = $this->xpath('//div[@class="profile" and @typeof="sioc:User" and @about=:account-uri]', array( + ':account-uri' => $account_uri, + )); $this->assertTrue(!empty($user2_profile_about), t('RDFa markup found on user profile page')); - $user_account_holder = $this->xpath("//meta[contains(@typeof, 'foaf:Person') and @about='$person_uri' and @resource='$account_uri' and contains(@rel, 'foaf:account')]"); + + $user_account_holder = $this->xpath('//meta[contains(@typeof, "foaf:Person") and @about=:person-uri and @resource=:account-uri and contains(@rel, "foaf:account")]', array( + ':person-uri' => $person_uri, + ':account-uri' => $account_uri, + )); $this->assertTrue(!empty($user_account_holder), t('URI created for account holder and username set on sioc:User.')); - $user_username = $this->xpath("//meta[@about='$account_uri' and contains(@property, 'foaf:name') and @content='$username']"); + + $user_username = $this->xpath('//meta[@about=:account-uri and contains(@property, "foaf:name") and @content=:username]', array( + ':account-uri' => $account_uri, + ':username' => $username, + )); $this->assertTrue(!empty($user_username), t('foaf:name set on username.')); // User 2 creates node. @@ -329,7 +346,9 @@ class RdfMappingDefinitionTestCase extends DrupalWebTestCase { $this->drupalGet('node/' . $node->nid); // Ensures the default bundle mapping for user is used on the Authored By // information on the node. - $author_about = $this->xpath("//a[@typeof='sioc:User' and @about='$account_uri' and @property='foaf:name' and contains(@xml:lang, '')]"); + $author_about = $this->xpath('//a[@typeof="sioc:User" and @about=:account-uri and @property="foaf:name" and contains(@xml:lang, "")]', array( + ':account-uri' => $account_uri, + )); $this->assertTrue(!empty($author_about), t('RDFa markup found on author information on post. xml:lang on username is set to empty string.')); } @@ -344,7 +363,10 @@ class RdfMappingDefinitionTestCase extends DrupalWebTestCase { $this->drupalGet('taxonomy/term/' . $term->tid); $term_url = url('taxonomy/term/' . $term->tid); $term_name = $term->name; - $term_rdfa_meta = $this->xpath("//meta[@typeof='skos:Concept' and @about='$term_url' and contains(@property, 'rdfs:label') and contains(@property, 'skos:prefLabel') and @content='$term_name']"); + $term_rdfa_meta = $this->xpath('//meta[@typeof="skos:Concept" and @about=:term-url and contains(@property, "rdfs:label") and contains(@property, "skos:prefLabel") and @content=:term-name]', array( + ':term-url' => $term_url, + ':term-name' => $term_name, + )); $this->assertTrue(!empty($term_rdfa_meta), t('RDFa markup found on term page.')); } } @@ -406,19 +428,19 @@ class RdfTrackerAttributesTestCase extends DrupalWebTestCase { // Tests whether the about property is applied. This is implicit in the // success of the following tests, but making it explicit will make // debugging easier in case of failure. - $tracker_about = $this->xpath("//tr[@about='$url']"); + $tracker_about = $this->xpath('//tr[@about=:url]', array(':url' => $url)); $this->assertTrue(!empty($tracker_about), t('About attribute found on table row for @user content.', array('@user'=> $user))); // Tests whether the title has the correct property attribute. - $tracker_title = $this->xpath("//tr[@about='$url']/td[@property='dc:title' and @datatype='']"); + $tracker_title = $this->xpath('//tr[@about=:url]/td[@property="dc:title" and @datatype=""]', array(':url' => $url)); $this->assertTrue(!empty($tracker_title), t('Title property attribute found on @user content.', array('@user'=> $user))); // Tests whether the relationship between the content and user has been set. - $tracker_user = $this->xpath("//tr[@about='$url']//td[contains(@rel, 'sioc:has_creator')]//*[contains(@typeof, 'sioc:User') and contains(@property, 'foaf:name')]"); + $tracker_user = $this->xpath('//tr[@about=:url]//td[contains(@rel, "sioc:has_creator")]//*[contains(@typeof, "sioc:User") and contains(@property, "foaf:name")]', array(':url' => $url)); $this->assertTrue(!empty($tracker_user), t('Typeof and name property attributes found on @user.', array('@user'=> $user))); // There should be an about attribute on logged in users and no about // attribute for anonymous users. - $tracker_user = $this->xpath("//tr[@about='$url']//td[@rel='sioc:has_creator']/*[@about]"); + $tracker_user = $this->xpath('//tr[@about=:url]//td[@rel="sioc:has_creator"]/*[@about]', array(':url' => $url)); if ($node->uid == 0) { $this->assertTrue(empty($tracker_user), t('No about attribute is present on @user.', array('@user'=> $user))); } @@ -427,14 +449,14 @@ class RdfTrackerAttributesTestCase extends DrupalWebTestCase { } // Tests whether the property has been set for number of comments. - $tracker_replies = $this->xpath("//tr[@about='$url']//td[contains(@property, 'sioc:num_replies') and contains(@content, '0') and @datatype='xsd:integer']"); + $tracker_replies = $this->xpath('//tr[@about=:url]//td[contains(@property, "sioc:num_replies") and contains(@content, "0") and @datatype="xsd:integer"]', array(':url' => $url)); $this->assertTrue($tracker_replies, t('Num replies property and content attributes found on @user content.', array('@user'=> $user))); // Tests that the appropriate RDFa markup to annotate the latest activity // date has been added to the tracker output before comments have been // posted, meaning the latest activity reflects changes to the node itself. $isoDate = date('c', $node->changed); - $tracker_activity = $this->xpath("//tr[@about='$url']//td[contains(@property, 'dc:modified') and contains(@property, 'sioc:last_activity_date') and contains(@datatype, 'xsd:dateTime') and @content='$isoDate']"); + $tracker_activity = $this->xpath('//tr[@about=:url]//td[contains(@property, "dc:modified") and contains(@property, "sioc:last_activity_date") and contains(@datatype, "xsd:dateTime") and @content=:date]', array(':url' => $url, ':date' => $isoDate)); $this->assertTrue(!empty($tracker_activity), t('Latest activity date and changed properties found when there are no comments on @user content. Latest activity date content is correct.', array('@user'=> $user))); // Tests that the appropriate RDFa markup to annotate the latest activity @@ -443,7 +465,7 @@ class RdfTrackerAttributesTestCase extends DrupalWebTestCase { $this->drupalGet('tracker'); // Tests whether the property has been set for number of comments. - $tracker_replies = $this->xpath("//tr[@about='$url']//td[contains(@property, 'sioc:num_replies') and contains(@content, '1') and @datatype='xsd:integer']"); + $tracker_replies = $this->xpath('//tr[@about=:url]//td[contains(@property, "sioc:num_replies") and contains(@content, "1") and @datatype="xsd:integer"]', array(':url' => $url)); $this->assertTrue($tracker_replies, t('Num replies property and content attributes found on @user content.', array('@user'=> $user))); // Need to query database directly to obtain last_activity_date because @@ -453,7 +475,7 @@ class RdfTrackerAttributesTestCase extends DrupalWebTestCase { $expected_last_activity_date = $node->changed; } $isoDate = date('c', $expected_last_activity_date); - $tracker_activity = $this->xpath("//tr[@about='$url']//td[@property='sioc:last_activity_date' and @datatype='xsd:dateTime' and @content='$isoDate']"); + $tracker_activity = $this->xpath('//tr[@about=:url]//td[@property="sioc:last_activity_date" and @datatype="xsd:dateTime" and @content=:date]', array(':url' => $url, ':date' => $isoDate)); $this->assertTrue(!empty($tracker_activity), t('Latest activity date found when there are comments on @user content. Latest activity date content is correct.', array('@user'=> $user))); } } diff --git a/modules/simpletest/drupal_web_test_case.php b/modules/simpletest/drupal_web_test_case.php index 81270b2f9..5d64abb5c 100644 --- a/modules/simpletest/drupal_web_test_case.php +++ b/modules/simpletest/drupal_web_test_case.php @@ -1900,6 +1900,48 @@ class DrupalWebTestCase extends DrupalTestCase { } /** + * Builds an XPath query. + * + * Builds an XPath query by replacing placeholders in the query by the value + * of the arguments. + * + * XPath 1.0 (the version supported by libxml2, the underlying XML library + * used by PHP) doesn't support any form of quotation. This function + * simplifies the building of XPath expression. + * + * @param $xpath + * An XPath query, possibly with placeholders in the form ':name'. + * @param $args + * An array of arguments with keys in the form ':name' matching the + * placeholders in the query. The values may be either strings or numeric + * values. + * @return + * An XPath query with arguments replaced. + */ + protected function buildXPathQuery($xpath, array $args = array()) { + // Replace placeholders. + foreach ($args as $placeholder => $value) { + // XPath 1.0 doesn't support a way to escape single or double quotes in a + // string literal. We split double quotes out of the string, and encode + // them separately. + if (is_string($value)) { + // Explode the text at the quote characters. + $parts = explode('"', $value); + + // Quote the parts. + foreach ($parts as &$part) { + $part = '"' . $part . '"'; + } + + // Return the string. + $value = count($parts) > 1 ? 'concat(' . implode(', \'"\', ', $parts) . ')' : $parts[0]; + } + $xpath = preg_replace('/' . preg_quote($placeholder) . '\b/', $value, $xpath); + } + return $xpath; + } + + /** * Perform an xpath search on the contents of the internal browser. The search * is relative to the root element (HTML tag normally) of the page. * @@ -1910,11 +1952,14 @@ class DrupalWebTestCase extends DrupalTestCase { * format and return values see the SimpleXML documentation, * http://us.php.net/manual/function.simplexml-element-xpath.php. */ - protected function xpath($xpath) { + protected function xpath($xpath, array $arguments = array()) { if ($this->parse()) { + $xpath = $this->buildXPathQuery($xpath, $arguments); return $this->elements->xpath($xpath); } - return FALSE; + else { + return FALSE; + } } /** @@ -1957,7 +2002,7 @@ class DrupalWebTestCase extends DrupalTestCase { * TRUE if the assertion succeeded, FALSE otherwise. */ protected function assertLink($label, $index = 0, $message = '', $group = 'Other') { - $links = $this->xpath('//a[text()="' . $label . '"]'); + $links = $this->xpath('//a[text()=:label]', array(':label' => $label)); $message = ($message ? $message : t('Link with label %label found.', array('%label' => $label))); return $this->assert(isset($links[$index]), $message, $group); } @@ -1977,7 +2022,7 @@ class DrupalWebTestCase extends DrupalTestCase { * TRUE if the assertion succeeded, FALSE otherwise. */ protected function assertNoLink($label, $message = '', $group = 'Other') { - $links = $this->xpath('//a[text()="' . $label . '"]'); + $links = $this->xpath('//a[text()=:label]', array(':label' => $label)); $message = ($message ? $message : t('Link with label %label not found.', array('%label' => $label))); return $this->assert(empty($links), $message, $group); } @@ -1998,7 +2043,7 @@ class DrupalWebTestCase extends DrupalTestCase { * TRUE if the assertion succeeded, FALSE otherwise. */ protected function assertLinkByHref($href, $index = 0, $message = '', $group = 'Other') { - $links = $this->xpath('//a[contains(@href, "' . $href . '")]'); + $links = $this->xpath('//a[contains(@href, :href)]', array(':href' => $href)); $message = ($message ? $message : t('Link containing href %href found.', array('%href' => $href))); return $this->assert(isset($links[$index]), $message, $group); } @@ -2017,7 +2062,7 @@ class DrupalWebTestCase extends DrupalTestCase { * TRUE if the assertion succeeded, FALSE otherwise. */ protected function assertNoLinkByHref($href, $message = '', $group = 'Other') { - $links = $this->xpath('//a[contains(@href, "' . $href . '")]'); + $links = $this->xpath('//a[contains(@href, :href)]', array(':href' => $href)); $message = ($message ? $message : t('No link containing href %href found.', array('%href' => $href))); return $this->assert(empty($links), $message, $group); } @@ -2039,7 +2084,7 @@ class DrupalWebTestCase extends DrupalTestCase { */ protected function clickLink($label, $index = 0) { $url_before = $this->getUrl(); - $urls = $this->xpath('//a[text()="' . $label . '"]'); + $urls = $this->xpath('//a[text()=:label]', array(':label' => $label)); if (isset($urls[$index])) { $url_target = $this->getAbsoluteUrl($urls[$index]['href']); @@ -2657,7 +2702,7 @@ class DrupalWebTestCase extends DrupalTestCase { * TRUE on pass, FALSE on fail. */ protected function assertFieldChecked($id, $message = '') { - $elements = $this->xpath('//input[@id="' . $id . '"]'); + $elements = $this->xpath('//input[@id=:id]', array(':id' => $id)); return $this->assertTrue(isset($elements[0]) && !empty($elements[0]['checked']), $message ? $message : t('Checkbox field @id is checked.', array('@id' => $id)), t('Browser')); } @@ -2672,7 +2717,7 @@ class DrupalWebTestCase extends DrupalTestCase { * TRUE on pass, FALSE on fail. */ protected function assertNoFieldChecked($id, $message = '') { - $elements = $this->xpath('//input[@id="' . $id . '"]'); + $elements = $this->xpath('//input[@id=:id]', array(':id' => $id)); return $this->assertTrue(isset($elements[0]) && empty($elements[0]['checked']), $message ? $message : t('Checkbox field @id is not checked.', array('@id' => $id)), t('Browser')); } @@ -2689,7 +2734,7 @@ class DrupalWebTestCase extends DrupalTestCase { * TRUE on pass, FALSE on fail. */ protected function assertOptionSelected($id, $option, $message = '') { - $elements = $this->xpath('//select[@id="' . $id . '"]//option[@value="' . $option . '"]'); + $elements = $this->xpath('//select[@id=:id]//option[@value=:option]', array(':id' => $id, ':option' => $option)); return $this->assertTrue(isset($elements[0]) && !empty($elements[0]['selected']), $message ? $message : t('Option @option for field @id is selected.', array('@option' => $option, '@id' => $id)), t('Browser')); } @@ -2706,7 +2751,7 @@ class DrupalWebTestCase extends DrupalTestCase { * TRUE on pass, FALSE on fail. */ protected function assertNoOptionSelected($id, $option, $message = '') { - $elements = $this->xpath('//select[@id="' . $id . '"]//option[@value="' . $option . '"]'); + $elements = $this->xpath('//select[@id=:id]//option[@value=:option]', array(':id' => $id, ':option' => $option)); return $this->assertTrue(isset($elements[0]) && empty($elements[0]['selected']), $message ? $message : t('Option @option for field @id is not selected.', array('@option' => $option, '@id' => $id)), t('Browser')); } @@ -2753,7 +2798,8 @@ class DrupalWebTestCase extends DrupalTestCase { * XPath for specified values. */ protected function constructFieldXpath($attribute, $value) { - return '//textarea[@' . $attribute . '="' . $value . '"]|//input[@' . $attribute . '="' . $value . '"]|//select[@' . $attribute . '="' . $value . '"]'; + $xpath = '//textarea[@' . $attribute . '=:value]|//input[@' . $attribute . '=:value]|//select[@' . $attribute . '=:value]'; + return $this->buildXPathQuery($xpath, array(':value' => $value)); } /** diff --git a/modules/simpletest/simpletest.test b/modules/simpletest/simpletest.test index 375dab881..11bf16ef7 100644 --- a/modules/simpletest/simpletest.test +++ b/modules/simpletest/simpletest.test @@ -281,13 +281,13 @@ class SimpleTestFunctionalTest extends DrupalWebTestCase { } /** - * Test internal testing framework URL handling. + * Test internal testing framework browser. */ -class SimpleTestURLTestCase extends DrupalWebTestCase { +class SimpleTestBrowserTestCase extends DrupalWebTestCase { public static function getInfo() { return array( - 'name' => 'SimpleTest URL handling', - 'description' => 'Test the URL handling in the testing framework.', + 'name' => 'SimpleTest browser', + 'description' => 'Test the internal browser of the testing framework.', 'group' => 'SimpleTest', ); } @@ -315,6 +315,28 @@ class SimpleTestURLTestCase extends DrupalWebTestCase { $this->assertEqual($absolute, $this->url, t('Passed and requested URL are equal.')); $this->assertEqual($this->url, $this->getAbsoluteUrl($this->url), t('Requested and returned absolute URL are equal.')); } + + /** + * Tests XPath escaping. + */ + function testXPathEscaping() { + $testpage = <<< EOF +<html> +<body> +<a href="link1">A "weird" link, just to bother the dumb "XPath 1.0"</a> +<a href="link2">A second "even more weird" link, in memory of George O'Malley</a> +</body> +</html> +EOF; + $this->drupalSetContent($testpage); + + // Matches the first link. + $urls = $this->xpath('//a[text()=:text]', array(':text' => 'A "weird" link, just to bother the dumb "XPath 1.0"')); + $this->assertEqual($urls[0]['href'], 'link1', 'Match with quotes.'); + + $urls = $this->xpath('//a[text()=:text]', array(':text' => 'A second "even more weird" link, in memory of George O\'Malley')); + $this->assertEqual($urls[0]['href'], 'link2', 'Match with mixed single and double quotes.'); + } } class SimpleTestMailCaptureTestCase extends DrupalWebTestCase { diff --git a/modules/syslog/syslog.test b/modules/syslog/syslog.test index 6a0dbafd0..4f0950dd9 100644 --- a/modules/syslog/syslog.test +++ b/modules/syslog/syslog.test @@ -29,7 +29,7 @@ class SyslogTestCase extends DrupalWebTestCase { $this->drupalGet('admin/config/development/logging'); if ($this->parse()) { - $field = $this->xpath('//option[@value="' . LOG_LOCAL6 . '"]'); // Should be one field. + $field = $this->xpath('//option[@value=:value]', array(':value' => LOG_LOCAL6)); // Should be one field. $this->assertTrue($field[0]['selected'] == 'selected', t('Facility value saved.')); } } diff --git a/modules/translation/translation.test b/modules/translation/translation.test index 0ef64c275..19b421df8 100644 --- a/modules/translation/translation.test +++ b/modules/translation/translation.test @@ -110,7 +110,7 @@ class TranslationTestCase extends DrupalWebTestCase { $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.')); } } - elseif ($this->xpath('//input[@type=\'checkbox\' and @name=\'enabled[' . $language_code . ']\' and @checked=\'checked\']')) { + elseif ($this->xpath('//input[@type="checkbox" and @name=:name and @checked="checked"]', array(':name' => 'enabled[' . $language_code . ']'))) { // It's installed and enabled. No need to do anything. $this->assertTrue(true, 'Language [' . $language_code . '] already installed and enabled.'); } |