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/>.
16
17
18/**
19 * Unit tests for the calculated question definition class.
20 *
21 * @package    qtype
22 * @subpackage calculated
23 * @copyright  2011 The Open University
24 * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
25 */
26
27defined('MOODLE_INTERNAL') || die();
28
29global $CFG;
30require_once($CFG->dirroot . '/question/engine/tests/helpers.php');
31
32
33/**
34 * Unit tests for qtype_calculated_definition.
35 *
36 * @copyright  2011 The Open University
37 * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
38 */
39class qtype_calculated_question_test extends advanced_testcase {
40    public function test_is_complete_response() {
41        $question = test_question_maker::make_question('calculated');
42
43        $this->assertFalse($question->is_complete_response(array()));
44        $this->assertTrue($question->is_complete_response(array('answer' => '0')));
45        $this->assertTrue($question->is_complete_response(array('answer' => 0)));
46        $this->assertFalse($question->is_complete_response(array('answer' => 'test')));
47    }
48
49    public function test_is_gradable_response() {
50        $question = test_question_maker::make_question('calculated');
51
52        $this->assertFalse($question->is_gradable_response(array()));
53        $this->assertTrue($question->is_gradable_response(array('answer' => '0')));
54        $this->assertTrue($question->is_gradable_response(array('answer' => 0)));
55        $this->assertTrue($question->is_gradable_response(array('answer' => 'test')));
56    }
57
58    public function test_grading() {
59        $question = test_question_maker::make_question('calculated');
60        $question->start_attempt(new question_attempt_step(), 1);
61        $values = $question->vs->get_values();
62
63        $this->assertEquals(array(0, question_state::$gradedwrong),
64                $question->grade_response(array('answer' => $values['a'] - $values['b'])));
65        $this->assertEquals(array(1, question_state::$gradedright),
66                $question->grade_response(array('answer' => $values['a'] + $values['b'])));
67    }
68
69    public function test_get_correct_response() {
70        // Testing with 3.0 + 0.1416.
71        $question = test_question_maker::make_question('calculated');
72        $question->start_attempt(new question_attempt_step(), 3);
73        $values = $question->vs->get_values();
74        $this->assertSame(array('answer' => '3.01' ), $question->get_correct_response());
75        foreach ($question->answers as $answer) {
76            $answer->correctanswerlength = 2;
77            $answer->correctanswerformat = 2;
78        }
79        $this->assertSame(array('answer' => '3.0' ), $question->get_correct_response());
80
81        // Testing with 1.0 + 5.0.
82        $question = test_question_maker::make_question('calculated');
83        $question->start_attempt(new question_attempt_step(), 1);
84        $values = $question->vs->get_values();
85        $this->assertSame(array('answer' => '6.00' ), $question->get_correct_response());
86
87        foreach ($question->answers as $answer) {
88            $answer->correctanswerlength = 2;
89            $answer->correctanswerformat = 2;
90        }
91        $this->assertSame(array('answer' => '6.0' ),
92                $question->get_correct_response());
93        // Testing with 31.0 + 0.01416 .
94        $question = test_question_maker::make_question('calculated');
95        $question->start_attempt(new question_attempt_step(), 4);
96        $values = $question->vs->get_values();
97        $this->assertSame(array('answer' => '31.01' ), $question->get_correct_response());
98
99        foreach ($question->answers as $answer) {
100            $answer->correctanswerlength = 3;
101            $answer->correctanswerformat = 2;
102        }
103        $this->assertSame(array('answer' => '31.0' ), $question->get_correct_response());
104
105    }
106
107    public function test_get_question_summary() {
108        $question = test_question_maker::make_question('calculated');
109        $question->start_attempt(new question_attempt_step(), 1);
110        $values = $question->vs->get_values();
111
112        $qsummary = $question->get_question_summary();
113        $this->assertEquals('What is ' . $values['a'] . ' + ' . $values['b'] . '?', $qsummary);
114    }
115
116    public function test_summarise_response() {
117        $question = test_question_maker::make_question('calculated');
118        $question->start_attempt(new question_attempt_step(), 1);
119        $values = $question->vs->get_values();
120
121        $this->assertEquals('3.1', $question->summarise_response(array('answer' => '3.1')));
122    }
123
124    public function test_classify_response() {
125        $question = test_question_maker::make_question('calculated');
126        $question->start_attempt(new question_attempt_step(), 1);
127        $values = $question->vs->get_values();
128
129        $this->assertEquals(array(
130                new question_classified_response(13, $values['a'] + $values['b'], 1.0)),
131                $question->classify_response(array('answer' => $values['a'] + $values['b'])));
132        $this->assertEquals(array(
133                new question_classified_response(14, $values['a'] - $values['b'], 0.0)),
134                $question->classify_response(array('answer' => $values['a'] - $values['b'])));
135        $this->assertEquals(array(
136                new question_classified_response(17, 7 * $values['a'], 0.0)),
137                $question->classify_response(array('answer' => 7 * $values['a'])));
138        $this->assertEquals(array(
139                question_classified_response::no_response()),
140                $question->classify_response(array('answer' => '')));
141    }
142
143    public function test_classify_response_no_star() {
144        $question = test_question_maker::make_question('calculated');
145        unset($question->answers[17]);
146        $question->start_attempt(new question_attempt_step(), 1);
147        $values = $question->vs->get_values();
148
149        $this->assertEquals(array(
150                new question_classified_response(13, $values['a'] + $values['b'], 1.0)),
151                $question->classify_response(array('answer' => $values['a'] + $values['b'])));
152        $this->assertEquals(array(
153                new question_classified_response(14, $values['a'] - $values['b'], 0.0)),
154                $question->classify_response(array('answer' => $values['a'] - $values['b'])));
155        $this->assertEquals(array(
156                new question_classified_response(0, 7 * $values['a'], 0.0)),
157                $question->classify_response(array('answer' => 7 * $values['a'])));
158        $this->assertEquals(array(
159                question_classified_response::no_response()),
160                $question->classify_response(array('answer' => '')));
161    }
162
163    public function test_get_variants_selection_seed_q_not_synchronised() {
164        $question = test_question_maker::make_question('calculated');
165        $this->assertEquals($question->stamp, $question->get_variants_selection_seed());
166    }
167
168    public function test_get_variants_selection_seed_q_synchronised_datasets_not() {
169        $question = test_question_maker::make_question('calculated');
170        $question->synchronised = true;
171        $this->assertEquals($question->stamp, $question->get_variants_selection_seed());
172    }
173
174    public function test_get_variants_selection_seed_q_synchronised() {
175        $question = test_question_maker::make_question('calculated');
176        $question->synchronised = true;
177        $question->datasetloader->set_are_synchronised($question->category, true);
178        $this->assertEquals('category' . $question->category,
179                $question->get_variants_selection_seed());
180    }
181
182    /**
183     * test_get_question_definition_for_external_rendering
184     */
185    public function test_get_question_definition_for_external_rendering() {
186        $this->resetAfterTest();
187
188        $question = test_question_maker::make_question('calculated');
189        $question->start_attempt(new question_attempt_step(), 1);
190        $qa = test_question_maker::get_a_qa($question);
191        $displayoptions = new question_display_options();
192
193        $options = $question->get_question_definition_for_external_rendering($qa, $displayoptions);
194        $this->assertNotEmpty($options);
195        $this->assertEquals(0, $options['unitgradingtype']);
196        $this->assertEquals(0, $options['unitpenalty']);
197        $this->assertEquals(qtype_numerical::UNITNONE, $options['unitdisplay']);
198        $this->assertEmpty($options['unitsleft']);
199    }
200}
201