Index: includes/form.inc
===================================================================
RCS file: /cvs/drupal/drupal/includes/form.inc,v
retrieving revision 1.356
diff -u -p -r1.356 form.inc
--- includes/form.inc	12 Aug 2009 11:45:14 -0000	1.356
+++ includes/form.inc	13 Aug 2009 11:53:28 -0000
@@ -1122,6 +1122,12 @@ function _form_builder_handle_input_elem
         $element['#value'] = isset($element['#default_value']) ? $element['#default_value'] : '';
       }
     }
+    elseif (!empty($element['#disabled']) && $element['#value'] != $element['#default_value']) {
+      // Issue a validation error, when an element is disabled and its #value is
+      // different than its #default_value.
+      form_set_error($element['#name'], t('Disabled elements can not be changed.'));
+      $element['#value'] = $element['#default_value'];
+    }
   }
 
   // Determine which button (if any) was clicked to submit the form.
@@ -1273,12 +1279,7 @@ function form_type_image_button_value($f
  */
 function form_type_checkbox_value($element, $input = FALSE) {
   if ($input !== FALSE) {
-    if (empty($element['#disabled'])) {
-      return !empty($input) ? $element['#return_value'] : 0;
-    }
-    else {
-      return $element['#default_value'];
-    }
+    return !empty($input) ? $element['#return_value'] : 0;
   }
 }
 
Index: modules/simpletest/tests/form.test
===================================================================
RCS file: /cvs/drupal/drupal/modules/simpletest/tests/form.test,v
retrieving revision 1.14
diff -u -p -r1.14 form.test
--- modules/simpletest/tests/form.test	13 Jul 2009 21:51:41 -0000	1.14
+++ modules/simpletest/tests/form.test	13 Aug 2009 11:53:29 -0000
@@ -10,8 +10,8 @@ class FormsTestCase extends DrupalWebTes
 
   public static function getInfo() {
     return array(
-      'name' => 'Required field validation',
-      'description' => 'Carriage returns, tabs, and spaces are not valid content for a required field.',
+      'name' => 'Form element validation',
+      'description' => 'Verify that form elements return expected values or invalidate the form.',
       'group' => 'Form API',
     );
   }
@@ -19,6 +19,9 @@ class FormsTestCase extends DrupalWebTes
   /**
    * Check several empty values for required forms elements.
    *
+   * Carriage returns, tabs, and spaces are not valid content for a required
+   * field.
+   *
    * If the form field is found in form_get_errors() then the test pass.
    */
   function testRequiredFields() {
@@ -55,7 +58,8 @@ class FormsTestCase extends DrupalWebTes
     foreach ($elements as $type => $data) {
       foreach ($data['empty_values'] as $key => $empty) {
         $form_id = $this->randomName();
-        $form = $form_state = array();
+        $form = array();
+        $form_state = form_state_defaults();
         $form['op'] = array('#type' => 'submit', '#value' => t('Submit'));
         $element = $data['element']['#title'];
         $form[$element] = $data['element'];
@@ -72,42 +76,86 @@ class FormsTestCase extends DrupalWebTes
     // Clear the expected form error messages so they don't appear as exceptions.
     drupal_get_messages();
   }
-}
 
-/**
- * Test form type functions for expected behavior.
- */
-class FormsTestTypeCase extends DrupalUnitTestCase {
-  public static function getInfo() {
-    return array(
-      'name' => 'Form type-specific tests',
-      'description' => 'Test form type functions for expected behavior.',
-      'group' => 'Form API',
+  /**
+   * Check submitted values for disabled form elements.
+   */
+  function testDisabledFields() {
+    // Verify #disabled textareas cannot be manipulated and throw a form
+    // validation error.
+    $properties = array(
+      // Non-empty textarea.
+      array('#default_value' => $this->randomString()),
+      // Required, non-empty textarea.
+      array('#default_value' => $this->randomString(), '#required' => TRUE),
+      // Required, empty textarea.
+      array('#default_value' => '', '#required' => TRUE),
+    );
+    foreach ($properties as $extras) {
+      $form = $edit = array();
+      $form['textarea'] = array(
+        '#type' => 'textarea',
+        '#default_value' => $this->randomString(),
+        '#disabled' => TRUE,
+      ) + $extras;
+      $edit['textarea'] = $this->randomString();
+      list($processed_form, $form_state, $errors) = $this->_submitForm($form, $edit);
+      $this->assertEqual($form['textarea']['#default_value'], $form_state['values']['textarea']);
+      $this->assertTrue(isset($errors['textarea']), 'Form validation failed for manipulated, disabled form element.');
+    }
+
+    // Verify #disabled checkbox form elements.
+    $form = $edit = array();
+    $form['checkbox'] = array(
+      '#type' => 'checkbox',
+      '#default_value' => FALSE,
+      '#disabled' => TRUE,
+    );
+    $edit['checkbox'] = TRUE;
+    list($processed_form, $form_state, $errors) = $this->_submitForm($form, $edit);
+    $this->assertEqual($form['checkbox']['#default_value'], $form_state['values']['checkbox']);
+    $this->assertTrue(isset($errors['checkbox']), 'Form validation failed for manipulated, disabled form element.');
+
+    // Verify #disabled and #required textareas do not throw a validation error.
+    $form = $edit = array();
+    $form['textarea'] = array(
+      '#type' => 'textarea',
+      '#default_value' => $this->randomString(),
+      '#disabled' => TRUE,
+      '#required' => TRUE,
     );
+    list($processed_form, $form_state, $errors) = $this->_submitForm($form, $edit);
+    $this->assertEqual($form['textarea']['#default_value'], $form_state['values']['textarea']);
+    $this->assertFalse(isset($errors['textarea']), 'Form validation passed for required, but disabled form element.');
   }
 
   /**
-   * Test form_type_checkbox_value() function for expected behavior.
+   * Helper function to submit a form internally and collect errors.
+   *
+   * @param $form
+   *   A form element array to test.
+   * @param $edit
+   *   An array containing post data.
+   *
+   * @return
+   *   An array containing the processed form, the form_state, and any errors.
    */
-  function testFormCheckboxValue() {
-    $form['#return_value'] = $return_value = $this->randomName();
-    $form['#default_value'] = $default_value = $this->randomName();
-    // Element is disabled , and $edit is not empty.
-    $form['#disabled'] = TRUE;
-    $edit = array(1);
-    $this->assertEqual(form_type_checkbox_value($form, $edit), $default_value, t('form_type_checkbox_value() returns the default value when #disabled is set.'));
-
-    // Element is not disabled, $edit is not empty.
-    unset($form['#disabled']);
-    $this->assertEqual(form_type_checkbox_value($form, $edit), $return_value, t('form_type_checkbox_value() returns the return value when #disabled is not set.'));
+  private function _submitForm($form, $edit) {
+    $form_id = $this->randomName();
+    $form_state = form_state_defaults();
+    $form_state['input'] = $edit;
+    $form_state['input']['form_id'] = $form_id;
 
-    // Element is not disabled, $edit is empty.
-    $edit = array();
-    $this->assertIdentical(form_type_checkbox_value($form, $edit), 0, t('form_type_checkbox_value() returns 0 when #disabled is not set, and $edit is empty.'));
+    $form = array_merge(array('op' => array('#type' => 'submit', '#value' => t('Submit'))), $form);
+    drupal_prepare_form($form_id, $form, $form_state);
+    drupal_process_form($form_id, $form, $form_state);
+    $errors = form_get_errors();
+
+    // Clear errors and messages.
+    drupal_get_messages();
+    form_clear_error();
 
-    // $edit is FALSE.
-    $edit = FALSE;
-    $this->assertNull(form_type_checkbox_value($form, $edit), t('form_type_checkbox_value() returns NULL when $edit is FALSE'));
+    return array($form, $form_state, $errors);
   }
 }
 
@@ -358,6 +406,10 @@ class FormAPITestCase extends DrupalWebT
     );
   }
 
+  function setUp() {
+    parent::setUp('form_test');
+  }
+
   /**
    * Check that we can run drupal_form_submit during a batch.
    */
@@ -377,11 +429,6 @@ class FormAPITestCase extends DrupalWebT
     // Clean our variable up.
     variable_del('form_test_mock_submit');
   }
-
-  function setUp() {
-    parent::setUp('form_test');
-  }
-
 }
 
 /**
