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