<?php
// $Id: text.test,v 1.22 2010/04/10 10:01:15 dries Exp $

class TextFieldTestCase extends DrupalWebTestCase {
  protected $instance;
  protected $admin_user;
  protected $web_user;

  public static function getInfo() {
    return array(
      'name'  => 'Text field',
      'description'  => "Test the creation of text fields.",
      'group' => 'Field types'
    );
  }

  function setUp() {
    parent::setUp('field_test');

    $this->admin_user = $this->drupalCreateUser(array('administer filters'));
    $this->web_user = $this->drupalCreateUser(array('access field_test content', 'administer field_test content'));
    $this->drupalLogin($this->web_user);
  }

  // Test fields.

  /**
   * Test text field validation.
   */
  function testTextFieldValidation() {
    // Create a field with settings to validate.
    $max_length = 3;
    $this->field = array(
      'field_name' => drupal_strtolower($this->randomName()),
      'type' => 'text',
      'settings' => array(
        'max_length' => $max_length,
      )
    );
    field_create_field($this->field);
    $this->instance = array(
      'field_name' => $this->field['field_name'],
      'entity_type' => 'test_entity',
      'bundle' => 'test_bundle',
      'widget' => array(
        'type' => 'text_textfield',
      ),
      'display' => array(
        'full' => array(
          'type' => 'text_default',
        ),
      ),
    );
    field_create_instance($this->instance);
    // Test valid and invalid values with field_attach_validate().
    $entity = field_test_create_stub_entity();
    $langcode = LANGUAGE_NONE;
    for ($i = 0; $i <= $max_length + 2; $i++) {
      $entity->{$this->field['field_name']}[$langcode][0]['value'] = str_repeat('x', $i);
      try {
        field_attach_validate('test_entity', $entity);
        $this->assertTrue($i <= $max_length, "Length $i does not cause validation error when max_length is $max_length");
      }
      catch (FieldValidationException $e) {
        $this->assertTrue($i > $max_length, "Length $i causes validation error when max_length is $max_length");
      }
    }
  }

  /**
   * Test widgets.
   */
  function testTextfieldWidgets() {
    $this->_testTextfieldWidgets('text', 'text_textfield');
    $this->_testTextfieldWidgets('text_long', 'text_textarea');
  }

  /**
   * Helper function for testTextfieldWidgets().
   */
  function _testTextfieldWidgets($field_type, $widget_type) {
    // Setup a field and instance
    $entity_type = 'test_entity';
    $this->field_name = drupal_strtolower($this->randomName());
    $this->field = array('field_name' => $this->field_name, 'type' => $field_type);
    field_create_field($this->field);
    $this->instance = array(
      'field_name' => $this->field_name,
      'entity_type' => 'test_entity',
      'bundle' => 'test_bundle',
      'label' => $this->randomName() . '_label',
      'settings' => array(
        'text_processing' => TRUE,
      ),
      'widget' => array(
        'type' => $widget_type,
      )
    );
    field_create_instance($this->instance);
    $langcode = LANGUAGE_NONE;

    // Display creation form.
    $this->drupalGet('test-entity/add/test-bundle');
    $this->assertFieldByName("{$this->field_name}[$langcode][0][value]", '', t('Widget is displayed'));
    $this->assertNoFieldByName("{$this->field_name}[$langcode][0][format]", '1', t('Format selector is not displayed'));

    // Submit with some value.
    $value = $this->randomName();
    $edit = array(
      "{$this->field_name}[$langcode][0][value]" => $value,
    );
    $this->drupalPost(NULL, $edit, t('Save'));
    preg_match('|test-entity/(\d+)/edit|', $this->url, $match);
    $id = $match[1];
    $this->assertRaw(t('test_entity @id has been created.', array('@id' => $id)), t('Entity was created'));

    // Display the entity.
    $entity = field_test_entity_test_load($id);
    $entity->content = field_attach_view($entity_type, $entity);
    $this->content = drupal_render($entity->content);
    $this->assertText($value, 'Filtered tags are not displayed');
  }

  /**
   * Test widgets + 'formatted_text' setting.
   */
  function testTextfieldWidgetsFormatted() {
    $this->_testTextfieldWidgetsFormatted('text', 'text_textfield');
    $this->_testTextfieldWidgetsFormatted('text_long', 'text_textarea');
  }

