You are here

search_by_page.test in Search by Page 7

Same filename and directory in other branches
  1. 6 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_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 $env_info1;
  public $envid1;
  public $env_info2;
  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',
      'administer search',
    ));
    $this
      ->drupalLogin($user);

    // Content access permissions always need to be rebuilt for some reason.
    node_access_rebuild();

    // Verify this module is active in Search.
    $active = variable_get('search_active_modules', array(
      'node',
      'user',
    ));
    $this
      ->assertTrue(in_array('search_by_page', $active));

    // 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/config/search/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/config/search/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();
    }
    $this
      ->cronRun();
  }

  /**
   * 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();
    return db_query('SELECT pid, last_index_time FROM {sbp_path}')
      ->fetchAllKeyed();
  }

  /**
   * 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");
  }

}

/**
 * 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 = array_keys(search_by_page_permission());
    $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/structure/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/structure/block', array(
      'blocks[search_by_page_' . $this->envid1 . '][region]' => 'content',
      'blocks[search_by_page_' . $this->envid2 . '][region]' => 'content',
    ), 'Save blocks');

    // Verify block titles appear.
    $this
      ->drupalGet('<front>');
    $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 $nodeid1;
  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');
    $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',
      'bypass node access',
    ));
    $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 priveleged user.
    $this
      ->drupalPost('admin/config/search/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_bootstrap');
    variable_initialize();
    $info = array(
      'body' => array(
        LANGUAGE_NONE => array(
          array(
            'value' => 'double trouble',
          ),
        ),
      ),
      'type' => 'page',
      'language' => LANGUAGE_NONE,
      'title' => 'first page',
    );
    $node = $this
      ->drupalCreateNode($info);
    $this
      ->drupalGet('node/' . $node->nid);
    $this
      ->assertText('trouble', "Node page could be found");

    // Throw in a few nodes that won't match our tests.
    $info = array(
      'body' => array(
        LANGUAGE_NONE => array(
          array(
            'value' => 'blah',
            'summary' => 'blah',
          ),
        ),
      ),
      'title' => 'blah',
      'language' => LANGUAGE_NONE,
    );
    $node = $this
      ->drupalCreateNode($info);
    $this
      ->drupalGet('node/' . $node->nid);
    $this
      ->assertText('blah', "Node page could be found");
    $node = $this
      ->drupalCreateNode($info);
    $this
      ->drupalGet('node/' . $node->nid);
    $this
      ->assertText('blah', "Node page could be found");
    $node = $this
      ->drupalCreateNode($info);
    $this
      ->drupalGet('node/' . $node->nid);
    $this
      ->assertText('blah', "Node page could be found");

    // Create some content that we'll look for - make sure it has the
    // word "walk" in it.
    $info = array(
      'body' => array(
        LANGUAGE_NONE => array(
          array(
            'value' => 'I walk through the streets, looking around for trouble',
            'summary' => 'I walk on a path, where it is quiet',
          ),
        ),
      ),
      'type' => 'sbp_indexed',
      'test_private' => FALSE,
      'language' => LANGUAGE_NONE,
    );
    $node = $this
      ->drupalCreateNode($info);
    $this->nodetitle1 = $node->title;
    $this->nodeid1 = $node->nid;
    $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' => array(
        LANGUAGE_NONE => array(
          array(
            'value' => 'I can walk really far, maybe even to the north pole.',
            'summary' => 'I will walk to the south pole.',
          ),
        ),
      ),
      'type' => 'sbp_indexed',
      'test_private' => TRUE,
      'language' => LANGUAGE_NONE,
    );
    $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' => array(
        LANGUAGE_NONE => array(
          array(
            'value' => 'When I walk, I try not to run into people.',
          ),
        ),
      ),
      'type' => 'sbp_hidden',
      'test_private' => FALSE,
      'language' => LANGUAGE_NONE,
    );
    $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');

    // Find the Full HTML format.
    $filters = filter_formats();
    $filternum = 0;
    foreach ($filters as $filter) {
      if ($filter->name == 'Full HTML') {
        $filternum = $filter->format;
        break;
      }
    }
    $info = array(
      'body' => array(
        LANGUAGE_NONE => array(
          array(
            'value' => 'This content <tagtoexclude>only has walk gobble in the excluded tag</tagtoexclude> and then gobble appears after it.',
            'summary' => 'Short version of this content',
            'format' => $filternum,
          ),
        ),
      ),
      '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');
  }

  /**
   * Tests that the content of the designated types only can be searched.
   */
  function testSearchTypes() {
    $search_path = $this->envinfo1['page_path'];
    $this
      ->drupalLogin($this->privuser);
    $this
      ->drupalGet('node/' . $this->nodeid1);
    $this
      ->assertText('streets', "Priv user can see first node page");

    // 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
      ->assertFalse(isset($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/config/search/search_by_page/edit/' . $this->envid1, array(
      'sbp_nodes_display_type' => 'teasers',
    ), 'Save configuration');
    cache_clear_all('variables', 'cache_bootstrap');
    variable_initialize();

    // 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/config/search/search_by_page/edit/' . $this->envid1, array(
      'sbp_nodes_display_type' => 'excerpts',
    ), 'Save configuration');
    cache_clear_all('variables', 'cache_bootstrap');
    variable_initialize();

    // 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');
    $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',
      'skip comment approval',
      'administer comments',
    ));
    $this
      ->drupalLogin($this->superuser);

    // Set up so "sbp_indexed" nodes are searchable.
    // Index them with the super-user.
    $this
      ->drupalPost('admin/config/search/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_bootstrap');
    variable_initialize();

    // Create 5 nodes with the same content.
    $info = array(
      'body' => array(
        LANGUAGE_NONE => array(
          array(
            'value' => 'blah',
          ),
        ),
      ),
      'type' => 'sbp_indexed',
      'language' => LANGUAGE_NONE,
      'title' => 'blah',
      '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/config/search/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_initialize();

    // 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/structure/types/manage/sbp-indexed', array(
      'comment' => '2',
      'comment_form_location' => '1',
      'comment_preview' => '0',
    ), 'Save content type');

    // Set to never reindex automatically.
    $this
      ->drupalPost('admin/config/search/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_initialize();

    // 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_body[und][0][value]' => $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/config/search/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_initialize();

    // 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;
    }
  }

}

