MDL-70153 qtype_essay: Add behat test for attachments max size
[moodle.git] / question / engine / tests / questionattempt_with_steps_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  * This file contains tests for the question_attempt class.
19  *
20  * Action methods like start, process_action and finish are assumed to be
21  * tested by walkthrough tests in the various behaviours.
22  *
23  * @package    moodlecore
24  * @subpackage questionengine
25  * @copyright  2009 The Open University
26  * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
27  */
30 defined('MOODLE_INTERNAL') || die();
32 global $CFG;
33 require_once(__DIR__ . '/../lib.php');
34 require_once(__DIR__ . '/helpers.php');
37 /**
38  * These tests use a standard fixture of a {@link question_attempt} with three steps.
39  *
40  * @copyright  2009 The Open University
41  * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
42  */
43 class question_attempt_with_steps_test extends advanced_testcase {
44     private $question;
45     private $qa;
47     protected function setUp(): void {
48         $this->question = test_question_maker::make_question('description');
49         $this->qa = new testable_question_attempt($this->question, 0, null, 2);
50         for ($i = 0; $i < 3; $i++) {
51             $step = new question_attempt_step(array('i' => $i));
52             $this->qa->add_step($step);
53         }
54     }
56     protected function tearDown(): void {
57         $this->qa = null;
58     }
60     public function test_get_step_before_start() {
61         $this->expectException(moodle_exception::class);
62         $step = $this->qa->get_step(-1);
63     }
65     public function test_get_step_at_start() {
66         $step = $this->qa->get_step(0);
67         $this->assertEquals(0, $step->get_qt_var('i'));
68     }
70     public function test_get_step_at_end() {
71         $step = $this->qa->get_step(2);
72         $this->assertEquals(2, $step->get_qt_var('i'));
73     }
75     public function test_get_step_past_end() {
76         $this->expectException(moodle_exception::class);
77         $step = $this->qa->get_step(3);
78     }
80     public function test_get_num_steps() {
81         $this->assertEquals(3, $this->qa->get_num_steps());
82     }
84     public function test_get_last_step() {
85         $step = $this->qa->get_last_step();
86         $this->assertEquals(2, $step->get_qt_var('i'));
87     }
89     public function test_get_last_qt_var_there1() {
90         $this->assertEquals(2, $this->qa->get_last_qt_var('i'));
91     }
93     public function test_get_last_qt_var_there2() {
94         $this->qa->get_step(0)->set_qt_var('_x', 'a value');
95         $this->assertEquals('a value', $this->qa->get_last_qt_var('_x'));
96     }
98     public function test_get_last_qt_var_missing() {
99         $this->assertNull($this->qa->get_last_qt_var('notthere'));
100     }
102     public function test_get_last_qt_var_missing_default() {
103         $this->assertEquals('default', $this->qa->get_last_qt_var('notthere', 'default'));
104     }
106     public function test_get_last_behaviour_var_missing() {
107         $this->assertNull($this->qa->get_last_qt_var('notthere'));
108     }
110     public function test_get_last_behaviour_var_there() {
111         $this->qa->get_step(1)->set_behaviour_var('_x', 'a value');
112         $this->assertEquals('a value', '' . $this->qa->get_last_behaviour_var('_x'));
113     }
115     public function test_get_state_gets_state_of_last() {
116         $this->qa->get_step(2)->set_state(question_state::$gradedright);
117         $this->qa->get_step(1)->set_state(question_state::$gradedwrong);
118         $this->assertEquals(question_state::$gradedright, $this->qa->get_state());
119     }
121     public function test_get_mark_gets_mark_of_last() {
122         $this->assertEquals(2, $this->qa->get_max_mark());
123         $this->qa->get_step(2)->set_fraction(0.5);
124         $this->qa->get_step(1)->set_fraction(0.1);
125         $this->assertEquals(1, $this->qa->get_mark());
126     }
128     public function test_get_fraction_gets_fraction_of_last() {
129         $this->qa->get_step(2)->set_fraction(0.5);
130         $this->qa->get_step(1)->set_fraction(0.1);
131         $this->assertEquals(0.5, $this->qa->get_fraction());
132     }
134     public function test_get_fraction_returns_null_if_none() {
135         $this->assertNull($this->qa->get_fraction());
136     }
138     public function test_format_mark() {
139         $this->qa->get_step(2)->set_fraction(0.5);
140         $this->assertEquals('1.00', $this->qa->format_mark(2));
141     }
143     public function test_format_max_mark() {
144         $this->assertEquals('2.0000000', $this->qa->format_max_mark(7));
145     }
147     public function test_get_min_fraction() {
148         $this->qa->set_min_fraction(-1);
149         $this->assertEquals(-1, $this->qa->get_min_fraction());
150     }
152     public function test_cannot_get_min_fraction_before_start() {
153         $qa = new question_attempt($this->question, 0);
154         $this->expectException('moodle_exception');
155         $qa->get_min_fraction();
156     }
158     public function test_get_max_fraction() {
159         $this->qa->set_max_fraction(2);
160         $this->assertEquals(2, $this->qa->get_max_fraction());
161     }
163     public function test_cannot_get_max_fraction_before_start() {
164         $qa = new question_attempt($this->question, 0);
165         $this->expectException('moodle_exception');
166         $qa->get_max_fraction();
167     }
169     /**
170      * Test cases for {@see test_validate_manual_mark()}.
171      *
172      * @return array test cases
173      */
174     public function validate_manual_mark_cases(): array {
175         // Recall, the DB schema stores question grade information to 7 decimal places.
176         return [
177             [0, 1, 2, null, ''],
178             [0, 1, 2, '', ''],
179             [0, 1, 2, '0', ''],
180             [0, 1, 2, '0.0', ''],
181             [0, 1, 2, '2,0', ''],
182             [0, 1, 2, 'frog', get_string('manualgradeinvalidformat', 'question')],
183             [0, 1, 2, '2.1', get_string('manualgradeoutofrange', 'question')],
184             [0, 1, 2, '-0,01', get_string('manualgradeoutofrange', 'question')],
185             [-0.3333333, 1, 0.75, '0.75', ''],
186             [-0.3333333, 1, 0.75, '0.7500001', get_string('manualgradeoutofrange', 'question')],
187             [-0.3333333, 1, 0.75, '-0.25', ''],
188             [-0.3333333, 1, 0.75, '-0.2500001', get_string('manualgradeoutofrange', 'question')],
189         ];
190     }
192     /**
193      * Test validate_manual_mark.
194      *
195      * @dataProvider validate_manual_mark_cases
196      *
197      * @param float $minfraction minimum fraction for the question being attempted.
198      * @param float $maxfraction maximum fraction for the question being attempted.
199      * @param float $maxmark marks for the question attempt.
200      * @param string|null $currentmark submitted mark.
201      * @param string $expectederror expected error, if any.
202      */
203     public function test_validate_manual_mark(float $minfraction, float $maxfraction,
204             float $maxmark, ?string $currentmark, string $expectederror) {
205         $this->qa->set_min_fraction($minfraction);
206         $this->qa->set_max_fraction($maxfraction);
207         $this->qa->set_max_mark($maxmark);
208         $this->assertSame($expectederror, $this->qa->validate_manual_mark($currentmark));
209     }