  /**
   * Helper function for testTextfieldWidgetsFormatted().
   */
  function _testTextfieldWidgetsFormatted($field_type, $widget_type) {
    // Setup a field and instance
    $entity_type = 'test_entity';
    $this->field_name = drupal_strtolower($this->randomName());
    $this->field = array('field_name' => $this->field_name, 'type' => $field_type);
    field_create_field($this->field);
    $this->instance = array(
      'field_name' => $this->field_name,
      'entity_type' => 'test_entity',
      'bundle' => 'test_bundle',
      'label' => $this->randomName() . '_label',
      'settings' => array(
        'text_processing' => TRUE,
      ),
      'widget' => array(
        'type' => $widget_type,
      )
    );
    field_create_instance($this->instance);
    $langcode = LANGUAGE_NONE;

    // Delete all text formats besides the plain text fallback format.
    $this->drupalLogin($this->admin_user);
    foreach (filter_formats() as $format) {
      if ($format->format != filter_fallback_format()) {
        $this->drupalPost('admin/config/content/formats/' . $format->format . '/delete', array(), t('Delete'));
      }
    }
    $this->drupalLogin($this->web_user);

    // Display the creation form. Since the user only has access to one format,
    // no format selector will be displayed.
    $this->drupalGet('test-entity/add/test-bundle');
    $this->assertFieldByName("{$this->field_name}[$langcode][0][value]", '', t('Widget is displayed'));
    $this->assertNoFieldByName("{$this->field_name}[$langcode][0][format]", '', t('Format selector is not displayed'));

    // Submit with data that should be filtered.
    $value = '<em>' . $this->randomName() . '</em>';
    $edit = array(
      "{$this->field_name}[$langcode][0][value]" => $value,
    );
    $this->drupalPost(NULL, $edit, t('Save'));
    preg_match('|test-entity/(\d+)/edit|', $this->url, $match);
    $id = $match[1];
    $this->assertRaw(t('test_entity @id has been created.', array('@id' => $id)), t('Entity was created'));

    // Display the entity.
    $entity = field_test_entity_test_load($id);
    $entity->content = field_attach_view($entity_type, $entity);
    $this->content = drupal_render($entity->content);
    $this->assertNoRaw($value, t('HTML tags are not displayed.'));
    $this->assertRaw(check_plain($value), t('Escaped HTML is displayed correctly.'));

    // Create a new text format that does not escape HTML, and grant the user
    // access to it.
    $this->drupalLogin($this->admin_user);
    $edit = array('name' => $this->randomName());
    $this->drupalPost('admin/config/content/formats/add', $edit, t('Save configuration'));
    filter_formats_reset();
    $this->checkPermissions(array(), TRUE);
    $format_id = db_query("SELECT format FROM {filter_format} WHERE name = :name", array(':name' => $edit['name']))->fetchField();
    $permission = filter_permission_name(filter_format_load($format_id));
    $rid = max(array_keys($this->web_user->roles));
    user_role_grant_permissions($rid, array($permission));
    $this->drupalLogin($this->web_user);

    // Display edition form.
    // We should now have a 'text format' selector.
    $this->drupalGet('test-entity/' . $id . '/edit');
    $this->assertFieldByName("{$this->field_name}[$langcode][0][value]", '', t('Widget is displayed'));
    $this->assertFieldByName("{$this->field_name}[$langcode][0][format]", '', t('Format selector is displayed'));

    // Edit and change the text format to the new one that was created.
    $edit = array(
      "{$this->field_name}[$langcode][0][format]" => $format_id,
    );
    $this->drupalPost(NULL, $edit, t('Save'));
    $this->assertRaw(t('test_entity @id has been updated.', array('@id' => $id)), t('Entity was updated'));

    // Display the entity.
    $entity = field_test_entity_test_load($id);
    $entity->content = field_attach_view($entity_type, $entity);
    $this->content = drupal_render($entity->content);
    $this->assertRaw($value, t('Value is displayed unfiltered'));
  }
}

class TextSummaryTestCase extends DrupalWebTestCase {
  public static function getInfo() {
    return array(
      'name' => 'Text summary',
      'description' => 'Test text_summary() with different strings and lengths.',
      'group' => 'Field types',
    );
  }

  /**
   * Tests an edge case where the first sentence is a question and
   * subsequent sentences are not. This edge case is documented at
   * http://drupal.org/node/180425.
   */
  function testFirstSentenceQuestion() {
    $text = 'A question? A sentence. Another sentence.';
    $expected = 'A question? A sentence.';
    $this->callTextSummary($text, $expected, NULL, 30);
  }

  /**
   * Test summary with long example.
   */
  function testLongSentence() {
    $text = 'Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. ' . // 125
            'Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. ' . // 108
            'Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. ' . // 103
            'Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.'; // 110
    $expected = 'Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. ' .
                'Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. ' .
                'Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur.';
    // First three sentences add up to: 336, so add one for space and then 3 to get half-way into next word.
    $this->callTextSummary($text, $expected, NULL, 340);
  }

