<?php

/**
 * @file
 * Tests for Entity translation module.
 */

/**
 * Base class for entity translation module tests.
 */
class EntityTranslationTestCase extends DrupalWebTestCase {

  protected $current_user;
  protected $admin_user;
  protected $translator_user;

  /**
   * {@inheritdoc}
   */
  function setUp() {
    $args = func_get_args();
    call_user_func_array(array('parent', 'setUp'), $args);

    // Reset user fields to make test object reusable.
    unset($this->current_user);
    unset($this->admin_user);
    unset($this->translator_user);
  }

  /**
   * Retrieves a Drupal path or an absolute path with language.
   *
   * @param $language
   *   Language code or language object.
   */
  function get($language, $path = '', array $options = array(), array $headers = array()) {
    $options['language'] = $this->getLanguage($language);
    return $this->drupalGet($path, $options, $headers);
  }

  /**
   * Posts to a Drupal path with language.
   */
  function post($language, $path, $edit, $submit, array $options = array(), array $headers = array(), $form_html_id = NULL, $extra_post = NULL) {
    $options['language'] = $this->getLanguage($language);
    $this->drupalPost($path, $edit, $submit, $options, $headers, $form_html_id, $extra_post);
  }

  /**
   * Login the given user only if she has not changed.
   */
  function login($user) {
    if (!isset($this->current_user) || $this->current_user->uid != $user->uid) {
      $this->current_user = $user;
      $this->drupalLogin($user);
    }
  }

  /**
   * Returns a user with administration rights.
   *
   * @param $permissions
   *   Additional permissions for administrative user.
   */
  function getAdminUser(array $permissions = array()) {
    if (!isset($this->admin_user)) {
      $this->admin_user = $this->drupalCreateUser(array_merge(array(
        'bypass node access',
        'administer nodes',
        'administer fields',
        'administer languages',
        'administer content types',
        'administer blocks',
        'access administration pages',
        'administer site configuration',
      ), $permissions));
    }
    return $this->admin_user;
  }

  /**
   * Returns a user with minimal translation rights.
   *
   * @param $permissions
   *   Additional permissions for administrative user.
   */
  function getTranslatorUser(array $permissions = array()) {
    if (!isset($this->translator_user)) {
      $this->translator_user = $this->drupalCreateUser(array_merge(array(
        'create page content',
        'edit own page content',
        'delete own page content',
        'translate any entity',
      ), $permissions));
    }
    return $this->translator_user;
  }

  /**
   * Make sure the clean urls are enabled.
   */
  function enableCleanUrls() {
    $this->drupalGet('admin/config/search/clean-urls');
    $edit = array();
    $edit['clean_url'] = TRUE;
    $this->drupalPost(NULL, $edit, t('Save configuration'));
  }

  /**
   * Enable URL language detection.
   */
  function enableUrlLanguageDetection() {
    // Enable URL language detection and selection.
    $edit = array(
      'language[enabled][locale-url]' => TRUE,
      'language_content[enabled][locale-interface]' => TRUE
    );
    $this->drupalPost('admin/config/regional/language/configure', $edit, t('Save settings'));
    $this->assertRaw(t('Language negotiation configuration saved.'), t('URL language detection enabled.'));
    $this->drupalGet('admin/config/regional/language/configure');
    // Reset caches.
    drupal_static_reset('locale_url_outbound_alter');
    drupal_static_reset('language_list');
  }

  /**
   * Get a language object from a language code.
   */
  public function getLanguage($langcode) {
    if (is_object($langcode)) {
      return $langcode;
    }
    else {
      $language_list = language_list();
      return $language_list[$langcode];
    }
  }

  /**
   * Disable a language which is in the language list.
   *
   * @param string $langcode
   *   The code of the language to disable, which must exist.
   */
  function disableLanguage($langcode) {
    $edit = array(
      'enabled[' . $langcode . ']' => FALSE,
    );
    $this->drupalPost('admin/config/regional/language', $edit, 'Save configuration');
  }

  /**
   * Install a specified language if it has not been already, otherwise make sure that the language is enabled.
   *
   * @param $langcode
   *   The language code to check.
   */
  function addLanguage($langcode) {
    // Check to make sure that language has not already been installed.
    $this->drupalGet('admin/config/regional/language');

    if (strpos($this->drupalGetContent(), 'enabled[' . $langcode . ']') === FALSE) {
      // Doesn't have language installed so add it.
      $edit = array();
      $edit['langcode'] = $langcode;
      $this->drupalPost('admin/config/regional/language/add', $edit, t('Add language'));

      // Make sure we are not using a stale list.
      drupal_static_reset('language_list');
      $languages = language_list('language');
      $this->assertTrue(array_key_exists($langcode, $languages), t('Language was installed successfully.'));

      if (array_key_exists($langcode, $languages)) {
        $this->assertRaw(t('The language %language has been created and can now be used. More information is available on the <a href="@locale-help">help screen</a>.', array('%language' => $languages[$langcode]->name, '@locale-help' => url('admin/help/locale'))), t('Language has been created.'));
      }
    }
    elseif ($this->xpath('//input[@type="checkbox" and @name=:name and @checked="checked"]', array(':name' => 'enabled[' . $langcode . ']'))) {
      // It is installed and enabled. No need to do anything.
      $this->assertTrue(TRUE, 'Language [' . $langcode . '] already installed and enabled.');
    }
    else {
      // It is installed but not enabled. Enable it.
      $this->assertTrue(TRUE, 'Language [' . $langcode . '] already installed.');
      $this->drupalPost(NULL, array('enabled[' . $langcode . ']' => TRUE), t('Save configuration'));
      $this->assertRaw(t('Configuration saved.'), t('Language successfully enabled.'));
    }
  }

  /**
   * Configure the "Basic page" content type for entity translation tests.
   */
  function configureContentType() {
    // Configure the "Basic page" content type to use multilingual support with
    // translation.
    $edit = array();
    $edit['language_content_type'] = ENTITY_TRANSLATION_ENABLED;
    $this->drupalPost('admin/structure/types/manage/page', $edit, t('Save content type'));
    $this->assertRaw(t('The content type %type has been updated.', array('%type' => 'Basic page')), t('Basic page content type has been updated.'));

    // Set body field's cardinality to unlimited and toggle translatability.
    $edit = array();
    $edit['field[cardinality]'] = FIELD_CARDINALITY_UNLIMITED;
    $edit['field[translatable]'] = 1;
    $this->drupalPost('admin/structure/types/manage/page/fields/body', $edit, t('Save settings'));
    $this->assertRaw(t('Saved %field configuration.', array('%field' => 'Body')), t('Body field settings have been updated.'));

    // Check if the setting works.
    $this->drupalGet('node/add/page');
    $this->assertFieldById('edit-body-en-add-more', t('Add another item'), t('Add another item button found.'));

    // Settings defaults for new page nodes.
    variable_set('entity_translation_settings_node__page', array(
      'default_language' => ENTITY_TRANSLATION_LANGUAGE_CURRENT,
      'hide_language_selector' => 0,
      'exclude_language_none' => 1,
      'lock_language' => 1,
      'shared_fields_original_only' => 0,
      'locale_field_language_fallback' => 0,
    ));
  }

