You are here

search_by_page.test in Search by Page 6

Same filename and directory in other branches
  1. 7 tests/search_by_page.test

Tests for the Search by Page module. By Jennifer Hodgdon of Poplar ProductivityWare, www.poplarware.com

File

tests/search_by_page.test
View source
<?php

/**
 * @file
 * Tests for the Search by Page module.
 * By Jennifer Hodgdon of Poplar ProductivityWare, www.poplarware.com
 */

/**
 * Unit tests for Search by Page functions.
 */
class SearchByPageUnitTest extends DrupalWebTestCase {
  public static function getInfo() {
    return array(
      'name' => t('Search by Page Unit Tests'),
      'description' => t('Test individual functions in search_by_page.module'),
      'group' => t('Search by Page'),
      'dependencies' => array(
        'search',
        'sbp_test',
        'search_by_page',
      ),
    );
  }
  public function setUp() {
    parent::setUp('search', 'search_by_page', 'sbp_test');
  }

  /**
   * Tests the search_by_page_path_parts() function.
   */
  function testPathParts() {
    $path = "abc/def?a=b&c=f";
    $res = search_by_page_path_parts($path);
    $this
      ->assertEqual(count($res), 2, "search_by_page_path_parts() returns right count in results");
    $this
      ->assertEqual($res[0], 'abc/def', "search_by_page_path_parts() returns right base path");
    $this
      ->assertEqual($res[1], 'a=b&c=f', "search_by_page_path_parts() returns right query part");
    $path = "abc/def";
    $res = search_by_page_path_parts($path);
    $this
      ->assertEqual(count($res), 1, "search_by_page_path_parts() returns right count in results");
    $this
      ->assertEqual($res[0], 'abc/def', "search_by_page_path_parts() returns right base path");
    $path = "abc/def&a=b&c=f";
    $res = search_by_page_path_parts($path);
    $this
      ->assertEqual(count($res), 2, "search_by_page_path_parts() returns right count in results");
    $this
      ->assertEqual($res[0], 'abc/def', "search_by_page_path_parts() returns right base path");
    $this
      ->assertEqual($res[1], 'a=b&c=f', "search_by_page_path_parts() returns right query part");
  }

  /**
   * Tests the search_by_page_unique_rewrite() function.
   */
  function testUniqueRewrite() {
    $result = search_by_page_unique_rewrite('abc_');
    $this
      ->assertTrue(count($result) >= 2, "search_by_page_unique_rewrite() has 2 or more components");
    $this
      ->assertTrue(strrpos($result[0], 'abc_n') > 0, "search_by_page_unique_rewrite() join contains abc_n");
    $this
      ->assertTrue(strrpos($result[1], 'abc_n') > 0, "search_by_page_unique_rewrite() where contains abc_n");
  }

  /**
   * Tests the search_by_page_excerpt() function.
   */
  function testExcerpt() {

    // Our test class should have made the 'walking' key match walks, walker,
    // walking, and walked. They should now be highlighted with <strong> HTML
    // tags.
    $result = search_by_page_excerpt('walking', 'He walks through the forest');
    $this
      ->assertTrue(strpos($result, '<strong>walks</strong>') > 0, "Excerpt highlights walks");
    $result = search_by_page_excerpt('walking', 'He is a walker through the forest');
    $this
      ->assertTrue(strpos($result, '<strong>walker</strong>') > 0, "Excerpt highlights walker");
    $result = search_by_page_excerpt('walking', 'He is walking through the forest');
    $this
      ->assertTrue(strpos($result, '<strong>walking</strong>') > 0, "Excerpt highlights walking");
    $result = search_by_page_excerpt('walking', 'He walked through the forest');
    $this
      ->assertTrue(strpos($result, '<strong>walked</strong>') > 0, "Excerpt highlights walked");

    // Verify that an exact match after a stemmed match highlights the stemmed.
    $result = search_by_page_excerpt('walking', 'He walked on the long walk in town');
    $this
      ->assertTrue(strpos($result, '<strong>walked</strong>') > 0, "Excerpt highlights walked");
  }

  /**
   * Tests the search_by_page_strip_tags function.
   */
  function testStripTags() {
    $env = 1;
    $test_string = '<div>This is a test. <tag1>This should be removed</tag1> <tag2>This should also be removed</tag2> This should be left. <tag1>This should not be here</tag1><tag1 some="attribute">This although with attributes, should also be removed</tag1></div>';

    // Try excluding some tags.
    search_by_page_setting_set('exclude_tags', $env, 'tag1 tag2');
    $result = search_by_page_strip_tags($test_string, $env);
    $this
      ->assertEqual($result, '<div>This is a test.   This should be left. </div>', 'search_by_page_strip_tags() is working correctly.');

    // Try not excluding any tags.
    search_by_page_setting_set('exclude_tags', $env, '');
    $result = search_by_page_strip_tags($test_string, $env);
    $this
      ->assertEqual($result, $test_string, 'search_by_page_strip_tags() with no tags to strip is working correctly.');
  }

}

/**
 * Base class for testing Search by Page.
 */
class SearchByPageTester extends DrupalWebTestCase {
  public $envinfo1;
  public $envid1;
  public $envinfo2;
  public $envid2;

  /**
   * Creates two environments for Search by Page.
   */
  public function setUpEnvironments() {
    $user = $this
      ->drupalCreateUser(array(
      'administer search by page',
      'access administration pages',
      'administer site configuration',
    ));
    $this
      ->drupalLogin($user);

    // Clear out any existing search environments that may have been defined.
    $envs = search_by_page_list_environments();
    foreach ($envs as $env) {
      module_invoke_all('sbp_delete_environment', $env);
    }

    // Define two new environments. They should have ID numbers 1 and 2.
    $this->envinfo1 = array(
      'environment_name' => 'env1',
      'set_as_default' => 1,
      'page_title' => t('Search page 1 title'),
      'block_title' => t('Search block 1 title'),
      'field_label' => t('Search field 1 label'),
      'button_label' => t('Search button 1 label'),
      'page_path' => 'search_path_1',
      'exclude_tags' => 'tagtoexclude',
    );
    $this
      ->drupalPost('admin/settings/search_by_page/add', $this->envinfo1, 'Save configuration');
    $this->envid1 = 1;
    $this->envinfo2 = array(
      'environment_name' => 'env2',
      'set_as_default' => 2,
      'page_title' => t('Search page 2 title'),
      'block_title' => t('Search block 2 title'),
      'field_label' => t('Search field 2 label'),
      'button_label' => t('Search button 2 label'),
      'page_path' => 'search_path_2',
    );
    $this
      ->drupalPost('admin/settings/search_by_page/add', $this->envinfo2, 'Save configuration');
    $this->envid2 = 2;

    // Reset the SimpleTest permissions cache.
    $this
      ->checkPermissions(array(), TRUE);
    $this
      ->drupalLogout();
  }

  /**
   * Returns the permission name to search the given search environment.
   */
  public function searchPerm($envinfo) {
    return 'search page environment ' . $envinfo['environment_name'];
  }

  /**
   * Updates the search index.
   *
   * Logs current user out, and runs cron to make sure search content
   * is indexed.
   */
  public function doCronRun() {

    // Make sure we are logged out before cron run.
    if ($this->loggedInUser) {
      $this
        ->drupalLogout();
    }

    // Note: Could use $this->cronRun(), but not available in 6.x SimpleTest,
    // so using the body of cronRun() from Drupal 7 instead
    $this
      ->drupalGet($GLOBALS['base_url'] . '/cron.php', array(
      'external' => TRUE,
      'query' => array(
        'cron_key' => variable_get('cron_key', 'drupal'),
      ),
    ));
  }

  /**
   * Returns the unique role ID created by the testing framework.
   */
  public function getNewRoleID($account) {
    $roles = $account->roles;
    $allroles = user_roles();
    foreach ($roles as $id => $name) {
      if ($id != DRUPAL_ANONYMOUS_RID && $id != DRUPAL_AUTHENTICATED_RID) {
        $this
          ->assertTrue(isset($allroles[$id]) && $allroles[$id], 'Found a role for new user and it exists');
        return $id;
      }
    }
    $this
      ->fail('Did not find a new role for new user');
    return DRUPAL_ANONYMOUS_RID;
  }

  /**
   * Helper function: returns an array of last index times for items.
   *
   * @return
   *   Array whose keys are the internal Search by Page IDs for the items,
   *   and whose values are the last time the item was indexed by Search by
   *   Page.
   */
  public function getIndexTimes() {
    $times = array();
    $result = db_query('SELECT * FROM {sbp_path}');
    while ($item = db_fetch_object($result)) {
      $times[$item->pid] = $item->last_index_time;
    }
    return $times;
  }

  /**
   * Helper function: Verifies reindexing.
   *
   * Tests that one item was reindexed, and it was the oldest item, given
   * previous and current output from getIndexTimes(). Assumes, but does
   * not explicitly check, that the array keys are the same for the two
   * arrays.
   *
   * @param $prev
   *   Previous index times array.
   * @param $curr
   *   Current index times array.
   */
  public function verifyIndexCycling($prev, $curr) {
    $keys = array_keys($prev);
    $min_val = min($prev);
    $count = 0;
    foreach ($keys as $key) {
      if ($prev[$key] != $curr[$key]) {
        $count++;
        $this
          ->assertEqual($prev[$key], $min_val, "Item indexed was the oldest");
      }
    }
    $this
      ->assertEqual($count, 1, "Exactly one item was indexed ({$count})");
  }

}

/**
 * Basic search environments test.
 */
class SearchByPageEnvironmentTest extends SearchByPageTester {
  public $superuser;
  public $user1;
  public $user2;
  public static function getInfo() {
    return array(
      'name' => t('Search by Page Environments Tests'),
      'description' => t('Test that search environments can be set up.'),
      'group' => t('Search by Page'),
      'dependencies' => array(
        'search',
        'search_by_page',
      ),
    );
  }
  public function setUp() {
    parent::setUp('search', 'search_by_page');
    $this
      ->setUpEnvironments();

    // Verify that environments are created
    $envs = search_by_page_list_environments();
    $this
      ->assertTrue(in_array($this->envid1, $envs), 'Environment 1 created');
    $this
      ->assertTrue(in_array($this->envid2, $envs), 'Environment 2 created');
    $perms = search_by_page_perm();
    $this
      ->assertTrue(in_array('search page environment ' . $this->envinfo1['environment_name'], $perms), 'Environment 1 perm created');
    $this
      ->assertTrue(in_array('search page environment ' . $this->envinfo2['environment_name'], $perms), 'Environment 2 perm created');
    $this
      ->assertEqual('search page environment ' . $this->envinfo1['environment_name'], $this
      ->searchPerm($this->envinfo1), 'searchPerm function working');
    $this->superuser = $this
      ->drupalCreateUser(array(
      'administer blocks',
      'access administration pages',
      'administer search',
      'administer search by page',
      'search content',
      $this
        ->searchPerm($this->envinfo1),
      $this
        ->searchPerm($this->envinfo2),
      'administer site configuration',
      'administer permissions',
    ));
    $this->user1 = $this
      ->drupalCreateUser(array(
      'search content',
      $this
        ->searchPerm($this->envinfo1),
    ));
    $this->user2 = $this
      ->drupalCreateUser(array(
      'search content',
      $this
        ->searchPerm($this->envinfo2),
    ));
  }

  /**
   * Tests that environment settings are working.
   */
  public function testEnvironments() {

    // Test that user1 and user2 can only see their pages.
    // And that the pages have correct text on them.
    // User 1 - has permission for env 1 only
    $this
      ->drupalLogin($this->user1);
    $this
      ->drupalGet($this->envinfo1['page_path']);

    // The assertTitle function is lame, because it includes the site name...
    $this
      ->assertTrue(strstr(current($this
      ->xpath('//title')), $this->envinfo1['page_title']), 'Page title contains correct string');
    $this
      ->assertText($this->envinfo1['page_title'], 'Page title is visible');
    $this
      ->assertText($this->envinfo1['field_label'], 'Field label is correct');
    $this
      ->assertRaw($this->envinfo1['button_label'], 'Button label is correct');
    $this
      ->drupalGet($this->envinfo2['page_path']);
    $this
      ->assertText('Access denied', 'Access denied to user without permission');

    // User 2 - has permission for env 2 only
    $this
      ->drupalLogin($this->user2);
    $this
      ->drupalGet($this->envinfo2['page_path']);
    $this
      ->assertTrue(strstr(current($this
      ->xpath('//title')), $this->envinfo2['page_title']), 'Page title contains correct string');
    $this
      ->assertText($this->envinfo2['page_title'], 'Page title is visible');
    $this
      ->assertText($this->envinfo2['field_label'], 'Field label is correct');
    $this
      ->assertRaw($this->envinfo2['button_label'], 'Button label is correct');
    $this
      ->drupalGet($this->envinfo1['page_path']);
    $this
      ->assertText(t('denied'), 'Access denied to user without permission');

    // Test that blocks exist and have right titles when displayed.
    $this
      ->drupalLogin($this->superuser);
    $this
      ->drupalGet('admin/build/block');
    $this
      ->assertText(t('Search by page @env', array(
      '@env' => $this->envinfo1['environment_name'],
    )), "Block 1 exists");
    $this
      ->assertText(t('Search by page @env', array(
      '@env' => $this->envinfo1['environment_name'],
    )), "Block 2 exists");

    // Turn on both blocks.
    $this
      ->drupalPost('admin/build/block', array(
      'search_by_page_' . $this->envid1 . '[region]' => 'content',
      'search_by_page_' . $this->envid2 . '[region]' => 'content',
    ), 'Save blocks');

    // Verify block titles appear.
    $this
      ->drupalGet('admin');
    $this
      ->assertText($this->envinfo1['block_title'], 'Block title is correct');
    $this
      ->assertText($this->envinfo2['block_title'], 'Block title is correct');
  }

}

/**
 * Functionality tests for Search by Page Nodes.
 */
