Differences Between: [Versions 311 and 400] [Versions 311 and 401] [Versions 311 and 402] [Versions 311 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 public function test_conversion_task() { 340 global $DB; 341 $this->require_ghostscript(); 342 $this->resetAfterTest(); 343 cron_setup_user(); 344 345 $task = new \assignfeedback_editpdf\task\convert_submissions; 346 347 $course = $this->getDataGenerator()->create_course(); 348 $student = $this->getDataGenerator()->create_and_enrol($course, 'student'); 349 $assignopts = [ 350 'assignsubmission_file_enabled' => 1, 351 'assignsubmission_file_maxfiles' => 1, 352 'assignfeedback_editpdf_enabled' => 1, 353 'assignsubmission_file_maxsizebytes' => 1000000, 354 ]; 355 $assign = $this->create_instance($course, $assignopts); 356 357 // Add the standard submission. 358 $this->add_file_submission($student, $assign); 359 360 // Run the conversion task. 361 ob_start(); 362 $task->execute(); 363 $output = ob_get_clean(); 364 365 // Verify it acted on both submissions in the queue. 366 $this->assertStringContainsString("Convert 1 submission attempt(s) for assignment {$assign->get_instance()->id}", $output); 367 $this->assertEquals(0, $DB->count_records('assignfeedback_editpdf_queue')); 368 369 // Set a known limit. 370 set_config('conversionattemptlimit', 3); 371 372 // Trigger a re-queue by 'updating' a submission. 373 $submission = $assign->get_user_submission($student->id, true); 374 $plugin = $assign->get_submission_plugin_by_type('file'); 375 $plugin->save($submission, (new \stdClass)); 376 377 // Verify that queued a conversion task. 378 $this->assertEquals(1, $DB->count_records('assignfeedback_editpdf_queue')); 379 380 // Fake some failed attempts for it. 381 $queuerecord = $DB->get_record('assignfeedback_editpdf_queue', ['submissionid' => $submission->id]); 382 $queuerecord->attemptedconversions = 3; 383 $DB->update_record('assignfeedback_editpdf_queue', $queuerecord); 384 385 ob_start(); 386 $task->execute(); 387 $output = ob_get_clean(); 388 389 // Verify that the cron task skipped the submission. 390 $this->assertStringNotContainsString("Convert 1 submission attempt(s) for assignment {$assign->get_instance()->id}", $output); 391 // And it removed it from the queue. 392 $this->assertEquals(0, $DB->count_records('assignfeedback_editpdf_queue')); 393 394 } 395 396 /** 397 * Test that modifying the annotated pdf form return true when modified 398 * and false when not modified. 399 */ 400 public function test_is_feedback_modified() { 401 $this->resetAfterTest(); 402 $course = $this->getDataGenerator()->create_course(); 403 $teacher = $this->getDataGenerator()->create_and_enrol($course, 'teacher'); 404 $student = $this->getDataGenerator()->create_and_enrol($course, 'student'); 405 $assign = $this->create_instance($course, [ 406 'assignsubmission_onlinetext_enabled' => 1, 407 'assignsubmission_file_enabled' => 1, 408 'assignsubmission_file_maxfiles' => 1, 409 'assignfeedback_editpdf_enabled' => 1, 410 'assignsubmission_file_maxsizebytes' => 1000000, 411 ]); 412 413 // Add the standard submission. 414 $this->add_file_submission($student, $assign); 415 416 $this->setUser($teacher); 417 $grade = $assign->get_user_grade($student->id, true); 418 419 $notempty = page_editor::has_annotations_or_comments($grade->id, false); 420 $this->assertFalse($notempty); 421 422 $comment = new comment(); 423 424 $comment->rawtext = 'Comment text'; 425 $comment->width = 100; 426 $comment->x = 100; 427 $comment->y = 100; 428 $comment->colour = 'red'; 429 430 page_editor::set_comments($grade->id, 0, array($comment)); 431 432 $annotations = array(); 433 434 $annotation = new annotation(); 435 $annotation->path = ''; 436 $annotation->x = 100; 437 $annotation->y = 100; 438 $annotation->endx = 200; 439 $annotation->endy = 200; 440 $annotation->type = 'line'; 441 $annotation->colour = 'red'; 442 array_push($annotations, $annotation); 443 444 page_editor::set_annotations($grade->id, 0, $annotations); 445 446 $plugin = $assign->get_feedback_plugin_by_type('editpdf'); 447 $data = new \stdClass(); 448 $data->editpdf_source_userid = $student->id; 449 $this->assertTrue($plugin->is_feedback_modified($grade, $data)); 450 $plugin->save($grade, $data); 451 452 $annotation = new annotation(); 453 $annotation->gradeid = $grade->id; 454 $annotation->pageno = 0; 455 $annotation->path = ''; 456 $annotation->x = 100; 457 $annotation->y = 100; 458 $annotation->endx = 200; 459 $annotation->endy = 200; 460 $annotation->type = 'rectangle'; 461 $annotation->colour = 'yellow'; 462 463 $yellowannotationid = page_editor::add_annotation($annotation); 464 465 // Add a comment as well. 466 $comment = new comment(); 467 $comment->gradeid = $grade->id; 468 $comment->pageno = 0; 469 $comment->rawtext = 'Second Comment text'; 470 $comment->width = 100; 471 $comment->x = 100; 472 $comment->y = 100; 473 $comment->colour = 'red'; 474 page_editor::add_comment($comment); 475 476 $this->assertTrue($plugin->is_feedback_modified($grade, $data)); 477 $plugin->save($grade, $data); 478 479 // We should have two annotations. 480 $this->assertCount(2, page_editor::get_annotations($grade->id, 0, false)); 481 // And two comments. 482 $this->assertCount(2, page_editor::get_comments($grade->id, 0, false)); 483 484 // Add one annotation and delete another. 485 $annotation = new annotation(); 486 $annotation->gradeid = $grade->id; 487 $annotation->pageno = 0; 488 $annotation->path = '100,100:105,105:110,100'; 489 $annotation->x = 100; 490 $annotation->y = 100; 491 $annotation->endx = 110; 492 $annotation->endy = 105; 493 $annotation->type = 'pen'; 494 $annotation->colour = 'black'; 495 page_editor::add_annotation($annotation); 496 497 $annotations = page_editor::get_annotations($grade->id, 0, true); 498 page_editor::remove_annotation($yellowannotationid); 499 $this->assertTrue($plugin->is_feedback_modified($grade, $data)); 500 $plugin->save($grade, $data); 501 502 // We should have two annotations. 503 $this->assertCount(2, page_editor::get_annotations($grade->id, 0, false)); 504 // And two comments. 505 $this->assertCount(2, page_editor::get_comments($grade->id, 0, false)); 506 507 // Add a comment and then remove it. Should not be considered as modified. 508 $comment = new comment(); 509 $comment->gradeid = $grade->id; 510 $comment->pageno = 0; 511 $comment->rawtext = 'Third Comment text'; 512 $comment->width = 400; 513 $comment->x = 57; 514 $comment->y = 205; 515 $comment->colour = 'black'; 516 $comment->id = page_editor::add_comment($comment); 517 518 // We should now have three comments. 519 $this->assertCount(3, page_editor::get_comments($grade->id, 0, true)); 520 // Now delete the newest record. 521 page_editor::remove_comment($comment->id); 522 // Back to two comments. 523 $this->assertCount(2, page_editor::get_comments($grade->id, 0, true)); 524 // No modification. 525 $this->assertFalse($plugin->is_feedback_modified($grade, $data)); 526 } 527 528 /** 529 * Test Convert submissions scheduled task limit. 530 * 531 * @covers \assignfeedback_editpdf\task\convert_submissions 532 */ 533 public function test_conversion_task_limit() { 534 global $DB; 535 $this->require_ghostscript(); 536 $this->resetAfterTest(); 537 cron_setup_user(); 538 539 $course = $this->getDataGenerator()->create_course(); 540 $assignopts = [ 541 'assignsubmission_file_enabled' => 1, 542 'assignsubmission_file_maxfiles' => 1, 543 'assignfeedback_editpdf_enabled' => 1, 544 'assignsubmission_file_maxsizebytes' => 1000000, 545 ]; 546 $assign = $this->create_instance($course, $assignopts); 547 548 // Generate 110 submissions. 549 for ($i = 0; $i < 110; $i++) { 550 $student = $this->getDataGenerator()->create_and_enrol($course, 'student'); 551 $this->add_file_submission($student, $assign); 552 } 553 $this->assertEquals(110, $DB->count_records('assignfeedback_editpdf_queue')); 554 555 // Run the conversion task. 556 $task = new \assignfeedback_editpdf\task\convert_submissions; 557 ob_start(); 558 $task->execute(); 559 ob_end_clean(); 560 561 // Confirm, that 100 records were processed and 10 were left for the next task run. 562 $this->assertEquals(10, $DB->count_records('assignfeedback_editpdf_queue')); 563 } 564 565 /** 566 * Test that overwriting a submission file deletes any associated conversions. 567 */ 568 public function test_submission_file_overridden() { 569 $this->resetAfterTest(); 570 $course = $this->getDataGenerator()->create_course(); 571 $student = $this->getDataGenerator()->create_and_enrol($course, 'student'); 572 $assign = $this->create_instance($course, [ 573 'assignsubmission_onlinetext_enabled' => 1, 574 'assignsubmission_file_enabled' => 1, 575 'assignsubmission_file_maxfiles' => 1, 576 'assignfeedback_editpdf_enabled' => 1, 577 'assignsubmission_file_maxsizebytes' => 1000000, 578 ]); 579 580 $this->add_file_submission($student, $assign, true); 581 $submission = $assign->get_user_submission($student->id, true); 582 583 $fs = get_file_storage(); 584 $sourcefile = $fs->get_file( 585 $assign->get_context()->id, 586 'assignsubmission_file', 587 ASSIGNSUBMISSION_FILE_FILEAREA, 588 $submission->id, 589 '/', 590 'submission.txt' 591 ); 592 593 $conversion = new \core_files\conversion(0, (object)[ 594 'sourcefileid' => $sourcefile->get_id(), 595 'targetformat' => 'pdf' 596 ]); 597 $conversion->create(); 598 599 $conversions = \core_files\conversion::get_conversions_for_file($sourcefile, 'pdf'); 600 $this->assertCount(1, $conversions); 601 602 $filerecord = (object)[ 603 'contextid' => $assign->get_context()->id, 604 'component' => 'core', 605 'filearea' => 'unittest', 606 'itemid' => $submission->id, 607 'filepath' => '/', 608 'filename' => 'submission.txt' 609 ]; 610 611 $fs = get_file_storage(); 612 $newfile = $fs->create_file_from_string($filerecord, 'something totally different'); 613 $sourcefile->replace_file_with($newfile); 614 615 $conversions = \core_files\conversion::get_conversions_for_file($sourcefile, 'pdf'); 616 $this->assertCount(0, $conversions); 617 } 618 }
title
Description
Body
title
Description
Body
title
Description
Body
title
Body