  /**
   * Create a "Basic page" in the specified language.
   *
   * @param $title
   *   Title of the basic page in the specified language.
   * @param $body
   *   Body of the basic page in the specified language.
   * @param $langcode
   *   The language code to be assigned to the specified values.
   */
  function createPage($title, $body, $langcode) {
    $edit = array();
    $edit["title"] = $title;
    $edit["body[$langcode][0][value]"] = $body;
    $edit['language'] = $langcode;
    $this->drupalPost('node/add/page', $edit, t('Save'));
    $this->assertRaw(t('Basic page %title has been created.', array('%title' => $title)), t('Basic page created.'));

    // Check to make sure the node was created.
    $node = $this->drupalGetNodeByTitle($title);
    $this->assertTrue($node, t('Node found in database.'));

    return $node;
  }

  /**
   * Create a translation.
   *
   * @param $node
   *   Node of the basic page to create translation for.
   * @param $title
   *   Title of the basic page in the specified language.
   * @param $body
   *   Body of the basic page in the specified language.
   * @param $langcode
   *   The language code to be assigned to the specified values.
   */
  function createTranslation($node, $title, $body, $langcode, $source_langcode = 'en') {
    $this->drupalGet('node/' . $node->nid . '/edit/add/' . $source_langcode . '/' . $langcode);

    $body_key = "body[$langcode][0][value]";
    $this->assertFieldByXPath("//textarea[@name='$body_key']", $node->body[$source_langcode][0]['value'], 'Original body value correctly populated.');
    $this->assertFieldById('edit-body-' . $langcode . '-add-more', t('Add another item'), t('Add another item button found.'));

    $edit = array();
    $edit[$body_key] = $body;

    $this->drupalPost(NULL, $edit, t('Save'));
    $this->drupalGet('node/' . $node->nid . '/translate');
    $this->assertLinkByHref('node/' . $node->nid . '/edit/' . $langcode, 0, t('Translation edit link found. Translation created.'));

    return $node;
  }
}

/**
 * Basic tests for the translation creation/editing workflow.
 */
class EntityTranslationTranslationTestCase extends EntityTranslationTestCase {

  /**
   * Return the test information.
   */
  public static function getInfo() {
    return array(
      'name' => 'Entity translation workflow',
      'description' => 'Basic tests for the translation creation/editing workflow.',
      'group' => 'Entity translation',
    );
  }

  function setUp() {
    parent::setUp('locale', 'entity_translation', 'entity_translation_test');
    $perms = array(
      'administer entity translation',
    );
    $this->login($this->getAdminUser($perms));
    $this->addLanguage('en');
    $this->addLanguage('es');
    $this->addLanguage('fr');
    $this->disableLanguage('fr');
    $this->configureContentType();
    $this->enableUrlLanguageDetection();
    $this->login($this->getTranslatorUser());
  }

  /**
   * Test disabled languages.
   *
   * Make sure disabled languages are not accessible in the language list when
   * the option entity_translation_languages_enabled is enabled.
   */
  function testDisabledLanguages() {
    $this->drupalGet('node/add/page');
    $this->assertRaw('value="fr"', 'French is available even if the language is disabled');

    variable_set('entity_translation_languages_enabled', TRUE);
    $this->drupalGet('node/add/page');
    $this->assertNoRaw('value="fr"', 'French is not available when the language is disabled and the option entity_translation_languages_enabled is enabled.');
  }

  /**
   * Test if field based translation works.
   *
   * Enable field based translation for basic pages. Add a field with a
   * cardinality higher than 1, to test if field_default_extract_form_values()
   * is invoked. Create a basic page and translate it.
   */
  function testFieldTranslation() {
    // Create Basic page in English.
    $node_title = $this->randomName();
    $node_body = $this->randomName();
    $node = $this->createPage($node_title, $node_body, 'en');

    // Submit translation in Spanish.
    $node_translation_title = $this->randomName();
    $node_translation_body = $this->randomName();
    $node_translation = $this->createTranslation($node, $node_translation_title, $node_translation_body, 'es');
  }

  /**
   * Tests the interplay of the locale language selector on a new Page node.
   *
   * Add a new Page node in a given language (using URL language detection).
   * On the node page form, use the Locale language field to set the new node's
   * language to a language different from the URL language.
   * Make sure that the newly created node has translatable fields created in the
   * Locale's set language (and not the one coming from the URL).
   */
  function testLocaleLanguageWidgetTranslation() {
    variable_set('entity_translation_test_disable_form_cache', TRUE);
    // Create Basic page in Spanish.
    $this->drupalGet('es/node/add/page');
    $node_title = $this->randomName();
    $node_body = $this->randomName();
    $edit["title"] = $node_title;
    $edit["body[es][0][value]"] = $node_body;
    // But switch the locale field to English.
    $edit['language'] = 'en';
    $this->drupalPost(NULL, $edit, t('Save'));
    $node = $this->drupalGetNodeByTitle($node_title);
    $this->assertTrue(in_array('en', array_keys($node->body)), 'Locale field language settings takes precedence.');
  }

}

/**
 * Basic tests for comment related things.
 *
 * @todo Add tests for comment translation workflow.
 */
class EntityTranslationCommentTestCase extends EntityTranslationTestCase {

  protected $comment_user;

  /**
   * Return the test information.
   */
  public static function getInfo() {
    return array(
      'name' => 'Comment translation',
      'description' => 'Basic tests for comment translation/filtering.',
      'group' => 'Entity translation',
    );
  }

  function setUp() {
    parent::setUp('locale', 'entity_translation', 'comment');
    $this->login($this->getAdminUser());
    $this->addLanguage('en');
    $this->addLanguage('es');
    $this->enableUrlLanguageDetection();
    $this->configureContentType();
    $this->configureComments(FALSE);
    $this->login($this->getTranslatorUser());
  }

  function tearDown() {
    unset($this->comment_user);
    parent::tearDown();
  }

  function getCommentUser() {
    if (empty($this->comment_user)) {
      $this->comment_user = $this->drupalCreateUser(array(
        'access comments',
        'post comments',
        'edit own comments',
      ));
    }
    return $this->comment_user;
  }

  /**
   * Enable comments and comment filtering by language.
   */
  function configureComments($filter_by_language = TRUE) {
    $edit = array();
    $edit['comment'] = COMMENT_NODE_OPEN;
    $edit['entity_translation_comment_filter'] = $filter_by_language;
    $this->drupalPost('admin/structure/types/manage/page', $edit, t('Save content type'));
    $this->assertRaw(t('The content type %type has been updated.', array('%type' => 'Basic page')));

    $this->drupalGet('admin/structure/types/manage/page');
    if ($filter_by_language) {
      $this->assertFieldChecked('edit-entity-translation-comment-filter', 'Comment filtering is enabled.');
    }
    else {
      $this->assertNoFieldChecked('edit-entity-translation-comment-filter', 'Comment filtering is disabled.');
    }
  }