class SearchByPageNodesTest extends SearchByPageTester {
  public $superuser;
  public $noprivuser;
  public $privuser;
  public $privnodeid;
  public $nodetitle1;
  public $exclnodetitle;
  public static function getInfo() {
    return array(
      'name' => t('Search by Page Nodes Tests'),
      'description' => t('Test functionality of sbp_nodes.module'),
      'group' => t('Search by Page'),
      'dependencies' => array(
        'search',
        'sbp_test',
        'sbp_nodes',
        'dblog',
        'search_by_page',
      ),
    );
  }
  public function setUp() {
    parent::setUp('search', 'search_by_page', 'sbp_nodes', 'sbp_test', 'dblog');

    // Note: I think SimpleTest inherits the default node access from the
    // base system. Needs to be rebuilt in order for the access tests below
    // to pass!
    node_access_rebuild();
    $this
      ->setUpEnvironments();

    // Set up super-user and other users with different privileges.
    $this->superuser = $this
      ->drupalCreateUser(array(
      'administer nodes',
      'access content',
      'administer content types',
      'administer blocks',
      'administer search',
      'search content',
      'administer search by page',
      'access administration pages',
      $this
        ->searchPerm($this->envinfo1),
      'administer site configuration',
      'administer users',
      'administer permissions',
      'view test private content',
      'access site reports',
    ));
    $this->noprivuser = $this
      ->drupalCreateUser(array(
      'access content',
      'search content',
      $this
        ->searchPerm($this->envinfo1),
    ));
    $this->privuser = $this
      ->drupalCreateUser(array(
      'access content',
      'search content',
      $this
        ->searchPerm($this->envinfo1),
      'view test private content',
    ));
    $this
      ->drupalLogin($this->superuser);

    // Set up so "sbp_indexed" nodes are searchable, and "sbp_hidden" nodes are
    // not. Index them with the privileged user.
    $this
      ->drupalPost('admin/settings/search_by_page/edit/' . $this->envid1, array(
      'sbp_nodes_types_indexed[sbp_indexed]' => TRUE,
      'sbp_nodes_display_type' => 'excerpts',
      'sbp_nodes_role' => $this
        ->getNewRoleID($this->privuser),
      'button_label' => t('Search pages'),
    ), 'Save configuration');
    cache_clear_all('variables', 'cache');
    variable_init();

    // Throw in a few nodes that won't match our tests.
    $info = array(
      'body' => 'blah',
      'teaser' => 'blah',
      'title' => 'blah',
    );
    $this
      ->drupalCreateNode($info);
    $this
      ->drupalCreateNode($info);
    $this
      ->drupalCreateNode($info);
    $this
      ->drupalCreateNode($info);

    // Create some content that we'll look for - make sure it has the
    // word "walk" in it.
    $info = array(
      'body' => 'I walk through the streets, looking around for trouble',
      'teaser' => 'I walk on a path, where it is quiet',
      'type' => 'sbp_indexed',
      'test_private' => FALSE,
    );
    $node = $this
      ->drupalCreateNode($info);
    $this->nodetitle1 = $node->title;
    $this
      ->assertFalse($node->test_private, "Created a non-private node");
    $this
      ->drupalGet('node/' . $node->nid);
    $this
      ->assertText('streets', "Streets appears on first node page");
    $this
      ->assertNoText('north', "North does not appear on first node page");
    $this
      ->assertNoText('people', "People does not appear on first node page");

    // Create some "private" content, also with the word "walk" in it
    $info = array(
      'body' => 'I can walk really far, maybe even to the north pole.',
      'teaser' => 'I will walk to the south pole.',
      'type' => 'sbp_indexed',
      'test_private' => TRUE,
    );
    $node = $this
      ->drupalCreateNode($info);
    $this->privnodeid = $node->nid;
    $this
      ->assertTrue($node->test_private, "Created a private node");
    $this
      ->drupalGet('node/' . $node->nid);
    $this
      ->assertNoText('streets', "Streets does not appear on second node page");
    $this
      ->assertText('north', "North appears on second node page");
    $this
      ->assertNoText('people', "People does not appear on second node page");

    // Create some non-indexed content, also with the word "walk" in it
    $info = array(
      'body' => 'When I walk, I try not to run into people.',
      'type' => 'sbp_hidden',
      'test_private' => FALSE,
    );
    $node = $this
      ->drupalCreateNode($info);
    $this
      ->drupalGet('node/' . $node->nid);
    $this
      ->assertNoText('streets', "Streets does not appear on third node page");
    $this
      ->assertNoText('north', "North does not appear on third node page");
    $this
      ->assertText('people', "People appears on third node page");

    // Create some content with excluded tags. Make sure to use Full HTML
    // input format.
    $excluded = search_by_page_setting_get('exclude_tags', $this->envid1, '');
    $this
      ->assertEqual($excluded, 'tagtoexclude', 'Correct tag is marked excluded');
    $info = array(
      'body' => 'This content <tagtoexclude>only has walk gobble in the excluded tag</tagtoexclude> and then gobble appears after it.',
      'format' => 2,
      'teaser' => 'Short version of this content',
      'type' => 'sbp_indexed',
      'test_private' => FALSE,
    );
    $node = $this
      ->drupalCreateNode($info);
    $this->exclnodetitle = $node->title;
    $this
      ->drupalGet('node/' . $node->nid);
    $this
      ->assertText('walk', "walk appears on the excluded node page");
    $this
      ->assertText('gobble', "gobble appears on the excluded node page");
    $this
      ->doCronrun();
    $this
      ->drupalLogin($this->superuser);
    $this
      ->drupalGet('admin/reports/dblog');
    $this
      ->assertText(t('Cron run completed'), 'Log shows cron run completed');
    $this
      ->drupalLogout();
  }

  /**
   * Tests that the content of the designated types only can be searched.
   */
  function testSearchTypes() {
    $search_path = $this->envinfo1['page_path'];
    $this
      ->drupalLogin($this->privuser);

    // Search for the word 'walk'
    $this
      ->drupalPost($search_path, array(
      'keys' => 'walk',
    ), t('Search pages'));

    // Verify that the "indexed" pages are searchable, and the non-indexed not.
    $this
      ->assertText('walk', "Walk appears in search results for walk");
    $this
      ->assertText('streets', "First page was found");
    $this
      ->assertText('north', "Second page was found");
    $this
      ->assertNoText('people', "Non-searchable content was not found");
    $this
      ->assertLink($this->nodetitle1, 0, "Link to first node is found");

    // Try searching for something that isn't there
    $this
      ->drupalPost($search_path, array(
      'keys' => 'blsdfsdfsadf',
    ), t('Search pages'));
    $this
      ->assertNoText('walk', "Walk does not appear in search results for gibberish");
    $this
      ->assertText('no results', "No results appears on search results page for gibberish");
  }

  /**
   * Tests that access permissions are obeyed.
   */
  function testSearchAccess() {

    // Log in as a non-priv user
    $this
      ->drupalLogin($this->noprivuser);

    // Some node access tests...
    // Note: The following access tests are low-level, but they were failing at
    // one time, until I rebuilt node access permissions in startup. So, leave
    // them here -- at the least they are useful for debugging if other tests
    // start failing later!
    $node = node_load($this->privnodeid, NULL, TRUE);
    $this
      ->assertTrue($node->test_private, "Node is marked private");
    $this
      ->assertTrue($node->status, "Node is published");
    $grants = node_access_grants('view', $this->noprivuser);
    $this
      ->assertTrue(!isset($grants['sbp_test']) || !$grants['sbp_test'], "Non-priv user does not have sbp test grant");
    $grants = node_access_grants('view', $this->privuser);
    $this
      ->assertTrue($grants['sbp_test'], "Priv user does have sbp test grant");
    $this
      ->assertFalse(user_access('administer nodes', $this->noprivuser), "Non priv user does not have administer nodes permission");
    $this
      ->assertTrue(user_access('access content', $this->noprivuser), "Non priv user does have access content permission");
    $this
      ->assertFalse(node_access("view", $node, $this->noprivuser), "Node access is restricted for non-priv user");
    $this
      ->assertTrue(node_access("view", $node, $this->privuser), "Node access is not restricted for priv user");

    // Verify we cannot see the private page
    $this
      ->drupalGet('node/' . $this->privnodeid);
    $this
      ->assertNoText('walk', "Cannot see private page");

    // Run  a search for "walk"
    $search_path = $this->envinfo1['page_path'];
    $this
      ->drupalPost($search_path, array(
      'keys' => 'walk',
    ), t('Search pages'));

    // Should be able to see the public page, but not the private page.
    $this
      ->assertText('walk', "Walk appears in search results");
    $this
      ->assertText('streets', "Streets appears in search results");
    $this
      ->assertNoText('north', "North does not appear in search results for nonpriv user");
  }

  /**
   * Tests that the teaser display option works.
   */
  function testTeaserDisplay() {
    $this
      ->drupalLogin($this->superuser);

    // Set display output to display teasers
    $this
      ->drupalPost('admin/settings/search_by_page/edit/' . $this->envid1, array(
      'sbp_nodes_display_type' => 'teasers',
    ), 'Save configuration');
    cache_clear_all('variables', 'cache');
    variable_init();

    // Search for the word 'walk'
    $search_path = $this->envinfo1['page_path'];
    $this
      ->drupalPost($search_path, array(
      'keys' => 'walk',
    ), t('Search pages'));

    // Verify that teasers are displayed instead of excerpts
    $this
      ->assertText('walk', "Walk appears in search results for walk");
    $this
      ->assertNoText('streets', "First page excerpt not displayed");
    $this
      ->assertText('path', "First page teaser displayed");

    // Set display output to display excerpts
    $this
      ->drupalLogin($this->superuser);
    $this
      ->drupalPost('admin/settings/search_by_page/edit/' . $this->envid1, array(
      'sbp_nodes_display_type' => 'excerpts',
    ), 'Save configuration');
    cache_clear_all('variables', 'cache');
    variable_init();

    // Search for the word 'walk'
    $this
      ->drupalPost($search_path, array(
      'keys' => 'walk',
    ), t('Search pages'));

    // Verify that excerpts are displayed instead of teasers
    $this
      ->assertText('walk', "Walk appears in search results for walk");
    $this
      ->assertText('streets', "First page excerpt displayed");
    $this
      ->assertNoText('path', "First page teaser not displayed");
  }

  /**
   * Tests that the excluded tag is excluded from search.
   */
  function testSearchExclude() {

    // Make sure to use environment 1, since that has the exclude tags.
    $search_path = $this->envinfo1['page_path'];
    $excluded = search_by_page_setting_get('exclude_tags', $this->envid1, '');
    $this
      ->assertEqual($excluded, 'tagtoexclude', 'Correct tag is marked excluded');
    $this
      ->drupalLogin($this->privuser);

    // Search for the word 'walk'.
    $this
      ->drupalPost($search_path, array(
      'keys' => 'walk',
    ), t('Search pages'));

    // Verify that the "excluded" page doesn't show up.
    $this
      ->assertNoText($this->exclnodetitle, "Excluded node was not found in search for walk");
    $this
      ->assertNoText('gobble', "Gobble is not shown on the page in search for walk");

    // Search for the word 'gobble'
    $this
      ->drupalPost($search_path, array(
      'keys' => 'gobble',
    ), t('Search pages'));

    // Verify that the "excluded" page does show up, but not with the word walk showing.
    $this
      ->assertText($this->exclnodetitle, "Excluded node was found in search for gobble");
    $this
      ->assertNoText('walk', "Walk is not shown on the page");
  }

}

/**
 * Tests when nodes are reindexed.
 */
class SearchByPageNodesReindexTest extends SearchByPageTester {
  public $superuser;
  public $nodes;
  public static function getInfo() {
    return array(
      'name' => t('Search by Page Nodes Reindex'),
      'description' => t('Test reindexing in sbp_nodes.module'),
      'group' => t('Search by Page'),
      'dependencies' => array(
        'search',
        'sbp_test',
        'sbp_nodes',
        'dblog',
        'search_by_page',
        'comment',
      ),
    );
  }
  public function setUp() {
    parent::setUp('search', 'search_by_page', 'sbp_nodes', 'sbp_test', 'dblog', 'comment');

    // Note: I think SimpleTest inherits the default node access from the
    // base system. Needs to be rebuilt in order for the access tests below
    // to pass!
    node_access_rebuild();
    $this
      ->setUpEnvironments();

    // Set up super-user.
    $this->superuser = $this
      ->drupalCreateUser(array(
      'administer nodes',
      'access content',
      'administer content types',
      'administer blocks',
      'administer search',
      'search content',
      'administer search by page',
      'access administration pages',
      $this
        ->searchPerm($this->envinfo1),
      'administer site configuration',
      'administer users',
      'administer permissions',
      'view test private content',
      'access site reports',
      'access comments',
      'post comments without approval',
      'administer comments',
    ));
    $this
      ->drupalLogin($this->superuser);

    // Set up so "sbp_indexed" nodes are searchable.
    // Index them with the super-user.
    $this
      ->drupalPost('admin/settings/search_by_page/edit/' . $this->envid1, array(
      'sbp_nodes_types_indexed[sbp_indexed]' => TRUE,
      'sbp_nodes_display_type' => 'excerpts',
      'sbp_nodes_role' => $this
        ->getNewRoleID($this->superuser),
      'button_label' => t('Search pages'),
    ), 'Save configuration');
    cache_clear_all('variables', 'cache');
    variable_init();

    // Create 5 nodes with the same content.
    $info = array(
      'body' => 'blah',
      'teaser' => 'blah',
      'title' => 'blah',
      'type' => 'sbp_indexed',
      'test_private' => FALSE,
    );
    $this->nodes = array();
    for ($i = 0; $i < 5; $i++) {
      $this->nodes[] = $this
        ->drupalCreateNode($info);
    }

    // Run cron to index these nodes.
    $this
      ->doCronrun();
    $this
      ->drupalLogin($this->superuser);
    $this
      ->drupalGet('admin/reports/dblog');
    $this
      ->assertText(t('Cron run completed'), 'Log shows cron run completed');
    $this
      ->drupalLogout();
  }

