See Release Notes
Long Term Support Release
Differences Between: [Versions 311 and 401] [Versions 400 and 401] [Versions 401 and 402] [Versions 401 and 403]
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 assignfeedback_editpdf; 18 19 use mod_assign_test_generator; 20 21 defined('MOODLE_INTERNAL') || die(); 22 23 global $CFG; 24 require_once($CFG->dirroot . '/mod/assign/tests/generator.php'); 25 26 /** 27 * Unit tests for assignfeedback_editpdf\comments_quick_list 28 * 29 * @package assignfeedback_editpdf 30 * @category test 31 * @copyright 2013 Damyon Wiese 32 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 33 */ 34 class feedback_test extends \advanced_testcase { 35 36 // Use the generator helper. 37 use mod_assign_test_generator; 38 39 /** 40 * Ensure that GS is available. 41 */ 42 protected function require_ghostscript() { 43 // Skip this test if ghostscript is not supported. 44 $result = pdf::test_gs_path(false); 45 if ($result->status !== pdf::GSPATH_OK) { 46 $this->markTestSkipped('Ghostscript not setup'); 47 } 48 } 49 50 /** 51 * Helper method to add a file to a submission. 52 * 53 * @param stdClass $student Student submitting. 54 * @param assign $assign Assignment being submitted. 55 * @param bool $textfile Use textfile fixture instead of pdf. 56 */ 57 protected function add_file_submission($student, $assign, $textfile = false) { 58 global $CFG; 59 60 $this->setUser($student); 61 62 // Create a file submission with the test pdf. 63 $submission = $assign->get_user_submission($student->id, true); 64 65 $fs = get_file_storage(); 66 $filerecord = (object) array( 67 'contextid' => $assign->get_context()->id, 68 'component' => 'assignsubmission_file', 69 'filearea' => ASSIGNSUBMISSION_FILE_FILEAREA, 70 'itemid' => $submission->id, 71 'filepath' => '/', 72 'filename' => $textfile ? 'submission.txt' : 'submission.pdf' 73 ); 74 $sourcefile = $CFG->dirroot . '/mod/assign/feedback/editpdf/tests/fixtures/submission.' . ($textfile ? 'txt' : 'pdf'); 75 $fs->create_file_from_pathname($filerecord, $sourcefile); 76 77 $data = new \stdClass(); 78 $plugin = $assign->get_submission_plugin_by_type('file'); 79 $plugin->save($submission, $data); 80 } 81 82 public function test_comments_quick_list() { 83 $this->resetAfterTest(); 84 $course = $this->getDataGenerator()->create_course(); 85 $teacher = $this->getDataGenerator()->create_and_enrol($course, 'teacher'); 86 87 $this->setUser($teacher); 88 89 $this->assertEmpty(comments_quick_list::get_comments()); 90 91 $comment = comments_quick_list::add_comment('test', 45, 'red'); 92 $comments = comments_quick_list::get_comments(); 93 $this->assertEquals(count($comments), 1); 94 $first = reset($comments); 95 $this->assertEquals($comment, $first); 96 97 $commentbyid = comments_quick_list::get_comment($comment->id); 98 $this->assertEquals($comment, $commentbyid); 99 100 $this->assertTrue(comments_quick_list::remove_comment($comment->id)); 101 102 $comments = comments_quick_list::get_comments(); 103 $this->assertEmpty($comments); 104 } 105 106 public function test_page_editor() { 107 $this->resetAfterTest(); 108 $course = $this->getDataGenerator()->create_course(); 109 $teacher = $this->getDataGenerator()->create_and_enrol($course, 'teacher'); 110 $student = $this->getDataGenerator()->create_and_enrol($course, 'student'); 111 $assign = $this->create_instance($course, [ 112 'assignsubmission_onlinetext_enabled' => 1, 113 'assignsubmission_file_enabled' => 1, 114 'assignsubmission_file_maxfiles' => 1, 115 'assignfeedback_editpdf_enabled' => 1, 116 'assignsubmission_file_maxsizebytes' => 1000000, 117 ]); 118 119 // Add the standard submission. 120 $this->add_file_submission($student, $assign); 121 122 $this->setUser($teacher); 123 124 $grade = $assign->get_user_grade($student->id, true); 125 126 $notempty = page_editor::has_annotations_or_comments($grade->id, false); 127 $this->assertFalse($notempty); 128 129 $comment = new comment(); 130 $comment->rawtext = 'Comment text'; 131 $comment->width = 100; 132 $comment->x = 100; 133 $comment->y = 100; 134 $comment->colour = 'red'; 135 136 $comment2 = new comment(); 137 $comment2->rawtext = 'Comment text 2'; 138 $comment2->width = 100; 139 $comment2->x = 200; 140 $comment2->y = 100; 141 $comment2->colour = 'clear'; 142 143 page_editor::set_comments($grade->id, 0, array($comment, $comment2)); 144 145 $annotation = new annotation(); 146 $annotation->path = ''; 147 $annotation->x = 100; 148 $annotation->y = 100; 149 $annotation->endx = 200; 150 $annotation->endy = 200; 151 $annotation->type = 'line'; 152 $annotation->colour = 'red'; 153 154 $annotation2 = new annotation(); 155 $annotation2->path = ''; 156 $annotation2->x = 100; 157 $annotation2->y = 100; 158 $annotation2->endx = 200; 159 $annotation2->endy = 200; 160 $annotation2->type = 'rectangle'; 161 $annotation2->colour = 'yellow'; 162 163 page_editor::set_annotations($grade->id, 0, array($annotation, $annotation2)); 164 165 // Still empty because all edits are still drafts. 166 $this->assertFalse(page_editor::has_annotations_or_comments($grade->id, false)); 167 168 $comments = page_editor::get_comments($grade->id, 0, false); 169 $this->assertEmpty($comments); 170 171 $comments = page_editor::get_comments($grade->id, 0, true); 172 $this->assertEquals(count($comments), 2); 173 174 $annotations = page_editor::get_annotations($grade->id, 0, false); 175 $this->assertEmpty($annotations); 176 177 $annotations = page_editor::get_annotations($grade->id, 0, true); 178 $this->assertEquals(count($annotations), 2); 179 180 $comment = reset($comments); 181 $annotation = reset($annotations); 182 183 page_editor::remove_comment($comment->id); 184 page_editor::remove_annotation($annotation->id); 185 186 $comments = page_editor::get_comments($grade->id, 0, true); 187 $this->assertEquals(count($comments), 1); 188 189 $annotations = page_editor::get_annotations($grade->id, 0, true); 190 $this->assertEquals(count($annotations), 1); 191 192 // Release the drafts. 193 page_editor::release_drafts($grade->id); 194 195 $notempty = page_editor::has_annotations_or_comments($grade->id, false); 196 $this->assertTrue($notempty); 197 198 // Unrelease the drafts. 199 page_editor::unrelease_drafts($grade->id); 200 201 $notempty = page_editor::has_annotations_or_comments($grade->id, false); 202 $this->assertFalse($notempty); 203 } 204 205 public function test_document_services() { 206 $this->require_ghostscript(); 207 $this->resetAfterTest(); 208 $course = $this->getDataGenerator()->create_course(); 209 $teacher = $this->getDataGenerator()->create_and_enrol($course, 'teacher'); 210 $student = $this->getDataGenerator()->create_and_enrol($course, 'student'); 211 $assign = $this->create_instance($course, [ 212 'assignsubmission_onlinetext_enabled' => 1, 213 'assignsubmission_file_enabled' => 1, 214 'assignsubmission_file_maxfiles' => 1, 215 'assignfeedback_editpdf_enabled' => 1, 216 'assignsubmission_file_maxsizebytes' => 1000000, 217 ]); 218 219 // Add the standard submission. 220 $this->add_file_submission($student, $assign); 221 222 $this->setUser($teacher); 223 224 $grade = $assign->get_user_grade($student->id, true); 225 226 $contextid = $assign->get_context()->id; 227 $component = 'assignfeedback_editpdf'; 228 $filearea = document_services::COMBINED_PDF_FILEAREA; 229 $itemid = $grade->id; 230 $filepath = '/'; 231 $filename = document_services::COMBINED_PDF_FILENAME; 232 $fs = \get_file_storage(); 233 234 // Generate a blank combined pdf. 235 $record = new \stdClass(); 236 $record->contextid = $contextid; 237 $record->component = $component; 238 $record->filearea = $filearea; 239 $record->itemid = $itemid; 240 $record->filepath = $filepath; 241 $record->filename = $filename; 242 $fs->create_file_from_string($record, base64_decode(document_services::BLANK_PDF_BASE64)); 243 244 // Verify that the blank combined pdf has the expected hash. 245 $combinedpdf = $fs->get_file($contextid, $component, $filearea, $itemid, $filepath, $filename); 246 $this->assertEquals($combinedpdf->get_contenthash(), document_services::BLANK_PDF_HASH); 247 248 // Generate page images and verify that the combined pdf has been replaced. 249 document_services::get_page_images_for_attempt($assign, $student->id, -1); 250 $combinedpdf = $fs->get_file($contextid, $component, $filearea, $itemid, $filepath, $filename); 251 $this->assertNotEquals($combinedpdf->get_contenthash(), document_services::BLANK_PDF_HASH); 252 253 $notempty = page_editor::has_annotations_or_comments($grade->id, false); 254 $this->assertFalse($notempty); 255 256 $comment = new comment(); 257 258 // Use some different charset in the comment text. 259 $comment->rawtext = 'Testing example: בקלות ואמנות'; 260 $comment->width = 100; 261 $comment->x = 100; 262 $comment->y = 100; 263 $comment->colour = 'red'; 264 265 page_editor::set_comments($grade->id, 0, array($comment)); 266 267 $annotations = array(); 268 269 $annotation = new annotation(); 270 $annotation->path = ''; 271 $annotation->x = 100; 272 $annotation->y = 100; 273 $annotation->endx = 200; 274 $annotation->endy = 200; 275 $annotation->type = 'line'; 276 $annotation->colour = 'red'; 277 array_push($annotations, $annotation); 278 279 $annotation = new annotation(); 280 $annotation->path = ''; 281 $annotation->x = 100; 282 $annotation->y = 100; 283 $annotation->endx = 200; 284 $annotation->endy = 200; 285 $annotation->type = 'rectangle'; 286 $annotation->colour = 'yellow'; 287 array_push($annotations, $annotation); 288 289 $annotation = new annotation(); 290 $annotation->path = ''; 291 $annotation->x = 100; 292 $annotation->y = 100; 293 $annotation->endx = 200; 294 $annotation->endy = 200; 295 $annotation->type = 'oval'; 296 $annotation->colour = 'green'; 297 array_push($annotations, $annotation); 298 299 $annotation = new annotation(); 300 $annotation->path = ''; 301 $annotation->x = 100; 302 $annotation->y = 100; 303 $annotation->endx = 200; 304 $annotation->endy = 116; 305 $annotation->type = 'highlight'; 306 $annotation->colour = 'blue'; 307 array_push($annotations, $annotation); 308 309 $annotation = new annotation(); 310 $annotation->path = '100,100:105,105:110,100'; 311 $annotation->x = 100; 312 $annotation->y = 100; 313 $annotation->endx = 110; 314 $annotation->endy = 105; 315 $annotation->type = 'pen'; 316 $annotation->colour = 'black'; 317 array_push($annotations, $annotation); 318 page_editor::set_annotations($grade->id, 0, $annotations); 319 320 page_editor::release_drafts($grade->id); 321 322 $notempty = page_editor::has_annotations_or_comments($grade->id, false); 323 324 $this->assertTrue($notempty); 325 326 $file = document_services::generate_feedback_document($assign->get_instance()->id, $grade->userid, $grade->attemptnumber); 327 $this->assertNotEmpty($file); 328 329 $file2 = document_services::get_feedback_document($assign->get_instance()->id, $grade->userid, $grade->attemptnumber); 330 331 $this->assertEquals($file, $file2); 332 333 document_services::delete_feedback_document($assign->get_instance()->id, $grade->userid, $grade->attemptnumber); 334 $file3 = document_services::get_feedback_document($assign->get_instance()->id, $grade->userid, $grade->attemptnumber); 335 336 $this->assertEmpty($file3); 337 } 338 339 /** 340 * Test Convert submission ad-hoc task. 341 * 342 * @covers \assignfeedback_editpdf\task\convert_submission 343 */ 344 public function test_conversion_task() { 345 $this->require_ghostscript(); 346 $this->resetAfterTest(); 347 cron_setup_user(); 348 349 $course = $this->getDataGenerator()->create_course(); 350 $student = $this->getDataGenerator()->create_and_enrol($course, 'student'); 351 $assignopts = [ 352 'assignsubmission_file_enabled' => 1, 353 'assignsubmission_file_maxfiles' => 1, 354 'assignfeedback_editpdf_enabled' => 1, 355 'assignsubmission_file_maxsizebytes' => 1000000, 356 ]; 357 $assign = $this->create_instance($course, $assignopts); 358 359 // Add the standard submission. 360 $this->add_file_submission($student, $assign); 361 362 // Run the conversion task. 363 $task = \core\task\manager::get_next_adhoc_task(time()); 364 ob_start(); 365 $task->execute(); 366 \core\task\manager::adhoc_task_complete($task); 367 $output = ob_get_clean(); 368 369 // Confirm, that submission has been converted and the task queue is now empty. 370 $this->assertStringContainsString('Converting submission for user id ' . $student->id, $output); 371 $this->assertStringContainsString('The document has been successfully converted', $output); 372 $this->assertNull(\core\task\manager::get_next_adhoc_task(time())); 373 374 // Trigger a re-queue by 'updating' a submission. 375 $submission = $assign->get_user_submission($student->id, true); 376 $plugin = $assign->get_submission_plugin_by_type('file'); 377 $plugin->save($submission, (new \stdClass)); 378 379 $task = \core\task\manager::get_next_adhoc_task(time()); 380 // Verify that queued a conversion task. 381 $this->assertNotNull($task); 382 383 ob_start(); 384 $task->execute(); 385 \core\task\manager::adhoc_task_complete($task); 386 $output = ob_get_clean(); 387 388 // Confirm, that submission has been converted and the task queue is now empty. 389 $this->assertStringContainsString('Converting submission for user id ' . $student->id, $output); 390 $this->assertStringContainsString('The document has been successfully converted', $output); 391 $this->assertNull(\core\task\manager::get_next_adhoc_task(time())); 392 } 393 394 /** 395 * Test that modifying the annotated pdf form return true when modified 396 * and false when not modified. 397 */ 398 public function test_is_feedback_modified() { 399 $this->resetAfterTest(); 400 $course = $this->getDataGenerator()->create_course(); 401 $teacher = $this->getDataGenerator()->create_and_enrol($course, 'teacher'); 402 $student = $this->getDataGenerator()->create_and_enrol($course, 'student'); 403 $assign = $this->create_instance($course, [ 404 'assignsubmission_onlinetext_enabled' => 1, 405 'assignsubmission_file_enabled' => 1, 406 'assignsubmission_file_maxfiles' => 1, 407 'assignfeedback_editpdf_enabled' => 1, 408 'assignsubmission_file_maxsizebytes' => 1000000, 409 ]); 410 411 // Add the standard submission. 412 $this->add_file_submission($student, $assign); 413 414 $this->setUser($teacher); 415 $grade = $assign->get_user_grade($student->id, true); 416 417 $notempty = page_editor::has_annotations_or_comments($grade->id, false); 418 $this->assertFalse($notempty); 419 420 $comment = new comment(); 421 422 $comment->rawtext = 'Comment text'; 423 $comment->width = 100; 424 $comment->x = 100; 425 $comment->y = 100; 426 $comment->colour = 'red'; 427 428 page_editor::set_comments($grade->id, 0, array($comment)); 429 430 $annotations = array(); 431 432 $annotation = new annotation(); 433 $annotation->path = ''; 434 $annotation->x = 100; 435 $annotation->y = 100; 436 $annotation->endx = 200; 437 $annotation->endy = 200; 438 $annotation->type = 'line'; 439 $annotation->colour = 'red'; 440 array_push($annotations, $annotation); 441 442 page_editor::set_annotations($grade->id, 0, $annotations); 443 444 $plugin = $assign->get_feedback_plugin_by_type('editpdf'); 445 $data = new \stdClass(); 446 $data->editpdf_source_userid = $student->id; 447 $this->assertTrue($plugin->is_feedback_modified($grade, $data)); 448 $plugin->save($grade, $data); 449 450 $annotation = new annotation(); 451 $annotation->gradeid = $grade->id; 452 $annotation->pageno = 0; 453 $annotation->path = ''; 454 $annotation->x = 100; 455 $annotation->y = 100; 456 $annotation->endx = 200; 457 $annotation->endy = 200; 458 $annotation->type = 'rectangle'; 459 $annotation->colour = 'yellow'; 460 461 $yellowannotationid = page_editor::add_annotation($annotation); 462 463 // Add a comment as well. 464 $comment = new comment(); 465 $comment->gradeid = $grade->id; 466 $comment->pageno = 0; 467 $comment->rawtext = 'Second Comment text'; 468 $comment->width = 100; 469 $comment->x = 100; 470 $comment->y = 100; 471 $comment->colour = 'red'; 472 page_editor::add_comment($comment); 473 474 $this->assertTrue($plugin->is_feedback_modified($grade, $data)); 475 $plugin->save($grade, $data); 476 477 // We should have two annotations. 478 $this->assertCount(2, page_editor::get_annotations($grade->id, 0, false)); 479 // And two comments. 480 $this->assertCount(2, page_editor::get_comments($grade->id, 0, false)); 481 482 // Add one annotation and delete another. 483 $annotation = new annotation(); 484 $annotation->gradeid = $grade->id; 485 $annotation->pageno = 0; 486 $annotation->path = '100,100:105,105:110,100'; 487 $annotation->x = 100; 488 $annotation->y = 100; 489 $annotation->endx = 110; 490 $annotation->endy = 105; 491 $annotation->type = 'pen'; 492 $annotation->colour = 'black'; 493 page_editor::add_annotation($annotation); 494 495 $annotations = page_editor::get_annotations($grade->id, 0, true); 496 page_editor::remove_annotation($yellowannotationid); 497 $this->assertTrue($plugin->is_feedback_modified($grade, $data)); 498 $plugin->save($grade, $data); 499 500 // We should have two annotations. 501 $this->assertCount(2, page_editor::get_annotations($grade->id, 0, false)); 502 // And two comments. 503 $this->assertCount(2, page_editor::get_comments($grade->id, 0, false)); 504 505 // Add a comment and then remove it. Should not be considered as modified. 506 $comment = new comment(); 507 $comment->gradeid = $grade->id; 508 $comment->pageno = 0; 509 $comment->rawtext = 'Third Comment text'; 510 $comment->width = 400; 511 $comment->x = 57; 512 $comment->y = 205; 513 $comment->colour = 'black'; 514 $comment->id = page_editor::add_comment($comment); 515 516 // We should now have three comments. 517 $this->assertCount(3, page_editor::get_comments($grade->id, 0, true)); 518 // Now delete the newest record. 519 page_editor::remove_comment($comment->id); 520 // Back to two comments. 521 $this->assertCount(2, page_editor::get_comments($grade->id, 0, true)); 522 // No modification. 523 $this->assertFalse($plugin->is_feedback_modified($grade, $data)); 524 } 525 526 /** 527 * Test that overwriting a submission file deletes any associated conversions. 528 * 529 * @covers \core_files\conversion::get_conversions_for_file 530 */ 531 public function test_submission_file_overridden() { 532 $this->resetAfterTest(); 533 $course = $this->getDataGenerator()->create_course(); 534 $student = $this->getDataGenerator()->create_and_enrol($course, 'student'); 535 $assign = $this->create_instance($course, [ 536 'assignsubmission_onlinetext_enabled' => 1, 537 'assignsubmission_file_enabled' => 1, 538 'assignsubmission_file_maxfiles' => 1, 539 'assignfeedback_editpdf_enabled' => 1, 540 'assignsubmission_file_maxsizebytes' => 1000000, 541 ]); 542 543 $this->add_file_submission($student, $assign, true); 544 $submission = $assign->get_user_submission($student->id, true); 545 546 $fs = get_file_storage(); 547 $sourcefile = $fs->get_file( 548 $assign->get_context()->id, 549 'assignsubmission_file', 550 ASSIGNSUBMISSION_FILE_FILEAREA, 551 $submission->id, 552 '/', 553 'submission.txt' 554 ); 555 556 $conversion = new \core_files\conversion(0, (object)[ 557 'sourcefileid' => $sourcefile->get_id(), 558 'targetformat' => 'pdf' 559 ]); 560 $conversion->create(); 561 562 $conversions = \core_files\conversion::get_conversions_for_file($sourcefile, 'pdf'); 563 $this->assertCount(1, $conversions); 564 565 $filerecord = (object)[ 566 'contextid' => $assign->get_context()->id, 567 'component' => 'core', 568 'filearea' => 'unittest', 569 'itemid' => $submission->id, 570 'filepath' => '/', 571 'filename' => 'submission.txt' 572 ]; 573 574 $fs = get_file_storage(); 575 $newfile = $fs->create_file_from_string($filerecord, 'something totally different'); 576 $sourcefile->replace_file_with($newfile); 577 578 $conversions = \core_files\conversion::get_conversions_for_file($sourcefile, 'pdf'); 579 $this->assertCount(0, $conversions); 580 } 581 582 /** 583 * Tests that when the plugin is not enabled for an assignment it does not create conversion tasks. 584 * 585 * @covers \assignfeedback_editpdf\event\observer 586 */ 587 public function test_submission_not_enabled() { 588 $this->require_ghostscript(); 589 $this->resetAfterTest(); 590 cron_setup_user(); 591 592 $course = $this->getDataGenerator()->create_course(); 593 $student = $this->getDataGenerator()->create_and_enrol($course, 'student'); 594 $assignopts = [ 595 'assignsubmission_file_enabled' => 1, 596 'assignsubmission_file_maxfiles' => 1, 597 'assignfeedback_editpdf_enabled' => 0, 598 'assignsubmission_file_maxsizebytes' => 1000000, 599 ]; 600 $assign = $this->create_instance($course, $assignopts); 601 602 // Add the standard submission. 603 $this->add_file_submission($student, $assign); 604 605 $task = \core\task\manager::get_next_adhoc_task(time()); 606 607 // No task was created. 608 $this->assertNull($task); 609 } 610 }
title
Description
Body
title
Description
Body
title
Description
Body
title
Body