  /**
   * Add a comment for the given node.
   *
   * @param $node
   *   The node for which to add the comment.
   * @param $comment_body
   *   The comment body text.
   * @param $language
   *   The comment language.
   */
  function postComment($node, $comment_body, $language) {
    $edit = array();
    $edit['comment_body[' . LANGUAGE_NONE . '][0][value]'] = $comment_body;
    $this->post($language, 'comment/reply/' . $node->nid, $edit, t('Save'));
  }

  /**
   * Test comment filtering by language.
   */
  function testCommentLanguageFiltering() {
    $node = $this->createPage($this->randomName(), $this->randomName(), 'en');
    $this->login($this->getCommentUser());

    // Create comments in different languages.
    $comment_en = $this->randomName();
    $this->postComment($node, $comment_en, 'en');
    $comment_es = $this->randomName();
    $this->postComment($node, $comment_es, 'es');

    // Check that ALL comments are being displayed when comment language filter
    // is disabled (default behavior).
    $this->get('en', 'node/' . $node->nid);
    $this->assertText($comment_en, 'English comment found.');
    $this->assertText($comment_es, 'Spanish comment found.');

    // Enable comment filtering by language.
    $this->login($this->getAdminUser());
    $this->configureComments(TRUE);
    $this->login($this->getCommentUser());

    // Load page in different languages. Check that only comments matching
    // current language are being displayed.
    $this->get('en', 'node/' . $node->nid);
    $this->assertText($comment_en, 'English comment found.');
    $this->assertNoText($comment_es, 'Spanish comment not found.');

    $this->get('es', 'node/' . $node->nid);
    $this->assertNoText($comment_en, 'English comment not found.');
    $this->assertText($comment_es, 'Spanish comment found.');
  }
}

/**
 * Test CRUD hook invocation.
 */
class EntityTranslationHookTestCase extends EntityTranslationTestCase {

  /**
   * Return the test information.
   */
  public static function getInfo() {
    return array(
      'name' => 'Entity translation hooks',
      'description' => 'Test that entity translation hooks are properly fired.',
      'group' => 'Entity translation',
    );
  }

  function setUp() {
    parent::setUp('locale', 'entity_translation', 'entity_translation_test');
    $this->login($this->getAdminUser());
    $this->addLanguage('it');
    $this->addLanguage('es');
    $this->configureContentType();
    $this->login($this->getTranslatorUser());
  }

  /**
   * Test whether hooks are properly fired in the regular form workflow.
   */
  function testFormWorkflow() {
    // Create Basic page in English.
    $node_title = $this->randomName();
    $node_body = $this->randomName();
    $node = $this->createPage($node_title, $node_body, 'en');

    // Submit translation in Italian.
    $node_translation_body = $this->randomName();
    $this->createTranslation($node, NULL, $node_translation_body, 'it');
    $info = $this->getHookInfo();
    $this->assertTrue(!empty($info['insert']), t('Insert hook has been properly fired.'));

    // Edit translation in Italian.
    $edit = array("body[it][0][value]" => $this->randomName());
    $this->drupalPost('node/' . $node->nid . '/edit/it', $edit, t('Save'));
    $info = $this->getHookInfo();
    $this->assertTrue(!empty($info['update']), t('Update hook has been properly fired.'));

    // Delete the Basic page.
    $edit = array();
    $this->drupalPost('node/' . $node->nid . '/delete', $edit, t('Delete'));
    $info = $this->getHookInfo('delete');
    $this->assertTrue(count($info) == 2 && !empty($info['en']) && !empty($info['it']), t('Delete hook has been properly fired.'));
  }

  /**
   * Test whether hooks are properly fired when using the API.
   */
  function testAPI() {
    // Create Basic page in English.
    $node = $this->createPage($this->randomName(), $this->randomName(), 'en');
    $handler = entity_translation_get_handler('node', $node);

    // Create a translation in Italian.
    $translation = array('source' => 'en', 'language' => 'it');
    $handler->setTranslation($translation);
    $handler->saveTranslations();
    $node = node_load($node->nid, NULL, TRUE);
    $handler = entity_translation_get_handler('node', $node);
    $translations = $handler->getTranslations();
    $this->assertTrue(!empty($translations->data['it']), t('An Italian translation has been created'));
    $info = $this->getHookInfo();
    $this->assertTrue(!empty($info['insert']), t('Insert hook has been properly fired.'));

    // Check that the update hook is properly fired.
    $translation['status'] = 1;
    $handler->setTranslation($translation);
    $handler->saveTranslations();
    $info = $this->getHookInfo();
    $this->assertTrue(!empty($info['update']), t('Update hook has been properly fired.'));

    // Create a Spanish translation and update it before saving it.
    $translation = array('source' => 'it', 'language' => 'es');
    $handler->setTranslation($translation);
    $translation['status'] = 1;
    $handler->setTranslation($translation);
    $handler->saveTranslations();
    $node = node_load($node->nid, NULL, TRUE);
    $handler = entity_translation_get_handler('node', $node);
    $translations = $handler->getTranslations();
    $this->assertTrue(!empty($translations->data['es']), t('A Spanish translation has been created'));
    $info = $this->getHookInfo();
    $this->assertTrue(!empty($info['insert']), t('Insert hook has been properly fired.'));

    // Delete a translation after updating it without saving.
    $translation['status'] = 0;
    $handler->setTranslation($translation);
    $handler->removeTranslation('es');
    $handler->saveTranslations();
    $info = $this->getHookInfo();
    $this->assertTrue(empty($info['update']), t('Update hook has not been fired.'));
    $info = $this->getHookInfo('delete');
    $this->assertTrue(!empty($info['es']), t('Delete hook has been properly fired.'));
  }

  /**
   * Retrieve the information stored by hook implementations.
   */
  protected function getHookInfo($op = 'save') {
    $name = 'entity_translation_test_' . $op;
    $info = variable_get($name);
    variable_del($name);
    return $info;
  }
}

/**
 * Tests that entity translation handler hierarchy works properly.
 */
class EntityTranslationHierarchyTestCase extends EntityTranslationTestCase {

  /**
   * Return the test information.
   */
  public static function getInfo() {
    return array(
      'name' => 'Entity translation hierarchy',
      'description' => 'Tests that entity translation handler hierarchy works properly.',
      'group' => 'Entity translation',
    );
  }

  /**
   * {@inheritdoc}
   */
  function setUp() {
    parent::setUp('locale', 'entity_translation');
  }