  /**
   * Tests that node reindexing happens in the right order on node update.
   */
  function testReindexingOnUpdate() {
    $this
      ->drupalLogin($this->superuser);
    $search_path = $this->envinfo1['page_path'];

    // Set to never reindex automatically.
    $this
      ->drupalPost('admin/settings/search_by_page/edit/' . $this->envid1, array(
      'sbp_nodes_min_time' => 0,
      'sbp_nodes_max_time' => 0,
    ), 'Save configuration');
    cache_clear_all('variables', 'cache');
    variable_init();

    // Set search so it only indexes 1 node per cron run.
    variable_set('sbp_cron_limit', 1);

    // Run this test several times...
    for ($j = 0; $j < 10; $j++) {

      // Choose a random title and index.
      $newtitle = $this
        ->randomName();
      $i = rand(0, count($this->nodes) - 1);
      $this->nodes[$i]->title = $newtitle;
      node_save($this->nodes[$i]);

      // Verify new title is not searchable.
      $this
        ->drupalPost($search_path, array(
        'keys' => $newtitle,
      ), t('Search pages'));
      $this
        ->assertNoText($newtitle, 'New title not found in search');

      // Run cron - should reindex just this node.
      $this
        ->doCronrun();
      $this
        ->drupalLogin($this->superuser);

      // Verify new title is searchable.
      $this
        ->drupalPost($search_path, array(
        'keys' => $newtitle,
      ), t('Search pages'));
      $this
        ->assertText($newtitle, 'New title found in search after reindex');
    }
  }

  /**
   * Tests that node reindexing happens in the right order on comment update.
   */
  function testReindexingOnComment() {
    $this
      ->drupalLogin($this->superuser);
    $search_path = $this->envinfo1['page_path'];

    // Turn on comments for 'sbp_indexed' content type, and put the
    // comment form on the node.
    $this
      ->drupalPost('admin/content/node-type/sbp-indexed', array(
      'comment' => '2',
      'comment_form_location' => '1',
      'comment_preview' => '0',
    ), 'Save content type');

    // Set to never reindex automatically.
    $this
      ->drupalPost('admin/settings/search_by_page/edit/' . $this->envid1, array(
      'sbp_nodes_min_time' => 0,
      'sbp_nodes_max_time' => 0,
    ), 'Save configuration');
    cache_clear_all('variables', 'cache');
    variable_init();

    // Set search so it only indexes 1 node per cron run.
    variable_set('sbp_cron_limit', 1);

    // Run this test several times...
    for ($j = 0; $j < 10; $j++) {

      // Enter a random comment.
      $newsubj = $this
        ->randomName();
      $newbody = $this
        ->randomName();
      $i = rand(0, count($this->nodes) - 1);
      $this
        ->drupalPost('node/' . $this->nodes[$i]->nid, array(
        'subject' => $newsubj,
        'comment' => $newbody,
      ), 'Save');

      // Verify new comment subject is not searchable.
      $this
        ->drupalPost($search_path, array(
        'keys' => $newsubj,
      ), t('Search pages'));
      $this
        ->assertNoText($newsubj, 'New comment not found in search');

      // Run cron - should reindex just this node.
      $this
        ->doCronrun();
      $this
        ->drupalLogin($this->superuser);

      // Verify new title is searchable.
      $this
        ->drupalPost($search_path, array(
        'keys' => $newsubj,
      ), t('Search pages'));
      $this
        ->assertText($newsubj, 'New comment found in search after reindex');
    }
  }

  /**
   * Tests that cycling through content reindexing happens correctly.
   */
  function testReindexingAutomatic() {
    $this
      ->drupalLogin($this->superuser);
    $search_path = $this->envinfo1['page_path'];

    // Set to reindex automatically on normal cycle.
    $this
      ->drupalPost('admin/settings/search_by_page/edit/' . $this->envid1, array(
      'sbp_nodes_min_time' => 1,
      'sbp_nodes_max_time' => 0,
    ), 'Save configuration');
    cache_clear_all('variables', 'cache');
    variable_init();

    // Set search so it only indexes 1 node per cron run.
    variable_set('sbp_cron_limit', 1);

    // Figure out the current index times of the nodes.
    $orig = $this
      ->getIndexTimes();

    // In a loop: run cron, and verify each time that the oldest item
    // (or one of them, if there was a tie) was reindexed.
    for ($i = 0; $i < 10; $i++) {

      // Run cron - should reindex just one node.
      $this
        ->doCronrun();
      $this
        ->drupalLogin($this->superuser);

      // Figure out the current index times of the nodes.
      $new = $this
        ->getIndexTimes();

      // Verify that only one was indexed, and it was the oldest one.
      $this
        ->verifyIndexCycling($orig, $new);
      $orig = $new;
    }
  }

}

/**
 * Functionality tests for Search by Page Users.
 */
class SearchByPageUsersTest extends SearchByPageTester {
  public $usera;
  public $userb;
  public $superuser;
  public static function getInfo() {
    return array(
      'name' => t('Search by Page Users Tests'),
      'description' => t('Test functionality of sbp_users.module'),
      'group' => t('Search by Page'),
      'dependencies' => array(
        'search',
        'sbp_test',
        'sbp_users',
        'dblog',
        'search_by_page',
      ),
    );
  }
  public function setUp() {
    parent::setUp('search', 'search_by_page', 'sbp_users', 'sbp_test', 'dblog');
    $this
      ->setUpEnvironments();

    // Create some random users that won't be found
    $u = $this
      ->drupalCreateUser();
    $u = $this
      ->drupalCreateUser();
    $u = $this
      ->drupalCreateUser();
    $u = $this
      ->drupalCreateUser();

    // Set up two users for searching - just make sure they have different
    // permissions, so they get different roles.
    $this->usera = $this
      ->drupalCreateUser(array(
      'access content',
    ));
    $this->userb = $this
      ->drupalCreateUser(array(
      'access content',
      $this
        ->searchPerm($this->envinfo2),
    ));

    // Set up a user that can see user profiles, to use when indexing.
    $this->indexuser = $this
      ->drupalCreateUser(array(
      'access user profiles',
    ));

    // Verify that this user can see user profiles A and B
    $this
      ->drupalLogin($this->indexuser);
    $this
      ->drupalGet('user/' . $this->usera->uid);
    $this
      ->assertText($this->usera->name, "Indexing user can see user A page");
    $this
      ->drupalGet('user/' . $this->userb->uid);
    $this
      ->assertText($this->userb->name, "Indexing user can see user B page");

    // Set up an admin user and login as that user
    $this->superuser = $this
      ->drupalCreateUser(array(
      'administer nodes',
      'access content',
      'administer content types',
      'administer blocks',
      'administer search',
      'search content',
      'administer search by page',
      'access administration pages',
      $this
        ->searchPerm($this->envinfo2),
      'administer site configuration',
      'administer users',
      'administer permissions',
      'view test private content',
      'access user profiles',
      'access site reports',
    ));
    $this
      ->drupalLogin($this->superuser);

    // Set up so user a is indexed and user b is not.
    // First have to find the role ID that SimpleTest set up.
    // Relies on the role name having the word 'test' in it somewhere.
    $rid = $this
      ->getNewRoleID($this->usera);
    $this
      ->drupalPost('admin/settings/search_by_page/edit/' . $this->envid2, array(
      'sbp_users_roles_indexed[' . $rid . ']' => TRUE,
      'sbp_users_role' => $this
        ->getNewRoleID($this->indexuser),
      'button_label' => t('Search pages'),
    ), 'Save configuration');
    cache_clear_all('variables', 'cache');
    variable_init();
    $this
      ->doCronrun();
    $this
      ->drupalLogin($this->superuser);
    $this
      ->drupalGet('admin/reports/dblog');
    $this
      ->assertText(t('Cron run completed'), 'Log shows cron run completed');
    $this
      ->drupalLogout();
  }

  /**
   * Tests that users can be searched.
   */
  function testSearchUsers() {

    // Search for user a
    $search_path = $this->envinfo2['page_path'];
    $this
      ->drupalLogin($this->superuser);
    $this
      ->drupalPost($search_path, array(
      'keys' => $this->usera->name,
    ), t('Search pages'));

    // Verify we found user a
    $this
      ->assertText($this->usera->name, "User a appears in search results");
    $this
      ->assertLink($this->usera->name, 0, "Link to user a appears in search results");

    // Search for user b
    $this
      ->drupalPost($search_path, array(
      'keys' => $this->userb->name,
    ), t('Search pages'));

    // Verify we did not find user b, and have "no results"
    $this
      ->assertNoText($this->userb->name, "User b does not appear in search results");
    $this
      ->assertText('no results', "No results appears on search results page for user b");
  }

}

/**
 * Tests when users are reindexed.
 */
class SearchByPageUsersReindexTest extends SearchByPageTester {
  public $superuser;
  public $users;
  public $indexuser;
  public $roles;
  public static function getInfo() {
    return array(
      'name' => t('Search by Page Users Reindex'),
      'description' => t('Test reindexing in sbp_users.module'),
      'group' => t('Search by Page'),
      'dependencies' => array(
        'search',
        'sbp_test',
        'sbp_users',
        'dblog',
        'search_by_page',
      ),
    );
  }
  public function setUp() {
    parent::setUp('search', 'search_by_page', 'sbp_users', 'sbp_test', 'dblog');
    $this
      ->setUpEnvironments();

    // Set up five users for searching
    for ($i = 0; $i < 5; $i++) {
      $acct = $this
        ->drupalCreateUser(array(
        'access content',
      ));
      $this->users[] = $acct;
      $this->roles[$this
        ->getNewRoleID($acct)] = 1;
    }

    // Set up a user that can see user profiles, to use when indexing.
    $this->indexuser = $this
      ->drupalCreateUser(array(
      'access user profiles',
    ));
    $this->superuser = $this
      ->drupalCreateUser(array(
      'administer nodes',
      'access content',
      'administer content types',
      'administer blocks',
      'administer search',
      'search content',
      'administer search by page',
      'access administration pages',
      $this
        ->searchPerm($this->envinfo2),
      'administer site configuration',
      'administer users',
      'administer permissions',
      'view test private content',
      'access user profiles',
      'access site reports',
    ));
    $this
      ->drupalLogin($this->superuser);

    // Make sure all our test users are indexed.
    $edit = array(
      'sbp_users_role' => $this
        ->getNewRoleID($this->indexuser),
      'button_label' => t('Search pages'),
    );
    foreach (array_keys($this->roles) as $rid) {
      $edit['sbp_users_roles_indexed[' . $rid . ']'] = TRUE;
    }
    $this
      ->drupalPost('admin/settings/search_by_page/edit/' . $this->envid2, $edit, 'Save configuration');
    cache_clear_all('variables', 'cache');
    variable_init();
    $this
      ->doCronrun();
    $this
      ->drupalLogin($this->superuser);
    $this
      ->drupalGet('admin/reports/dblog');
    $this
      ->assertText(t('Cron run completed'), 'Log shows cron run completed');
    $this
      ->drupalLogout();
  }

  /**
   * Tests that user reindexing happens in the right order on user update.
   */
  function testReindexingOnUpdate() {
    $this
      ->drupalLogin($this->superuser);
    $search_path = $this->envinfo2['page_path'];

    // Set to never reindex automatically.
    $this
      ->drupalPost('admin/settings/search_by_page/edit/' . $this->envid2, array(
      'sbp_users_min_time' => 0,
      'sbp_users_max_time' => 0,
    ), 'Save configuration');
    cache_clear_all('variables', 'cache');
    variable_init();

    // Set search so it only indexes 1 user per cron run.
    variable_set('sbp_cron_limit', 1);

    // Run this test several times...
    for ($j = 0; $j < 10; $j++) {

      // Choose a random user name.
      $newname = $this
        ->randomName();
      $i = rand(0, count($this->users) - 1);
      user_save($this->users[$i], array(
        'name' => $newname,
      ));

      // Verify user can be loaded and has right name.
      $acct = user_load($this->users[$i]->uid);
      $this
        ->assertEqual($acct->name, $newname, "New user name was saved");

      // Verify new name shows on user page
      $this
        ->drupalGet('user/' . $this->users[$i]->uid);
      $this
        ->assertText($newname, 'New user name appears on user page');

      // Verify new name is not searchable.
      $this
        ->drupalPost($search_path, array(
        'keys' => $newname,
      ), t('Search pages'));
      $this
        ->assertNoText($newname, 'New user name not found in search');

      // Run cron - should reindex just this user.
      $this
        ->doCronrun();
      $this
        ->drupalLogin($this->superuser);
      $this
        ->drupalGet('admin/reports/dblog');
      $this
        ->assertText(t('Cron run completed'), 'Log shows cron run completed');

      // Verify new name is searchable.
      $this
        ->drupalPost($search_path, array(
        'keys' => $newname,
      ), t('Search pages'));
      $this
        ->assertText($newname, 'New user name found in search after reindex');
    }
  }

  /**
   * Tests that cycling through user reindexing happens correctly.
   */
  function testReindexingAutomatic() {
    $this
      ->drupalLogin($this->superuser);
    $search_path = $this->envinfo2['page_path'];

    // Set to reindex automatically on normal cycle.
    $this
      ->drupalPost('admin/settings/search_by_page/edit/' . $this->envid2, array(
      'sbp_users_min_time' => 1,
      'sbp_users_max_time' => 0,
    ), 'Save configuration');
    cache_clear_all('variables', 'cache');
    variable_init();

    // Set search so it only indexes 1 user per cron run.
    variable_set('sbp_cron_limit', 1);

    // Figure out the current index times of the users.
    $orig = $this
      ->getIndexTimes();

    // In a loop: run cron, and verify each time that the oldest item
    // (or one of them, if there was a tie) was reindexed.
    for ($i = 0; $i < 10; $i++) {

      // Run cron - should reindex just one node.
      $this
        ->doCronrun();
      $this
        ->drupalLogin($this->superuser);

      // Figure out the current index times of the nodes.
      $new = $this
        ->getIndexTimes();

      // Verify that only one was indexed, and it was the oldest one.
      $this
        ->verifyIndexCycling($orig, $new);
      $orig = $new;
    }
  }

}

/**
 * Functionality tests for Search by Page Paths.
 */
