[ Index ]

PHP Cross Reference of Drupal 6 (gatewave)

title

Body

[close]

/sites/all/modules/mollom/tests/ -> mollom.test (source)

   1  <?php
   2  // $Id: mollom.test,v 1.1.2.60 2010/09/15 02:56:56 dries Exp $
   3  
   4  /**
   5   * @file
   6   * Tests for the Mollom module.
   7   */
   8  
   9  /**
  10   * Defines Mollom testing keys.
  11   *
  12   * These keys will only work in test mode, so consult the Mollom API
  13   * documentation for details. Do NOT use PRODUCTION keys for testing!
  14   */
  15  define('MOLLOM_TEST_PUBLIC_KEY', '9cc3d2e43971de758ecddad61a3d12ec');
  16  define('MOLLOM_TEST_PRIVATE_KEY', '603a8d11099f17faaab49139bfc7d00a');
  17  
  18  /**
  19   * Indicates that Mollom testing keys are reseller keys.
  20   *
  21   * If the above keys are reseller keys, make sure to change this value to TRUE.
  22   * If you set this to TRUE and you are testing with non-reseller keys, the
  23   * tests will fail due to unprivileged API access.
  24   */
  25  define('MOLLOM_TEST_RESELLER_KEY', FALSE);
  26  
  27  /**
  28   * Common base test class for Mollom tests.
  29   */
  30  class MollomWebTestCase extends DrupalWebTestCase {
  31    /**
  32     * The Mollom administrator user account.
  33     */
  34    protected $admin_user;
  35  
  36    /**
  37     * A normal web user account.
  38     */
  39    protected $web_user;
  40  
  41    /**
  42     * The text the user should see when they are blocked from submitting a form
  43     * because the Mollom servers are unreachable.
  44     */
  45    protected $fallback_message = 'The spam filter installed on this site is currently unavailable. Per site policy, we are unable to accept new submissions until that problem is resolved. Please try resubmitting the form in a couple of minutes.';
  46  
  47    /**
  48     * The text the user should see if there submission was determinted to be spam.
  49     */
  50    protected $spam_message = 'Your submission has triggered the spam filter and will not be accepted.';
  51  
  52    /**
  53     * The text the user should see if they did not fill out the CAPTCHA correctly.
  54     */
  55    protected $incorrect_message = 'The word verification was not completed correctly. Please complete this new word verification and try again.';
  56  
  57    /**
  58     * The text the user should see if the textual analysis was unsure about the
  59     * content.
  60     */
  61    protected $unsure_message = "To complete this form, please complete the word verification below.";
  62  
  63    /**
  64     * The public key used during testing.
  65     */
  66    protected $public_key = '';
  67  
  68    /**
  69     * The private key used during testing.
  70     */
  71    protected $private_key = '';
  72  
  73    /**
  74     * A boolean that is TRUE if the above keys are for a reseller account.
  75     */
  76    protected $is_reseller = FALSE;
  77  
  78    /**
  79     * Set up an administrative user account and testing keys.
  80     */
  81    function setUp() {
  82      // Re-initialize stored session_id and watchdog messages.
  83      $this->resetSessionID();
  84      $this->messages = array();
  85  
  86      // If not explicitly disabled by a test, setup with Mollom and default admin
  87      // user.
  88      if (empty($this->disableDefaultSetup)) {
  89        // Call parent::setUp() allowing Mollom test cases to pass further modules.
  90        $modules = func_get_args();
  91        $modules[] = 'mollom';
  92        $modules[] = 'dblog';
  93        call_user_func_array(array($this, 'parent::setUp'), $modules);
  94  
  95        $this->admin_user = $this->drupalCreateUser(array(
  96          'administer mollom',
  97          'access administration pages',
  98          'administer content types',
  99          'administer comments',
 100          'administer permissions',
 101          'administer users',
 102        ));
 103      }
 104      else {
 105        $modules = func_get_args();
 106        $modules[] = 'dblog';
 107        call_user_func_array(array($this, 'parent::setUp'), $modules);
 108      }
 109  
 110      // If not explicitly disabled by a test, setup and validate testing keys.
 111      if (empty($this->disableDefaultSetup)) {
 112        $this->setKeys();
 113        $this->assertValidKeys();
 114      }
 115    }
 116  
 117    function tearDown() {
 118      // Capture any (remaining) watchdog messages.
 119      $this->assertMollomWatchdogMessages();
 120      parent::tearDown();
 121    }
 122  
 123    /**
 124     * Assert any watchdog messages based on their severity.
 125     *
 126     * This function can be (repeatedly) invoked to assert new watchdog messages.
 127     * All watchdog messages with a higher severity than WATCHDOG_NOTICE are
 128     * considered as fails.
 129     *
 130     * @param $no_fail_expected
 131     *   (optional) Boolean whether a failing watchdog message is expected.
 132     *   Defaults to TRUE (no fail expected). If FALSE is passed, the logic for
 133     *   assertion messages is flipped.
 134     *
 135     * @todo Add this to D7 core.
 136     */
 137    protected function assertMollomWatchdogMessages($no_fail_expected = TRUE) {
 138      module_load_include('inc', 'dblog', 'dblog.admin');
 139  
 140      $this->messages = array();
 141      $result = db_query("SELECT * FROM {watchdog} WHERE type = 'mollom' ORDER BY timestamp ASC");
 142      while ($row = db_fetch_object($result)) {
 143        if ($no_fail_expected ? $row->severity >= WATCHDOG_NOTICE : $row->severity < WATCHDOG_NOTICE) {
 144          $this->pass(_dblog_format_message($row), t('Watchdog'));
 145        }
 146        else {
 147          $this->fail(_dblog_format_message($row), t('Watchdog'));
 148        }
 149        $this->messages[$row->wid] = $row;
 150      }
 151      // Delete processed watchdog messages.
 152      if (!empty($this->messages)) {
 153        $seen_ids = array_keys($this->messages);
 154        db_query("DELETE FROM {watchdog} WHERE wid IN (" . db_placeholders($seen_ids) . ")", $seen_ids);
 155      }
 156    }
 157  
 158    /**
 159     * Assert that the Mollom session id remains the same.
 160     *
 161     * The Mollom session id is only known to one server. If we are communicating
 162     * with a different Mollom server (due to a refreshed server list or being
 163     * redirected), then we will get a new session_id.
 164     *
 165     * @param $session_id
 166     *   A Mollom session_id of the last request, as contained in the XML-RPC
 167     *   response.
 168     */
 169    protected function assertSessionID($session_id) {
 170      // Check whether watchdog messages indicate a refresh or redirect.
 171      foreach ($this->messages as $message) {
 172        if ($message->message == 'Refreshed servers: %servers' || $message->message == 'Server %server redirected to: %next.') {
 173          $this->resetSessionID();
 174        }
 175      }
 176  
 177      if (!isset($this->session_id)) {
 178        // Use assertTrue() instead of pass(), to test !empty().
 179        $this->assertTrue($session_id, t('New session_id: %session_id', array('%session_id' => $session_id)));
 180        $this->session_id = $session_id;
 181      }
 182      else {
 183        $this->assertSame('session_id', $session_id, $this->session_id);
 184      }
 185      return $this->session_id;
 186    }
 187  
 188    /**
 189     * Reset the statically cached Mollom session id.
 190     */
 191    protected function resetSessionID() {
 192      $this->session_id = NULL;
 193    }
 194  
 195    /**
 196     * Assert a Mollom session id in a form.
 197     *
 198     * This is a wrapper around assertSessionID() allows to assert that a proper
 199     * Mollom session id is found in the form contained in the internal browser
 200     * output. The usual flow is:
 201     * - drupalGet() or drupalPost() requests or submits a form.
 202     * - drupalGet() and drupalPost() invoke assertMollomWatchdogMessages()
 203     *   internally, which records all new watchdog messages.
 204     * - This function, assertSessionIDInForm(), is invoked to assert that there
 205     *   is a Mollom session id and, depending on the recorded watchdog messages,
 206     *   that it either equals the last known session id or the new session id is
 207     *   used for future comparisons in case of a server redirect.
 208     * - The return value of this function is used to invoke assertMollomData(),
 209     *   to verify that the proper session id was stored in the database.
 210     */
 211    protected function assertSessionIDInForm() {
 212      // The session id found in the form element value is prefixed with the UNIX
 213      // timestamp denoting the time it was generated/output. The form element
 214      // #process callback mollom_process_mollom_session_id() uses this timestamp
 215      // to additionally validate its age.
 216      list($timestamp, $session_id) = explode('-', $this->getFieldValueByName('mollom[session_id]'));
 217      return $this->assertSessionID($session_id);
 218    }
 219  
 220    /**
 221     * Assign the Mollom API keys to internal variables and reset the server list.
 222     *
 223     * @param $public
 224     *   The public Mollom API key.
 225     * @param $private
 226     *   The private Mollom API key.
 227     * @param $reseller
 228     *   A boolean that is TRUE if the keys are for a reseller account, or FALSE
 229     *   otherwise.
 230     */
 231    protected function setKeys($public = MOLLOM_TEST_PUBLIC_KEY, $private = MOLLOM_TEST_PRIVATE_KEY, $reseller = MOLLOM_TEST_RESELLER_KEY) {
 232      // Save internal properties.
 233      $this->public_key = $public;
 234      $this->private_key = $private;
 235      $this->is_reseller = $reseller;
 236  
 237      // Set the module key settings.
 238      variable_set('mollom_public_key', $public);
 239      variable_set('mollom_private_key', $private);
 240  
 241      // Enable testing mode.
 242      variable_set('mollom_testing_mode', 1);
 243  
 244      // Delete any previously set Mollom servers to make sure we are using
 245      // the default ones.
 246      variable_del('mollom_servers');
 247    }
 248  
 249    /**
 250     * Call the mollom.verifyKey function directly and check that the current
 251     * keys are valid.
 252     */
 253    protected function assertValidKeys() {
 254      $status = _mollom_status(TRUE);
 255      $this->assertMollomWatchdogMessages();
 256      $this->assertIdentical($status, TRUE, t('Mollom servers can be contacted and testing API keys are valid.'));
 257    }
 258  
 259    /**
 260     * Configure Mollom protection for a given form.
 261     *
 262     * @param $form_id
 263     *   The form id to configure.
 264     * @param $mode
 265     *   The Mollom protection mode for the form.
 266     * @param $fields
 267     *   (optional) A list of form elements to enable for text analysis. If
 268     *   omitted and the form registers individual elements, all fields are
 269     *   enabled by default.
 270     * @param $edit
 271     *   (optional) An array of POST data to pass through to drupalPost() when
 272     *   configuring the form's protection.
 273     */
 274    protected function setProtection($form_id, $mode = MOLLOM_MODE_ANALYSIS, $fields = NULL, $edit = array()) {
 275      // Always start from overview page, also to make debugging easier.
 276      $this->drupalGet('admin/settings/mollom');
 277      // Determine whether the form is already protected.
 278      $exists = db_result(db_query_range("SELECT 1 FROM {mollom_form} WHERE form_id = '%s'", $form_id, 0, 1));
 279      // Add a new form.
 280      if (!$exists) {
 281        $this->clickLink(t('Add form'));
 282        $add_form_edit = array(
 283          'mollom[form_id]' => $form_id,
 284        );
 285        $this->drupalPost(NULL, $add_form_edit, t('Next'));
 286      }
 287      // Edit an existing form.
 288      else {
 289        $this->drupalGet('admin/settings/mollom/manage/' . $form_id);
 290      }
 291  
 292      $edit += array(
 293        'mollom[mode]' => $mode,
 294      );
 295  
 296      // Process the enabled fields.
 297      $form_list = mollom_form_list();
 298      $form_info = mollom_form_info($form_id, $form_list[$form_id]['module']);
 299      foreach (array_keys($form_info['elements']) as $field) {
 300        if (!isset($fields) || in_array($field, $fields)) {
 301          // If the user specified all fields by default or to include this
 302          // field, set its checkbox value to TRUE.
 303          $edit['mollom[enabled_fields][' . rawurlencode($field) . ']'] = TRUE;
 304        }
 305        else {
 306          // Otherwise set the field's checkbox value to FALSE.
 307          $edit['mollom[enabled_fields][' . rawurlencode($field) . ']'] = FALSE;
 308        }
 309      }
 310      $this->drupalPost(NULL, $edit, t('Save'));
 311      if (!$exists) {
 312        $this->assertText(t('The form protection has been added.'));
 313      }
 314      else {
 315        $this->assertText(t('The form protection has been updated.'));
 316      }
 317    }
 318  
 319    /**
 320     * Remove Mollom protection for a given form.
 321     *
 322     * @param $form_id
 323     *   The form id to configure.
 324     */
 325    protected function delProtection($form_id) {
 326      // Determine whether the form is protected.
 327      $exists = db_result(db_query_range("SELECT 1 FROM {mollom_form} WHERE form_id = '%s'", $form_id, 0, 1));
 328      if ($exists) {
 329        $this->drupalGet('admin/settings/mollom/unprotect/' . $form_id);
 330        $this->assertText(t('Mollom will no longer protect this form from spam.'), t('Unprotect confirmation form found.'));
 331        $this->drupalPost(NULL, array(), t('Confirm'));
 332      }
 333    }
 334  
 335    /**
 336     * Assert that Mollom session data was stored for a submission.
 337     *
 338     * @param $entity
 339     *   The entity type to search for in {mollom}.
 340     * @param $id
 341     *   The entity id to search for in {mollom}.
 342     * @param $session_id
 343     *   (optional) The Mollom session id to assert additionally.
 344     */
 345    protected function assertMollomData($entity, $id, $session_id = NULL) {
 346      $data = mollom_data_load($entity, $id);
 347      $this->assertTrue($data->session, t('Mollom session data for %entity @id exists: <pre>@data</pre>', array('%entity' => $entity, '@id' => $id, '@data' => var_export($data, TRUE))));
 348      if (isset($session_id)) {
 349        $this->assertSame(t('Stored session id'), $data->session, $session_id);
 350      }
 351      return $data;
 352    }
 353  
 354    /**
 355     * Assert that no Mollom session data exists for a certain entity.
 356     */
 357    protected function assertNoMollomData($entity, $id) {
 358      $data = mollom_data_load($entity, $id);
 359      $this->assertFalse($data, t('No Mollom session data exists for %entity @id.', array('%entity' => $entity, '@id' => $id)));
 360    }
 361  
 362    /**
 363     * Assert that the CAPTCHA field is found on the current page.
 364     */
 365    protected function assertCaptchaField() {
 366      $this->assertFieldByXPath('//input[@type="text"][@name="mollom[captcha]"]', '', 'CAPTCHA field found.');
 367      $image = $this->xpath('//img[@alt="' . t('Type the characters you see in this picture.') . '"]');
 368      $this->assert(!empty($image), 'CAPTCHA image found.');
 369    }
 370  
 371    /**
 372     * Assert that the CAPTCHA field is not found on the current page.
 373     */
 374    protected function assertNoCaptchaField() {
 375      $this->assertNoFieldByXPath('//input[@type="text"][@name="mollom[captcha]"]', '', 'CAPTCHA field not found.');
 376      $image = $this->xpath('//img[@alt="' . t('Type the characters you see in this picture.') . '"]');
 377      $this->assert(empty($image), 'CAPTCHA image not found.');
 378    }
 379  
 380    /**
 381     * Assert that the privacy policy link is found on the current page.
 382     */
 383    protected function assertPrivacyLink() {
 384      $elements = $this->xpath('//div[contains(@class, "mollom-privacy")]');
 385      $this->assertTrue($elements, t('Privacy policy container found.'));
 386    }
 387  
 388    /**
 389     * Assert that the privacy policy link is not found on the current page.
 390     */
 391    protected function assertNoPrivacyLink() {
 392      $elements = $this->xpath('//div[contains(@class, "mollom-privacy")]');
 393      $this->assertFalse($elements, t('Privacy policy container not found.'));
 394    }
 395  
 396    /**
 397     * Test submitting a form with a correct CAPTCHA value.
 398     *
 399     * @param $url
 400     *   The URL of the form, or NULL to use the current page.
 401     * @param $edit
 402     *   An array of form values used in drupalPost().
 403     * @param $button
 404     *   The text of the form button to click in drupalPost().
 405     * @param $success_message
 406     *   An optional message to test does appear after submission.
 407     */
 408    protected function postCorrectCaptcha($url, array $edit = array(), $button, $success_message = '') {
 409      $edit['mollom[captcha]'] = 'correct';
 410      $this->drupalPost($url, $edit, $button);
 411      $this->assertNoCaptchaField();
 412      $this->assertNoText($this->incorrect_message);
 413      if ($success_message) {
 414        $this->assertText($success_message);
 415      }
 416    }
 417  
 418    /**
 419     * Test submitting a form with an incorrect CAPTCHA value.
 420     *
 421     * @param $url
 422     *   The URL of the form, or NULL to use the current page.
 423     * @param $edit
 424     *   An array of form values used in drupalPost().
 425     * @param $button
 426     *   The text of the form button to click in drupalPost().
 427     * @param $success_message
 428     *   An optional message to test does not appear after submission.
 429     */
 430    protected function postIncorrectCaptcha($url, array $edit = array(), $button, $success_message = '') {
 431      $edit['mollom[captcha]'] = 'incorrect';
 432      $before_url = $this->getUrl();
 433      $this->drupalPost($url, $edit, $button);
 434      if ($this->getUrl() == $before_url) {
 435        $this->assertCaptchaField();
 436      }
 437      $this->assertText($this->incorrect_message);
 438      if ($success_message) {
 439        $this->assertNoText($success_message);
 440      }
 441    }
 442  
 443    /**
 444     * Test submitting a form with 'spam' values.
 445     *
 446     * @param $url
 447     *   The URL of the form, or NULL to use the current page.
 448     * @param $spam_fields
 449     *   An array of form field names to inject spam content into.
 450     * @param $edit
 451     *   An array of non-spam form values used in drupalPost().
 452     * @param $button
 453     *   The text of the form button to click in drupalPost().
 454     * @param $success_message
 455     *   An optional message to test does not appear after submission.
 456     */
 457    protected function assertSpamSubmit($url, array $spam_fields, array $edit = array(), $button, $success_message = '') {
 458      $edit += array_fill_keys($spam_fields, 'spam');
 459      $this->drupalPost($url, $edit, $button);
 460      $this->assertNoCaptchaField($url);
 461      $this->assertText($this->spam_message);
 462      if ($success_message) {
 463        $this->assertNoText($success_message);
 464      }
 465    }
 466  
 467    /**
 468     * Test submitting a form with 'ham' values.
 469     *
 470     * @param $url
 471     *   The URL of the form, or NULL to use the current page.
 472     * @param $ham_fields
 473     *   An array of form field names to inject ham content into.
 474     * @param $edit
 475     *   An array of non-spam form values used in drupalPost().
 476     * @param $button
 477     *   The text of the form button to click in drupalPost().
 478     * @param $success_message
 479     *   An optional message to test does appear after submission.
 480     */
 481    protected function assertHamSubmit($url, array $ham_fields, array $edit = array(), $button, $success_message = '') {
 482      $edit += array_fill_keys($ham_fields, 'ham');
 483      $this->drupalPost($url, $edit, $button);
 484      $this->assertNoCaptchaField($url);
 485      $this->assertNoText($this->spam_message);
 486      if ($success_message) {
 487        $this->assertText($success_message);
 488      }
 489    }
 490  
 491    /**
 492     * Test submitting a form with unsure values and resulting CAPTCHA submissions.
 493     *
 494     * @param $url
 495     *   The URL of the form, or NULL to use the current page.
 496     * @param $unsure_fields
 497     *   An array of form field names to inject unsure content into.
 498     * @param $edit
 499     *   An array of non-spam form values used in drupalPost().
 500     * @param $button
 501     *   The text of the form button to click in drupalPost().
 502     * @param $success_message
 503     *   An optional message to test does appear after sucessful form and CAPTCHA
 504     *   submission.
 505     */
 506    protected function assertUnsureSubmit($url, array $unsure_fields, array $edit = array(), $button, $success_message = '') {
 507      $edit += array_fill_keys($unsure_fields, 'unsure');
 508      $before_url = $this->getUrl();
 509      $this->drupalPost($url, $edit, $button);
 510      if ($this->getUrl() == $before_url) {
 511        $this->assertCaptchaField();
 512      }
 513      $this->assertText($this->unsure_message);
 514      if ($success_message) {
 515        $this->assertNoText($success_message);
 516      }
 517  
 518      $this->postIncorrectCaptcha(NULL, $edit, $button, $success_message);
 519      $this->postCorrectCaptcha(NULL, $edit, $button, $success_message);
 520    }
 521  
 522    /**
 523     * Retrieve a field value by ID.
 524     */
 525    protected function getFieldValueByID($id) {
 526      $fields = $this->xpath($this->constructFieldXpath('id', $id));
 527      return (string) $fields[0]['value'];
 528    }
 529  
 530    /**
 531     * Retrieve a field value by name.
 532     */
 533    protected function getFieldValueByName($name) {
 534      $fields = $this->xpath($this->constructFieldXpath('name', $name));
 535      return (string) $fields[0]['value'];
 536    }
 537  
 538    /**
 539     * Retrieve submitted XML-RPC values from testing server implementation.
 540     *
 541     * @param $method
 542     *   (optional) The XML-RPC method name to retrieve submitted values from.
 543     *   Defaults to 'mollom.checkContent'.
 544     *
 545     * @see MollomWebTestCase::resetServerRecords()
 546     * @see mollom_test_xmlrpc()
 547     */
 548    protected function getServerRecord($method = 'mollom.checkContent') {
 549      // Map the XML-RPC method name to the corresponding function callback name.
 550      drupal_load('module', 'mollom_test');
 551      $method_function_map = mollom_test_xmlrpc();
 552      $function = $method_function_map[$method];
 553  
 554      // Retrieve last recorded values.
 555      $storage = variable_get($function, array());
 556      $return = array_shift($storage);
 557      variable_set($function, $storage);
 558  
 559      return $return;
 560    }
 561  
 562    /**
 563     * Resets recorded XML-RPC values.
 564     *
 565     * @param $method
 566     *   (optional) The XML-RPC method name to reset records of. Defaults to
 567     *   'mollom.checkContent'.
 568     *
 569     * @see MollomWebTestCase::getServerRecord()
 570     * @see mollom_test_xmlrpc()
 571     */
 572    protected function resetServerRecords($method = 'mollom.checkContent') {
 573      // Map the XML-RPC method name to the corresponding function callback name.
 574      drupal_load('module', 'mollom_test');
 575      $method_function_map = mollom_test_xmlrpc();
 576      $function = $method_function_map[$method];
 577  
 578      // Delete the variable.
 579      variable_del($function);
 580    }
 581  
 582    /**
 583     * Wraps drupalGet() for additional watchdog message assertion.
 584     *
 585     * @param $options
 586     *   In addition to regular $options that are passed to url():
 587     *   - watchdog: (optional) Boolean whether to assert that only non-severe
 588     *     watchdog messages have been logged. Defaults to TRUE. Use FALSE to
 589     *     negate the watchdog message severity assertion.
 590     *
 591     * @see DrupalWebTestCase->drupalGet()
 592     * @see MollomWebTestCase->assertMollomWatchdogMessages()
 593     * @see MollomWebTestCase->assertSessionID()
 594     */
 595    protected function drupalGet($path, array $options = array(), array $headers = array()) {
 596      $output = parent::drupalGet($path, $options, $headers);
 597      $options += array('watchdog' => TRUE);
 598      $this->assertMollomWatchdogMessages($options['watchdog']);
 599      return $output;
 600    }
 601  
 602    /**
 603     * Wraps drupalPost() for additional watchdog message assertion.
 604     *
 605     * @param $options
 606     *   In addition to regular $options that are passed to url():
 607     *   - watchdog: (optional) Boolean whether to assert that only non-severe
 608     *     watchdog messages have been logged. Defaults to TRUE. Use FALSE to
 609     *     negate the watchdog message severity assertion.
 610     *
 611     * @see MollomWebTestCase->assertMollomWatchdogMessages()
 612     * @see MollomWebTestCase->assertSessionID()
 613     * @see DrupalWebTestCase->drupalPost()
 614     */
 615    protected function drupalPost($path, $edit, $submit, array $options = array(), array $headers = array()) {
 616      $output = parent::drupalPost($path, $edit, $submit, $options, $headers);
 617      $options += array('watchdog' => TRUE);
 618      $this->assertMollomWatchdogMessages($options['watchdog']);
 619      return $output;
 620    }
 621  
 622    /**
 623     * Asserts that two values belonging to the same variable are equal.
 624     *
 625     * Checks to see whether two values, which belong to the same variable name or
 626     * identifier, are equal and logs a readable assertion message.
 627     *
 628     * @param $name
 629     *   A name or identifier to use in the assertion message.
 630     * @param $first
 631     *   The first value to check.
 632     * @param $second
 633     *   The second value to check.
 634     *
 635     * @return
 636     *   TRUE if the assertion succeeded, FALSE otherwise.
 637     *
 638     * @see MollomWebTestCase::assertNotSame()
 639     *
 640     * @todo D8: Move into core. This improved assertEqual() did not get into D7,
 641     *   since the function signature differs and it's plenty of work to manually
 642     *   update all assertEqual() invocations throughout all tests.
 643     */
 644    protected function assertSame($name, $first, $second) {
 645      $message = t("@name: @first is equal to @second.", array(
 646        '@name' => $name,
 647        '@first' => var_export($first, TRUE),
 648        '@second' => var_export($second, TRUE),
 649      ));
 650      $this->assertEqual($first, $second, $message);
 651    }
 652  
 653    /**
 654     * Asserts that two values belonging to the same variable are not equal.
 655     *
 656     * Checks to see whether two values, which belong to the same variable name or
 657     * identifier, are not equal and logs a readable assertion message.
 658     *
 659     * @param $name
 660     *   A name or identifier to use in the assertion message.
 661     * @param $first
 662     *   The first value to check.
 663     * @param $second
 664     *   The second value to check.
 665     *
 666     * @return
 667     *   TRUE if the assertion succeeded, FALSE otherwise.
 668     *
 669     * @see MollomWebTestCase::assertSame()
 670     */
 671    protected function assertNotSame($name, $first, $second) {
 672      $message = t("@name: '@first' is not equal to '@second'.", array(
 673        '@name' => $name,
 674        '@first' => var_export($first, TRUE),
 675        '@second' => var_export($second, TRUE),
 676      ));
 677      $this->assertNotEqual($first, $second, $message);
 678    }
 679  }
 680  
 681  /**
 682   * Tests module installation and global status handling.
 683   */
 684  class MollomInstallationTestCase extends MollomWebTestCase {
 685    public static function getInfo() {
 686      return array(
 687        'name' => 'Installation and key handling',
 688        'description' => 'Tests module installation and key error handling.',
 689        'group' => 'Mollom',
 690      );
 691    }
 692  
 693    function setUp() {
 694      // Re-initialize stored session_id and watchdog messages.
 695      $this->resetSessionID();
 696      $this->messages = array();
 697  
 698      $this->disableDefaultSetup = TRUE;
 699      parent::setUp('comment');
 700  
 701      $this->admin_user = $this->drupalCreateUser(array(
 702        'access administration pages',
 703        'administer site configuration',
 704        'administer permissions',
 705      ));
 706      $this->web_user = $this->drupalCreateUser();
 707    }
 708  
 709    /**
 710     * Tests status handling after installation.
 711     *
 712     * We walk through a regular installation of the Mollom module instead of using
 713     * setUp() to ensure that everything works as expected.
 714     *
 715     * Note: Partial error messages tested here; hence, no t().
 716     */
 717    function testInstallationProcess() {
 718      $admin_message = t('Visit the <a href="@settings-url">Mollom settings page</a> to configure your keys.', array(
 719        '@settings-url' => url('admin/settings/mollom/settings'),
 720      ));
 721      $this->drupalLogin($this->admin_user);
 722  
 723      // Ensure there is no requirements error by default.
 724      $this->drupalGet('admin/reports/status');
 725      $this->clickLink('run cron manually');
 726  
 727      // Install the Mollom module.
 728      $this->drupalPost('admin/build/modules', array('status[mollom]' => TRUE), t('Save configuration'));
 729      $this->assertRaw(t('The Mollom API keys are not configured yet. !admin-message', array(
 730        '!admin-message' => $admin_message,
 731      )), t('Post installation warning found.'));
 732  
 733      // Verify that forms can be submitted without valid Mollom module configuration.
 734      $node = $this->drupalCreateNode(array('type' => 'story', 'promoted' => TRUE));
 735      $this->drupalLogin($this->web_user);
 736      $this->drupalGet('comment/reply/' . $node->nid);
 737      $edit = array(
 738        'comment' => 'spam',
 739      );
 740      $this->drupalPost(NULL, $edit, t('Preview'));
 741      $this->drupalPost(NULL, array(), t('Save'));
 742      $this->assertRaw('<p>' . $edit['comment'] . '</p>', t('Comment found.'));
 743  
 744      // Assign the 'administer mollom' permission and log in a user.
 745      $this->drupalLogin($this->admin_user);
 746      $edit = array(
 747        DRUPAL_AUTHENTICATED_RID . '[administer mollom]' => TRUE,
 748      );
 749      $this->drupalPost('admin/user/permissions', $edit, t('Save permissions'));
 750  
 751      // Verify presence of 'empty keys' error message.
 752      $this->drupalGet('admin/settings/mollom');
 753      $this->assertText('The Mollom API keys are not configured yet.');
 754      $this->assertNoText('The configured Mollom API keys are invalid.');
 755  
 756      // Verify requirements error about missing API keys.
 757      $this->drupalGet('admin/reports/status');
 758      $this->assertRaw(t('The Mollom API keys are not configured yet. !admin-message', array(
 759        '!admin-message' => $admin_message,
 760      )), t('Requirements error found.'));
 761  
 762      // Configure invalid keys.
 763      $edit = array(
 764        'mollom_public_key' => 'foo',
 765        'mollom_private_key' => 'bar',
 766      );
 767      $this->drupalPost('admin/settings/mollom/settings', $edit, t('Save configuration'), array('watchdog' => FALSE));
 768      $this->assertText(t('The configuration options have been saved.'));
 769      $this->assertNoText($this->fallback_message, t('Fallback message not found.'));
 770  
 771      // Verify presence of 'incorrect keys' error message.
 772      $this->assertText('The configured Mollom API keys are invalid.');
 773      $this->assertNoText('The Mollom API keys are not configured yet.');
 774      $this->assertNoText(t('The Mollom servers could not be contacted. Please make sure that your web server can make outgoing HTTP requests.'));
 775  
 776      // Verify requirements error about invalid API keys.
 777      $this->drupalGet('admin/reports/status', array('watchdog' => FALSE));
 778      $this->assertText('The configured Mollom API keys are invalid.');
 779  
 780      // Ensure unreachable servers.
 781      variable_set('mollom_servers', array('http://fake-host'));
 782  
 783      // Verify presence of 'network error' message.
 784      $this->drupalGet('admin/settings/mollom/settings', array('watchdog' => FALSE));
 785      $this->assertText(t('The Mollom servers could not be contacted. Please make sure that your web server can make outgoing HTTP requests.'));
 786  
 787      // Ensure unreachable servers.
 788      variable_set('mollom_servers', array('http://fake-host'));
 789  
 790      // Verify requirements error about network error.
 791      $this->drupalGet('admin/reports/status', array('watchdog' => FALSE));
 792      $this->assertText(t('The Mollom servers could not be contacted. Please make sure that your web server can make outgoing HTTP requests.'));
 793      $this->assertNoText($this->fallback_message, t('Fallback message not found.'));
 794  
 795      // Verify that valid keys work.
 796      $this->drupalGet('admin/settings/mollom/settings', array('watchdog' => FALSE));
 797      $edit = array(
 798        'mollom_public_key' => MOLLOM_TEST_PUBLIC_KEY,
 799        'mollom_private_key' => MOLLOM_TEST_PRIVATE_KEY,
 800        'mollom_testing_mode' => 1,
 801      );
 802      $this->drupalPost(NULL, $edit, t('Save configuration'));
 803      $this->assertText(t('The configuration options have been saved.'));
 804      $this->assertText('We are now blocking spam.');
 805      $this->assertNoText('The Mollom API keys are not configured yet.');
 806      $this->assertNoText('The configured Mollom API keys are invalid.');
 807  
 808      // Verify presence of testing mode warning.
 809      $this->drupalGet('admin/settings/mollom');
 810      $this->assertText('Mollom testing mode is still enabled.');
 811    }
 812  }
 813  
 814  /**
 815   * Tests low-level XML-RPC communication with Mollom servers.
 816   */
 817  class MollomResponseTestCase extends MollomWebTestCase {
 818    public static function getInfo() {
 819      return array(
 820        'name' => 'Server responses',
 821        'description' => 'Tests that Mollom server responses match expectations.',
 822        'group' => 'Mollom',
 823      );
 824    }
 825  
 826    /**
 827     * Tests mollom.checkContent().
 828     */
 829    function testCheckContent() {
 830      $data = array(
 831        'author_name' => $this->admin_user->name,
 832        'author_mail' => $this->admin_user->mail,
 833        'author_id' => $this->admin_user->uid,
 834        'author_ip' => ip_address(),
 835      );
 836  
 837      // Ensure proper response for 'ham' submissions.
 838      // By default (i.e., omitting 'checks') we expect spam and quality checking
 839      // only.
 840      $data['post_body'] = 'ham';
 841      $result = mollom('mollom.checkContent', $data);
 842      $this->assertMollomWatchdogMessages();
 843      $this->assertSame('spam', $result['spam'], MOLLOM_ANALYSIS_HAM);
 844      $this->assertSame('quality', $result['quality'], 1);
 845      $this->assertTrue(!isset($result['profanity']), 'profanity not returned.');
 846      $session_id = $this->assertSessionID($result['session_id']);
 847  
 848      // Ensure proper response for 'spam' submissions, re-using session_id.
 849      $data['post_body'] = 'spam';
 850      $data['session_id'] = $session_id;
 851      $result = mollom('mollom.checkContent', $data);
 852      $this->assertMollomWatchdogMessages();
 853      $this->assertSame('spam', $result['spam'], MOLLOM_ANALYSIS_SPAM);
 854      $this->assertSame('quality', $result['quality'], 0);
 855      $this->assertTrue(!isset($result['profanity']), 'profanity not returned.');
 856      $session_id = $this->assertSessionID($result['session_id']);
 857  
 858      // Ensure proper response for 'unsure' submissions, re-using session_id.
 859      $data['post_body'] = 'unsure';
 860      $data['session_id'] = $session_id;
 861      $result = mollom('mollom.checkContent', $data);
 862      $this->assertMollomWatchdogMessages();
 863      $this->assertSame('spam', $result['spam'], MOLLOM_ANALYSIS_UNSURE);
 864      $this->assertSame('quality', $result['quality'], 0.5);
 865      $this->assertTrue(!isset($result['profanity']), 'profanity not returned.');
 866      $session_id = $this->assertSessionID($result['session_id']);
 867  
 868      // Additionally enable profanity checking.
 869      $data['post_body'] = 'spam profanity';
 870      $data['checks'] = 'spam,quality,profanity';
 871      $data['session_id'] = $session_id;
 872      $result = mollom('mollom.checkContent', $data);
 873      $this->assertMollomWatchdogMessages();
 874      $this->assertSame('spam', $result['spam'], MOLLOM_ANALYSIS_SPAM);
 875      $this->assertSame('quality', $result['quality'], 0);
 876      $this->assertSame('profanity', $result['profanity'], 1);
 877      $session_id = $this->assertSessionID($result['session_id']);
 878  
 879      // Change the string to contain profanity only.
 880      $data['post_body'] = 'profanity';
 881      $data['checks'] = 'spam,quality,profanity';
 882      $data['session_id'] = $session_id;
 883      $result = mollom('mollom.checkContent', $data);
 884      $this->assertMollomWatchdogMessages();
 885      $this->assertSame('spam', $result['spam'], MOLLOM_ANALYSIS_UNSURE);
 886      $this->assertSame('quality', $result['quality'], 0);
 887      $this->assertSame('profanity', $result['profanity'], 1);
 888      $session_id = $this->assertSessionID($result['session_id']);
 889  
 890      // Disable spam checking, only do profanity checking.
 891      $data['post_body'] = 'spam profanity';
 892      $data['checks'] = 'profanity';
 893      $data['session_id'] = $session_id;
 894      $result = mollom('mollom.checkContent', $data);
 895      $this->assertMollomWatchdogMessages();
 896      $this->assertTrue(!isset($result['spam']), 'spam not returned.');
 897      $this->assertTrue(!isset($result['quality']), 'quality not returned.');
 898      $this->assertSame('profanity', $result['profanity'], 1);
 899      $session_id = $this->assertSessionID($result['session_id']);
 900  
 901      // Pass arbitrary string to profanity checking.
 902      $data['post_body'] = $this->randomString(12);
 903      $data['session_id'] = $session_id;
 904      $result = mollom('mollom.checkContent', $data);
 905      $this->assertMollomWatchdogMessages();
 906      $this->assertTrue(!isset($result['spam']), 'spam not returned.');
 907      $this->assertTrue(!isset($result['quality']), 'quality not returned.');
 908      $this->assertSame('profanity', $result['profanity'], 0);
 909      $session_id = $this->assertSessionID($result['session_id']);
 910    }
 911  
 912    /**
 913     * Tests results of mollom.checkContent() across requests for a single session.
 914     */
 915    function testCheckContentSession() {
 916      $data = array(
 917        'author_name' => $this->admin_user->name,
 918        'author_mail' => $this->admin_user->mail,
 919        'author_id' => $this->admin_user->uid,
 920        'author_ip' => ip_address(),
 921      );
 922  
 923      // Sequence: Post unsure spam, correct CAPTCHA, change post into spam,
 924      // expect it to be ham (due to correct CAPTCHA).
 925      $data['post_body'] = 'unsure';
 926      $result = mollom('mollom.checkContent', $data);
 927      $this->assertMollomWatchdogMessages();
 928      $this->assertSame('spam', $result['spam'], MOLLOM_ANALYSIS_UNSURE);
 929      $data['session_id'] = $this->assertSessionID($result['session_id']);
 930  
 931      $captcha_data = array(
 932        'session_id' => $data['session_id'],
 933        'author_ip' => $data['author_ip'],
 934      );
 935      $result = mollom('mollom.getImageCaptcha', $captcha_data);
 936      $this->assertMollomWatchdogMessages();
 937      $data['session_id'] = $this->assertSessionID($result['session_id']);
 938  
 939      $captcha_data = array(
 940        'session_id' => $data['session_id'],
 941        'author_ip' => $data['author_ip'],
 942        'author_id' => $data['author_id'],
 943        'captcha_result' => 'correct',
 944      );
 945      $result = mollom('mollom.checkCaptcha', $captcha_data);
 946      $this->assertMollomWatchdogMessages();
 947      $this->assertIdentical($result, TRUE, t('CAPTCHA response was correct.'));
 948  
 949      $data['post_body'] = 'spam';
 950      $result = mollom('mollom.checkContent', $data);
 951      $this->assertMollomWatchdogMessages();
 952      $this->assertSame('spam', $result['spam'], MOLLOM_ANALYSIS_HAM);
 953      $data['session_id'] = $this->assertSessionID($result['session_id']);
 954    }
 955  
 956    /**
 957     * Tests mollom.getImageCaptcha().
 958     */
 959    function testGetImageCaptcha() {
 960      // Ensure we get no SSL URL by default.
 961      $data = array(
 962        'author_ip' => ip_address(),
 963      );
 964      $result = mollom('mollom.getImageCaptcha', $data);
 965      $this->assertMollomWatchdogMessages();
 966      $this->assertTrue(strpos($result['url'], 'http://') === 0, t('CAPTCHA URL uses HTTP protocol.'));
 967  
 968      // Ensure we get a SSL URL when passing the 'ssl' parameter.
 969      $data = array(
 970        'author_ip' => ip_address(),
 971        'ssl' => TRUE,
 972      );
 973      $result = mollom('mollom.getImageCaptcha', $data);
 974      $this->assertMollomWatchdogMessages();
 975      $this->assertTrue(strpos($result['url'], 'https://') === 0, t('CAPTCHA URL uses HTTPS protocol.'));
 976    }
 977  
 978    /**
 979     * Tests mollom.checkCaptcha().
 980     */
 981    function testCheckCaptcha() {
 982      // Ensure we can send an 'author_id'.
 983      // Verifying no severe watchdog messages is sufficient, as unsupported
 984      // parameters would trigger a XML-RPC error.
 985      $uid = rand();
 986      $data = array(
 987        'author_ip' => ip_address(),
 988        'author_id' => $uid,
 989      );
 990      $result = mollom('mollom.getImageCaptcha', $data);
 991      $this->assertMollomWatchdogMessages();
 992  
 993      $data += array(
 994        'session_id' => $result['session_id'],
 995        'captcha_result' => 'correct',
 996      );
 997      $result = mollom('mollom.checkCaptcha', $data);
 998      $this->assertMollomWatchdogMessages();
 999    }
1000  }
1001  
1002  class MollomAccessTestCase extends MollomWebTestCase {
1003    public static function getInfo() {
1004      return array(
1005        'name' => 'Access checking',
1006        'description' => 'Confirm that there is a working key pair and that this status is correctly indicated on the module settings page for appropriate users.',
1007        'group' => 'Mollom',
1008      );
1009    }
1010  
1011    /**
1012     * Configure an invalid key pair and ensure error message.
1013     */
1014    function testKeyPairs() {
1015      // No error message or watchdog messages should be thrown with default
1016      // testing keys.
1017      $this->drupalLogin($this->admin_user);
1018      $this->drupalGet('admin/settings/mollom/settings');
1019  
1020      // Set up invalid test keys and check that an error message is shown.
1021      $edit = array(
1022        'mollom_public_key' => 'invalid-public-key',
1023        'mollom_private_key' => 'invalid-private-key',
1024      );
1025      $this->drupalPost(NULL, $edit, t('Save configuration'), array('watchdog' => FALSE));
1026      $this->assertText(t('The configuration options have been saved.'));
1027      $this->assertText('The configured Mollom API keys are invalid.');
1028    }
1029  
1030    /**
1031     * Make sure that the Mollom settings page works for users with the
1032     * 'administer mollom' permission but not those without
1033     * it.
1034     */
1035    function testAdminAccessRights() {
1036      // Check access for a user that only has access to the 'administer
1037      // site configuration' permission. This user should have access to
1038      // the Mollom settings page.
1039      $this->drupalLogin($this->admin_user);
1040      $this->drupalGet('admin/settings/mollom');
1041      $this->assertResponse(200);
1042  
1043      // Check access for a user that has everything except the 'administer
1044      // mollom' permission. This user should not have access to the Mollom
1045      // settings page.
1046      $this->web_user = $this->drupalCreateUser(array_diff(module_invoke_all('perm'), array('administer mollom')));
1047      $this->drupalLogin($this->web_user);
1048      $this->drupalGet('admin/settings/mollom');
1049      $this->assertResponse(403);
1050    }
1051  
1052    /**
1053     * Tests 'bypass access' property of registered forms.
1054     */
1055    function testBypassAccess() {
1056      $this->drupalLogin($this->admin_user);
1057      $this->setProtection('comment_form');
1058      $this->drupalLogout();
1059  
1060      $node = $this->drupalCreateNode(array('body' => 'node body', 'type' => 'story'));
1061  
1062      // Create a regular user and post a comment.
1063      $this->web_user = $this->drupalCreateUser();
1064      $this->drupalLogin($this->web_user);
1065      $edit = array(
1066        'comment' => 'ham',
1067      );
1068      $this->drupalPost('comment/reply/' . $node->nid, $edit, t('Preview'));
1069  
1070      $this->drupalPost(NULL, array(), t('Save'));
1071      $this->assertText('node body');
1072      $this->assertText($edit['comment']);
1073  
1074      // Ensure a user having one of the permissions to bypass access can post
1075      // spam without triggering the spam protection.
1076      $this->drupalLogin($this->admin_user);
1077      $this->drupalGet('node/' . $node->nid);
1078      $this->clickLink('edit');
1079  
1080      $this->drupalPost(NULL, array('subject' => '', 'comment' => 'spam'), t('Preview'));
1081      $this->assertNoText($this->spam_message);
1082  
1083      $this->drupalPost(NULL, array(), t('Save'));
1084      $this->assertNoText($this->spam_message);
1085      $this->assertText('node body');
1086  
1087      // Log in back the regular user and try to edit the comment containing spam.
1088      $this->drupalLogin($this->web_user);
1089      $this->drupalGet('node/' . $node->nid);
1090      $this->clickLink('edit');
1091  
1092      $this->drupalPost(NULL, array(), t('Preview'));
1093      $this->assertText($this->spam_message);
1094  
1095      $this->drupalPost(NULL, array(), t('Save'));
1096      $this->assertText($this->spam_message);
1097      $this->assertNoText('node body');
1098    }
1099  }
1100  
1101  class MollomFallbackTestCase extends MollomWebTestCase {
1102    public static function getInfo() {
1103      return array(
1104        'name' => 'Fallback behavior',
1105        'description' => 'Check that the module uses the correct fallback mechanism when one or more of the specified Mollom servers are not available.',
1106        'group' => 'Mollom',
1107      );
1108    }
1109  
1110    function setUp() {
1111      // Enable testing server implementation.
1112      parent::setUp('mollom_test');
1113    }
1114  
1115    /**
1116     * Make sure that "request new password" submissions can be blocked when
1117     * the Mollom servers are unreachable.
1118     */
1119    function testFallbackMechanismBlock() {
1120      // Enable Mollom for the request password form.
1121      $this->drupalLogin($this->admin_user);
1122      $this->setProtection('user_pass', MOLLOM_MODE_CAPTCHA);
1123      // Set the fallback strategy to 'blocking mode'.
1124      $this->drupalPost('admin/settings/mollom/settings', array('mollom_fallback' => MOLLOM_FALLBACK_BLOCK), t('Save configuration'));
1125      $this->assertText('The configuration options have been saved.');
1126      $this->drupalLogout();
1127  
1128      // Configure Mollom to use a non-existent server as that should trigger
1129      // the fallback mechanism.
1130      variable_set('mollom_servers', array('http://fake-host'));
1131  
1132      // Check the password request form.
1133      // @todo Test mail sending with assertMail() now that it is available.
1134      $this->drupalGet('user/password', array('watchdog' => FALSE));
1135      $this->assertNoCaptchaField();
1136      $this->assertText($this->fallback_message);
1137    }
1138  
1139    /**
1140     * Make sure that "request new password" submissions can be allowed when
1141     * the Mollom servers are unreachable.
1142     */
1143    function testFallbackMechanismAccept() {
1144      // Enable Mollom for the request password form.
1145      $this->drupalLogin($this->admin_user);
1146      $this->setProtection('user_pass', MOLLOM_MODE_CAPTCHA);
1147      // Set the fallback strategy to 'accept mode'.
1148      $this->drupalPost('admin/settings/mollom/settings', array('mollom_fallback' => MOLLOM_FALLBACK_ACCEPT), t('Save configuration'));
1149      $this->assertText('The configuration options have been saved.');
1150      $this->drupalLogout();
1151  
1152      // Configure Mollom to use a non-existent server as that should trigger
1153      // the fallback mechanism.
1154      variable_set('mollom_servers', array('http://fake-host'));
1155  
1156      // Check the password request form.
1157      $this->drupalGet('user/password', array('watchdog' => FALSE));
1158      $this->assertNoCaptchaField();
1159      $this->assertNoText($this->fallback_message);
1160    }
1161  
1162    /**
1163     * Make sure that spam protection is still active even when some of the
1164     * Mollom servers are unavailable.
1165     *
1166     * @todo Test mail sending with assertMail() now that it is available.
1167     */
1168    function testFailoverMechanism() {
1169      $this->drupalLogin($this->admin_user);
1170      $this->setProtection('user_pass', MOLLOM_MODE_CAPTCHA);
1171      $this->drupalLogout();
1172  
1173      // Set the fallback strategy to 'blocking mode', so that if the failover
1174      // mechanism does not work, we would expect to get a warning.
1175      variable_set('mollom_fallback', MOLLOM_FALLBACK_BLOCK);
1176  
1177      // Configure Mollom to use a list of servers that have a number of
1178      // unknown servers, but one real server.
1179      variable_set('mollom_servers', array(
1180        'http://fake-host-1',
1181        'http://fake-host-2',
1182        $GLOBALS['base_url'] . '/xmlrpc.php?version=',
1183        'http://xmlrpc1.mollom.com', // The real server.
1184        'http://fake-host-3',
1185      ));
1186  
1187      // Validate that the request password form has a CAPTCHA text field and
1188      // that a user is not blocked from submitting it.
1189      $this->drupalGet('user/password');
1190      $this->assertCaptchaField();
1191      $this->assertNoText($this->fallback_message);
1192  
1193      $this->postCorrectCaptcha('user/password', array('name' => $this->admin_user->name), t('E-mail new password'));
1194      $this->assertText(t('Further instructions have been sent to your e-mail address.'));
1195    }
1196  }
1197  
1198  class MollomServerListRecoveryTestCase extends MollomWebTestCase {
1199    public static function getInfo() {
1200      return array(
1201        'name' => 'Server list recovery',
1202        'description' => 'Check that the module can recover from an invalid server list.',
1203        'group' => 'Mollom',
1204      );
1205    }
1206  
1207    /**
1208     * Make sure the server list is reset when the Mollom servers are unavailable or incorrect.
1209     */
1210    function testServerListRecovery() {
1211      $list = array(
1212        array(
1213          'http://not-a-valid-server-1',
1214          'http://not-a-valid-server-2',
1215        ),
1216        // The lack of the http://-schema results in different error codes
1217        array(
1218          'not-a-valid-server-url-1',
1219          'not-a-valid-server-url-2',
1220        ),
1221      );
1222  
1223      foreach ($list as $servers) {
1224        // Call mollom.verifyKey with an invalid server list.  The expected behavior
1225        // is that the first call fails, but that the second call succeeds because
1226        // the server list is automatically reset or recovered by the Mollom module.
1227        variable_set('mollom_servers', $servers);
1228  
1229        $key_is_valid = mollom('mollom.verifyKey');
1230        $this->assertIdentical($key_is_valid, NETWORK_ERROR, t('The Mollom servers could not be contacted.'));
1231        $this->assertMollomWatchdogMessages(FALSE);
1232  
1233        $key_is_valid = mollom('mollom.verifyKey');
1234        $this->assertIdentical($key_is_valid, TRUE, t('The Mollom servers could be contacted.'));
1235        $this->assertMollomWatchdogMessages();
1236      }
1237    }
1238  }
1239  
1240  class MollomLanguageDetectionTestCase extends MollomWebTestCase {
1241    public static function getInfo() {
1242      return array(
1243        'name' => 'Language detection',
1244        'description' => 'Tests language detection functionality.',
1245        'group' => 'Mollom',
1246      );
1247    }
1248  
1249    /**
1250     * Test the language detection functionality at the API level without using a web interface.
1251     */
1252    function testLanguageDetectionAPI() {
1253      // Note that Mollom supports more languages than those tested.
1254      $strings = array(
1255        'en' => "Hi, this is a test of the language detection code to see if it works well.",
1256        'nl' => "Hallo, dit is een test van de taaldetectiecode om te controleren of het werkt.",
1257        'fr' => "Bonjour, ceci est un test du detecteur langue automatique pour voir ci ça marche bien.",
1258        'de' => "Bedecke deinen Himmel, Zeus, Mit Wolkendunst Und übe, dem Knaben gleich, der Disteln köpft, An Eichen dich und Bergeshöhn.",
1259        'ko' => "'엄마야 누나야 강변살자. 뜰에는 반짝이는 금모래 빛. 뒷문 밖에는 갈잎의 노래",
1260        'ru' => "Холуй трясется. Раб хохочет. Палач свою секиру точит. Тиран кромсает каплуна. Сверкает зимняя луна.",
1261        'hu' => "Földszintiek mászófámról pillantva fejjel lefelé ti lógtok bele nézőim az űrbe ki tudja így kölcsönös kíváncsiak a helyes felelet kié",
1262        'el' => "Σαν να 'χουνε την όψη της αιώνες οργωμένη. Κάτι άναρχο κι ατέλειωτο στο πρόσωπό της μένει.",
1263        'ja' => "吹くからに秋の草木のしをるれば",
1264        'th' => "ทั่วประเทศ ประมาณ ๔๐,๐๐๐ แห่ง ชาวไทยนับตั้งแต่ครั้งอดีตมีวิถี ชีวิตผูกพันกับพุทธศาสนาอย่างใกล้ชิด แสดงออกมาเป็น ขนบธรรมเนียมประเพณี",
1265        'zh' => "螽斯羽,诜诜兮。宜尔子孙,振振兮",
1266      );
1267  
1268      foreach ($strings as $language => $text) {
1269        $result = mollom('mollom.detectLanguage', array('text' => $text));
1270        $this->assertEqual($result[0]['language'], $language, t('A language code was specified and they match.'));
1271        $this->assertTrue($result[0]['confidence'] > 0, t('A confidence value was specified and it is greater than 0.'));
1272      }
1273    }
1274  }
1275  
1276  /**
1277   * Tests blacklist functionality.
1278   *
1279   * The blacklists are stored on the server. These tests can fail when
1280   * different people run the tests at the same time because all tests share
1281   * the same blacklist. You can configure a custom key to avoid this.
1282   */
1283  class MollomBlacklistTestCase extends MollomWebTestCase {
1284    public static function getInfo() {
1285      return array(
1286        'name' => 'Blacklisting',
1287        'description' => 'Tests URL and text blacklist functionality.',
1288        'group' => 'Mollom',
1289      );
1290    }
1291  
1292    /**
1293     * Test the URL blacklist functionality at the API level without using a web interface.
1294     */
1295    function testUrlBlacklistAPI() {
1296      // Remove any stale blacklist entries from test runs that did not finish.
1297      $blacklist = mollom('mollom.listBlacklistURL');
1298      foreach ($blacklist as $entry) {
1299        if (strtotime($entry['created']) - time() > 86400) {
1300          mollom('mollom.removeBlacklistURL', array('url' => $entry['url']));
1301        }
1302      }
1303  
1304      // Blacklist a URL.
1305      $domain = $this->randomName() . '.com';
1306      $result = mollom('mollom.addBlacklistURL', array('url' => 'http://' . $domain));
1307      $this->assertTrue($result, t('The URL was blacklisted.'));
1308  
1309      // Check whether posts containing the blacklisted URL are properly blocked.
1310      $result = mollom('mollom.checkContent', array(
1311        'post_body' => "When the exact URL is present, the post should get blocked: http://{$domain}",
1312      ));
1313      $this->assertEqual($result['spam'], MOLLOM_ANALYSIS_SPAM, t('Exact URL match was blocked.'));
1314  
1315      $result = mollom('mollom.checkContent', array(
1316        'post_body' => "When the URL is expanded in the back, the post should get blocked: http://{$domain}/oh-my",
1317      ));
1318      $this->assertEqual($result['spam'], MOLLOM_ANALYSIS_SPAM, t('Partial URL match was blocked.'));
1319  
1320      $result = mollom('mollom.checkContent', array(
1321        'post_body' => "When the URL is expanded in the front, the post should get blocked: http://www.{$domain}",
1322      ));
1323      $this->assertEqual($result['spam'], MOLLOM_ANALYSIS_SPAM, t('URL with www-prefix was blocked.'));
1324  
1325      $result = mollom('mollom.checkContent', array(
1326        'post_body' => "When the URL has a different schema, the post should get blocked: ftp://www.{$domain}",
1327      ));
1328      $this->assertEqual($result['spam'], MOLLOM_ANALYSIS_SPAM, t('URL with different schema was blocked.'));
1329  
1330      // @todo Not implemented yet.
1331      /*
1332      $result = mollom('mollom.checkContent', array(
1333        'post_body' => "When the domain appears on its own, the post should get blocked: www.{$domain}",
1334      ));
1335      $this->assertEqual($result['spam'], MOLLOM_ANALYSIS_SPAM, t('Plain domain name with www-prefix was blocked.'));
1336      */
1337  
1338      $result = mollom('mollom.removeBlacklistURL', array('url' => 'http://' . $domain));
1339      $this->assertTrue($result, t('The blacklisted URL was removed.'));
1340    }
1341  
1342    /**
1343     * Test the text blacklist functionality at the API level without using a web interface.
1344     */
1345    function testTextBlacklistAPI() {
1346      // Remove any stale blacklist entries from test runs that did not finish.
1347      $blacklist = mollom('mollom.listBlacklistText');
1348      foreach ($blacklist as $entry) {
1349        if (strtotime($entry['created']) - time() > 86400) {
1350          mollom('mollom.removeBlacklistText', array('text' => $entry['text']));
1351        }
1352      }
1353  
1354      // Blacklist a word.
1355      // @todo As of now, only non-numeric, lower-case text seems to be supported.
1356      $term = drupal_strtolower(preg_replace('/[^a-zA-Z]/', '', $this->randomName()));
1357      $result = mollom('mollom.addBlacklistText', array(
1358        'text' => $term,
1359        'match' => 'contains',
1360        'reason' => 'spam',
1361      ));
1362      $this->assertIdentical($result, TRUE, t('The text was blacklisted.'));
1363  
1364      // Check whether posts containing the blacklisted word are properly blocked.
1365      $result = mollom('mollom.checkContent', array(
1366        'post_body' => $term,
1367      ));
1368      $this->assertEqual($result['spam'], MOLLOM_ANALYSIS_SPAM, t('Identical match was blocked.'));
1369  
1370      $result = mollom('mollom.checkContent', array(
1371        'post_body' => "When the term is present, the post should get blocked: " . $term,
1372      ));
1373      $this->assertEqual($result['spam'], MOLLOM_ANALYSIS_SPAM, t('Exact match was blocked.'));
1374  
1375      $result = mollom('mollom.checkContent', array(
1376        'post_body' => "When match is 'contains', the word can be surrounded by other text: abc" . $term . "def",
1377      ));
1378      $this->assertEqual($result['spam'], MOLLOM_ANALYSIS_SPAM, t('Partial match was blocked.'));
1379  
1380      // To update the work (i.e. to change the 'match' property), we simply
1381      // overwrite it.
1382      $result = mollom('mollom.addBlacklistText', array(
1383        'text' => $term,
1384        'match' => 'exact',
1385        'reason' => 'spam',
1386      ));
1387      $this->assertTrue($result, t('The text was blacklisted.'));
1388  
1389      $result = mollom('mollom.checkContent', array(
1390        'post_body' => "When match is 'exact', it has to be exact: " . $term,
1391      ));
1392      $this->assertEqual($result['spam'], MOLLOM_ANALYSIS_SPAM, t('Exact match was blocked.'));
1393  
1394      $result = mollom('mollom.checkContent', array(
1395        'post_body' => "When match is 'exact', it has to be exact: abc{$term}def",
1396      ));
1397      $this->assertNotEqual($result['spam'], MOLLOM_ANALYSIS_SPAM, t('Partial match was not blocked.'));
1398  
1399      $result = mollom('mollom.removeBlacklistText', array('text' => $term));
1400      $this->assertTrue($result, t('The blacklisted text was removed.'));
1401    }
1402  
1403    /**
1404     * Test the blacklist administration interface.
1405     *
1406     * We don't need to check whether the blacklisting actually works
1407     * (i.e. blocks posts) because that is tested in testTextBlacklistAPI() and
1408     * testURLBlacklistAPI().
1409     */
1410    function testBlacklistUI() {
1411      // Log in as an administrator and access the blacklist administration page.
1412      $this->drupalLogin($this->admin_user);
1413  
1414      // Add a word to the spam blacklist.
1415      $this->drupalGet('admin/settings/mollom/blacklist');
1416      $text = $this->randomName();
1417      $edit = array(
1418        'entry[context]' => 'everything',
1419        'entry[text]' => $text,
1420      );
1421      $this->drupalPost(NULL, $edit, t('Add'));
1422      $this->assertText(t('The entry was added to the blacklist.'));
1423      $this->assertText($text);
1424  
1425      // Remove the word from the spam blacklist.
1426      $links = $this->xpath('//td[contains(., "' . $text . '")]/following-sibling::td/a');
1427      $delete_url = $GLOBALS['base_root'] . (string) $links[0]['href'];
1428      $this->drupalGet($delete_url);
1429      $this->drupalPost(NULL, array(), t('Delete'));
1430      $this->assertEqual($this->getUrl(), url('admin/settings/mollom/blacklist', array('absolute' => TRUE)), t('Correct page redirection.'));
1431      $this->assertNoText($text, 'Text blacklist removed.');
1432  
1433      // Add a word to the profanity blacklist.
1434      $this->drupalGet('admin/settings/mollom/blacklist/profanity');
1435      $text = $this->randomName();
1436      $edit = array(
1437        'entry[context]' => 'everything',
1438        'entry[text]' => $text,
1439      );
1440      $this->drupalPost(NULL, $edit, t('Add'));
1441      $this->assertText(t('The entry was added to the blacklist.'));
1442      $this->assertText($text);
1443  
1444      // Remove the word from the profanity blacklist.
1445      $links = $this->xpath('//td[contains(., "' . $text . '")]/following-sibling::td/a');
1446      $delete_url = $GLOBALS['base_root'] . (string) $links[0]['href'];
1447      $this->drupalGet($delete_url);
1448      $this->drupalPost(NULL, array(), t('Delete'));
1449      $this->assertEqual($this->getUrl(), url('admin/settings/mollom/blacklist/profanity', array('absolute' => TRUE)), t('Correct page redirection.'));
1450      $this->assertNoText($text, 'Text blacklist removed.');
1451    }
1452  }
1453  
1454  /**
1455   * Tests Mollom form configuration functionality.
1456   */
1457  class MollomFormConfigurationTestCase extends MollomWebTestCase {
1458    public static function getInfo() {
1459      return array(
1460        'name' => 'Form administration',
1461        'description' => 'Verify that forms can be properly protected and unprotected.',
1462        'group' => 'Mollom',
1463      );
1464    }
1465  
1466    function setUp() {
1467      parent::setUp('mollom_test');
1468      // Re-route Mollom communication to this testing site.
1469      variable_set('mollom_servers', array($GLOBALS['base_url'] . '/xmlrpc.php?version='));
1470  
1471      $this->drupalLogin($this->admin_user);
1472    }
1473  
1474    /**
1475     * Tests configuration of form fields for textual analysis.
1476     */
1477    function testFormFieldsConfiguration() {
1478      // Protect Mollom test form.
1479      $this->drupalGet('admin/settings/mollom/add');
1480      $edit = array(
1481        'mollom[form_id]' => 'mollom_test_form',
1482      );
1483      $this->drupalPost(NULL, $edit, t('Next'));
1484      $this->assertText('Mollom test form');
1485      $edit = array(
1486        'mollom[mode]' => MOLLOM_MODE_ANALYSIS,
1487        'mollom[enabled_fields][title]' => TRUE,
1488        'mollom[enabled_fields][body]' => TRUE,
1489        'mollom[enabled_fields][exclude]' => FALSE,
1490        'mollom[enabled_fields][' . rawurlencode('parent][child') . ']' => TRUE,
1491        'mollom[enabled_fields][field]' => TRUE,
1492      );
1493      $this->drupalPost(NULL, $edit, t('Save'));
1494  
1495      // Verify that mollom_test_form form was protected.
1496      $this->assertText(t('The form protection has been added.'));
1497      $this->assertText('Mollom test form');
1498      $mollom_form = mollom_form_load('mollom_test_form');
1499      $this->assertTrue($mollom_form, t('Form configuration exists.'));
1500  
1501      // Verify that field configuration was properly stored.
1502      $this->drupalGet('admin/settings/mollom/manage/mollom_test_form');
1503      foreach ($edit as $name => $value) {
1504        // Skip any inputs that are not the fields for analysis checkboxes.
1505        if (strpos($name, '[enabled_fields]') === FALSE) {
1506          continue;
1507        }
1508        // assertFieldByName() does not work for checkboxes.
1509        // @see assertFieldChecked()
1510        $elements = $this->xpath('//input[@name="' . $name . '"]');
1511        if (isset($elements[0])) {
1512          if ($value) {
1513            $this->assertTrue(!empty($elements[0]['checked']), t('Field @name is checked', array('@name' => $name)));
1514          }
1515          else {
1516            $this->assertTrue(empty($elements[0]['checked']), t('Field @name is not checked', array('@name' => $name)));
1517          }
1518        }
1519        else {
1520          $this->fail(t('Field @name not found.', array('@name' => $name)));
1521        }
1522      }
1523  
1524      // Add a field to the stored configuration that existed previously.
1525      $mollom_form['enabled_fields'][] = 'orphan_field';
1526      mollom_form_save($mollom_form);
1527  
1528      // Verify that field configuration contains only available elements.
1529      $this->drupalGet('admin/settings/mollom/manage/mollom_test_form');
1530      $form_info = mollom_form_info('mollom_test_form', 'mollom_test');
1531      $fields = $this->xpath('//input[starts-with(@name, "mollom[enabled_fields]")]');
1532      $elements = array();
1533      foreach ($fields as $field) {
1534        $elements[] = substr(substr(rawurldecode($field['name']), 0, -1), 23);
1535      }
1536      $this->assertEqual($elements, array_keys($form_info['elements']), t('Field list only contains available form elements.'));
1537  
1538      // Try a simple submit of the form.
1539      $this->drupalLogout();
1540      $edit = array(
1541        'title' => 'unsure',
1542      );
1543      $this->drupalPost('mollom-test/form', $edit, 'Submit');
1544      $this->assertNoText('Successful form submission.');
1545      $this->assertText($this->unsure_message);
1546      $this->postCorrectCaptcha(NULL, array(), 'Submit', 'Successful form submission.');
1547  
1548      // Try to submit values for top-level fields.
1549      $edit = array(
1550        'title' => 'spam',
1551        'body' => 'spam',
1552      );
1553      $this->drupalPost('mollom-test/form', $edit, 'Submit');
1554      $this->assertNoText('Successful form submission.');
1555      $this->assertNoText($this->unsure_message);
1556      $this->assertText($this->spam_message);
1557  
1558      // Try to submit values for nested field.
1559      $edit = array(
1560        'title' => $this->randomString(),
1561        'parent[child]' => 'spam',
1562      );
1563      $this->drupalPost('mollom-test/form', $edit, 'Submit');
1564      $this->assertNoText('Successful form submission.');
1565      $this->assertNoText($this->unsure_message);
1566      $this->assertText($this->spam_message);
1567  
1568      // Try to submit values for nested field and multiple value field.
1569      // Start with ham values for simple, nested, and first multiple field.
1570      $edit = array(
1571        'title' => 'ham',
1572        'parent[child]' => 'ham',
1573        'field[new]' => 'ham',
1574      );
1575      $this->drupalPost('mollom-test/form', $edit, 'Add');
1576  
1577      // Verify that the form was rebuilt.
1578      $this->assertNoText('Successful form submission.');
1579      $this->assertNoText($this->unsure_message);
1580      $this->assertNoText($this->spam_message);
1581  
1582      // Add another value for multiple field.
1583      $edit = array(
1584        'field[new]' => 'ham',
1585      );
1586      $this->drupalPost(NULL, $edit, 'Add');
1587  
1588      // Verify that the form was rebuilt.
1589      $this->assertNoText('Successful form submission.');
1590      $this->assertNoText($this->unsure_message);
1591      $this->assertNoText($this->spam_message);
1592  
1593      // Now replace all ham values with random values, add a spam value to the
1594      // multiple field and submit the form.
1595      $edit = array(
1596        'title' => $this->randomString(),
1597        'parent[child]' => $this->randomString(),
1598        'field[0]' => $this->randomString(),
1599        'field[1]' => $this->randomString(),
1600        'field[new]' => 'spam',
1601      );
1602      $this->drupalPost(NULL, $edit, 'Submit');
1603  
1604      // Verify that the form was not submitted and cannot be submitted.
1605      $this->assertNoText('Successful form submission.');
1606      $this->assertText($this->spam_message);
1607    }
1608  
1609    /**
1610     * Tests default configuration, protecting, and unprotecting forms.
1611     */
1612    function testFormAdministration() {
1613      $form_info = mollom_form_list();
1614      foreach ($form_info as $form_id => $info) {
1615        $form_info[$form_id] += mollom_form_info($form_id, $info['module']);
1616      }
1617  
1618      // Verify that user registration form is not protected.
1619      $this->drupalGet('admin/settings/mollom');
1620      $this->assertNoText($form_info['user_register']['title']);
1621      $this->assertFalse(mollom_form_load('user_register'), t('Form configuration does not exist.'));
1622  
1623      // Re-protect user registration form.
1624      $this->drupalGet('admin/settings/mollom/add');
1625      $this->assertNoText(t('All available forms are protected already.'));
1626      $edit = array(
1627        'mollom[form_id]' => 'user_register',
1628      );
1629      $this->drupalPost(NULL, $edit, t('Next'));
1630      $this->assertText($form_info['user_register']['title']);
1631      $this->assertNoText(t('Text fields to analyze'));
1632      $this->drupalPost(NULL, array(), t('Save'));
1633  
1634      // Verify that user registration form was protected.
1635      $this->assertText(t('The form protection has been added.'));
1636      $this->assertText($form_info['user_register']['title']);
1637      $this->assertTrue(mollom_form_load('user_register'), t('Form configuration exists.'));
1638  
1639      // Iterate over all unconfigured forms and protect them.
1640      foreach ($form_info as $form_id => $info) {
1641        if (!mollom_form_load($form_id)) {
1642          $edit = array(
1643            'mollom[form_id]' => $form_id,
1644          );
1645          $this->drupalPost('admin/settings/mollom/add', $edit, t('Next'));
1646          $this->assertText($info['title']);
1647          // Verify that forms specifying elements have all possible elements
1648          // preselected for textual analysis.
1649          $edit = array();
1650          if (!empty($info['elements'])) {
1651            foreach ($info['elements'] as $field => $label) {
1652              $field = rawurlencode($field);
1653              $this->assertFieldByName("mollom[enabled_fields][$field]", TRUE);
1654            }
1655          }
1656          // Verify that CAPTCHA-only forms contain no configurable fields.
1657          else {
1658            $this->assertNoText(t('Analyze text for'));
1659            $this->assertNoText(t('Text fields to analyze'));
1660          }
1661          $this->drupalPost(NULL, $edit, t('Save'));
1662          $this->assertText(t('The form protection has been added.'));
1663        }
1664      }
1665  
1666      // Verify that trying to add a form redirects to the overview.
1667      $this->drupalGet('admin/settings/mollom/add');
1668      $this->assertText(t('All available forms are protected already.'));
1669      $this->assertText(t('Operations'));
1670    }
1671  
1672    /**
1673     * Tests programmatically, conditionally disabling Mollom.
1674     */
1675    function testFormAlter() {
1676      // Enable CAPTCHA-only protection for request user password form.
1677      $this->drupalLogin($this->admin_user);
1678      $this->setProtection('user_pass', MOLLOM_MODE_CAPTCHA);
1679      $this->drupalLogout();
1680  
1681      // Verify regular form protection.
1682      $this->drupalGet('user/password');
1683      $this->assertCaptchaField();
1684  
1685      // Conditionally disable protection and verify again.
1686      variable_set('mollom_test_disable_mollom', TRUE);
1687      $this->drupalGet('user/password');
1688      $this->assertNoCaptchaField();
1689    }
1690  }
1691  
1692  class MollomUserFormsTestCase extends MollomWebTestCase {
1693    public static function getInfo() {
1694      return array(
1695        'name' => 'User registration and password protection',
1696        'description' => 'Check that the user registration and password request forms can be protected.',
1697        'group' => 'Mollom',
1698      );
1699    }
1700  
1701    /**
1702     * Make sure that the request password form is protected correctly.
1703     *
1704     * @todo Test mail sending with assertMail() now that it is available.
1705     */
1706    function testProtectRequestPassword() {
1707      // We first enable Mollom for the request password form.
1708      $this->drupalLogin($this->admin_user);
1709      $this->setProtection('user_pass', MOLLOM_MODE_CAPTCHA);
1710      $this->drupalLogout();
1711  
1712      // Create a new user.
1713      $this->web_user = $this->drupalCreateUser();
1714  
1715      $this->drupalGet('user/password');
1716  
1717      // Try to reset the user's password by specifying an invalid CAPTCHA.
1718      $edit = array('name' => $this->web_user->name);
1719      $this->postIncorrectCaptcha('user/password', $edit, t('E-mail new password'));
1720      $this->postCorrectCaptcha(NULL, array(), t('E-mail new password'));
1721  
1722      // Try to reset the user's password by specifying a valid CAPTCHA.
1723      $this->postCorrectCaptcha('user/password', $edit, t('E-mail new password'));
1724      $this->assertText(t('Further instructions have been sent to your e-mail address.'));
1725    }
1726  
1727    /**
1728     * Make sure that the user registration form is protected correctly.
1729     */
1730    function testProtectRegisterUser() {
1731      // We first enable Mollom for the user registration form.
1732      $this->drupalLogin($this->admin_user);
1733      $this->setProtection('user_register', MOLLOM_MODE_CAPTCHA);
1734      $this->drupalLogout();
1735  
1736      // Validate that the user registration form has a CAPTCHA text field.
1737      $this->drupalGet('user/register');
1738      $this->assertCaptchaField();
1739  
1740      // Try to register with an invalid CAPTCHA. Make sure the user did not
1741      // successfully register.
1742      $name = $this->randomName();
1743      $edit = array(
1744        'name' => $name,
1745        'mail' => $name . '@example.com',
1746      );
1747      $this->postIncorrectCaptcha('user/register', $edit, t('Create new account'));
1748      $this->assertFalse(user_load(array('name' => $name)), t('The user who attempted to register cannot be found in the database when the CAPTCHA is invalid.'));
1749  
1750      // Try to register with a valid CAPTCHA. Make sure the user was able
1751      // to successfully register.
1752      $this->postCorrectCaptcha('user/register', $edit, t('Create new account'));
1753      $this->assertText(t('Your password and further instructions have been sent to your e-mail address.'));
1754      $this->assertTrue(user_load(array('name' => $name)), t('The user who attempted to register appears in the database when the CAPTCHA is valid.'));
1755    }
1756  }
1757  
1758  class MollomCommentFormTestCase extends MollomWebTestCase {
1759    private $node;
1760  
1761    public static function getInfo() {
1762      return array(
1763        'name' => 'Comment form protection',
1764        'description' => 'Check that the comment submission form can be protected.',
1765        'group' => 'Mollom',
1766      );
1767    }
1768  
1769    function setUp() {
1770      parent::setUp('comment');
1771  
1772      $this->web_user = $this->drupalCreateUser(array('access comments', 'post comments', 'post comments without approval', 'create story content'));
1773      $this->node = $this->drupalCreateNode(array('type' => 'story', 'uid' => $this->web_user->uid));
1774      variable_set('comment_preview_story', COMMENT_PREVIEW_OPTIONAL);
1775    }
1776  
1777    /**
1778     * Make sure that the comment submission form can be unprotected.
1779     */
1780    function testUnprotectedCommentForm() {
1781      // Request the comment reply form. There should be no CAPTCHA.
1782      $this->drupalLogin($this->web_user);
1783      $this->drupalGet('comment/reply/'. $this->node->nid);
1784      $this->assertNoCaptchaField();
1785      $this->assertNoPrivacyLink();
1786  
1787      // Preview a comment that is 'spam' and make sure there is still no CAPTCHA.
1788      $this->drupalPost(NULL, array('comment' => 'spam'), t('Preview'));
1789      $this->assertNoCaptchaField();
1790      $this->assertNoPrivacyLink();
1791  
1792      // Save the comment and make sure it appears.
1793      $this->drupalPost(NULL, array(), t('Save'));
1794      $this->assertRaw('<p>spam</p>', t('A comment that is known to be spam appears on the screen after it is submitted.'));
1795    }
1796  
1797    /**
1798     * Make sure that the comment submission form can be protected by captcha only.
1799     */
1800    function testCaptchaProtectedCommentForm() {
1801      // Enable Mollom CAPTCHA protection for comments.
1802      $this->drupalLogin($this->admin_user);
1803      $this->setProtection('comment_form', MOLLOM_MODE_CAPTCHA);
1804      $this->drupalLogout();
1805  
1806      // Request the comment reply form. There should be a CAPTCHA form.
1807      $this->drupalLogin($this->web_user);
1808      $this->drupalGet('comment/reply/' . $this->node->nid);
1809      $this->assertCaptchaField();
1810      $this->assertSessionIDInForm();
1811      $this->assertNoPrivacyLink();
1812  
1813      // Try to submit an incorrect answer for the CAPTCHA, without value for
1814      // required field.
1815      $this->postIncorrectCaptcha(NULL, array(), t('Preview'));
1816      $this->assertText(t('Comment field is required.'));
1817      $this->assertSessionIDInForm();
1818      $this->assertNoPrivacyLink();
1819  
1820      // Try to submit a correct answer for the CAPTCHA, still without required
1821      // field value.
1822      $this->postCorrectCaptcha(NULL, array(), t('Preview'));
1823      $this->assertText(t('Comment field is required.'));
1824      $session_id = $this->assertSessionIDInForm();
1825      $this->assertNoPrivacyLink();
1826  
1827      // Finally, we should be able to submit a comment.
1828      $this->drupalPost(NULL, array('comment' => 'spam'), t('Save'));
1829      $this->assertRaw('<p>spam</p>', t('Spam comment could be posted with correct CAPTCHA.'));
1830      $cid = db_result(db_query("SELECT cid FROM {comments} WHERE comment = '%s' ORDER BY timestamp DESC", array('spam')));
1831      $this->assertMollomData('comment', $cid, $session_id);
1832    }
1833  
1834    /**
1835     * Make sure that the comment submission form can be fully protected.
1836     */
1837    function testTextAnalysisProtectedCommentForm() {
1838      // Enable Mollom text-classification for comments.
1839      $this->drupalLogin($this->admin_user);
1840      $this->setProtection('comment_form');
1841      $this->drupalLogout();
1842  
1843      // Request the comment reply form.  Initially, there should be no CAPTCHA.
1844      $this->drupalLogin($this->web_user);
1845      $this->drupalGet('comment/reply/'. $this->node->nid);
1846      $this->assertNoCaptchaField();
1847      $this->assertPrivacyLink();
1848  
1849      // Try to save a comment that is 'unsure' and make sure there is a CAPTCHA.
1850      $edit = array(
1851        'comment' => 'unsure',
1852      );
1853      $this->drupalPost(NULL, $edit, t('Save'));
1854      $this->assertCaptchaField();
1855      $session_id = $this->assertSessionIDInForm();
1856      $this->assertPrivacyLink();
1857  
1858      // Try to submit the form by solving the CAPTCHA incorrectly. At this point,
1859      // the submission should be blocked and a new CAPTCHA generated, but only if
1860      // the comment is still neither ham or spam.
1861      $this->postIncorrectCaptcha(NULL, array(), t('Save'));
1862      $this->assertCaptchaField();
1863      $session_id = $this->assertSessionIDInForm();
1864      $this->assertPrivacyLink();
1865  
1866      // Correctly solving the CAPTCHA should accept the form submission.
1867      $this->postCorrectCaptcha(NULL, array(), t('Save'));
1868      $this->assertRaw('<p>' . $edit['comment'] . '</p>', t('A comment that may contain spam was found.'));
1869      $cid = db_result(db_query("SELECT cid FROM {comments} WHERE comment = '%s' ORDER BY timestamp DESC", array($edit['comment'])));
1870      $this->assertMollomData('comment', $cid, $session_id);
1871  
1872      // Try to save a new 'spam' comment; it should be rejected, with no CAPTCHA
1873      // appearing on the page.
1874      $this->resetSessionID();
1875      $this->drupalGet('comment/reply/' . $this->node->nid);
1876      $this->assertPrivacyLink();
1877      $original_number_of_comments = $this->getCommentCount($this->node->nid);
1878      $this->assertSpamSubmit(NULL, array('comment'), array(), t('Save'));
1879      $session_id = $this->assertSessionIDInForm();
1880      $this->assertCommentCount($this->node->nid, $original_number_of_comments);
1881      $this->assertPrivacyLink();
1882  
1883      // Try to save again; it should be rejected, with no CAPTCHA.
1884      $this->assertSpamSubmit(NULL, array('comment'), array(), t('Save'));
1885      $session_id = $this->assertSessionIDInForm();
1886      $this->assertCommentCount($this->node->nid, $original_number_of_comments);
1887      $this->assertPrivacyLink();
1888  
1889      // Save a new 'ham' comment.
1890      $this->resetSessionID();
1891      $this->drupalGet('comment/reply/' . $this->node->nid);
1892      $this->assertPrivacyLink();
1893      $original_number_of_comments = $this->getCommentCount($this->node->nid);
1894      $this->assertHamSubmit(NULL, array('comment'), array(), t('Save'));
1895      $this->assertRaw('<p>ham</p>', t('A comment that is known to be ham appears on the screen after it is submitted.'));
1896      $this->assertCommentCount($this->node->nid, $original_number_of_comments + 1);
1897      $cid = db_result(db_query("SELECT cid FROM {comments} WHERE comment = '%s' ORDER BY timestamp DESC", array('ham')));
1898      $this->assertMollomData('comment', $cid);
1899    }
1900  
1901    /**
1902     * Return the number of comments for a node of the given node ID.  We
1903     * can't use comment_num_all() here, because that is statically cached
1904     * and therefore will not work correctly with the SimpleTest browser.
1905     */
1906    private function getCommentCount($nid) {
1907      return db_result(db_query('SELECT comment_count FROM {node_comment_statistics} WHERE nid = %d', $nid));
1908    }
1909  
1910    /**
1911     * Test that the number of comments for a node matches an expected value.
1912     *
1913     * @param $nid
1914     *   A node ID
1915     * @param $expected
1916     *   An integer with the expected number of comments for the node.
1917     * @param $message
1918     *   An optional string with the message to be used in the assertion.
1919     */
1920    protected function assertCommentCount($nid, $expected, $message = '') {
1921      $actual = $this->getCommentCount($nid);
1922      if (!$message) {
1923        $message = t('Node @nid has @actual comment(s), expected @expected.', array('@nid' => $nid, '@actual' => $actual, '@expected' => $expected));
1924      }
1925      $this->assertEqual($actual, $expected, $message);
1926    }
1927  }
1928  
1929  class MollomContactFormTestCase extends MollomWebTestCase {
1930    public static function getInfo() {
1931      return array(
1932        'name' => 'Contact form protection',
1933        'description' => 'Check that the contact form can be protected.',
1934        'group' => 'Mollom',
1935      );
1936    }
1937  
1938    function setUp() {
1939      parent::setUp('contact');
1940  
1941      $this->web_user = $this->drupalCreateUser(array('access site-wide contact form', 'access user profiles'));
1942    }
1943  
1944    /**
1945     * Make sure that the user contact form is protected correctly.
1946     *
1947     * @todo Test mail sending with assertMail() now that it is available.
1948     */
1949    function testProtectContactUserForm() {
1950      // Enable Mollom for the contact form.
1951      $this->drupalLogin($this->admin_user);
1952      $this->setProtection('contact_mail_user');
1953      $this->drupalLogout();
1954  
1955      $this->drupalLogin($this->web_user);
1956      $url = 'user/' . $this->admin_user->uid . '/contact';
1957      $button = t('Send e-mail');
1958      $success = t('The message has been sent.');
1959  
1960      // Submit a 'spam' message.  This should be blocked.
1961      $this->assertSpamSubmit($url, array('subject', 'message'), array(), $button);
1962      $this->assertNoText($success);
1963  
1964      // Submit a 'ham' message.  This should be accepted.
1965      $this->assertHamSubmit($url, array('subject', 'message'), array(), $button);
1966      $this->assertText($success);
1967  
1968      // Submit an 'unsure' message.  This should be accepted only after the
1969      // CAPTCHA has been solved.
1970      $this->assertUnsureSubmit($url, array('subject', 'message'), array(), $button, $success);
1971    }
1972  
1973    /**
1974     * Make sure that the site-wide contact form is protected correctly.
1975     *
1976     * @todo Test mail sending with assertMail() now that it is available.
1977     */
1978    function testProtectContactSiteForm() {
1979      // Enable Mollom for the contact form.
1980      $this->drupalLogin($this->admin_user);
1981      $this->setProtection('contact_mail_page');
1982      $this->drupalLogout();
1983  
1984      // Add some fields to the contact form so that it is active.
1985      // Empty 'reply' so as to not have to fiddle with auto-reply messages.
1986      $this->drupalLogin($this->web_user);
1987      db_query("INSERT INTO {contact} (category, recipients, reply) VALUES ('%s', '%s', '%s')", 'test category', $this->web_user->mail, '');
1988  
1989      $url = 'contact';
1990      $button = t('Send e-mail');
1991      $success = t('Your message has been sent.');
1992  
1993      // Submit a 'spam' message.  This should be blocked.
1994      $this->assertSpamSubmit($url, array('subject', 'message'), array(), $button);
1995      $this->assertNoText($success);
1996  
1997      // Submit a 'ham' message.  This should be accepted.
1998      $this->assertHamSubmit($url, array('subject', 'message'), array(), $button);
1999      $this->assertText($success);
2000      $report_link = $this->parseMollomMailReportLink();
2001      $this->assertTrue($report_link, t('Report to Mollom link found in e-mail.'));
2002      $this->assertEqual($report_link['entity'], 'session', t('Report link in e-mail uses entity type "session".'));
2003      $this->assertMollomData($report_link['entity'], $report_link['session_id']);
2004  
2005      // Submit an 'unsure' message.  This should be accepted only after the
2006      // CAPTCHA has been solved.
2007      $this->assertUnsureSubmit($url, array('subject', 'message'), array(), $button, $success);
2008      $report_link = $this->parseMollomMailReportLink();
2009      $this->assertTrue($report_link, t('Report to Mollom link found in e-mail.'));
2010      $this->assertEqual($report_link['entity'], 'session', t('Report link in e-mail uses entity type "session".'));
2011      $this->assertMollomData($report_link['entity'], $report_link['session_id']);
2012  
2013      // Report the mail to Mollom.
2014      $this->drupalGet($report_link['url']);
2015      $edit = array(
2016        'feedback' => 'spam',
2017      );
2018      $this->drupalPost(NULL, $edit, t('Delete'));
2019      $this->assertText(t('The content was successfully reported as inappropriate.'));
2020    }
2021  
2022    /**
2023     * Returns data about the report to Mollom link in the last sent mail.
2024     *
2025     * Contrary to DrupalWebTestCase::assertMail(), this function removes the last
2026     * sent mail from the internally recorded stack.
2027     */
2028    function parseMollomMailReportLink() {
2029      // Grab the last sent mail.
2030      // @see DrupalWebTestCase::assertMail()
2031      $captured_emails = variable_get('drupal_test_email_collector', array());
2032      $email = array_pop($captured_emails);
2033      variable_set('drupal_test_email_collector', $captured_emails);
2034  
2035      $found = FALSE;
2036      if (preg_match('@http.+?mollom/report/([^/]+)/([^\s]+)@', $email['body'], $matches)) {
2037        $found = array(
2038          'url' => $matches[0],
2039          'entity' => $matches[1],
2040          'session_id' => $matches[2],
2041          'mail' => $email,
2042        );
2043      }
2044      return $found;
2045    }
2046  }
2047  
2048  class MollomResellerTestCase extends MollomWebTestCase {
2049    public static function getInfo() {
2050      return array(
2051        'name' => 'Reseller functionality',
2052        'description' => 'Check that the reseller APIs are working properly.',
2053        'group' => 'Mollom',
2054      );
2055    }
2056  
2057    /**
2058     * Make sure that resellers can create a new site.
2059     */
2060    function testKeyManagement() {
2061      if (!$this->is_reseller) {
2062        // If the current test keys are not reseller keys, skip this test.
2063        return;
2064      }
2065  
2066      // Create 3 test sites:
2067      for ($i = 1; $i <= 3; $i++) {
2068        $keys[] = mollom('mollom.createSite', array(
2069          'url' => 'http://example.com/site-'. $i,
2070          'mail' => 'mail@example.com',
2071          'status' => 0,
2072          'testing' => 1,
2073        ));
2074      }
2075  
2076      // Assert that there were no XML-RPC errors or watchdog messages.
2077      $this->assertMollomWatchdogMessages();
2078  
2079      $sites = mollom('mollom.listSites');
2080      foreach ($sites as $site) {
2081        // Retrieve the site information:
2082        $details = mollom('mollom.getSite', array('client_key' => $site));
2083  
2084        $this->assertEqual($details['mail'], 'mail@example.com', t('The original information is correctly retrieved from Mollom.'));
2085        $this->assertEqual($details['status'], 0, t('The original information is correctly retrieved from Mollom.'));
2086        $this->assertEqual($details['testing'], 1, t('The original information is correctly retrieved from Mollom.'));
2087  
2088        // Perform a safety check to avoid that the tests would delete
2089        // valid sites in case someone messed up their Mollom settings!
2090        if ($details['mail'] == 'mail@example.com' || $details['mail'] == 'root@example.com') {
2091          // Update the information on the site and verify that it was updated.
2092          mollom('mollom.updateSite', array('client_key' => $site, 'mail' => 'root@example.com'));
2093          $details = mollom('mollom.getSite', array('client_key' => $site));
2094          $this->assertEqual($details['mail'], 'root@example.com', t('The updated information is correctly retrieved from Mollom.'));
2095  
2096          // Verify that the existing information did not change (partial updates).
2097          $this->assertEqual($details['status'], 0, t('The original information is correctly retrieved from Mollom.'));
2098          $this->assertEqual($details['testing'], 1, t('The original information is correctly retrieved from Mollom.'));
2099  
2100          // Delete the test site:
2101          mollom('mollom.deleteSite', array('client_key' => $site));
2102        }
2103        else {
2104          $this->fail(t('We tried to delete a non-test site.'));
2105        }
2106      }
2107  
2108      // Assert that there were no XML-RPC errors or watchdog messages.
2109      $this->assertMollomWatchdogMessages();
2110  
2111      // Retrieve information about a non-existing site:
2112      $details = mollom('mollom.getSite', array('client_key' => 'bogus'));
2113      $this->assertEqual(xmlrpc_errno(), TRUE, t('Retrieving information from a non-existing site returned an XML-RPC error.'));
2114      $this->assertMollomWatchdogMessages(FALSE);
2115  
2116      // Verify that all sites have been deleted:
2117      $sites = mollom('mollom.listSites');
2118      $this->assertEqual(count($sites), 0, t('All Mollom sites have been deleted.'));
2119    }
2120  }
2121  
2122  /**
2123   * Tests form value processing.
2124   */
2125  class MollomDataTestCase extends MollomWebTestCase {
2126    public static function getInfo() {
2127      return array(
2128        'name' => 'Data processing',
2129        'description' => 'Verify that form registry information is properly transformed into data that is sent to Mollom servers.',
2130        'group' => 'Mollom',
2131      );
2132    }
2133  
2134    function setUp() {
2135      // Enable testing server implementation.
2136      parent::setUp('mollom_test');
2137      // Re-route Mollom communication to this testing site.
2138      variable_set('mollom_servers', array($GLOBALS['base_url'] . '/xmlrpc.php?version='));
2139    }
2140  
2141    /**
2142     * Test mollom_form_get_values().
2143     */
2144    function testFormGetValues() {
2145      global $user;
2146  
2147      // Form registry information.
2148      $form_info = array(
2149        'elements' => array(
2150          'subject' => 'Subject',
2151          'message' => 'Message',
2152          'parent][child' => 'Some nested element',
2153        ),
2154        'mapping' => array(
2155          'post_title' => 'subject',
2156          'author_name' => 'name',
2157          'author_mail' => 'mail',
2158        ),
2159      );
2160      // Fields configured via Mollom admin UI based on $form_info['elements'].
2161      $fields = array(
2162        'subject',
2163        'message',
2164        'parent][child',
2165      );
2166  
2167      // Verify submitted form values for an anonymous/arbitrary user.
2168      $values = array(
2169        'subject' => 'Foo',
2170        'message' => 'Bar',
2171        'parent' => array(
2172          'child' => 'Beer',
2173        ),
2174        'name' => 'Drupaler',
2175        'mail' => 'drupaler@example.com',
2176      );
2177      $data = mollom_form_get_values($values, $fields, $form_info['mapping']);
2178  
2179      $this->assertSame('post_title', $data['post_title'], $values['subject']);
2180      $this->assertSame('post_body', $data['post_body'], $values['message'] . "\n" . $values['parent']['child']);
2181      $this->assertSame('author_name', $data['author_name'], $values['name']);
2182      $this->assertSame('author_mail', $data['author_mail'], $values['mail']);
2183      $this->assertFalse(isset($data['author_url']), t('author_url: Undefined.'));
2184      $this->assertFalse(isset($data['author_openid']), t('author_openid: Undefined.'));
2185      $this->assertFalse(isset($data['author_id']), t('author_id: Undefined.'));
2186      $this->assertSame('author_ip', $data['author_ip'], ip_address());
2187  
2188      // Verify submitted form values for an registered user.
2189      $values = array(
2190        'subject' => 'Foo',
2191        'message' => 'Bar',
2192        'name' => $this->admin_user->name,
2193      );
2194      $data = mollom_form_get_values($values, $fields, $form_info['mapping']);
2195  
2196      $this->assertSame('post_title', $data['post_title'], $values['subject']);
2197      $this->assertSame('post_body', $data['post_body'], $values['message']);
2198      $this->assertSame('author_name', $data['author_name'], $this->admin_user->name);
2199      $this->assertSame('author_mail', $data['author_mail'], $this->admin_user->mail);
2200      $this->assertFalse(isset($data['author_url']), t('author_url: Undefined.'));
2201      // @todo Test this.
2202      $this->assertFalse(isset($data['author_openid']), t('author_openid: Undefined.'));
2203      $this->assertSame('author_id', $data['author_id'], $this->admin_user->uid);
2204      $this->assertSame('author_ip', $data['author_ip'], ip_address());
2205    }
2206  
2207    /**
2208     * Test submitted post and author information for textual analysis.
2209     */
2210    function testAnalysis() {
2211      $this->drupalLogin($this->admin_user);
2212      $this->setProtection('comment_form');
2213  
2214      // Make comment preview optional.
2215      $edit = array(
2216        'comment_preview' => 0,
2217      );
2218      $this->drupalPost('admin/content/node-type/story', $edit, t('Save content type'));
2219  
2220      // Create a node we can comment on.
2221      $node = $this->drupalCreateNode(array('type' => 'story', 'promote' => 1));
2222      $this->drupalGet('');
2223      $this->assertText($node->title);
2224  
2225      // Log in regular user and post a comment.
2226      $this->drupalLogout();
2227      $this->web_user = $this->drupalCreateUser();
2228      $this->drupalLogin($this->web_user);
2229      $this->drupalGet('');
2230      $this->clickLink(t('Add new comment'));
2231  
2232      $edit = array(
2233        'subject' => $this->randomString(),
2234        'comment' => 'unsure',
2235      );
2236      $this->drupalPost(NULL, $edit, t('Save'));
2237      $this->assertText($this->unsure_message);
2238  
2239      // Verify that submitted data equals post data.
2240      $data = $this->getServerRecord();
2241      $this->assertSame('post_title', $data['post_title'], $edit['subject']);
2242      $this->assertSame('post_body', $data['post_body'], $edit['comment']);
2243      $this->assertSame('author_name', $data['author_name'], $this->web_user->name);
2244      $this->assertSame('author_mail', $data['author_mail'], $this->web_user->mail);
2245      $this->assertSame('author_id', $data['author_id'], $this->web_user->uid);
2246  
2247      $this->PostCorrectCaptcha(NULL, array(), t('Save'));
2248      $comment = db_fetch_object(db_query("SELECT * FROM {comments} WHERE subject = '%s'", $edit['subject']));
2249      $this->assertTrue($comment, t('Comment exists in database.'));
2250  
2251      // Verify that submitted data equals post data.
2252      $data = $this->getServerRecord('mollom.checkCaptcha');
2253      $this->assertSame('author_id', $data['author_id'], $this->web_user->uid);
2254  
2255      // Allow anonymous users to post comments without approval.
2256      $this->drupalLogin($this->admin_user);
2257      $edit = array(
2258        DRUPAL_ANONYMOUS_RID . '[access comments]' => TRUE,
2259        DRUPAL_ANONYMOUS_RID . '[post comments]' => TRUE,
2260        DRUPAL_ANONYMOUS_RID . '[post comments without approval]' => TRUE,
2261      );
2262      $this->drupalPost('admin/user/permissions', $edit, t('Save permissions'));
2263  
2264      // Allow anonymous users to post contact information.
2265      $edit = array(
2266        'comment_anonymous' => COMMENT_ANONYMOUS_MAY_CONTACT,
2267      );
2268      $this->drupalPost('admin/content/node-type/story', $edit, t('Save content type'));
2269  
2270      // Log out and post a comment as anonymous user.
2271      $this->resetServerRecords();
2272      $this->drupalLogout();
2273      $this->drupalGet('node/' . $node->nid);
2274      $this->clickLink(t('Add new comment'));
2275      // Ensure we have some potentially escaped characters in the values.
2276      $edit = array(
2277        'name' => $this->randomString(6) . ' & ' . $this->randomString(8),
2278        'mail' => 'mollom@example.com',
2279        'homepage' => 'http://mollom.com',
2280        'subject' => '"' . $this->randomString() . '"',
2281        'comment' => 'unsure',
2282      );
2283      $this->drupalPost(NULL, $edit, t('Save'));
2284      $this->assertText($this->unsure_message);
2285  
2286      // Verify that submitted data equals post data.
2287      $data = $this->getServerRecord();
2288      $this->assertSame('post_title', $data['post_title'], $edit['subject']);
2289      $this->assertSame('post_body', $data['post_body'], $edit['comment']);
2290      $this->assertSame('author_name', $data['author_name'], $edit['name']);
2291      $this->assertSame('author_mail', $data['author_mail'], $edit['mail']);
2292      $this->assertSame('author_url', $data['author_url'], $edit['homepage']);
2293      $this->assertFalse(isset($data['author_id']), t('author_id: Undefined.'));
2294  
2295      $this->PostCorrectCaptcha(NULL, array(), t('Save'));
2296      $comment = db_fetch_object(db_query("SELECT * FROM {comments} WHERE subject = '%s'", $edit['subject']));
2297      $this->assertTrue($comment, t('Comment exists in database.'));
2298  
2299      // Verify that submitted data equals post data.
2300      $data = $this->getServerRecord('mollom.checkCaptcha');
2301      $this->assertSame('author_id', $data['author_id'], NULL);
2302  
2303      // Log in admin user and edit comment containing spam.
2304      $this->resetServerRecords();
2305      $this->drupalLogin($this->admin_user);
2306      $this->drupalGet('comment/edit/' . $comment->cid);
2307      // Post without modification.
2308      $this->drupalPost(NULL, array(), t('Save'));
2309  
2310      // Verify that no data was submitted to Mollom.
2311      $data = $this->getServerRecord();
2312      $this->assertFalse($data, t('Administrative form submission was not validated by Mollom.'));
2313    }
2314  
2315    /**
2316     * Tests automated 'post_id' mapping and session data storage.
2317     *
2318     * This is an atomic test to verify that a simple 'post_id' mapping defined
2319     * via hook_mollom_form_info() is sufficient for basic integration with
2320     * Mollom (without reporting).
2321     */
2322    function testPostIdMapping() {
2323      // Enable protection for mollom_test_form.
2324      $this->drupalLogin($this->admin_user);
2325      $this->setProtection('mollom_test_form');
2326      $this->drupalLogout();
2327  
2328      // Submit a mollom_test thingy.
2329      $edit = array(
2330        'title' => 'ham',
2331        'body' => $this->randomString(),
2332      );
2333      $this->drupalPost('mollom-test/form', $edit, 'Submit');
2334      $this->assertText('Successful form submission.');
2335      $mid = $this->getFieldValueByName('mid');
2336      $this->assertTrue($mid > 0, t('Submission was stored.'));
2337      $data = $this->assertMollomData('mollom_test', $mid);
2338  
2339      // Ensure we were redirected to the form for the stored entry.
2340      $this->assertFieldByName('body', $edit['body'], t('Existing body value found.'));
2341      $new_mid = $this->getFieldValueByName('mid');
2342      $this->assertEqual($new_mid, $mid, t('Existing entity id found.'));
2343  
2344      // Update the stored entry.
2345      $edit['title'] = 'unsure';
2346      $this->drupalPost(NULL, $edit, 'Submit');
2347      $this->assertCaptchaField();
2348      $this->postCorrectCaptcha(NULL, array(), 'Submit', 'Successful form submission.');
2349      $new_data = $this->assertMollomData('mollom_test', $mid);
2350  
2351      // Verify that only session data was updated.
2352      $this->assertSame('entity', $data->entity, $new_data->entity);
2353      $this->assertSame('id', $data->did, $new_data->did);
2354      $this->assertNotSame('session_id', $data->session, $new_data->session);
2355      $this->assertSame('quality', $data->quality, $new_data->quality);
2356      $count = db_result(db_query("SELECT COUNT(1) FROM {mollom}"));
2357      $this->assertEqual($count, 1, t('Stored data in {mollom} was updated.'));
2358    }
2359  
2360    /**
2361     * Tests data sent for mollom.verifyKey.
2362     */
2363    function testVerifyKey() {
2364      $this->drupalLogin($this->admin_user);
2365      $this->drupalGet('admin/settings/mollom/settings');
2366  
2367      // Verify that we additionally sent version data.
2368      $data = $this->getServerRecord('mollom.verifyKey');
2369      $info = _mollom_get_version();
2370      $this->assertTrue(!empty($info['platform_name']), t('Version information found.'));
2371      $this->assertSame('platform_name', $data['platform_name'], $info['platform_name']);
2372      $this->assertSame('platform_version', $data['platform_version'], $info['platform_version']);
2373      $this->assertSame('client_name', $data['client_name'], $info['client_name']);
2374      $this->assertSame('client_version', $data['client_version'], $info['client_version']);
2375    }
2376  }
2377  
2378  /**
2379   * Tests report to Mollom functionality.
2380   */
2381  class MollomReportTestCase extends MollomWebTestCase {
2382    public static function getInfo() {
2383      return array(
2384        'name' => 'Reporting functionality',
2385        'description' => 'Verify that session data is properly stored and content can be reported to Mollom.',
2386        'group' => 'Mollom',
2387      );
2388    }
2389  
2390    function setUp() {
2391      parent::setUp('comment');
2392  
2393      $this->web_user = $this->drupalCreateUser(array('access comments', 'post comments', 'post comments without approval', 'create story content'));
2394    }
2395  
2396    /**
2397     * Tests reporting comments.
2398     */
2399    function testReportComment() {
2400      $this->drupalLogin($this->admin_user);
2401      $this->setProtection('comment_form');
2402      $this->drupalLogout();
2403  
2404      $this->node = $this->drupalCreateNode(array('type' => 'story'));
2405      variable_set('comment_preview_story', COMMENT_PREVIEW_OPTIONAL);
2406  
2407      // Post a comment.
2408      $this->drupalLogin($this->web_user);
2409      $edit = array(
2410        'comment' => 'ham',
2411      );
2412      $this->drupalPost('comment/reply/' . $this->node->nid, $edit, t('Save'));
2413      $this->comment = db_fetch_object(db_query("SELECT * FROM {comments} WHERE comment = '%s' AND nid = %d", array($edit['comment'], $this->node->nid)));
2414      $this->assertTrue($this->comment, t('Comment was found in the database.'));
2415      $this->assertMollomData('comment', $this->comment->cid);
2416  
2417      // Log in comment administrator and verify that we can report to Mollom.
2418      $this->drupalLogin($this->admin_user);
2419      $this->drupalGet('node/' . $this->node->nid);
2420      $this->assertText($edit['comment'], t('Comment found.'));
2421      $this->clickLink('report to Mollom');
2422      $edit = array(
2423        'feedback' => 'spam',
2424      );
2425      $this->drupalPost(NULL, $edit, t('Delete'));
2426      $this->assertText(t('The comment has been deleted.'));
2427      $this->assertText(t('The content was successfully reported as inappropriate.'));
2428  
2429      // Verify that the comment and Mollom session data has been deleted.
2430      $this->assertFalse(_comment_load($this->comment->cid), t('Comment was deleted.'));
2431      $this->assertNoMollomData('comment', $this->comment->cid);
2432    }
2433  
2434    /**
2435     * Tests mass-reporting comments.
2436     */
2437    function testMassReportComments() {
2438      $this->drupalLogin($this->admin_user);
2439      $this->setProtection('comment_form');
2440      $this->drupalLogout();
2441  
2442      $this->node = $this->drupalCreateNode(array('type' => 'story'));
2443      variable_set('comment_preview_story', COMMENT_PREVIEW_OPTIONAL);
2444  
2445      // Post 3 comments.
2446      $this->drupalLogin($this->web_user);
2447      $this->comments = array();
2448      foreach (range(1, 3) as $num) {
2449        $edit = array(
2450          'subject' => $this->randomName(),
2451          'comment' => 'ham',
2452        );
2453        $this->drupalPost('comment/reply/' . $this->node->nid, $edit, t('Save'));
2454        $this->comments[$num] = db_fetch_object(db_query("SELECT * FROM {comments} WHERE subject = '%s' AND nid = %d", array($edit['subject'], $this->node->nid)));
2455        $this->assertTrue($this->comments[$num], t('Comment was found in the database.'));
2456        $this->assertMollomData('comment', $this->comments[$num]->cid);
2457      }
2458  
2459      // Log in comment administrator and verify that we can mass-report all
2460      // comments to Mollom.
2461      $this->drupalLogin($this->admin_user);
2462      $this->drupalGet('admin/content/comment');
2463      $edit = array(
2464        'operation' => 'mollom-unpublish',
2465      );
2466      foreach ($this->comments as $comment) {
2467        $this->assertText($comment->subject, t('Comment found.'));
2468        $edit["comments[{$comment->cid}]"] = TRUE;
2469      }
2470      $this->drupalPost(NULL, $edit, t('Update'));
2471      $this->assertText(t('The selected comments have been reported as inappropriate and are unpublished.'));
2472  
2473      // Verify that unpublished comments are found in approval queue and
2474      // mass-report all comments again to delete them.
2475      $this->drupalGet('admin/content/comment/approval');
2476      $edit['operation'] = 'mollom-delete';
2477      foreach ($this->comments as $comment) {
2478        $this->assertText($comment->subject, t('Comment found.'));
2479      }
2480      $this->drupalPost(NULL, $edit, t('Update'));
2481      $this->assertText(t('The selected comments have been reported as inappropriate and are deleted.'));
2482  
2483      // Verify that the comments and Mollom session data has been deleted.
2484      foreach ($this->comments as $comment) {
2485        $this->assertFalse(_comment_load($comment->cid), t('Comment was deleted.'));
2486        $this->assertNoMollomData('comment', $comment->cid);
2487      }
2488    }
2489  }
2490  


Generated: Thu Mar 24 11:18:33 2011 Cross-referenced by PHPXref 0.7