MDL-42428 Javascript: Switch M.util.show_confirm_dialog to use moodle-core-notification
[moodle.git] / mod / quiz / report / statistics / tests / statistics_test.php
1 <?php
2 // This file is part of Moodle - http://moodle.org/
3 //
4 // Moodle is free software: you can redistribute it and/or modify
5 // it under the terms of the GNU General Public License as published by
6 // the Free Software Foundation, either version 3 of the License, or
7 // (at your option) any later version.
8 //
9 // Moodle is distributed in the hope that it will be useful,
10 // but WITHOUT ANY WARRANTY; without even the implied warranty of
11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12 // GNU General Public License for more details.
13 //
14 // You should have received a copy of the GNU General Public License
15 // along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
17 /**
18  * Unit tests for (some of) /question/engine/statistics.php
19  *
20  * @package   quiz_statistics
21  * @category  phpunit
22  * @copyright 2008 Jamie Pratt
23  * @license   http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
24  */
26 defined('MOODLE_INTERNAL') || die();
28 global $CFG;
29 require_once($CFG->libdir . '/questionlib.php');
30 require_once($CFG->dirroot . '/mod/quiz/locallib.php');
31 require_once($CFG->dirroot . '/mod/quiz/report/reportlib.php');
33 /**
34  * Test helper subclass of question_statistics
35  *
36  * @copyright 2010 The Open University
37  * @license   http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
38  */
39 class testable_question_statistics extends \core_question\statistics\questions\calculator {
41     /**
42      * @var object[]
43      */
44     protected $lateststeps;
46     public function set_step_data($states) {
47         $this->lateststeps = $states;
48     }
50     protected function get_random_guess_score($questiondata) {
51         return 0;
52     }
54     /**
55      * @param $qubaids qubaid_condition is ignored in this test
56      * @return array with three items
57      *              - $lateststeps array of latest step data for the question usages
58      *              - $summarks    array of total marks for each usage, indexed by usage id
59      *              - $summarksavg the average of the total marks over all the usages     */
60     protected function get_latest_steps($qubaids) {
61         $summarks = array();
62         $fakeusageid = 0;
63         foreach ($this->lateststeps as $step) {
64             // The same 'sumgrades' field is available in step data for every slot, we will ignore all slots but slot 1.
65             // The step for slot 1 is always the first one in the csv file for each usage, we will use that to separate steps from
66             // each usage.
67             if ($step->slot == 1) {
68                 $fakeusageid++;
69                 $summarks[$fakeusageid] = $step->sumgrades;
70             }
71             unset($step->sumgrades);
72             $step->questionusageid = $fakeusageid;
73         }
75         $summarksavg = array_sum($summarks) / count($summarks);
76         return array($this->lateststeps, $summarks, $summarksavg);
77     }
79     protected function cache_stats($qubaids) {
80         // No caching wanted for tests.
81     }
82 }
83 /**
84  * Unit tests for (some of) question_statistics.
85  *
86  * @copyright 2008 Jamie Pratt
87  * @license   http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
88  */
89 class quiz_statistics_question_stats_testcase extends basic_testcase {
90     /** @var qstats object created to test class. */
91     protected $qstats;
93     public function test_qstats() {
94         global $CFG;
95         // Data is taken from randomly generated attempts data generated by
96         // contrib/tools/generators/qagenerator/.
97         $steps = $this->get_records_from_csv(__DIR__.'/fixtures/mdl_question_states.csv');
98         // Data is taken from questions mostly generated by
99         // contrib/tools/generators/generator.php.
100         $questions = $this->get_records_from_csv(__DIR__.'/fixtures/mdl_question.csv');
101         $calculator = new testable_question_statistics($questions);
102         $calculator->set_step_data($steps);
103         list($this->qstats, ) = $calculator->calculate(null);
105         // Values expected are taken from contrib/tools/quiz_tools/stats.xls.
106         $facility = array(0, 0, 0, 0, null, null, null, 41.19318182, 81.36363636,
107             71.36363636, 65.45454545, 65.90909091, 36.36363636, 59.09090909, 50,
108             59.09090909, 63.63636364, 45.45454545, 27.27272727, 50);
109         $this->qstats_q_fields('facility', $facility, 100);
110         $sd = array(0, 0, 0, 0, null, null, null, 1912.733589, 251.2738111,
111             322.6312277, 333.4199022, 337.5811591, 492.3659639, 503.2362797,
112             511.7663157, 503.2362797, 492.3659639, 509.6471914, 455.8423058, 511.7663157);
113         $this->qstats_q_fields('sd', $sd, 1000);
114         $effectiveweight = array(0, 0, 0, 0, 0, 0, 0, 26.58464457, 3.368456046,
115             3.253955259, 7.584083694, 3.79658376, 3.183278505, 4.532356904,
116             7.78856243, 10.08351572, 8.381139345, 8.727645713, 7.946277111, 4.769500946);
117         $this->qstats_q_fields('effectiveweight', $effectiveweight);
118         $discriminationindex = array(null, null, null, null, null, null, null,
119             25.88327077, 1.170256965, -4.207816809, 28.16930644, -2.513606859,
120             -12.99017581, -8.900638238, 8.670004606, 29.63337745, 15.18945843,
121             16.21079629, 15.52451404, -8.396734802);
122         $this->qstats_q_fields('discriminationindex', $discriminationindex);
123         $discriminativeefficiency = array(null, null, null, null, null, null, null,
124             27.23492723, 1.382386552, -4.691171307, 31.12404354, -2.877487579,
125             -17.5074184, -10.27568922, 10.86956522, 34.58997279, 17.4790556,
126             20.14359793, 22.06477733, -10);
127         $this->qstats_q_fields('discriminativeefficiency', $discriminativeefficiency);
128     }
130     public function qstats_q_fields($fieldname, $values, $multiplier=1) {
131         foreach ($this->qstats as $qstat) {
132             $value = array_shift($values);
133             if ($value !== null) {
134                 $this->assertEquals($qstat->{$fieldname} * $multiplier,
135                     $value, '', 1E-6);
136             } else {
137                 $this->assertEquals($qstat->{$fieldname} * $multiplier, $value);
138             }
139         }
140     }
142     public function get_fields_from_csv($line) {
143         $line = trim($line);
144         $items = preg_split('!,!', $line);
145         while (list($key) = each($items)) {
146             if ($items[$key]!='') {
147                 if ($start = ($items[$key]{0}=='"')) {
148                     $items[$key] = substr($items[$key], 1);
149                     while (!$end = ($items[$key]{strlen($items[$key])-1}=='"')) {
150                         $item = $items[$key];
151                         unset($items[$key]);
152                         list($key) = each($items);
153                         $items[$key] = $item . ',' . $items[$key];
154                     }
155                     $items[$key] = substr($items[$key], 0, strlen($items[$key])-1);
156                 }
158             }
159         }
160         return $items;
161     }
163     public function get_records_from_csv($filename) {
164         $filecontents = file($filename, FILE_IGNORE_NEW_LINES);
165         $records = array();
166         // Skip the first line containing field names.
167         $keys = $this->get_fields_from_csv(array_shift($filecontents));
168         while (null !== ($line = array_shift($filecontents))) {
169             $data = $this->get_fields_from_csv($line);
170             $arraykey = reset($data);
171             $object = new stdClass();
172             foreach ($keys as $key) {
173                 $value = array_shift($data);
174                 if ($value !== null) {
175                     $object->{$key} = $value;
176                 } else {
177                     $object->{$key} = '';
178                 }
179             }
180             $records[$arraykey] = $object;
181         }
182         return $records;
183     }