class SearchByPagePathsTest extends SearchByPageTester {
  public $noprivuser;
  public $privuser;
  public $superuser;
  public static function getInfo() {
    return array(
      'name' => t('Search by Page Paths Tests'),
      'description' => t('Test functionality of sbp_paths.module'),
      'group' => t('Search by Page'),
      'dependencies' => array(
        'search',
        'sbp_test',
        'sbp_paths',
        'dblog',
        'search_by_page',
      ),
    );
  }
  public function setUp() {
    parent::setUp('search', 'search_by_page', 'sbp_paths', 'sbp_test', 'dblog');
    $this
      ->setUpEnvironments();
    $this->superuser = $this
      ->drupalCreateUser(array(
      'administer nodes',
      'access content',
      'administer content types',
      'administer blocks',
      'administer search',
      'search content',
      'administer search by page',
      $this
        ->searchPerm($this->envinfo1),
      'access administration pages',
      'administer site configuration',
      'administer users',
      'administer permissions',
      'view test private content',
      'access site reports',
    ));
    $this->noprivuser = $this
      ->drupalCreateUser(array(
      $this
        ->searchPerm($this->envinfo1),
      'access content',
      'search content',
    ));
    $this->privuser = $this
      ->drupalCreateUser(array(
      'access content',
      'search content',
      $this
        ->searchPerm($this->envinfo1),
      'view test private content',
    ));
    $this
      ->drupalLogin($this->superuser);

    // Set up indexing of pages.
    $this
      ->drupalPost('admin/settings/search_by_page/edit/' . $this->envid1, array(
      'button_label' => t('Search pages'),
    ), 'Save configuration');
    $path_add_path = 'admin/settings/search_by_page/edit/' . $this->envid1 . '/paths/add';
    $this
      ->drupalPost($path_add_path, array(
      'path' => 'sbp_test_priv_page',
      'title' => t("Private page"),
      'type' => t('Page'),
      'snippet' => 'yes',
      'role' => $this
        ->getNewRoleID($this->privuser),
    ), 'Create new indexed page');
    $this
      ->drupalPost($path_add_path, array(
      'path' => 'sbp_test_pub_page',
      'title' => t("Public page"),
      'type' => t('Page'),
      'snippet' => 'yes',
      'role' => $this
        ->getNewRoleID($this->noprivuser),
    ), 'Create new indexed page');
    $this
      ->drupalPost($path_add_path, array(
      'path' => 'sbp_test_another_page',
      'title' => t("Public page"),
      'type' => t('Page'),
      'snippet' => t('Trees: Orange and Lemon'),
      'role' => $this
        ->getNewRoleID($this->noprivuser),
    ), 'Create new indexed page');
    $this
      ->drupalPost($path_add_path, array(
      'path' => 'sbp_test_queried_page?a=3',
      'title' => t("Public page with query"),
      'type' => t('Page'),
      'snippet' => 'yes',
      'role' => $this
        ->getNewRoleID($this->noprivuser),
    ), 'Create new indexed page');
    $this
      ->drupalPost($path_add_path, array(
      'path' => 'sbp_test_exclude_page',
      'title' => t("Public page with excluded text"),
      'type' => t('Page'),
      'snippet' => 'yes',
      'role' => $this
        ->getNewRoleID($this->noprivuser),
    ), 'Create new indexed page');
    cache_clear_all('variables', 'cache');
    variable_init();
    $this
      ->doCronrun();
    $this
      ->drupalLogin($this->superuser);
    $this
      ->drupalGet('admin/reports/dblog');
    $this
      ->assertText(t('Cron run completed'), 'Log shows cron run completed');
    $this
      ->drupalLogout();
  }

  /**
   * Tests that pages can be searched.
   */
  function testSearchPages() {

    // Non-privileged user - should only see the public pages
    $search_path = $this->envinfo1['page_path'];
    $this
      ->drupalLogin($this->noprivuser);
    $this
      ->drupalPost($search_path, array(
      'keys' => 'Trees',
    ), t('Search pages'));
    $this
      ->assertText('Trees', "Found Trees on the search results page");
    $this
      ->assertNoText('Pine', "Cannot see private page in search results");
    $this
      ->assertText('Oak', "Can see public page in search results");
    $this
      ->assertText('Orange', "Snippet override is shown");
    $this
      ->assertNoText('Apple', "Overridden excerpt is not shown");
    $this
      ->assertText('Walnut', "Page with query is shown");

    // Privileged user - should see the public and private pages
    $this
      ->drupalLogin($this->privuser);
    $this
      ->drupalPost($search_path, array(
      'keys' => 'Trees',
    ), t('Search pages'));
    $this
      ->assertText('Trees', "Found Trees on the search results page");
    $this
      ->assertText('Pine', "Can see private page in search results");
    $this
      ->assertText('Oak', "Can see public page in search results");
    $this
      ->assertText('Orange', "Snippet override is shown");
    $this
      ->assertNoText('Apple', "Overridden excerpt is not shown");
    $this
      ->assertText('Walnut', "Page with query is shown");
  }

  /**
   * Tests that the text in the excluded tag is actually excluded.
   */
  function testSearchExclusions() {
    $search_path = $this->envinfo1['page_path'];
    $this
      ->drupalLogin($this->noprivuser);
    $this
      ->drupalPost($search_path, array(
      'keys' => 'Trees',
    ), t('Search pages'));
    $this
      ->assertNoText('Poplar', "Excluded text is not shown in search for Trees");
    $this
      ->assertText('Cottonwood', "Non-excluded text is shown in search for Trees");
    $this
      ->drupalPost($search_path, array(
      'keys' => 'Poplar',
    ), t('Search pages'));
    $this
      ->assertNoText('Poplar', "Excluded text is not shown in search for excluded text");
    $this
      ->assertNoText('Trees', "Trees is not shown in search for excluded text");
    $this
      ->assertNoText('Cottonwood', "Non-excluded text is not shown in search for excluded text");
  }

}

/**
 * Tests for Search by Page Paths - searching nodes.
 */
class SearchByPagePathsNodesTest extends SearchByPageTester {
  public $superuser;
  public static function getInfo() {
    return array(
      'name' => t('Search by Page Paths Tests for Nodes'),
      'description' => t('Test node indexing/searching of sbp_paths.module'),
      'group' => t('Search by Page'),
      'dependencies' => array(
        'search',
        'sbp_test',
        'sbp_paths',
        'dblog',
        'search_by_page',
      ),
    );
  }
  public function setUp() {
    parent::setUp('search', 'search_by_page', 'sbp_paths', 'sbp_test', 'dblog');
    $this
      ->setUpEnvironments();
    $this->superuser = $this
      ->drupalCreateUser(array(
      'administer nodes',
      'access content',
      'administer blocks',
      'administer search',
      'search content',
      'administer search by page',
      'access administration pages',
      $this
        ->searchPerm($this->envinfo2),
      'administer site configuration',
      'administer users',
      'administer permissions',
      'administer filters',
      'access site reports',
    ));
    $this
      ->drupalLogin($this->superuser);

    // Set up Search by Page button name
    $this
      ->drupalPost('admin/settings/search_by_page/edit/' . $this->envid2, array(
      'button_label' => t('Search pages'),
    ), 'Save configuration');
    cache_clear_all('variables', 'cache');
    variable_init();

    // Throw in a few nodes that won't match our tests.
    $info = array(
      'body' => 'blah',
      'teaser' => 'blah',
      'title' => 'blah',
    );
    $this
      ->drupalCreateNode($info);
    $this
      ->drupalCreateNode($info);
    $this
      ->drupalCreateNode($info);
    $this
      ->drupalCreateNode($info);

    // Create some content with different input formats and add to SBP Paths.
    // Also verify that menu_execute_active_handler() can find the pages.
    $info = array(
      'body' => 'I walk through the streets, looking around for trouble',
      'teaser' => 'I walk on a path, where it is quiet',
      'type' => 'page',
      'format' => 1,
    );
    $node = $this
      ->drupalCreateNode($info);
    $content = menu_execute_active_handler('node/' . $node->nid);
    $this
      ->assertTrue($content, "First node content is not empty");
    $this
      ->assertFalse(is_int($content), "First node content is not an integer");
    $path_add_path = 'admin/settings/search_by_page/edit/' . $this->envid2 . '/paths/add';
    $this
      ->drupalPost($path_add_path, array(
      'path' => 'node/' . $node->nid,
      'title' => t($node->title),
      'type' => t('Page'),
      'snippet' => 'yes',
      'role' => $this
        ->getNewRoleID($this->superuser),
    ), 'Create new indexed page');
    $info = array(
      'body' => 'I can walk really far, maybe even to the north pole.',
      'teaser' => 'I will walk to the south pole.',
      'type' => 'page',
      'format' => 2,
    );
    $node = $this
      ->drupalCreateNode($info);
    $content = menu_execute_active_handler('node/' . $node->nid);
    $this
      ->assertTrue($content, "Second node content is not empty");
    $this
      ->assertFalse(is_int($content), "Second node content is not an integer");
    $this
      ->drupalPost($path_add_path, array(
      'path' => 'node/' . $node->nid,
      'title' => t($node->title),
      'type' => t('Page'),
      'snippet' => 'yes',
      'role' => $this
        ->getNewRoleID($this->superuser),
    ), 'Create new indexed page');
    $this
      ->doCronrun();
    $this
      ->drupalLogin($this->superuser);
    $this
      ->drupalGet('admin/reports/dblog');
    $this
      ->assertText(t('Cron run completed'), 'Log shows cron run completed');
    $this
      ->drupalLogout();
  }

  /**
   * Tests that pages can be searched.
   */
  function testSearchPages() {

    // Search for 'walk' - should find both pages
    $search_path = $this->envinfo2['page_path'];
    $this
      ->drupalLogin($this->superuser);
    $this
      ->drupalPost($search_path, array(
      'keys' => 'walk',
    ), t('Search pages'));
    $this
      ->assertText('walk', "Walk appears in search results for walk");
    $this
      ->assertText('streets', "First page was found");
    $this
      ->assertText('north', "Second page was found");
  }

}

/**
 * Tests for Search by Page Paths - searching nodes with aliases.
 */
class SearchByPagePathsAliasTest extends SearchByPageTester {
  public $superuser;
  public static function getInfo() {
    return array(
      'name' => t('Search by Page Paths Tests for Aliases'),
      'description' => t('Tests that path aliases can be used in sbp_paths.module'),
      'group' => t('Search by Page'),
      'dependencies' => array(
        'search',
        'sbp_test',
        'sbp_paths',
        'dblog',
        'search_by_page',
      ),
    );
  }
  public function setUp() {
    parent::setUp('search', 'search_by_page', 'sbp_paths', 'sbp_test', 'path', 'dblog');
    $this
      ->setUpEnvironments();
    $this->superuser = $this
      ->drupalCreateUser(array(
      'administer nodes',
      'access content',
      'administer blocks',
      'administer search',
      'search content',
      'administer search by page',
      'access administration pages',
      $this
        ->searchPerm($this->envinfo1),
      'administer site configuration',
      'administer users',
      'administer permissions',
      'administer url aliases',
      'create url aliases',
      'access site reports',
    ));
    $this
      ->drupalLogin($this->superuser);

    // Set up Search by Page button name
    $this
      ->drupalPost('admin/settings/search_by_page/edit/' . $this->envid1, array(
      'button_label' => t('Search pages'),
    ), 'Save configuration');
    cache_clear_all('variables', 'cache');
    variable_init();

    // Throw in a few nodes that won't match our tests.
    $info = array(
      'body' => 'blah',
      'teaser' => 'blah',
      'title' => 'blah',
    );
    $this
      ->drupalCreateNode($info);
    $this
      ->drupalCreateNode($info);
    $this
      ->drupalCreateNode($info);
    $this
      ->drupalCreateNode($info);

    // Create some content with a path alias and add to SBP Paths.
    $info = array(
      'body' => 'I walk through the streets, looking around for trouble',
      'teaser' => 'I walk on a path, where it is quiet',
      'type' => 'page',
    );
    $node = $this
      ->drupalCreateNode($info);
    $alias = $this
      ->randomName();
    $this
      ->drupalPost('admin/build/path/add', array(
      'src' => 'node/' . $node->nid,
      'dst' => $alias,
    ), t('Create new alias'));
    $path_add_path = 'admin/settings/search_by_page/edit/' . $this->envid1 . '/paths/add';
    $this
      ->drupalPost($path_add_path, array(
      'path' => $alias,
      'title' => t($node->title),
      'type' => t('Page'),
      'snippet' => 'yes',
      'role' => $this
        ->getNewRoleID($this->superuser),
    ), 'Create new indexed page');
    $this
      ->doCronrun();
    $this
      ->drupalLogin($this->superuser);
    $this
      ->drupalGet('admin/reports/dblog');
    $this
      ->assertText(t('Cron run completed'), 'Log shows cron run completed');
    $this
      ->drupalLogout();
  }

  /**
   * Tests that aliased page can be searched.
   */
  function testSearchPage() {

    // Search for 'walk' - should find the page
    $search_path = $this->envinfo1['page_path'];
    $this
      ->drupalLogin($this->superuser);
    $this
      ->drupalPost($search_path, array(
      'keys' => 'walk',
    ), t('Search pages'));
    $this
      ->assertText('walk', "Walk appears in search results for walk");
    $this
      ->assertText('streets', "Aliased page was found");
  }

}

/**
 * Functionality test for removing paths from Search by Page Paths.
 */
