function test_save_grades()
 {
     $test_item_name1 = 'testing-iclicker-item1';
     $test_item_name2 = 'testing-iclicker-item2';
     $test_item_name3 = 'testing-iclicker-item3';
     $gradebook = new stdClass();
     // saving a gradebook with no course_id not allowed
     try {
         $result = iclicker_service::save_gradebook($gradebook);
         $this->fail("should have died");
     } catch (Exception $e) {
         $this->assertNotNull($e);
     }
     $gradebook->course_id = $this->courseid;
     $gradebook->items = array();
     // saving an empty gradebook not allowed
     try {
         $result = iclicker_service::save_gradebook($gradebook);
         $this->fail("should have died");
     } catch (Exception $e) {
         $this->assertNotNull($e);
     }
     // saving one with one valid item
     $score = new stdClass();
     $score->user_id = 1;
     $score->score = 75.0;
     $grade_item = new stdClass();
     $grade_item->name = $test_item_name1;
     $grade_item->points_possible = 90;
     $grade_item->type = iclicker_service::GRADE_CATEGORY_NAME;
     $grade_item->scores = array();
     $grade_item->scores[] = $score;
     $gradebook->items[] = $grade_item;
     $result = iclicker_service::save_gradebook($gradebook);
     $this->assertNotNull($result);
     $this->assertNotNull($result->course_id);
     $this->assertNotNull($result->course);
     $this->assertNotNull($result->default_category_id);
     $this->assertNotNull($result->items);
     $this->assertEqual($result->course_id, $this->courseid);
     $this->assertEqual(count($result->items), 1);
     $this->assertNotNull($result->items[0]);
     $this->assertNotNull($result->items[0]->id);
     $this->assertNotNull($result->items[0]->scores);
     $this->assertEqual(count($result->items[0]->scores), 1);
     $this->assertFalse(isset($result->items[0]->errors));
     $this->assertEqual($result->items[0]->grademax, 90);
     $this->assertEqual($result->items[0]->iteminfo, iclicker_service::GRADE_CATEGORY_NAME);
     $this->assertNotNull($result->items[0]->categoryid);
     $this->assertEqual($result->items[0]->courseid, $result->course_id);
     $this->assertEqual($result->items[0]->itemname, $test_item_name1);
     $this->assertNotNull($result->items[0]->scores[0]);
     $this->assertFalse(isset($result->items[0]->scores[0]->error));
     // saving one with multiple items, some invalid
     $grade_item->type = 'stuff';
     // update category
     $score->score = 50;
     // SCORE_UPDATE_ERRORS
     $score1 = new stdClass();
     $score1->user_id = 'xxxxxx';
     // USER_DOES_NOT_EXIST_ERROR
     $score1->score = 80;
     $grade_item->scores[] = $score1;
     $score2 = new stdClass();
     $score2->user_id = '2';
     $score2->score = 101;
     // POINTS_POSSIBLE_UPDATE_ERRORS
     $grade_item->scores[] = $score2;
     $score3 = new stdClass();
     $score3->user_id = '3';
     $score3->score = 'XX';
     // GENERAL_ERRORS
     $grade_item->scores[] = $score3;
     $result = iclicker_service::save_gradebook($gradebook);
     $this->assertNotNull($result);
     $this->assertNotNull($result->course_id);
     $this->assertNotNull($result->course);
     //$this->assertNotNull($result->default_category_id);
     $this->assertNotNull($result->items);
     $this->assertEqual($result->course_id, $this->courseid);
     $this->assertEqual(count($result->items), 1);
     $this->assertNotNull($result->items[0]);
     $this->assertNotNull($result->items[0]->id);
     $this->assertEqual($result->items[0]->iteminfo, 'stuff');
     $this->assertNotNull($result->items[0]->scores);
     $this->assertEqual(count($result->items[0]->scores), 4);
     $this->assertTrue(isset($result->items[0]->errors));
     $this->assertEqual(count($result->items[0]->errors), 4);
     $this->assertEqual($result->items[0]->grademax, 90);
     $this->assertNotNull($result->items[0]->categoryid);
     $this->assertEqual($result->items[0]->courseid, $result->course_id);
     $this->assertEqual($result->items[0]->itemname, $test_item_name1);
     $this->assertNotNull($result->items[0]->scores[0]);
     $this->assertTrue(isset($result->items[0]->scores[0]->error));
     $this->assertEqual($result->items[0]->scores[0]->error, iclicker_service::SCORE_UPDATE_ERRORS);
     $this->assertNotNull($result->items[0]->scores[1]);
     $this->assertTrue(isset($result->items[0]->scores[1]->error));
     $this->assertEqual($result->items[0]->scores[1]->error, iclicker_service::USER_DOES_NOT_EXIST_ERROR);
     $this->assertNotNull($result->items[0]->scores[2]);
     $this->assertTrue(isset($result->items[0]->scores[2]->error));
     $this->assertEqual($result->items[0]->scores[2]->error, iclicker_service::POINTS_POSSIBLE_UPDATE_ERRORS);
     $this->assertNotNull($result->items[0]->scores[3]);
     $this->assertTrue(isset($result->items[0]->scores[3]->error));
     $this->assertEqual($result->items[0]->scores[3]->error, 'SCORE_INVALID');
     $xml = iclicker_service::encode_gradebook_results($result);
     $this->assertNotNull($xml);
     $this->assertTrue(stripos($xml, '<user ') > 0);
     $this->assertTrue(stripos($xml, '<lineitem ') > 0);
     $this->assertTrue(stripos($xml, '<error ') > 0);
     $this->assertTrue(stripos($xml, iclicker_service::SCORE_UPDATE_ERRORS) > 0);
     $this->assertTrue(stripos($xml, iclicker_service::USER_DOES_NOT_EXIST_ERROR) > 0);
     $this->assertTrue(stripos($xml, iclicker_service::POINTS_POSSIBLE_UPDATE_ERRORS) > 0);
     $this->assertTrue(stripos($xml, iclicker_service::GENERAL_ERRORS) > 0);
     //echo "<xmp>$xml</xmp>";
     // Save 1 update and 2 new grades
     $score->score = 85;
     $score2->score = 50;
     $score3->score = 0;
     $grade_item->scores = array();
     $grade_item->scores[] = $score;
     $grade_item->scores[] = $score2;
     $grade_item->scores[] = $score3;
     $result = iclicker_service::save_gradebook($gradebook);
     $this->assertNotNull($result);
     $this->assertNotNull($result->course_id);
     $this->assertNotNull($result->items);
     $this->assertEqual($result->course_id, $this->courseid);
     $this->assertEqual(count($result->items), 1);
     $this->assertNotNull($result->items[0]);
     $this->assertNotNull($result->items[0]->id);
     $this->assertNotNull($result->items[0]->scores);
     $this->assertEqual(count($result->items[0]->scores), 3);
     $this->assertFalse(isset($result->items[0]->errors));
     $this->assertEqual($result->items[0]->grademax, 90);
     $this->assertNotNull($result->items[0]->scores[0]);
     $this->assertEqual($result->items[0]->scores[0]->rawgrade, 85);
     $this->assertNotNull($result->items[0]->scores[1]);
     $this->assertEqual($result->items[0]->scores[1]->rawgrade, 50);
     $this->assertNotNull($result->items[0]->scores[2]);
     $this->assertEqual($result->items[0]->scores[2]->rawgrade, 0);
     /*
     echo "<pre>";
     var_export($result->items[0]);
     echo "</pre>";
     */
     $xml = iclicker_service::encode_gradebook_results($result);
     $this->assertNull($xml);
     // no errors
     // test saving multiple items at once
     $gradebook->course_id = $this->courseid;
     $gradebook->items = array();
     $grade_item1 = new stdClass();
     $grade_item1->name = $test_item_name2;
     $grade_item1->points_possible = 100;
     $grade_item1->type = NULL;
     // default
     $grade_item1->scores = array();
     $gradebook->items[] = $grade_item1;
     $grade_item2 = new stdClass();
     $grade_item2->name = $test_item_name3;
     $grade_item2->points_possible = 50;
     $grade_item2->type = 'stuff';
     $grade_item2->scores = array();
     $gradebook->items[] = $grade_item2;
     $score = new stdClass();
     $score->user_id = 1;
     $score->score = 80.0;
     $grade_item1->scores[] = $score;
     $score = new stdClass();
     $score->user_id = 2;
     $score->score = 90.0;
     $grade_item1->scores[] = $score;
     $score = new stdClass();
     $score->user_id = 2;
     $score->score = 45.0;
     $grade_item2->scores[] = $score;
     $score = new stdClass();
     $score->user_id = 3;
     $score->score = 40.0;
     $grade_item2->scores[] = $score;
     $result = iclicker_service::save_gradebook($gradebook);
     $this->assertNotNull($result);
     $this->assertNotNull($result->course_id);
     $this->assertNotNull($result->items);
     $this->assertNotNull($result->default_category_id);
     $this->assertEqual($result->course_id, $this->courseid);
     $this->assertEqual(count($result->items), 2);
     $this->assertNotNull($result->items[0]);
     $this->assertNotNull($result->items[0]->id);
     $this->assertNotNull($result->items[0]->scores);
     $this->assertEqual(count($result->items[0]->scores), 2);
     $this->assertFalse(isset($result->items[0]->errors));
     $this->assertEqual($result->items[0]->grademax, 100);
     $this->assertNotNull($result->items[0]->scores[0]);
     $this->assertEqual($result->items[0]->scores[0]->rawgrade, 80);
     $this->assertNotNull($result->items[0]->scores[1]);
     $this->assertEqual($result->items[0]->scores[1]->rawgrade, 90);
     $this->assertNotNull($result->items[1]);
     $this->assertNotNull($result->items[1]->id);
     $this->assertNotNull($result->items[1]->scores);
     $this->assertEqual(count($result->items[1]->scores), 2);
     $this->assertFalse(isset($result->items[1]->errors));
     $this->assertEqual($result->items[1]->grademax, 50);
     $this->assertNotNull($result->items[1]->scores[0]);
     $this->assertEqual($result->items[1]->scores[0]->rawgrade, 45);
     $this->assertNotNull($result->items[1]->scores[1]);
     $this->assertEqual($result->items[1]->scores[1]->rawgrade, 40);
     $xml = iclicker_service::encode_gradebook_results($result);
     $this->assertNull($xml);
 }
         }
     }
 } else {
     // POST
     if ("gradebook" == $pathSeg0) {
         // handle retrieval of the list of students
         $course_id = $pathSeg1;
         if ($course_id == null) {
             throw new InvalidArgumentException("valid course_id must be included in the URL /gradebook/{course_id}");
         }
         iclicker_get_and_check_current_user("upload grades into the gradebook");
         $xml = iclicker_get_xml_data($cntlr);
         try {
             $gradebook = iclicker_service::decode_gradebook($xml);
             // process gradebook data
             $results = iclicker_service::save_gradebook($gradebook);
             // generate the output
             $output = iclicker_service::encode_gradebook_results($results);
             if (!$output) {
                 // special RETURN, non-XML, no failures in save
                 $cntlr->setStatus(200);
                 $cntlr->setContentType("text/plain");
                 $output = "True";
                 $cntlr->sendResponse($output);
                 return;
                 // SHORT CIRCUIT
             } else {
                 // failures occurred during save
                 $status = 200;
                 //OK;
             }