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 13 Jun 2009 20:11:57 -0000 @@ -10,22 +10,29 @@ public static function getInfo() { return array( - 'name' => t('Required field validation'), - 'description' => t('Carriage returns, tabs, and spaces are not valid content for a required field.'), + 'name' => t('Field validation'), + 'description' => t('Test various field validation mechanisms.'), 'group' => t('Form API'), ); } + + function setUp() { + return parent::setUp('form_test'); + } /** * Check several empty values for required forms elements. * + * Carriage returns, tabs, spaces, and unchecked checkbox elements are not + * valid content for a required field. + * * If the form field is found in form_get_errors() then the test pass. */ function testRequiredFields() { - // Originates from http://drupal.org/node/117748 // Sets of empty strings and arrays $empty_strings = array('""' => "", '"\n"' => "\n", '" "' => " ", '"\t"' => "\t", '" \n\t "' => " \n\t ", '"\n\n\n\n\n"' => "\n\n\n\n\n"); $empty_arrays = array('array()' => array()); + $empty_checkbox = array(NULL); $elements['textfield']['element'] = array('#title' => $this->randomName(), '#type' => 'textfield', '#required' => TRUE); $elements['textfield']['empty_values'] = $empty_strings; @@ -42,6 +49,9 @@ $elements['radios']['element'] = array('#title' => $this->randomName(), '#type' => 'radios', '#required' => TRUE, '#options' => array($this->randomName(), $this->randomName(), $this->randomName())); $elements['radios']['empty_values'] = $empty_arrays; + $elements['checkbox']['element'] = array('#title' => $this->randomName(), '#type' => 'checkbox', '#required' => TRUE, '#title' => $this->randomName()); + $elements['checkbox']['empty_values'] = $empty_checkbox; + $elements['checkboxes']['element'] = array('#title' => $this->randomName(), '#type' => 'checkboxes', '#required' => TRUE, '#options' => array($this->randomName(), $this->randomName(), $this->randomName())); $elements['checkboxes']['empty_values'] = $empty_arrays; @@ -72,42 +82,32 @@ // 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' => t('Form type-specific tests'), - 'description' => t('Test form type functions for expected behavior.'), - 'group' => t('Form API'), - ); - } /** - * Test form_type_checkbox_value() function for expected behavior. + * Test default value handling for checkboxes. + * + * @see form_test_checkbox(). */ - 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.')); - - // 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.')); + function testCheckBoxProcessing() { + // First, try to submit without the required checkbox. + $this->drupalPost('form-test/checkbox', array(), t('Submit')); + if ($this->assertRaw(t('!name field is required.', array('!name' => 'required_checkbox')), t('A required checkbox is actually mandatory'))) { + // Now try to submit the form correctly. + $this->drupalPost(NULL, array('required_checkbox' => 1), t('Submit')); + } - // $edit is FALSE. - $edit = FALSE; - $this->assertNull(form_type_checkbox_value($form, $edit), t('form_type_checkbox_value() returns NULL when $edit is FALSE')); + $values = json_decode($this->drupalGetContent(), TRUE); + $expected_values = array( + 'disabled_checkbox_on' => 'disabled_checkbox_on', + 'disabled_checkbox_off' => '', + 'checkbox_on' => 'checkbox_on', + 'checkbox_off' => '', + 'zero_checkbox_on' => '0', + 'zero_checkbox_off' => '', + ); + foreach ($expected_values as $widget => $expected_value) { + $this->assertEqual($values[$widget], $expected_value, t('Checkbox %widget returns expected value (expected: %expected, got: %value)', array('%widget' => var_export($widget, TRUE), '%expected' => var_export($expected_value, TRUE), '%value' => var_export($values[$widget], TRUE)))); + } } } 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 13 Jun 2009 20:11:57 -0000 @@ -66,6 +66,14 @@ 'type' => MENU_CALLBACK, ); + $items['form-test/checkbox'] = array( + 'title' => t('Form test'), + 'page callback' => 'drupal_get_form', + 'page arguments' => array('_form_test_checkbox'), + 'access callback' => TRUE, + 'type' => MENU_CALLBACK, + ); + return $items; } @@ -168,6 +176,83 @@ } /** + * Build a form to test a checkbox. + */ +function _form_test_checkbox() { + $form = array(); + + // A required checkbox. + $form['required_checkbox'] = array( + '#type' => 'checkbox', + '#required' => TRUE, + '#title' => 'required_checkbox', + ); + + // A disabled checkbox should get its default value back. + $form['disabled_checkbox_on'] = array( + '#type' => 'checkbox', + '#disabled' => TRUE, + '#return_value' => 'disabled_checkbox_on', + '#default_value' => 'disabled_checkbox_on', + '#title' => 'disabled_checkbox_on', + ); + $form['disabled_checkbox_off'] = array( + '#type' => 'checkbox', + '#disabled' => TRUE, + '#return_value' => 'disabled_checkbox_off', + '#default_value' => NULL, + '#title' => 'disabled_checkbox_off', + ); + + // A checkbox is active when #default_value == #return_value. + $form['checkbox_on'] = array( + '#type' => 'checkbox', + '#return_value' => 'checkbox_on', + '#default_value' => 'checkbox_on', + '#title' => 'checkbox_on', + ); + + // But inactive in any other case. + $form['checkbox_off'] = array( + '#type' => 'checkbox', + '#return_value' => 'checkbox_off', + '#default_value' => 'checkbox_on', + '#title' => 'checkbox_off', + ); + + // Checkboxes with a #return_value of '0' are supported. + $form['zero_checkbox_on'] = array( + '#type' => 'checkbox', + '#return_value' => '0', + '#default_value' => '0', + '#title' => 'zero_checkbox_on', + ); + + // In that case, passing a #default_value != '0' means that the checkbox is off. + $form['zero_checkbox_off'] = array( + '#type' => 'checkbox', + '#return_value' => '0', + '#default_value' => 1, + '#title' => 'zero_checkbox_off', + ); + + $form['op'] = array( + '#type' => 'submit', + '#value' => t('Submit') + ); + + return $form; +} + +/** + * Return the form values by JSON. + */ +function _form_test_checkbox_submit($form_id, &$form_state) { + drupal_json($form_state['values']); + exit; +} + +/** * Process the tableselect #multiple = TRUE submitted values. */ function _form_test_tableselect_multiple_true_form_submit($form, &$form_state) { Index: includes/form.inc =================================================================== RCS file: /cvs/drupal/drupal/includes/form.inc,v retrieving revision 1.339 diff -u -r1.339 form.inc --- includes/form.inc 2 Jun 2009 13:47:25 -0000 1.339 +++ includes/form.inc 13 Jun 2009 20:11:57 -0000 @@ -1256,11 +1256,20 @@ */ function form_type_checkbox_value($form, $edit = FALSE) { if ($edit !== FALSE) { - if (empty($form['#disabled'])) { - return !empty($edit) ? $form['#return_value'] : 0; + if (isset($edit)) { + // A value is passed by the browser: the checkbox is on. + return $form['#return_value']; } else { - return $form['#default_value']; + if (!empty($form['#disabled'])) { + // Disabled checkbox values are not passed by the browser, + // use default instead. + return $form['#default_value']; + } + else { + // The checkbox is off. + return ''; + } } } } @@ -2049,17 +2058,19 @@ * @ingroup themeable */ function theme_checkbox($element) { + $t = get_t(); _form_set_class($element, array('form-checkbox')); $checkbox = ''; if (!is_null($element['#title'])) { - $checkbox = ''; + $required = !empty($element['#required']) ? ' *' : ''; + $checkbox = ''; } return $checkbox; @@ -2112,7 +2123,7 @@ '#processed' => TRUE, '#title' => $choice, '#return_value' => $key, - '#default_value' => isset($value[$key]), + '#default_value' => isset($value[$key]) ? $key : NULL, '#attributes' => $element['#attributes'], '#ahah' => isset($element['#ahah']) ? $element['#ahah'] : NULL, );