Index: modules/simpletest/tests/form.test
===================================================================
RCS file: /cvs/drupal/drupal/modules/simpletest/tests/form.test,v
retrieving revision 1.1
diff -u -r1.1 form.test
--- modules/simpletest/tests/form.test	14 Aug 2008 09:18:28 -0000	1.1
+++ modules/simpletest/tests/form.test	6 Jan 2009 19:45:46 -0000
@@ -11,7 +11,7 @@
   function getInfo() {
     return array(
       'name' => t('Required field validation'),
-      'description' => t('Carriage returns, tabs, and spaces are not valid content for a required field.'),
+      'description' => t('Carriage returns, tabs, spaces, and unchecked checkbox elements are not valid content for a required field.'),
       'group' => t('Form API'),
     );
   }
@@ -26,6 +26,7 @@
     // 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(0);
 
     $elements['textfield']['element'] = array('#title' => $this->randomName(), '#type' => 'textfield', '#required' => TRUE);
     $elements['textfield']['empty_values'] = $empty_strings;
@@ -42,6 +43,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;
 
Index: includes/form.inc
===================================================================
RCS file: /cvs/drupal/drupal/includes/form.inc,v
retrieving revision 1.310
diff -u -r1.310 form.inc
--- includes/form.inc	30 Dec 2008 16:43:14 -0000	1.310
+++ includes/form.inc	6 Jan 2009 19:45:45 -0000
@@ -676,7 +676,9 @@
       // A simple call to empty() will not cut it here as some fields, like
       // checkboxes, can return a valid value of '0'. Instead, check the
       // length if it's a string, and the item count if it's an array.
-      if ($elements['#required'] && (!count($elements['#value']) || (is_string($elements['#value']) && strlen(trim($elements['#value'])) == 0))) {
+      // To cover the case where an unchecked single checkbox actually does
+      // return a value of zero, we explicitly check for the checkbox type.
+      if ($elements['#required'] && (!count($elements['#value']) || ($elements['#type'] == 'checkbox' && !$elements['#value']) || (is_string($elements['#value']) && strlen(trim($elements['#value'])) == 0))) {
         form_error($elements, $t('!name field is required.', array('!name' => $elements['#title'])));
       }
 
@@ -1967,6 +1969,7 @@
  * @ingroup themeable
  */
 function theme_checkbox($element) {
+  $t = get_t();
   _form_set_class($element, array('form-checkbox'));
   $checkbox = '<input ';
   $checkbox .= 'type="checkbox" ';
@@ -1976,8 +1979,14 @@
   $checkbox .= $element['#value'] ? ' checked="checked" ' : ' ';
   $checkbox .= drupal_attributes($element['#attributes']) . ' />';
 
+  $required = !empty($element['#required']) ? ' <span class="form-required" title="' . $t('This field is required.') . '">*</span>' : '';
   if (!is_null($element['#title'])) {
-    $checkbox = '<label class="option">' . $checkbox . ' ' . $element['#title'] . '</label>';
+    if (!empty($required)) {
+      $checkbox = '<label class="option">' . $checkbox . ' ' . $element['#title'] . $required . '</label>';
+    }
+    else {
+      $checkbox = '<label class="option">' . $checkbox . ' ' . $element['#title'] . '</label>';
+    }
   }
 
   unset($element['#title']);