/**
 * Tests that no extra Search by Page indexing users are created.
 */
class SearchByPageExtraUsersTest extends SearchByPageTester {
  public $superuser;
  public $nodes;
  public static function getInfo() {
    return array(
      'name' => t('Search by Page Extra Users'),
      'description' => t('Test that only the necessary users are created.'),
      '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');
    $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',
      'skip comment approval',
      'administer comments',
    ));
    $this
      ->drupalLogin($this->superuser);

    // Set up so "sbp_indexed" nodes are searchable.
    // Index them with the super-user.
    $this
      ->drupalPost('admin/config/search/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_bootstrap');
    variable_initialize();

    // Create 5 nodes with the same content.
    $info = array(
      'body' => array(
        LANGUAGE_NONE => array(
          array(
            'value' => 'blah',
          ),
        ),
      ),
      'type' => 'sbp_indexed',
      'language' => LANGUAGE_NONE,
      'title' => 'blah',
      '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 no new users are created when reindexing.
   */
  function testReindexingUsers() {
    $this
      ->drupalLogin($this->superuser);
    $search_path = $this->envinfo1['page_path'];

    // Count the number of users.
    $num_before = $this
      ->howManyUsers();

    // Set to reindex automatically on normal cycle.
    $this
      ->drupalPost('admin/config/search/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_initialize();

    // 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 something 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;
    }

    // Now see how many users there are.
    $num_after = $this
      ->howManyUsers();
    $this
      ->assertEqual($num_before, $num_after, "Number of users before ({$num_before}) and after ({$num_after}) is the same");
  }

  // Counts how many user accounts there are.
  function howManyUsers() {
    $query = db_select('users', 'u');
    $query
      ->addExpression('count(*)');
    return $query
      ->execute()
      ->fetchField();
  }

}

