Index: modules/simpletest/tests/form.test
===================================================================
RCS file: /cvs/drupal/drupal/modules/simpletest/tests/form.test,v
retrieving revision 1.13
diff -u -r1.13 form.test
--- modules/simpletest/tests/form.test	2 Jun 2009 13:47:26 -0000	1.13
+++ modules/simpletest/tests/form.test	17 Jun 2009 20:44:34 -0000
@@ -385,6 +385,36 @@
 }
 
 /**
+ * Test of Form API behavior of disabled fields.
+ */
+class FormDisabledFieldTestCase extends DrupalWebTestCase {
+
+  public static function getInfo() {
+    return array(
+      'name' => t('Disabled field'),
+      'description' => t('Test of Form API behavior of disabled fields.'),
+      'group' => t('Form API'),
+    );
+  }
+
+  public function setUp() {
+    parent::setUp('form_test');
+  }
+
+  /**
+   * Test of Form API behavior of disabled fields.
+   */
+  public function testDisabledField() {
+    $edit = array(
+      'form_test_disabled_field' => $this->randomName(),
+    );
+    $this->drupalPost('form_test/disabled_field', array(), t('Save configuration'), array('additional_post' => $edit));
+    $this->assertText(t('The configuration options have been saved.'));
+    $this->assertFieldByName('form_test_disabled_field', $edit['form_test_disabled_field']);
+  }
+}
+
+/**
  * Test the form storage on a multistep form.
  *
  * The tested form puts data into the storage during the initial form
@@ -430,7 +460,7 @@
     $user = $this->drupalCreateUser(array('access content'));
     $this->drupalLogin($user);
 
-    $this->drupalPost('form_test/form-storage', array('title' => 'new', 'value' => 'value_is_set'), 'Continue', array('query' => 'cache=1'));
+    $this->drupalPost('form_test/form-storage', array('title' => 'new', 'value' => 'value_is_set'), 'Continue', array('url_options' => array('query' => 'cache=1')));
     $this->assertText('Form constructions: 1', t('The form has been constructed one time till now.'));
 
     $this->drupalPost(NULL, array(), 'Save', array('query' => 'cache=1'));
Index: modules/simpletest/tests/form_test.module
===================================================================
RCS file: /cvs/drupal/drupal/modules/simpletest/tests/form_test.module,v
retrieving revision 1.7
diff -u -r1.7 form_test.module
--- modules/simpletest/tests/form_test.module	27 May 2009 18:34:00 -0000	1.7
+++ modules/simpletest/tests/form_test.module	17 Jun 2009 20:44:34 -0000
@@ -66,6 +66,14 @@
     'type' => MENU_CALLBACK,
   );
 
+  $items['form_test/disabled_field'] = array(
+    'title' => 'Disabled field',
+    'page callback' => 'drupal_get_form',
+    'page arguments' => array('form_test_disabled_field_form'),
+    'access arguments' => array('access content'),
+    'type' => MENU_CALLBACK,
+  );
+
   return $items;
 }
 
@@ -233,7 +241,7 @@
  * drupal_form_submit using the values specified in this function.
  *
  * The form's field test_value begins at 'initial_value', and is changed
- * to 'form_submitted' when the form is submitted successfully. On 
+ * to 'form_submitted' when the form is submitted successfully. On
  * completion this function is passed 'done' to complete the process.
  */
 function form_test_drupal_form_submit_batch_api($arg = '') {
@@ -289,6 +297,21 @@
 }
 
 /**
+ * A settings form with a disabled field on it.
+ */
+function form_test_disabled_field_form($form_state) {
+  $form = array();
+
+  $form['form_test_disabled_field'] = array(
+    '#type' => 'textfield',
+    '#default_value' => variable_get('form_test_disabled_field', ''),
+    '#disabled' => TRUE,
+  );
+
+  return system_settings_form($form);
+}
+
+/**
  * A multistep form for testing the form storage.
  *
  * It uses two steps for editing a virtual "thing". Any changes to it are saved
Index: modules/translation/translation.test
===================================================================
RCS file: /cvs/drupal/drupal/modules/translation/translation.test,v
retrieving revision 1.12
diff -u -r1.12 translation.test
--- modules/translation/translation.test	12 Jun 2009 08:39:40 -0000	1.12
+++ modules/translation/translation.test	17 Jun 2009 20:44:34 -0000
@@ -111,10 +111,13 @@
     }
     else {
       // Ensure that it is enabled.
-      $this->assertTrue(true, 'Language [' . $language_code . '] already installed.');
-      $this->drupalPost(NULL, array('enabled[' . $language_code . ']' => TRUE), t('Save configuration'));
-
-      $this->assertRaw(t('Configuration saved.'), t('Language successfully enabled.'));
+      $this->assertTrue(TRUE, 'Language [' . $language_code . '] already installed.');
+      if (!$this->xpath("//input[@id='edit-enabled-" . $language_code . "' and @checked='checked']")) {
+        $this->drupalPost(NULL, array('enabled[' . $language_code . ']' => TRUE), t('Save configuration'));
+        $this->assertRaw(t('Configuration saved.'), t('Language [' . $language_code . '] successfully enabled.'));
+      } else {
+        $this->assertTrue(TRUE, t('Language [' . $language_code . '] already enabled.'));
+      }
     }
   }
 
Index: modules/simpletest/drupal_web_test_case.php
===================================================================
RCS file: /cvs/drupal/drupal/modules/simpletest/drupal_web_test_case.php,v
retrieving revision 1.117
diff -u -r1.117 drupal_web_test_case.php
--- modules/simpletest/drupal_web_test_case.php	16 Jun 2009 04:43:47 -0000	1.117
+++ modules/simpletest/drupal_web_test_case.php	17 Jun 2009 20:44:34 -0000
@@ -1313,13 +1313,15 @@
    *   NULL to post to the current page. For multi-stage forms you can set the
    *   path to NULL and have it post to the last received page. Example:
    *
-   *   // First step in form.
-   *   $edit = array(...);
-   *   $this->drupalPost('some_url', $edit, t('Save'));
-   *
-   *   // Second step in form.
-   *   $edit = array(...);
-   *   $this->drupalPost(NULL, $edit, t('Save'));
+   *   @code
+   *     // First step in form.
+   *     $edit = array(...);
+   *     $this->drupalPost('some_url', $edit, t('Save'));
+   *
+   *     // Second step in form.
+   *     $edit = array(...);
+   *     $this->drupalPost(NULL, $edit, t('Save'));
+   *   @endcode
    * @param  $edit
    *   Field data in an associative array. Changes the current input fields
    *   (where possible) to the values indicated. A checkbox can be set to
@@ -1329,20 +1331,37 @@
    *
    *   Multiple select fields can be set using name[] and setting each of the
    *   possible values. Example:
-   *   $edit = array();
-   *   $edit['name[]'] = array('value1', 'value2');
+   *   @code
+   *     $edit = array();
+   *     $edit['name[]'] = array('value1', 'value2');
+   *   @endcode
    * @param $submit
    *   Value of the submit button.
    * @param $options
-   *   Options to be forwarded to url().
-   * @param $headers
-   *   An array containing additional HTTP request headers, each formatted as
-   *   "name: value".
-   */
-  protected function drupalPost($path, $edit, $submit, array $options = array(), array $headers = array()) {
+   *   Array with additional options. The following keys can be used:
+   *   - "url_options": Options to be passed to url() as $options parameter.
+   *   - "headers": Array with HTTP headers, each formatted as "name: value".
+   *   - "additional_post": An associative array of additional POST data to be
+   *     submitted in addition to any values in $edit. The values will not be
+   *     checked against the current form as values in $edit are and thus it
+   *     can be used to submit values for disabled fields or non-existant
+   *     fields. An example for how to send values for disabled fields follows:
+   *
+   *   @code
+   *     $options = array('additional_post' => array('disabled_field' => value));
+   *   @endcode
+   */
+  protected function drupalPost($path, $edit, $submit, array $options = array()) {
+
+    $options += array(
+      'url_options' => array(),
+      'headers' => array(),
+      'additional_post' => array(),
+    );
+
     $submit_matches = FALSE;
     if (isset($path)) {
-      $html = $this->drupalGet($path, $options);
+      $html = $this->drupalGet($path, $options['url_options']);
     }
     if ($this->parse()) {
       $edit_save = $edit;
@@ -1359,6 +1378,7 @@
         // We post only if we managed to handle every field in edit and the
         // submit button matches.
         if (!$edit && $submit_matches) {
+          $post += $options['additional_post'];
           if ($upload) {
             // TODO: cURL handles file uploads for us, but the implementation
             // is broken. This is a less than elegant workaround. Alternatives
@@ -1379,7 +1399,7 @@
             }
             $post = implode('&', $post);
           }
-          $out = $this->curlExec(array(CURLOPT_URL => $action, CURLOPT_POST => TRUE, CURLOPT_POSTFIELDS => $post, CURLOPT_HTTPHEADER => $headers));
+          $out = $this->curlExec(array(CURLOPT_URL => $action, CURLOPT_POST => TRUE, CURLOPT_POSTFIELDS => $post, CURLOPT_HTTPHEADER => $options['headers']));
           // Ensure that any changes to variables in the other thread are picked up.
           $this->refreshVariables();
 
@@ -1464,6 +1484,18 @@
     foreach ($elements as $element) {
       // SimpleXML objects need string casting all the time.
       $name = (string) $element['name'];
+
+      // Generate a failure when disabled elements are set, as those cannot be 'successful' (ie. be part
+      // of form submissions), according to:
+      // http://www.w3.org/TR/REC-html40/interact/forms.html#h-17.12
+      if (!empty($element['disabled'])) {
+        if (isset($edit[$name])) {
+          $this->fail(t('Field @name is disabled, sending of disabled fields is not allowed.', array('@name' => $name)));
+        }
+        unset($edit[$name]);
+        continue;
+      }
+
       // This can either be the type of <input> or the name of the tag itself
       // for <select> or <textarea>.
       $type = isset($element['type']) ? (string)$element['type'] : $element->getName();
@@ -1484,7 +1516,7 @@
             }
             break;
           case 'checkbox':
-            // To prevent checkbox from being checked.pass in a FALSE,
+            // To prevent checkbox from being checked, pass in a FALSE,
             // otherwise the checkbox will be set to its value regardless
             // of $edit.
             if ($edit[$name] === FALSE) {