class SearchByPagePathsRemoveTest extends SearchByPageTester {
  public $noprivuser;
  public $privuser;
  public $superuser;
  public static function getInfo() {
    return array(
      'name' => t('Search by Page Paths Remove Tests'),
      'description' => t('Test functionality of sbp_paths.module when removing paths.'),
      'group' => t('Search by Page'),
      'dependencies' => array(
        'search',
        'sbp_test',
        'sbp_paths',
        'dblog',
        'search_by_page',
      ),
    );
  }
  public function setUp() {
    parent::setUp('search', 'search_by_page', 'sbp_paths', 'sbp_test', 'dblog');
    $this
      ->setUpEnvironments();
    $this->superuser = $this
      ->drupalCreateUser(array(
      'administer nodes',
      'access content',
      'administer content types',
      'administer blocks',
      'administer search',
      'search content',
      'administer search by page',
      $this
        ->searchPerm($this->envinfo1),
      'access administration pages',
      'administer site configuration',
      'administer users',
      'administer permissions',
      'view test private content',
      'access site reports',
    ));
    $this->noprivuser = $this
      ->drupalCreateUser(array(
      $this
        ->searchPerm($this->envinfo1),
      'access content',
      'search content',
    ));
    $this->privuser = $this
      ->drupalCreateUser(array(
      'access content',
      'search content',
      $this
        ->searchPerm($this->envinfo1),
      'view test private content',
    ));
    $this
      ->drupalLogin($this->superuser);

    // Set up indexing of pages.
    $this
      ->drupalPost('admin/settings/search_by_page/edit/' . $this->envid1, array(
      'button_label' => t('Search pages'),
    ), 'Save configuration');
    $path_add_path = 'admin/settings/search_by_page/edit/' . $this->envid1 . '/paths/add';
    $this
      ->drupalPost($path_add_path, array(
      'path' => 'sbp_test_priv_page',
      'title' => t("Private page"),
      'type' => t('Page'),
      'snippet' => 'yes',
      'role' => $this
        ->getNewRoleID($this->privuser),
    ), 'Create new indexed page');
    $this
      ->drupalPost($path_add_path, array(
      'path' => 'sbp_test_pub_page',
      'title' => t("Public page"),
      'type' => t('Page'),
      'snippet' => 'yes',
      'role' => $this
        ->getNewRoleID($this->noprivuser),
    ), 'Create new indexed page');
    $this
      ->drupalPost($path_add_path, array(
      'path' => 'sbp_test_another_page',
      'title' => t("Public page"),
      'type' => t('Page'),
      'snippet' => t('Trees: Orange and Lemon'),
      'role' => $this
        ->getNewRoleID($this->noprivuser),
    ), 'Create new indexed page');
    cache_clear_all('variables', 'cache');
    variable_init();
    $this
      ->doCronrun();
    $this
      ->drupalLogin($this->superuser);
    $this
      ->drupalGet('admin/reports/dblog');
    $this
      ->assertText(t('Cron run completed'), 'Log shows cron run completed');

    // Assuming that the regular tests worked, we know at this point that
    // these pages will have been indexed. So now remove two of the pages
    // from SBP Paths, and we'll test that they can no longer be found.
    $this
      ->drupalLogin($this->superuser);
    $path_del_path = 'admin/settings/search_by_page/edit/' . $this->envid1 . '/paths/delete/';
    $this
      ->drupalPost($path_del_path . '1', array(), t('Confirm'));
    $this
      ->drupalPost($path_del_path . '2', array(), t('Confirm'));
  }

  /**
   * Tests that pages can be searched.
   */
  function testSearchPages() {

    // Privileged user - should see the one remaining page.
    $search_path = $this->envinfo1['page_path'];
    $this
      ->drupalLogin($this->privuser);
    $this
      ->drupalPost($search_path, array(
      'keys' => 'Trees',
    ), t('Search pages'));
    $this
      ->assertText('Trees', "Found Trees on the search results page");
    $this
      ->assertNoText('Pine', "Cannot see first deleted page in search results");
    $this
      ->assertNoText('Oak', "Cannot see second deleted page in search results");
    $this
      ->assertText('Orange', "Can see third page in search results");
  }

}

/**
 * Reindexing test for Search by Page Paths.
 */
class SearchByPagePathsReindexTest extends SearchByPageTester {
  public $noprivuser;
  public $privuser;
  public $superuser;
  public static function getInfo() {
    return array(
      'name' => t('Search by Page Paths Reindex Tests'),
      'description' => t('Test reindexing of sbp_paths.module.'),
      'group' => t('Search by Page'),
      'dependencies' => array(
        'search',
        'sbp_test',
        'sbp_paths',
        'dblog',
        'search_by_page',
      ),
    );
  }
  public function setUp() {
    parent::setUp('search', 'search_by_page', 'sbp_paths', 'sbp_test', 'dblog');
    $this
      ->setUpEnvironments();
    $this->superuser = $this
      ->drupalCreateUser(array(
      'administer nodes',
      'access content',
      'administer content types',
      'administer blocks',
      'administer search',
      'search content',
      'administer search by page',
      $this
        ->searchPerm($this->envinfo1),
      'access administration pages',
      'administer site configuration',
      'administer users',
      'administer permissions',
      'view test private content',
      'access site reports',
    ));
    $this->noprivuser = $this
      ->drupalCreateUser(array(
      $this
        ->searchPerm($this->envinfo1),
      'access content',
      'search content',
    ));
    $this->privuser = $this
      ->drupalCreateUser(array(
      'access content',
      'search content',
      $this
        ->searchPerm($this->envinfo1),
      'view test private content',
    ));
    $this
      ->drupalLogin($this->superuser);

    // Set up indexing of pages.
    $this
      ->drupalPost('admin/settings/search_by_page/edit/' . $this->envid1, array(
      'button_label' => t('Search pages'),
    ), 'Save configuration');
    $path_add_path = 'admin/settings/search_by_page/edit/' . $this->envid1 . '/paths/add';
    $this
      ->drupalPost($path_add_path, array(
      'path' => 'sbp_test_priv_page',
      'title' => t("Private page"),
      'type' => t('Page'),
      'snippet' => 'yes',
      'role' => $this
        ->getNewRoleID($this->privuser),
    ), 'Create new indexed page');
    $this
      ->drupalPost($path_add_path, array(
      'path' => 'sbp_test_pub_page',
      'title' => t("Public page"),
      'type' => t('Page'),
      'snippet' => 'yes',
      'role' => $this
        ->getNewRoleID($this->noprivuser),
    ), 'Create new indexed page');
    $this
      ->drupalPost($path_add_path, array(
      'path' => 'sbp_test_another_page',
      'title' => t("Public page"),
      'type' => t('Page'),
      'snippet' => t('Trees: Orange and Lemon'),
      'role' => $this
        ->getNewRoleID($this->noprivuser),
    ), 'Create new indexed page');
    cache_clear_all('variables', 'cache');
    variable_init();
    $this
      ->doCronrun();
    $this
      ->drupalLogin($this->superuser);
    $this
      ->drupalGet('admin/reports/dblog');
    $this
      ->assertText(t('Cron run completed'), 'Log shows cron run completed');
  }

  /**
   * Tests that cycling through path reindexing happens correctly.
   */
  function testReindexingAutomatic() {
    $this
      ->drupalLogin($this->superuser);
    $search_path = $this->envinfo1['page_path'];

    // Set to reindex automatically on normal cycle.
    $this
      ->drupalPost('admin/settings/search_by_page/edit/' . $this->envid1, array(
      'sbp_paths_min_time' => 1,
      'sbp_paths_max_time' => 0,
    ), 'Save configuration');
    cache_clear_all('variables', 'cache');
    variable_init();

    // Set search so it only indexes 1 attachment per cron run.
    variable_set('sbp_cron_limit', 1);

    // Figure out the current index times of the attachments.
    $orig = $this
      ->getIndexTimes();

    // In a loop: run cron, and verify each time that the oldest item
    // (or one of them, if there was a tie) was reindexed.
    for ($i = 0; $i < 10; $i++) {

      // Run cron - should reindex just one path.
      $this
        ->doCronrun();
      $this
        ->drupalLogin($this->superuser);

      // Figure out the current index times of the paths.
      $new = $this
        ->getIndexTimes();

      // Verify that only one was indexed, and it was the oldest one.
      $this
        ->verifyIndexCycling($orig, $new);
      $orig = $new;
    }
  }

}

/**
 * Functionality test 1 for Search by Page Attachments with Uploads module.
 */
class SearchByPageAttachUploadsTest extends SearchByPageTester {
  public $superuser;
  public $noprivuser;
  public static function getInfo() {
    return array(
      'name' => t('Search by Page Attach with Upload Test 1'),
      'description' => t('Test functionality of sbp_attach.module with Upload module. Note that this test assumes you have uploaded the Search Files API module, and it also assumes that the default configuration of the Search Files API module "text helper" will work.'),
      'group' => t('Search by Page'),
      'dependencies' => array(
        'search',
        'sbp_test',
        'sbp_attach',
        'upload',
        'search_files',
        'dblog',
        'search_by_page',
      ),
    );
  }
  public function setUp() {
    parent::setUp('search', 'search_by_page', 'sbp_attach', 'upload', 'search_files', 'sbp_test', 'dblog');

    // Note: I think SimpleTest inherits the default node access from the
    // base system. Needs to be rebuilt in order for the access stuff to work!
    node_access_rebuild();
    $this
      ->setUpEnvironments();
    $this
      ->setUpUsers($this->envinfo2);
    $this
      ->setUpTypes();
    $this
      ->makeContent();

    // Set up so "sbp_indexed" node attachments are searchable and
    // "sbp_hidden" nodes are not. Also make it so only listed files are
    // searchable.
    $this
      ->drupalPost('admin/settings/search_by_page/edit/' . $this->envid2, array(
      'sbp_attach_node_types[]' => 'sbp_indexed',
      'sbp_attach_only_listed' => TRUE,
      'sbp_attach_prepend_node_title' => FALSE,
      'sbp_attach_title_sep' => " bush ",
      'sbp_attach_use_description' => FALSE,
      'button_label' => t('Search pages'),
    ), 'Save configuration');
    cache_clear_all('variables', 'cache');
    variable_init();
    $this
      ->doCronrun();
    $this
      ->drupalLogin($this->superuser);
    $this
      ->drupalGet('admin/reports/dblog');
    $this
      ->assertText(t('Cron run completed'), 'Log shows cron run completed');
    $this
      ->drupalLogout();
  }

  /**
   * Tests that attachments are searched, and permissions, and display options.
   */
  function testSearchAttach() {
    $this
      ->drupalLogin($this->superuser);
    $search_path = $this->envinfo2['page_path'];

    // Search for the word 'flowers'
    $this
      ->drupalPost($search_path, array(
      'keys' => 'flowers',
    ), t('Search pages'));

    // Should find just the one listed attachment
    $this
      ->assertText('flowers', "Flowers appears in search results for flowers");
    $this
      ->assertText('daisy', "First attachment was found");
    $this
      ->assertNoText('snapdragon', "Second attachment was not found");
    $this
      ->assertNoText('dahlia', "Third attachment was not found");

    // Non-privileged user
    $this
      ->drupalLogin($this->noprivuser);

    // Search for the word 'flowers'
    $this
      ->drupalPost($search_path, array(
      'keys' => 'flowers',
    ), t('Search pages'));

    // Should find no attachments
    $this
      ->assertNoText('flowers', "Flowers does not appear in search results for flowers");
    $this
      ->assertNoText('daisy', "First attachment was not found");
    $this
      ->assertNoText('snapdragon', "Second attachment was not found");
    $this
      ->assertNoText('dahlia', "Third attachment was not found");

    // Display options section...
    $this
      ->drupalLogin($this->superuser);

    // Set display options so it should have attachment file name only
    $this
      ->setDisplayOptions(FALSE, " bush ", FALSE, $this->envid2);

    // Search for the word 'flowers'
    $this
      ->drupalPost($search_path, array(
      'keys' => 'flowers',
    ), t('Search pages'));

    // Verify display options
    $this
      ->assertText('attach1.txt', "File name shown");
    $this
      ->assertNoText('foods', "Page title not shown");
    $this
      ->assertNoText('bush', "Separator not shown");
    $this
      ->assertNoText('lonely', "Description not shown");

    // Verify that the upper-case extension was also found.
    $this
      ->assertText('attach5.TXT', "File name shown for upper-case extension");

    // Set display options so it should have page title shown with separator
    $this
      ->setDisplayOptions(TRUE, " bush ", FALSE, $this->envid2);

    // Search for the word 'flowers'
    $this
      ->drupalPost($search_path, array(
      'keys' => 'flowers',
    ), t('Search pages'));

    // Verify display options
    $this
      ->assertText('attach1.txt', "File name shown");
    $this
      ->assertText('foods', "Page title shown");
    $this
      ->assertText('bush', "Separator shown");
    $this
      ->assertNoText('lonely', "Description not shown");

    // Set display options so it should have description, no page title
    $this
      ->setDisplayOptions(FALSE, " bush ", TRUE, $this->envid2);

    // Search for the word 'flowers'
    $this
      ->drupalPost($search_path, array(
      'keys' => 'flowers',
    ), t('Search pages'));

    // Verify display options
    $this
      ->assertNoText('attach1.txt', "File name not shown");
    $this
      ->assertNoText('foods', "Page title not shown");
    $this
      ->assertNoText('bush', "Separator not shown");
    $this
      ->assertText('lonely', "Description shown");
  }

  /**
   * Attaches a file to a node, using Upload module.
   *
   * @param $node
   *   Node object to attach to.
   * @param $filename
   *   File name, not including path (assumed to be in test directory).
   * @param $listed
   *   Whether to mark as listed (TRUE) or not (FALSE).
   * @param $desc
   *   Description to put on the file upload.
   */
  public function attachFileUpload($node, $filename, $listed, $desc) {
    $path = realpath(drupal_get_path('module', 'search_by_page') . "/tests/" . $filename);

    // First attach the file.
    $this
      ->drupalPost('node/' . $node->nid . '/edit', array(
      'files[upload]' => $path,
    ), t('Save'));

    // Find the file ID of the file we just uploaded
    $node = node_load($node->nid, NULL, TRUE);
    $thisfid = 0;
    foreach ($node->files as $fid => $stuff) {
      if ($stuff->filename == $filename) {
        $thisfid = $fid;
        break;
      }
    }
    $this
      ->assertTrue($thisfid > 0, "Found the file ID for uploaded file");

    // Now go back and edit node again, updating listed and description.
    $this
      ->drupalPost('node/' . $node->nid . '/edit', array(
      'files[' . $thisfid . '][list]' => $listed,
      'files[' . $thisfid . '][description]' => $desc,
    ), t('Save'));
  }

  /**
   * Sets up the content types to allow uploads.
   */
  public function setUpTypes() {

    // Set the content types to allow uploads
    $info = array(
      'upload' => TRUE,
    );
    $this
      ->drupalPost('admin/content/node-type/sbp-indexed', $info, t('Save content type'));
    $this
      ->drupalPost('admin/content/node-type/sbp-hidden', $info, t('Save content type'));
  }