  /**
   * Tests the handler hierarchy.
   */
  public function testHierarchy() {
    $entity_type = 'node';
    $node = $this->drupalCreateNode();
    $factory = EntityTranslationHandlerFactory::getInstance();
    $handler = $factory->getHandler($entity_type, $node);

    $children = array();
    foreach (range(0, 4) as $index) {
      $children[$index] = $this->drupalCreateNode();
      $handler->addChild($entity_type, $children[$index]);
    }

    $langcode = 'it';
    $handler->setActiveLanguage($langcode);
    foreach ($children as $child) {
      $child_handler = $factory->getHandler($entity_type, $child);
      $this->assertEqual($child_handler->getActiveLanguage(), $langcode);
    }

    $rm_index = mt_rand(0, count($children) - 1);
    $handler->removeChild($entity_type, $children[$rm_index]);

    $langcode = 'fr';
    $handler->setActiveLanguage($langcode);
    foreach ($children as $index => $child) {
      $child_handler = $factory->getHandler($entity_type, $child);
      $this->assertEqual($child_handler->getActiveLanguage() == $langcode, $index != $rm_index);
    }

    // @todo Test the other properties.
  }

}

/**
 * Basic tests for nodes using both content and entity translation.
 */
class EntityTranslationContentTranslationTestCase extends EntityTranslationTestCase {

  /**
   * Return the test information.
   */
  public static function getInfo() {
    return array(
      'name' => 'Content and entity translation',
      'description' => 'Basic tests for nodes using both content and entity translatio.',
      'group' => 'Entity translation',
    );
  }

  /**
   * {@inheritdoc}
   */
  public function setUp() {
    // Activate modules and unset users.
    parent::setUp('locale', 'translation', 'translation_test', 'entity_translation');
    // Create admin and translator users with one extra permission,
    // namely the 'translate content' permission.
    // These getters works also as setters.
    $this->getAdminUser(array(
      'translate content',
    ));
    $this->getTranslatorUser(array(
      'translate content',
    ));
    $this->login($this->getAdminUser());
    $this->addLanguage('en');
    $this->addLanguage('es');
    $this->enableUrlLanguageDetection();
    $this->configureContentType();
    $this->login($this->getTranslatorUser());
  }

  /**
   * Configure the "Basic page" content type for entity translation tests.
   */
  public function configureContentType() {
    // Configure the "Basic page" content type to use multilingual support with
    // content translation.
    $edit = array();
    $edit['language_content_type'] = TRANSLATION_ENABLED;
    $this->drupalPost('admin/structure/types/manage/page', $edit, t('Save content type'));
    $this->assertRaw(t('The content type %type has been updated.', array('%type' => 'Basic page')), t('Basic page content type has been updated.'));

    // Toggle body field's translatability.
    $edit = array();
    $edit['field[translatable]'] = 1;
    $this->drupalPost('admin/structure/types/manage/page/fields/body', $edit, t('Save settings'));
    $this->assertRaw(t('Saved %field configuration.', array('%field' => 'Body')), t('Body field settings have been updated.'));
  }

  /**
   * @see TranslationTestCase::createPage()
   */
  function createPage($title, $body, $language = NULL) {
    $edit = array();
    $langcode = LANGUAGE_NONE;
    $edit["title"] = $title;
    $edit["body[$langcode][0][value]"] = $body;
    if (!empty($language)) {
      $edit['language'] = $language;
    }
    $this->drupalPost('node/add/page', $edit, t('Save'));
    $this->assertRaw(t('Basic page %title has been created.', array('%title' => $title)), 'Basic page created.');

    // Check to make sure the node was created.
    $node = $this->drupalGetNodeByTitle($title);
    $this->assertTrue($node, 'Node found in database.');

    return $node;
  }

  /**
   * Tests copying of source node's body value in the add translation form page.
   */
  public function testCopyFieldsUsingContentTranslation() {
    // Create Basic page in English.
    $node_title = $this->randomName();
    $node_body = $this->randomName();
    $node = $this->createPage($node_title, $node_body, 'en');

    // Check that the edit form correctly copies over the field's values from
    // the source node.
    $target_language = 'es';
    $this->drupalGet('node/add/page', array('query' => array('translation' => $node->nid, 'target' => $target_language)));
    $body_key = "body[${target_language}][0][value]";
    $this->assertFieldByXPath("//textarea[@name='$body_key']", $node_body, "Body field correctly instantiated with the value of the source language.");
  }

}

/**
 * Tests for integration of Entity Translation with other modules.
 */
class EntityTranslationIntegrationTestCase extends EntityTranslationTestCase {

  /**
   * Return the test information.
   */
  public static function getInfo() {
    return array(
      'name' => 'Integration with other modules',
      'description' => 'Tests for integration of Entity Translation with other modules.',
      'group' => 'Entity translation',
      // We need to add this to the test_dependencies[] as well.
      'dependencies' => array('pathauto'),
    );
  }

  /**
   * {@inheritdoc}
   */
  public function setUp() {
    // Activate modules.
    parent::setUp('locale', 'entity_translation');
    // Create admin and translator users with one extra permission,
    // namely the 'administer content' permission for the admin, to
    // allow enabling the pathauto module during testing. The
    // Translator user needs to be able to create url aliases.
    $this->getAdminUser(array(
      'administer modules',
    ));
    $this->getTranslatorUser(array(
      'create url aliases',
    ));
    $this->login($this->getAdminUser());
    $this->addLanguage('en');
    $this->addLanguage('es');
    $this->addLanguage('fr');
    $this->enableUrlLanguageDetection();
    $this->configureContentType();
    $this->login($this->getTranslatorUser());
  }

  /**
   * Returns the role id of an $account object.
   */
  protected function getUserRole($account) {
    return reset($account->roles);
  }

