Differences Between: [Versions 310 and 400] [Versions 39 and 400]
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 namespace qbehaviour_adaptive; 18 19 use question_state; 20 21 defined('MOODLE_INTERNAL') || die(); 22 23 global $CFG; 24 require_once (__DIR__ . '/../../../engine/lib.php'); 25 require_once (__DIR__ . '/../../../engine/tests/helpers.php'); 26 27 28 /** 29 * Unit tests for the adaptive behaviour. 30 * 31 * @package qbehaviour_adaptive 32 * @copyright 2009 The Open University 33 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 34 */ 35 class walkthrough_test extends \qbehaviour_walkthrough_test_base { 36 protected function get_contains_penalty_info_expectation($penalty) { 37 $penaltyinfo = get_string('gradingdetailspenalty', 'qbehaviour_adaptive', 38 format_float($penalty, $this->displayoptions->markdp)); 39 return new \question_pattern_expectation('/'.preg_quote($penaltyinfo, '/').'/'); 40 } 41 42 protected function get_does_not_contain_penalty_info_expectation() { 43 $penaltyinfo = get_string('gradingdetailspenalty', 'qbehaviour_adaptive', 'XXXXX'); 44 $penaltypattern = '/'.str_replace('XXXXX', '\\w*', preg_quote($penaltyinfo, '/')).'/'; 45 return new \question_no_pattern_expectation($penaltypattern); 46 } 47 48 protected function get_contains_total_penalty_expectation($penalty) { 49 $penaltyinfo = get_string('gradingdetailspenaltytotal', 'qbehaviour_adaptive', 50 format_float($penalty, $this->displayoptions->markdp)); 51 return new \question_pattern_expectation('/'.preg_quote($penaltyinfo, '/').'/'); 52 } 53 54 protected function get_does_not_contain_total_penalty_expectation() { 55 $penaltyinfo = get_string('gradingdetailspenaltytotal', 'qbehaviour_adaptive', 'XXXXX'); 56 $penaltypattern = '/'.str_replace('XXXXX', '\\w*', preg_quote($penaltyinfo, '/')).'/'; 57 return new \question_no_pattern_expectation($penaltypattern); 58 } 59 60 protected function get_contains_disregarded_info_expectation() { 61 $penaltyinfo = get_string('disregardedwithoutpenalty', 'qbehaviour_adaptive'); 62 return new \question_pattern_expectation('/'.preg_quote($penaltyinfo, '/').'/'); 63 } 64 65 protected function get_does_not_contain_disregarded_info_expectation() { 66 $penaltyinfo = get_string('disregardedwithoutpenalty', 'qbehaviour_adaptive'); 67 return new \question_no_pattern_expectation('/'.preg_quote($penaltyinfo, '/').'/'); 68 } 69 70 public function test_adaptive_multichoice() { 71 72 // Create a multiple choice, single response question. 73 $mc = \test_question_maker::make_a_multichoice_single_question(); 74 $mc->penalty = 0.3333333; 75 $this->start_attempt_at_question($mc, 'adaptive', 3); 76 77 $rightindex = $this->get_mc_right_answer_index($mc); 78 $wrongindex = ($rightindex + 1) % 3; 79 80 // Check the initial state. 81 $this->check_current_state(question_state::$todo); 82 $this->check_current_mark(null); 83 $this->check_current_output( 84 $this->get_contains_marked_out_of_summary(), 85 $this->get_contains_question_text_expectation($mc), 86 $this->get_contains_mc_radio_expectation(0, true, false), 87 $this->get_contains_mc_radio_expectation(1, true, false), 88 $this->get_contains_mc_radio_expectation(2, true, false), 89 $this->get_contains_submit_button_expectation(true), 90 $this->get_does_not_contain_feedback_expectation()); 91 92 // Process a submit. 93 $this->process_submission(array('answer' => $wrongindex, '-submit' => 1)); 94 95 // Verify. 96 $this->check_current_state(question_state::$todo); 97 $this->check_current_mark(0); 98 $this->check_current_output( 99 $this->get_contains_mark_summary(0), 100 $this->get_contains_mc_radio_expectation($wrongindex, true, true), 101 $this->get_contains_mc_radio_expectation(($wrongindex + 1) % 3, true, false), 102 $this->get_contains_mc_radio_expectation(($wrongindex + 2) % 3, true, false), 103 $this->get_contains_incorrect_expectation(), 104 $this->get_contains_penalty_info_expectation(1.00), 105 $this->get_does_not_contain_total_penalty_expectation()); 106 $this->assertMatchesRegularExpression('/B|C/', 107 $this->quba->get_response_summary($this->slot)); 108 109 // Process a change of answer to the right one, but not sumbitted. 110 $this->process_submission(array('answer' => $rightindex)); 111 112 // Verify. 113 $this->check_current_state(question_state::$todo); 114 $this->check_current_mark(0); 115 $this->check_current_output( 116 $this->get_contains_mark_summary(0), 117 $this->get_contains_mc_radio_expectation($rightindex, true, true), 118 $this->get_contains_mc_radio_expectation(($rightindex + 1) % 3, true, false), 119 $this->get_contains_mc_radio_expectation(($rightindex + 2) % 3, true, false)); 120 $this->assertMatchesRegularExpression('/B|C/', 121 $this->quba->get_response_summary($this->slot)); 122 123 // Now submit the right answer. 124 $this->process_submission(array('answer' => $rightindex, '-submit' => 1)); 125 126 // Verify. 127 $this->check_current_state(question_state::$complete); 128 $this->check_current_mark(3 * (1 - $mc->penalty)); 129 $this->check_current_output( 130 $this->get_contains_mark_summary(3 * (1 - $mc->penalty)), 131 $this->get_contains_mc_radio_expectation($rightindex, true, true), 132 $this->get_contains_mc_radio_expectation(($rightindex + 1) % 3, true, false), 133 $this->get_contains_mc_radio_expectation(($rightindex + 2) % 3, true, false), 134 $this->get_contains_correct_expectation(), 135 $this->get_does_not_contain_penalty_info_expectation(), 136 $this->get_does_not_contain_total_penalty_expectation()); 137 $this->assertEquals('A', 138 $this->quba->get_response_summary($this->slot)); 139 140 // Finish the attempt. 141 $this->quba->finish_all_questions(); 142 143 // Verify. 144 $this->check_current_state(question_state::$gradedright); 145 $this->check_current_mark(3 * (1 - $mc->penalty)); 146 $this->check_current_output( 147 $this->get_contains_mark_summary(3 * (1 - $mc->penalty)), 148 $this->get_contains_mc_radio_expectation($rightindex, false, true), 149 $this->get_contains_mc_radio_expectation(($rightindex + 1) % 3, false, false), 150 $this->get_contains_mc_radio_expectation(($rightindex + 2) % 3, false, false), 151 $this->get_contains_correct_expectation()); 152 153 // Process a manual comment. 154 $this->manual_grade('Not good enough!', 1, FORMAT_HTML); 155 156 // Verify. 157 $this->check_current_state(question_state::$mangrpartial); 158 $this->check_current_mark(1); 159 $this->check_current_output( 160 $this->get_contains_mark_summary(1), 161 new \question_pattern_expectation('/' . preg_quote('Not good enough!', '/') . '/')); 162 163 // Now change the correct answer to the question, and regrade. 164 $mc->answers[13]->fraction = -0.33333333; 165 $mc->answers[14]->fraction = 1; // We don't know which "wrong" index we chose above! 166 $mc->answers[15]->fraction = 1; // Therefore, treat answers B and C with the same score. 167 $this->quba->regrade_all_questions(); 168 169 // Verify. 170 $this->check_current_state(question_state::$mangrpartial); 171 $this->check_current_mark(1); 172 $this->check_current_output( 173 $this->get_contains_mark_summary(1), 174 $this->get_contains_partcorrect_expectation()); 175 176 $autogradedstep = $this->get_step($this->get_step_count() - 2); 177 $this->assertEqualsWithDelta($autogradedstep->get_fraction(), 1, 0.0000001); 178 } 179 180 public function test_adaptive_multichoice2() { 181 182 // Create a multiple choice, multiple response question. 183 $mc = \test_question_maker::make_a_multichoice_multi_question(); 184 $mc->penalty = 0.3333333; 185 $mc->shuffleanswers = 0; 186 $this->start_attempt_at_question($mc, 'adaptive', 2); 187 188 // Check the initial state. 189 $this->check_current_state(question_state::$todo); 190 $this->check_current_mark(null); 191 $this->check_current_output( 192 $this->get_contains_marked_out_of_summary(), 193 $this->get_contains_question_text_expectation($mc), 194 $this->get_contains_submit_button_expectation(true), 195 $this->get_does_not_contain_feedback_expectation()); 196 197 // Process a submit. 198 $this->process_submission(array('choice0' => 1, 'choice2' => 1, '-submit' => 1)); 199 200 // Verify. 201 $this->check_current_state(question_state::$complete); 202 $this->check_current_mark(2); 203 $this->check_current_output( 204 $this->get_contains_mark_summary(2), 205 $this->get_contains_submit_button_expectation(true), 206 $this->get_contains_correct_expectation(), 207 $this->get_does_not_contain_penalty_info_expectation(), 208 $this->get_does_not_contain_total_penalty_expectation()); 209 210 // Save the same correct answer again. Should not do anything. 211 $numsteps = $this->get_step_count(); 212 $this->process_submission(array('choice0' => 1, 'choice2' => 1)); 213 214 // Verify. 215 $this->check_step_count($numsteps); 216 $this->check_current_mark(2); 217 $this->check_current_state(question_state::$complete); 218 219 // Finish the attempt. 220 $this->quba->finish_all_questions(); 221 222 // Verify. 223 $this->check_step_count($numsteps + 1); 224 $this->check_current_state(question_state::$gradedright); 225 $this->check_current_mark(2); 226 $this->check_current_output( 227 $this->get_contains_mark_summary(2), 228 $this->get_does_not_contain_submit_button_expectation(), 229 $this->get_contains_correct_expectation()); 230 } 231 232 public function test_adaptive_shortanswer_partially_right() { 233 234 // Create a short answer question. 235 $sa = \test_question_maker::make_question('shortanswer'); 236 $this->start_attempt_at_question($sa, 'adaptive'); 237 238 // Check the initial state. 239 $this->check_current_state(question_state::$todo); 240 $this->check_current_mark(null); 241 $this->render(); 242 $this->check_output_does_not_contain_text_input_with_class('answer', 'correct'); 243 $this->check_output_does_not_contain_text_input_with_class('answer', 'partiallycorrect'); 244 $this->check_output_does_not_contain_text_input_with_class('answer', 'incorrect'); 245 $this->check_current_output( 246 $this->get_contains_marked_out_of_summary(), 247 $this->get_contains_submit_button_expectation(true), 248 $this->get_does_not_contain_feedback_expectation()); 249 250 // Submit a partially correct answer. 251 $this->process_submission(array('-submit' => 1, 'answer' => 'toad')); 252 253 // Verify. 254 $this->check_current_state(question_state::$todo); 255 $this->check_current_mark(0.8); 256 $this->render(); 257 $this->check_output_contains_text_input_with_class('answer', 'partiallycorrect'); 258 $this->check_current_output( 259 $this->get_contains_mark_summary(0.8), 260 $this->get_contains_submit_button_expectation(true), 261 $this->get_contains_partcorrect_expectation(), 262 $this->get_contains_penalty_info_expectation(0.33), 263 $this->get_does_not_contain_total_penalty_expectation(), 264 $this->get_does_not_contain_validation_error_expectation()); 265 266 // Submit an incorrect answer. 267 $this->process_submission(array('-submit' => 1, 'answer' => 'bumblebee')); 268 269 // Verify. 270 $this->check_current_state(question_state::$todo); 271 $this->check_current_mark(0.8); 272 $this->render(); 273 $this->check_output_contains_text_input_with_class('answer', 'incorrect'); 274 $this->check_current_output( 275 $this->get_contains_mark_summary(0.8), 276 $this->get_contains_submit_button_expectation(true), 277 $this->get_contains_incorrect_expectation(), 278 $this->get_contains_penalty_info_expectation(0.33), 279 $this->get_contains_total_penalty_expectation(0.67), 280 $this->get_does_not_contain_validation_error_expectation()); 281 282 // Submit a correct answer. 283 $this->process_submission(array('-submit' => 1, 'answer' => 'frog')); 284 285 // Verify. 286 $this->check_current_state(question_state::$complete); 287 $this->check_current_mark(0.8); 288 $this->render(); 289 $this->check_output_contains_text_input_with_class('answer', 'correct'); 290 $this->check_current_output( 291 $this->get_contains_mark_summary(0.8), 292 $this->get_contains_submit_button_expectation(true), 293 $this->get_contains_correct_expectation(), 294 $this->get_does_not_contain_penalty_info_expectation(), 295 $this->get_does_not_contain_total_penalty_expectation(), 296 $this->get_does_not_contain_validation_error_expectation()); 297 298 // Finish the attempt. 299 $this->quba->finish_all_questions(); 300 301 // Verify. 302 $this->check_current_state(question_state::$gradedright); 303 $this->check_current_mark(0.8); 304 $this->check_current_output( 305 $this->get_contains_mark_summary(0.8), 306 $this->get_does_not_contain_submit_button_expectation(), 307 $this->get_contains_correct_expectation(), 308 $this->get_does_not_contain_validation_error_expectation()); 309 } 310 311 public function test_adaptive_shortanswer_wrong_right_wrong() { 312 313 // Create a short answer question. 314 $sa = \test_question_maker::make_question('shortanswer'); 315 $this->start_attempt_at_question($sa, 'adaptive', 6); 316 317 // Check the initial state. 318 $this->check_current_state(question_state::$todo); 319 $this->check_current_mark(null); 320 $this->check_current_output( 321 $this->get_contains_marked_out_of_summary(), 322 $this->get_contains_submit_button_expectation(true), 323 $this->get_does_not_contain_feedback_expectation()); 324 325 // Submit a wrong answer. 326 $this->process_submission(array('-submit' => 1, 'answer' => 'hippopotamus')); 327 328 // Verify. 329 $this->check_current_state(question_state::$todo); 330 $this->check_current_mark(0); 331 $this->check_current_output( 332 $this->get_contains_mark_summary(0), 333 $this->get_contains_submit_button_expectation(true), 334 $this->get_contains_incorrect_expectation(), 335 $this->get_contains_penalty_info_expectation(2.00), 336 $this->get_does_not_contain_total_penalty_expectation(), 337 $this->get_does_not_contain_validation_error_expectation()); 338 339 // Submit the same wrong answer again. Nothing should change. 340 $this->process_submission(array('-submit' => 1, 'answer' => 'hippopotamus')); 341 342 // Verify. 343 $this->check_current_state(question_state::$todo); 344 $this->check_current_mark(0); 345 $this->check_current_output( 346 $this->get_contains_mark_summary(0), 347 $this->get_contains_submit_button_expectation(true), 348 $this->get_contains_incorrect_expectation(), 349 $this->get_contains_penalty_info_expectation(2.00), 350 $this->get_does_not_contain_total_penalty_expectation(), 351 $this->get_does_not_contain_validation_error_expectation()); 352 353 // Submit a correct answer. 354 $this->process_submission(array('-submit' => 1, 'answer' => 'frog')); 355 356 // Verify. 357 $this->check_current_state(question_state::$complete); 358 $this->check_current_mark(4.00); 359 $this->check_current_output( 360 $this->get_contains_mark_summary(4.00), 361 $this->get_contains_submit_button_expectation(true), 362 $this->get_contains_correct_expectation(), 363 $this->get_does_not_contain_penalty_info_expectation(), 364 $this->get_does_not_contain_total_penalty_expectation(), 365 $this->get_does_not_contain_validation_error_expectation()); 366 367 // Submit another incorrect answer. 368 $this->process_submission(array('-submit' => 1, 'answer' => 'bumblebee')); 369 370 // Verify. 371 $this->check_current_state(question_state::$complete); 372 $this->check_current_mark(4.00); 373 $this->check_current_output( 374 $this->get_contains_mark_summary(4.00), 375 $this->get_contains_submit_button_expectation(true), 376 $this->get_contains_incorrect_expectation(), 377 $this->get_does_not_contain_penalty_info_expectation(), 378 $this->get_does_not_contain_total_penalty_expectation(), 379 $this->get_does_not_contain_validation_error_expectation()); 380 381 // Finish the attempt. 382 $this->quba->finish_all_questions(); 383 384 // Verify. 385 $this->check_current_state(question_state::$gradedwrong); 386 $this->check_current_mark(4.00); 387 $this->check_current_output( 388 $this->get_contains_mark_summary(4.00), 389 $this->get_does_not_contain_submit_button_expectation(), 390 $this->get_contains_incorrect_expectation(), 391 $this->get_does_not_contain_validation_error_expectation()); 392 } 393 394 public function test_adaptive_shortanswer_invalid_after_complete() { 395 396 // Create a short answer question. 397 $sa = \test_question_maker::make_question('shortanswer'); 398 $this->start_attempt_at_question($sa, 'adaptive'); 399 400 // Check the initial state. 401 $this->check_current_state(question_state::$todo); 402 $this->check_current_mark(null); 403 $this->check_current_output( 404 $this->get_contains_marked_out_of_summary(), 405 $this->get_contains_submit_button_expectation(true), 406 $this->get_does_not_contain_feedback_expectation()); 407 408 // Submit a wrong answer. 409 $this->process_submission(array('-submit' => 1, 'answer' => 'hippopotamus')); 410 411 // Verify. 412 $this->check_current_state(question_state::$todo); 413 $this->check_current_mark(0); 414 $this->check_current_output( 415 $this->get_contains_mark_summary(0), 416 $this->get_contains_submit_button_expectation(true), 417 $this->get_contains_incorrect_expectation(), 418 $this->get_contains_penalty_info_expectation(0.33), 419 $this->get_does_not_contain_total_penalty_expectation(), 420 $this->get_does_not_contain_validation_error_expectation()); 421 422 // Submit a correct answer. 423 $this->process_submission(array('-submit' => 1, 'answer' => 'frog')); 424 425 // Verify. 426 $this->check_current_state(question_state::$complete); 427 $this->check_current_mark(0.66666667); 428 $this->check_current_output( 429 $this->get_contains_mark_summary(0.67), 430 $this->get_contains_submit_button_expectation(true), 431 $this->get_contains_correct_expectation(), 432 $this->get_does_not_contain_penalty_info_expectation(), 433 $this->get_does_not_contain_total_penalty_expectation(), 434 $this->get_does_not_contain_validation_error_expectation()); 435 436 // Submit an empty answer. 437 $this->process_submission(array('-submit' => 1, 'answer' => '')); 438 439 // Verify. 440 $this->check_current_state(question_state::$invalid); 441 $this->check_current_mark(0.66666667); 442 $this->check_current_output( 443 $this->get_contains_mark_summary(0.67), 444 $this->get_contains_submit_button_expectation(true), 445 $this->get_does_not_contain_penalty_info_expectation(), 446 $this->get_does_not_contain_total_penalty_expectation(), 447 $this->get_contains_validation_error_expectation()); 448 449 // Submit another wrong answer. 450 $this->process_submission(array('-submit' => 1, 'answer' => 'bumblebee')); 451 452 // Verify. 453 $this->check_current_state(question_state::$complete); 454 $this->check_current_mark(0.66666667); 455 $this->check_current_output( 456 $this->get_contains_mark_summary(0.67), 457 $this->get_contains_submit_button_expectation(true), 458 $this->get_contains_incorrect_expectation(), 459 $this->get_does_not_contain_penalty_info_expectation(), 460 $this->get_does_not_contain_total_penalty_expectation(), 461 $this->get_does_not_contain_validation_error_expectation()); 462 463 // Finish the attempt. 464 $this->quba->finish_all_questions(); 465 466 // Verify. 467 $this->check_current_state(question_state::$gradedwrong); 468 $this->check_current_mark(0.66666667); 469 $this->check_current_output( 470 $this->get_contains_mark_summary(0.67), 471 $this->get_does_not_contain_submit_button_expectation(), 472 $this->get_contains_incorrect_expectation(), 473 $this->get_does_not_contain_validation_error_expectation()); 474 } 475 476 public function test_adaptive_shortanswer_zero_penalty() { 477 478 // Create a short answer question. 479 $sa = \test_question_maker::make_question('shortanswer'); 480 // Disable penalties for this question. 481 $sa->penalty = 0; 482 $this->start_attempt_at_question($sa, 'adaptive'); 483 484 // Check the initial state. 485 $this->check_current_state(question_state::$todo); 486 $this->check_current_mark(null); 487 $this->check_current_output( 488 $this->get_contains_marked_out_of_summary(), 489 $this->get_contains_submit_button_expectation(true), 490 $this->get_does_not_contain_feedback_expectation()); 491 492 // Submit a wrong answer. 493 $this->process_submission(array('-submit' => 1, 'answer' => 'hippopotamus')); 494 495 // Verify. 496 $this->check_current_state(question_state::$todo); 497 $this->check_current_mark(0); 498 $this->check_current_output( 499 $this->get_contains_mark_summary(0), 500 $this->get_contains_submit_button_expectation(true), 501 $this->get_contains_incorrect_expectation(), 502 $this->get_does_not_contain_penalty_info_expectation(), 503 $this->get_does_not_contain_total_penalty_expectation(), 504 $this->get_does_not_contain_validation_error_expectation()); 505 506 // Submit a correct answer. 507 $this->process_submission(array('-submit' => 1, 'answer' => 'frog')); 508 509 // Verify. 510 $this->check_current_state(question_state::$complete); 511 $this->check_current_mark(1.0); 512 $this->check_current_output( 513 $this->get_contains_mark_summary(1.0), 514 $this->get_contains_submit_button_expectation(true), 515 $this->get_contains_correct_expectation(), 516 $this->get_does_not_contain_penalty_info_expectation(), 517 $this->get_does_not_contain_total_penalty_expectation(), 518 $this->get_does_not_contain_validation_error_expectation()); 519 520 // Finish the attempt. 521 $this->quba->finish_all_questions(); 522 523 // Verify. 524 $this->check_current_state(question_state::$gradedright); 525 $this->check_current_mark(1.0); 526 $this->check_current_output( 527 $this->get_contains_mark_summary(1.0), 528 $this->get_does_not_contain_submit_button_expectation(), 529 $this->get_contains_correct_expectation(), 530 $this->get_does_not_contain_validation_error_expectation()); 531 } 532 533 public function test_adaptive_shortanswer_try_to_submit_blank() { 534 535 // Create a short answer question with correct answer true. 536 $sa = \test_question_maker::make_question('shortanswer'); 537 $this->start_attempt_at_question($sa, 'adaptive'); 538 539 // Check the initial state. 540 $this->check_current_state(question_state::$todo); 541 $this->check_current_mark(null); 542 $this->check_current_output( 543 $this->get_contains_marked_out_of_summary(), 544 $this->get_contains_submit_button_expectation(true), 545 $this->get_does_not_contain_feedback_expectation()); 546 547 // Submit with blank answer. 548 $this->process_submission(array('-submit' => 1, 'answer' => '')); 549 550 // Verify. 551 $this->check_current_state(question_state::$invalid); 552 $this->check_current_mark(null); 553 $this->check_current_output( 554 $this->get_contains_marked_out_of_summary(), 555 $this->get_contains_submit_button_expectation(true), 556 $this->get_does_not_contain_correctness_expectation(), 557 $this->get_does_not_contain_penalty_info_expectation(), 558 $this->get_does_not_contain_total_penalty_expectation(), 559 $this->get_contains_validation_error_expectation(), 560 $this->get_contains_disregarded_info_expectation()); 561 $this->assertNull($this->quba->get_response_summary($this->slot)); 562 563 // Now get it wrong. 564 $this->process_submission(array('-submit' => 1, 'answer' => 'toad')); 565 566 // Verify. 567 $this->check_current_state(question_state::$todo); 568 $this->check_current_mark(0.8); 569 $this->check_current_output( 570 $this->get_contains_mark_summary(0.8), 571 $this->get_contains_submit_button_expectation(true), 572 $this->get_contains_partcorrect_expectation(), 573 $this->get_contains_penalty_info_expectation(0.33), 574 $this->get_does_not_contain_total_penalty_expectation(), 575 $this->get_does_not_contain_validation_error_expectation()); 576 577 // Now submit blank again. 578 $this->process_submission(array('-submit' => 1, 'answer' => '')); 579 580 // Verify. 581 $this->check_current_state(question_state::$invalid); 582 $this->check_current_mark(0.8); 583 $this->check_current_output( 584 $this->get_contains_mark_summary(0.8), 585 $this->get_contains_submit_button_expectation(true), 586 $this->get_does_not_contain_correctness_expectation(), 587 $this->get_does_not_contain_penalty_info_expectation(), 588 $this->get_does_not_contain_total_penalty_expectation(), 589 $this->get_contains_validation_error_expectation()); 590 } 591 592 public function test_adaptive_numerical() { 593 594 // Create a numerical question. 595 $sa = \test_question_maker::make_question('numerical', 'pi'); 596 $this->start_attempt_at_question($sa, 'adaptive'); 597 598 // Check the initial state. 599 $this->check_current_state(question_state::$todo); 600 $this->check_current_mark(null); 601 $this->check_current_output( 602 $this->get_contains_marked_out_of_summary(), 603 $this->get_contains_submit_button_expectation(true), 604 $this->get_does_not_contain_feedback_expectation()); 605 606 // Submit the correct answer. 607 $this->process_submission(array('-submit' => 1, 'answer' => '3.14')); 608 609 // Verify. 610 $this->check_current_state(question_state::$complete); 611 $this->check_current_mark(1); 612 $this->check_current_output( 613 $this->get_contains_mark_summary(1), 614 $this->get_contains_submit_button_expectation(true), 615 $this->get_contains_correct_expectation(), 616 $this->get_does_not_contain_penalty_info_expectation(), 617 $this->get_does_not_contain_total_penalty_expectation(), 618 $this->get_does_not_contain_validation_error_expectation()); 619 620 // Submit an incorrect answer. 621 $this->process_submission(array('-submit' => 1, 'answer' => '-5')); 622 623 // Verify. 624 $this->check_current_state(question_state::$complete); 625 $this->check_current_mark(1); 626 $this->check_current_output( 627 $this->get_contains_mark_summary(1), 628 $this->get_contains_submit_button_expectation(true), 629 $this->get_contains_incorrect_expectation(), 630 $this->get_does_not_contain_penalty_info_expectation(), 631 $this->get_does_not_contain_total_penalty_expectation(), 632 $this->get_does_not_contain_validation_error_expectation()); 633 634 // Finish the attempt. 635 $this->quba->finish_all_questions(); 636 637 // Verify. 638 $this->check_current_state(question_state::$gradedwrong); 639 $this->check_current_mark(1); 640 $this->check_current_output( 641 $this->get_contains_mark_summary(1), 642 $this->get_does_not_contain_submit_button_expectation(), 643 $this->get_contains_incorrect_expectation(), 644 $this->get_does_not_contain_validation_error_expectation()); 645 } 646 647 public function test_adaptive_numerical_invalid() { 648 649 // Create a numerical question. 650 $numq = \test_question_maker::make_question('numerical', 'pi'); 651 $numq->penalty = 0.1; 652 $this->start_attempt_at_question($numq, 'adaptive'); 653 654 // Check the initial state. 655 $this->check_current_state(question_state::$todo); 656 $this->check_current_mark(null); 657 $this->check_current_output( 658 $this->get_contains_marked_out_of_summary(), 659 $this->get_contains_submit_button_expectation(true), 660 $this->get_does_not_contain_feedback_expectation()); 661 662 // Submit a non-numerical answer. 663 $this->process_submission(array('-submit' => 1, 'answer' => 'Pi')); 664 665 // Verify. 666 $this->check_current_state(question_state::$invalid); 667 $this->check_current_mark(null); 668 $this->check_current_output( 669 $this->get_contains_marked_out_of_summary(1), 670 $this->get_contains_submit_button_expectation(true), 671 $this->get_does_not_contain_correctness_expectation(), 672 $this->get_does_not_contain_penalty_info_expectation(), 673 $this->get_does_not_contain_total_penalty_expectation(), 674 $this->get_contains_validation_error_expectation(), 675 $this->get_contains_disregarded_info_expectation()); 676 677 // Submit an incorrect answer. 678 $this->process_submission(array('-submit' => 1, 'answer' => '-5')); 679 680 // Verify. 681 $this->check_current_state(question_state::$todo); 682 $this->check_current_mark(0); 683 $this->check_current_output( 684 $this->get_contains_mark_summary(0), 685 $this->get_contains_submit_button_expectation(true), 686 $this->get_contains_incorrect_expectation(), 687 $this->get_contains_penalty_info_expectation(0.1), 688 $this->get_does_not_contain_total_penalty_expectation(), 689 $this->get_does_not_contain_validation_error_expectation(), 690 $this->get_does_not_contain_disregarded_info_expectation()); 691 692 // Submit another non-numerical answer. 693 $this->process_submission(array('-submit' => 1, 'answer' => 'Pi*2')); 694 695 // Verify. 696 $this->check_current_state(question_state::$invalid); 697 $this->check_current_mark(0); 698 $this->check_current_output( 699 $this->get_contains_mark_summary(0), 700 $this->get_contains_submit_button_expectation(true), 701 $this->get_does_not_contain_correctness_expectation(), 702 $this->get_does_not_contain_penalty_info_expectation(), 703 $this->get_does_not_contain_total_penalty_expectation(), 704 $this->get_contains_validation_error_expectation(), 705 $this->get_contains_disregarded_info_expectation()); 706 707 // Submit the correct answer. 708 $this->process_submission(array('-submit' => 1, 'answer' => '3.14')); 709 710 // Verify. 711 $this->check_current_state(question_state::$complete); 712 $this->check_current_mark(0.9); 713 $this->check_current_output( 714 $this->get_contains_mark_summary(0.9), 715 $this->get_contains_submit_button_expectation(true), 716 $this->get_contains_correct_expectation(), 717 $this->get_does_not_contain_penalty_info_expectation(), 718 $this->get_does_not_contain_total_penalty_expectation(), 719 $this->get_does_not_contain_validation_error_expectation(), 720 $this->get_does_not_contain_disregarded_info_expectation()); 721 722 // Submit another non-numerical answer. 723 $this->process_submission(array('-submit' => 1, 'answer' => 'Pi/3')); 724 725 // Verify. 726 $this->check_current_state(question_state::$invalid); 727 $this->check_current_mark(0.9); 728 $this->check_current_output( 729 $this->get_contains_mark_summary(0.9), 730 $this->get_contains_submit_button_expectation(true), 731 $this->get_does_not_contain_correctness_expectation(), 732 $this->get_does_not_contain_penalty_info_expectation(), 733 $this->get_does_not_contain_total_penalty_expectation(), 734 $this->get_contains_validation_error_expectation(), 735 $this->get_contains_disregarded_info_expectation()); 736 737 // Finish the attempt. 738 $this->quba->finish_all_questions(); 739 740 // Verify. 741 $this->check_current_state(question_state::$gradedwrong); 742 $this->check_current_mark(0.9); 743 $this->check_current_output( 744 $this->get_contains_mark_summary(0.9), 745 $this->get_does_not_contain_submit_button_expectation(), 746 $this->get_contains_incorrect_expectation(), 747 $this->get_does_not_contain_validation_error_expectation(), 748 $this->get_does_not_contain_disregarded_info_expectation()); 749 } 750 751 public function test_adaptive_multianswer() { 752 753 // Create a multianswer question. 754 $q = \test_question_maker::make_question('multianswer', 'twosubq'); 755 // To simplify testing, multichoice subquestion's answers are not shuffled. 756 $q->subquestions[2]->shuffleanswers = 0; 757 $choices = array('0' => 'Bow-wow', '1' => 'Wiggly worm', '2' => 'Pussy-cat'); 758 759 $this->start_attempt_at_question($q, 'adaptive', 12); 760 761 // Check the initial state. 762 $this->check_current_state(question_state::$todo); 763 $this->check_current_mark(null); 764 $this->assertEquals('adaptive', 765 $this->quba->get_question_attempt($this->slot)->get_behaviour_name()); 766 $this->render(); 767 $this->check_output_contains_text_input('sub1_answer', '', true); 768 $this->check_output_does_not_contain_text_input_with_class('sub1_answer', 'correct'); 769 $this->check_output_does_not_contain_text_input_with_class('sub1_answer', 'partiallycorrect'); 770 $this->check_output_does_not_contain_text_input_with_class('sub1_answer', 'incorrect'); 771 $this->check_current_output( 772 $this->get_contains_marked_out_of_summary(), 773 $this->get_contains_submit_button_expectation(true), 774 $this->get_does_not_contain_validation_error_expectation(), 775 $this->get_does_not_contain_feedback_expectation()); 776 $this->check_output_contains_selectoptions( 777 $this->get_contains_select_expectation('sub2_answer', $choices, null, true)); 778 779 // Submit an invalid response. 780 $this->process_submission(array('sub1_answer' => '', 'sub2_answer' => 1, '-submit' => 1)); 781 782 // Verify. 783 $this->check_current_state(question_state::$invalid); 784 $this->check_current_mark(null); 785 $this->check_output_contains_text_input('sub1_answer', '', true); 786 $this->check_current_output( 787 $this->get_contains_submit_button_expectation(true), 788 $this->get_does_not_contain_penalty_info_expectation(), 789 $this->get_does_not_contain_total_penalty_expectation(), 790 $this->get_contains_disregarded_info_expectation()); 791 $this->check_output_contains_selectoptions( 792 $this->get_contains_select_expectation('sub2_answer', $choices, 1, true)); 793 794 // Check that extract responses will return the reset data. 795 $prefix = $this->quba->get_field_prefix($this->slot); 796 $this->assertEquals(array('sub2_answer' => 1), 797 $this->quba->extract_responses($this->slot, array($prefix . 'sub2_answer' => 1))); 798 799 // Submit an incorrect response. 800 $this->process_submission(array('sub1_answer' => 'Dog', 801 'sub2_answer' => 1, '-submit' => 1)); 802 803 // Verify. 804 $this->check_current_state(question_state::$todo); 805 $this->check_current_mark(0); 806 $this->render(); 807 $this->check_output_contains_text_input('sub1_answer', 'Dog', true); 808 $this->check_output_contains_text_input_with_class('sub1_answer', 'incorrect'); 809 $this->check_current_output( 810 $this->get_contains_mark_summary(0), 811 $this->get_contains_submit_button_expectation(true), 812 $this->get_contains_incorrect_expectation(), 813 $this->get_contains_penalty_info_expectation(4.00), 814 $this->get_does_not_contain_validation_error_expectation()); 815 $this->check_output_contains_selectoptions( 816 $this->get_contains_select_expectation('sub2_answer', $choices, 1, true)); 817 818 // Submit the right answer. 819 $this->process_submission(array('sub1_answer' => 'Owl', 'sub2_answer' => 2, '-submit' => 1)); 820 821 // Verify. 822 $this->check_current_state(question_state::$complete); 823 $this->check_current_mark(8.00); 824 $this->render(); 825 $this->check_output_contains_text_input('sub1_answer', 'Owl', true); 826 $this->check_output_contains_text_input_with_class('sub1_answer', 'correct'); 827 $this->check_current_output( 828 $this->get_contains_mark_summary(8.00), 829 $this->get_contains_submit_button_expectation(true), 830 $this->get_contains_correct_expectation(), 831 $this->get_does_not_contain_penalty_info_expectation(), 832 $this->get_does_not_contain_total_penalty_expectation(), 833 $this->get_does_not_contain_validation_error_expectation()); 834 $this->check_output_contains_selectoptions( 835 $this->get_contains_select_expectation('sub2_answer', $choices, '2', true)); 836 837 // Finish the attempt. 838 $this->quba->finish_all_questions(); 839 840 // Verify. 841 $this->check_current_state(question_state::$gradedright); 842 $this->check_current_mark(8.00); 843 $this->render(); 844 $this->check_output_contains_text_input('sub1_answer', 'Owl', false); 845 $this->check_output_contains_text_input_with_class('sub1_answer', 'correct'); 846 $this->check_current_output( 847 $this->get_contains_mark_summary(8.00), 848 $this->get_does_not_contain_submit_button_expectation(), 849 $this->get_contains_correct_expectation(), 850 $this->get_does_not_contain_validation_error_expectation()); 851 } 852 }
title
Description
Body
title
Description
Body
title
Description
Body
title
Body