Differences Between: [Versions 310 and 402] [Versions 311 and 402] [Versions 39 and 402]
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 core_analytics; 18 19 defined('MOODLE_INTERNAL') || die(); 20 21 require_once (__DIR__ . '/fixtures/test_indicator_max.php'); 22 require_once (__DIR__ . '/fixtures/test_indicator_min.php'); 23 require_once (__DIR__ . '/fixtures/test_indicator_fullname.php'); 24 require_once (__DIR__ . '/fixtures/test_target_course_level_shortname.php'); 25 26 /** 27 * Unit tests for the core_analytics manager. 28 * 29 * @package core_analytics 30 * @copyright 2017 David MonllaĆ³ {@link http://www.davidmonllao.com} 31 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 32 * @covers \core_analytics\manager 33 */ 34 class manager_test extends \advanced_testcase { 35 36 /** 37 * test_deleted_context 38 */ 39 public function test_deleted_context() { 40 global $DB; 41 42 $this->resetAfterTest(true); 43 $this->setAdminuser(); 44 set_config('enabled_stores', 'logstore_standard', 'tool_log'); 45 46 $target = \core_analytics\manager::get_target('test_target_course_level_shortname'); 47 $indicators = array('test_indicator_max', 'test_indicator_min', 'test_indicator_fullname'); 48 foreach ($indicators as $key => $indicator) { 49 $indicators[$key] = \core_analytics\manager::get_indicator($indicator); 50 } 51 52 $model = \core_analytics\model::create($target, $indicators); 53 $modelobj = $model->get_model_obj(); 54 55 $coursepredict1 = $this->getDataGenerator()->create_course(array('visible' => 0)); 56 $coursepredict2 = $this->getDataGenerator()->create_course(array('visible' => 0)); 57 $coursetrain1 = $this->getDataGenerator()->create_course(array('visible' => 1)); 58 $coursetrain2 = $this->getDataGenerator()->create_course(array('visible' => 1)); 59 60 $model->enable('\core\analytics\time_splitting\no_splitting'); 61 62 $model->train(); 63 $model->predict(); 64 65 // Generate a prediction action to confirm that it is deleted when there is an important update. 66 $predictions = $DB->get_records('analytics_predictions'); 67 $prediction = reset($predictions); 68 $prediction = new \core_analytics\prediction($prediction, array('whatever' => 'not used')); 69 $prediction->action_executed(\core_analytics\prediction::ACTION_USEFUL, $model->get_target()); 70 71 $predictioncontextid = $prediction->get_prediction_data()->contextid; 72 73 $npredictions = $DB->count_records('analytics_predictions', array('contextid' => $predictioncontextid)); 74 $npredictionactions = $DB->count_records('analytics_prediction_actions', 75 array('predictionid' => $prediction->get_prediction_data()->id)); 76 $nindicatorcalc = $DB->count_records('analytics_indicator_calc', array('contextid' => $predictioncontextid)); 77 78 \core_analytics\manager::cleanup(); 79 80 // Nothing is incorrectly deleted. 81 $this->assertEquals($npredictions, $DB->count_records('analytics_predictions', 82 array('contextid' => $predictioncontextid))); 83 $this->assertEquals($npredictionactions, $DB->count_records('analytics_prediction_actions', 84 array('predictionid' => $prediction->get_prediction_data()->id))); 85 $this->assertEquals($nindicatorcalc, $DB->count_records('analytics_indicator_calc', 86 array('contextid' => $predictioncontextid))); 87 88 // Now we delete a context, the course predictions and prediction actions should be deleted. 89 $deletedcontext = \context::instance_by_id($predictioncontextid); 90 delete_course($deletedcontext->instanceid, false); 91 92 \core_analytics\manager::cleanup(); 93 94 $this->assertEmpty($DB->count_records('analytics_predictions', array('contextid' => $predictioncontextid))); 95 $this->assertEmpty($DB->count_records('analytics_prediction_actions', 96 array('predictionid' => $prediction->get_prediction_data()->id))); 97 $this->assertEmpty($DB->count_records('analytics_indicator_calc', array('contextid' => $predictioncontextid))); 98 99 set_config('enabled_stores', '', 'tool_log'); 100 get_log_manager(true); 101 } 102 103 /** 104 * test_deleted_analysable 105 */ 106 public function test_deleted_analysable() { 107 global $DB; 108 109 $this->resetAfterTest(true); 110 $this->setAdminuser(); 111 set_config('enabled_stores', 'logstore_standard', 'tool_log'); 112 113 $target = \core_analytics\manager::get_target('test_target_course_level_shortname'); 114 $indicators = array('test_indicator_max', 'test_indicator_min', 'test_indicator_fullname'); 115 foreach ($indicators as $key => $indicator) { 116 $indicators[$key] = \core_analytics\manager::get_indicator($indicator); 117 } 118 119 $model = \core_analytics\model::create($target, $indicators); 120 $modelobj = $model->get_model_obj(); 121 122 $coursepredict1 = $this->getDataGenerator()->create_course(array('visible' => 0)); 123 $coursepredict2 = $this->getDataGenerator()->create_course(array('visible' => 0)); 124 $coursetrain1 = $this->getDataGenerator()->create_course(array('visible' => 1)); 125 $coursetrain2 = $this->getDataGenerator()->create_course(array('visible' => 1)); 126 127 $model->enable('\core\analytics\time_splitting\no_splitting'); 128 129 $model->train(); 130 $model->predict(); 131 132 $this->assertNotEmpty($DB->count_records('analytics_predict_samples')); 133 $this->assertNotEmpty($DB->count_records('analytics_train_samples')); 134 $this->assertNotEmpty($DB->count_records('analytics_used_analysables')); 135 136 // Now we delete an analysable, stored predict and training samples should be deleted. 137 $deletedcontext = \context_course::instance($coursepredict1->id); 138 delete_course($coursepredict1, false); 139 140 \core_analytics\manager::cleanup(); 141 142 $this->assertEmpty($DB->count_records('analytics_predict_samples', array('analysableid' => $coursepredict1->id))); 143 $this->assertEmpty($DB->count_records('analytics_train_samples', array('analysableid' => $coursepredict1->id))); 144 $this->assertEmpty($DB->count_records('analytics_used_analysables', array('analysableid' => $coursepredict1->id))); 145 146 set_config('enabled_stores', '', 'tool_log'); 147 get_log_manager(true); 148 } 149 150 /** 151 * Tests for the {@link \core_analytics\manager::load_default_models_for_component()} implementation. 152 */ 153 public function test_load_default_models_for_component() { 154 $this->resetAfterTest(); 155 156 // Attempting to load builtin models should always work without throwing exception. 157 \core_analytics\manager::load_default_models_for_component('core'); 158 159 // Attempting to load from a core subsystem without its own subsystem directory. 160 $this->assertSame([], \core_analytics\manager::load_default_models_for_component('core_access')); 161 162 // Attempting to load from a non-existing subsystem. 163 $this->assertSame([], \core_analytics\manager::load_default_models_for_component('core_nonexistingsubsystem')); 164 165 // Attempting to load from a non-existing plugin of a known plugin type. 166 $this->assertSame([], \core_analytics\manager::load_default_models_for_component('mod_foobarbazquaz12240996776')); 167 168 // Attempting to load from a non-existing plugin type. 169 $this->assertSame([], \core_analytics\manager::load_default_models_for_component('foo_bar2776327736558')); 170 } 171 172 /** 173 * Tests for the {@link \core_analytics\manager::load_default_models_for_all_components()} implementation. 174 */ 175 public function test_load_default_models_for_all_components() { 176 $this->resetAfterTest(); 177 178 $models = \core_analytics\manager::load_default_models_for_all_components(); 179 180 $this->assertTrue(is_array($models['core'])); 181 $this->assertNotEmpty($models['core']); 182 $this->assertNotEmpty($models['core'][0]['target']); 183 $this->assertNotEmpty($models['core'][0]['indicators']); 184 } 185 186 /** 187 * Tests for the successful execution of the {@link \core_analytics\manager::validate_models_declaration()}. 188 */ 189 public function test_validate_models_declaration() { 190 $this->resetAfterTest(); 191 192 // This is expected to run without an exception. 193 $models = $this->load_models_from_fixture_file('no_teaching'); 194 \core_analytics\manager::validate_models_declaration($models); 195 } 196 197 /** 198 * Tests for the exceptions thrown by {@link \core_analytics\manager::validate_models_declaration()}. 199 * 200 * @dataProvider validate_models_declaration_exceptions_provider 201 * @param array $models Models declaration. 202 * @param string $exception Expected coding exception message. 203 */ 204 public function test_validate_models_declaration_exceptions(array $models, string $exception) { 205 $this->resetAfterTest(); 206 207 $this->expectException(\coding_exception::class); 208 $this->expectExceptionMessage($exception); 209 \core_analytics\manager::validate_models_declaration($models); 210 } 211 212 /** 213 * Data provider for the {@link self::test_validate_models_declaration_exceptions()}. 214 * 215 * @return array of (string)testcase => [(array)models, (string)expected exception message] 216 */ 217 public function validate_models_declaration_exceptions_provider() { 218 return [ 219 'missing_target' => [ 220 $this->load_models_from_fixture_file('missing_target'), 221 'Missing target declaration', 222 ], 223 'invalid_target' => [ 224 $this->load_models_from_fixture_file('invalid_target'), 225 'Invalid target classname', 226 ], 227 'missing_indicators' => [ 228 $this->load_models_from_fixture_file('missing_indicators'), 229 'Missing indicators declaration', 230 ], 231 'invalid_indicators' => [ 232 $this->load_models_from_fixture_file('invalid_indicators'), 233 'Invalid indicator classname', 234 ], 235 'invalid_time_splitting' => [ 236 $this->load_models_from_fixture_file('invalid_time_splitting'), 237 'Invalid time splitting classname', 238 ], 239 'invalid_time_splitting_fq' => [ 240 $this->load_models_from_fixture_file('invalid_time_splitting_fq'), 241 'Expecting fully qualified time splitting classname', 242 ], 243 'invalid_enabled' => [ 244 $this->load_models_from_fixture_file('invalid_enabled'), 245 'Cannot enable a model without time splitting method specified', 246 ], 247 ]; 248 } 249 250 /** 251 * Loads models as declared in the given fixture file. 252 * 253 * @param string $filename 254 * @return array 255 */ 256 protected function load_models_from_fixture_file(string $filename) { 257 global $CFG; 258 259 $models = null; 260 261 require($CFG->dirroot.'/analytics/tests/fixtures/db_analytics_php/'.$filename.'.php'); 262 263 return $models; 264 } 265 266 /** 267 * Test the implementation of the {@link \core_analytics\manager::create_declared_model()}. 268 */ 269 public function test_create_declared_model() { 270 global $DB; 271 272 $this->resetAfterTest(); 273 $this->setAdminuser(); 274 275 $declaration = [ 276 'target' => 'test_target_course_level_shortname', 277 'indicators' => [ 278 'test_indicator_max', 279 'test_indicator_min', 280 'test_indicator_fullname', 281 ], 282 ]; 283 284 $declarationwithtimesplitting = array_merge($declaration, [ 285 'timesplitting' => '\core\analytics\time_splitting\no_splitting', 286 ]); 287 288 $declarationwithtimesplittingenabled = array_merge($declarationwithtimesplitting, [ 289 'enabled' => true, 290 ]); 291 292 // Check that no such model exists yet. 293 $target = \core_analytics\manager::get_target('test_target_course_level_shortname'); 294 $this->assertEquals(0, $DB->count_records('analytics_models', ['target' => $target->get_id()])); 295 $this->assertFalse(\core_analytics\model::exists($target)); 296 297 // Check that the model is created. 298 $created = \core_analytics\manager::create_declared_model($declaration); 299 $this->assertTrue($created instanceof \core_analytics\model); 300 $this->assertTrue(\core_analytics\model::exists($target)); 301 $this->assertEquals(1, $DB->count_records('analytics_models', ['target' => $target->get_id()])); 302 $modelid = $created->get_id(); 303 304 // Check that created models are disabled by default. 305 $existing = new \core_analytics\model($modelid); 306 $this->assertEquals(0, $existing->get_model_obj()->enabled); 307 $this->assertEquals(0, $DB->get_field('analytics_models', 'enabled', ['target' => $target->get_id()], MUST_EXIST)); 308 309 // Let the admin enable the model. 310 $existing->enable('\core\analytics\time_splitting\no_splitting'); 311 $this->assertEquals(1, $DB->get_field('analytics_models', 'enabled', ['target' => $target->get_id()], MUST_EXIST)); 312 313 // Check that further calls create a new model. 314 $repeated = \core_analytics\manager::create_declared_model($declaration); 315 $this->assertTrue($repeated instanceof \core_analytics\model); 316 $this->assertEquals(2, $DB->count_records('analytics_models', ['target' => $target->get_id()])); 317 318 // Delete the models. 319 $existing->delete(); 320 $repeated->delete(); 321 $this->assertEquals(0, $DB->count_records('analytics_models', ['target' => $target->get_id()])); 322 $this->assertFalse(\core_analytics\model::exists($target)); 323 324 // Create it again, this time with time splitting method specified. 325 $created = \core_analytics\manager::create_declared_model($declarationwithtimesplitting); 326 $this->assertTrue($created instanceof \core_analytics\model); 327 $this->assertTrue(\core_analytics\model::exists($target)); 328 $this->assertEquals(1, $DB->count_records('analytics_models', ['target' => $target->get_id()])); 329 $modelid = $created->get_id(); 330 331 // Even if the time splitting method was specified, the model is still not enabled automatically. 332 $existing = new \core_analytics\model($modelid); 333 $this->assertEquals(0, $existing->get_model_obj()->enabled); 334 $this->assertEquals(0, $DB->get_field('analytics_models', 'enabled', ['target' => $target->get_id()], MUST_EXIST)); 335 $existing->delete(); 336 337 // Let's define the model so that it is enabled by default. 338 $enabled = \core_analytics\manager::create_declared_model($declarationwithtimesplittingenabled); 339 $this->assertTrue($enabled instanceof \core_analytics\model); 340 $this->assertTrue(\core_analytics\model::exists($target)); 341 $this->assertEquals(1, $DB->count_records('analytics_models', ['target' => $target->get_id()])); 342 $modelid = $enabled->get_id(); 343 $existing = new \core_analytics\model($modelid); 344 $this->assertEquals(1, $existing->get_model_obj()->enabled); 345 $this->assertEquals(1, $DB->get_field('analytics_models', 'enabled', ['target' => $target->get_id()], MUST_EXIST)); 346 347 // Let the admin disable the model. 348 $existing->update(0, false, false); 349 $this->assertEquals(0, $DB->get_field('analytics_models', 'enabled', ['target' => $target->get_id()], MUST_EXIST)); 350 } 351 352 /** 353 * Test the implementation of the {@link \core_analytics\manager::update_default_models_for_component()}. 354 */ 355 public function test_update_default_models_for_component() { 356 357 $this->resetAfterTest(); 358 $this->setAdminuser(); 359 360 $noteaching = \core_analytics\manager::get_target('\core_course\analytics\target\no_teaching'); 361 $dropout = \core_analytics\manager::get_target('\core_course\analytics\target\course_dropout'); 362 $upcomingactivities = \core_analytics\manager::get_target('\core_user\analytics\target\upcoming_activities_due'); 363 $norecentaccesses = \core_analytics\manager::get_target('\core_course\analytics\target\no_recent_accesses'); 364 $noaccesssincestart = \core_analytics\manager::get_target('\core_course\analytics\target\no_access_since_course_start'); 365 366 $this->assertTrue(\core_analytics\model::exists($noteaching)); 367 $this->assertTrue(\core_analytics\model::exists($dropout)); 368 $this->assertTrue(\core_analytics\model::exists($upcomingactivities)); 369 $this->assertTrue(\core_analytics\model::exists($norecentaccesses)); 370 $this->assertTrue(\core_analytics\model::exists($noaccesssincestart)); 371 372 foreach (\core_analytics\manager::get_all_models() as $model) { 373 $model->delete(); 374 } 375 376 $this->assertFalse(\core_analytics\model::exists($noteaching)); 377 $this->assertFalse(\core_analytics\model::exists($dropout)); 378 $this->assertFalse(\core_analytics\model::exists($upcomingactivities)); 379 $this->assertFalse(\core_analytics\model::exists($norecentaccesses)); 380 $this->assertFalse(\core_analytics\model::exists($noaccesssincestart)); 381 382 $updated = \core_analytics\manager::update_default_models_for_component('moodle'); 383 384 $this->assertEquals(5, count($updated)); 385 $this->assertTrue(array_pop($updated) instanceof \core_analytics\model); 386 $this->assertTrue(array_pop($updated) instanceof \core_analytics\model); 387 $this->assertTrue(array_pop($updated) instanceof \core_analytics\model); 388 $this->assertTrue(array_pop($updated) instanceof \core_analytics\model); 389 $this->assertTrue(array_pop($updated) instanceof \core_analytics\model); 390 $this->assertTrue(\core_analytics\model::exists($noteaching)); 391 $this->assertTrue(\core_analytics\model::exists($dropout)); 392 $this->assertTrue(\core_analytics\model::exists($upcomingactivities)); 393 $this->assertTrue(\core_analytics\model::exists($norecentaccesses)); 394 $this->assertTrue(\core_analytics\model::exists($noaccesssincestart)); 395 396 $repeated = \core_analytics\manager::update_default_models_for_component('moodle'); 397 398 $this->assertSame([], $repeated); 399 } 400 401 /** 402 * test_get_time_splitting_methods description 403 * @return null 404 */ 405 public function test_get_time_splitting_methods() { 406 $this->resetAfterTest(true); 407 408 $all = \core_analytics\manager::get_all_time_splittings(); 409 $this->assertArrayHasKey('\core\analytics\time_splitting\upcoming_week', $all); 410 $this->assertArrayHasKey('\core\analytics\time_splitting\quarters', $all); 411 412 $allforevaluation = \core_analytics\manager::get_time_splitting_methods_for_evaluation(true); 413 $this->assertArrayNotHasKey('\core\analytics\time_splitting\upcoming_week', $allforevaluation); 414 $this->assertArrayHasKey('\core\analytics\time_splitting\quarters', $allforevaluation); 415 416 $defaultforevaluation = \core_analytics\manager::get_time_splitting_methods_for_evaluation(false); 417 $this->assertArrayNotHasKey('\core\analytics\time_splitting\upcoming_week', $defaultforevaluation); 418 $this->assertArrayHasKey('\core\analytics\time_splitting\quarters', $defaultforevaluation); 419 420 $sometimesplittings = '\core\analytics\time_splitting\single_range,' . 421 '\core\analytics\time_splitting\tenths'; 422 set_config('defaulttimesplittingsevaluation', $sometimesplittings, 'analytics'); 423 424 $defaultforevaluation = \core_analytics\manager::get_time_splitting_methods_for_evaluation(false); 425 $this->assertArrayNotHasKey('\core\analytics\time_splitting\quarters', $defaultforevaluation); 426 } 427 428 /** 429 * Test the implementation of the {@link \core_analytics\manager::model_declaration_identifier()}. 430 */ 431 public function test_model_declaration_identifier() { 432 433 $noteaching1 = $this->load_models_from_fixture_file('no_teaching'); 434 $noteaching2 = $this->load_models_from_fixture_file('no_teaching'); 435 $noteaching3 = $this->load_models_from_fixture_file('no_teaching'); 436 437 // Same model declaration should always lead to same identifier. 438 $this->assertEquals( 439 \core_analytics\manager::model_declaration_identifier(reset($noteaching1)), 440 \core_analytics\manager::model_declaration_identifier(reset($noteaching2)) 441 ); 442 443 // If something is changed, the identifier should change, too. 444 $noteaching2[0]['target'] .= '_'; 445 $this->assertNotEquals( 446 \core_analytics\manager::model_declaration_identifier(reset($noteaching1)), 447 \core_analytics\manager::model_declaration_identifier(reset($noteaching2)) 448 ); 449 450 $noteaching3[0]['indicators'][] = '\core_analytics\local\indicator\binary'; 451 $this->assertNotEquals( 452 \core_analytics\manager::model_declaration_identifier(reset($noteaching1)), 453 \core_analytics\manager::model_declaration_identifier(reset($noteaching3)) 454 ); 455 456 // The identifier is supposed to contain PARAM_ALPHANUM only. 457 $this->assertEquals( 458 \core_analytics\manager::model_declaration_identifier(reset($noteaching1)), 459 clean_param(\core_analytics\manager::model_declaration_identifier(reset($noteaching1)), PARAM_ALPHANUM) 460 ); 461 $this->assertEquals( 462 \core_analytics\manager::model_declaration_identifier(reset($noteaching2)), 463 clean_param(\core_analytics\manager::model_declaration_identifier(reset($noteaching2)), PARAM_ALPHANUM) 464 ); 465 $this->assertEquals( 466 \core_analytics\manager::model_declaration_identifier(reset($noteaching3)), 467 clean_param(\core_analytics\manager::model_declaration_identifier(reset($noteaching3)), PARAM_ALPHANUM) 468 ); 469 } 470 471 /** 472 * Tests for the {@link \core_analytics\manager::get_declared_target_and_indicators_instances()}. 473 */ 474 public function test_get_declared_target_and_indicators_instances() { 475 $this->resetAfterTest(); 476 477 $definition = $this->load_models_from_fixture_file('no_teaching'); 478 479 list($target, $indicators) = \core_analytics\manager::get_declared_target_and_indicators_instances($definition[0]); 480 481 $this->assertTrue($target instanceof \core_analytics\local\target\base); 482 $this->assertNotEmpty($indicators); 483 $this->assertContainsOnlyInstancesOf(\core_analytics\local\indicator\base::class, $indicators); 484 } 485 486 /** 487 * test_get_potential_context_restrictions description 488 */ 489 public function test_get_potential_context_restrictions() { 490 $this->resetAfterTest(); 491 492 // No potential context restrictions. 493 $this->assertFalse(\core_analytics\manager::get_potential_context_restrictions([])); 494 495 $defaultcategory = \core_course_category::get_default(); 496 $defaultcategorycontext = $defaultcategory->get_context(); 497 498 // Include the all context levels so the misc. category get included. 499 $this->assertEquals([ 500 $defaultcategorycontext->id => "Category: {$defaultcategory->name}", 501 ], manager::get_potential_context_restrictions()); 502 503 $category = $this->getDataGenerator()->create_category(['name' => 'My category']); 504 $categorycontext = $category->get_context(); 505 506 $courseone = $this->getDataGenerator()->create_course(['fullname' => 'Course one', 'shortname' => 'CS1']); 507 $courseonecontext = \context_course::instance($courseone->id); 508 509 $coursetwo = $this->getDataGenerator()->create_course(['fullname' => 'Course two', 'shortname' => 'CS2']); 510 $coursetwocontext = \context_course::instance($coursetwo->id); 511 512 // All context levels. 513 $this->assertEqualsCanonicalizing([ 514 $defaultcategorycontext->id => "Category: {$defaultcategory->name}", 515 $categorycontext->id => "Category: {$category->name}", 516 $courseonecontext->id => "Course: {$courseone->shortname}", 517 $coursetwocontext->id => "Course: {$coursetwo->shortname}", 518 ], manager::get_potential_context_restrictions()); 519 520 // All category/course context levels. 521 $this->assertEqualsCanonicalizing([ 522 $defaultcategorycontext->id => "Category: {$defaultcategory->name}", 523 $categorycontext->id => "Category: {$category->name}", 524 $courseonecontext->id => "Course: {$courseone->shortname}", 525 $coursetwocontext->id => "Course: {$coursetwo->shortname}", 526 ], manager::get_potential_context_restrictions([CONTEXT_COURSECAT, CONTEXT_COURSE])); 527 528 // All category context levels. 529 $this->assertEqualsCanonicalizing([ 530 $defaultcategorycontext->id => "Category: {$defaultcategory->name}", 531 $categorycontext->id => "Category: {$category->name}", 532 ], manager::get_potential_context_restrictions([CONTEXT_COURSECAT])); 533 534 // Filtered category context levels. 535 $this->assertEquals([ 536 $categorycontext->id => "Category: {$category->name}", 537 ], manager::get_potential_context_restrictions([CONTEXT_COURSECAT], 'My cat')); 538 539 $this->assertEmpty(manager::get_potential_context_restrictions([CONTEXT_COURSECAT], 'nothing')); 540 541 // All course context levels. 542 $this->assertEqualsCanonicalizing([ 543 $courseonecontext->id => "Course: {$courseone->shortname}", 544 $coursetwocontext->id => "Course: {$coursetwo->shortname}", 545 ], manager::get_potential_context_restrictions([CONTEXT_COURSE])); 546 547 // Filtered course context levels. 548 $this->assertEquals([ 549 $courseonecontext->id => "Course: {$courseone->shortname}", 550 ], manager::get_potential_context_restrictions([CONTEXT_COURSE], 'one')); 551 552 $this->assertEmpty(manager::get_potential_context_restrictions([CONTEXT_COURSE], 'nothing')); 553 } 554 }
title
Description
Body
title
Description
Body
title
Description
Body
title
Body