  /**
   * Makes 2 nodes with attachments, for search testing.
   */
  public function makeContent() {

    // Throw in a few nodes that won't match our tests.
    $info = array(
      'body' => 'blah',
      'teaser' => 'blah',
      'title' => 'blah',
    );
    $this
      ->drupalCreateNode($info);
    $this
      ->drupalCreateNode($info);
    $this
      ->drupalCreateNode($info);
    $this
      ->drupalCreateNode($info);
    $info = array(
      'title' => 'Favorite foods',
      'body' => 'I eat pizza every day.',
      'type' => 'sbp_indexed',
    );
    $node = $this
      ->drupalCreateNode($info);
    $this
      ->attachFileUpload($node, 'attach1.txt', TRUE, 'A very lonely file');
    $this
      ->attachFileUpload($node, 'attach2.txt', FALSE, 'A very happy file');
    $this
      ->attachFileUpload($node, 'attach5.TXT', TRUE, 'An upper-case file');
    $info = array(
      'title' => 'Favorite cars',
      'body' => 'I drive a hatchback.',
      'type' => 'sbp_hidden',
    );
    $node = $this
      ->drupalCreateNode($info);
    $this
      ->attachFileUpload($node, 'attach3.txt', TRUE, 'A very pretty file');

    // Configure Search Files API helpers
    $this
      ->drupalPost('admin/settings/search_files/helpers/autodetect', array(), t('Autodetect'));
    $this
      ->drupalGet('admin/settings/search_files/helpers/list');
    $this
      ->assertText('Text files', 'Text file helper for Search Files set up (without this, no file searching is possible)');
    $this
      ->assertText('Good', 'Safe mode message found (without this, no file searching is possible)');
  }

  /**
   * Sets up superuser and low-privilege user.
   *
   * Assumes environments have been set up first.
   *
   * @param $env
   *   Search by Page environment ID to set up permissions for.
   */
  public function setUpUsers($env) {
    $this->superuser = $this
      ->drupalCreateUser(array(
      'administer nodes',
      'access content',
      'administer content types',
      'administer blocks',
      'administer search',
      'search content',
      'administer search by page',
      'access administration pages',
      $this
        ->searchPerm($env),
      'administer site configuration',
      'administer users',
      'administer permissions',
      'view test private content',
      'view uploaded files',
      'administer search_files configuration',
      'upload files',
      'access site reports',
    ));
    $this->noprivuser = $this
      ->drupalCreateUser(array(
      'access content',
      $this
        ->searchPerm($env),
      'search content',
    ));
    $this
      ->drupalLogin($this->superuser);
  }

  /**
   * Sets display options for Search by Page Attachments.
   *
   * @param $pre_title
   *   TRUE to prepend node title, FALSE to not do so.
   * @param $sep
   *   Separator to use between node title and file name.
   * @param $use_desc
   *   TRUE to replace file name with description, FALSE to not do so.
   * @param $env
   *   ID of Search by Page environment to use.
   */
  function setDisplayOptions($pre_title, $sep, $use_desc, $env) {
    $this
      ->drupalPost('admin/settings/search_by_page/edit/' . $env, array(
      'sbp_attach_prepend_node_title' => $pre_title,
      'sbp_attach_title_sep' => $sep,
      'sbp_attach_use_description' => $use_desc,
    ), 'Save configuration');

    // Reset variables, because Drupal doesn't realize they could be
    // reset within the same PHP session... sigh.
    cache_clear_all('variables', 'cache');
    variable_init();

    // Verify settings
    $this
      ->assertEqual(search_by_page_setting_get('sbp_attach_prepend_node_title', $env, 0), $pre_title, 'Prepend node title is set correctly');
    $this
      ->assertEqual(search_by_page_setting_get('sbp_attach_use_description', $env, 0), $use_desc, 'Use description is set correctly');
    $this
      ->assertEqual(search_by_page_setting_get('sbp_attach_title_sep', $env, "/"), $sep, 'Separator is set correctly');
  }

}

/**
 * Functionality test 2 for Search by Page Attachments with Uploads module.
 */
class SearchbyPageAttachUploads2Test extends SearchByPageAttachUploadsTest {
  public static function getInfo() {
    return array(
      'name' => t('Search by Page Attach with Upload Test 2'),
      'description' => t('Test functionality of sbp_attach.module with Upload module. Note that this test assumes you have uploaded the Search Files API module, and it also assumes that the default configuration of the Search Files API module "text helper" will work.'),
      'group' => t('Search by Page'),
      'dependencies' => array(
        'search',
        'sbp_test',
        'sbp_attach',
        'upload',
        'search_files',
        'dblog',
        'search_by_page',
      ),
    );
  }
  public function setUp() {
    DrupalWebTestCase::setUp('search', 'search_by_page', 'sbp_attach', 'upload', 'search_files', 'sbp_test', 'dblog');

    // Note: I think SimpleTest inherits the default node access from the
    // base system. Needs to be rebuilt in order for the access stuff to work!
    node_access_rebuild();
    $this
      ->setUpEnvironments();
    $this
      ->setUpUsers($this->envinfo1);
    $this
      ->setUpTypes();
    $this
      ->makeContent();

    // Set up so "sbp_indexed" node attachments are searchable and
    // "sbp_hidden" attachments are not. Also make it so both listed and
    // unlisted files are searchable (functionality test 1 did only listed
    // files).
    // NOTE: When posting to a page with checkboxes, it is VITAL to pass in
    // FALSE rather than 0 for the value, if you want to unset the checkbox!
    $this
      ->drupalPost('admin/settings/search_by_page/edit/' . $this->envid1, array(
      'sbp_attach_node_types[]' => 'sbp_indexed',
      'sbp_attach_only_listed' => FALSE,
      'sbp_attach_prepend_node_title' => FALSE,
      'sbp_attach_title_sep' => " bush ",
      'sbp_attach_use_description' => FALSE,
      'button_label' => t('Search pages'),
    ), 'Save configuration');
    cache_clear_all('variables', 'cache');
    variable_init();
    $this
      ->assertEqual(search_by_page_setting_get('sbp_attach_only_listed', $this->envid1, 0), 0, 'Search only listed files is set to FALSE');
    $this
      ->doCronrun();
    $this
      ->drupalLogin($this->superuser);
    $this
      ->drupalGet('admin/reports/dblog');
    $this
      ->assertText(t('Cron run completed'), 'Log shows cron run completed');
    $this
      ->drupalLogout();
  }

  /**
   * Tests that attachments are searched, and permissions.
   */
  function testSearchAttach() {
    $this
      ->drupalLogin($this->superuser);
    $search_path = $this->envinfo1['page_path'];

    // Search for the word 'flowers'
    $this
      ->drupalPost($search_path, array(
      'keys' => 'flowers',
    ), t('Search pages'));

    // Should find both listed attachments on the first node
    $this
      ->assertText('flowers', "Flowers appears in search results for flowers");
    $this
      ->assertText('daisy', "First attachment was found");
    $this
      ->assertText('snapdragon', "Second attachment was found");
    $this
      ->assertNoText('dahlia', "Third attachment was not found");
  }

}

/**
 * Functionality test 1 for Search by Page Attachments with CCK module.
 */
class SearchByPageAttachCCKTest extends SearchByPageAttachUploadsTest {
  public static function getInfo() {
    return array(
      'name' => t('Search by Page Attach CCK Test 1'),
      'description' => t('Test functionality of sbp_attach.module with CCK FileField module. Note that this test assumes you have uploaded the Search Files API, CCK, and FileFields modules, and it also assumes that the default configuration of the Search Files API module "text helper" will work.'),
      'group' => t('Search by Page'),
      'dependencies' => array(
        'search',
        'sbp_test',
        'sbp_attach',
        'content',
        'filefield',
        'search_files',
        'dblog',
        'search_by_page',
      ),
    );
  }
  public function setUp() {
    DrupalWebTestCase::setUp('search', 'search_by_page', 'sbp_attach', 'content', 'filefield', 'search_files', 'sbp_test', 'dblog');

    // Note: I think SimpleTest inherits the default node access from the
    // base system. Needs to be rebuilt in order for the access stuff to work!
    node_access_rebuild();
    $this
      ->setUpEnvironments();
    $this
      ->setUpUsers($this->envinfo1);
    $this
      ->setUpTypes();
    $this
      ->makeContent();

    // Set up so "sbp_indexed" node attachments are searchable and
    // "sbp_hidden" nodes are not. Make sure our file field is searchable.
    // Also make it so only listed files are searchable.
    $this
      ->drupalPost('admin/settings/search_by_page/edit/' . $this->envid1, array(
      'sbp_attach_node_types[]' => 'sbp_indexed',
      'sbp_attach_field_types[]' => 'field_myfile',
      'sbp_attach_only_listed' => TRUE,
      'sbp_attach_prepend_node_title' => FALSE,
      'sbp_attach_title_sep' => " bush ",
      'sbp_attach_use_description' => FALSE,
      'button_label' => t('Search pages'),
    ), 'Save configuration');
    cache_clear_all('variables', 'cache');
    variable_init();
    $types = search_by_page_setting_get('sbp_attach_node_types', $this->envid1, array());
    $this
      ->assertTrue($types['sbp_indexed'], "sbp_indexed is indexed");
    $this
      ->assertTrue(!isset($types['sbp_hidden']) || !$types['sbp_hidden'], "sbp_hidden is hidden");
    $this
      ->doCronrun();
    $this
      ->drupalLogin($this->superuser);
    $this
      ->drupalGet('admin/reports/dblog');
    $this
      ->assertText(t('Cron run completed'), 'Log shows cron run completed');
    $this
      ->drupalLogout();
  }

  /**
   * Tests that attachments are searched, and display options.
   */
  function testSearchAttach() {
    $this
      ->drupalLogin($this->superuser);
    $search_path = $this->envinfo1['page_path'];

    // Search for the word 'flowers'
    $this
      ->drupalPost($search_path, array(
      'keys' => 'flowers',
    ), t('Search pages'));

    // Should find just the one listed attachment
    $this
      ->assertText('flowers', "Flowers appears in search results for flowers");
    $this
      ->assertText('daisy', "First attachment was found");
    $this
      ->assertNoText('snapdragon', "Second attachment was not found");
    $this
      ->assertNoText('dahlia', "Third attachment was not found");

    // Display options section...
    // Set display options so it should have attachment file name only
    $this
      ->setDisplayOptions(FALSE, " bush ", FALSE, $this->envid1);

    // Search for the word 'flowers'
    $this
      ->drupalPost($search_path, array(
      'keys' => 'flowers',
    ), t('Search pages'));

    // Verify display options
    $this
      ->assertText('attach1.txt', "File name shown");
    $this
      ->assertNoText('foods', "Page title not shown");
    $this
      ->assertNoText('bush', "Separator not shown");
    $this
      ->assertNoText('lonely', "Description not shown");

    // Set display options so it should have page title shown with separator
    $this
      ->setDisplayOptions(TRUE, " bush ", FALSE, $this->envid1);

    // Search for the word 'flowers'
    $this
      ->drupalPost($search_path, array(
      'keys' => 'flowers',
    ), t('Search pages'));

    // Verify display options
    $this
      ->assertText('attach1.txt', "File name shown");
    $this
      ->assertText('foods', "Page title shown");
    $this
      ->assertText('bush', "Separator shown");
    $this
      ->assertNoText('lonely', "Description not shown");

    // Set display options so it should have description, no page title
    $this
      ->setDisplayOptions(FALSE, " bush ", TRUE, $this->envid1);

    // Search for the word 'flowers'
    $this
      ->drupalPost($search_path, array(
      'keys' => 'flowers',
    ), t('Search pages'));

    // Verify display options
    $this
      ->assertNoText('attach1.txt', "File name not shown");
    $this
      ->assertNoText('foods', "Page title not shown");
    $this
      ->assertNoText('bush', "Separator not shown");
    $this
      ->assertText('lonely', "Description shown");
  }

  /**
   * Sets up superuser and low-privilege user.
   */
  public function setUpUsers($env) {
    $this->superuser = $this
      ->drupalCreateUser(array(
      'administer nodes',
      'access content',
      'administer content types',
      'administer blocks',
      'administer search',
      'search content',
      'administer search by page',
      'access administration pages',
      $this
        ->searchPerm($env),
      'administer site configuration',
      'administer users',
      'administer permissions',
      'view test private content',
      'administer search_files configuration',
      'access site reports',
    ));
    $this->noprivuser = $this
      ->drupalCreateUser(array(
      'access content',
      $this
        ->searchPerm($env),
      'search content',
    ));
    $this
      ->drupalLogin($this->superuser);
  }

  /**
   * Attaches a file to a node, using CCK module.
   *
   * @param $node
   *   Node object to attach to.
   * @param $filename
   *   File name, not including path (assumed to be in test directory).
   * @param $listed
   *   Whether to mark as listed (TRUE) or not (FALSE).
   * @param $desc
   *   Description to put on the file upload.
   */
  public function attachFileUpload($node, $filename, $listed, $desc) {
    $path = realpath(drupal_get_path('module', 'search_by_page') . "/tests/" . $filename);
    $node = node_load($node->nid, NULL, TRUE);

    // Save any previous file information.
    $savefiles = $node->field_myfile;

    // Attach the file.
    $this
      ->drupalPost('node/' . $node->nid . '/edit', array(
      'files[field_myfile_3]' => $path,
    ), t('Save'));

    // Find the file we just uploaded and add description.
    $node = node_load($node->nid, NULL, TRUE);
    $thisfid = 0;
    $thisindex = 0;
    foreach ($node->field_myfile as $stuff) {
      if ($stuff['filename'] == $filename) {
        $node->field_myfile[$thisindex]['list'] = $listed;
        $tmp = array(
          'description' => $desc,
        );
        $node->field_myfile[$thisindex]['data'] = $tmp;
        $thisfid = $node->field_myfile[$thisindex]['fid'];
      }
      else {

        // Something bad is happening to the description when we save above,
        // and I'm not sure why, but...
        $node->field_myfile[$thisindex]['data'] = $savefiles[$thisindex]['data'];
      }
      $thisindex++;
    }
    $this
      ->assertTrue($thisfid > 0, "Found the file ID for uploaded file");
    node_save($node);

    // Load the node again and verify the information is there.
    $node = node_load($node->nid, NULL, TRUE);
    $thisindex = 0;
    foreach ($node->field_myfile as $stuff) {
      if ($stuff['filename'] == $filename) {
        $this
          ->assertEqual($node->field_myfile[$thisindex]['list'], $listed, 'Listed value was saved correctly');
        $this
          ->assertEqual($node->field_myfile[$thisindex]['data']['description'], $desc, 'Description was saved correctly');
      }
      $thisindex++;
    }
  }