/**
 * 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/config/search/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_bootstrap');
    variable_initialize();
    $this
      ->doCronRun();
    $this
      ->drupalLogin($this->superuser);
    $this
      ->drupalGet('admin/reports/dblog');
    $this
      ->assertText(t('Cron run completed'), 'Log shows cron run completed');
  }

  /**
   * 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/config/search/search_by_page/edit/' . $this->envid2, $edit, 'Save configuration');
    cache_clear_all('variables', 'cache');
    variable_initialize();
    $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/config/search/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_initialize();

    // 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, TRUE);
      $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/config/search/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_initialize();

    // 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',
    ));

    // Verify that the priv user can see the pages.
    $this
      ->drupalLogin($this->privuser);
    $this
      ->drupalGet('sbp_test_priv_page');
    $this
      ->assertText('Trees', "Private page can be seen.");
    $this
      ->drupalGet('sbp_test_pub_page');
    $this
      ->assertText('Trees', "Public page can be seen.");
    $this
      ->drupalGet('sbp_test_another_page');
    $this
      ->assertText('Trees', "Another page can be seen.");

    // Verify that the non-priv user can see only some of the pages.
    $this
      ->drupalLogin($this->noprivuser);
    $this
      ->drupalGet('sbp_test_priv_page');
    $this
      ->assertNoText('Trees', "Private page cannot be seen.");
    $this
      ->drupalGet('sbp_test_pub_page');
    $this
      ->assertText('Trees', "Public page can be seen.");
    $this
      ->drupalGet('sbp_test_another_page');
    $this
      ->assertText('Trees', "Another page can be seen.");
    $this
      ->drupalLogin($this->superuser);

    // Set up indexing of pages.
    $this
      ->drupalPost('admin/config/search/search_by_page/edit/' . $this->envid1, array(
      'button_label' => t('Search pages'),
    ), 'Save configuration');
    $path_add_path = 'admin/config/search/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
      ->drupalGet('sbp_test_queried_page', array(
      'query' => array(
        'a' => 3,
      ),
    ));
    $this
      ->assertText('three', 'First query page shows query text');
    $this
      ->drupalGet('sbp_test_queried_page', array(
      'query' => array(
        'a' => 4,
      ),
    ));
    $this
      ->assertText('four', 'Second query page shows query text');
    $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_queried_page?a=4',
      'title' => t("Public page with other 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_bootstrap');
    variable_initialize();
    $this
      ->doCronRun();
    $this
      ->drupalLogin($this->superuser);
    $this
      ->drupalGet('admin/reports/dblog');
    $this
      ->assertText(t('Cron run completed'), 'Log shows cron run completed');
  }

  /**
   * 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");
    $this
      ->assertText('three', "Page with query shows query text");
    $this
      ->assertText('four', "Second page with query shows query text");

    // 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");
    $this
      ->assertText('three', "Page with query shows query text");
    $this
      ->assertText('four', "Second page with query shows query text");
  }

  /**
   * 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");
  }

}

/**
 * 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/config/search/search_by_page/edit/' . $this->envid1, array(
      'button_label' => t('Search pages'),
    ), 'Save configuration');
    $path_add_path = 'admin/config/search/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_bootstrap');
    variable_initialize();
    $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/config/search/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");
  }

}

/**
 * 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/config/search/search_by_page/edit/' . $this->envid2, array(
      'button_label' => t('Search pages'),
    ), 'Save configuration');
    cache_clear_all('variables', 'cache_bootstrap');
    variable_initialize();

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

    // Create some content with different input formats and add to SBP Paths.
    $format_to_use = filter_default_format($this->superuser);
    $info = array(
      'body' => array(
        LANGUAGE_NONE => array(
          array(
            'value' => 'I walk through the streets, looking around for trouble',
            'summary' => 'I walk on a path, where it is quiet',
            'format' => $format_to_use,
          ),
        ),
      ),
      'type' => 'page',
      'language' => LANGUAGE_NONE,
    );
    $node = $this
      ->drupalCreateNode($info);
    $this
      ->drupalGet('node/' . $node->nid);
    $this
      ->assertText('walk', 'Walk found on node page');
    $path_add_path = 'admin/config/search/search_by_page/edit/' . $this->envid2 . '/paths/add';
    $rid = $this
      ->getNewRoleID($this->superuser);
    $this
      ->drupalPost($path_add_path, array(
      'path' => 'node/' . $node->nid,
      'title' => t($node->title),
      'type' => t('Page'),
      'snippet' => 'yes',
      'role' => $rid,
    ), t('Create new indexed page'));

    // Make sure there's a second text format.
    $this
      ->drupalPost('admin/config/content/formats/add', array(
      'name' => $this
        ->randomName(10),
      'roles[' . $rid . ']' => TRUE,
    ), t('Save configuration'));

    // Pick out a new format to use.
    $formats = filter_formats($this->superuser);
    foreach ($formats as $fid => $info) {
      if ($fid != $format_to_use) {
        $format_to_use = $fid;
        break;
      }
    }
    $info = array(
      'body' => array(
        LANGUAGE_NONE => array(
          array(
            'value' => 'I can walk really far, maybe even to the north pole.',
            'summary' => 'I will walk to the south pole.',
            'format' => $format_to_use,
          ),
        ),
      ),
      'type' => 'page',
      'language' => LANGUAGE_NONE,
    );
    $node = $this
      ->drupalCreateNode($info);
    $this
      ->drupalGet('node/' . $node->nid);
    $this
      ->assertText('walk', 'Walk found on node page');
    $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');
  }

  /**
   * 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/config/search/search_by_page/edit/' . $this->envid1, array(
      'button_label' => t('Search pages'),
    ), 'Save configuration');
    cache_clear_all('variables', 'cache_bootstrap');
    variable_initialize();

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

    // Create some content with a path alias and add to SBP Paths.
    // Create the content.
    $info = array(
      'body' => array(
        LANGUAGE_NONE => array(
          array(
            'value' => 'I walk through the streets, looking around for trouble',
            'summary' => 'I walk on a path, where it is quiet',
          ),
        ),
      ),
      'type' => 'page',
      'language' => LANGUAGE_NONE,
    );
    $node = $this
      ->drupalCreateNode($info);

    // Add a URL alias to the system.
    $alias = $this
      ->randomName();
    $this
      ->drupalPost('admin/config/search/path/add', array(
      'source' => 'node/' . $node->nid,
      'alias' => $alias,
    ), t('Save'));

    // Add it to Search by Page Paths.
    $path_add_path = 'admin/config/search/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');
  }

  /**
   * 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");
  }

}

/**
 * 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/config/search/search_by_page/edit/' . $this->envid1, array(
      'button_label' => t('Search pages'),
    ), 'Save configuration');
    $path_add_path = 'admin/config/search/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_initialize();
    $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/config/search/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_initialize();

    // 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.
 */
