Skip to content

Commit 034100e

Browse files
committed
Add PHPUnit tests
1 parent e7a7606 commit 034100e

2 files changed

Lines changed: 592 additions & 0 deletions

File tree

Lines changed: 290 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,290 @@
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 tool_corruptpdfdetector;
18+
19+
use tool_corruptpdfdetector\task\fix_assignments;
20+
/**
21+
* Unit tests for the fix_assignments scheduled task.
22+
*
23+
* @covers \tool_corruptpdfdetector\task\fix_assignments
24+
* @package tool_corruptpdfdetector
25+
* @copyright Catalyst IT
26+
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
27+
*/
28+
final class task_fix_assignments_test extends \advanced_testcase {
29+
/**
30+
* Helper: insert a minimal record into tool_corruptpdfdetector_assigns.
31+
*
32+
* @param string $contenthash SHA-1 hash stored in the filename column.
33+
* @param bool $fixed Whether the record is already fixed.
34+
* @return int Inserted record ID.
35+
*/
36+
private function insert_assigns_record(string $contenthash, bool $fixed = false): int {
37+
global $DB;
38+
39+
$record = (object)[
40+
'assignid' => 1,
41+
'submissionid' => random_int(1, 99999),
42+
'coursename' => 'Test course',
43+
'assignname' => 'Test assignment',
44+
'userfullname' => 'Test User',
45+
'email' => 'test@example.com',
46+
'filename' => $contenthash,
47+
'message' => 'Corrupt PDF detected',
48+
'submitted' => time(),
49+
'detected' => time(),
50+
'fixed' => (int) $fixed,
51+
];
52+
53+
return $DB->insert_record('tool_corruptpdfdetector_assigns', $record);
54+
}
55+
56+
/**
57+
* Helper: insert a minimal record into the files table with filename = 'combined.pdf'.
58+
*
59+
* @param string $contenthash Content hash matching the filename column in assigns.
60+
* @param string $filearea 'combined' or 'partial'.
61+
* @return int Inserted record ID.
62+
*/
63+
private function insert_file_record(string $contenthash, string $filearea = 'combined'): int {
64+
global $DB;
65+
66+
$record = (object)[
67+
'contenthash' => $contenthash,
68+
'pathnamehash' => sha1(uniqid('', true)),
69+
'contextid' => \context_system::instance()->id,
70+
'component' => 'assignfeedback_editpdf',
71+
'filearea' => $filearea,
72+
'itemid' => 1,
73+
'filepath' => '/',
74+
'filename' => 'combined.pdf',
75+
'userid' => 0,
76+
'filesize' => 12345,
77+
'mimetype' => 'application/pdf',
78+
'status' => 0,
79+
'source' => null,
80+
'author' => null,
81+
'license' => null,
82+
'timecreated' => time(),
83+
'timemodified' => time(),
84+
'sortorder' => 0,
85+
'referencefileid' => null,
86+
];
87+
88+
return $DB->insert_record('files', $record);
89+
}
90+
91+
/**
92+
* Verify that get_name() returns the expected localised string.
93+
*/
94+
public function test_task_name(): void {
95+
$task = new fix_assignments();
96+
$this->assertEquals(
97+
get_string('task_fix_assignments', 'tool_corruptpdfdetector'),
98+
$task->get_name()
99+
);
100+
}
101+
102+
/**
103+
* execute() should complete silently when there are no unfixed records.
104+
*/
105+
public function test_execute_does_nothing_when_table_is_empty(): void {
106+
global $DB;
107+
$this->resetAfterTest();
108+
109+
$task = new fix_assignments();
110+
$task->execute();
111+
112+
$this->assertEquals(0, $DB->count_records('tool_corruptpdfdetector_assigns'));
113+
}
114+
115+
/**
116+
* execute() should mark every unfixed record as fixed after running.
117+
*/
118+
public function test_execute_marks_unfixed_records_as_fixed(): void {
119+
global $DB;
120+
$this->resetAfterTest();
121+
122+
$id1 = $this->insert_assigns_record(sha1('content1'), false);
123+
$id2 = $this->insert_assigns_record(sha1('content2'), false);
124+
125+
$task = new fix_assignments();
126+
$task->execute();
127+
128+
$record1 = $DB->get_record('tool_corruptpdfdetector_assigns', ['id' => $id1]);
129+
$record2 = $DB->get_record('tool_corruptpdfdetector_assigns', ['id' => $id2]);
130+
131+
$this->assertEquals(1, $record1->fixed, 'First record should be marked fixed.');
132+
$this->assertEquals(1, $record2->fixed, 'Second record should be marked fixed.');
133+
}
134+
135+
/**
136+
* execute() should delete the combined.pdf file (filearea = 'combined') for each unfixed record.
137+
*/
138+
public function test_execute_deletes_combined_pdf_file(): void {
139+
global $DB;
140+
$this->resetAfterTest();
141+
142+
$contenthash = sha1('combinedcontent');
143+
$this->insert_assigns_record($contenthash, false);
144+
$fileid = $this->insert_file_record($contenthash, 'combined');
145+
146+
$this->assertTrue(
147+
$DB->record_exists('files', ['id' => $fileid]),
148+
'File record should exist before task runs.'
149+
);
150+
151+
$task = new fix_assignments();
152+
$task->execute();
153+
154+
$this->assertFalse(
155+
$DB->record_exists('files', ['id' => $fileid]),
156+
'Combined PDF file record should be deleted after task runs.'
157+
);
158+
}
159+
160+
/**
161+
* execute() should also delete the partial combined.pdf file (filearea = 'partial').
162+
*/
163+
public function test_execute_deletes_partial_pdf_file(): void {
164+
global $DB;
165+
$this->resetAfterTest();
166+
167+
$contenthash = sha1('partialcontent');
168+
$this->insert_assigns_record($contenthash, false);
169+
$fileid = $this->insert_file_record($contenthash, 'partial');
170+
171+
$task = new fix_assignments();
172+
$task->execute();
173+
174+
$this->assertFalse(
175+
$DB->record_exists('files', ['id' => $fileid]),
176+
'Partial PDF file record should be deleted after task runs.'
177+
);
178+
}
179+
180+
/**
181+
* execute() must NOT delete files unrelated to the corrupt submission
182+
* (different contenthash, or a different filename in the same filearea).
183+
*/
184+
public function test_execute_does_not_delete_unrelated_files(): void {
185+
global $DB;
186+
$this->resetAfterTest();
187+
188+
$contenthash = sha1('targetcontent');
189+
$otherhash = sha1('othercontent');
190+
$this->insert_assigns_record($contenthash, false);
191+
192+
// File with a different contenthash – must be preserved.
193+
$differenthashfileid = $this->insert_file_record($otherhash);
194+
195+
// File with the right hash but a different filename – must be preserved.
196+
$differentnamerecord = (object)[
197+
'contenthash' => $contenthash,
198+
'pathnamehash' => sha1(uniqid('', true)),
199+
'contextid' => \context_system::instance()->id,
200+
'component' => 'assignfeedback_editpdf',
201+
'filearea' => 'combined',
202+
'itemid' => 1,
203+
'filepath' => '/',
204+
'filename' => 'other.pdf',
205+
'userid' => 0,
206+
'filesize' => 100,
207+
'mimetype' => 'application/pdf',
208+
'status' => 0,
209+
'source' => null,
210+
'author' => null,
211+
'license' => null,
212+
'timecreated' => time(),
213+
'timemodified' => time(),
214+
'sortorder' => 0,
215+
'referencefileid' => null,
216+
];
217+
$differentnamefileid = $DB->insert_record('files', $differentnamerecord);
218+
219+
$task = new fix_assignments();
220+
$task->execute();
221+
222+
$this->assertTrue(
223+
$DB->record_exists('files', ['id' => $differenthashfileid]),
224+
'File with a different hash should not be deleted.'
225+
);
226+
$this->assertTrue(
227+
$DB->record_exists('files', ['id' => $differentnamefileid]),
228+
'File with a different filename should not be deleted.'
229+
);
230+
}
231+
232+
/**
233+
* execute() should leave already-fixed records (fixed = 1) completely untouched.
234+
*/
235+
public function test_execute_skips_already_fixed_records(): void {
236+
global $DB;
237+
$this->resetAfterTest();
238+
239+
$contenthash = sha1('fixedcontent');
240+
$fixedid = $this->insert_assigns_record($contenthash, true);
241+
$fileid = $this->insert_file_record($contenthash);
242+
243+
$task = new fix_assignments();
244+
$task->execute();
245+
246+
$this->assertTrue(
247+
$DB->record_exists('files', ['id' => $fileid]),
248+
'File for an already-fixed record should not be deleted.'
249+
);
250+
251+
$record = $DB->get_record('tool_corruptpdfdetector_assigns', ['id' => $fixedid]);
252+
$this->assertEquals(1, $record->fixed);
253+
}
254+
255+
/**
256+
* execute() processes unfixed records while leaving already-fixed records intact.
257+
*/
258+
public function test_execute_mixed_fixed_and_unfixed_records(): void {
259+
global $DB;
260+
$this->resetAfterTest();
261+
262+
$unfixedhash = sha1('unfixedcontent');
263+
$fixedhash = sha1('alreadyfixedcontent');
264+
265+
$unfixedid = $this->insert_assigns_record($unfixedhash);
266+
$fixedid = $this->insert_assigns_record($fixedhash, true);
267+
268+
$unfixedfileid = $this->insert_file_record($unfixedhash);
269+
$fixedfileid = $this->insert_file_record($fixedhash);
270+
271+
$task = new fix_assignments();
272+
$task->execute();
273+
274+
// Unfixed record – should now be fixed, its file deleted.
275+
$unfixedrecord = $DB->get_record('tool_corruptpdfdetector_assigns', ['id' => $unfixedid]);
276+
$this->assertEquals(1, $unfixedrecord->fixed, 'Unfixed record should now be marked fixed.');
277+
$this->assertFalse(
278+
$DB->record_exists('files', ['id' => $unfixedfileid]),
279+
'File for the unfixed record should be deleted.'
280+
);
281+
282+
// Already-fixed record – unchanged, file retained.
283+
$fixedrecord = $DB->get_record('tool_corruptpdfdetector_assigns', ['id' => $fixedid]);
284+
$this->assertEquals(1, $fixedrecord->fixed, 'Already-fixed record should remain fixed.');
285+
$this->assertTrue(
286+
$DB->record_exists('files', ['id' => $fixedfileid]),
287+
'File for the already-fixed record should not be deleted.'
288+
);
289+
}
290+
}

0 commit comments

Comments
 (0)