  /**
   * Tests Pathauto integration.
   */
  public function testPathautoIntegration() {
    $languages = language_list();

    // Enable and configure the pathauto module.
    $this->login($this->getAdminUser());
    if (!module_exists('pathauto')) {
      module_enable(array('pathauto'));
    }
    // Configure pathauto patterns.
    variable_set('pathauto_node_page_en_pattern', 'content/[node:title]/en_pattern');
    variable_set('pathauto_node_page_fr_pattern', 'content/[node:title]/fr_pattern');
    variable_set('pathauto_node_page_es_pattern', 'content/[node:title]/es_pattern');
    // Disable pathauto lowercase conversion.
    variable_set('pathauto_case', 0);
    // Configure pathauto related permissions.
    $admin_rid = $this->getUserRole($this->getAdminUser());
    user_role_grant_permissions($admin_rid, array('administer url aliases', 'administer pathauto'));
    $translator_rid = $this->getUserRole($this->getTranslatorUser());
    user_role_grant_permissions($translator_rid, array('create url aliases'));
    $this->login($this->getTranslatorUser());

    // Configure auto-generation of all aliases for new translations.
    variable_set('entity_translation_pathauto_state_active_new_translation', TRUE);
    variable_set('entity_translation_pathauto_state_mode_update', 'generate_all_aliases_all_languages');

    // Create Basic page in English and add a translation in Spanish.
    $node_title = $this->randomName();
    $node_body = $this->randomName();
    $node = $this->createPage($node_title, $node_body, 'en');
    $this->createTranslation($node, $node_title, $node_body, 'es');

    // Clear the static caches in case they interfere.
    drupal_lookup_path('wipe');

    // Check that a pathauto alias was created for the source and
    // matches the pathauto's pattern logic.
    $source_alias = drupal_get_path_alias('node/' . $node->nid);
    $this->assertEqual($source_alias, 'content/' . $node_title . '/en_pattern');

    // Check that a pathauto alias was created for the translation and
    // matches the pathauto's pattern logic.
    $translation_alias = drupal_get_path_alias('node/' . $node->nid, 'es');
    $this->assertEqual($translation_alias, 'content/' . $node_title . '/es_pattern');

    // Check that when adding a new translation, and the variable
    // 'entity_translation_pathauto_state_active_new_translation' is not set,
    // TRUE is used as its default value and the path[pathauto] checkbox is
    // checked.
    variable_del('entity_translation_pathauto_state_active_new_translation');
    $this->drupalGet('node/' . $node->nid . '/edit/add/en/fr');
    $this->assertFieldChecked('edit-path-pathauto');
    // Check that when adding a new translation, and the variable
    // 'entity_translation_pathauto_state_active_new_translation' is TRUE,
    // the path[pathauto] checkbox is checked.
    variable_set('entity_translation_pathauto_state_active_new_translation', TRUE);
    $this->drupalGet('node/' . $node->nid . '/edit/add/en/fr');
    $this->assertFieldChecked('edit-path-pathauto');
    // Check that when adding a new translation, and the variable
    // 'entity_translation_pathauto_state_active_new_translation' is FALSE,
    // the path[pathauto] checkbox is unchecked.
    variable_set('entity_translation_pathauto_state_active_new_translation', FALSE);
    $this->drupalGet('node/' . $node->nid . '/edit/add/en/fr');
    $this->assertNoFieldChecked('edit-path-pathauto');

    // Check that when adding a new translation, and the variables
    // 'entity_translation_pathauto_state_active_new_translation' is TRUE,
    // and 'entity_translation_pathauto_state_mode_update' is set to
    // 'generate_all_aliases_all_languages', aliases are added for all
    // languages, overwriting existing ones.
    variable_set('entity_translation_pathauto_state_active_new_translation', TRUE);
    variable_set('entity_translation_pathauto_state_mode_update', 'generate_all_aliases_all_languages');
    path_delete(array('source' => 'node/' . $node->nid));
    $path_en = drupal_get_path_alias('node/' . $node->nid, 'en');
    $path_fr = drupal_get_path_alias('node/' . $node->nid, 'fr');
    $path_es = drupal_get_path_alias('node/' . $node->nid, 'es');
    $this->createTranslation($node, $node_title, '', 'fr');
    // Clear the static caches in case they interfere.
    drupal_lookup_path('wipe');
    $path_en_new = drupal_get_path_alias('node/' . $node->nid, 'en');
    $path_fr_new = drupal_get_path_alias('node/' . $node->nid, 'fr');
    $path_es_new = drupal_get_path_alias('node/' . $node->nid, 'es');
    $this->assertNotEqual($path_en, $path_en_new);
    $this->assertNotEqual($path_fr, $path_fr_new);
    $this->assertNotEqual($path_es, $path_es_new);

    // Check that when adding a new translation, and the variables
    // 'entity_translation_pathauto_state_active_new_translation' is TRUE,
    // and 'entity_translation_pathauto_state_mode_update' is set to
    // 'generate_alias_active_language', an alias is generated only for
    // the active language, maintaining the existing one(s).
    variable_set('entity_translation_pathauto_state_active_new_translation', TRUE);
    variable_set('entity_translation_pathauto_state_mode_update', 'generate_alias_active_language');
    // Create another Basic page in English.
    $node_title = $this->randomName();
    $node_body = $this->randomName();
    $node = $this->createPage($node_title, $node_body, 'en');
    $this->createTranslation($node, $node_title, '', 'es');
    $path_en = drupal_get_path_alias('node/' . $node->nid, 'en');
    $path_es = drupal_get_path_alias('node/' . $node->nid, 'es');
    $edit = array(
      'title' => $this->randomName(),
    );
    $this->drupalPost('node/' . $node->nid . '/edit/add/en/fr', $edit, t('Save'));
    // Clear the static caches in case they interfere.
    drupal_lookup_path('wipe');
    $path_en_new = drupal_get_path_alias('node/' . $node->nid, 'en');
    $path_fr_new = drupal_get_path_alias('node/' . $node->nid, 'fr');
    $path_es_new = drupal_get_path_alias('node/' . $node->nid, 'es');
    $this->assertEqual($path_en, $path_en_new);
    $this->assertNotEqual($path_fr_new, 'node/' . $node->nid);
    $this->assertEqual($path_es, $path_es_new);

    // Check that when adding a new translation, and the variable
    // 'entity_translation_pathauto_state_active_new_translation' is FALSE
    // no alias is generated for the active language or otherwise,
    // maintaining the existing one(s), irrespective of the value of the
    // 'entity_translation_pathauto_state_mode_update' variable.
    variable_set('entity_translation_pathauto_state_active_new_translation', FALSE);
    variable_set('entity_translation_pathauto_state_mode_update', 'generate_all_aliases_all_languages');
    // Create another Basic page in English.
    $node_title = $this->randomName();
    $node_body = $this->randomName();
    $node = $this->createPage($node_title, $node_body, 'en');
    $this->createTranslation($node, $node_title, '', 'es');
    $path_en = drupal_get_path_alias('node/' . $node->nid, 'en');
    $path_es = drupal_get_path_alias('node/' . $node->nid, 'es');
    $edit = array(
      'title' => $this->randomName(),
    );
    $this->drupalPost('node/' . $node->nid . '/edit/add/en/fr', $edit, t('Save'));
    // Clear the static caches in case they interfere.
    drupal_lookup_path('wipe');
    $path_en_new = drupal_get_path_alias('node/' . $node->nid, 'en');
    $path_fr_new = drupal_get_path_alias('node/' . $node->nid, 'fr');
    $path_es_new = drupal_get_path_alias('node/' . $node->nid, 'es');
    $this->assertEqual($path_en, $path_en_new);
    $this->assertEqual($path_fr_new, 'node/' . $node->nid);
    $this->assertEqual($path_es, $path_es_new);

    // Check that when adding a new translation, and the variables
    // 'entity_translation_pathauto_state_active_new_translation' is TRUE,
    // and 'entity_translation_pathauto_state_mode_update' is set to
    // 'generate_missing_aliases_all_languages', only missing aliases are
    // generated for all languages, maintaining the existing one(s).
    variable_set('entity_translation_pathauto_state_active_new_translation', TRUE);
    variable_set('entity_translation_pathauto_state_mode_update', 'generate_missing_aliases_all_languages');
    // Create another Basic page in English.
    $node_title = $this->randomName();
    $node_body = $this->randomName();
    $node = $this->createPage($node_title, $node_body, 'en');
    $this->createTranslation($node, $node_title, '', 'es');
    path_delete(array('source' => 'node/' . $node->nid, 'language' => 'es'));
    $path_en = drupal_get_path_alias('node/' . $node->nid, 'en');
    $path_fr = drupal_get_path_alias('node/' . $node->nid, 'fr');
    $path_es = drupal_get_path_alias('node/' . $node->nid, 'es');
    $edit = array(
      'title' => $this->randomName(),
    );
    $this->drupalPost('node/' . $node->nid . '/edit/add/en/fr', $edit, t('Save'));
    // Clear the static caches in case they interfere.
    drupal_lookup_path('wipe');
    $path_en_new = drupal_get_path_alias('node/' . $node->nid, 'en');
    $path_fr_new = drupal_get_path_alias('node/' . $node->nid, 'fr');
    $path_es_new = drupal_get_path_alias('node/' . $node->nid, 'es');
    $this->assertEqual($path_en, $path_en_new);
    $this->assertNotEqual($path_fr_new, 'node/' . $node->nid);
    $this->assertNotEqual($path_es, $path_es_new);

  }

}