class SearchByPageAttachTest extends SearchByPageTester {
  public $superuser;
  public $noprivuser;
  public $fieldid;
  public static function getInfo() {
    return array(
      'name' => t('Search by Page Attach Test 1'),
      'description' => t('Test functionality of sbp_attach.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',
        'file',
        'search_files',
        'dblog',
        'search_by_page',
      ),
    );
  }
  public function setUp() {
    parent::setUp('search', 'sbp_test', 'sbp_attach', 'file', 'search_files', 'dblog', 'search_by_page');
    $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/config/search/search_by_page/edit/' . $this->envid2, 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,
      'sbp_attach_role' => $this
        ->getNewRoleID($this->superuser),
      'button_label' => t('Search pages'),
    ), 'Save configuration');
    cache_clear_all('variables', 'cache_bootstrap');
    variable_initialize();
    $this
      ->doCronRun();
    $this
      ->drupalLogin($this->superuser);
    $this
      ->drupalGet('admin/reports/dblog');
    $this
      ->assertText(t('Cron run completed'), 'Log shows cron run completed');
  }

  /**
   * 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");

    // Also verify that the upper-case extension was found.
    $this
      ->assertText('attach5.TXT', "Upper case extension file name shown");

    // 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");
  }

  /**
   * 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(
      $this
        ->searchPerm($env),
      'search content',
    ));

    // Clear default permissions for authenticated users.
    db_delete('role_permission')
      ->condition('rid', DRUPAL_AUTHENTICATED_RID)
      ->execute();
    $this
      ->assertFalse(user_access('access content', $this->noprivuser), 'No priv user cannot access content');
    $this
      ->drupalLogin($this->superuser);
  }

  /**
   * Sets up File field for content type.
   */
  public function setUpTypes() {

    // Create the field type.
    $field = array(
      'field_name' => 'field_myfile',
      'type' => 'file',
      'cardinality' => 5,
      'settings' => array(
        'display_field' => 1,
        'display_default' => 1,
      ),
    );
    $field = field_create_field($field);
    $this
      ->assertTrue($field['id'], "Field was given an ID");
    $this->fieldid = $field['id'];

    // Attach it to both sbp_indexed and spb_hidden content types.
    $instance = array(
      'field_name' => $field['field_name'],
      'entity_type' => 'node',
      'bundle' => 'sbp_indexed',
      'settings' => array(
        'file_extensions' => 'txt not',
        'description_field' => 1,
      ),
      'label' => 'A file',
    );
    field_create_instance($instance);
    $instance['bundle'] = 'sbp_hidden';
    field_create_instance($instance);

    // Verify the field was attached.
    $fieldinfo = field_info_field_by_id($field['id']);
    $this
      ->assertTrue($fieldinfo, "Field information could be read");
    $this
      ->assertEqual($fieldinfo['field_name'], 'field_myfile', "Field name is correct");
    $this
      ->assertTrue(count($fieldinfo['bundles']), 'Field is attached to a bundle');
    $this
      ->assertTrue(count($fieldinfo['bundles']['node']), 'Field is attached to a node bundle');
    $this
      ->assertTrue(in_array('sbp_indexed', $fieldinfo['bundles']['node']), 'Field is attached to sbp_indexed');
    $this
      ->assertTrue(in_array('sbp_hidden', $fieldinfo['bundles']['node']), 'Field is attached to sbp_hidden');
  }

  /**
   * 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' => array(
        LANGUAGE_NONE => array(
          array(
            'value' => 'blah',
            'summary' => 'blah',
          ),
        ),
      ),
      'title' => 'blah',
      'language' => LANGUAGE_NONE,
    );
    $this
      ->drupalCreateNode($info);
    $this
      ->drupalCreateNode($info);
    $this
      ->drupalCreateNode($info);
    $this
      ->drupalCreateNode($info);
    $info = array(
      'title' => 'Favorite foods',
      'body' => array(
        LANGUAGE_NONE => array(
          array(
            'value' => 'I eat pizza every day.',
          ),
        ),
      ),
      'type' => 'sbp_indexed',
      'language' => LANGUAGE_NONE,
    );
    $node = $this
      ->drupalCreateNode($info);
    $this
      ->attachFileUpload($node, 'attach2.txt', 0, 'A very happy file');
    $this
      ->attachFileUpload($node, 'attach1.txt', 1, 'A very lonely file');
    $this
      ->attachFileUpload($node, 'attach5.TXT', 1, 'An upper-case extension file');
    $info = array(
      'title' => 'Favorite cars',
      'body' => array(
        LANGUAGE_NONE => array(
          array(
            'value' => 'I drive a hatchback.',
          ),
        ),
      ),
      'type' => 'sbp_hidden',
      'language' => LANGUAGE_NONE,
    );
    $node = $this
      ->drupalCreateNode($info);
    $this
      ->attachFileUpload($node, 'attach3.txt', 1, 'A very pretty file');

    // Configure Search Files API helpers
    $this
      ->drupalPost('admin/config/search/search_files/helpers/autodetect', array(), t('Autodetect'));
    $this
      ->drupalGet('admin/config/search/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)');
  }

  /**
   * Attaches a file to a node, using File field.
   *
   * @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 displayed (1) or not (0).
   * @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);

    // Add the file to the files table and file downloads directory.
    $file = file_get_contents($path);
    $file = file_save_data($file, 'public://' . $filename);
    $this
      ->assertTrue($file->fid, "File record was created");
    $info = array(
      'display' => $listed,
      'description' => $desc,
      'fid' => $file->fid,
    );

    // Load the node, add the file to it, and save.
    $node = node_load($node->nid, NULL, TRUE);
    $done = FALSE;
    foreach ($node->field_myfile as $lang => $langstuff) {
      $node->field_myfile[$lang][] = $info;
      $done = TRUE;
      break;
    }
    if (!$done) {
      $node->field_myfile['und'] = array(
        $info,
      );
    }
    node_save($node);

    // Verify the file is attached
    $node = node_load($node->nid, NULL, TRUE);
    $found = FALSE;
    foreach ($node->field_myfile as $lang => $langstuff) {
      foreach ($langstuff as $stuff) {
        if ($stuff['fid'] == $file->fid) {
          $found = TRUE;
          break;
        }
      }
    }
    $this
      ->assertTrue($found, "File was actually attached");
  }

  /**
   * 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/config/search/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_bootstrap');
    variable_initialize();

    // 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.
 */