  /**
   * Sets up CCK fields for content types.
   */
  public function setUpTypes() {

    // Reset CCK info to make sure nothing is cached.
    _content_type_info(TRUE);

    // Use functions to attach field to content -- too complex in UI...
    module_load_include('inc', 'content', 'includes/content.crud');

    // Figure out what the FileField field type is (not stable module)
    $info = filefield_field_info();
    $keys = array_keys($info);
    $fieldtype = $keys[0];
    $this
      ->assertTrue(1, "Field name is " . $fieldtype);

    // Figure out what the FileField widget type is (not stable module)
    $info = filefield_widget_info();
    $keys = array_keys($info);
    $widgettype = $keys[0];
    $this
      ->assertTrue(1, "Widget name is " . $widgettype);
    $info = _content_field_types($fieldtype);
    $this
      ->assertFalse(empty($info), "Field type for filefield exists");

    // Note: depending on the FileField version, the description and list
    // settings might be on the field or on the widget. Sigh.
    $field = array(
      'field_name' => 'field_myfile',
      'type_name' => 'sbp_indexed',
      'type' => $fieldtype,
      'widget_type' => $widgettype,
      'field_settings' => array(
        'description_field' => TRUE,
        'list_field' => TRUE,
        'file_extensions' => 'txt not',
      ),
      'widget_settings' => array(
        'description_field' => TRUE,
        'list_field' => TRUE,
        'file_extensions' => 'txt not',
      ),
      'label' => 'A file',
      'multiple' => 5,
    );
    content_field_instance_create($field);

    // Verify field was created.
    $field = array(
      'field_name' => 'field_myfile',
      'type_name' => 'sbp_indexed',
    );
    $info = content_field_instance_read($field);
    $this
      ->assertFalse(empty($info), 'File field is attached to content type sbp_indexed');
    $field = array(
      'field_name' => 'field_myfile',
      'type_name' => 'sbp_hidden',
    );
    content_field_instance_create($field);
    $info = content_field_instance_read($field);
    $this
      ->assertFalse(empty($info), 'File field is attached to content type sbp_hidden');
  }

}

/**
 * Functionality test 2 for Search by Page Attachments with CCK module.
 */
class SearchbyPageAttachCCK2Test extends SearchByPageAttachCCKTest {
  public static function getInfo() {
    return array(
      'name' => t('Search by Page Attach CCK Test 2'),
      'description' => t('Test functionality of sbp_attach.module with CCK FileField module. Note that this test assumes you have uploaded the Search Files API, CCK, and FileFields modules, and it also assumes that the default configuration of the Search Files API module "text helper" will work.'),
      'group' => t('Search by Page'),
      'dependencies' => array(
        'search',
        'sbp_test',
        'sbp_attach',
        'content',
        'filefield',
        'search_files',
        'dblog',
        'search_by_page',
      ),
    );
  }
  public function setUp() {
    DrupalWebTestCase::setUp('search', 'search_by_page', 'sbp_attach', 'content', 'filefield', 'search_files', 'sbp_test', 'dblog');

    // Note: I think SimpleTest inherits the default node access from the
    // base system. Needs to be rebuilt in order for the access stuff to work!
    node_access_rebuild();
    $this
      ->setUpEnvironments();
    $this
      ->setUpUsers($this->envinfo2);
    $this
      ->setUpTypes();
    $this
      ->makeContent();

    // Set up so "sbp_indexed" node attachments are searchable and
    // "sbp_hidden" attachments are not. Also make it so both listed and
    // unlisted files are searchable (functionality test 1 did only listed
    // files). And make our file field searchable.
    // NOTE: When posting to a page with checkboxes, it is VITAL to pass in
    // FALSE rather than 0 for the value, if you want to unset the checkbox!
    $this
      ->drupalPost('admin/settings/search_by_page/edit/' . $this->envid2, array(
      'sbp_attach_node_types[]' => 'sbp_indexed',
      'sbp_attach_field_types[]' => 'field_myfile',
      'sbp_attach_only_listed' => FALSE,
      'sbp_attach_prepend_node_title' => FALSE,
      'sbp_attach_title_sep' => " bush ",
      'sbp_attach_use_description' => FALSE,
      'button_label' => t('Search pages'),
    ), 'Save configuration');
    cache_clear_all('variables', 'cache');
    variable_init();
    $this
      ->assertEqual(search_by_page_setting_get('sbp_attach_only_listed', $this->envid2, 0), 0, 'Search only listed files is set to FALSE');
    $this
      ->doCronrun();
    $this
      ->drupalLogin($this->superuser);
    $this
      ->drupalGet('admin/reports/dblog');
    $this
      ->assertText(t('Cron run completed'), 'Log shows cron run completed');
    $this
      ->drupalLogout();
  }

  /**
   * Tests that attachments are searched.
   */
  function testSearchAttach() {
    $this
      ->drupalLogin($this->superuser);
    $search_path = $this->envinfo2['page_path'];

    // Search for the word 'flowers'
    $this
      ->drupalPost($search_path, array(
      'keys' => 'flowers',
    ), t('Search pages'));

    // Should find both listed and non-listed attachments on the first node
    $this
      ->assertText('flowers', "Flowers appears in search results for flowers");
    $this
      ->assertText('daisy', "First attachment was found");
    $this
      ->assertText('snapdragon', "Second attachment was found");
    $this
      ->assertNoText('dahlia', "Third attachment was not found");
  }

}

/**
 * Tests attachments that cannot be read.
 */
class SearchbyPageAttachNotReadable extends SearchByPageAttachCCKTest {
  public static function getInfo() {
    return array(
      'name' => t('Search by Page Attach Not Readable'),
      'description' => t('Test functionality of sbp_attach.module with files that cannot be read. Note that this test assumes you have uploaded the Search Files API, CCK, and FileFields modules.'),
      'group' => t('Search by Page'),
      'dependencies' => array(
        'search',
        'sbp_test',
        'sbp_attach',
        'content',
        'filefield',
        'search_files',
        'dblog',
        'search_by_page',
      ),
    );
  }
  public function setUp() {
    DrupalWebTestCase::setUp('search', 'search_by_page', 'sbp_attach', 'content', 'filefield', 'search_files', 'sbp_test', 'dblog');

    // Note: I think SimpleTest inherits the default node access from the
    // base system. Needs to be rebuilt in order for the access stuff to work!
    node_access_rebuild();
    $this
      ->setUpEnvironments();
    $this
      ->setUpUsers($this->envinfo2);
    $this
      ->setUpTypes();
    $this
      ->makeContent();

    // Set up so "sbp_indexed" node attachments are searchable, and that our
    // file field is searchable.
    // NOTE: When posting to a page with checkboxes, it is VITAL to pass in
    // FALSE rather than 0 for the value, if you want to unset the checkbox!
    $this
      ->drupalPost('admin/settings/search_by_page/edit/' . $this->envid2, array(
      'sbp_attach_node_types[]' => 'sbp_indexed',
      'sbp_attach_field_types[]' => 'field_myfile',
      'sbp_attach_only_listed' => FALSE,
      'sbp_attach_prepend_node_title' => TRUE,
      'sbp_attach_title_sep' => " bush ",
      'sbp_attach_use_description' => TRUE,
      'button_label' => t('Search pages'),
    ), 'Save configuration');
    cache_clear_all('variables', 'cache');
    variable_init();
    $this
      ->assertEqual(search_by_page_setting_get('sbp_attach_only_listed', $this->envid2, 0), 0, 'Search only listed files is set to FALSE');
    $this
      ->doCronrun();
    $this
      ->drupalLogin($this->superuser);
    $this
      ->drupalGet('admin/reports/dblog');
    $this
      ->assertText(t('Cron run completed'), 'Log shows cron run completed');
    $this
      ->drupalLogout();
  }

  /**
   * Makes a node with an unreadable attachment, for search testing.
   *
   * This is an override of the inherited method from SearchByPageAttachCCKTest,
   * which attaches one file that cannot be read (no helpers).
   */
  public function makeContent() {

    // Throw in a few nodes that won't match our tests.
    $info = array(
      'body' => 'blah',
      'teaser' => 'blah',
      'title' => 'blah',
    );
    $this
      ->drupalCreateNode($info);
    $this
      ->drupalCreateNode($info);
    $this
      ->drupalCreateNode($info);
    $this
      ->drupalCreateNode($info);
    $info = array(
      'title' => 'Favorite foods',
      'body' => 'I eat pizza every day.',
      'type' => 'sbp_indexed',
    );
    $node = $this
      ->drupalCreateNode($info);
    $this
      ->attachFileUpload($node, 'attach4.not', TRUE, 'A very lonely file');

    // Configure Search Files API helpers
    $this
      ->drupalPost('admin/settings/search_files/helpers/autodetect', array(), t('Autodetect'));
    $this
      ->drupalGet('admin/settings/search_files/helpers/list');
    $this
      ->assertText('Text files', 'Text file helper for Search Files set up (without this, no file searching is possible)');
    $this
      ->assertText('Good', 'Safe mode message found (without this, no file searching is possible)');
  }

  /**
   * Tests that attachments with unreadable text are handled OK.
   *
   * They shouldn't appear in search results, but they shouldn't screw up
   * search indexing.
   */
  function testSearchAttach() {
    $this
      ->drupalLogin($this->superuser);
    $search_path = $this->envinfo2['page_path'];

    // Search for the word 'flowers' -- should find nothing.
    $this
      ->drupalPost($search_path, array(
      'keys' => 'flowers',
    ), t('Search pages'));
    $this
      ->assertNoText('flowers', "Flowers does not appear in search results for flowers");

    // Search indexing should show 100%.
    $this
      ->drupalGet('admin/settings/search');
    $this
      ->assertText('100% of the site has been indexed.');
    $this
      ->assertText('There are 0 items left to index.');
  }

}

/**
 * Tests attachment reindexing.
 */
class SearchbyPageAttachReindexTest extends SearchByPageAttachCCKTest {
  public $nodes;
  public $descs;
  public static function getInfo() {
    return array(
      'name' => t('Search by Page Attach Reindex'),
      'description' => t('Test reindexing in sbp_attach.module. Note that this test assumes you have uploaded the Search Files API, CCK, and FileFields modules.'),
      'group' => t('Search by Page'),
      'dependencies' => array(
        'search',
        'sbp_test',
        'sbp_attach',
        'content',
        'filefield',
        'search_files',
        'dblog',
        'search_by_page',
      ),
    );
  }
  public function setUp() {
    DrupalWebTestCase::setUp('search', 'search_by_page', 'sbp_attach', 'content', 'filefield', 'search_files', 'sbp_test', 'dblog');

    // Note: I think SimpleTest inherits the default node access from the
    // base system. Needs to be rebuilt in order for the access stuff to work!
    node_access_rebuild();
    $this
      ->setUpEnvironments();
    $this
      ->setUpUsers($this->envinfo2);
    $this
      ->setUpTypes();
    $this
      ->makeContent();

    // Set up so "sbp_indexed" node attachments are searchable, and that our
    // file field is searchable.
    // NOTE: When posting to a page with checkboxes, it is VITAL to pass in
    // FALSE rather than 0 for the value, if you want to unset the checkbox!
    $this
      ->drupalPost('admin/settings/search_by_page/edit/' . $this->envid2, array(
      'sbp_attach_node_types[]' => 'sbp_indexed',
      'sbp_attach_field_types[]' => 'field_myfile',
      'sbp_attach_only_listed' => FALSE,
      'sbp_attach_prepend_node_title' => TRUE,
      'sbp_attach_title_sep' => " bush ",
      'sbp_attach_use_description' => TRUE,
      'button_label' => t('Search pages'),
    ), 'Save configuration');
    cache_clear_all('variables', 'cache');
    variable_init();
    $this
      ->assertEqual(search_by_page_setting_get('sbp_attach_only_listed', $this->envid2, 0), 0, 'Search only listed files is set to FALSE');
    $this
      ->doCronrun();
    $this
      ->drupalLogin($this->superuser);
    $this
      ->drupalGet('admin/reports/dblog');
    $this
      ->assertText(t('Cron run completed'), 'Log shows cron run completed');
    $this
      ->drupalLogout();
  }

  /**
   * Makes several nodes with attachments, for search testing.
   */
  public function makeContent() {

    // Throw in a few nodes that won't match our tests.
    $info = array(
      'body' => 'blah',
      'teaser' => 'blah',
      'title' => 'blah',
    );
    $this
      ->drupalCreateNode($info);
    $this
      ->drupalCreateNode($info);
    $this
      ->drupalCreateNode($info);
    $this
      ->drupalCreateNode($info);

    // Create a bunch of indexed nodes, with random titles.
    $info = array(
      'body' => 'I eat pizza every day.',
      'type' => 'sbp_indexed',
    );
    $this->nodes = array();
    for ($i = 0; $i < 5; $i++) {
      $this->nodes[] = $this
        ->drupalCreateNode($info);
      $this->descs[] = $this
        ->randomName();
      $this
        ->attachFileUpload($this->nodes[$i], 'attach1.txt', TRUE, $this->descs[$i]);
    }

    // Configure Search Files API helpers
    $this
      ->drupalPost('admin/settings/search_files/helpers/autodetect', array(), t('Autodetect'));
    $this
      ->drupalGet('admin/settings/search_files/helpers/list');
    $this
      ->assertText('Text files', 'Text file helper for Search Files set up (without this, no file searching is possible)');
    $this
      ->assertText('Good', 'Safe mode message found (without this, no file searching is possible)');
  }