/**
 * Tests for enabling fields to use Entity Translation or disabling them.
 */
class EntityTranslationToggleFieldsTranslatabilityTestCase extends EntityTranslationTestCase {

  /**
   * {@inheritdoc}
   */
  public static function getInfo() {
    return array(
      'name' => 'Fields translatability toggling',
      'description' => 'Tests for enabling fields to use Entity Translation or disabling them.',
      'group' => 'Entity translation',
    );
  }

  /**
   * {@inheritdoc}
   */
  public function setUp() {
    // Activate modules.
    parent::setUp('locale', 'taxonomy', 'entity_translation', 'entity_translation_test');
    $this->login($this->getAdminUser(array(
      'administer taxonomy',
      'toggle field translatability',
    )));
    $this->login($this->getTranslatorUser(array(
      'administer taxonomy',
    )));
  }

  /**
   * Configure the "Basic page" content type for entity translation tests.
   */
  protected function configureContentTypeForRevisions() {
    // Configure the "Basic page" content type to use revisions.
    $edit = array(
      'node_options[revision]' => 1,
    );
    $this->drupalPost('admin/structure/types/manage/page', $edit, t('Save content type'));
    $this->assertRaw(t('The content type %type has been updated.', array('%type' => 'Basic page')), t('Basic page content type has been updated.'));
  }

  /**
   * Create a "Basic page" in the specified language.
   *
   * @param $title
   *   Title of the basic page in the specified language.
   * @param $body
   *   Body of the basic page in the specified language.
   */
  protected function createUntranslatedPage($title, $body) {
    $edit = array(
      'title' => $title,
      'body[und][0][value]' => $body,
    );
    $this->drupalPost('node/add/page', $edit, t('Save'));
    $this->assertRaw(t('Basic page %title has been created.', array('%title' => $title)), t('Basic page created.'));

    // Check to make sure the node was created.
    $node = $this->drupalGetNodeByTitle($title);
    $this->assertTrue($node, t('Node found in database.'));

    return $node;
  }

  /**
   * Create a "Tags" term in the specified language.
   *
   * @param $name
   *   Name of the term.
   * @param $description
   *   Description of the term.
   * @param $text
   *   Content for the field_simple_text field.
   */
  protected function createUntranslatedTag($name, $description, $text) {
    $edit = array(
      'name' => $name,
      'description[value]' => $description,
      "field_simple_text[und][0][value]" => $text,
    );
    $this->drupalPost('admin/structure/taxonomy/tags/add', $edit, t('Save'));

    // Check to make sure the term was created.
    $term = current(entity_load('taxonomy_term', FALSE, array('name' => $name), TRUE));
    $this->assertTrue($term, t('Term found in database.'));

    return $term;
  }

  /**
   * Tests toggling translatability on fields with data (non-revisionable).
   */
  public function testTogglingFieldsWithDataNonRevisionable() {
    // Create an untranslated Basic page.
    $node_title = $this->randomName();
    $node_body = $this->randomName();
    $node = $this->createUntranslatedPage($node_title, $node_body);
    $this->assert(isset($node->body[LANGUAGE_NONE]), t('Found body field data in LANGUAGE_NONE as expected.'));
    $this->assertEqual($node->body[LANGUAGE_NONE][0]['value'], $node_body);

    // Create an untranslated Tags term.
    $term_name = $this->randomName();
    $term_description = $this->randomName();
    $term_simple_text = $this->randomName();
    $term = $this->createUntranslatedTag($term_name, $term_description, $term_simple_text);
    $this->assert(isset($term->field_simple_text[LANGUAGE_NONE]), t('Found field data in LANGUAGE_NONE as expected.'));
    $this->assertEqual($term->field_simple_text[LANGUAGE_NONE][0]['value'], $term_simple_text);

    // Enable translation for field body and check field migration.
    $this->login($this->getAdminUser());
    $this->drupalGet('admin/structure/types/manage/page/fields/body');
    $this->clickLink('Enable translation');
    $this->drupalPost(NULL, array(), t('Confirm'));
    $node = current(entity_load('node', FALSE, array('title' => $node_title), TRUE));
    $this->assert(isset($node->body['en']), t('Found field data in English as expected.'));
    $this->assertEqual($node->body['en'][0]['value'], $node_body);
    $this->assert(!isset($node->body[LANGUAGE_NONE]), t('No field data in LANGUAGE_NONE found.'));

    // Disable translation for body field and check field reverse migration.
    $this->drupalGet('admin/structure/types/manage/page/fields/body');
    $this->clickLink('Disable translation');
    $this->drupalPost(NULL, array(), t('Confirm'));
    $node = current(entity_load('node', FALSE, array('title' => $node_title), TRUE));
    $this->assert(isset($node->body[LANGUAGE_NONE]), t('Found field data in LANGUAGE_NONE as expected.'));
    $this->assertEqual($node->body[LANGUAGE_NONE][0]['value'], $node_body);
    $this->assert(!isset($node->body['en']), t('No field data in English found.'));

    // Enable translation for field_simple_text and check field migration.
    $this->drupalGet('admin/structure/taxonomy/tags/fields/field_simple_text');
    $this->clickLink('Enable translation');
    $this->drupalPost(NULL, array(), t('Confirm'));
    // Clear the field cache in order to load current field data.
    field_info_cache_clear();
    // Load the term and check that the fields data are under 'en'.
    $term = current(entity_load('taxonomy_term', FALSE, array('name' => $term_name), TRUE));
    $this->assert(isset($term->field_simple_text['en']), t('Found field data in English as expected.'));
    $this->assertEqual($term->field_simple_text['en'][0]['value'], $term_simple_text);
    $this->assert(!isset($term->field_simple_text[LANGUAGE_NONE]), t('No field data in LANGUAGE_NONE found.'));

    // Disable translation for field_simple_text.
    $this->drupalGet('admin/structure/taxonomy/tags/fields/field_simple_text');
    $this->clickLink('Disable translation');
    $this->drupalPost(NULL, array(), t('Confirm'));

    // Load the term and check that the fields data are under LANGUAGE_NONE.
    $term = current(entity_load('taxonomy_term', FALSE, array('name' => $term_name), TRUE));
    $this->assert(isset($term->field_simple_text[LANGUAGE_NONE]), t('Found field data in LANGUAGE_NONE as expected.'));
    $this->assertEqual($term->field_simple_text[LANGUAGE_NONE][0]['value'], $term_simple_text);
    $this->assert(!isset($term->field_simple_text['en']), t('No field data in English found.'));
  }