class SearchbyPageAttach2Test extends SearchByPageAttachTest {
  public static function getInfo() {
    return array(
      'name' => t('Search by Page Attach Test 2'),
      'description' => t('Test functionality of sbp_attach.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',
        'file',
        'search_files',
        'dblog',
        'search_by_page',
      ),
    );
  }
  public function setUp() {
    DrupalWebTestCase::setUp('search', 'sbp_test', 'sbp_attach', 'file', 'search_files', 'dblog', 'search_by_page');
    $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/config/search/search_by_page/edit/' . $this->envid1, 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,
      'sbp_attach_role' => $this
        ->getNewRoleID($this->superuser),
      'button_label' => t('Search pages'),
    ), 'Save configuration');
    cache_clear_all('variables', 'cache_bootstrap');
    variable_initialize();
    $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');
  }

  /**
   * 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");
  }

}

/**
 * Tests attachments that cannot be read.
 */
class SearchbyPageAttachNotReadable extends SearchByPageAttachTest {
  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 module.'),
      'group' => t('Search by Page'),
      'dependencies' => array(
        'search',
        'sbp_test',
        'sbp_attach',
        'file',
        'search_files',
        'dblog',
        'search_by_page',
      ),
    );
  }
  public function setUp() {
    DrupalWebTestCase::setUp('search', 'sbp_test', 'sbp_attach', 'file', 'search_files', 'dblog', 'search_by_page');
    $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/config/search/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_bootstrap');
    variable_initialize();
    $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 SearchByPageAttachTest,
   * 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' => array(
        LANGUAGE_NONE => array(
          array(
            'value' => 'blah',
            'summary' => 'blah',
          ),
        ),
      ),
      'title' => 'blah',
      'language' => LANGUAGE_NONE,
    );
    $this
      ->drupalCreateNode($info);
    $this
      ->drupalCreateNode($info);
    $this
      ->drupalCreateNode($info);
    $this
      ->drupalCreateNode($info);
    $info = array(
      'title' => 'Favorite foods',
      'body' => array(
        LANGUAGE_NONE => array(
          array(
            'value' => 'I eat pizza every day.',
          ),
        ),
      ),
      'type' => 'sbp_indexed',
      'language' => LANGUAGE_NONE,
    );
    $node = $this
      ->drupalCreateNode($info);
    $this
      ->attachFileUpload($node, 'attach4.not', TRUE, 'A very lonely file');

    // Configure Search Files API helpers
    $this
      ->drupalPost('admin/config/search/search_files/helpers/autodetect', array(), t('Autodetect'));
    $this
      ->drupalGet('admin/config/search/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/config/search/settings');
    $this
      ->assertText('100% of the site has been indexed.');
    $this
      ->assertText('There are 0 items left to index.');
  }

}