  /**
   * Test various summary length edge cases.
   */
  function testLength() {
    // This string tests a number of edge cases.
    $text = "<p>\nHi\n</p>\n<p>\nfolks\n<br />\n!\n</p>";

    // The summaries we expect text_summary() to return when $size is the index
    // of each array item.
    // Using no text format:
    $expected = array(
      "<p>\nHi\n</p>\n<p>\nfolks\n<br />\n!\n</p>",
      "<",
      "<p",
      "<p>",
      "<p>\n",
      "<p>\nH",
      "<p>\nHi",
      "<p>\nHi\n",
      "<p>\nHi\n<",
      "<p>\nHi\n</",
      "<p>\nHi\n</p",
      "<p>\nHi\n</p>",
      "<p>\nHi\n</p>",
      "<p>\nHi\n</p>",
      "<p>\nHi\n</p>",
      "<p>\nHi\n</p>",
      "<p>\nHi\n</p>",
      "<p>\nHi\n</p>",
      "<p>\nHi\n</p>",
      "<p>\nHi\n</p>",
      "<p>\nHi\n</p>",
      "<p>\nHi\n</p>",
      "<p>\nHi\n</p>",
      "<p>\nHi\n</p>",
      "<p>\nHi\n</p>",
      "<p>\nHi\n</p>",
      "<p>\nHi\n</p>",
      "<p>\nHi\n</p>",
      "<p>\nHi\n</p>",
      "<p>\nHi\n</p>",
      "<p>\nHi\n</p>",
      "<p>\nHi\n</p>",
      "<p>\nHi\n</p>",
      "<p>\nHi\n</p>",
      "<p>\nHi\n</p>",
      "<p>\nHi\n</p>\n<p>\nfolks\n<br />\n!\n</p>",
      "<p>\nHi\n</p>\n<p>\nfolks\n<br />\n!\n</p>",
      "<p>\nHi\n</p>\n<p>\nfolks\n<br />\n!\n</p>",
    );

    // And using a text format WITH the line-break and htmlcorrector filters.
    $expected_lb = array(
      "<p>\nHi\n</p>\n<p>\nfolks\n<br />\n!\n</p>",
      "",
      "<p></p>",
      "<p></p>",
      "<p></p>",
      "<p></p>",
      "<p></p>",
      "<p>\nHi</p>",
      "<p>\nHi</p>",
      "<p>\nHi</p>",
      "<p>\nHi</p>",
      "<p>\nHi\n</p>",
      "<p>\nHi\n</p>",
      "<p>\nHi\n</p>",
      "<p>\nHi\n</p>",
      "<p>\nHi\n</p>",
      "<p>\nHi\n</p>",
      "<p>\nHi\n</p>",
      "<p>\nHi\n</p>",
      "<p>\nHi\n</p>",
      "<p>\nHi\n</p>",
      "<p>\nHi\n</p>",
      "<p>\nHi\n</p>",
      "<p>\nHi\n</p>",
      "<p>\nHi\n</p>",
      "<p>\nHi\n</p>",
      "<p>\nHi\n</p>",
      "<p>\nHi\n</p>",
      "<p>\nHi\n</p>",
      "<p>\nHi\n</p>",
      "<p>\nHi\n</p>",
      "<p>\nHi\n</p>",
      "<p>\nHi\n</p>",
      "<p>\nHi\n</p>",
      "<p>\nHi\n</p>",
      "<p>\nHi\n</p>\n<p>\nfolks\n<br />\n!\n</p>",
      "<p>\nHi\n</p>\n<p>\nfolks\n<br />\n!\n</p>",
      "<p>\nHi\n</p>\n<p>\nfolks\n<br />\n!\n</p>",
    );

    // Test text_summary() for different sizes.
    for ($i = 0; $i <= 37; $i++) {
      $this->callTextSummary($text, $expected[$i],    NULL, $i);
      $this->callTextSummary($text, $expected_lb[$i], 1,    $i);
      $this->callTextSummary($text, $expected_lb[$i], 2,    $i);
    }
  }

  /**
   * Calls text_summary() and asserts that the expected teaser is returned.
   */
  function callTextSummary($text, $expected, $format = NULL, $size = NULL) {
    $summary = text_summary($text, $format, $size);
    $this->assertIdentical($summary, $expected, t('Generated summary "@summary" matches expected "@expected".', array('@summary' => $summary, '@expected' => $expected)));
  }
}
