diff --git a/includes/form.inc b/includes/form.inc
index 47d8c9908b97c6998deaacd512e01c6c8bd5ad6b..4ae2bb40bde3bbf7b26246a5b6052118da67d764 100644
--- a/includes/form.inc
+++ b/includes/form.inc
@@ -231,12 +231,12 @@ function drupal_build_form($form_id, &$form_state) {
   // the form will simply be re-rendered with the values still in its
   // fields.
   //
-  // If $form_state['rebuild'] has been set and the form has been submitted, we
+  // If $form_state['rebuild'] has been set and input has been processed, we
   // know that we're in a multi-part process of some sort and the form's
   // workflow is not complete. We need to construct a fresh copy of the form,
   // passing in the latest $form_state in addition to any other variables passed
   // into drupal_get_form().
-  if ($form_state['rebuild'] && $form_state['submitted'] && !form_get_errors()) {
+  if ($form_state['rebuild'] && $form_state['process_input'] && !form_get_errors()) {
     $form = drupal_rebuild_form($form_id, $form_state);
   }
   // After processing the form, the form builder or a #process callback may
diff --git a/modules/simpletest/tests/form.test b/modules/simpletest/tests/form.test
index f1c40b2293727930276f70366e7bdd9602f3c195..ba6a5d622c7b3efff2af7e73fc9885f42cc805d2 100644
--- a/modules/simpletest/tests/form.test
+++ b/modules/simpletest/tests/form.test
@@ -559,11 +559,28 @@ class FormsFormStorageTestCase extends DrupalWebTestCase {
    * Tests using the form in a usual way.
    */
   function testForm() {
-    $this->drupalPost('form_test/form-storage', array('title' => 'new', 'value' => 'value_is_set'), 'Continue');
-    $this->assertText('Form constructions: 2', t('The form has been constructed two times till now.'));
+    $this->drupalGet('form_test/form-storage');
+    $this->assertText('Form constructions: 1');
+
+    $edit = array('title' => 'new', 'value' => 'value_is_set');
+    // Reload the form, but don't rebuild.
+    $this->drupalPost(NULL, $edit, 'Reload');
+    $this->assertText('Form constructions: 2');
+
+    // Now use form rebuilding triggered by a submit button.
+    $this->drupalPost(NULL, $edit, 'Continue submit');
+    $this->assertText('Form constructions: 3');
+    $this->assertText('Form constructions: 4');
+
+    // Reset the form to the values of the storage, using a form rebuild
+    // triggered by button of type button.
+    $this->drupalPost(NULL, array('title' => 'changed'), 'Reset');
+    $this->assertFieldByName('title', 'new', 'Values have been resetted.');
+    // After rebuilding, the form has been cached.
+    $this->assertText('Form constructions: 5');
 
-    $this->drupalPost(NULL, array(), 'Save');
-    $this->assertText('Form constructions: 3', t('The form has been constructed three times till now.'));
+    $this->drupalPost(NULL, $edit, 'Save');
+    $this->assertText('Form constructions: 5');
     $this->assertText('Title: new', t('The form storage has stored the values.'));
   }
 
@@ -571,11 +588,26 @@ class FormsFormStorageTestCase extends DrupalWebTestCase {
    * Tests using the form with an activated $form_state['cache'] property.
    */
   function testFormCached() {
-    $this->drupalPost('form_test/form-storage', array('title' => 'new', 'value' => 'value_is_set'), 'Continue', array('query' => array('cache' => 1)));
-    $this->assertText('Form constructions: 1', t('The form has been constructed one time till now.'));
+    $this->drupalGet('form_test/form-storage', array('query' => array('cache' => 1)));
+    $this->assertText('Form constructions: 1');
+
+    $edit = array('title' => 'new', 'value' => 'value_is_set');
+    // Reload the form, but don't rebuild.
+    $this->drupalPost(NULL, $edit, 'Reload');
+    $this->assertNoText('Form constructions');
 
-    $this->drupalPost(NULL, array(), 'Save', array('query' => array('cache' => 1)));
-    $this->assertText('Form constructions: 2', t('The form has been constructed two times till now.'));
+    // Now use form rebuilding triggered by a submit button.
+    $this->drupalPost(NULL, $edit, 'Continue submit');
+    $this->assertText('Form constructions: 2');
+
+    // Reset the form to the values of the storage, using a form rebuild
+    // triggered by button of type button.
+    $this->drupalPost(NULL, array('title' => 'changed'), 'Reset');
+    $this->assertFieldByName('title', 'new', 'Values have been resetted.');
+    $this->assertText('Form constructions: 3');
+
+    $this->drupalPost(NULL, $edit, 'Save');
+    $this->assertText('Form constructions: 3');
     $this->assertText('Title: new', t('The form storage has stored the values.'));
   }
 
@@ -583,8 +615,8 @@ class FormsFormStorageTestCase extends DrupalWebTestCase {
    * Tests validation when form storage is used.
    */
   function testValidation() {
-    $this->drupalPost('form_test/form-storage', array('title' => '', 'value' => 'value_is_set'), 'Continue');
-    $this->assertPattern('/value_is_set/', t("The input values have been kept."));
+    $this->drupalPost('form_test/form-storage', array('title' => '', 'value' => 'value_is_set'), 'Continue submit');
+    $this->assertPattern('/value_is_set/', t('The input values have been kept.'));
   }
 
   /**
@@ -605,7 +637,7 @@ class FormsFormStorageTestCase extends DrupalWebTestCase {
     // 'title' into form storage, but we want to verify that changes in the form
     // storage are updated in the cache during form validation.
     $edit = array('title' => 'foo');
-    $this->drupalPost(NULL, $edit, 'Continue');
+    $this->drupalPost(NULL, $edit, 'Continue submit');
 
     // In step 2, trigger a validation error for the required 'title' field, and
     // post the special 'change_title' value for the 'value' field, which
@@ -616,13 +648,10 @@ class FormsFormStorageTestCase extends DrupalWebTestCase {
 
     // At this point, the form storage should contain updated values, but we do
     // not see them, because the form has not been rebuilt yet due to the
-    // validation error. Post again with an arbitrary 'title' (which is only
-    // updated in form storage in step 1) and verify that the rebuilt form
-    // contains the values of the updated form storage.
-    $edit = array('title' => 'foo', 'value' => '');
-    $this->drupalPost(NULL, $edit, 'Save');
-    $this->assertFieldByName('title', 'title_changed', t('The altered form storage value was updated in cache and taken over.'));
-    $this->assertText('Title: title_changed', t('The form storage has stored the values.'));
+    // validation error. Post again and verify that the rebuilt form contains
+    // the values of the updated form storage.
+    $this->drupalPost(NULL, array('title' => 'foo', 'value' => 'bar'), 'Save');
+    $this->assertText("The thing has been changed.", 'The altered form storage value was updated in cache and taken over.');
   }
 
   /**
diff --git a/modules/simpletest/tests/form_test.module b/modules/simpletest/tests/form_test.module
index d871a6654463eff262021f68b733774a503b4a28..2036204ba26189157ee30838c00319e13f0c0f77 100644
--- a/modules/simpletest/tests/form_test.module
+++ b/modules/simpletest/tests/form_test.module
@@ -420,11 +420,10 @@ function form_test_storage_form($form, &$form_state) {
         'value' => '',
       ),
     );
-    $form_state['storage'] += array('step' => 1);
   }
-
-  // Count how often the form is constructed
+  // Count how often the form is constructed.
   $_SESSION['constructions']++;
+  drupal_set_message("Form constructions: ". $_SESSION['constructions']);
 
   $form['title'] = array(
     '#type' => 'textfield',
@@ -438,22 +437,26 @@ function form_test_storage_form($form, &$form_state) {
     '#default_value' => $form_state['storage']['thing']['value'],
     '#element_validate' => array('form_test_storage_element_validate_value_cached'),
   );
-  if ($form_state['storage']['step'] == 1) {
-    $form['submit'] = array(
-      '#type' => 'submit',
-      '#value' => 'Continue',
-    );
-  }
-  else {
-    $form['body'] = array(
-      '#type' => 'item',
-      '#value' => 'This is the second step.',
-    );
-    $form['submit'] = array(
-      '#type' => 'submit',
-      '#value' => 'Save',
-    );
-  }
+  $form['button'] = array(
+    '#type' => 'button',
+    '#value' => 'Reload',
+    // Reload the form (don't rebuild), thus we start at the initial step again.
+  );
+  $form['continue_button'] = array(
+    '#type' => 'button',
+    '#value' => 'Reset',
+    // Rebuilds the form without keeping the values.
+    '#validate' => array('form_storage_test_form_continue_validate'),
+  );
+  $form['continue_submit'] = array(
+    '#type' => 'submit',
+    '#value' => 'Continue submit',
+    '#submit' => array('form_storage_test_form_continue_submit'),
+  );
+  $form['submit'] = array(
+    '#type' => 'submit',
+    '#value' => 'Save',
+  );
 
   if (isset($_REQUEST['cache'])) {
     // Manually activate caching, so we can test that the storage keeps working
@@ -470,12 +473,12 @@ function form_test_storage_form($form, &$form_state) {
  * Tests updating of cached form storage during validation.
  */
 function form_test_storage_element_validate_value_cached($element, &$form_state) {
-  // If caching is enabled and we receive a certain value, change the value of
-  // 'title'. This presumes that another submitted form value triggers a
-  // validation error elsewhere in the form. Form API should still update the
-  // cached form storage though.
+  // If caching is enabled and we receive a certain value, change the storage.
+  // This presumes that another submitted form value triggers a validation error
+  // elsewhere in the form. Form API should still update the cached form storage
+  // though.
   if (isset($_REQUEST['cache']) && $form_state['values']['value'] == 'change_title') {
-    $form_state['storage']['thing']['title'] = 'title_changed';
+    $form_state['storage']['thing']['changed'] = TRUE;
     // @todo Fix FAPI to make it unnecessary to explicitly set the cache flag in
     //   this situation. @see http://drupal.org/node/641356.
     $form_state['cache'] = TRUE;
@@ -483,19 +486,33 @@ function form_test_storage_element_validate_value_cached($element, &$form_state)
 }
 
 /**
- * Form submit handler for form_test_storage_form().
+ * Form submit handler to continue multi-step form.
  */
-function form_test_storage_form_submit($form, &$form_state) {
-  if ($form_state['storage']['step'] == 1) {
-    $form_state['storage']['thing']['title'] = $form_state['values']['title'];
-    $form_state['storage']['thing']['value'] = $form_state['values']['value'];
-  }
-  else {
-    drupal_set_message("Title: ". check_plain($form_state['storage']['thing']['title']));
-  }
+function form_storage_test_form_continue_submit($form, &$form_state) {
+  $form_state['storage']['thing']['title'] = $form_state['values']['title'];
+  $form_state['storage']['thing']['value'] = $form_state['values']['value'];
+  $form_state['rebuild'] = TRUE;
+}
+
+/**
+ * Form validation handler, which doesn't preserve the values but rebuilds the
+ * form. We cannot use a submit handler here, as buttons of type button don't
+ * submit the form.
+ */
+function form_storage_test_form_continue_validate($form, &$form_state) {
   $form_state['rebuild'] = TRUE;
-  $form_state['storage']['step']++;
+}
+
+/**
+ * Form submit handler to finish multi-step form.
+ */
+function form_test_storage_form_submit($form, &$form_state) {
+  drupal_set_message("Title: ". check_plain($form_state['values']['title']));
   drupal_set_message("Form constructions: ". $_SESSION['constructions']);
+  if (isset($form_state['storage']['thing']['changed'])) {
+    drupal_set_message("The thing has been changed.");
+  }
+  $form_state['redirect'] = 'node';
 }
 
  /**