/**
 * Tests attachment reindexing.
 */
class SearchbyPageAttachReindexTest extends SearchByPageAttachTest {
  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 module.'),
      'group' => t('Search by Page'),
      'dependencies' => array(
        'search',
        'sbp_test',
        'sbp_attach',
        'file',
        'search_files',
        'dblog',
        'search_by_page',
      ),
    );
  }
  public function setUp() {
    DrupalWebTestCase::setUp('search', 'search_by_page', 'sbp_attach', 'file', 'search_files', 'sbp_test', 'dblog');
    $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/config/search/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_bootstrap');
    variable_initialize();
    $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' => array(
        LANGUAGE_NONE => array(
          array(
            'value' => 'blah',
            'summary' => 'blah',
          ),
        ),
      ),
      'title' => 'blah',
      'language' => LANGUAGE_NONE,
    );
    $this
      ->drupalCreateNode($info);
    $this
      ->drupalCreateNode($info);
    $this
      ->drupalCreateNode($info);
    $this
      ->drupalCreateNode($info);

    // Create a bunch of indexed nodes, with random titles.
    // Throw in a few nodes that won't match our tests.
    $info = array(
      'body' => array(
        LANGUAGE_NONE => array(
          array(
            'value' => 'I eat pizza every day.',
            'summary' => 'blah',
          ),
        ),
      ),
      'language' => LANGUAGE_NONE,
      '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/config/search/search_files/helpers/autodetect', array(), t('Autodetect'));
    $this
      ->drupalGet('admin/config/search/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/config/search/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_initialize();

    // 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();
      $key = rand(0, count($this->nodes) - 1);
      $node = node_load($this->nodes[$key]->nid, NULL, TRUE);
      foreach ($node->field_myfile as $lang => $stuff) {
        $node->field_myfile[$lang][0]['description'] = $newdesc;
      }
      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/config/search/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_initialize();

    // 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/config/search/search_by_page/edit/' . $this->envid1, array(
      'button_label' => t('Search pages'),
    ), 'Save configuration');
    $path_add_path = 'admin/config/search/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_bootstrap');
    variable_initialize();
    $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',
        'variable',
        'i18n',
        'i18n_string',
        'sbp_paths',
        'sbp_test',
        'locale',
        'translation',
        'block',
      ),
    );
  }
  public function setUp() {
    parent::setUp('locale', 'translation', 'search', 'search_by_page', 'variable', 'i18n', 'i18n_string', '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',
      'translate user-defined strings',
      'translate admin strings',
    ));
    $this
      ->drupalLogin($this->superuser);

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

    // 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/config/regional/language/add', array(
      'langcode' => $lang,
    ), t('Add language'));

    // Set up path prefix language negotiation.
    $this
      ->drupalPost('admin/config/regional/language/configure', array(
      'language[enabled][locale-url]' => 1,
    ), t('Save settings'));
  }

  /**
   * Sets up SBP Paths with a path to index.
   */
  function setupPath() {
    $path_add_path = 'admin/config/search/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/config/regional/translate/translate', array(
        'string' => $english,
      ), 'Filter');
      $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/config/regional/translate/translate', array(
      'string' => $english,
      'group' => 'default',
    ), 'Filter');
    $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");
    }
  }

}

