diff --git a/core/modules/filter/filter.module b/core/modules/filter/filter.module
index 8eb3373..85fa327 100644
--- a/core/modules/filter/filter.module
+++ b/core/modules/filter/filter.module
@@ -497,8 +497,11 @@ function check_markup($text, $format_id = NULL, $langcode = '', $filter_types_to
  *   The form element to process. Properties used:
  *   - #base_type: The form element #type to use for the 'value' element.
  *     'textarea' by default.
- *   - #format: (optional) The text format ID to preselect. If NULL or not set,
- *     the default format for the current user will be used.
+ *   - #format: (optional) The text format ID to preselect. If omitted, the
+ *     default format for the current user will be used.
+ *   - #allowed_formats: (optional) An array of text format IDs that are
+ *     available for this element. If omitted, all text formats that the current
+ *     user has access to will be allowed.
  *
  * @return
  *   The expanded element.
@@ -537,6 +540,8 @@ function filter_process_format($element) {
 
   $element['value']['#type'] = $element['#base_type'];
   $element['value'] += element_info($element['#base_type']);
+  // Make sure the #default_value key is set, so we can use it below.
+  $element['value'] += array('#default_value' => '');
 
   // Turn original element into a text format wrapper.
   $element['#attached']['library'][] = 'filter/drupal.filter';
@@ -550,15 +555,30 @@ function filter_process_format($element) {
   // Get a list of formats that the current user has access to.
   $formats = filter_formats($user);
 
-  // Use the default format for this user if none was selected.
-  if (!isset($element['#format'])) {
-    $element['#format'] = filter_default_format($user);
+  // Allow the list of formats to be restricted.
+  if (isset($element['#allowed_formats'])) {
+    // We do not add the fallback format here to allow the use-case of forcing
+    // certain text formats to be used for certain text areas. In case the
+    // fallback format is supposed to be allowed as well, it must be added to
+    // $element['#allowed_formats'] explicitly.
+    $formats = array_intersect_key($formats, array_flip($element['#allowed_formats']));
   }
 
-  // If multiple text formats are available, remove the fallback. The
-  // "always_show_fallback_choice" is a hidden variable that has no UI. It
-  // defaults to false.
-  if (!\Drupal::config('filter.settings')->get('always_show_fallback_choice')) {
+  if (!isset($element['#format']) && !empty($formats)) {
+    // If no text format was selected, use the allowed format with the highest
+    // weight. This is equivalent to calling filter_default_format().
+    $element['#format'] = reset($formats)->format;
+  }
+
+  // If #allowed_formats is set, the list of formats must not be modified in any
+  // way. Otherwise, however, if all of the following conditions are true,
+  // remove the fallback format from the list of formats:
+  // 1. The 'always_show_fallback_choice' filter setting has not been activated.
+  // 2. Multiple text formats are available.
+  // 3. The fallback format is not the default format.
+  // The 'always_show_fallback_choice' filter setting is a hidden setting that
+  // has no UI. It defaults to FALSE.
+  if (!isset($element['#allowed_formats']) && !\Drupal::config('filter.settings')->get('always_show_fallback_choice')) {
     $fallback_format = filter_fallback_format();
     if ($element['#format'] !== $fallback_format && count($formats) > 1) {
       unset($formats[$fallback_format]);
@@ -600,12 +620,13 @@ function filter_process_format($element) {
 
   $all_formats = filter_formats();
   $format_exists = isset($all_formats[$element['#format']]);
+  $format_allowed = !isset($element['#allowed_formats']) || in_array($element['#format'], $element['#allowed_formats']);
   $user_has_access = isset($formats[$element['#format']]);
   $user_is_admin = user_access('administer filters');
 
-  // If the stored format does not exist, administrators have to assign a new
-  // format.
-  if (!$format_exists && $user_is_admin) {
+  // If the stored format does not exist or if it is not among the allowed
+  // formats for this textarea, administrators have to assign a new format.
+  if ((!$format_exists || !$format_allowed) && $user_is_admin) {
     $element['format']['format']['#required'] = TRUE;
     $element['format']['format']['#default_value'] = NULL;
     // Force access to the format selector (it may have been denied above if
diff --git a/core/modules/filter/src/Tests/FilterAPITest.php b/core/modules/filter/src/Tests/FilterAPITest.php
index e0c06d5..2c5522a 100644
--- a/core/modules/filter/src/Tests/FilterAPITest.php
+++ b/core/modules/filter/src/Tests/FilterAPITest.php
@@ -24,7 +24,7 @@ class FilterAPITest extends EntityUnitTestBase {
 
   public static function getInfo() {
     return array(
-      'name' => 'API',
+      'name' => 'Filter API',
       'description' => 'Test the behavior of the API of the Filter module.',
       'group' => 'Filter',
     );
@@ -34,36 +34,6 @@ function setUp() {
     parent::setUp();
 
     $this->installConfig(array('system', 'filter'));
-
-    // Create Filtered HTML format.
-    $filtered_html_format = entity_create('filter_format', array(
-      'format' => 'filtered_html',
-      'name' => 'Filtered HTML',
-      'filters' => array(
-        // Note that the filter_html filter is of the type FilterInterface::TYPE_MARKUP_LANGUAGE.
-        'filter_url' => array(
-          'weight' => -1,
-          'status' => 1,
-        ),
-        // Note that the filter_html filter is of the type FilterInterface::TYPE_HTML_RESTRICTOR.
-        'filter_html' => array(
-          'status' => 1,
-          'settings' => array(
-            'allowed_html' => '<p> <br> <strong> <a>',
-          ),
-        ),
-      )
-    ));
-    $filtered_html_format->save();
-
-    // Create Full HTML format.
-    $full_html_format = entity_create('filter_format', array(
-      'format' => 'full_html',
-      'name' => 'Full HTML',
-      'weight' => 1,
-      'filters' => array(),
-    ));
-    $full_html_format->save();
   }
 
   /**
@@ -105,13 +75,17 @@ function testCheckMarkupFilterSubset() {
     $expected_filtered_text = "Text with evil content and a URL: <a href=\"http://drupal.org\">http://drupal.org</a>!";
     $expected_filter_text_without_html_generators = "Text with evil content and a URL: http://drupal.org!";
 
+    $actual_filtered_text = check_markup($text, 'filtered_html', '', array());
+    $this->verbose("Actual:<pre>$actual_filtered_text</pre>Expected:<pre>$expected_filtered_text</pre>");
     $this->assertIdentical(
-      check_markup($text, 'filtered_html', '', array()),
+      $actual_filtered_text,
       $expected_filtered_text,
       'Expected filter result.'
     );
+    $actual_filtered_text_without_html_generators = check_markup($text, 'filtered_html', '', array(FilterInterface::TYPE_MARKUP_LANGUAGE));
+    $this->verbose("Actual:<pre>$actual_filtered_text_without_html_generators</pre>Expected:<pre>$expected_filter_text_without_html_generators</pre>");
     $this->assertIdentical(
-      check_markup($text, 'filtered_html', '', array(FilterInterface::TYPE_MARKUP_LANGUAGE)),
+      $actual_filtered_text_without_html_generators,
       $expected_filter_text_without_html_generators,
       'Expected filter result when skipping FilterInterface::TYPE_MARKUP_LANGUAGE filters.'
     );
@@ -119,8 +93,10 @@ function testCheckMarkupFilterSubset() {
     // this check focuses on the ability to filter multiple filter types at once.
     // Drupal core only ships with these two types of filters, so this is the
     // most extensive test possible.
+    $actual_filtered_text_without_html_generators = check_markup($text, 'filtered_html', '', array(FilterInterface::TYPE_HTML_RESTRICTOR, FilterInterface::TYPE_MARKUP_LANGUAGE));
+    $this->verbose("Actual:<pre>$actual_filtered_text_without_html_generators</pre>Expected:<pre>$expected_filter_text_without_html_generators</pre>");
     $this->assertIdentical(
-      check_markup($text, 'filtered_html', '', array(FilterInterface::TYPE_HTML_RESTRICTOR, FilterInterface::TYPE_MARKUP_LANGUAGE)),
+      $actual_filtered_text_without_html_generators,
       $expected_filter_text_without_html_generators,
       'Expected filter result when skipping FilterInterface::TYPE_MARKUP_LANGUAGE filters, even when trying to disable filters of the FilterInterface::TYPE_HTML_RESTRICTOR type.'
     );
diff --git a/core/modules/filter/src/Tests/FilterFormTest.php b/core/modules/filter/src/Tests/FilterFormTest.php
new file mode 100644
index 0000000..142bee4
--- /dev/null
+++ b/core/modules/filter/src/Tests/FilterFormTest.php
@@ -0,0 +1,302 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\filter\Tests\FilterFormTest.
+ */
+
+namespace Drupal\filter\Tests;
+
+use Drupal\Component\Utility\String;
+use Drupal\simpletest\WebTestBase;
+
+/**
+ * Tests form elements provided by Filter module.
+ */
+class FilterFormTest extends WebTestBase {
+
+  /**
+   * Modules to enable for this test.
+   *
+   * @var array
+   */
+  protected static $modules = array('filter', 'filter_test');
+
+  /**
+   * An administrative user account that can administer text formats.
+   *
+   * @var \Drupal\user\Entity\User
+   */
+  protected $adminUser;
+
+  /**
+   * An basic user account that can only access basic HTML text format.
+   *
+   * @var \Drupal\user\Entity\User
+   */
+  protected $webUser;
+
+  /**
+   * {@inheritdoc}
+   */
+  public static function getInfo() {
+    return array(
+      'name' => 'Text format form element',
+      'description' => 'Tests form elements with associated text formats.',
+      'group' => 'Filter',
+    );
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function setUp() {
+    parent::setUp();
+
+    /** @var \Drupal\filter\FilterFormatInterface $filter_test_format */
+    $filter_test_format = entity_load('filter_format', 'filter_test');
+    /** @var \Drupal\filter\FilterFormatInterface $filtered_html_format */
+    $filtered_html_format = entity_load('filter_format', 'filtered_html');
+    /** @var \Drupal\filter\FilterFormatInterface $full_html_format */
+    $full_html_format = entity_load('filter_format', 'full_html');
+
+    // Create users.
+    $this->adminUser = $this->drupalCreateUser(array(
+      'administer filters',
+      $filtered_html_format->getPermissionName(),
+      $full_html_format->getPermissionName(),
+      $filter_test_format->getPermissionName(),
+    ));
+
+    $this->webUser = $this->drupalCreateUser(array(
+      $filtered_html_format->getPermissionName(),
+      $filter_test_format->getPermissionName(),
+    ));
+  }
+
+  /**
+   * Tests various different configurations of the 'text_format' element.
+   */
+  public function testFilterForm() {
+    $this->doFilterFormTestAsAdmin();
+    $this->doFilterFormTestAsNonAdmin();
+  }
+
+  /**
+   * Tests the behavior of the 'text_format' element as an administrator.
+   */
+  protected function doFilterFormTestAsAdmin() {
+    $this->drupalLogin($this->adminUser);
+    $this->drupalGet('filter-test/text-format');
+
+    // Test a text format element with all formats.
+    $formats = array('filtered_html', 'full_html', 'filter_test');
+    $this->assertEnabledTextarea('edit-all-formats-no-default-value');
+    // If no default is given, the format with the lowest weight becomes the
+    // default.
+    $this->assertOptions('edit-all-formats-no-default-format--2', $formats, 'filtered_html');
+    $this->assertEnabledTextarea('edit-all-formats-default-value');
+    // \Drupal\filter_test\Form\FilterTestFormatForm::buildForm() uses
+    // 'filter_test' as the default value in this case.
+    $this->assertOptions('edit-all-formats-default-format--2', $formats, 'filter_test');
+    $this->assertEnabledTextarea('edit-all-formats-default-missing-value');
+    // If a missing format is set as the default, administrators must select a
+    // valid replacement format.
+    $this->assertRequiredSelectAndOptions('edit-all-formats-default-missing-format--2', $formats);
+
+    // Test a text format element with a predefined list of formats.
+    $formats = array('full_html', 'filter_test');
+    $this->assertEnabledTextarea('edit-restricted-formats-no-default-value');
+    $this->assertOptions('edit-restricted-formats-no-default-format--2', $formats, 'full_html');
+    $this->assertEnabledTextarea('edit-restricted-formats-default-value');
+    $this->assertOptions('edit-restricted-formats-default-format--2', $formats, 'full_html');
+    $this->assertEnabledTextarea('edit-restricted-formats-default-missing-value');
+    $this->assertRequiredSelectAndOptions('edit-restricted-formats-default-missing-format--2', $formats);
+    $this->assertEnabledTextarea('edit-restricted-formats-default-disallowed-value');
+    $this->assertRequiredSelectAndOptions('edit-restricted-formats-default-disallowed-format--2', $formats);
+
+    // Test a text format element with a fixed format.
+    $formats = array('filter_test');
+    // When there is only a single option there is no point in choosing.
+    $this->assertEnabledTextarea('edit-single-format-no-default-value');
+    $this->assertNoSelect('edit-single-format-no-default-format--2');
+    $this->assertEnabledTextarea('edit-single-format-default-value');
+    $this->assertNoSelect('edit-single-format-default-format--2');
+    // If the select has a missing or disallowed format, administrators must
+    // explicitly choose the format.
+    $this->assertEnabledTextarea('edit-single-format-default-missing-value');
+    $this->assertRequiredSelectAndOptions('edit-single-format-default-missing-format--2', $formats);
+    $this->assertEnabledTextarea('edit-single-format-default-disallowed-value');
+    $this->assertRequiredSelectAndOptions('edit-single-format-default-disallowed-format--2', $formats);
+  }
+
+  /**
+   * Tests the behavior of the 'text_format' element as a normal user.
+   */
+  protected function doFilterFormTestAsNonAdmin() {
+    $this->drupalLogin($this->webUser);
+    $this->drupalGet('filter-test/text-format');
+
+    // Test a text format element with all formats. Only formats the user has
+    // access to are shown.
+    $formats = array('filtered_html', 'filter_test');
+    $this->assertEnabledTextarea('edit-all-formats-no-default-value');
+    // If no default is given, the format with the lowest weight becomes the
+    // default. This happens to be 'filtered_html'.
+    $this->assertOptions('edit-all-formats-no-default-format--2', $formats, 'filtered_html');
+    $this->assertEnabledTextarea('edit-all-formats-default-value');
+    // \Drupal\filter_test\Form\FilterTestFormatForm::buildForm() uses
+    // 'filter_test' as the default value in this case.
+    $this->assertOptions('edit-all-formats-default-format--2', $formats, 'filter_test');
+    // If a missing format is given as default, non-admin users are presented
+    // with a disabled textarea.
+    $this->assertDisabledTextarea('edit-all-formats-default-missing-value');
+
+    // Test a text format element with a predefined list of formats.
+    $this->assertEnabledTextarea('edit-restricted-formats-no-default-value');
+    // The user only has access to the 'filter_test' format, so when no default
+    // is given that is preselected and the text format select is hidden.
+    $this->assertNoSelect('edit-restricted-formats-no-default-format--2');
+    // When the format that the user does not have access to is preselected, the
+    // textarea should be disabled.
+    $this->assertDisabledTextarea('edit-restricted-formats-default-value');
+    $this->assertDisabledTextarea('edit-restricted-formats-default-missing-value');
+    $this->assertDisabledTextarea('edit-restricted-formats-default-disallowed-value');
+
+    // Test a text format element with a fixed format.
+    // When there is only a single option there is no point in choosing.
+    $this->assertEnabledTextarea('edit-single-format-no-default-value');
+    $this->assertNoSelect('edit-single-format-no-default-format--2');
+    $this->assertEnabledTextarea('edit-single-format-default-value');
+    $this->assertNoSelect('edit-single-format-default-format--2');
+    // If the select has a missing or disallowed format make sure the textarea
+    // is disabled.
+    $this->assertDisabledTextarea('edit-single-format-default-missing-value');
+    $this->assertDisabledTextarea('edit-single-format-default-disallowed-value');
+  }
+
+  /**
+   * Makes sure that no select element with the given ID exists on the page.
+   *
+   * @param string $id
+   *   The HTML ID of the select element.
+   */
+  protected function assertNoSelect($id) {
+    $select = $this->xpath('//select[@id=:id]', array(':id' => $id));
+    $this->assertFalse($select, String::format('Field @id does not exist.', array(
+      '@id' => $id,
+    )));
+    return $select;
+  }
+
+  /**
+   * Asserts that a select element has the correct options.
+   *
+   * @param string $id
+   *   The HTML ID of the select element.
+   * @param array $expected_options
+   *   An array of option values.
+   * @param string $selected
+   *   The value of the selected option.
+   */
+  protected function assertOptions($id, array $expected_options, $selected) {
+    $select = $this->xpath('//select[@id=:id]', array(':id' => $id));
+    $select = reset($select);
+    $this->assertTrue($select instanceof \SimpleXMLElement, String::format('Field @id exists.', array(
+      '@id' => $id,
+    )));
+
+    $found_options = $this->getAllOptions($select);
+    foreach ($found_options as $found_key => $found_option) {
+      $expected_key = array_search($found_option->attributes()->value, $expected_options);
+      if ($expected_key !== FALSE) {
+        $this->pass(String::format('Option @option for field @id exists.', array(
+          '@option' => $expected_options[$expected_key],
+          '@id' => $id,
+        )));
+        unset($found_options[$found_key]);
+        unset($expected_options[$expected_key]);
+      }
+    }
+
+    // Make sure that all expected options were found and that there are no
+    // unexpected options.
+    foreach ($expected_options as $expected_option) {
+      $this->fail(String::format('Option @option for field @id exists.', array(
+        '@option' => $expected_option,
+        '@id' => $id,
+      )));
+    }
+    foreach ($found_options as $found_option) {
+      $this->fail(String::format('Option @option for field @id does not exist.', array(
+        '@option' => $found_option->attributes()->value,
+        '@id' => $id,
+      )));
+    }
+
+    $this->assertOptionSelected($id, $selected);
+  }
+
+  /**
+   * Asserts that there is a select element with the given ID that is required.
+   *
+   * @param string $id
+   *   The HTML ID of the select element.
+   * @param array $options
+   *   An array of option values that are contained in the select element
+   *   besides the "- Select -" option.
+   */
+  protected function assertRequiredSelectAndOptions($id, array $options) {
+    $select = $this->xpath('//select[@id=:id and contains(@required, "required")]', array(
+      ':id' => $id,
+    ));
+    $select = reset($select);
+    $this->assertTrue($select instanceof \SimpleXMLElement, String::format('Required field @id exists.', array(
+      '@id' => $id,
+    )));
+    // A required select element has a "- Select -" option whose key is an empty
+    // string.
+    $options[] = '';
+    $this->assertOptions($id, $options, '');
+  }
+
+  /**
+   * Asserts that a textarea with a given ID exists and is not disabled.
+   *
+   * @param string $id
+   *   The HTML ID of the textarea.
+   */
+  protected function assertEnabledTextarea($id) {
+    $textarea = $this->xpath('//textarea[@id=:id and not(contains(@disabled, "disabled"))]', array(
+      ':id' => $id,
+    ));
+    $textarea = reset($textarea);
+    $this->assertTrue($textarea instanceof \SimpleXMLElement, String::format('Enabled field @id exists.', array(
+      '@id' => $id,
+    )));
+  }
+
+  /**
+   * Asserts that a textarea with a given ID has been disabled from editing.
+   *
+   * @param string $id
+   *   The HTML ID of the textarea.
+   */
+  protected function assertDisabledTextarea($id) {
+    $textarea = $this->xpath('//textarea[@id=:id and contains(@disabled, "disabled")]', array(
+      ':id' => $id,
+    ));
+    $textarea = reset($textarea);
+    $this->assertTrue($textarea instanceof \SimpleXMLElement, String::format('Disabled field @id exists.', array(
+      '@id' => $id,
+    )));
+    $expected = 'This field has been disabled because you do not have sufficient permissions to edit it.';
+    $this->assertEqual((string) $textarea, $expected, String::format('Disabled textarea @id hides text in an inaccessible text format.', array(
+      '@id' => $id,
+    )));
+    // Make sure the text format select is not shown.
+    $select_id = str_replace('value', 'format--2', $id);
+    $this->assertNoSelect($select_id);
+  }
+
+}
diff --git a/core/modules/filter/src/Tests/FilterSecurityTest.php b/core/modules/filter/src/Tests/FilterSecurityTest.php
index 6aea5de..82971f4 100644
--- a/core/modules/filter/src/Tests/FilterSecurityTest.php
+++ b/core/modules/filter/src/Tests/FilterSecurityTest.php
@@ -32,7 +32,7 @@ class FilterSecurityTest extends WebTestBase {
 
   public static function getInfo() {
     return array(
-      'name' => 'Security',
+      'name' => 'Filter security',
       'description' => 'Test the behavior of check_markup() when a filter or text format vanishes, or when check_markup() is called in such a way that it is instructed to skip all filters of the "FilterInterface::TYPE_HTML_RESTRICTOR" type.',
       'group' => 'Filter',
     );
@@ -44,19 +44,8 @@ function setUp() {
     // Create Basic page node type.
     $this->drupalCreateContentType(array('type' => 'page', 'name' => 'Basic page'));
 
-    // Create Filtered HTML format.
-    $filtered_html_format = entity_create('filter_format', array(
-      'format' => 'filtered_html',
-      'name' => 'Filtered HTML',
-      'filters' => array(
-        // Note that the filter_html filter is of the type FilterInterface::TYPE_HTML_RESTRICTOR.
-        'filter_html' => array(
-          'status' => 1,
-        ),
-      )
-    ));
-    $filtered_html_format->save();
-
+    /** @var \Drupal\filter\Entity\FilterFormat $filtered_html_format */
+    $filtered_html_format = entity_load('filter_format', 'filtered_html');
     $filtered_html_permission = $filtered_html_format->getPermissionName();
     user_role_grant_permissions(DRUPAL_ANONYMOUS_RID, array($filtered_html_permission));
 
@@ -101,8 +90,8 @@ function testDisableFilterModule() {
    * Tests that security filters are enforced even when marked to be skipped.
    */
   function testSkipSecurityFilters() {
-    $text = "Text with some disallowed tags: <script />, <em><object>unicorn</object></em>, <i><table></i>.";
-    $expected_filtered_text = "Text with some disallowed tags: , <em>unicorn</em>, .";
+    $text = "Text with some disallowed tags: <script />, <p><object>unicorn</object></p>, <i><table></i>.";
+    $expected_filtered_text = "Text with some disallowed tags: , <p>unicorn</p>, .";
     $this->assertEqual(check_markup($text, 'filtered_html', '', array()), $expected_filtered_text, 'Expected filter result.');
     $this->assertEqual(check_markup($text, 'filtered_html', '', array(FilterInterface::TYPE_HTML_RESTRICTOR)), $expected_filtered_text, 'Expected filter result, even when trying to disable filters of the FilterInterface::TYPE_HTML_RESTRICTOR type.');
   }
diff --git a/core/modules/filter/tests/filter_test/config/install/filter.format.filtered_html.yml b/core/modules/filter/tests/filter_test/config/install/filter.format.filtered_html.yml
new file mode 100644
index 0000000..a1a38d7
--- /dev/null
+++ b/core/modules/filter/tests/filter_test/config/install/filter.format.filtered_html.yml
@@ -0,0 +1,15 @@
+format: filtered_html
+name: 'Filtered HTML'
+weight: 1
+filters:
+  filter_url:
+    id: filter_url
+    provider: filter
+    weight: -1
+    status: true
+  filter_html:
+    id: filter_html
+    provider: filter
+    status: true
+    settings:
+      allowed_html: '<p> <br> <strong> <a>'
diff --git a/core/modules/filter/tests/filter_test/config/install/filter.format.full_html.yml b/core/modules/filter/tests/filter_test/config/install/filter.format.full_html.yml
new file mode 100644
index 0000000..abb5662
--- /dev/null
+++ b/core/modules/filter/tests/filter_test/config/install/filter.format.full_html.yml
@@ -0,0 +1,3 @@
+format: full_html
+name: 'Full HTML'
+weight: 2
diff --git a/core/modules/filter/tests/filter_test/filter_test.routing.yml b/core/modules/filter/tests/filter_test/filter_test.routing.yml
new file mode 100644
index 0000000..14bb7ab
--- /dev/null
+++ b/core/modules/filter/tests/filter_test/filter_test.routing.yml
@@ -0,0 +1,8 @@
+
+filter_text.text_format:
+  path: '/filter-test/text-format'
+  defaults:
+    _title: 'Text format test forms'
+    _form: 'Drupal\filter_test\Form\FilterTestFormatForm'
+  requirements:
+    _access: 'TRUE'
diff --git a/core/modules/filter/tests/filter_test/src/Form/FilterTestFormatForm.php b/core/modules/filter/tests/filter_test/src/Form/FilterTestFormatForm.php
new file mode 100644
index 0000000..be8cd12
--- /dev/null
+++ b/core/modules/filter/tests/filter_test/src/Form/FilterTestFormatForm.php
@@ -0,0 +1,115 @@
+<?php
+/**
+ * @file
+ * Contains \Drupal\filter_test\Form\FilterTestFormatForm.
+ */
+
+namespace Drupal\filter_test\Form;
+
+use Drupal\Core\Form\FormBase;
+
+/**
+ * Shows a test form for testing the 'text_format' form element.
+ */
+class FilterTestFormatForm extends FormBase {
+
+  /**
+   * {@inheritdoc}
+   */
+  public function getFormId() {
+    return 'filter_test_format_form';
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function buildForm(array $form, array &$form_state) {
+    // This ensures that the parent array key makes it into the HTML ID of the
+    // form elements.
+    $form['#tree'] = TRUE;
+
+    $form['all_formats'] = array(
+      '#type' => 'details',
+      '#title' => 'All text formats',
+    );
+    $form['all_formats']['no_default'] = array(
+      '#type' => 'text_format',
+      '#title' => 'No default value',
+    );
+    $form['all_formats']['default'] = array(
+      '#type' => 'text_format',
+      '#title' => 'Default value',
+      '#format' => 'filter_test',
+    );
+    $form['all_formats']['default_missing'] = array(
+      '#type' => 'text_format',
+      '#title' => 'Missing default value',
+      '#format' => 'missing_format',
+    );
+
+    $form['restricted_formats'] = array(
+      '#type' => 'details',
+      '#title' => 'Restricted text format list',
+    );
+    $form['restricted_formats']['no_default'] = array(
+      '#type' => 'text_format',
+      '#title' => 'No default value',
+      '#allowed_formats' => array('full_html', 'filter_test'),
+    );
+    $form['restricted_formats']['default'] = array(
+      '#type' => 'text_format',
+      '#title' => 'Default value',
+      '#format' => 'full_html',
+      '#allowed_formats' => array('full_html', 'filter_test'),
+    );
+    $form['restricted_formats']['default_missing'] = array(
+      '#type' => 'text_format',
+      '#title' => 'Missing default value',
+      '#format' => 'missing_format',
+      '#allowed_formats' => array('full_html', 'filter_test'),
+    );
+    $form['restricted_formats']['default_disallowed'] = array(
+      '#type' => 'text_format',
+      '#title' => 'Disallowed default value',
+      '#format' => 'filtered_html',
+      '#allowed_formats' => array('full_html', 'filter_test'),
+    );
+
+    $form['single_format'] = array(
+      '#type' => 'details',
+      '#title' => 'Single text format',
+    );
+    $form['single_format']['no_default'] = array(
+      '#type' => 'text_format',
+      '#title' => 'No default value',
+      '#allowed_formats' => array('filter_test'),
+    );
+    $form['single_format']['default'] = array(
+      '#type' => 'text_format',
+      '#title' => 'Default value',
+      '#format' => 'filter_test',
+      '#allowed_formats' => array('filter_test'),
+    );
+    $form['single_format']['default_missing'] = array(
+      '#type' => 'text_format',
+      '#title' => 'Missing default value',
+      '#format' => 'missing_format',
+      '#allowed_formats' => array('filter_test'),
+    );
+    $form['single_format']['default_disallowed'] = array(
+      '#type' => 'text_format',
+      '#title' => 'Disallowed default value',
+      '#format' => 'full_html',
+      '#allowed_formats' => array('filter_test'),
+    );
+
+    return $form;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function submitForm(array &$form, array &$form_state) {
+  }
+
+}
