|
Moodle
2.2.1
http://www.collinsharper.com
|
00001 <?php 00002 00003 // This file is part of Moodle - http://moodle.org/ 00004 // 00005 // Moodle is free software: you can redistribute it and/or modify 00006 // it under the terms of the GNU General Public License as published by 00007 // the Free Software Foundation, either version 3 of the License, or 00008 // (at your option) any later version. 00009 // 00010 // Moodle is distributed in the hope that it will be useful, 00011 // but WITHOUT ANY WARRANTY; without even the implied warranty of 00012 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00013 // GNU General Public License for more details. 00014 // 00015 // You should have received a copy of the GNU General Public License 00016 // along with Moodle. If not, see <http://www.gnu.org/licenses/>. 00017 00027 defined('MOODLE_INTERNAL') || die(); 00028 00029 // Include the code to test 00030 require_once($CFG->dirroot . '/mod/workshop/locallib.php'); 00031 require_once($CFG->dirroot . '/mod/workshop/allocation/random/lib.php'); 00032 00036 class testable_workshop_random_allocator extends workshop_random_allocator { 00037 public function self_allocation($authors=array(), $reviewers=array(), $assessments=array()) { 00038 return parent::self_allocation($authors, $reviewers, $assessments); 00039 } 00040 public function get_author_ids($newallocations) { 00041 return parent::get_author_ids($newallocations); 00042 } 00043 public function index_submissions_by_authors($submissions) { 00044 return parent::index_submissions_by_authors($submissions); 00045 } 00046 public function get_unique_allocations($newallocations) { 00047 return parent::get_unique_allocations($newallocations); 00048 } 00049 public function get_unkept_assessments($assessments, $newallocations, $keepselfassessments) { 00050 return parent::get_unkept_assessments($assessments, $newallocations, $keepselfassessments); 00051 } 00052 public function convert_assessments_to_links($assessments) { 00053 return parent::convert_assessments_to_links($assessments); 00054 } 00055 public function get_element_with_lowest_workload($workload) { 00056 return parent::get_element_with_lowest_workload($workload); 00057 } 00058 public function filter_current_assessments(&$newallocations, $assessments) { 00059 return parent::filter_current_assessments($newallocations, $assessments); 00060 } 00061 } 00062 00063 class workshop_allocation_random_test extends UnitTestCase { 00064 00066 protected $workshop; 00067 00069 protected $allocator; 00070 00071 public function setUp() { 00072 $cm = new stdclass(); 00073 $course = new stdclass(); 00074 $context = new stdclass(); 00075 $workshop = (object)array('id' => 42); 00076 $this->workshop = new workshop($workshop, $cm, $course, $context); 00077 $this->allocator = new testable_workshop_random_allocator($this->workshop); 00078 } 00079 00080 public function tearDown() { 00081 $this->allocator = null; 00082 $this->workshop = null; 00083 } 00084 00085 public function test_self_allocation_empty_values() { 00086 // fixture setup & exercise SUT & verify 00087 $this->assertEqual(array(), $this->allocator->self_allocation()); 00088 } 00089 00090 public function test_self_allocation_equal_user_groups() { 00091 // fixture setup 00092 $authors = array(0 => array_fill_keys(array(4, 6, 10), new stdclass())); 00093 $reviewers = array(0 => array_fill_keys(array(4, 6, 10), new stdclass())); 00094 // exercise SUT 00095 $newallocations = $this->allocator->self_allocation($authors, $reviewers); 00096 // verify 00097 $this->assertEqual(array(array(4 => 4), array(6 => 6), array(10 => 10)), $newallocations); 00098 } 00099 00100 public function test_self_allocation_different_user_groups() { 00101 // fixture setup 00102 $authors = array(0 => array_fill_keys(array(1, 4, 5, 10, 13), new stdclass())); 00103 $reviewers = array(0 => array_fill_keys(array(4, 7, 10), new stdclass())); 00104 // exercise SUT 00105 $newallocations = $this->allocator->self_allocation($authors, $reviewers); 00106 // verify 00107 $this->assertEqual(array(array(4 => 4), array(10 => 10)), $newallocations); 00108 } 00109 00110 public function test_self_allocation_skip_existing() { 00111 // fixture setup 00112 $authors = array(0 => array_fill_keys(array(3, 4, 10), new stdclass())); 00113 $reviewers = array(0 => array_fill_keys(array(3, 4, 10), new stdclass())); 00114 $assessments = array(23 => (object)array('authorid' => 3, 'reviewerid' => 3)); 00115 // exercise SUT 00116 $newallocations = $this->allocator->self_allocation($authors, $reviewers, $assessments); 00117 // verify 00118 $this->assertEqual(array(array(4 => 4), array(10 => 10)), $newallocations); 00119 } 00120 00121 public function test_get_author_ids() { 00122 // fixture setup 00123 $newallocations = array(array(1 => 3), array(2 => 1), array(3 => 1)); 00124 // exercise SUT & verify 00125 $this->assertEqual(array(3, 1), $this->allocator->get_author_ids($newallocations)); 00126 } 00127 00128 public function test_index_submissions_by_authors() { 00129 // fixture setup 00130 $submissions = array( 00131 676 => (object)array('id' => 676, 'authorid' => 23), 00132 121 => (object)array('id' => 121, 'authorid' => 56), 00133 ); 00134 // exercise SUT 00135 $submissions = $this->allocator->index_submissions_by_authors($submissions); 00136 // verify 00137 $this->assertEqual(array( 00138 23 => (object)array('id' => 676, 'authorid' => 23), 00139 56 => (object)array('id' => 121, 'authorid' => 56), 00140 ), $submissions); 00141 } 00142 00143 public function test_index_submissions_by_authors_duplicate_author() { 00144 // fixture setup 00145 $submissions = array( 00146 14 => (object)array('id' => 676, 'authorid' => 3), 00147 87 => (object)array('id' => 121, 'authorid' => 3), 00148 ); 00149 // set expectation 00150 $this->expectException('moodle_exception'); 00151 // exercise SUT 00152 $submissions = $this->allocator->index_submissions_by_authors($submissions); 00153 } 00154 00155 public function test_get_unique_allocations() { 00156 // fixture setup 00157 $newallocations = array(array(4 => 5), array(6 => 6), array(1 => 16), array(4 => 5), array(16 => 1)); 00158 // exercise SUT 00159 $newallocations = $this->allocator->get_unique_allocations($newallocations); 00160 // verify 00161 $this->assertEqual(array(array(4 => 5), array(6 => 6), array(1 => 16), array(16 => 1)), $newallocations); 00162 } 00163 00164 public function test_get_unkept_assessments_no_keep_selfassessments() { 00165 // fixture setup 00166 $assessments = array( 00167 23 => (object)array('authorid' => 3, 'reviewerid' => 3), 00168 45 => (object)array('authorid' => 5, 'reviewerid' => 11), 00169 12 => (object)array('authorid' => 6, 'reviewerid' => 3), 00170 ); 00171 $newallocations = array(array(4 => 5), array(11 => 5), array(1 => 16), array(4 => 5), array(16 => 1)); 00172 // exercise SUT 00173 $delassessments = $this->allocator->get_unkept_assessments($assessments, $newallocations, false); 00174 // verify 00175 // we want to keep $assessments[45] because it has been re-allocated 00176 $this->assertEqual(array(23, 12), $delassessments); 00177 } 00178 00179 public function test_get_unkept_assessments_keep_selfassessments() { 00180 // fixture setup 00181 $assessments = array( 00182 23 => (object)array('authorid' => 3, 'reviewerid' => 3), 00183 45 => (object)array('authorid' => 5, 'reviewerid' => 11), 00184 12 => (object)array('authorid' => 6, 'reviewerid' => 3), 00185 ); 00186 $newallocations = array(array(4 => 5), array(11 => 5), array(1 => 16), array(4 => 5), array(16 => 1)); 00187 // exercise SUT 00188 $delassessments = $this->allocator->get_unkept_assessments($assessments, $newallocations, true); 00189 // verify 00190 // we want to keep $assessments[45] because it has been re-allocated 00191 // we want to keep $assessments[23] because if is self assessment 00192 $this->assertEqual(array(12), $delassessments); 00193 } 00194 00198 public function test_convert_assessments_to_links() { 00199 // fixture setup 00200 $assessments = array( 00201 23 => (object)array('authorid' => 3, 'reviewerid' => 3), 00202 45 => (object)array('authorid' => 5, 'reviewerid' => 11), 00203 12 => (object)array('authorid' => 5, 'reviewerid' => 3), 00204 ); 00205 // exercise SUT 00206 list($authorlinks, $reviewerlinks) = $this->allocator->convert_assessments_to_links($assessments); 00207 // verify 00208 $this->assertEqual(array(3 => array(3), 5 => array(11, 3)), $authorlinks); 00209 $this->assertEqual(array(3 => array(3, 5), 11 => array(5)), $reviewerlinks); 00210 } 00211 00215 public function test_convert_assessments_to_links_empty() { 00216 // fixture setup 00217 $assessments = array(); 00218 // exercise SUT 00219 list($authorlinks, $reviewerlinks) = $this->allocator->convert_assessments_to_links($assessments); 00220 // verify 00221 $this->assertEqual(array(), $authorlinks); 00222 $this->assertEqual(array(), $reviewerlinks); 00223 } 00224 00228 public function test_get_element_with_lowest_workload_deterministic() { 00229 // fixture setup 00230 $workload = array(4 => 6, 9 => 1, 10 => 2); 00231 // exercise SUT 00232 $chosen = $this->allocator->get_element_with_lowest_workload($workload); 00233 // verify 00234 $this->assertEqual(9, $chosen); 00235 } 00236 00240 public function test_get_element_with_lowest_workload_impossible() { 00241 // fixture setup 00242 $workload = array(); 00243 // exercise SUT 00244 $chosen = $this->allocator->get_element_with_lowest_workload($workload); 00245 // verify 00246 $this->assertTrue($chosen === false); 00247 } 00248 00252 public function test_get_element_with_lowest_workload_random() { 00253 // fixture setup 00254 $workload = array(4 => 6, 9 => 2, 10 => 2); 00255 // exercise SUT 00256 $elements = $this->allocator->get_element_with_lowest_workload($workload); 00257 // verify 00258 // in theory, this test can fail even if the function works well. However, the probability of getting 00259 // a row of a hundred same ids in this use case is 1/pow(2, 100) 00260 // also, this just tests that each of the two elements has been chosen at least once. this is not to 00261 // measure the quality or randomness of the algorithm 00262 $counts = array(4 => 0, 9 => 0, 10 => 0); 00263 for ($i = 0; $i < 100; $i++) { 00264 $chosen = $this->allocator->get_element_with_lowest_workload($workload); 00265 if (!in_array($chosen, array(4, 9, 10))) { 00266 $this->fail('Invalid element ' . var_export($chosen, true) . ' chosen'); 00267 break; 00268 } else { 00269 $counts[$this->allocator->get_element_with_lowest_workload($workload)]++; 00270 } 00271 } 00272 $this->assertTrue(($counts[9] > 0) && ($counts[10] > 0)); 00273 } 00274 00280 public function test_get_element_with_lowest_workload_random_floats() { 00281 // fixture setup 00282 $workload = array(1 => 1/13, 2 => 0.0769230769231); // should be considered as the same value 00283 // exercise SUT 00284 $elements = $this->allocator->get_element_with_lowest_workload($workload); 00285 // verify 00286 $counts = array(1 => 0, 2 => 0); 00287 for ($i = 0; $i < 100; $i++) { 00288 $chosen = $this->allocator->get_element_with_lowest_workload($workload); 00289 if (!in_array($chosen, array(1, 2))) { 00290 $this->fail('Invalid element ' . var_export($chosen, true) . ' chosen'); 00291 break; 00292 } else { 00293 $counts[$this->allocator->get_element_with_lowest_workload($workload)]++; 00294 } 00295 } 00296 $this->assertTrue(($counts[1] > 0) && ($counts[2] > 0)); 00297 00298 } 00299 00303 public function test_filter_current_assessments() { 00304 // fixture setup 00305 $newallocations = array(array(3 => 5), array(11 => 5), array(2 => 9), array(3 => 5)); 00306 $assessments = array( 00307 23 => (object)array('authorid' => 3, 'reviewerid' => 3), 00308 45 => (object)array('authorid' => 5, 'reviewerid' => 11), 00309 12 => (object)array('authorid' => 5, 'reviewerid' => 3), 00310 ); 00311 // exercise SUT 00312 $this->allocator->filter_current_assessments($newallocations, $assessments); 00313 // verify 00314 $this->assertEqual(array_values($newallocations), array(array(2 => 9))); 00315 } 00316 00317 00318 }