/**
 * Tests that the right theme is used for indexing.
 *
 * This was issue http://drupal.org/node/1598710.
 */
class SearchByPageThemeTest extends SearchByPageTester {
  public $superuser;
  public static function getInfo() {
    return array(
      'name' => t('Search by Page Theme Test'),
      'description' => t('Test that the right theme is used for indexing'),
      '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',
      'administer themes',
      'view the administration theme',
    ));
    $this
      ->drupalLogin($this->superuser);

    // Set up indexing of pages.
    $this
      ->drupalPost('admin/config/search/search_by_page/edit/' . $this->envid1, array(
      'button_label' => t('Search pages'),
    ), 'Save configuration');
    $path_add_path = 'admin/config/search/search_by_page/edit/' . $this->envid1 . '/paths/add';
    $this
      ->drupalPost($path_add_path, array(
      'path' => 'sbp_test_pub_page',
      'title' => t("Public page"),
      'type' => t('Page'),
      'snippet' => 'yes',
      'role' => $this
        ->getNewRoleID($this->superuser),
    ), 'Create new indexed page');

    // Turn on the administrative theme.
    $this
      ->drupalPost('admin/appearance', array(
      'admin_theme' => 'seven',
    ), t('Save configuration'));

    // Add different blocks to the Content region in the admin and regular
    // themes.
    $this
      ->drupalPost('admin/structure/block', array(
      'blocks[sbp_test_cat][region]' => 'content',
    ), t('Save blocks'));
    $this
      ->drupalPost('admin/structure/block/list/seven', array(
      'blocks[sbp_test_dog][region]' => 'content',
    ), t('Save blocks'));
    cache_clear_all('variables', 'cache_bootstrap');
    variable_initialize();