  /**
   * Tests toggling translatability on fields with data (revisionable).
   */
  public function testTogglingFieldsWithDataRevisionable() {
    // Enable revisions for Basic pages.
    $this->login($this->getAdminUser());
    $this->configureContentTypeForRevisions();

    // Create an untranslated Basic page.
    $this->login($this->getTranslatorUser());
    $node_title = $this->randomName();
    $node_body = $this->randomName();
    $node = $this->createUntranslatedPage($node_title, $node_body);
    $this->assert(isset($node->body[LANGUAGE_NONE]), t('Found field data in LANGUAGE_NONE as expected.'));
    $this->assertEqual($node->body[LANGUAGE_NONE][0]['value'], $node_body);

    // Create a new revision for the page.
    $edit_revision = array(
      'title' => $this->randomName(),
    );
    $this->drupalPost('node/' . $node->nid . '/edit', $edit_revision, t('Save'));
    $node = node_load($node->nid, NULL, TRUE);
    $this->assert($node->vid == $node->nid + 1, t('Correct vid attached to the node object.'));

    // Enable translation for field body and check field migration on all
    // revisions.
    $this->login($this->getAdminUser());
    $this->drupalGet('admin/structure/types/manage/page/fields/body');
    $this->clickLink('Enable translation');
    $this->drupalPost(NULL, array(), t('Confirm'));
    $node_current_revision = current(entity_load('node', FALSE, array('vid' => $node->vid), TRUE));
    $this->assert(isset($node_current_revision->body['en']), t('Found field data in English as expected.'));
    $this->assertEqual($node_current_revision->body['en'][0]['value'], $node_body);
    $this->assert(!isset($node_current_revision->body[LANGUAGE_NONE]), t('No field data in LANGUAGE_NONE found.'));
    $node_previous_revision = current(entity_load('node', FALSE, array('vid' => ($node->vid - 1)), TRUE));
    $this->assert(isset($node_previous_revision->body['en']), t('Found field data in English as expected.'));
    $this->assertEqual($node_previous_revision->body['en'][0]['value'], $node_body);
    $this->assert(!isset($node_previous_revision->body[LANGUAGE_NONE]), t('No field data in LANGUAGE_NONE found.'));

    // Disable translation for field_body.
    $this->drupalGet('admin/structure/types/manage/page/fields/body');
    $this->clickLink('Disable translation');
    $this->drupalPost(NULL, array(), t('Confirm'));

    // Disable translation for field body and check field reverse migration on
    // all revisions.
    $node_current_revision = current(entity_load('node', FALSE, array('vid' => $node->vid), TRUE));
    $this->assert(isset($node_current_revision->body[LANGUAGE_NONE]), t('Found field data in LANGUAGE_NONE as expected.'));
    $this->assertEqual($node_current_revision->body[LANGUAGE_NONE][0]['value'], $node_body);
    $this->assert(!isset($node_current_revision->body['en']), t('No field data in English found.'));
    $node_previous_revision = current(entity_load('node', FALSE, array('vid' => ($node->vid - 1)), TRUE));
    $this->assert(isset($node_previous_revision->body[LANGUAGE_NONE]), t('Found field data in LANGUAGE_NONE as expected.'));
    $this->assertEqual($node_previous_revision->body[LANGUAGE_NONE][0]['value'], $node_body);
    $this->assert(!isset($node_previous_revision->body['en']), t('No field data in English found.'));
  }

}

/**
 * Tests for the taxonomy autocomplete translation modes.
 */
class EntityTranslationTaxonomyAutocompleteTestCase extends EntityTranslationTestCase {

  /**
   * Returns the test information.
   */
  public static function getInfo() {
    return array(
      'name' => 'Entity translation taxonomy autocomplete',
      'description' => 'Tests for the taxonomy autocomplete translation modes.',
      'group' => 'Entity translation',
      'dependencies' => array('title'),
    );
  }

  /**
   * {@inheritdoc}
   */
  function setUp() {
    parent::setUp('locale', 'entity_translation', 'taxonomy', 'title');
    $this->login($this->getAdminUser(array(
      'administer taxonomy',
      'administer entity translation',
    )));
    $this->addLanguage('en');
    $this->addLanguage('it');
    $this->addLanguage('fr');
    $this->enableUrlLanguageDetection();
    $this->configureVocabulary();
    $this->configureContentType();
  }

  /**
   * Makes the "Tags" vocabulary translatable.
   */
  function configureVocabulary() {
    $edit = array(
      'entity_translation_entity_types[taxonomy_term]' => TRUE,
    );
    $this->drupalPost('admin/config/regional/entity_translation', $edit, t('Save configuration'));

    $edit = array(
      'entity_translation_taxonomy' => TRUE,
    );
    $this->drupalPost('admin/structure/taxonomy/tags/edit', $edit, t('Save'));

    $edit = array(
      'enabled' => TRUE,
    );
    $this->drupalPost('admin/structure/taxonomy/tags/fields/replace/name', $edit, t('Save settings'));

    $edit = array(
      'enabled' => TRUE,
    );
    $this->drupalPost('admin/structure/taxonomy/tags/fields/replace/description', $edit, t('Save settings'));
  }

