See Release Notes
Long Term Support Release
Differences Between: [Versions 310 and 401] [Versions 39 and 401]
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 /** 18 * Tests for class core_course_category methods invoking hooks. 19 * 20 * @package core_course 21 * @category test 22 * @copyright 2020 Ruslan Kabalin 23 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 24 */ 25 26 namespace core_course; 27 28 defined('MOODLE_INTERNAL') || die(); 29 30 global $CFG; 31 require_once($CFG->dirroot . '/course/tests/fixtures/mock_hooks.php'); 32 33 use PHPUnit\Framework\MockObject\MockObject; 34 use core_course\test\mock_hooks; 35 36 /** 37 * Functional test for class core_course_category methods invoking hooks. 38 */ 39 class category_hooks_test extends \advanced_testcase { 40 41 protected function setUp(): void { 42 $this->resetAfterTest(); 43 $this->setAdminUser(); 44 } 45 46 /** 47 * Provides mocked category configured for named callback function. 48 * 49 * get_plugins_callback_function will return callable prefixed with `tool_unittest_`, 50 * the actual callbacks are defined in mock_hooks.php fixture file. 51 * 52 * @param core_course_category $category Category to mock 53 * @param string $callback Callback function used in method we test. 54 * @return MockObject 55 */ 56 public function get_mock_category(\core_course_category $category, string $callback = '') : MockObject { 57 // Setup mock object for \core_course_category. 58 // Disable original constructor, since we can't use it directly since it is private. 59 $mockcategory = $this->getMockBuilder(\core_course_category::class) 60 ->onlyMethods(['get_plugins_callback_function']) 61 ->disableOriginalConstructor() 62 ->getMock(); 63 64 // Define get_plugins_callback_function use and return value. 65 if (!empty($callback)) { 66 $mockcategory->method('get_plugins_callback_function') 67 ->with($this->equalTo($callback)) 68 ->willReturn(['tool_unittest_' . $callback]); 69 } 70 71 // Modify constructor visibility and invoke mock object with real object. 72 // This is used to overcome private constructor. 73 $reflected = new \ReflectionClass(\core_course_category::class); 74 $constructor = $reflected->getConstructor(); 75 $constructor->setAccessible(true); 76 $constructor->invoke($mockcategory, $category->get_db_record()); 77 78 return $mockcategory; 79 } 80 81 public function test_can_course_category_delete_hook() { 82 $category1 = \core_course_category::create(array('name' => 'Cat1')); 83 $category2 = \core_course_category::create(array('name' => 'Cat2', 'parent' => $category1->id)); 84 $category3 = \core_course_category::create(array('name' => 'Cat3')); 85 86 $mockcategory2 = $this->get_mock_category($category2, 'can_course_category_delete'); 87 88 // Add course to mocked clone of category2. 89 $course1 = $this->getDataGenerator()->create_course(array('category' => $mockcategory2->id)); 90 91 // Now configure fixture to return false for the callback. 92 mock_hooks::set_can_course_category_delete_return(false); 93 $this->assertFalse($mockcategory2->can_delete_full($category3->id)); 94 95 // Now configure fixture to return true for the callback. 96 mock_hooks::set_can_course_category_delete_return(true); 97 $this->assertTrue($mockcategory2->can_delete_full($category3->id)); 98 99 // Verify passed arguments. 100 $arguments = mock_hooks::get_calling_arguments(); 101 $this->assertCount(1, $arguments); 102 103 // Argument 1 is the same core_course_category instance. 104 $argument = array_shift($arguments); 105 $this->assertSame($mockcategory2, $argument); 106 } 107 108 public function test_can_course_category_delete_move_hook() { 109 $category1 = \core_course_category::create(array('name' => 'Cat1')); 110 $category2 = \core_course_category::create(array('name' => 'Cat2', 'parent' => $category1->id)); 111 $category3 = \core_course_category::create(array('name' => 'Cat3')); 112 113 $mockcategory2 = $this->get_mock_category($category2, 'can_course_category_delete_move'); 114 115 // Add course to mocked clone of category2. 116 $course1 = $this->getDataGenerator()->create_course(array('category' => $mockcategory2->id)); 117 118 // Now configure fixture to return false for the callback. 119 mock_hooks::set_can_course_category_delete_move_return(false); 120 $this->assertFalse($mockcategory2->can_move_content_to($category3->id)); 121 122 // Now configure fixture to return true for the callback. 123 mock_hooks::set_can_course_category_delete_move_return(true); 124 $this->assertTrue($mockcategory2->can_move_content_to($category3->id)); 125 126 // Verify passed arguments. 127 $arguments = mock_hooks::get_calling_arguments(); 128 $this->assertCount(2, $arguments); 129 130 // Argument 1 is the same core_course_category instance. 131 $argument = array_shift($arguments); 132 $this->assertSame($mockcategory2, $argument); 133 134 // Argument 2 is referring to category 3. 135 $argument = array_shift($arguments); 136 $this->assertInstanceOf(\core_course_category::class, $argument); 137 $this->assertEquals($category3->id, $argument->id); 138 } 139 140 public function test_pre_course_category_delete_hook() { 141 $category1 = \core_course_category::create(array('name' => 'Cat1')); 142 $category2 = \core_course_category::create(array('name' => 'Cat2', 'parent' => $category1->id)); 143 144 $mockcategory2 = $this->get_mock_category($category2, 'pre_course_category_delete'); 145 $mockcategory2->delete_full(); 146 147 // Verify passed arguments. 148 $arguments = mock_hooks::get_calling_arguments(); 149 $this->assertCount(1, $arguments); 150 151 // Argument 1 is the category object. 152 $argument = array_shift($arguments); 153 $this->assertEquals($mockcategory2->get_db_record(), $argument); 154 } 155 156 public function test_pre_course_category_delete_move_hook() { 157 $category1 = \core_course_category::create(array('name' => 'Cat1')); 158 $category2 = \core_course_category::create(array('name' => 'Cat2', 'parent' => $category1->id)); 159 $category3 = \core_course_category::create(array('name' => 'Cat3')); 160 161 $mockcategory2 = $this->get_mock_category($category2, 'pre_course_category_delete_move'); 162 163 // Add course to mocked clone of category2. 164 $course1 = $this->getDataGenerator()->create_course(array('category' => $mockcategory2->id)); 165 166 $mockcategory2->delete_move($category3->id); 167 168 // Verify passed arguments. 169 $arguments = mock_hooks::get_calling_arguments(); 170 $this->assertCount(2, $arguments); 171 172 // Argument 1 is the same core_course_category instance. 173 $argument = array_shift($arguments); 174 $this->assertSame($mockcategory2, $argument); 175 176 // Argument 2 is referring to category 3. 177 $argument = array_shift($arguments); 178 $this->assertInstanceOf(\core_course_category::class, $argument); 179 $this->assertEquals($category3->id, $argument->id); 180 } 181 182 public function test_get_course_category_contents_hook() { 183 $category1 = \core_course_category::create(array('name' => 'Cat1')); 184 $category2 = \core_course_category::create(array('name' => 'Cat2', 'parent' => $category1->id)); 185 186 $mockcategory2 = $this->get_mock_category($category2); 187 188 // Define get_plugins_callback_function use in the mock, it is called twice for different callback in the form. 189 $mockcategory2->expects($this->exactly(2)) 190 ->method('get_plugins_callback_function') 191 ->withConsecutive( 192 [$this->equalTo('can_course_category_delete')], 193 [$this->equalTo('get_course_category_contents')] 194 ) 195 ->willReturn( 196 ['tool_unittest_can_course_category_delete'], 197 ['tool_unittest_get_course_category_contents'] 198 ); 199 200 // Now configure fixture to return string for the callback. 201 $content = 'Bunch of test artefacts'; 202 mock_hooks::set_get_course_category_contents_return($content); 203 204 $mform = new \core_course_deletecategory_form(null, $mockcategory2); 205 $this->expectOutputRegex("/<li>$content<\/li>/"); 206 $mform->display(); 207 208 // Verify passed arguments. 209 $arguments = mock_hooks::get_calling_arguments(); 210 $this->assertCount(1, $arguments); 211 212 // Argument 1 is the same core_course_category instance. 213 $argument = array_shift($arguments); 214 $this->assertSame($mockcategory2, $argument); 215 } 216 }
title
Description
Body
title
Description
Body
title
Description
Body
title
Body