  /**
   * Tests that attachments are reindexed when the node changes.
   *
   * Note that the name must be testSearchAttach() to override the function
   * by the same name in the base class.
   */
  function testSearchAttach() {
    $this
      ->drupalLogin($this->superuser);
    $search_path = $this->envinfo2['page_path'];

    // Verify that all the test nodes are found on a search for their
    // descriptions, and for the attachment (contains daisy).
    for ($i = 0; $i < count($this->nodes); $i++) {
      $node = $this->nodes[$i];
      $desc = $this->descs[$i];
      $this
        ->drupalPost($search_path, array(
        'keys' => 'daisy',
      ), t('Search pages'));
      $this
        ->assertText($node->title, "Node appears in search of first attachment");
      $this
        ->drupalPost($search_path, array(
        'keys' => $desc,
      ), t('Search pages'));
      $this
        ->assertText($node->title, "Node appears in search of attachment description");
    }

    // Set to never reindex automatically.
    $this
      ->drupalPost('admin/settings/search_by_page/edit/' . $this->envid2, array(
      'sbp_attach_min_time' => 0,
      'sbp_attach_max_time' => 0,
    ), 'Save configuration');
    cache_clear_all('variables', 'cache');
    variable_init();

    // Set search so it only indexes 1 node per cron run.
    variable_set('sbp_cron_limit', 1);

    // Run the next test several times. Pick a random node, attach the
    // file again with a new description, and run cron to index it.
    // Verify the new description can be found.
    for ($i = 0; $i < 10; $i++) {

      // Choose a random title and index.
      $newdesc = $this
        ->randomName();
      $tmp = array(
        'description' => $newdesc,
      );
      $key = rand(0, count($this->nodes) - 1);
      $node = node_load($this->nodes[$key]->nid, NULL, TRUE);
      $node->field_myfile[0]['data'] = $tmp;
      node_save($node);
      $this
        ->doCronrun();
      $this
        ->drupalLogin($this->superuser);
      $this
        ->drupalGet('admin/reports/dblog');
      $this
        ->assertText(t('Cron run completed'), 'Log shows cron run completed');
      $this
        ->drupalPost($search_path, array(
        'keys' => $newdesc,
      ), t('Search pages'));
      $this
        ->assertText($this->nodes[$key]->title, "Node appears in search of attachment description after reindex");
    }
  }

  /**
   * Tests that cycling through attachment reindexing happens correctly.
   */
  function testReindexingAutomatic() {
    $this
      ->drupalLogin($this->superuser);
    $search_path = $this->envinfo2['page_path'];

    // Set to reindex automatically on normal cycle.
    $this
      ->drupalPost('admin/settings/search_by_page/edit/' . $this->envid2, array(
      'sbp_attach_min_time' => 1,
      'sbp_attach_max_time' => 0,
    ), 'Save configuration');
    cache_clear_all('variables', 'cache');
    variable_init();

    // Set search so it only indexes 1 attachment per cron run.
    variable_set('sbp_cron_limit', 1);

    // Figure out the current index times of the attachments.
    $orig = $this
      ->getIndexTimes();

    // In a loop: run cron, and verify each time that the oldest item
    // (or one of them, if there was a tie) was reindexed.
    for ($i = 0; $i < 10; $i++) {

      // Run cron - should reindex just one node.
      $this
        ->doCronrun();
      $this
        ->drupalLogin($this->superuser);

      // Figure out the current index times of the nodes.
      $new = $this
        ->getIndexTimes();

      // Verify that only one was indexed, and it was the oldest one.
      $this
        ->verifyIndexCycling($orig, $new);
      $orig = $new;
    }
  }

}

/**
 * Tests that Search by Page doesn't get fooled by page output.
 */
class SearchByPageOutputTest extends SearchByPageTester {
  public $superuser;
  public static function getInfo() {
    return array(
      'name' => t('Search by Page Output Tests'),
      'description' => t('Test that page title, active trail, etc. do not affect search results display'),
      'group' => t('Search by Page'),
      'dependencies' => array(
        'search',
        'sbp_test',
        'sbp_paths',
        'dblog',
        'search_by_page',
      ),
    );
  }
  public function setUp() {
    parent::setUp('search', 'search_by_page', 'sbp_paths', 'sbp_test', 'dblog');
    $this
      ->setUpEnvironments();
    $this->superuser = $this
      ->drupalCreateUser(array(
      'administer nodes',
      'access content',
      'administer content types',
      'administer blocks',
      'administer search',
      'search content',
      'administer search by page',
      $this
        ->searchPerm($this->envinfo1),
      'access administration pages',
      'administer site configuration',
      'administer users',
      'administer permissions',
      'view test private content',
      'access site reports',
    ));
    $this
      ->drupalLogin($this->superuser);

    // Set up indexing of pages.
    $this
      ->drupalPost('admin/settings/search_by_page/edit/' . $this->envid1, array(
      'button_label' => t('Search pages'),
    ), 'Save configuration');
    $path_add_path = 'admin/settings/search_by_page/edit/' . $this->envid1 . '/paths/add';
    $this
      ->drupalPost($path_add_path, array(
      'path' => 'sbp_test_output_page',
      'title' => t("Output page"),
      'type' => t('Page'),
      'snippet' => 'yes',
      'role' => $this
        ->getNewRoleID($this->superuser),
    ), 'Create new indexed page');
    cache_clear_all('variables', 'cache');
    variable_init();
    $this
      ->doCronrun();
    $this
      ->drupalLogin($this->superuser);
    $this
      ->drupalGet('admin/reports/dblog');
    $this
      ->assertText(t('Cron run completed'), 'Log shows cron run completed');
    $this
      ->drupalLogout();
  }

  /**
   * Tests that pages can be searched.
   */
  function testSearchPages() {

    // Search and verify that the word "wrong" doesn't appear on the page.
    // It would appear if some of the bad output got through. Also make
    // sure that the correct output does appear.
    $search_path = $this->envinfo1['page_path'];
    $this
      ->drupalLogin($this->superuser);
    $this
      ->drupalPost($search_path, array(
      'keys' => 'Trees',
    ), t('Search pages'));
    $this
      ->assertText('Trees', "Found Trees on the search results page");
    $this
      ->assertText('Apple', "Found Apple on the search results page");
    $this
      ->assertNoText('Wrong', "Bad output did not make it to the results page");
  }

}

/**
 * Environment internationalization test.
 */
class SearchByPageIntlTest extends SearchByPageTester {
  public $superuser;
  public $lang_to_use = 'es';
  public $strings_to_test = array(
    'page_title' => 'Translated page title',
    'block_title' => 'Translated block title',
    'field_label' => 'Translated field label',
    'button_label' => 'Translated button label',
    'path_title' => 'Translated path title',
    'path_type' => 'Translated path type',
    'path_snippet' => 'Translated path snippet',
  );
  public static function getInfo() {
    return array(
      'name' => t('Search by Page Internationalization Tests'),
      'description' => t('Test that search environments can be internationalized.'),
      'group' => t('Search by Page'),
      'dependencies' => array(
        'search',
        'search_by_page',
        'i18n',
        'i18nstrings',
        'sbp_paths',
        'sbp_test',
        'locale',
        'translation',
        'block',
      ),
    );
  }
  public function setUp() {
    parent::setUp('locale', 'translation', 'search', 'search_by_page', 'i18n', 'i18nstrings', 'sbp_paths', 'sbp_test', 'block');
    $this
      ->setUpEnvironments();
    $this->superuser = $this
      ->drupalCreateUser(array(
      'administer blocks',
      'access administration pages',
      'administer search',
      'administer search by page',
      'search content',
      'access content',
      $this
        ->searchPerm($this->envinfo1),
      'administer site configuration',
      'administer permissions',
      'administer languages',
      'translate interface',
      'administer all languages',
      'administer translations',
    ));
    $this
      ->drupalLogin($this->superuser);

    // Set up the languages, environments, path, and block. Run cron.
    $this
      ->setUpLanguages();
    $this
      ->setUpPath();
    $this
      ->drupalPost('admin/build/block', array(
      'search_by_page_' . $this->envid1 . '[region]' => 'content',
    ), 'Save blocks');
    cache_clear_all('variables', 'cache');
    variable_init();

    // Visit the foreign-language search page to trigger the page title getting
    // added to the translation interface.
    $langs = language_list();
    $lang = $langs[$this->lang_to_use];
    $this
      ->drupalGet($this->envinfo1['page_path'], array(
      'language' => $lang,
    ));

    // Run cron to index.
    $this
      ->doCronrun();
    $this
      ->drupalLogin($this->superuser);
  }

  /**
   * Tests that environment settings for main module and paths are translated.
   */
  public function testTranslations() {
    $this
      ->translateEnvironment();

    // Visit the search results page in English, and verify that all the
    // test strings are there.
    $this
      ->drupalPost($this->envinfo1['page_path'], array(
      'keys' => 'Trees',
    ), t('Search button 1 label'));
    $this
      ->doLanguageTest('en');

    // Now visit the page in the other language and test.
    $langs = language_list();
    $lang = $langs[$this->lang_to_use];
    $this
      ->drupalPost($this->envinfo1['page_path'], array(
      'keys' => 'Trees',
    ), $this->strings_to_test['button_label'], array(
      'language' => $lang,
    ));
    $this
      ->doLanguageTest($this->lang_to_use);
  }

  /**
   * Sets up languages for this test.
   */
  public function setUpLanguages() {
    $lang = $this->lang_to_use;

    // Add the language.
    $this
      ->drupalPost('admin/settings/language/add', array(
      'langcode' => $lang,
    ), t('Add language'));

    // Set up path prefix language negotiation.
    $this
      ->drupalPost('admin/settings/language/configure', array(
      'language_negotiation' => 1,
    ), t('Save settings'));
  }

  /**
   * Sets up SBP Paths with a path to index.
   */
  function setupPath() {
    $path_add_path = 'admin/settings/search_by_page/edit/' . $this->envid1 . '/paths/add';
    $this->envinfo1['path_title'] = t('Public page title');
    $this->envinfo1['path_type'] = t('Public page type');
    $this->envinfo1['path_snippet'] = t('Public page snippet');
    $this
      ->drupalPost($path_add_path, array(
      'path' => 'sbp_test_pub_page',
      'title' => $this->envinfo1['path_title'],
      'type' => $this->envinfo1['path_type'],
      'snippet' => $this->envinfo1['path_snippet'],
      'role' => $this
        ->getNewRoleID($this->superuser),
      'languages[en]' => 'en',
      'languages[' . $this->lang_to_use . ']' => $this->lang_to_use,
    ), 'Create new indexed page');
  }

  /**
   * Translates environment 1.
   */
  public function translateEnvironment() {
    $stuff = $this->envinfo1;
    $lang = $this->lang_to_use;
    foreach ($this->strings_to_test as $key => $trans) {

      // Find the string in the translate interface.
      $english = $stuff[$key];
      $this
        ->drupalPost('admin/build/translate/search', array(
        'string' => $english,
      ), 'Search');
      $this
        ->assertLink('edit', 0, 'Found translation link for ' . $english);
      $this
        ->clickLink('edit');
      $this
        ->drupalPost(NULL, array(
        'translations[' . $lang . ']' => $trans,
      ), 'Save translations');
    }

    // Special case for the page title: since it's in hook_menu, it gets
    // into the translate interface as part of the built-in interface. So
    // make sure that version of it is translated too.
    $key = 'page_title';
    $english = $stuff[$key];
    $this
      ->drupalPost('admin/build/translate/search', array(
      'string' => $english,
      'group' => 'default',
    ), 'Search');
    $this
      ->assertLink('edit', 0, 'Found translation link for ' . $english);
    $this
      ->clickLink('edit');
    $this
      ->drupalPost(NULL, array(
      'translations[' . $lang . ']' => $this->strings_to_test[$key],
    ), 'Save translations');
  }

  /**
   * Tests that the right strings are present for the given language.
   */
  public function doLanguageTest($lang) {

    // Figure out which strings we want to look for and verify are not there.
    $good = $this->envinfo1;
    $bad = $this->strings_to_test;
    if ($lang != 'en') {
      $bad = $this->envinfo1;
      $good = $this->strings_to_test;
    }

    // Verify that all the good strings are there and not the bad ones.
    foreach ($this->strings_to_test as $key => $ignore) {
      $this
        ->assertRaw($good[$key], "Text for {$key} in right language is present");
      $this
        ->assertNoRaw($bad[$key], "Text for {$key} in other language is not present");
    }
  }

}

Classes

Namesort descending Description
SearchbyPageAttachCCK2Test Functionality test 2 for Search by Page Attachments with CCK module.
SearchByPageAttachCCKTest Functionality test 1 for Search by Page Attachments with CCK module.
SearchbyPageAttachNotReadable Tests attachments that cannot be read.
SearchbyPageAttachReindexTest Tests attachment reindexing.
SearchbyPageAttachUploads2Test Functionality test 2 for Search by Page Attachments with Uploads module.
SearchByPageAttachUploadsTest Functionality test 1 for Search by Page Attachments with Uploads module.
SearchByPageEnvironmentTest Basic search environments test.
SearchByPageIntlTest Environment internationalization test.
SearchByPageNodesReindexTest Tests when nodes are reindexed.
SearchByPageNodesTest Functionality tests for Search by Page Nodes.
SearchByPageOutputTest Tests that Search by Page doesn't get fooled by page output.
SearchByPagePathsAliasTest Tests for Search by Page Paths - searching nodes with aliases.
SearchByPagePathsNodesTest Tests for Search by Page Paths - searching nodes.
SearchByPagePathsReindexTest Reindexing test for Search by Page Paths.
SearchByPagePathsRemoveTest Functionality test for removing paths from Search by Page Paths.
SearchByPagePathsTest Functionality tests for Search by Page Paths.
SearchByPageTester Base class for testing Search by Page.
SearchByPageUnitTest Unit tests for Search by Page functions.
SearchByPageUsersReindexTest Tests when users are reindexed.
SearchByPageUsersTest Functionality tests for Search by Page Users.