  /**
   * {@inheritdoc}
   */
  function configureContentType() {
    parent::configureContentType();

    // Create an untranslatable term reference field with unlimited cardinality.
    $edit = array(
      'fields[_add_new_field][label]' => 'Test tags',
      'fields[_add_new_field][field_name]' => 'test_tags',
      'fields[_add_new_field][type]' => 'taxonomy_term_reference',
      'fields[_add_new_field][widget_type]' => 'taxonomy_autocomplete',
    );
    $this->drupalPost('admin/structure/types/manage/page/fields', $edit, t('Save'));

    $edit = array(
      'field[settings][allowed_values][0][vocabulary]' => 'tags',
    );
    $this->drupalPost('admin/structure/types/manage/page/fields/field_test_tags/field-settings', $edit, t('Save field settings'));

    // Verify the in-place translation option is available.
    $this->drupalGet('admin/structure/types/manage/page/fields/field_test_tags');
    $this->assertRaw(t('Enable in-place translation of terms'));

    $edit = array(
      'field[cardinality]' => FIELD_CARDINALITY_UNLIMITED,
    );
    $this->drupalPost(NULL, $edit, t('Save settings'));

    // Ensure entity info is up-to-date.
    drupal_flush_all_caches();
  }

  /**
   * Enables in-place translation.
   */
  function enableInPlaceTranslation() {
    $edit = array(
      'instance[settings][entity_translation_taxonomy_autocomplete_translate]' => TRUE,
    );
    $this->drupalPost('admin/structure/types/manage/page/fields/field_test_tags', $edit, t('Save settings'));
  }

  /**
   * Tests that in-place translation works as expected.
   */
  function testInPlaceTranslation() {
    $this->enableInPlaceTranslation();
    $this->login($this->getTranslatorUser(array(
      'administer taxonomy',
    )));

    $values = array(
      'Red' => 'Rosso',
      'Green' => 'Verde',
      'Blue' => 'Blu',
    );

    // Create an English node with a few new tags.
    $edit = array(
      'title' => 'Test 1',
      'field_test_tags[' . LANGUAGE_NONE . ']' => implode(', ', array_keys($values)),
      'language' => 'en',
    );
    $this->drupalPost('node/add/page', $edit, t('Save'));
    $node = $this->drupalGetNodeByTitle($edit['title']);

    // Create an Italian translation and translate the English tags.
    $this->drupalGet('node/' . $node->nid . '/translate');
    $this->clickLink('add', 1);
    $edit = array();
    foreach (array_values($values) as $delta => $value) {
      $edit['field_test_tags[' . LANGUAGE_NONE . '][' . $delta . ']'] = $value;
    }
    $this->drupalPost(NULL, $edit, t('Save'));

    // Verify that the Italian values are correctly stored/displayed.
    foreach ($values as $original => $translation) {
      $this->assertRaw($translation);
    }

    // Verify that the original English values were correctly retained.
    $this->drupalGet('node/' . $node->nid);
    foreach ($values as $original => $translation) {
      $this->assertRaw($original);
    }
  }

  /**
   * That the autocomplete works with translated terms.
   */
  function testTranslatedAutocomplete() {
    $this->login($this->getTranslatorUser(array(
      'administer taxonomy',
    )));

    $vocabulary = taxonomy_vocabulary_machine_name_load('tags');
    $entity_type = 'taxonomy_term';
    $existing_values = array();
    $translated_values = array(
      'en' => array(
        'Red' => 'Rosso',
        'Green' => 'Verde',
      ),
      'it' => array(
        'Blu' => 'Blue',
      ),
    );
    $langcodes = array_keys($translated_values);

    // Create a few existing tags with different original language and translate
    // them accordingly.
    foreach ($translated_values as $langcode => $values) {
      title_active_language($langcode);
      $translation_langcode = current(array_diff($langcodes, array($langcode)));

      foreach ($values as $original => $translation) {
        $term = (object) array(
          'vid' => $vocabulary->vid,
          'vocabulary_machine_name' => $vocabulary->machine_name,
          'name' => $original,
          'name_field' => array(
            $langcode => array(array('value' => $original)),
            $translation_langcode => array(array('value' => $translation)),
          ),
        );
        $translation = array(
          'language' => $translation_langcode,
          'source' => $langcode,
          'status' => TRUE,
        );

        $handler = entity_translation_get_handler($entity_type, $term);
        $handler->setOriginalLanguage($langcode);
        $handler->initTranslations();
        $handler->setTranslation($translation);
        taxonomy_term_save($term);

        $existing_values[$term->name_field['en'][0]['value']] = $term->name_field['it'][0]['value'];
      }
    }

    // Verify that the English autocomplete route returns results for terms
    // originally created in English.
    $this->autocompleteGet('en', 'Re');
    $this->assertRaw('Red');
    $this->assertRaw('Green');

    // Verify that the English autocomplete route returns results for terms
    // translated into English.
    $this->autocompleteGet('en', 'Blu');
    $this->assertRaw('Blue');

    // Verify that the Italian autocomplete route returns results for terms
    // originally created in Italian.
    $this->autocompleteGet('it', 'Blu');
    $this->assertRaw('Blu');
    $this->assertNoRaw('Blue');

    // Verify that the Italian autocomplete route returns results for terms
    // translated into Italian.
    $this->autocompleteGet('it', 'R');
    $this->assertRaw('Rosso');
    $this->assertRaw('Verde');

    // Verify that existing tags are correctly referenced and new tags are
    // correctly created, when saving an English node.
    $new_values = array(
      'Cyan' => 'Ciano',
      'Magenta' => 'Magenta',
      'Yellow' => 'Giallo',
      'Black' => 'Nero',
    );
    $all_values = $existing_values + $new_values;

    $edit = array(
      'title' => 'Test 1',
      'field_test_tags[' . LANGUAGE_NONE . ']' => implode(', ', array_keys($all_values)),
      'language' => 'en',
    );
    $this->drupalPost('node/add/page', $edit, t('Save'));
    foreach ($all_values as $original => $translation) {
      $this->assertRaw($original);
    }

    // Verify that existing translated tags are correctly referenced and new
    // tags are correctly created, when translated the node into Italian.
    $node = $this->drupalGetNodeByTitle($edit['title']);
    $this->drupalGet('node/' . $node->nid . '/translate');
    $this->clickLink('add', 1);
    $edit = array(
      'field_test_tags[' . LANGUAGE_NONE . ']' => implode(', ', $all_values),
    );
    $this->drupalPost(NULL, $edit, t('Save'));
    foreach ($all_values as $original => $translation) {
      $this->assertRaw($translation);
    }

    // Verify that existing (translated) tags were preserved, while new Italian
    // tags replaced the corresponding English versions.
    $this->drupalGet('node/' . $node->nid);
    foreach ($existing_values as $original => $translation) {
      $this->assertRaw($original);
    }
    foreach ($new_values as $original => $translation) {
      $this->assertRaw($translation);
    }
  }

  /**
   * Performs a GET request to the autocomplete path.
   *
   * @param string $langcode
   *   The language to use to query results.
   * @param string $query
   *   The search query string.
   */
  protected function autocompleteGet($langcode, $query) {
    $path = 'entity_translation/taxonomy_term/autocomplete/' . $langcode . '/field_test_tags/' . $query;
    $languages = language_list();
    $this->drupalGet($path, array('language' => $languages[$langcode]));
  }

}