    // Run cron by clicking on the Status Report link.
    $this
      ->drupalGet('admin/reports/status');
    $this
      ->clickLink('run cron manually');
    $this
      ->drupalGet('admin/reports/dblog');
    $this
      ->assertText(t('Cron run completed'), 'Log shows cron run completed');
    $this
      ->assertText('dog', 'Dog block is showing on admin page');
  }

  /**
   * Tests that the right theme was used to index the page.
   */
  function testTheme() {
    $search_path = $this->envinfo1['page_path'];

    // Search for Cat (block in the right theme) should be successful.
    $this
      ->drupalPost($search_path, array(
      'keys' => 'cat',
    ), t('Search pages'));
    $this
      ->assertText('Trees', "Found Trees on the search results page");
    $this
      ->assertText('cat', "Found cat block on the search results page");
    $this
      ->assertNoText('dog', "Did not find dog block on the search results page");

    // Search for Dog (block in the wrong theme) should not be successful.
    $this
      ->drupalPost($search_path, array(
      'keys' => 'dog',
    ), t('Search pages'));
    $this
      ->assertText('Your search yielded no results', 'Search for dog was unsuccessful');
  }

}

Classes

Namesort descending Description
SearchbyPageAttach2Test Functionality test 2 for Search by Page Attachments.
SearchbyPageAttachNotReadable Tests attachments that cannot be read.
SearchbyPageAttachReindexTest Tests attachment reindexing.
SearchByPageAttachTest Functionality test 1 for Search by Page Attachments.
SearchByPageEnvironmentTest Basic search environments test.
SearchByPageExtraUsersTest Tests that no extra Search by Page indexing users are created.
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.
SearchByPageThemeTest Tests that the right theme is used for indexing.
SearchByPageUnitTest Unit tests for Search by Page functions.
SearchByPageUsersReindexTest Tests when users are reindexed.
SearchByPageUsersTest Functionality tests for Search by Page Users.