@@ -139,4 +139,121 @@ public function test_no_logo(): void {
139139 $ outputimg ->create_image ();
140140 $ this ->assertFileExists ($ file );
141141 }
142+
143+ /**
144+ * The course link generation without modulecontextid returns course URL.
145+ * @covers \block_qrcode\output_image::course_link_url
146+ */
147+ public function test_course_link_url_without_activity (): void {
148+ set_config ('custom_wwwroot ' , '' , 'block_qrcode ' );
149+ $ image = new output_image (1 , 150 , $ this ->course ->id , $ this ->block ->id );
150+
151+ $ expectedurl = new url ('/course/view.php ' , [
152+ 'id ' => $ this ->course ->id ,
153+ 'utm_source ' => 'block_qrcode ' ,
154+ ]);
155+
156+ $ this ->assertEquals ($ expectedurl , $ image ->course_link_url ());
157+ }
158+
159+ /**
160+ * The course link generation with valid modulecontextid returns activity URL.
161+ * @covers \block_qrcode\output_image::course_link_url
162+ */
163+ public function test_course_link_url_with_activity (): void {
164+ global $ DB ;
165+
166+ set_config ('custom_wwwroot ' , '' , 'block_qrcode ' );
167+
168+ // Create a forum activity.
169+ $ forum = $ this ->getDataGenerator ()->create_module ('forum ' , ['course ' => $ this ->course ->id ]);
170+ $ cm = $ DB ->get_record ('course_modules ' , ['course ' => $ this ->course ->id , 'instance ' => $ forum ->id ]);
171+
172+ $ image = new output_image (1 , 150 , $ this ->course ->id , $ this ->block ->id , $ cm ->id );
173+ $ url = $ image ->course_link_url ();
174+
175+ $ this ->assertStringContainsString ('/mod/forum/view.php ' , $ url ->out (false ));
176+ $ this ->assertStringContainsString ('id= ' . $ cm ->id , $ url ->out (false ));
177+ $ this ->assertStringContainsString ('utm_source=block_qrcode ' , $ url ->out (false ));
178+ }
179+
180+ /**
181+ * The course link generation with activity falls back to course URL if module not found.
182+ * @covers \block_qrcode\output_image::course_link_url
183+ */
184+ public function test_course_link_url_with_invalid_activity (): void {
185+ set_config ('custom_wwwroot ' , '' , 'block_qrcode ' );
186+
187+ // Use a non-existent modulecontextid.
188+ $ image = new output_image (1 , 150 , $ this ->course ->id , $ this ->block ->id , 99999 );
189+
190+ $ expectedurl = new url ('/course/view.php ' , [
191+ 'id ' => $ this ->course ->id ,
192+ 'utm_source ' => 'block_qrcode ' ,
193+ ]);
194+
195+ // Should fall back to course URL.
196+ $ this ->assertEquals ($ expectedurl , $ image ->course_link_url ());
197+ }
198+
199+ /**
200+ * The course link generation respects custom wwwroot with activity URL.
201+ * @covers \block_qrcode\output_image::course_link_url
202+ */
203+ public function test_course_link_url_with_activity_and_custom_wwwroot (): void {
204+ global $ DB ;
205+
206+ $ customwwwroot = 'https://moodle.example.de ' ;
207+ set_config ('custom_wwwroot ' , $ customwwwroot , 'block_qrcode ' );
208+
209+ // Create a quiz activity.
210+ $ quiz = $ this ->getDataGenerator ()->create_module ('quiz ' , ['course ' => $ this ->course ->id ]);
211+ $ cm = $ DB ->get_record ('course_modules ' , ['course ' => $ this ->course ->id , 'instance ' => $ quiz ->id ]);
212+
213+ $ image = new output_image (1 , 150 , $ this ->course ->id , $ this ->block ->id , $ cm ->id );
214+ $ url = $ image ->course_link_url ();
215+
216+ $ this ->assertStringContainsString ($ customwwwroot . '/mod/quiz/view.php ' , $ url ->out (false ));
217+ $ this ->assertStringContainsString ('id= ' . $ cm ->id , $ url ->out (false ));
218+ }
219+
220+ /**
221+ * The output_image constructor accepts optional modulecontextid parameter.
222+ * @covers \block_qrcode\output_image::__construct
223+ */
224+ public function test_output_image_constructor_with_modulecontextid (): void {
225+ global $ DB ;
226+
227+ // Create an assignment activity.
228+ $ assign = $ this ->getDataGenerator ()->create_module ('assign ' , ['course ' => $ this ->course ->id ]);
229+ $ cm = $ DB ->get_record ('course_modules ' , ['course ' => $ this ->course ->id , 'instance ' => $ assign ->id ]);
230+
231+ // Should not throw any exceptions.
232+ $ image = new output_image (1 , 150 , $ this ->course ->id , $ this ->block ->id , $ cm ->id );
233+ $ this ->assertInstanceOf (output_image::class, $ image );
234+ }
235+
236+ /**
237+ * Different activity types generate correct module URLs.
238+ * @covers \block_qrcode\output_image::course_link_url
239+ */
240+ public function test_course_link_url_with_different_activity_types (): void {
241+ global $ DB ;
242+
243+ set_config ('custom_wwwroot ' , '' , 'block_qrcode ' );
244+
245+ // Test with different activity types.
246+ $ activity_types = ['forum ' , 'quiz ' , 'assign ' ];
247+
248+ foreach ($ activity_types as $ type ) {
249+ $ activity = $ this ->getDataGenerator ()->create_module ($ type , ['course ' => $ this ->course ->id ]);
250+ $ cm = $ DB ->get_record ('course_modules ' , ['course ' => $ this ->course ->id , 'instance ' => $ activity ->id ]);
251+
252+ $ image = new output_image (1 , 150 , $ this ->course ->id , $ this ->block ->id , $ cm ->id );
253+ $ url = $ image ->course_link_url ()->out (false );
254+
255+ $ this ->assertStringContainsString ("/mod/ {$ type }/view.php " , $ url );
256+ $ this ->assertStringContainsString ('id= ' . $ cm ->id , $ url );
257+ }
258+ }
142259}
0 commit comments