From 4ee2d5f7a374d16c7ed4545afc3d364956ca5d65 Mon Sep 17 00:00:00 2001
From: Bram Goffings <bramgoffings@gmail.com>
Date: Mon, 21 May 2012 12:53:00 +0200
Subject: [PATCH] language tests to psr-0

---
 core/modules/language/language.info                |    1 -
 core/modules/language/language.test                | 1127 --------------------
 .../Tests/LanguageBrowserDetectionUnitTest.php     |  131 +++
 .../language/Tests/LanguageConfigurationTest.php   |   76 ++
 .../Tests/LanguageDependencyInjectionTest.php      |   98 ++
 .../lib/Drupal/language/Tests/LanguageListTest.php |  165 +++
 .../language/Tests/LanguageNegotiationInfoTest.php |  165 +++
 .../language/Tests/LanguagePathMonolingualTest.php |   70 ++
 .../language/Tests/LanguageSwitchingTest.php       |   88 ++
 .../Tests/LanguageUILanguageNegotiationTest.php    |  330 ++++++
 .../language/Tests/LanguageUrlRewritingTest.php    |   82 ++
 11 files changed, 1205 insertions(+), 1128 deletions(-)
 delete mode 100644 core/modules/language/language.test
 create mode 100644 core/modules/language/lib/Drupal/language/Tests/LanguageBrowserDetectionUnitTest.php
 create mode 100644 core/modules/language/lib/Drupal/language/Tests/LanguageConfigurationTest.php
 create mode 100644 core/modules/language/lib/Drupal/language/Tests/LanguageDependencyInjectionTest.php
 create mode 100644 core/modules/language/lib/Drupal/language/Tests/LanguageListTest.php
 create mode 100644 core/modules/language/lib/Drupal/language/Tests/LanguageNegotiationInfoTest.php
 create mode 100644 core/modules/language/lib/Drupal/language/Tests/LanguagePathMonolingualTest.php
 create mode 100644 core/modules/language/lib/Drupal/language/Tests/LanguageSwitchingTest.php
 create mode 100644 core/modules/language/lib/Drupal/language/Tests/LanguageUILanguageNegotiationTest.php
 create mode 100644 core/modules/language/lib/Drupal/language/Tests/LanguageUrlRewritingTest.php

diff --git a/core/modules/language/language.info b/core/modules/language/language.info
index b4b307a..309704f 100644
--- a/core/modules/language/language.info
+++ b/core/modules/language/language.info
@@ -4,4 +4,3 @@ package = Core
 version = VERSION
 core = 8.x
 configure = admin/config/regional/language
