Index: includes/form.inc
===================================================================
RCS file: /cvs/drupal/drupal/includes/form.inc,v
retrieving revision 1.373
diff -r1.373 form.inc
806c806,808
<       if ($elements['#required'] && (!count($elements['#value']) || (is_string($elements['#value']) && strlen(trim($elements['#value'])) == 0))) {
---
>       // Unchecked checkbox has #value of numeric 0 (different than 
> 	  // string '0', which could be a valid value).
>       if ($elements['#required'] && (!count($elements['#value']) || (is_string($elements['#value']) && strlen(trim($elements['#value'])) == 0) || $elements['#value'] === 0)) {
1334c1336,1340
<       return !empty($input) ? $element['#return_value'] : 0;
---
>       // Successful (checked) checkboxes are present with a value (possibly '0').
>       // http://www.w3.org/TR/html401/interact/forms.html#successful-controls
>       // For an unchecked checkbox, we return numeric 0 (something we can
>       // explicitly test for; different than string '0').
>       return isset($input) ? $element['#return_value'] : 0;
1336a1343,1344
>       // Disabled form controls are not submitted by the browser.
>       // Ignore any submitted value and always return default.
2015a2024
>   $t = get_t();
2022c2031,2032
<   $checkbox .= $element['#value'] ? ' checked="checked" ' : ' ';
---
>   // Unchecked checkbox has #value of numeric 0.
>   $checkbox .= ($element['#value'] !== 0 && $element['#value'] == $element['#return_value']) ? ' checked="checked" ' : ' ';
2026c2036,2037
<     $checkbox = '<label class="option" for="' . $element['#id'] . '">' . $checkbox . ' ' . $element['#title'] . '</label>';
---
>     $required = !empty($element['#required']) ? ' <span class="form-required" title="' . $t('This field is required.') . '">*</span>' : '';
>     $checkbox = '<label class="option" for="' . $element['#id'] . '">' . $checkbox . ' ' . $element['#title'] . $required . '</label>';
2080c2091
<           '#default_value' => isset($value[$key]),
---
>           '#default_value' => isset($value[$key]) ? $key : NULL,
2193c2204
<             '#default_value' => isset($value[$key]),
---
>             '#default_value' => isset($value[$key]) ? $key : NULL,
Index: modules/simpletest/tests/form.test
===================================================================
RCS file: /cvs/drupal/drupal/modules/simpletest/tests/form.test,v
retrieving revision 1.15
diff -r1.15 form.test
9c9
< class FormsTestCase extends DrupalWebTestCase {
---
> class FormsAPIUnitTest extends DrupalWebTestCase {
13,14c13,14
<       'name' => 'Required field validation',
<       'description' => 'Carriage returns, tabs, and spaces are not valid content for a required field.',
---
>       'name' => 'Field validation',
>       'description' => 'Test various field validation mechanisms.',
18a19,22
>   function setUp() {
>     parent::setUp('form_test');
>   }
> 
21a26,28
>    * Carriage returns, tabs, spaces, and unchecked checkbox elements are not
>    * valid content for a required field.
>    *
26c33
<     // Sets of empty strings and arrays
---
>     // Sets of empty strings and arrays.
28a36
>     $empty_checkbox = array(NULL);
44a53,55
>     $elements['checkbox']['element'] = array('#title' => $this->randomName(), '#type' => 'checkbox', '#required' => TRUE, '#title' => $this->randomName());
>     $elements['checkbox']['empty_values'] = $empty_checkbox;
> 
54c65
<     // Go through all the elements and all the empty values for them
---
>     // Go through all the elements and all the empty values for them.
75,87d85
< }
< 
< /**
<  * 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',
<     );
<   }
90c88,90
<    * Test form_type_checkbox_value() function for expected behavior.
---
>    * Test default value handling for checkboxes.
>    *
>    * @see form_test_checkbox().
92,102c92,98
<   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.'));
---
>   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'));
>     }
104,106c100,108
<     // 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.'));
---
>     $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' => '',
>     );
108,110c110,112
<     // $edit is FALSE.
<     $edit = FALSE;
<     $this->assertNull(form_type_checkbox_value($form, $edit), t('form_type_checkbox_value() returns NULL when $edit is FALSE'));
---
>     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.9
diff -r1.9 form_test.module
71a72,79
>   $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,
>   );
> 
365a374,387
>  /**
>   * 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',
>   );
> }
> 