-files[] = language.test
diff --git a/core/modules/language/language.test b/core/modules/language/language.test
deleted file mode 100644
index d48f2a9..0000000
--- a/core/modules/language/language.test
+++ /dev/null
@@ -1,1127 +0,0 @@
-<?php
-use Drupal\Core\DependencyInjection\ContainerBuilder;
-
-/**
- * @file
- * Tests for language.module.
- *
- * The test file includes:
- *  - a functional test for the language configuration forms;
- *  - comparison of $GLOBALS default language against dependency injection;
- */
-
-use Drupal\simpletest\WebTestBase;
-use Drupal\simpletest\UnitTestBase;
-
-/**
- * Functional tests for the language list configuration forms.
- */
-class LanguageListTest extends WebTestBase {
-  public static function getInfo() {
-    return array(
-      'name' => 'Language list configuration',
-      'description' => 'Adds a new language and tests changing its status and the default language.',
-      'group' => 'Language',
-    );
-  }
-
-  function setUp() {
-    parent::setUp('language');
-  }
-
-  /**
-   * Functional tests for adding, editing and deleting languages.
-   */
-  function testLanguageList() {
-    global $base_url;
-
-    // User to add and remove language.
-    $admin_user = $this->drupalCreateUser(array('administer languages', 'access administration pages'));
-    $this->drupalLogin($admin_user);
-
-    // Add predefined language.
-    $edit = array(
-      'predefined_langcode' => 'fr',
-    );
-    $this->drupalPost('admin/config/regional/language/add', $edit, t('Add language'));
-    $this->assertText('French', t('Language added successfully.'));
-    $this->assertEqual($this->getUrl(), url('admin/config/regional/language', array('absolute' => TRUE)), t('Correct page redirection.'));
-
-    // Add custom language.
-    $langcode = 'xx';
-    $name = $this->randomName(16);
-    $edit = array(
-      'predefined_langcode' => 'custom',
-      'langcode' => $langcode,
-      'name' => $name,
-      'direction' => '0',
-    );
-    $this->drupalPost('admin/config/regional/language/add', $edit, t('Add custom language'));
-    $this->assertEqual($this->getUrl(), url('admin/config/regional/language', array('absolute' => TRUE)), t('Correct page redirection.'));
-    $this->assertRaw('"edit-site-default-' . $langcode .'"', t('Language code found.'));
-    $this->assertText(t($name), t('Test language added.'));
-
-    // Check if we can change the default language.
-    $path = 'admin/config/regional/language';
-    $this->drupalGet($path);
-    $this->assertFieldChecked('edit-site-default-en', t('English is the default language.'));
-    // Change the default language.
-    $edit = array(
-      'site_default' => $langcode,
-    );
-    $this->drupalPost(NULL, $edit, t('Save configuration'));
-    $this->assertNoFieldChecked('edit-site-default-en', t('Default language updated.'));
-    $this->assertEqual($this->getUrl(), url('admin/config/regional/language', array('absolute' => TRUE)), t('Correct page redirection.'));
-
-    // Ensure we can't delete the default language.
-    $this->drupalGet('admin/config/regional/language/delete/' . $langcode);
-    $this->assertEqual($this->getUrl(), url('admin/config/regional/language', array('absolute' => TRUE)), t('Correct page redirection.'));
-    $this->assertText(t('The default language cannot be deleted.'), t('Failed to delete the default language.'));
-
-    // Ensure 'edit' link works.
-    $this->clickLink(t('edit'));
-    $this->assertTitle(t('Edit language | Drupal'), t('Page title is "Edit language".'));
-    // Edit a language.
-    $name = $this->randomName(16);
-    $edit = array(
-      'name' => $name,
-    );
-    $this->drupalPost('admin/config/regional/language/edit/' . $langcode, $edit, t('Save language'));
-    $this->assertRaw($name, t('The language has been updated.'));
-    $this->assertEqual($this->getUrl(), url('admin/config/regional/language', array('absolute' => TRUE)), t('Correct page redirection.'));
-
-    // Change back the default language.
-    $edit = array(
-      'site_default' => 'en',
-    );
-    $this->drupalPost(NULL, $edit, t('Save configuration'));
-    // Ensure 'delete' link works.
-    $this->drupalGet('admin/config/regional/language');
-    $this->clickLink(t('delete'));
-    $this->assertText(t('Are you sure you want to delete the language'), t('"delete" link is correct.'));
-    // Delete a language.
-    $this->drupalGet('admin/config/regional/language/delete/' . $langcode);
-    // First test the 'cancel' link.
-    $this->clickLink(t('Cancel'));
-    $this->assertEqual($this->getUrl(), url('admin/config/regional/language', array('absolute' => TRUE)), t('Correct page redirection.'));
-    $this->assertRaw($name, t('The language was not deleted.'));
-    // Delete the language for real. This a confirm form, we do not need any
-    // fields changed.
-    $this->drupalPost('admin/config/regional/language/delete/' . $langcode, array(), t('Delete'));
-    // We need raw here because %language and %langcode will add HTML.
-    $t_args = array('%language' => $name, '%langcode' => $langcode);
-    $this->assertRaw(t('The %language (%langcode) language has been removed.', $t_args), t('The test language has been removed.'));
-    $this->assertEqual($this->getUrl(), url('admin/config/regional/language', array('absolute' => TRUE)), t('Correct page redirection.'));
-    // Verify that language is no longer found.
-    $this->drupalGet('admin/config/regional/language/delete/' . $langcode);
-    $this->assertResponse(404, t('Language no longer found.'));
-    // Make sure the "language_count" variable has been updated correctly.
-    drupal_static_reset('language_list');
-    $languages = language_list();
-    $this->assertEqual(variable_get('language_count', 1), count($languages), t('Language count is correct.'));
-    // Delete French.
-    $this->drupalPost('admin/config/regional/language/delete/fr', array(), t('Delete'));
-    // Get the count of languages.
-    drupal_static_reset('language_list');
-    $languages = language_list();
-    // We need raw here because %language and %langcode will add HTML.
-    $t_args = array('%language' => 'French', '%langcode' => 'fr');
-    $this->assertRaw(t('The %language (%langcode) language has been removed.', $t_args), t('Disabled language has been removed.'));
-    $this->assertEqual($this->getUrl(), url('admin/config/regional/language', array('absolute' => TRUE)), t('Correct page redirection.'));
-    // Verify that language is no longer found.
-    $this->drupalGet('admin/config/regional/language/delete/fr');
-    $this->assertResponse(404, t('Language no longer found.'));
-    // Make sure the "language_count" variable has not changed.
-    $this->assertEqual(variable_get('language_count', 1), count($languages), t('Language count is correct.'));
-
-    // Ensure we can delete the English language. Right now English is the only
-    // language so we must add a new language and make it the default before
-    // deleting English.
-    $langcode = 'xx';
-    $name = $this->randomName(16);
-    $edit = array(
-      'predefined_langcode' => 'custom',
-      'langcode' => $langcode,
-      'name' => $name,
-      'direction' => '0',
-    );
-    $this->drupalPost('admin/config/regional/language/add', $edit, t('Add custom language'));
-    $this->assertEqual($this->getUrl(), url('admin/config/regional/language', array('absolute' => TRUE)), t('Correct page redirection.'));
-    $this->assertText($name, t('Name found.'));
-
-    // Check if we can change the default language.
-    $path = 'admin/config/regional/language';
-    $this->drupalGet($path);
-    $this->assertFieldChecked('edit-site-default-en', t('English is the default language.'));
-    // Change the default language.
-    $edit = array(
-      'site_default' => $langcode,
-    );
-    $this->drupalPost(NULL, $edit, t('Save configuration'));
-    $this->assertNoFieldChecked('edit-site-default-en', t('Default language updated.'));
-    $this->assertEqual($this->getUrl(), url('admin/config/regional/language', array('absolute' => TRUE)), t('Correct page redirection.'));
-
-    $this->drupalPost('admin/config/regional/language/delete/en', array(), t('Delete'));
-    // We need raw here because %language and %langcode will add HTML.
-    $t_args = array('%language' => 'English', '%langcode' => 'en');
-    $this->assertRaw(t('The %language (%langcode) language has been removed.', $t_args), t('The English language has been removed.'));
-  }
-}
-
-/**
- * Test for dependency injected language object.
- */
-class LanguageDependencyInjectionTest extends WebTestBase {
-  public static function getInfo() {
-    return array(
-        'name' => 'Language dependency injection',
-        'description' => 'Compares the default language from $GLOBALS against the dependency injected language object.',
-        'group' => 'Language',
-    );
-  }
-
-  function setUp() {
-    parent::setUp('language');
-
-    // Set up a new container to ensure we are building a new Language object
-    // for each test.
-    drupal_container(new ContainerBuilder());
-  }
-
-  /**
-   * Test dependency injected Language against the GLOBAL language object.
-   *
-   * @todo Once the PHP global is gone, we won't need this test as the same
-   * test is done without the PHP global in the following test.
-   */
-  function testDependencyInjectedLanguage() {
-    // Initialize the language system.
-    drupal_language_initialize();
-
-    $expected = $GLOBALS[LANGUAGE_TYPE_INTERFACE];
-    $result = drupal_container()->get(LANGUAGE_TYPE_INTERFACE);
-    foreach ($expected as $property => $value) {
-      $this->assertEqual($expected->$property, $result->$property, t('The dependency injected language object %prop property equals the $GLOBAL language object %prop property.', array('%prop' => $property)));
-    }
-  }
-
-  /**
-   * Test dependency injected languages against a new Language object.
-   *
-   * @see Drupal\Core\Language\Language
-   */
-  function testDependencyInjectedNewLanguage() {
-    // Initialize the language system.
-    drupal_language_initialize();
-
-    $expected = new Drupal\Core\Language\Language((array) language_default());
-    $result = drupal_container()->get(LANGUAGE_TYPE_INTERFACE);
-    foreach ($expected as $property => $value) {
-      $this->assertEqual($expected->$property, $result->$property, t('The dependency injected language object %prop property equals the new Language object %prop property.', array('%prop' => $property)));
-    }
-  }
-
-  /**
-   * Test dependency injected Language object against a new default language
-   * object.
-   *
-   * @see Drupal\Core\Language\Language
-   */
-  function testDependencyInjectedNewDefaultLanguage() {
-    // Change the language default object to different values.
-    $new_language_default = (object) array(
-      'langcode' => 'fr',
-      'name' => 'French',
-      'direction' => 0,
-      'weight' => 0,
-      'default' => TRUE,
-    );
-    variable_set('language_default', $new_language_default);
-
-    // Initialize the language system.
-    drupal_language_initialize();
-
-    // The langauge system creates a Language object which contains the
-    // same properties as the new default language object.
-    $expected = $new_language_default;
-    $result = drupal_container()->get(LANGUAGE_TYPE_INTERFACE);
-    foreach ($expected as $property => $value) {
-      $this->assertEqual($expected->$property, $result->$property, t('The dependency injected language object %prop property equals the default language object %prop property.', array('%prop' => $property)));
-    }
-
-    // Delete the language_default variable we previously set.
-    variable_del('language_default');
-  }
-}
-
-/**
- * Functional tests for language configuration's effect on negotiation setup.
- */
-class LanguageConfigurationTestCase extends WebTestBase {
-  public static function getInfo() {
-    return array(
-      'name' => 'Language negotiation autoconfiguration',
-      'description' => 'Adds and configures languages to check negotiation changes.',
-      'group' => 'Language',
-    );
-  }
-
-  function setUp() {
-    parent::setUp('language');
-  }
-
-  /**
-   * Functional tests for adding, editing and deleting languages.
-   */
-  function testLanguageConfiguration() {
-    global $base_url;
-
-    // User to add and remove language.
-    $admin_user = $this->drupalCreateUser(array('administer languages', 'access administration pages'));
-    $this->drupalLogin($admin_user);
-
-    // Check if the Default English language has no path prefix.
-    $this->drupalGet('admin/config/regional/language/detection/url');
-    $this->assertFieldByXPath('//input[@name="prefix[en]"]', '', t('Default English has no path prefix.'));
-
-    // Add predefined language.
-    $edit = array(
-      'predefined_langcode' => 'fr',
-    );
-    $this->drupalPost('admin/config/regional/language/add', $edit, t('Add language'));
-    $this->assertText('French');
-    $this->assertEqual($this->getUrl(), url('admin/config/regional/language', array('absolute' => TRUE)), t('Correct page redirection.'));
-
-    // Check if the Default English language has no path prefix.
-    $this->drupalGet('admin/config/regional/language/detection/url');
-    $this->assertFieldByXPath('//input[@name="prefix[en]"]', '', t('Default English has no path prefix.'));
-    // Check if French has a path prefix.
-    $this->drupalGet('admin/config/regional/language/detection/url');
-    $this->assertFieldByXPath('//input[@name="prefix[fr]"]', 'fr', t('French has a path prefix.'));
-
-    // Check if we can change the default language.
-    $this->drupalGet('admin/config/regional/language');
-    $this->assertFieldChecked('edit-site-default-en', t('English is the default language.'));
-    // Change the default language.
-    $edit = array(
-      'site_default' => 'fr',
-    );
-    $this->drupalPost(NULL, $edit, t('Save configuration'));
-    $this->assertNoFieldChecked('edit-site-default-en', t('Default language updated.'));
-    $this->assertEqual($this->getUrl(), url('admin/config/regional/language', array('absolute' => TRUE)), t('Correct page redirection.'));
-
-    // Check if a valid language prefix is added afrer changing the default
-    // language.
-    $this->drupalGet('admin/config/regional/language/detection/url');
-    $this->assertFieldByXPath('//input[@name="prefix[en]"]', 'en', t('A valid path prefix has been added to the previous default language.'));
-    // Check if French still has a path prefix.
-    $this->drupalGet('admin/config/regional/language/detection/url');
-    $this->assertFieldByXPath('//input[@name="prefix[fr]"]', 'fr', t('French still has a path prefix.'));
-  }
-}
-
-/**
- * Functional tests for the language switching feature.
- */
-class LanguageSwitchingFunctionalTestCase extends WebTestBase {
-
-  public static function getInfo() {
-    return array(
-      'name' => 'Language switching',
-      'description' => 'Tests for the language switching feature.',
-      'group' => 'Language',
-    );
-  }
-
-  function setUp() {
-    parent::setUp(array('language', 'block'));
-
-    // Create and login user.
-    $admin_user = $this->drupalCreateUser(array('administer blocks', 'administer languages', 'access administration pages'));
-    $this->drupalLogin($admin_user);
-  }
-
-  /**
-   * Functional tests for the language switcher block.
-   */
-  function testLanguageBlock() {
-    // Enable the language switching block.
-    $language_type = LANGUAGE_TYPE_INTERFACE;
-    $edit = array(
-      "blocks[language_{$language_type}][region]" => 'sidebar_first',
-    );
-    $this->drupalPost('admin/structure/block', $edit, t('Save blocks'));
-
-    // Add language.
-    $edit = array(
-      'predefined_langcode' => 'fr',
-    );
-    $this->drupalPost('admin/config/regional/language/add', $edit, t('Add language'));
-
-    // Enable URL language detection and selection.
-    $edit = array('language_interface[enabled][language-url]' => '1');
-    $this->drupalPost('admin/config/regional/language/detection', $edit, t('Save settings'));
-
-    // Assert that the language switching block is displayed on the frontpage.
-    $this->drupalGet('');
-    $this->assertText(t('Languages'), t('Language switcher block found.'));
-
-    // Assert that only the current language is marked as active.
-    list($language_switcher) = $this->xpath('//div[@id=:id]/div[@class="content"]', array(':id' => 'block-language-' . str_replace('_', '-', $language_type)));
-    $links = array(
-      'active' => array(),
-      'inactive' => array(),
-    );
-    $anchors = array(
-      'active' => array(),
-      'inactive' => array(),
-    );
-    foreach ($language_switcher->ul->li as $link) {
-      $classes = explode(" ", (string) $link['class']);
-      list($langcode) = array_intersect($classes, array('en', 'fr'));
-      if (in_array('active', $classes)) {
-        $links['active'][] = $langcode;
-      }
-      else {
-        $links['inactive'][] = $langcode;
-      }
-      $anchor_classes = explode(" ", (string) $link->a['class']);
-      if (in_array('active', $anchor_classes)) {
-        $anchors['active'][] = $langcode;
-      }
-      else {
-        $anchors['inactive'][] = $langcode;
-      }
-    }
-    $this->assertIdentical($links, array('active' => array('en'), 'inactive' => array('fr')), t('Only the current language list item is marked as active on the language switcher block.'));
-    $this->assertIdentical($anchors, array('active' => array('en'), 'inactive' => array('fr')), t('Only the current language anchor is marked as active on the language switcher block.'));
-  }
-}
-
-/**
- * Test browser language detection.
- */
-class LanguageBrowserDetectionTestCase extends UnitTestBase {
-
-  public static function getInfo() {
-    return array(
-      'name' => 'Browser language detection',
-      'description' => 'Tests for the browser language detection.',
-      'group' => 'Language',
-    );
-  }
-
-  /**
-   * Unit tests for the language_from_browser() function.
-   */
-  function testLanguageFromBrowser() {
-    // Load the required functions.
-    require_once DRUPAL_ROOT . '/core/modules/language/language.negotiation.inc';
-
-    $languages = array(
-      // In our test case, 'en' has priority over 'en-US'.
-      'en' => (object) array(
-        'langcode' => 'en',
-      ),
-      'en-US' => (object) array(
-        'langcode' => 'en-US',
-      ),
-      // But 'fr-CA' has priority over 'fr'.
-      'fr-CA' => (object) array(
-        'langcode' => 'fr-CA',
-      ),
-      'fr' => (object) array(
-        'langcode' => 'fr',
-      ),
-      // 'es-MX' is alone.
-      'es-MX' => (object) array(
-        'langcode' => 'es-MX',
-      ),
-      // 'pt' is alone.
-      'pt' => (object) array(
-        'langcode' => 'pt',
-      ),
-      // Language codes with more then one dash are actually valid.
-      // eh-oh-laa-laa is the official language code of the Teletubbies.
-      'eh-oh-laa-laa' => (object) array(
-        'langcode' => 'eh-oh-laa-laa',
-      ),
-    );
-
-    $test_cases = array(
-      // Equal qvalue for each language, choose the site prefered one.
-      'en,en-US,fr-CA,fr,es-MX' => 'en',
-      'en-US,en,fr-CA,fr,es-MX' => 'en',
-      'fr,en' => 'en',
-      'en,fr' => 'en',
-      'en-US,fr' => 'en',
-      'fr,en-US' => 'en',
-      'fr,fr-CA' => 'fr-CA',
-      'fr-CA,fr' => 'fr-CA',
-      'fr' => 'fr-CA',
-      'fr;q=1' => 'fr-CA',
-      'fr,es-MX' => 'fr-CA',
-      'fr,es' => 'fr-CA',
-      'es,fr' => 'fr-CA',
-      'es-MX,de' => 'es-MX',
-      'de,es-MX' => 'es-MX',
-
-      // Different cases and whitespace.
-      'en' => 'en',
-      'En' => 'en',
-      'EN' => 'en',
-      ' en' => 'en',
-      'en ' => 'en',
-      'en, fr' => 'en',
-
-      // A less specific language from the browser matches a more specific one
-      // from the website, and the other way around for compatibility with
-      // some versions of Internet Explorer.
-      'es' => 'es-MX',
-      'es-MX' => 'es-MX',
-      'pt' => 'pt',
-      'pt-PT' => 'pt',
-      'pt-PT;q=0.5,pt-BR;q=1,en;q=0.7' => 'en',
-      'pt-PT;q=1,pt-BR;q=0.5,en;q=0.7' => 'en',
-      'pt-PT;q=0.4,pt-BR;q=0.1,en;q=0.7' => 'en',
-      'pt-PT;q=0.1,pt-BR;q=0.4,en;q=0.7' => 'en',
-
-      // Language code with several dashes are valid. The less specific language
-      // from the browser matches the more specific one from the website.
-      'eh-oh-laa-laa' => 'eh-oh-laa-laa',
-      'eh-oh-laa' => 'eh-oh-laa-laa',
-      'eh-oh' => 'eh-oh-laa-laa',
-      'eh' => 'eh-oh-laa-laa',
-
-      // Different qvalues.
-      'en-US,en;q=0.5,fr;q=0.25' => 'en-US',
-      'fr,en;q=0.5' => 'fr-CA',
-      'fr,en;q=0.5,fr-CA;q=0.25' => 'fr',
-
-      // Silly wildcards are also valid.
-      '*,fr-CA;q=0.5' => 'en',
-      '*,en;q=0.25' => 'fr-CA',
-      'en,en-US;q=0.5,fr;q=0.25' => 'en',
-      'en-US,en;q=0.5,fr;q=0.25' => 'en-US',
-
-      // Unresolvable cases.
-      '' => FALSE,
-      'de,pl' => FALSE,
-      'iecRswK4eh' => FALSE,
-      $this->randomName(10) => FALSE,
-    );
-
-    foreach ($test_cases as $accept_language => $expected_result) {
-      $_SERVER['HTTP_ACCEPT_LANGUAGE'] = $accept_language;
-      $result = language_from_browser($languages);
-      $this->assertIdentical($result, $expected_result, t("Language selection '@accept-language' selects '@result', result = '@actual'", array('@accept-language' => $accept_language, '@result' => $expected_result, '@actual' => isset($result) ? $result : 'none')));
-    }
-  }
-}
-
-/**
- * Test UI language negotiation
- *
- * 1. URL (PATH) > DEFAULT
- *    UI Language base on URL prefix, browser language preference has no
- *    influence:
- *      admin/config
- *        UI in site default language
- *      zh-hans/admin/config
- *        UI in Chinese
- *      blah-blah/admin/config
- *        404
- * 2. URL (PATH) > BROWSER > DEFAULT
- *        admin/config
- *          UI in user's browser language preference if the site has that
- *          language enabled, if not, the default language
- *        zh-hans/admin/config
- *          UI in Chinese
- *        blah-blah/admin/config
- *          404
- * 3. URL (DOMAIN) > DEFAULT
- *        http://example.com/admin/config
- *          UI language in site default
- *        http://example.cn/admin/config
- *          UI language in Chinese
- */
-class LanguageUILanguageNegotiationTestCase extends WebTestBase {
-  public static function getInfo() {
-    return array(
-      'name' => 'UI language negotiation',
-      'description' => 'Test UI language switching by url path prefix and domain.',
-      'group' => 'Language',
-    );
-  }
-
-  function setUp() {
-    // We marginally use interface translation functionality here, so need to
-    // use the locale module instead of language only, but the 90% of the test
-    // is about the negotiation process which is solely in language module.
-    parent::setUp(array('locale', 'language_test', 'block'));
-    require_once DRUPAL_ROOT . '/core/includes/language.inc';
-    drupal_load('module', 'locale');
-    $admin_user = $this->drupalCreateUser(array('administer languages', 'translate interface', 'access administration pages', 'administer blocks'));
-    $this->drupalLogin($admin_user);
-  }
-
-  /**
-   * Tests for language switching by URL path.
-   */
-  function testUILanguageNegotiation() {
-    // A few languages to switch to.
-    // This one is unknown, should get the default lang version.
-    $langcode_unknown = 'blah-blah';
-    // For testing browser lang preference.
-    $langcode_browser_fallback = 'vi';
-    // For testing path prefix.
-    $langcode = 'zh-hans';
-    // For setting browser language preference to 'vi'.
-    $http_header_browser_fallback = array("Accept-Language: $langcode_browser_fallback;q=1");
-    // For setting browser language preference to some unknown.
-    $http_header_blah = array("Accept-Language: blah;q=1");
-
-    // This domain should switch the UI to Chinese.
-    $language_domain = 'example.cn';
-
-    // Setup the site languages by installing two languages.
-    $language = (object) array(
-      'langcode' => $langcode_browser_fallback,
-    );
-    language_save($language);
-    $language = (object) array(
-      'langcode' => $langcode,
-    );
-    language_save($language);
-
-    // We will look for this string in the admin/config screen to see if the
-    // corresponding translated string is shown.
-    $default_string = 'Configure languages for content and the user interface';
-
-    // Set the default language in order for the translated string to be registered
-    // into database when seen by t(). Without doing this, our target string
-    // is for some reason not found when doing translate search. This might
-    // be some bug.
-    drupal_static_reset('language_list');
-    $languages = language_list();
-    variable_set('language_default', $languages['vi']);
-    // First visit this page to make sure our target string is searchable.
-    $this->drupalGet('admin/config');
-    // Now the t()'ed string is in db so switch the language back to default.
-    variable_del('language_default');
-
-    // Translate the string.
-    $language_browser_fallback_string = "In $langcode_browser_fallback In $langcode_browser_fallback In $langcode_browser_fallback";
-    $language_string = "In $langcode In $langcode In $langcode";
-    // Do a translate search of our target string.
-    $edit = array( 'string' => $default_string);
-    $this->drupalPost('admin/config/regional/translate/translate', $edit, t('Filter'));
-    // Should find the string and now click edit to post translated string.
-    $this->clickLink('edit');
-    $edit = array(
-      "translations[$langcode_browser_fallback][0]" => $language_browser_fallback_string,
-      "translations[$langcode][0]" => $language_string,
-    );
-    $this->drupalPost(NULL, $edit, t('Save translations'));
-
-    // Configure URL language rewrite.
-    variable_set('language_negotiation_url_type', LANGUAGE_TYPE_INTERFACE);
-
-    $tests = array(
-      // Default, browser preference should have no influence.
-      array(
-        'language_negotiation' => array(LANGUAGE_NEGOTIATION_URL, LANGUAGE_NEGOTIATION_DEFAULT),
-        'path' => 'admin/config',
-        'expect' => $default_string,
-        'expected_method_id' => LANGUAGE_NEGOTIATION_DEFAULT,
-        'http_header' => $http_header_browser_fallback,
-        'message' => 'URL (PATH) > DEFAULT: no language prefix, UI language is default and the browser language preference setting is not used.',
-      ),
-      // Language prefix.
-      array(
-        'language_negotiation' => array(LANGUAGE_NEGOTIATION_URL, LANGUAGE_NEGOTIATION_DEFAULT),
-        'path' => "$langcode/admin/config",
-        'expect' => $language_string,
-        'expected_method_id' => LANGUAGE_NEGOTIATION_URL,
-        'http_header' => $http_header_browser_fallback,
-        'message' => 'URL (PATH) > DEFAULT: with language prefix, UI language is switched based on path prefix',
-      ),
-      // Default, go by browser preference.
-      array(
-        'language_negotiation' => array(LANGUAGE_NEGOTIATION_URL, LANGUAGE_NEGOTIATION_BROWSER),
-        'path' => 'admin/config',
-        'expect' => $language_browser_fallback_string,
-        'expected_method_id' => LANGUAGE_NEGOTIATION_BROWSER,
-        'http_header' => $http_header_browser_fallback,
-        'message' => 'URL (PATH) > BROWSER: no language prefix, UI language is determined by browser language preference',
-      ),
-      // Prefix, switch to the language.
-      array(
-        'language_negotiation' => array(LANGUAGE_NEGOTIATION_URL, LANGUAGE_NEGOTIATION_BROWSER),
-        'path' => "$langcode/admin/config",
-        'expect' => $language_string,
-        'expected_method_id' => LANGUAGE_NEGOTIATION_URL,
-        'http_header' => $http_header_browser_fallback,
-        'message' => 'URL (PATH) > BROWSER: with langage prefix, UI language is based on path prefix',
-      ),
-      // Default, browser language preference is not one of site's lang.
-      array(
-        'language_negotiation' => array(LANGUAGE_NEGOTIATION_URL, LANGUAGE_NEGOTIATION_BROWSER, LANGUAGE_NEGOTIATION_DEFAULT),
-        'path' => 'admin/config',
-        'expect' => $default_string,
-        'expected_method_id' => LANGUAGE_NEGOTIATION_DEFAULT,
-        'http_header' => $http_header_blah,
-        'message' => 'URL (PATH) > BROWSER > DEFAULT: no language prefix and browser language preference set to unknown language should use default language',
-      ),
-    );
-
-    foreach ($tests as $test) {
-      $this->runTest($test);
-    }
-
-    // Unknown language prefix should return 404.
-    variable_set('language_negotiation_' . LANGUAGE_TYPE_INTERFACE, language_language_negotiation_info());
-    $this->drupalGet("$langcode_unknown/admin/config", array(), $http_header_browser_fallback);
-    $this->assertResponse(404, "Unknown language path prefix should return 404");
-
-    // Setup for domain negotiation, first configure the language to have domain
-    // URL.
-    $edit = array("domain[$langcode]" => $language_domain);
-    $this->drupalPost("admin/config/regional/language/detection/url", $edit, t('Save configuration'));
-    // Set the site to use domain language negotiation.
-
-    $tests = array(
-      // Default domain, browser preference should have no influence.
-      array(
-        'language_negotiation' => array(LANGUAGE_NEGOTIATION_URL, LANGUAGE_NEGOTIATION_DEFAULT),
-        'language_negotiation_url_part' => LANGUAGE_NEGOTIATION_URL_DOMAIN,
-        'path' => 'admin/config',
-        'expect' => $default_string,
-        'expected_method_id' => LANGUAGE_NEGOTIATION_DEFAULT,
-        'http_header' => $http_header_browser_fallback,
-        'message' => 'URL (DOMAIN) > DEFAULT: default domain should get default language',
-      ),
-      // Language domain specific URL, we set the $_SERVER['HTTP_HOST'] in
-      // language_test.module hook_boot() to simulate this.
-      array(
-        'language_negotiation' => array(LANGUAGE_NEGOTIATION_URL, LANGUAGE_NEGOTIATION_DEFAULT),
-        'language_negotiation_url_part' => LANGUAGE_NEGOTIATION_URL_DOMAIN,
-        'language_test_domain' => $language_domain,
-        'path' => 'admin/config',
-        'expect' => $language_string,
-        'expected_method_id' => LANGUAGE_NEGOTIATION_URL,
-        'http_header' => $http_header_browser_fallback,
-        'message' => 'URL (DOMAIN) > DEFAULT: domain example.cn should switch to Chinese',
-      ),
-    );
-
-    foreach ($tests as $test) {
-      $this->runTest($test);
-    }
-  }
-
-  protected function runTest($test) {
-    if (!empty($test['language_negotiation'])) {
-      $method_weights = array_flip($test['language_negotiation']);
-      language_negotiation_set(LANGUAGE_TYPE_INTERFACE, $method_weights);
-    }
-    if (!empty($test['language_negotiation_url_part'])) {
-      variable_set('language_negotiation_url_part', $test['language_negotiation_url_part']);
-    }
-    if (!empty($test['language_test_domain'])) {
-      variable_set('language_test_domain', $test['language_test_domain']);
-    }
-    $this->drupalGet($test['path'], array(), $test['http_header']);
-    $this->assertText($test['expect'], $test['message']);
-    $this->assertText(t('Language negotiation method: @name', array('@name' => $test['expected_method_id'])));
-  }
-
-  /**
-   * Test URL language detection when the requested URL has no language.
-   */
-  function testUrlLanguageFallback() {
-    // Add the Italian language.
-    $langcode_browser_fallback = 'it';
-    $language = (object) array(
-      'langcode' => $langcode_browser_fallback,
-    );
-    language_save($language);
-    $languages = language_list();
-
-    // Enable the path prefix for the default language: this way any unprefixed
-    // URL must have a valid fallback value.
-    $edit = array('prefix[en]' => 'en');
-    $this->drupalPost('admin/config/regional/language/detection/url', $edit, t('Save configuration'));
-
-    // Enable browser and URL language detection.
-    $edit = array(
-      'language_interface[enabled][language-browser]' => TRUE,
-      'language_interface[enabled][language-url]' => TRUE,
-      'language_interface[weight][language-browser]' => -8,
-      'language_interface[weight][language-url]' => -10,
-    );
-    $this->drupalPost('admin/config/regional/language/detection', $edit, t('Save settings'));
-    $this->drupalGet('admin/config/regional/language/detection');
-
-    // Enable the language switcher block.
-    $edit = array('blocks[language_language_interface][region]' => 'sidebar_first');
-    $this->drupalPost('admin/structure/block', $edit, t('Save blocks'));
-
-    // Access the front page without specifying any valid URL language prefix
-    // and having as browser language preference a non-default language.
-    $http_header = array("Accept-Language: $langcode_browser_fallback;q=1");
-    $language = (object) array('langcode' => '');
-    $this->drupalGet('', array('language' => $language), $http_header);
-
-    // Check that the language switcher active link matches the given browser
-    // language.
-    $args = array(':url' => base_path() . $GLOBALS['script_path'] . $langcode_browser_fallback);
-    $fields = $this->xpath('//div[@id="block-language-language-interface"]//a[@class="language-link active" and starts-with(@href, :url)]', $args);
-    $this->assertTrue($fields[0] == $languages[$langcode_browser_fallback]->name, t('The browser language is the URL active language'));
-
-    // Check that URLs are rewritten using the given browser language.
-    $fields = $this->xpath('//p[@id="site-name"]/strong/a[@rel="home" and @href=:url]', $args);
-    $this->assertTrue($fields[0] == 'Drupal', t('URLs are rewritten using the browser language.'));
-  }
-
-  /**
-   * Tests url() when separate domains are used for multiple languages.
-   */
-  function testLanguageDomain() {
-    // Add the Italian language.
-    $langcode = 'it';
-    $language = (object) array(
-      'langcode' => $langcode,
-    );
-    language_save($language);
-    $languages = language_list();
-
-    // Enable browser and URL language detection.
-    $edit = array(
-      'language_interface[enabled][language-url]' => TRUE,
-      'language_interface[weight][language-url]' => -10,
-    );
-    $this->drupalPost('admin/config/regional/language/detection', $edit, t('Save settings'));
-
-    // Change the domain for the Italian language.
-    $edit = array(
-      'language_negotiation_url_part' => 1,
-      'domain[it]' => 'it.example.com',
-    );
-    $this->drupalPost('admin/config/regional/language/detection/url', $edit, t('Save configuration'));
-
-    // Build the link we're going to test.
-    $link = 'it.example.com/admin';
-
-    global $is_https;
-    // Test URL in another language: http://it.example.com/admin.
-    // Base path gives problems on the testbot, so $correct_link is hard-coded.
-    // @see UrlAlterFunctionalTest::assertUrlOutboundAlter (path.test).
-    $italian_url = url('admin', array('language' => $languages['it'], 'script' => ''));
-    $url_scheme = ($is_https) ? 'https://' : 'http://';
-    $correct_link = $url_scheme . $link;
-    $this->assertTrue($italian_url == $correct_link, t('The url() function returns the right url (@url) in accordance with the chosen language', array('@url' => $italian_url)));
-
-    // Test https via options.
-    variable_set('https', TRUE);
-    $italian_url = url('admin', array('https' => TRUE, 'language' => $languages['it'], 'script' => ''));
-    $correct_link = 'https://' . $link;
-    $this->assertTrue($italian_url == $correct_link, t('The url() function returns the right https url (via options) (@url) in accordance with the chosen language', array('@url' => $italian_url)));
-    variable_set('https', FALSE);
-
-    // Test https via current url scheme.
-    $temp_https = $is_https;
-    $is_https = TRUE;
-    $italian_url = url('admin', array('language' => $languages['it'], 'script' => ''));
-    $correct_link = 'https://' . $link;
-    $this->assertTrue($italian_url == $correct_link, t('The url() function returns the right url (via current url scheme) (@url) in accordance with the chosen language', array('@url' => $italian_url)));
-    $is_https = $temp_https;
-  }
-}
-
-/**
- * Test that URL rewriting works as expected.
- */
-class LanguageUrlRewritingTestCase extends WebTestBase {
-  public static function getInfo() {
-    return array(
-      'name' => 'URL rewriting',
-      'description' => 'Test that URL rewriting works as expected.',
-      'group' => 'Language',
-    );
-  }
-
-  function setUp() {
-    parent::setUp('language');
-
-    // Create and login user.
-    $this->web_user = $this->drupalCreateUser(array('administer languages', 'access administration pages'));
-    $this->drupalLogin($this->web_user);
-
-    // Install French language.
-    $edit = array();
-    $edit['predefined_langcode'] = 'fr';
-    $this->drupalPost('admin/config/regional/language/add', $edit, t('Add language'));
-
-    // Enable URL language detection and selection.
-    $edit = array('language_interface[enabled][language-url]' => 1);
-    $this->drupalPost('admin/config/regional/language/detection', $edit, t('Save settings'));
-
-    // Reset static caching.
-    drupal_static_reset('language_list');
-    drupal_static_reset('language_url_outbound_alter');
-    drupal_static_reset('language_url_rewrite_url');
-  }
-
-  /**
-   * Check that non-installed languages are not considered.
-   */
-  function testUrlRewritingEdgeCases() {
-    // Check URL rewriting with a non-installed language.
-    $non_existing = language_default();
-    $non_existing->langcode = $this->randomName();
-    $this->checkUrl($non_existing, t('Path language is ignored if language is not installed.'), t('URL language negotiation does not work with non-installed languages'));
-  }
-
-  /**
-   * Check URL rewriting for the given language.
-   *
-   * The test is performed with a fixed URL (the default front page) to simply
-   * check that language prefixes are not added to it and that the prefixed URL
-   * is actually not working.
-   */
-  private function checkUrl($language, $message1, $message2) {
-    $options = array('language' => $language, 'script' => '');
-    $base_path = trim(base_path(), '/');
-    $rewritten_path = trim(str_replace($base_path, '', url('node', $options)), '/');
-    $segments = explode('/', $rewritten_path, 2);
-    $prefix = $segments[0];
-    $path = isset($segments[1]) ? $segments[1] : $prefix;
-
-    // If the rewritten URL has not a language prefix we pick a random prefix so
-    // we can always check the prefixed URL.
-    $prefixes = language_negotiation_url_prefixes();
-    $stored_prefix = isset($prefixes[$language->langcode]) ? $prefixes[$language->langcode] : $this->randomName();
-    if ($this->assertNotEqual($stored_prefix, $prefix, $message1)) {
-      $prefix = $stored_prefix;
-    }
-
-    $this->drupalGet("$prefix/$path");
-    $this->assertResponse(404, $message2);
-  }
-}
-
-/**
- * Functional test for language types/negotiation info.
- */
-class LanguageNegotiationInfoTestCase extends WebTestBase {
-
-  public static function getInfo() {
-    return array(
-      'name' => 'Language negotiation info',
-      'description' => 'Tests alterations to language types/negotiation info.',
-      'group' => 'Language',
-    );
-  }
-
-  function setUp() {
-    parent::setUp('language');
-    require_once DRUPAL_ROOT .'/core/includes/language.inc';
-    $admin_user = $this->drupalCreateUser(array('administer languages', 'access administration pages', 'view the administration theme'));
-    $this->drupalLogin($admin_user);
-    $this->drupalPost('admin/config/regional/language/add', array('predefined_langcode' => 'it'), t('Add language'));
-  }
-
-  /**
-   * Tests alterations to language types/negotiation info.
-   */
-  function testInfoAlterations() {
-    // Enable language type/negotiation info alterations.
-    variable_set('language_test_language_types', TRUE);
-    variable_set('language_test_language_negotiation_info', TRUE);
-    $this->languageNegotiationUpdate();
-
-    // Check that fixed language types are properly configured without the need
-    // of saving the language negotiation settings.
-    $this->checkFixedLanguageTypes();
-
-    // Make the content language type configurable by updating the language
-    // negotiation settings with the proper flag enabled.
-    variable_set('language_test_content_language_type', TRUE);
-    $this->languageNegotiationUpdate();
-    $type = LANGUAGE_TYPE_CONTENT;
-    $language_types = variable_get('language_types', language_types_get_default());
-    $this->assertTrue($language_types[$type], t('Content language type is configurable.'));
-
-    // Enable some core and custom language negotiation methods. The test
-    // language type is supposed to be configurable.
-    $test_type = 'test_language_type';
-    $interface_method_id = LANGUAGE_NEGOTIATION_INTERFACE;
-    $test_method_id = 'test_language_negotiation_method';
-    $form_field = $type . '[enabled]['. $interface_method_id .']';
-    $edit = array(
-      $form_field => TRUE,
-      $type . '[enabled][' . $test_method_id . ']' => TRUE,
-      $test_type . '[enabled][' . $test_method_id . ']' => TRUE,
-    );
-    $this->drupalPost('admin/config/regional/language/detection', $edit, t('Save settings'));
-
-    // Remove the interface language negotiation method by updating the language
-    // negotiation settings with the proper flag enabled.
-    variable_set('language_test_language_negotiation_info_alter', TRUE);
-    $this->languageNegotiationUpdate();
-    $negotiation = variable_get("language_negotiation_$type", array());
-    $this->assertFalse(isset($negotiation[$interface_method_id]), t('Interface language negotiation method removed from the stored settings.'));
-    $this->assertNoFieldByXPath("//input[@name=\"$form_field\"]", NULL, t('Interface language negotiation method unavailable.'));
-
-    // Check that type-specific language negotiation methods can be assigned
-    // only to the corresponding language types.
-    foreach (language_types_get_configurable() as $type) {
-      $form_field = $type . '[enabled][test_language_negotiation_method_ts]';
-      if ($type == $test_type) {
-        $this->assertFieldByXPath("//input[@name=\"$form_field\"]", NULL, t('Type-specific test language negotiation method available for %type.', array('%type' => $type)));
-      }
-      else {
-        $this->assertNoFieldByXPath("//input[@name=\"$form_field\"]", NULL, t('Type-specific test language negotiation method unavailable for %type.', array('%type' => $type)));
-      }
-    }
-
-    // Check language negotiation results.
-    $this->drupalGet('');
-    $last = variable_get('language_test_language_negotiation_last', array());
-    foreach (language_types_get_all() as $type) {
-      $langcode = $last[$type];
-      $value = $type == LANGUAGE_TYPE_CONTENT || strpos($type, 'test') !== FALSE ? 'it' : 'en';
-      $this->assertEqual($langcode, $value, t('The negotiated language for %type is %language', array('%type' => $type, '%language' => $langcode)));
-    }
-
-    // Disable language_test and check that everything is set back to the
-    // original status.
-    $this->languageNegotiationUpdate('disable');
-
-    // Check that only the core language types are available.
-    foreach (language_types_get_all() as $type) {
-      $this->assertTrue(strpos($type, 'test') === FALSE, t('The %type language is still available', array('%type' => $type)));
-    }
-
-    // Check that fixed language types are properly configured, even those
-    // previously set to configurable.
-    $this->checkFixedLanguageTypes();
-
-    // Check that unavailable language negotiation methods are not present in
-    // the negotiation settings.
-    $negotiation = variable_get("language_negotiation_$type", array());
-    $this->assertFalse(isset($negotiation[$test_method_id]), t('The disabled test language negotiation method is not part of the content language negotiation settings.'));
-
-    // Check that configuration page presents the correct options and settings.
-    $this->assertNoRaw(t('Test language detection'), t('No test language type configuration available.'));
-    $this->assertNoRaw(t('This is a test language negotiation method'), t('No test language negotiation method available.'));
-  }
-
-  /**
-   * Update language types/negotiation information.
-   *
-   * Manually invoke language_modules_enabled()/language_modules_disabled()
-   * since they would not be invoked after enabling/disabling language_test the
-   * first time.
-   */
-  protected function languageNegotiationUpdate($op = 'enable') {
-    static $last_op = NULL;
-    $modules = array('language_test');
-
-    // Enable/disable language_test only if we did not already before.
-    if ($last_op != $op) {
-      $function = "module_{$op}";
-      $function($modules);
-      // Reset hook implementation cache.
-      module_implements_reset();
-    }
-
-    drupal_static_reset('language_types_info');
-    drupal_static_reset('language_negotiation_info');
-    $function = "language_modules_{$op}d";
-    if (function_exists($function)) {
-      $function($modules);
-    }
-
-    $this->drupalGet('admin/config/regional/language/detection');
-  }
-
-  /**
-   * Check that language negotiation for fixed types matches the stored one.
-   */
-  protected function checkFixedLanguageTypes() {
-    drupal_static_reset('language_types_info');
-    foreach (language_types_info() as $type => $info) {
-      if (isset($info['fixed'])) {
-        $negotiation = variable_get("language_negotiation_$type", array());
-        $equal = count($info['fixed']) == count($negotiation);
-        while ($equal && list($id) = each($negotiation)) {
-          list(, $info_id) = each($info['fixed']);
-          $equal = $info_id == $id;
-        }
-        $this->assertTrue($equal, t('language negotiation for %type is properly set up', array('%type' => $type)));
-      }
-    }
-  }
-}
-
-/**
- * Tests that paths are not prefixed on a monolingual site.
- */
-class LanguagePathMonolingualTestCase extends WebTestBase {
-  public static function getInfo() {
-    return array(
-      'name' => 'Paths on non-English monolingual sites',
-      'description' => 'Confirm that paths are not changed on monolingual non-English sites',
-      'group' => 'Language',
-    );
-  }
-
-  function setUp() {
-    parent::setUp('path', 'language');
-
-    // Create and login user.
-    $web_user = $this->drupalCreateUser(array('administer languages', 'access administration pages'));
-    $this->drupalLogin($web_user);
-
-    // Enable French language.
-    $edit = array();
-    $edit['predefined_langcode'] = 'fr';
-    $this->drupalPost('admin/config/regional/language/add', $edit, t('Add language'));
-
-    // Make French the default language.
-    $edit = array('site_default' => 'fr');
-    $this->drupalPost('admin/config/regional/language', $edit, t('Save configuration'));
-
-    // Delete English.
-    $this->drupalPost('admin/config/regional/language/delete/en', array(), t('Delete'));
-
-    // Verify that French is the only language.
-    $this->assertFalse(language_multilingual(), t('Site is mono-lingual'));
-    $this->assertEqual(language_default()->langcode, 'fr', t('French is the default language'));
-
-    // Set language detection to URL.
-    $edit = array('language_interface[enabled][language-url]' => TRUE);
-    $this->drupalPost('admin/config/regional/language/detection', $edit, t('Save settings'));
-
-    // Force languages to be initialized.
-    drupal_language_initialize();
-  }
-
-  /**
-   * Verifies that links do not have language prefixes in them.
-   */
-  function testPageLinks() {
-    // Navigate to 'admin/config' path.
-    $this->drupalGet('admin/config');
-
-    // Verify that links in this page do not have a 'fr/' prefix.
-    $this->assertNoLinkByHref('/fr/', 'Links do not contain language prefix');
-
-    // Verify that links in this page can be followed and work.
-    $this->clickLink(t('Languages'));
-    $this->assertResponse(200, 'Clicked link results in a valid page');
-    $this->assertText(t('Add language'), 'Page contains the add language text');
-  }
-}
diff --git a/core/modules/language/lib/Drupal/language/Tests/LanguageBrowserDetectionUnitTest.php b/core/modules/language/lib/Drupal/language/Tests/LanguageBrowserDetectionUnitTest.php
new file mode 100644
index 0000000..715da9c
--- /dev/null
+++ b/core/modules/language/lib/Drupal/language/Tests/LanguageBrowserDetectionUnitTest.php
@@ -0,0 +1,131 @@
+<?php
+
+/**
+ * @file
+ * Definition of Drupal\language\Tests\LanguageBrowserDetectionUnitTest.
+ */
+
+namespace Drupal\language\Tests;
+
+use Drupal\simpletest\UnitTestBase;
+
+/**
+ * Test browser language detection.
+ */
+class LanguageBrowserDetectionUnitTest extends UnitTestBase {
+
+  public static function getInfo() {
+    return array(
+      'name' => 'Browser language detection',
+      'description' => 'Tests for the browser language detection.',
+      'group' => 'Language',
+    );
+  }
+
+  /**
+   * Unit tests for the language_from_browser() function.
+   */
+  function testLanguageFromBrowser() {
+    // Load the required functions.
+    require_once DRUPAL_ROOT . '/core/modules/language/language.negotiation.inc';
+
+    $languages = array(
+      // In our test case, 'en' has priority over 'en-US'.
+      'en' => (object) array(
+        'langcode' => 'en',
+      ),
+      'en-US' => (object) array(
+        'langcode' => 'en-US',
+      ),
+      // But 'fr-CA' has priority over 'fr'.
+      'fr-CA' => (object) array(
+        'langcode' => 'fr-CA',
+      ),
+      'fr' => (object) array(
+        'langcode' => 'fr',
+      ),
+      // 'es-MX' is alone.
+      'es-MX' => (object) array(
+        'langcode' => 'es-MX',
+      ),
+      // 'pt' is alone.
+      'pt' => (object) array(
+        'langcode' => 'pt',
+      ),
+      // Language codes with more then one dash are actually valid.
+      // eh-oh-laa-laa is the official language code of the Teletubbies.
+      'eh-oh-laa-laa' => (object) array(
+        'langcode' => 'eh-oh-laa-laa',
+      ),
+    );
+
+    $test_cases = array(
+      // Equal qvalue for each language, choose the site prefered one.
+      'en,en-US,fr-CA,fr,es-MX' => 'en',
+      'en-US,en,fr-CA,fr,es-MX' => 'en',
+      'fr,en' => 'en',
+      'en,fr' => 'en',
+      'en-US,fr' => 'en',
+      'fr,en-US' => 'en',
+      'fr,fr-CA' => 'fr-CA',
+      'fr-CA,fr' => 'fr-CA',
+      'fr' => 'fr-CA',
+      'fr;q=1' => 'fr-CA',
+      'fr,es-MX' => 'fr-CA',
+      'fr,es' => 'fr-CA',
+      'es,fr' => 'fr-CA',
+      'es-MX,de' => 'es-MX',
+      'de,es-MX' => 'es-MX',
+
+      // Different cases and whitespace.
+      'en' => 'en',
+      'En' => 'en',
+      'EN' => 'en',
+      ' en' => 'en',
+      'en ' => 'en',
+      'en, fr' => 'en',
+
+      // A less specific language from the browser matches a more specific one
+      // from the website, and the other way around for compatibility with
+      // some versions of Internet Explorer.
+      'es' => 'es-MX',
+      'es-MX' => 'es-MX',
+      'pt' => 'pt',
+      'pt-PT' => 'pt',
+      'pt-PT;q=0.5,pt-BR;q=1,en;q=0.7' => 'en',
+      'pt-PT;q=1,pt-BR;q=0.5,en;q=0.7' => 'en',
+      'pt-PT;q=0.4,pt-BR;q=0.1,en;q=0.7' => 'en',
+      'pt-PT;q=0.1,pt-BR;q=0.4,en;q=0.7' => 'en',
+
+      // Language code with several dashes are valid. The less specific language
+      // from the browser matches the more specific one from the website.
+      'eh-oh-laa-laa' => 'eh-oh-laa-laa',
+      'eh-oh-laa' => 'eh-oh-laa-laa',
+      'eh-oh' => 'eh-oh-laa-laa',
+      'eh' => 'eh-oh-laa-laa',
+
+      // Different qvalues.
+      'en-US,en;q=0.5,fr;q=0.25' => 'en-US',
+      'fr,en;q=0.5' => 'fr-CA',
+      'fr,en;q=0.5,fr-CA;q=0.25' => 'fr',
+
+      // Silly wildcards are also valid.
+      '*,fr-CA;q=0.5' => 'en',
+      '*,en;q=0.25' => 'fr-CA',
+      'en,en-US;q=0.5,fr;q=0.25' => 'en',
+      'en-US,en;q=0.5,fr;q=0.25' => 'en-US',
+
+      // Unresolvable cases.
+      '' => FALSE,
+      'de,pl' => FALSE,
+      'iecRswK4eh' => FALSE,
+      $this->randomName(10) => FALSE,
+    );
+
+    foreach ($test_cases as $accept_language => $expected_result) {
+      $_SERVER['HTTP_ACCEPT_LANGUAGE'] = $accept_language;
+      $result = language_from_browser($languages);
+      $this->assertIdentical($result, $expected_result, t("Language selection '@accept-language' selects '@result', result = '@actual'", array('@accept-language' => $accept_language, '@result' => $expected_result, '@actual' => isset($result) ? $result : 'none')));
+    }
+  }
+}
diff --git a/core/modules/language/lib/Drupal/language/Tests/LanguageConfigurationTest.php b/core/modules/language/lib/Drupal/language/Tests/LanguageConfigurationTest.php
new file mode 100644
index 0000000..1e5f430
--- /dev/null
+++ b/core/modules/language/lib/Drupal/language/Tests/LanguageConfigurationTest.php
@@ -0,0 +1,76 @@
+<?php
+
+/**
+ * @file
+ * Definition of Drupal\language\Tests\LanguageConfigurationTest.
+ */
+
+namespace Drupal\language\Tests;
+
+use Drupal\simpletest\WebTestBase;
+
+/**
+ * Functional tests for language configuration's effect on negotiation setup.
+ */
+class LanguageConfigurationTest extends WebTestBase {
+  public static function getInfo() {
+    return array(
+      'name' => 'Language negotiation autoconfiguration',
+      'description' => 'Adds and configures languages to check negotiation changes.',
+      'group' => 'Language',
+    );
+  }
+
+  function setUp() {
+    parent::setUp('language');
+  }
+
+  /**
+   * Functional tests for adding, editing and deleting languages.
+   */
+  function testLanguageConfiguration() {
+    global $base_url;
+
+    // User to add and remove language.
+    $admin_user = $this->drupalCreateUser(array('administer languages', 'access administration pages'));
+    $this->drupalLogin($admin_user);
+
+    // Check if the Default English language has no path prefix.
+    $this->drupalGet('admin/config/regional/language/detection/url');
+    $this->assertFieldByXPath('//input[@name="prefix[en]"]', '', t('Default English has no path prefix.'));
+
+    // Add predefined language.
+    $edit = array(
+      'predefined_langcode' => 'fr',
+    );
+    $this->drupalPost('admin/config/regional/language/add', $edit, t('Add language'));
+    $this->assertText('French');
+    $this->assertEqual($this->getUrl(), url('admin/config/regional/language', array('absolute' => TRUE)), t('Correct page redirection.'));
+
+    // Check if the Default English language has no path prefix.
+    $this->drupalGet('admin/config/regional/language/detection/url');
+    $this->assertFieldByXPath('//input[@name="prefix[en]"]', '', t('Default English has no path prefix.'));
+    // Check if French has a path prefix.
+    $this->drupalGet('admin/config/regional/language/detection/url');
+    $this->assertFieldByXPath('//input[@name="prefix[fr]"]', 'fr', t('French has a path prefix.'));
+
+    // Check if we can change the default language.
+    $this->drupalGet('admin/config/regional/language');
+    $this->assertFieldChecked('edit-site-default-en', t('English is the default language.'));
+    // Change the default language.
+    $edit = array(
+      'site_default' => 'fr',
+    );
+    $this->drupalPost(NULL, $edit, t('Save configuration'));
+    $this->assertNoFieldChecked('edit-site-default-en', t('Default language updated.'));
+    $this->assertEqual($this->getUrl(), url('admin/config/regional/language', array('absolute' => TRUE)), t('Correct page redirection.'));
+
+    // Check if a valid language prefix is added afrer changing the default
+    // language.
+    $this->drupalGet('admin/config/regional/language/detection/url');
+    $this->assertFieldByXPath('//input[@name="prefix[en]"]', 'en', t('A valid path prefix has been added to the previous default language.'));
+    // Check if French still has a path prefix.
+    $this->drupalGet('admin/config/regional/language/detection/url');
+    $this->assertFieldByXPath('//input[@name="prefix[fr]"]', 'fr', t('French still has a path prefix.'));
+  }
+}
diff --git a/core/modules/language/lib/Drupal/language/Tests/LanguageDependencyInjectionTest.php b/core/modules/language/lib/Drupal/language/Tests/LanguageDependencyInjectionTest.php
new file mode 100644
index 0000000..e000531
--- /dev/null
+++ b/core/modules/language/lib/Drupal/language/Tests/LanguageDependencyInjectionTest.php
@@ -0,0 +1,98 @@
+<?php
+
+/**
+ * @file
+ * Definition of Drupal\language\Tests\LanguageDependencyInjectionTest.
+ */
+
+namespace Drupal\language\Tests;
+
+use Drupal\Core\DependencyInjection\ContainerBuilder;
+use Drupal\Core\Language\Language;
+use Drupal\simpletest\WebTestBase;
+
+/**
+ * Test for dependency injected language object.
+ */
+class LanguageDependencyInjectionTest extends WebTestBase {
+  public static function getInfo() {
+    return array(
+        'name' => 'Language dependency injection',
+        'description' => 'Compares the default language from $GLOBALS against the dependency injected language object.',
+        'group' => 'Language',
+    );
+  }
+
+  function setUp() {
+    parent::setUp('language');
+
+    // Set up a new container to ensure we are building a new Language object
+    // for each test.
+    drupal_container(new ContainerBuilder());
+  }
+
+  /**
+   * Test dependency injected Language against the GLOBAL language object.
+   *
+   * @todo Once the PHP global is gone, we won't need this test as the same
+   * test is done without the PHP global in the following test.
+   */
+  function testDependencyInjectedLanguage() {
+    // Initialize the language system.
+    drupal_language_initialize();
+
+    $expected = $GLOBALS[LANGUAGE_TYPE_INTERFACE];
+    $result = drupal_container()->get(LANGUAGE_TYPE_INTERFACE);
+    foreach ($expected as $property => $value) {
+      $this->assertEqual($expected->$property, $result->$property, t('The dependency injected language object %prop property equals the $GLOBAL language object %prop property.', array('%prop' => $property)));
+    }
+  }
+
+  /**
+   * Test dependency injected languages against a new Language object.
+   *
+   * @see Drupal\Core\Language\Language
+   */
+  function testDependencyInjectedNewLanguage() {
+    // Initialize the language system.
+    drupal_language_initialize();
+
+    $expected = new Language((array) language_default());
+    $result = drupal_container()->get(LANGUAGE_TYPE_INTERFACE);
+    foreach ($expected as $property => $value) {
+      $this->assertEqual($expected->$property, $result->$property, t('The dependency injected language object %prop property equals the new Language object %prop property.', array('%prop' => $property)));
+    }
+  }
+
+  /**
+   * Test dependency injected Language object against a new default language
+   * object.
+   *
+   * @see Drupal\Core\Language\Language
+   */
+  function testDependencyInjectedNewDefaultLanguage() {
+    // Change the language default object to different values.
+    $new_language_default = (object) array(
+      'langcode' => 'fr',
+      'name' => 'French',
+      'direction' => 0,
+      'weight' => 0,
+      'default' => TRUE,
+    );
+    variable_set('language_default', $new_language_default);
+
+    // Initialize the language system.
+    drupal_language_initialize();
+
+    // The langauge system creates a Language object which contains the
+    // same properties as the new default language object.
+    $expected = $new_language_default;
+    $result = drupal_container()->get(LANGUAGE_TYPE_INTERFACE);
+    foreach ($expected as $property => $value) {
+      $this->assertEqual($expected->$property, $result->$property, t('The dependency injected language object %prop property equals the default language object %prop property.', array('%prop' => $property)));
+    }
+
+    // Delete the language_default variable we previously set.
+    variable_del('language_default');
+  }
+}
diff --git a/core/modules/language/lib/Drupal/language/Tests/LanguageListTest.php b/core/modules/language/lib/Drupal/language/Tests/LanguageListTest.php
new file mode 100644
index 0000000..7346bfc
--- /dev/null
+++ b/core/modules/language/lib/Drupal/language/Tests/LanguageListTest.php
@@ -0,0 +1,165 @@
+<?php
+
+/**
+ * @file
+ * Definition of Drupal\language\Tests\LanguageListTest.
+ */
+
+namespace Drupal\language\Tests;
+
+use Drupal\simpletest\WebTestBase;
+
+/**
+ * Functional tests for the language list configuration forms.
+ */
+class LanguageListTest extends WebTestBase {
+  public static function getInfo() {
+    return array(
+      'name' => 'Language list configuration',
+      'description' => 'Adds a new language and tests changing its status and the default language.',
+      'group' => 'Language',
+    );
+  }
+
+  function setUp() {
+    parent::setUp('language');
+  }
+
+  /**
+   * Functional tests for adding, editing and deleting languages.
+   */
+  function testLanguageList() {
+    global $base_url;
+
+    // User to add and remove language.
+    $admin_user = $this->drupalCreateUser(array('administer languages', 'access administration pages'));
+    $this->drupalLogin($admin_user);
+
+    // Add predefined language.
+    $edit = array(
+      'predefined_langcode' => 'fr',
+    );
+    $this->drupalPost('admin/config/regional/language/add', $edit, t('Add language'));
+    $this->assertText('French', t('Language added successfully.'));
+    $this->assertEqual($this->getUrl(), url('admin/config/regional/language', array('absolute' => TRUE)), t('Correct page redirection.'));
+
+    // Add custom language.
+    $langcode = 'xx';
+    $name = $this->randomName(16);
+    $edit = array(
+      'predefined_langcode' => 'custom',
+      'langcode' => $langcode,
+      'name' => $name,
+      'direction' => '0',
+    );
+    $this->drupalPost('admin/config/regional/language/add', $edit, t('Add custom language'));
+    $this->assertEqual($this->getUrl(), url('admin/config/regional/language', array('absolute' => TRUE)), t('Correct page redirection.'));
+    $this->assertRaw('"edit-site-default-' . $langcode .'"', t('Language code found.'));
+    $this->assertText(t($name), t('Test language added.'));
+
+    // Check if we can change the default language.
+    $path = 'admin/config/regional/language';
+    $this->drupalGet($path);
+    $this->assertFieldChecked('edit-site-default-en', t('English is the default language.'));
+    // Change the default language.
+    $edit = array(
+      'site_default' => $langcode,
+    );
+    $this->drupalPost(NULL, $edit, t('Save configuration'));
+    $this->assertNoFieldChecked('edit-site-default-en', t('Default language updated.'));
+    $this->assertEqual($this->getUrl(), url('admin/config/regional/language', array('absolute' => TRUE)), t('Correct page redirection.'));
+
+    // Ensure we can't delete the default language.
+    $this->drupalGet('admin/config/regional/language/delete/' . $langcode);
+    $this->assertEqual($this->getUrl(), url('admin/config/regional/language', array('absolute' => TRUE)), t('Correct page redirection.'));
+    $this->assertText(t('The default language cannot be deleted.'), t('Failed to delete the default language.'));
+
+    // Ensure 'edit' link works.
+    $this->clickLink(t('edit'));
+    $this->assertTitle(t('Edit language | Drupal'), t('Page title is "Edit language".'));
+    // Edit a language.
+    $name = $this->randomName(16);
+    $edit = array(
+      'name' => $name,
+    );
+    $this->drupalPost('admin/config/regional/language/edit/' . $langcode, $edit, t('Save language'));
+    $this->assertRaw($name, t('The language has been updated.'));
+    $this->assertEqual($this->getUrl(), url('admin/config/regional/language', array('absolute' => TRUE)), t('Correct page redirection.'));
+
+    // Change back the default language.
+    $edit = array(
+      'site_default' => 'en',
+    );
+    $this->drupalPost(NULL, $edit, t('Save configuration'));
+    // Ensure 'delete' link works.
+    $this->drupalGet('admin/config/regional/language');
+    $this->clickLink(t('delete'));
+    $this->assertText(t('Are you sure you want to delete the language'), t('"delete" link is correct.'));
+    // Delete a language.
+    $this->drupalGet('admin/config/regional/language/delete/' . $langcode);
+    // First test the 'cancel' link.
+    $this->clickLink(t('Cancel'));
+    $this->assertEqual($this->getUrl(), url('admin/config/regional/language', array('absolute' => TRUE)), t('Correct page redirection.'));
+    $this->assertRaw($name, t('The language was not deleted.'));
+    // Delete the language for real. This a confirm form, we do not need any
+    // fields changed.
+    $this->drupalPost('admin/config/regional/language/delete/' . $langcode, array(), t('Delete'));
+    // We need raw here because %language and %langcode will add HTML.
+    $t_args = array('%language' => $name, '%langcode' => $langcode);
+    $this->assertRaw(t('The %language (%langcode) language has been removed.', $t_args), t('The test language has been removed.'));
+    $this->assertEqual($this->getUrl(), url('admin/config/regional/language', array('absolute' => TRUE)), t('Correct page redirection.'));
+    // Verify that language is no longer found.
+    $this->drupalGet('admin/config/regional/language/delete/' . $langcode);
+    $this->assertResponse(404, t('Language no longer found.'));
+    // Make sure the "language_count" variable has been updated correctly.
+    drupal_static_reset('language_list');
+    $languages = language_list();
+    $this->assertEqual(variable_get('language_count', 1), count($languages), t('Language count is correct.'));
+    // Delete French.
+    $this->drupalPost('admin/config/regional/language/delete/fr', array(), t('Delete'));
+    // Get the count of languages.
+    drupal_static_reset('language_list');
+    $languages = language_list();
+    // We need raw here because %language and %langcode will add HTML.
+    $t_args = array('%language' => 'French', '%langcode' => 'fr');
+    $this->assertRaw(t('The %language (%langcode) language has been removed.', $t_args), t('Disabled language has been removed.'));
+    $this->assertEqual($this->getUrl(), url('admin/config/regional/language', array('absolute' => TRUE)), t('Correct page redirection.'));
+    // Verify that language is no longer found.
+    $this->drupalGet('admin/config/regional/language/delete/fr');
+    $this->assertResponse(404, t('Language no longer found.'));
+    // Make sure the "language_count" variable has not changed.
+    $this->assertEqual(variable_get('language_count', 1), count($languages), t('Language count is correct.'));
+
+    // Ensure we can delete the English language. Right now English is the only
+    // language so we must add a new language and make it the default before
+    // deleting English.
+    $langcode = 'xx';
+    $name = $this->randomName(16);
+    $edit = array(
+      'predefined_langcode' => 'custom',
+      'langcode' => $langcode,
+      'name' => $name,
+      'direction' => '0',
+    );
+    $this->drupalPost('admin/config/regional/language/add', $edit, t('Add custom language'));
+    $this->assertEqual($this->getUrl(), url('admin/config/regional/language', array('absolute' => TRUE)), t('Correct page redirection.'));
+    $this->assertText($name, t('Name found.'));
+
+    // Check if we can change the default language.
+    $path = 'admin/config/regional/language';
+    $this->drupalGet($path);
+    $this->assertFieldChecked('edit-site-default-en', t('English is the default language.'));
+    // Change the default language.
+    $edit = array(
+      'site_default' => $langcode,
+    );
+    $this->drupalPost(NULL, $edit, t('Save configuration'));
+    $this->assertNoFieldChecked('edit-site-default-en', t('Default language updated.'));
+    $this->assertEqual($this->getUrl(), url('admin/config/regional/language', array('absolute' => TRUE)), t('Correct page redirection.'));
+
+    $this->drupalPost('admin/config/regional/language/delete/en', array(), t('Delete'));
+    // We need raw here because %language and %langcode will add HTML.
+    $t_args = array('%language' => 'English', '%langcode' => 'en');
+    $this->assertRaw(t('The %language (%langcode) language has been removed.', $t_args), t('The English language has been removed.'));
+  }
+}
diff --git a/core/modules/language/lib/Drupal/language/Tests/LanguageNegotiationInfoTest.php b/core/modules/language/lib/Drupal/language/Tests/LanguageNegotiationInfoTest.php
new file mode 100644
index 0000000..d7d68e4
--- /dev/null
+++ b/core/modules/language/lib/Drupal/language/Tests/LanguageNegotiationInfoTest.php
@@ -0,0 +1,165 @@
+<?php
+
+/**
+ * @file
+ * Definition of Drupal\language\Tests\LanguageNegotiationInfoTest.
+ */
+
+namespace Drupal\language\Tests;
+
+use Drupal\simpletest\WebTestBase;
+
+/**
+ * Functional test for language types/negotiation info.
+ */
+class LanguageNegotiationInfoTest extends WebTestBase {
+
+  public static function getInfo() {
+    return array(
+      'name' => 'Language negotiation info',
+      'description' => 'Tests alterations to language types/negotiation info.',
+      'group' => 'Language',
+    );
+  }
+
+  function setUp() {
+    parent::setUp('language');
+    require_once DRUPAL_ROOT .'/core/includes/language.inc';
+    $admin_user = $this->drupalCreateUser(array('administer languages', 'access administration pages', 'view the administration theme'));
+    $this->drupalLogin($admin_user);
+    $this->drupalPost('admin/config/regional/language/add', array('predefined_langcode' => 'it'), t('Add language'));
+  }
+
+  /**
+   * Tests alterations to language types/negotiation info.
+   */
+  function testInfoAlterations() {
+    // Enable language type/negotiation info alterations.
+    variable_set('language_test_language_types', TRUE);
+    variable_set('language_test_language_negotiation_info', TRUE);
+    $this->languageNegotiationUpdate();
+
+    // Check that fixed language types are properly configured without the need
+    // of saving the language negotiation settings.
+    $this->checkFixedLanguageTypes();
+
+    // Make the content language type configurable by updating the language
+    // negotiation settings with the proper flag enabled.
+    variable_set('language_test_content_language_type', TRUE);
+    $this->languageNegotiationUpdate();
+    $type = LANGUAGE_TYPE_CONTENT;
+    $language_types = variable_get('language_types', language_types_get_default());
+    $this->assertTrue($language_types[$type], t('Content language type is configurable.'));
+
+    // Enable some core and custom language negotiation methods. The test
+    // language type is supposed to be configurable.
+    $test_type = 'test_language_type';
+    $interface_method_id = LANGUAGE_NEGOTIATION_INTERFACE;
+    $test_method_id = 'test_language_negotiation_method';
+    $form_field = $type . '[enabled]['. $interface_method_id .']';
+    $edit = array(
+      $form_field => TRUE,
+      $type . '[enabled][' . $test_method_id . ']' => TRUE,
+      $test_type . '[enabled][' . $test_method_id . ']' => TRUE,
+    );
+    $this->drupalPost('admin/config/regional/language/detection', $edit, t('Save settings'));
+
+    // Remove the interface language negotiation method by updating the language
+    // negotiation settings with the proper flag enabled.
+    variable_set('language_test_language_negotiation_info_alter', TRUE);
+    $this->languageNegotiationUpdate();
+    $negotiation = variable_get("language_negotiation_$type", array());
+    $this->assertFalse(isset($negotiation[$interface_method_id]), t('Interface language negotiation method removed from the stored settings.'));
+    $this->assertNoFieldByXPath("//input[@name=\"$form_field\"]", NULL, t('Interface language negotiation method unavailable.'));
+
+    // Check that type-specific language negotiation methods can be assigned
+    // only to the corresponding language types.
+    foreach (language_types_get_configurable() as $type) {
+      $form_field = $type . '[enabled][test_language_negotiation_method_ts]';
+      if ($type == $test_type) {
+        $this->assertFieldByXPath("//input[@name=\"$form_field\"]", NULL, t('Type-specific test language negotiation method available for %type.', array('%type' => $type)));
+      }
+      else {
+        $this->assertNoFieldByXPath("//input[@name=\"$form_field\"]", NULL, t('Type-specific test language negotiation method unavailable for %type.', array('%type' => $type)));
+      }
+    }
+
+    // Check language negotiation results.
+    $this->drupalGet('');
+    $last = variable_get('language_test_language_negotiation_last', array());
+    foreach (language_types_get_all() as $type) {
+      $langcode = $last[$type];
+      $value = $type == LANGUAGE_TYPE_CONTENT || strpos($type, 'test') !== FALSE ? 'it' : 'en';
+      $this->assertEqual($langcode, $value, t('The negotiated language for %type is %language', array('%type' => $type, '%language' => $langcode)));
+    }
+
+    // Disable language_test and check that everything is set back to the
+    // original status.
+    $this->languageNegotiationUpdate('disable');
+
+    // Check that only the core language types are available.
+    foreach (language_types_get_all() as $type) {
+      $this->assertTrue(strpos($type, 'test') === FALSE, t('The %type language is still available', array('%type' => $type)));
+    }
+
+    // Check that fixed language types are properly configured, even those
+    // previously set to configurable.
+    $this->checkFixedLanguageTypes();
+
+    // Check that unavailable language negotiation methods are not present in
+    // the negotiation settings.
+    $negotiation = variable_get("language_negotiation_$type", array());
+    $this->assertFalse(isset($negotiation[$test_method_id]), t('The disabled test language negotiation method is not part of the content language negotiation settings.'));
+
+    // Check that configuration page presents the correct options and settings.
+    $this->assertNoRaw(t('Test language detection'), t('No test language type configuration available.'));
+    $this->assertNoRaw(t('This is a test language negotiation method'), t('No test language negotiation method available.'));
+  }
+
+  /**
+   * Update language types/negotiation information.
+   *
+   * Manually invoke language_modules_enabled()/language_modules_disabled()
+   * since they would not be invoked after enabling/disabling language_test the
+   * first time.
+   */
+  protected function languageNegotiationUpdate($op = 'enable') {
+    static $last_op = NULL;
+    $modules = array('language_test');
+
+    // Enable/disable language_test only if we did not already before.
+    if ($last_op != $op) {
+      $function = "module_{$op}";
+      $function($modules);
+      // Reset hook implementation cache.
+      module_implements_reset();
+    }
+
+    drupal_static_reset('language_types_info');
+    drupal_static_reset('language_negotiation_info');
+    $function = "language_modules_{$op}d";
+    if (function_exists($function)) {
+      $function($modules);
+    }
+
+    $this->drupalGet('admin/config/regional/language/detection');
+  }
+
+  /**
+   * Check that language negotiation for fixed types matches the stored one.
+   */
+  protected function checkFixedLanguageTypes() {
+    drupal_static_reset('language_types_info');
+    foreach (language_types_info() as $type => $info) {
+      if (isset($info['fixed'])) {
+        $negotiation = variable_get("language_negotiation_$type", array());
+        $equal = count($info['fixed']) == count($negotiation);
+        while ($equal && list($id) = each($negotiation)) {
+          list(, $info_id) = each($info['fixed']);
+          $equal = $info_id == $id;
+        }
+        $this->assertTrue($equal, t('language negotiation for %type is properly set up', array('%type' => $type)));
+      }
+    }
+  }
+}
diff --git a/core/modules/language/lib/Drupal/language/Tests/LanguagePathMonolingualTest.php b/core/modules/language/lib/Drupal/language/Tests/LanguagePathMonolingualTest.php
new file mode 100644
index 0000000..4f80277
--- /dev/null
+++ b/core/modules/language/lib/Drupal/language/Tests/LanguagePathMonolingualTest.php
@@ -0,0 +1,70 @@
+<?php
+
+/**
+ * @file
+ * Definition of Drupal\language\Tests\LanguagePathMonolingualTest.
+ */
+
+namespace Drupal\language\Tests;
+
+use Drupal\simpletest\WebTestBase;
+
+/**
+ * Tests that paths are not prefixed on a monolingual site.
+ */
+class LanguagePathMonolingualTest extends WebTestBase {
+  public static function getInfo() {
+    return array(
+      'name' => 'Paths on non-English monolingual sites',
+      'description' => 'Confirm that paths are not changed on monolingual non-English sites',
+      'group' => 'Language',
+    );
+  }
+
+  function setUp() {
+    parent::setUp('path', 'language');
+
+    // Create and login user.
+    $web_user = $this->drupalCreateUser(array('administer languages', 'access administration pages'));
+    $this->drupalLogin($web_user);
+
+    // Enable French language.
+    $edit = array();
+    $edit['predefined_langcode'] = 'fr';
+    $this->drupalPost('admin/config/regional/language/add', $edit, t('Add language'));
+
+    // Make French the default language.
+    $edit = array('site_default' => 'fr');
+    $this->drupalPost('admin/config/regional/language', $edit, t('Save configuration'));
+
+    // Delete English.
+    $this->drupalPost('admin/config/regional/language/delete/en', array(), t('Delete'));
+
+    // Verify that French is the only language.
+    $this->assertFalse(language_multilingual(), t('Site is mono-lingual'));
+    $this->assertEqual(language_default()->langcode, 'fr', t('French is the default language'));
+
+    // Set language detection to URL.
+    $edit = array('language_interface[enabled][language-url]' => TRUE);
+    $this->drupalPost('admin/config/regional/language/detection', $edit, t('Save settings'));
+
+    // Force languages to be initialized.
+    drupal_language_initialize();
+  }
+
+  /**
+   * Verifies that links do not have language prefixes in them.
+   */
+  function testPageLinks() {
+    // Navigate to 'admin/config' path.
+    $this->drupalGet('admin/config');
+
+    // Verify that links in this page do not have a 'fr/' prefix.
+    $this->assertNoLinkByHref('/fr/', 'Links do not contain language prefix');
+
+    // Verify that links in this page can be followed and work.
+    $this->clickLink(t('Languages'));
+    $this->assertResponse(200, 'Clicked link results in a valid page');
+    $this->assertText(t('Add language'), 'Page contains the add language text');
+  }
+}
diff --git a/core/modules/language/lib/Drupal/language/Tests/LanguageSwitchingTest.php b/core/modules/language/lib/Drupal/language/Tests/LanguageSwitchingTest.php
new file mode 100644
index 0000000..c8c6732
--- /dev/null
+++ b/core/modules/language/lib/Drupal/language/Tests/LanguageSwitchingTest.php
@@ -0,0 +1,88 @@
+<?php
+
+/**
+ * @file
+ * Definition of Drupal\language\Tests\LanguageSwitchingTest.
+ */
+
+namespace Drupal\language\Tests;
+
+use Drupal\simpletest\WebTestBase;
+
+/**
+ * Functional tests for the language switching feature.
+ */
+class LanguageSwitchingTest extends WebTestBase {
+
+  public static function getInfo() {
+    return array(
+      'name' => 'Language switching',
+      'description' => 'Tests for the language switching feature.',
+      'group' => 'Language',
+    );
+  }
+
+  function setUp() {
+    parent::setUp(array('language', 'block'));
+
+    // Create and login user.
+    $admin_user = $this->drupalCreateUser(array('administer blocks', 'administer languages', 'access administration pages'));
+    $this->drupalLogin($admin_user);
+  }
+
+  /**
+   * Functional tests for the language switcher block.
+   */
+  function testLanguageBlock() {
+    // Enable the language switching block.
+    $language_type = LANGUAGE_TYPE_INTERFACE;
+    $edit = array(
+      "blocks[language_{$language_type}][region]" => 'sidebar_first',
+    );
+    $this->drupalPost('admin/structure/block', $edit, t('Save blocks'));
+
+    // Add language.
+    $edit = array(
+      'predefined_langcode' => 'fr',
+    );
+    $this->drupalPost('admin/config/regional/language/add', $edit, t('Add language'));
+
+    // Enable URL language detection and selection.
+    $edit = array('language_interface[enabled][language-url]' => '1');
+    $this->drupalPost('admin/config/regional/language/detection', $edit, t('Save settings'));
+
+    // Assert that the language switching block is displayed on the frontpage.
+    $this->drupalGet('');
+    $this->assertText(t('Languages'), t('Language switcher block found.'));
+
+    // Assert that only the current language is marked as active.
+    list($language_switcher) = $this->xpath('//div[@id=:id]/div[@class="content"]', array(':id' => 'block-language-' . str_replace('_', '-', $language_type)));
+    $links = array(
+      'active' => array(),
+      'inactive' => array(),
+    );
+    $anchors = array(
+      'active' => array(),
+      'inactive' => array(),
+    );
+    foreach ($language_switcher->ul->li as $link) {
+      $classes = explode(" ", (string) $link['class']);
+      list($langcode) = array_intersect($classes, array('en', 'fr'));
+      if (in_array('active', $classes)) {
+        $links['active'][] = $langcode;
+      }
+      else {
+        $links['inactive'][] = $langcode;
+      }
+      $anchor_classes = explode(" ", (string) $link->a['class']);
+      if (in_array('active', $anchor_classes)) {
+        $anchors['active'][] = $langcode;
+      }
+      else {
+        $anchors['inactive'][] = $langcode;
+      }
+    }
+    $this->assertIdentical($links, array('active' => array('en'), 'inactive' => array('fr')), t('Only the current language list item is marked as active on the language switcher block.'));
+    $this->assertIdentical($anchors, array('active' => array('en'), 'inactive' => array('fr')), t('Only the current language anchor is marked as active on the language switcher block.'));
+  }
+}
diff --git a/core/modules/language/lib/Drupal/language/Tests/LanguageUILanguageNegotiationTest.php b/core/modules/language/lib/Drupal/language/Tests/LanguageUILanguageNegotiationTest.php
new file mode 100644
index 0000000..6397fa2
--- /dev/null
+++ b/core/modules/language/lib/Drupal/language/Tests/LanguageUILanguageNegotiationTest.php
@@ -0,0 +1,330 @@
+<?php
+
+/**
+ * @file
+ * Definition of Drupal\language\Tests\LanguageUILanguageNegotiationTest.
+ */
+
+namespace Drupal\language\Tests;
+
+use Drupal\simpletest\WebTestBase;
+
+/**
+ * Test UI language negotiation
+ *
+ * 1. URL (PATH) > DEFAULT
+ *    UI Language base on URL prefix, browser language preference has no
+ *    influence:
+ *      admin/config
+ *        UI in site default language
+ *      zh-hans/admin/config
+ *        UI in Chinese
+ *      blah-blah/admin/config
+ *        404
+ * 2. URL (PATH) > BROWSER > DEFAULT
+ *        admin/config
+ *          UI in user's browser language preference if the site has that
+ *          language enabled, if not, the default language
+ *        zh-hans/admin/config
+ *          UI in Chinese
+ *        blah-blah/admin/config
+ *          404
+ * 3. URL (DOMAIN) > DEFAULT
+ *        http://example.com/admin/config
+ *          UI language in site default
+ *        http://example.cn/admin/config
+ *          UI language in Chinese
+ */
+class LanguageUILanguageNegotiationTest extends WebTestBase {
+  public static function getInfo() {
+    return array(
+      'name' => 'UI language negotiation',
+      'description' => 'Test UI language switching by url path prefix and domain.',
+      'group' => 'Language',
+    );
+  }
+
+  function setUp() {
+    // We marginally use interface translation functionality here, so need to
+    // use the locale module instead of language only, but the 90% of the test
+    // is about the negotiation process which is solely in language module.
+    parent::setUp(array('locale', 'language_test', 'block'));
+    require_once DRUPAL_ROOT . '/core/includes/language.inc';
+    drupal_load('module', 'locale');
+    $admin_user = $this->drupalCreateUser(array('administer languages', 'translate interface', 'access administration pages', 'administer blocks'));
+    $this->drupalLogin($admin_user);
+  }
+
+  /**
+   * Tests for language switching by URL path.
+   */
+  function testUILanguageNegotiation() {
+    // A few languages to switch to.
+    // This one is unknown, should get the default lang version.
+    $langcode_unknown = 'blah-blah';
+    // For testing browser lang preference.
+    $langcode_browser_fallback = 'vi';
+    // For testing path prefix.
+    $langcode = 'zh-hans';
+    // For setting browser language preference to 'vi'.
+    $http_header_browser_fallback = array("Accept-Language: $langcode_browser_fallback;q=1");
+    // For setting browser language preference to some unknown.
+    $http_header_blah = array("Accept-Language: blah;q=1");
+
+    // This domain should switch the UI to Chinese.
+    $language_domain = 'example.cn';
+
+    // Setup the site languages by installing two languages.
+    $language = (object) array(
+      'langcode' => $langcode_browser_fallback,
+    );
+    language_save($language);
+    $language = (object) array(
+      'langcode' => $langcode,
+    );
+    language_save($language);
+
+    // We will look for this string in the admin/config screen to see if the
+    // corresponding translated string is shown.
+    $default_string = 'Configure languages for content and the user interface';
+
+    // Set the default language in order for the translated string to be registered
+    // into database when seen by t(). Without doing this, our target string
+    // is for some reason not found when doing translate search. This might
+    // be some bug.
+    drupal_static_reset('language_list');
+    $languages = language_list();
+    variable_set('language_default', $languages['vi']);
+    // First visit this page to make sure our target string is searchable.
+    $this->drupalGet('admin/config');
+    // Now the t()'ed string is in db so switch the language back to default.
+    variable_del('language_default');
+
+    // Translate the string.
+    $language_browser_fallback_string = "In $langcode_browser_fallback In $langcode_browser_fallback In $langcode_browser_fallback";
+    $language_string = "In $langcode In $langcode In $langcode";
+    // Do a translate search of our target string.
+    $edit = array( 'string' => $default_string);
+    $this->drupalPost('admin/config/regional/translate/translate', $edit, t('Filter'));
+    // Should find the string and now click edit to post translated string.
+    $this->clickLink('edit');
+    $edit = array(
+      "translations[$langcode_browser_fallback][0]" => $language_browser_fallback_string,
+      "translations[$langcode][0]" => $language_string,
+    );
+    $this->drupalPost(NULL, $edit, t('Save translations'));
+
+    // Configure URL language rewrite.
+    variable_set('language_negotiation_url_type', LANGUAGE_TYPE_INTERFACE);
+
+    $tests = array(
+      // Default, browser preference should have no influence.
+      array(
+        'language_negotiation' => array(LANGUAGE_NEGOTIATION_URL, LANGUAGE_NEGOTIATION_DEFAULT),
+        'path' => 'admin/config',
+        'expect' => $default_string,
+        'expected_method_id' => LANGUAGE_NEGOTIATION_DEFAULT,
+        'http_header' => $http_header_browser_fallback,
+        'message' => 'URL (PATH) > DEFAULT: no language prefix, UI language is default and the browser language preference setting is not used.',
+      ),
+      // Language prefix.
+      array(
+        'language_negotiation' => array(LANGUAGE_NEGOTIATION_URL, LANGUAGE_NEGOTIATION_DEFAULT),
+        'path' => "$langcode/admin/config",
+        'expect' => $language_string,
+        'expected_method_id' => LANGUAGE_NEGOTIATION_URL,
+        'http_header' => $http_header_browser_fallback,
+        'message' => 'URL (PATH) > DEFAULT: with language prefix, UI language is switched based on path prefix',
+      ),
+      // Default, go by browser preference.
+      array(
+        'language_negotiation' => array(LANGUAGE_NEGOTIATION_URL, LANGUAGE_NEGOTIATION_BROWSER),
+        'path' => 'admin/config',
+        'expect' => $language_browser_fallback_string,
+        'expected_method_id' => LANGUAGE_NEGOTIATION_BROWSER,
+        'http_header' => $http_header_browser_fallback,
+        'message' => 'URL (PATH) > BROWSER: no language prefix, UI language is determined by browser language preference',
+      ),
+      // Prefix, switch to the language.
+      array(
+        'language_negotiation' => array(LANGUAGE_NEGOTIATION_URL, LANGUAGE_NEGOTIATION_BROWSER),
+        'path' => "$langcode/admin/config",
+        'expect' => $language_string,
+        'expected_method_id' => LANGUAGE_NEGOTIATION_URL,
+        'http_header' => $http_header_browser_fallback,
+        'message' => 'URL (PATH) > BROWSER: with langage prefix, UI language is based on path prefix',
+      ),
+      // Default, browser language preference is not one of site's lang.
+      array(
+        'language_negotiation' => array(LANGUAGE_NEGOTIATION_URL, LANGUAGE_NEGOTIATION_BROWSER, LANGUAGE_NEGOTIATION_DEFAULT),
+        'path' => 'admin/config',
+        'expect' => $default_string,
+        'expected_method_id' => LANGUAGE_NEGOTIATION_DEFAULT,
+        'http_header' => $http_header_blah,
+        'message' => 'URL (PATH) > BROWSER > DEFAULT: no language prefix and browser language preference set to unknown language should use default language',
+      ),
+    );
+
+    foreach ($tests as $test) {
+      $this->runTest($test);
+    }
+
+    // Unknown language prefix should return 404.
+    variable_set('language_negotiation_' . LANGUAGE_TYPE_INTERFACE, language_language_negotiation_info());
+    $this->drupalGet("$langcode_unknown/admin/config", array(), $http_header_browser_fallback);
+    $this->assertResponse(404, "Unknown language path prefix should return 404");
+
+    // Setup for domain negotiation, first configure the language to have domain
+    // URL.
+    $edit = array("domain[$langcode]" => $language_domain);
+    $this->drupalPost("admin/config/regional/language/detection/url", $edit, t('Save configuration'));
+    // Set the site to use domain language negotiation.
+
+    $tests = array(
+      // Default domain, browser preference should have no influence.
+      array(
+        'language_negotiation' => array(LANGUAGE_NEGOTIATION_URL, LANGUAGE_NEGOTIATION_DEFAULT),
+        'language_negotiation_url_part' => LANGUAGE_NEGOTIATION_URL_DOMAIN,
+        'path' => 'admin/config',
+        'expect' => $default_string,
+        'expected_method_id' => LANGUAGE_NEGOTIATION_DEFAULT,
+        'http_header' => $http_header_browser_fallback,
+        'message' => 'URL (DOMAIN) > DEFAULT: default domain should get default language',
+      ),
+      // Language domain specific URL, we set the $_SERVER['HTTP_HOST'] in
+      // language_test.module hook_boot() to simulate this.
+      array(
+        'language_negotiation' => array(LANGUAGE_NEGOTIATION_URL, LANGUAGE_NEGOTIATION_DEFAULT),
+        'language_negotiation_url_part' => LANGUAGE_NEGOTIATION_URL_DOMAIN,
+        'language_test_domain' => $language_domain,
+        'path' => 'admin/config',
+        'expect' => $language_string,
+        'expected_method_id' => LANGUAGE_NEGOTIATION_URL,
+        'http_header' => $http_header_browser_fallback,
+        'message' => 'URL (DOMAIN) > DEFAULT: domain example.cn should switch to Chinese',
+      ),
+    );
+
+    foreach ($tests as $test) {
+      $this->runTest($test);
+    }
+  }
+
+  protected function runTest($test) {
+    if (!empty($test['language_negotiation'])) {
+      $method_weights = array_flip($test['language_negotiation']);
+      language_negotiation_set(LANGUAGE_TYPE_INTERFACE, $method_weights);
+    }
+    if (!empty($test['language_negotiation_url_part'])) {
+      variable_set('language_negotiation_url_part', $test['language_negotiation_url_part']);
+    }
+    if (!empty($test['language_test_domain'])) {
+      variable_set('language_test_domain', $test['language_test_domain']);
+    }
+    $this->drupalGet($test['path'], array(), $test['http_header']);
+    $this->assertText($test['expect'], $test['message']);
+    $this->assertText(t('Language negotiation method: @name', array('@name' => $test['expected_method_id'])));
+  }
+
+  /**
+   * Test URL language detection when the requested URL has no language.
+   */
+  function testUrlLanguageFallback() {
+    // Add the Italian language.
+    $langcode_browser_fallback = 'it';
+    $language = (object) array(
+      'langcode' => $langcode_browser_fallback,
+    );
+    language_save($language);
+    $languages = language_list();
+
+    // Enable the path prefix for the default language: this way any unprefixed
+    // URL must have a valid fallback value.
+    $edit = array('prefix[en]' => 'en');
+    $this->drupalPost('admin/config/regional/language/detection/url', $edit, t('Save configuration'));
+
+    // Enable browser and URL language detection.
+    $edit = array(
+      'language_interface[enabled][language-browser]' => TRUE,
+      'language_interface[enabled][language-url]' => TRUE,
+      'language_interface[weight][language-browser]' => -8,
+      'language_interface[weight][language-url]' => -10,
+    );
+    $this->drupalPost('admin/config/regional/language/detection', $edit, t('Save settings'));
+    $this->drupalGet('admin/config/regional/language/detection');
+
+    // Enable the language switcher block.
+    $edit = array('blocks[language_language_interface][region]' => 'sidebar_first');
+    $this->drupalPost('admin/structure/block', $edit, t('Save blocks'));
+
+    // Access the front page without specifying any valid URL language prefix
+    // and having as browser language preference a non-default language.
+    $http_header = array("Accept-Language: $langcode_browser_fallback;q=1");
+    $language = (object) array('langcode' => '');
+    $this->drupalGet('', array('language' => $language), $http_header);
+
+    // Check that the language switcher active link matches the given browser
+    // language.
+    $args = array(':url' => base_path() . $GLOBALS['script_path'] . $langcode_browser_fallback);
+    $fields = $this->xpath('//div[@id="block-language-language-interface"]//a[@class="language-link active" and starts-with(@href, :url)]', $args);
+    $this->assertTrue($fields[0] == $languages[$langcode_browser_fallback]->name, t('The browser language is the URL active language'));
+
+    // Check that URLs are rewritten using the given browser language.
+    $fields = $this->xpath('//p[@id="site-name"]/strong/a[@rel="home" and @href=:url]', $args);
+    $this->assertTrue($fields[0] == 'Drupal', t('URLs are rewritten using the browser language.'));
+  }
+
+  /**
+   * Tests url() when separate domains are used for multiple languages.
+   */
+  function testLanguageDomain() {
+    // Add the Italian language.
+    $langcode = 'it';
+    $language = (object) array(
+      'langcode' => $langcode,
+    );
+    language_save($language);
+    $languages = language_list();
+
+    // Enable browser and URL language detection.
+    $edit = array(
+      'language_interface[enabled][language-url]' => TRUE,
+      'language_interface[weight][language-url]' => -10,
+    );
+    $this->drupalPost('admin/config/regional/language/detection', $edit, t('Save settings'));
+
+    // Change the domain for the Italian language.
+    $edit = array(
+      'language_negotiation_url_part' => 1,
+      'domain[it]' => 'it.example.com',
+    );
+    $this->drupalPost('admin/config/regional/language/detection/url', $edit, t('Save configuration'));
+
+    // Build the link we're going to test.
+    $link = 'it.example.com/admin';
+
+    global $is_https;
+    // Test URL in another language: http://it.example.com/admin.
+    // Base path gives problems on the testbot, so $correct_link is hard-coded.
+    // @see UrlAlterFunctionalTest::assertUrlOutboundAlter (path.test).
+    $italian_url = url('admin', array('language' => $languages['it'], 'script' => ''));
+    $url_scheme = ($is_https) ? 'https://' : 'http://';
+    $correct_link = $url_scheme . $link;
+    $this->assertTrue($italian_url == $correct_link, t('The url() function returns the right url (@url) in accordance with the chosen language', array('@url' => $italian_url)));
+
+    // Test https via options.
+    variable_set('https', TRUE);
+    $italian_url = url('admin', array('https' => TRUE, 'language' => $languages['it'], 'script' => ''));
+    $correct_link = 'https://' . $link;
+    $this->assertTrue($italian_url == $correct_link, t('The url() function returns the right https url (via options) (@url) in accordance with the chosen language', array('@url' => $italian_url)));
+    variable_set('https', FALSE);
+
+    // Test https via current url scheme.
+    $temp_https = $is_https;
+    $is_https = TRUE;
+    $italian_url = url('admin', array('language' => $languages['it'], 'script' => ''));
+    $correct_link = 'https://' . $link;
+    $this->assertTrue($italian_url == $correct_link, t('The url() function returns the right url (via current url scheme) (@url) in accordance with the chosen language', array('@url' => $italian_url)));
+    $is_https = $temp_https;
+  }
+}
diff --git a/core/modules/language/lib/Drupal/language/Tests/LanguageUrlRewritingTest.php b/core/modules/language/lib/Drupal/language/Tests/LanguageUrlRewritingTest.php
new file mode 100644
index 0000000..137bba9
--- /dev/null
+++ b/core/modules/language/lib/Drupal/language/Tests/LanguageUrlRewritingTest.php
@@ -0,0 +1,82 @@
+<?php
+
+/**
+ * @file
+ * Definition of Drupal\language\Tests\LanguageUrlRewritingTest.
+ */
+
+namespace Drupal\language\Tests;
+
+use Drupal\simpletest\WebTestBase;
+
+/**
+ * Test that URL rewriting works as expected.
+ */
+class LanguageUrlRewritingTest extends WebTestBase {
+  public static function getInfo() {
+    return array(
+      'name' => 'URL rewriting',
+      'description' => 'Test that URL rewriting works as expected.',
+      'group' => 'Language',
+    );
+  }
+
+  function setUp() {
+    parent::setUp('language');
+
+    // Create and login user.
+    $this->web_user = $this->drupalCreateUser(array('administer languages', 'access administration pages'));
+    $this->drupalLogin($this->web_user);
+
+    // Install French language.
+    $edit = array();
+    $edit['predefined_langcode'] = 'fr';
+    $this->drupalPost('admin/config/regional/language/add', $edit, t('Add language'));
+
+    // Enable URL language detection and selection.
+    $edit = array('language_interface[enabled][language-url]' => 1);
+    $this->drupalPost('admin/config/regional/language/detection', $edit, t('Save settings'));
+
+    // Reset static caching.
+    drupal_static_reset('language_list');
+    drupal_static_reset('language_url_outbound_alter');
+    drupal_static_reset('language_url_rewrite_url');
+  }
+
+  /**
+   * Check that non-installed languages are not considered.
+   */
+  function testUrlRewritingEdgeCases() {
+    // Check URL rewriting with a non-installed language.
+    $non_existing = language_default();
+    $non_existing->langcode = $this->randomName();
+    $this->checkUrl($non_existing, t('Path language is ignored if language is not installed.'), t('URL language negotiation does not work with non-installed languages'));
+  }
+
+  /**
+   * Check URL rewriting for the given language.
+   *
+   * The test is performed with a fixed URL (the default front page) to simply
+   * check that language prefixes are not added to it and that the prefixed URL
+   * is actually not working.
+   */
+  private function checkUrl($language, $message1, $message2) {
+    $options = array('language' => $language, 'script' => '');
+    $base_path = trim(base_path(), '/');
+    $rewritten_path = trim(str_replace($base_path, '', url('node', $options)), '/');
+    $segments = explode('/', $rewritten_path, 2);
+    $prefix = $segments[0];
+    $path = isset($segments[1]) ? $segments[1] : $prefix;
+
+    // If the rewritten URL has not a language prefix we pick a random prefix so
+    // we can always check the prefixed URL.
+    $prefixes = language_negotiation_url_prefixes();
+    $stored_prefix = isset($prefixes[$language->langcode]) ? $prefixes[$language->langcode] : $this->randomName();
+    if ($this->assertNotEqual($stored_prefix, $prefix, $message1)) {
+      $prefix = $stored_prefix;
+    }
+
+    $this->drupalGet("$prefix/$path");
+    $this->assertResponse(404, $message2);
+  }
+}
-- 
1.7.4.msysgit.0

