[ Index ]

PHP Cross Reference of Unnamed Project

title

Body

[close]

/tag/tests/ -> taglib_test.php (source)

   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   * Tag related unit tests.
  19   *
  20   * @package core_tag
  21   * @category test
  22   * @copyright 2014 Mark Nelson <markn@moodle.com>
  23   * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  24   */
  25  
  26  defined('MOODLE_INTERNAL') || die();
  27  
  28  global $CFG;
  29  
  30  class core_tag_taglib_testcase extends advanced_testcase {
  31  
  32      /**
  33       * Test set up.
  34       *
  35       * This is executed before running any test in this file.
  36       */
  37      public function setUp() {
  38          $this->resetAfterTest();
  39      }
  40  
  41      /**
  42       * Test the tag_set function.
  43       * This function was deprecated in 3.1
  44       */
  45      public function test_tag_set_get() {
  46          global $DB;
  47  
  48          // Create a course to tag.
  49          $course = $this->getDataGenerator()->create_course();
  50  
  51          // Create the tag and tag instance.
  52          tag_set('course', $course->id, array('A random tag'), 'core', context_course::instance($course->id)->id);
  53          $this->assertDebuggingCalled();
  54  
  55          // Get the tag instance that should have been created.
  56          $taginstance = $DB->get_record('tag_instance', array('itemtype' => 'course', 'itemid' => $course->id), '*', MUST_EXIST);
  57          $this->assertEquals('core', $taginstance->component);
  58          $this->assertEquals(context_course::instance($course->id)->id, $taginstance->contextid);
  59  
  60          $tagbyname = tag_get('name', 'A random tag');
  61          $this->assertDebuggingCalled();
  62          $this->assertEquals('A random tag', $tagbyname->rawname);
  63  
  64          $this->assertEmpty(tag_get('name', 'Non existing tag'));
  65          $this->assertDebuggingCalled();
  66  
  67          $tagbyid = tag_get('id', $tagbyname->id);
  68          $this->assertDebuggingCalled();
  69          $this->assertEquals('A random tag', $tagbyid->rawname);
  70          $tagid = $tagbyname->id;
  71  
  72          $this->assertEmpty(tag_get('id', $tagid + 1));
  73          $this->assertDebuggingCalled();
  74  
  75          tag_set('tag', $tagid, array('Some related tag'));
  76          $this->assertDebuggingCalled();
  77          $relatedtags = tag_get_related_tags($tagid);
  78          $this->assertDebuggingCalled();
  79          $this->assertCount(1, $relatedtags);
  80          $this->assertEquals('Some related tag', $relatedtags[0]->rawname);
  81  
  82          $tagids = tag_get_id(array('A random tag', 'Some related tag'));
  83          $this->assertDebuggingCalled();
  84          $this->assertCount(2, $tagids);
  85          $this->assertEquals($tagid, $tagids['a random tag']);
  86          $this->assertEquals($relatedtags[0]->id, $tagids['some related tag']);
  87      }
  88  
  89      /**
  90       * Test the tag_set_add function.
  91       * This function was deprecated in 3.1
  92       */
  93      public function test_tag_set_add() {
  94          global $DB;
  95  
  96          // Create a course to tag.
  97          $course = $this->getDataGenerator()->create_course();
  98  
  99          // Create the tag and tag instance.
 100          tag_set_add('course', $course->id, 'A random tag', 'core', context_course::instance($course->id)->id);
 101          $this->assertDebuggingCalled();
 102  
 103          // Get the tag instance that should have been created.
 104          $taginstance = $DB->get_record('tag_instance', array('itemtype' => 'course', 'itemid' => $course->id), '*', MUST_EXIST);
 105          $this->assertEquals('core', $taginstance->component);
 106          $this->assertEquals(context_course::instance($course->id)->id, $taginstance->contextid);
 107          $tagid = $taginstance->tagid;
 108  
 109          tag_set_add('tag', $tagid, 'Some related tag');
 110          $this->assertDebuggingCalled();
 111          $relatedtags = tag_get_related_tags($tagid);
 112          $this->assertDebuggingCalled();
 113          $this->assertCount(1, $relatedtags);
 114          $this->assertEquals('Some related tag', $relatedtags[0]->rawname);
 115      }
 116  
 117      /**
 118       * Test the tag_set_delete function.
 119       * This function was deprecated in 3.1
 120       */
 121      public function test_tag_set_delete() {
 122          global $DB;
 123  
 124          // Create a course to tag.
 125          $course = $this->getDataGenerator()->create_course();
 126  
 127          // Create the tag and tag instance we are going to delete.
 128          tag_set_add('course', $course->id, 'A random tag', 'core', context_course::instance($course->id)->id);
 129          $this->assertDebuggingCalled();
 130  
 131          // Call the tag_set_delete function.
 132          tag_set_delete('course', $course->id, 'a random tag', 'core', context_course::instance($course->id)->id);
 133          $this->assertDebuggingCalled();
 134  
 135          // Now check that there are no tags or tag instances.
 136          $this->assertEquals(0, $DB->count_records('tag'));
 137          $this->assertEquals(0, $DB->count_records('tag_instance'));
 138  
 139          // Add tag again, add and remove related tag.
 140          tag_set_add('course', $course->id, 'A random tag', 'core', context_course::instance($course->id)->id);
 141          $this->assertDebuggingCalled();
 142          $taginstance = $DB->get_record('tag_instance', array('itemtype' => 'course', 'itemid' => $course->id), '*', MUST_EXIST);
 143          $tagid = $taginstance->tagid;
 144          tag_set_add('tag', $tagid, 'Some related tag');
 145          $this->assertDebuggingCalled();
 146          tag_set_delete('tag', $tagid, 'Some related tag');
 147          $this->assertDebuggingCalled();
 148          $relatedtags = tag_get_related_tags($tagid);
 149          $this->assertDebuggingCalled();
 150          $this->assertCount(0, $relatedtags);
 151      }
 152  
 153      /**
 154       * Test the core_tag_tag::add_item_tag() and core_tag_tag::remove_item_tag() functions.
 155       */
 156      public function test_add_remove_item_tag() {
 157          global $DB;
 158  
 159          // Create a course to tag.
 160          $course = $this->getDataGenerator()->create_course();
 161  
 162          // Create the tag and tag instance we are going to delete.
 163          core_tag_tag::add_item_tag('core', 'course', $course->id, context_course::instance($course->id), 'A random tag');
 164  
 165          $this->assertEquals(1, $DB->count_records('tag'));
 166          $this->assertEquals(1, $DB->count_records('tag_instance'));
 167  
 168          // Call the tag_set_delete function.
 169          core_tag_tag::remove_item_tag('core', 'course', $course->id, 'A random tag');
 170  
 171          // Now check that there are no tags or tag instances.
 172          $this->assertEquals(0, $DB->count_records('tag'));
 173          $this->assertEquals(0, $DB->count_records('tag_instance'));
 174      }
 175  
 176      /**
 177       * Test the tag_assign function.
 178       * This function was deprecated in 3.1
 179       */
 180      public function test_tag_assign() {
 181          global $DB;
 182  
 183          // Create a course to tag.
 184          $course = $this->getDataGenerator()->create_course();
 185  
 186          // Create the tag.
 187          $tag = $this->getDataGenerator()->create_tag();
 188          $tag2 = $this->getDataGenerator()->create_tag();
 189  
 190          // Tag the course with the tag we created.
 191          tag_assign('course', $course->id, $tag->id, 0, 0, 'core', context_course::instance($course->id)->id);
 192          $this->assertDebuggingCalled();
 193  
 194          // Get the tag instance that should have been created.
 195          $taginstance = $DB->get_record('tag_instance', array('itemtype' => 'course', 'itemid' => $course->id), '*', MUST_EXIST);
 196          $this->assertEquals('core', $taginstance->component);
 197          $this->assertEquals(context_course::instance($course->id)->id, $taginstance->contextid);
 198  
 199          // Now call the tag_assign function without specifying the component or
 200          // contextid and ensure the function debugging is called twice.
 201          tag_assign('course', $course->id, $tag2->id, 0, 0);
 202          $this->assertDebuggingCalled();
 203      }
 204  
 205      /**
 206       * Test the tag cleanup function used by the cron.
 207       */
 208      public function test_tag_cleanup() {
 209          global $DB;
 210  
 211          $task = new \core\task\tag_cron_task();
 212  
 213          // Create some users.
 214          $users = array();
 215          for ($i = 0; $i < 10; $i++) {
 216              $users[] = $this->getDataGenerator()->create_user();
 217          }
 218  
 219          // Create a course to tag.
 220          $course = $this->getDataGenerator()->create_course();
 221          $context = context_course::instance($course->id);
 222  
 223          // Test clean up instances with tags that no longer exist.
 224          $tags = array();
 225          $tagnames = array();
 226          for ($i = 0; $i < 10; $i++) {
 227              $tags[] = $tag = $this->getDataGenerator()->create_tag(array('userid' => $users[0]->id));
 228              $tagnames[] = $tag->rawname;
 229          }
 230          // Create instances with the tags.
 231          core_tag_tag::set_item_tags('core', 'course', $course->id, $context, $tagnames);
 232          // We should now have ten tag instances.
 233          $coursetaginstances = $DB->count_records('tag_instance', array('itemtype' => 'course'));
 234          $this->assertEquals(10, $coursetaginstances);
 235  
 236          // Delete four tags
 237          // Manual delete of tags is done as the function will remove the instances as well.
 238          $DB->delete_records('tag', array('id' => $tags[6]->id));
 239          $DB->delete_records('tag', array('id' => $tags[7]->id));
 240          $DB->delete_records('tag', array('id' => $tags[8]->id));
 241          $DB->delete_records('tag', array('id' => $tags[9]->id));
 242  
 243          // Clean up the tags.
 244          $task->cleanup();
 245          // Check that we now only have six tag_instance records left.
 246          $coursetaginstances = $DB->count_records('tag_instance', array('itemtype' => 'course'));
 247          $this->assertEquals(6, $coursetaginstances);
 248  
 249          // Test clean up with users that have been deleted.
 250          // Create a tag for this course.
 251          foreach ($users as $user) {
 252              $context = context_user::instance($user->id);
 253              core_tag_tag::set_item_tags('core', 'user', $user->id, $context, array($tags[0]->rawname));
 254          }
 255          $usertags = $DB->count_records('tag_instance', array('itemtype' => 'user'));
 256          $this->assertCount($usertags, $users);
 257          // Remove three students.
 258          // Using the proper function to delete the user will also remove the tags.
 259          $DB->update_record('user', array('id' => $users[4]->id, 'deleted' => 1));
 260          $DB->update_record('user', array('id' => $users[5]->id, 'deleted' => 1));
 261          $DB->update_record('user', array('id' => $users[6]->id, 'deleted' => 1));
 262  
 263          // Clean up the tags.
 264          $task->cleanup();
 265          $usertags = $DB->count_records('tag_instance', array('itemtype' => 'user'));
 266          $usercount = $DB->count_records('user', array('deleted' => 0));
 267          // Remove admin and guest from the count.
 268          $this->assertEquals($usertags, ($usercount - 2));
 269  
 270          // Test clean up where a course has been removed.
 271          // Delete the course. This also needs to be this way otherwise the tags are removed by using the proper function.
 272          $DB->delete_records('course', array('id' => $course->id));
 273          $task->cleanup();
 274          $coursetags = $DB->count_records('tag_instance', array('itemtype' => 'course'));
 275          $this->assertEquals(0, $coursetags);
 276  
 277          // Test clean up where a post has been removed.
 278          // Create default post.
 279          $post = new stdClass();
 280          $post->userid = $users[1]->id;
 281          $post->content = 'test post content text';
 282          $post->id = $DB->insert_record('post', $post);
 283          $context = context_system::instance();
 284          core_tag_tag::set_item_tags('core', 'post', $post->id, $context, array($tags[0]->rawname));
 285  
 286          // Add another one with a fake post id to be removed.
 287          core_tag_tag::set_item_tags('core', 'post', 15, $context, array($tags[0]->rawname));
 288          // Check that there are two tag instances.
 289          $posttags = $DB->count_records('tag_instance', array('itemtype' => 'post'));
 290          $this->assertEquals(2, $posttags);
 291          // Clean up the tags.
 292          $task->cleanup();
 293          // We should only have one entry left now.
 294          $posttags = $DB->count_records('tag_instance', array('itemtype' => 'post'));
 295          $this->assertEquals(1, $posttags);
 296      }
 297  
 298      /**
 299       * Test deleting a group of tag instances.
 300       */
 301      public function test_tag_bulk_delete_instances() {
 302          global $DB;
 303          $task = new \core\task\tag_cron_task();
 304  
 305          // Setup.
 306          $user = $this->getDataGenerator()->create_user();
 307          $course = $this->getDataGenerator()->create_course();
 308          $context = context_course::instance($course->id);
 309  
 310          // Create some tag instances.
 311          for ($i = 0; $i < 10; $i++) {
 312              $tag = $this->getDataGenerator()->create_tag(array('userid' => $user->id));
 313              core_tag_tag::add_item_tag('core', 'course', $course->id, $context, $tag->rawname);
 314          }
 315          // Get tag instances. tag name and rawname are required for the event fired in this function.
 316          $sql = "SELECT ti.*, t.name, t.rawname
 317                    FROM {tag_instance} ti
 318                    JOIN {tag} t ON t.id = ti.tagid";
 319          $taginstances = $DB->get_records_sql($sql);
 320          $this->assertCount(10, $taginstances);
 321          // Run the function.
 322          $task->bulk_delete_instances($taginstances);
 323          // Make sure they are gone.
 324          $instancecount = $DB->count_records('tag_instance');
 325          $this->assertEquals(0, $instancecount);
 326      }
 327  
 328      /**
 329       * Prepares environment for testing tag correlations
 330       * @return core_tag_tag[] list of used tags
 331       */
 332      protected function prepare_correlated() {
 333          global $DB;
 334  
 335          $user = $this->getDataGenerator()->create_user();
 336          $this->setUser($user);
 337  
 338          $user1 = $this->getDataGenerator()->create_user();
 339          $user2 = $this->getDataGenerator()->create_user();
 340          $user3 = $this->getDataGenerator()->create_user();
 341          $user4 = $this->getDataGenerator()->create_user();
 342          $user5 = $this->getDataGenerator()->create_user();
 343          $user6 = $this->getDataGenerator()->create_user();
 344  
 345          // Several records have both 'cat' and 'cats' tags attached to them.
 346          // This will make those tags automatically correlated.
 347          // Same with 'dog', 'dogs' and 'puppy.
 348          core_tag_tag::set_item_tags('core', 'user', $user1->id, context_user::instance($user1->id), array('cat', 'cats'));
 349          core_tag_tag::set_item_tags('core', 'user', $user2->id, context_user::instance($user2->id), array('cat', 'cats', 'kitten'));
 350          core_tag_tag::set_item_tags('core', 'user', $user3->id, context_user::instance($user3->id), array('cat', 'cats'));
 351          core_tag_tag::set_item_tags('core', 'user', $user4->id, context_user::instance($user4->id), array('dog', 'dogs', 'puppy'));
 352          core_tag_tag::set_item_tags('core', 'user', $user5->id, context_user::instance($user5->id), array('dog', 'dogs', 'puppy'));
 353          core_tag_tag::set_item_tags('core', 'user', $user6->id, context_user::instance($user6->id), array('dog', 'dogs', 'puppy'));
 354  
 355          $tags = core_tag_tag::get_by_name_bulk(core_tag_collection::get_default(),
 356              array('cat', 'cats', 'dog', 'dogs', 'kitten', 'puppy'), '*');
 357  
 358          // Add manual relation between tags 'cat' and 'kitten'.
 359          core_tag_tag::get($tags['cat']->id)->set_related_tags(array('kitten'));
 360  
 361          return $tags;
 362      }
 363  
 364      /**
 365       * Test for function tag_compute_correlations() that is part of tag cron
 366       */
 367      public function test_correlations() {
 368          global $DB;
 369          $task = new \core\task\tag_cron_task();
 370  
 371          $tags = array_map(function ($t) {
 372              return $t->id;
 373          }, $this->prepare_correlated());
 374  
 375          $task->compute_correlations();
 376  
 377          $this->assertEquals($tags['cats'],
 378              $DB->get_field_select('tag_correlation', 'correlatedtags',
 379                  'tagid = ?', array($tags['cat'])));
 380          $this->assertEquals($tags['cat'],
 381              $DB->get_field_select('tag_correlation', 'correlatedtags',
 382                  'tagid = ?', array($tags['cats'])));
 383          $this->assertEquals($tags['dogs'] . ',' . $tags['puppy'],
 384              $DB->get_field_select('tag_correlation', 'correlatedtags',
 385                  'tagid = ?', array($tags['dog'])));
 386          $this->assertEquals($tags['dog'] . ',' . $tags['puppy'],
 387              $DB->get_field_select('tag_correlation', 'correlatedtags',
 388                  'tagid = ?', array($tags['dogs'])));
 389          $this->assertEquals($tags['dog'] . ',' . $tags['dogs'],
 390              $DB->get_field_select('tag_correlation', 'correlatedtags',
 391                  'tagid = ?', array($tags['puppy'])));
 392  
 393          // Make sure get_correlated_tags() returns 'cats' as the only correlated tag to the 'cat'.
 394          $correlatedtags = array_values(core_tag_tag::get($tags['cat'])->get_correlated_tags(true));
 395          $this->assertCount(3, $correlatedtags); // This will return all existing instances but they all point to the same tag.
 396          $this->assertEquals('cats', $correlatedtags[0]->rawname);
 397          $this->assertEquals('cats', $correlatedtags[1]->rawname);
 398          $this->assertEquals('cats', $correlatedtags[2]->rawname);
 399  
 400          $correlatedtags = array_values(core_tag_tag::get($tags['cat'])->get_correlated_tags());
 401          $this->assertCount(1, $correlatedtags); // Duplicates are filtered out here.
 402          $this->assertEquals('cats', $correlatedtags[0]->rawname);
 403  
 404          // Make sure tag_get_correlated() returns 'dogs' and 'puppy' as the correlated tags to the 'dog'.
 405          $correlatedtags = core_tag_tag::get($tags['dog'])->get_correlated_tags(true);
 406          $this->assertCount(6, $correlatedtags); // 2 tags times 3 instances.
 407  
 408          $correlatedtags = array_values(core_tag_tag::get($tags['dog'])->get_correlated_tags());
 409          $this->assertCount(2, $correlatedtags);
 410          $this->assertEquals('dogs', $correlatedtags[0]->rawname);
 411          $this->assertEquals('puppy', $correlatedtags[1]->rawname);
 412  
 413          // Function get_related_tags() will return both related and correlated tags.
 414          $relatedtags = array_values(core_tag_tag::get($tags['cat'])->get_related_tags());
 415          $this->assertCount(2, $relatedtags);
 416          $this->assertEquals('kitten', $relatedtags[0]->rawname);
 417          $this->assertEquals('cats', $relatedtags[1]->rawname);
 418  
 419          // Also test deprecated method tag_get_related_tags() and tag_get_correlated().
 420          $correlatedtags = array_values(tag_get_correlated($tags['cat']));
 421          $this->assertDebuggingCalled();
 422          $this->assertCount(3, $correlatedtags); // This will return all existing instances but they all point to the same tag.
 423          $this->assertEquals('cats', $correlatedtags[0]->rawname);
 424          $this->assertEquals('cats', $correlatedtags[1]->rawname);
 425          $this->assertEquals('cats', $correlatedtags[2]->rawname);
 426  
 427          $correlatedtags = array_values(tag_get_related_tags($tags['cat'], TAG_RELATED_CORRELATED));
 428          $this->assertDebuggingCalled();
 429          $this->assertCount(1, $correlatedtags); // Duplicates are filtered out here.
 430          $this->assertEquals('cats', $correlatedtags[0]->rawname);
 431  
 432          $correlatedtags = array_values(tag_get_correlated($tags['dog']));
 433          $this->assertDebuggingCalled();
 434          $this->assertCount(6, $correlatedtags); // 2 tags times 3 instances.
 435  
 436          $correlatedtags = array_values(tag_get_related_tags($tags['dog'], TAG_RELATED_CORRELATED));
 437          $this->assertDebuggingCalled();
 438          $this->assertCount(2, $correlatedtags);
 439          $this->assertEquals('dogs', $correlatedtags[0]->rawname);
 440          $this->assertEquals('puppy', $correlatedtags[1]->rawname);
 441  
 442          $relatedtags = array_values(tag_get_related_tags($tags['cat']));
 443          $this->assertDebuggingCalled();
 444          $this->assertCount(2, $relatedtags);
 445          $this->assertEquals('kitten', $relatedtags[0]->rawname);
 446          $this->assertEquals('cats', $relatedtags[1]->rawname);
 447          // End of testing deprecated methods.
 448  
 449          // If we then manually set 'cat' and 'cats' as related, get_related_tags() will filter out duplicates.
 450          core_tag_tag::get($tags['cat'])->set_related_tags(array('kitten', 'cats'));
 451  
 452          $relatedtags = array_values(core_tag_tag::get($tags['cat'])->get_related_tags());
 453          $this->assertCount(2, $relatedtags);
 454          $this->assertEquals('kitten', $relatedtags[0]->rawname);
 455          $this->assertEquals('cats', $relatedtags[1]->rawname);
 456  
 457          // Make sure core_tag_tag::get_item_tags(), core_tag_tag::get_correlated_tags() return the same set of fields.
 458          $relatedtags = core_tag_tag::get_item_tags('core', 'tag', $tags['cat']);
 459          $relatedtag = reset($relatedtags);
 460          $correlatedtags = core_tag_tag::get($tags['cat'])->get_correlated_tags();
 461          $correlatedtag = reset($correlatedtags);
 462          $this->assertEquals(array_keys((array)$relatedtag->to_object()), array_keys((array)$correlatedtag->to_object()));
 463  
 464          // Make sure tag_get_correlated() and tag_get_tags() return the same set of fields.
 465          // Both functions were deprecated in 3.1.
 466          $relatedtags = tag_get_tags('tag', $tags['cat']);
 467          $this->assertDebuggingCalled();
 468          $relatedtag = reset($relatedtags);
 469          $correlatedtags = tag_get_correlated($tags['cat']);
 470          $this->assertDebuggingCalled();
 471          $correlatedtag = reset($correlatedtags);
 472          $this->assertEquals(array_keys((array)$relatedtag), array_keys((array)$correlatedtag));
 473      }
 474  
 475      /**
 476       * Test for function tag_cleanup() that is part of tag cron
 477       */
 478      public function test_cleanup() {
 479          global $DB;
 480          $task = new \core\task\tag_cron_task();
 481  
 482          $user = $this->getDataGenerator()->create_user();
 483          $defaultcoll = core_tag_collection::get_default();
 484  
 485          // Setting tags will create non-standard tags 'cat', 'dog' and 'fish'.
 486          core_tag_tag::set_item_tags('core', 'user', $user->id, context_user::instance($user->id), array('cat', 'dog', 'fish'));
 487  
 488          $this->assertTrue($DB->record_exists('tag', array('name' => 'cat')));
 489          $this->assertTrue($DB->record_exists('tag', array('name' => 'dog')));
 490          $this->assertTrue($DB->record_exists('tag', array('name' => 'fish')));
 491  
 492          // Make tag 'dog' standard.
 493          $dogtag = core_tag_tag::get_by_name($defaultcoll, 'dog', '*');
 494          $fishtag = core_tag_tag::get_by_name($defaultcoll, 'fish');
 495          $dogtag->update(array('isstandard' => 1));
 496  
 497          // Manually remove the instances pointing on tags 'dog' and 'fish'.
 498          $DB->execute('DELETE FROM {tag_instance} WHERE tagid in (?,?)', array($dogtag->id, $fishtag->id));
 499  
 500          // Call tag_cleanup().
 501          $task->cleanup();
 502  
 503          // Tag 'cat' is still present because it's used. Tag 'dog' is present because it's standard.
 504          // Tag 'fish' was removed because it is not standard and it is no longer used by anybody.
 505          $this->assertTrue($DB->record_exists('tag', array('name' => 'cat')));
 506          $this->assertTrue($DB->record_exists('tag', array('name' => 'dog')));
 507          $this->assertFalse($DB->record_exists('tag', array('name' => 'fish')));
 508  
 509          // Delete user without using API function.
 510          $DB->update_record('user', array('id' => $user->id, 'deleted' => 1));
 511  
 512          // Call tag_cleanup().
 513          $task->cleanup();
 514  
 515          // Tag 'cat' was now deleted too.
 516          $this->assertFalse($DB->record_exists('tag', array('name' => 'cat')));
 517  
 518          // Assign tag to non-existing record. Make sure tag was created in the DB.
 519          core_tag_tag::set_item_tags('core', 'course', 1231231, context_system::instance(), array('bird'));
 520          $this->assertTrue($DB->record_exists('tag', array('name' => 'bird')));
 521  
 522          // Call tag_cleanup().
 523          $task->cleanup();
 524  
 525          // Tag 'bird' was now deleted because the related record does not exist in the DB.
 526          $this->assertFalse($DB->record_exists('tag', array('name' => 'bird')));
 527  
 528          // Now we have a tag instance pointing on 'sometag' tag.
 529          $user = $this->getDataGenerator()->create_user();
 530          core_tag_tag::set_item_tags('core', 'user', $user->id, context_user::instance($user->id), array('sometag'));
 531          $sometag = core_tag_tag::get_by_name($defaultcoll, 'sometag');
 532  
 533          $this->assertTrue($DB->record_exists('tag_instance', array('tagid' => $sometag->id)));
 534  
 535          // Some hacker removes the tag without using API.
 536          $DB->delete_records('tag', array('id' => $sometag->id));
 537  
 538          // Call tag_cleanup().
 539          $task->cleanup();
 540  
 541          // The tag instances were also removed.
 542          $this->assertFalse($DB->record_exists('tag_instance', array('tagid' => $sometag->id)));
 543      }
 544  
 545      public function test_guess_tag() {
 546          global $DB;
 547          $user = $this->getDataGenerator()->create_user();
 548          $this->setUser($user);
 549          $tag1 = $this->getDataGenerator()->create_tag(array('name' => 'Cat'));
 550          $tc = core_tag_collection::create((object)array('name' => 'tagcoll'));
 551          $tag2 = $this->getDataGenerator()->create_tag(array('name' => 'Cat', 'tagcollid' => $tc->id));
 552          $this->assertEquals(2, count($DB->get_records('tag')));
 553          $this->assertEquals(2, count(core_tag_tag::guess_by_name('Cat')));
 554          $this->assertEquals(core_tag_collection::get_default(), core_tag_tag::get_by_name(0, 'Cat')->tagcollid);
 555      }
 556  
 557      public function test_instances() {
 558          global $DB;
 559          $user = $this->getDataGenerator()->create_user();
 560          $this->setUser($user);
 561  
 562          // Create a course to tag.
 563          $course = $this->getDataGenerator()->create_course();
 564          $context = context_course::instance($course->id);
 565  
 566          $initialtagscount = $DB->count_records('tag');
 567  
 568          core_tag_tag::set_item_tags('core', 'course', $course->id, $context, array('Tag 1', 'Tag 2'));
 569          $tags = core_tag_tag::get_item_tags('core', 'course', $course->id);
 570          $tagssimple = array_values($tags);
 571          $this->assertEquals(2, count($tags));
 572          $this->assertEquals('Tag 1', $tagssimple[0]->rawname);
 573          $this->assertEquals('Tag 2', $tagssimple[1]->rawname);
 574          $this->assertEquals($initialtagscount + 2, $DB->count_records('tag'));
 575  
 576          core_tag_tag::set_item_tags('core', 'course', $course->id, $context, array('Tag 3', 'Tag 2', 'Tag 1'));
 577          $tags = core_tag_tag::get_item_tags('core', 'course', $course->id);
 578          $tagssimple = array_values($tags);
 579          $this->assertEquals(3, count($tags));
 580          $this->assertEquals('Tag 3', $tagssimple[0]->rawname);
 581          $this->assertEquals('Tag 2', $tagssimple[1]->rawname);
 582          $this->assertEquals('Tag 1', $tagssimple[2]->rawname);
 583          $this->assertEquals($initialtagscount + 3, $DB->count_records('tag'));
 584  
 585          core_tag_tag::set_item_tags('core', 'course', $course->id, $context, array('Tag 3'));
 586          $tags = core_tag_tag::get_item_tags('core', 'course', $course->id);
 587          $tagssimple = array_values($tags);
 588          $this->assertEquals(1, count($tags));
 589          $this->assertEquals('Tag 3', $tagssimple[0]->rawname);
 590  
 591          // Make sure the unused tags were removed from tag table.
 592          $this->assertEquals($initialtagscount + 1, $DB->count_records('tag'));
 593      }
 594  
 595      public function test_related_tags() {
 596          global $DB;
 597          $user = $this->getDataGenerator()->create_user();
 598          $this->setUser($user);
 599          $tagcollid = core_tag_collection::get_default();
 600          $tag = $this->getDataGenerator()->create_tag(array('$tagcollid' => $tagcollid, 'rawname' => 'My tag'));
 601          $tag = core_tag_tag::get($tag->id, '*');
 602  
 603          $tag->set_related_tags(array('Synonym 1', 'Synonym 2'));
 604          $relatedtags = array_values(core_tag_tag::get_item_tags('core', 'tag', $tag->id));
 605          $this->assertEquals(2, count($relatedtags));
 606          $this->assertEquals('Synonym 1', $relatedtags[0]->rawname);
 607          $this->assertEquals('Synonym 2', $relatedtags[1]->rawname);
 608  
 609          $t1 = core_tag_tag::get_by_name($tagcollid, 'Synonym 1', '*');
 610          $relatedtags = array_values(core_tag_tag::get_item_tags('core', 'tag', $t1->id));
 611          $this->assertEquals(1, count($relatedtags));
 612          $this->assertEquals('My tag', $relatedtags[0]->rawname);
 613  
 614          $t2 = core_tag_tag::get_by_name($tagcollid, 'Synonym 2', '*');
 615          $relatedtags = array_values(core_tag_tag::get_item_tags('core', 'tag', $t2->id));
 616          $this->assertEquals(1, count($relatedtags));
 617          $this->assertEquals('My tag', $relatedtags[0]->rawname);
 618  
 619          $tag->set_related_tags(array('Synonym 3', 'Synonym 2', 'Synonym 1'));
 620          $relatedtags = array_values(core_tag_tag::get_item_tags('core', 'tag', $tag->id));
 621          $this->assertEquals(3, count($relatedtags));
 622          $this->assertEquals('Synonym 1', $relatedtags[0]->rawname);
 623          $this->assertEquals('Synonym 2', $relatedtags[1]->rawname);
 624          $this->assertEquals('Synonym 3', $relatedtags[2]->rawname);
 625  
 626          $t3 = core_tag_tag::get_by_name($tagcollid, 'Synonym 3', '*');
 627          $relatedtags = array_values(core_tag_tag::get_item_tags('core', 'tag', $t3->id));
 628          $this->assertEquals(1, count($relatedtags));
 629          $this->assertEquals('My tag', $relatedtags[0]->rawname);
 630  
 631          $tag->set_related_tags(array('Synonym 3', 'Synonym 2'));
 632          $relatedtags = array_values(core_tag_tag::get_item_tags('core', 'tag', $tag->id));
 633          $this->assertEquals(2, count($relatedtags));
 634          $this->assertEquals('Synonym 2', $relatedtags[0]->rawname);
 635          $this->assertEquals('Synonym 3', $relatedtags[1]->rawname);
 636  
 637          // Assert "Synonym 1" no longer links but is still present (will be removed by cron).
 638          $relatedtags = array_values(core_tag_tag::get_item_tags('core', 'tag', $t1->id));
 639          $this->assertEquals(0, count($relatedtags));
 640      }
 641  
 642      /**
 643       * Very basic test for create/move/update/delete actions, without any itemtype movements.
 644       */
 645      public function test_tag_coll_basic() {
 646          global $DB;
 647  
 648          // Make sure there is one and only one tag coll that is marked as default.
 649          $tagcolls = core_tag_collection::get_collections();
 650          $this->assertEquals(1, count($DB->get_records('tag_coll', array('isdefault' => 1))));
 651          $defaulttagcoll = core_tag_collection::get_default();
 652  
 653          // Create a new tag coll to store user tags and something else.
 654          $data = (object)array('name' => 'new tag coll');
 655          $tagcollid1 = core_tag_collection::create($data)->id;
 656          $tagcolls = core_tag_collection::get_collections();
 657          $this->assertEquals('new tag coll', $tagcolls[$tagcollid1]->name);
 658  
 659          // Create a new tag coll to store post tags.
 660          $data = (object)array('name' => 'posts');
 661          $tagcollid2 = core_tag_collection::create($data)->id;
 662          $tagcolls = core_tag_collection::get_collections();
 663          $this->assertEquals('posts', $tagcolls[$tagcollid2]->name);
 664          $this->assertEquals($tagcolls[$tagcollid1]->sortorder + 1,
 665              $tagcolls[$tagcollid2]->sortorder);
 666  
 667          // Illegal tag colls sortorder changing.
 668          $this->assertFalse(core_tag_collection::change_sortorder($tagcolls[$defaulttagcoll], 1));
 669          $this->assertFalse(core_tag_collection::change_sortorder($tagcolls[$defaulttagcoll], -1));
 670          $this->assertFalse(core_tag_collection::change_sortorder($tagcolls[$tagcollid2], 1));
 671  
 672          // Move the very last tag coll one position up.
 673          $this->assertTrue(core_tag_collection::change_sortorder($tagcolls[$tagcollid2], -1));
 674          $tagcolls = core_tag_collection::get_collections();
 675          $this->assertEquals($tagcolls[$tagcollid2]->sortorder + 1,
 676              $tagcolls[$tagcollid1]->sortorder);
 677  
 678          // Move the second last tag coll one position down.
 679          $this->assertTrue(core_tag_collection::change_sortorder($tagcolls[$tagcollid2], 1));
 680          $tagcolls = core_tag_collection::get_collections();
 681          $this->assertEquals($tagcolls[$tagcollid1]->sortorder + 1,
 682              $tagcolls[$tagcollid2]->sortorder);
 683  
 684          // Edit tag coll.
 685          $this->assertTrue(core_tag_collection::update($tagcolls[$tagcollid2],
 686              (object)array('name' => 'posts2')));
 687          $tagcolls = core_tag_collection::get_collections();
 688          $this->assertEquals('posts2', $tagcolls[$tagcollid2]->name);
 689  
 690          // Delete tag coll.
 691          $count = $DB->count_records('tag_coll');
 692          $this->assertFalse(core_tag_collection::delete($tagcolls[$defaulttagcoll]));
 693          $this->assertTrue(core_tag_collection::delete($tagcolls[$tagcollid1]));
 694          $this->assertEquals($count - 1, $DB->count_records('tag_coll'));
 695      }
 696  
 697      /**
 698       * Prepares environment for test_move_tags_* tests
 699       */
 700      protected function prepare_move_tags() {
 701          global $CFG;
 702          require_once($CFG->dirroot.'/blog/locallib.php');
 703          $this->setUser($this->getDataGenerator()->create_user());
 704  
 705          $collid1 = core_tag_collection::get_default();
 706          $collid2 = core_tag_collection::create(array('name' => 'newcoll'))->id;
 707          $user1 = $this->getDataGenerator()->create_user();
 708          $user2 = $this->getDataGenerator()->create_user();
 709          $blogpost = new blog_entry(null, array('subject' => 'test'), null);
 710          $states = blog_entry::get_applicable_publish_states();
 711          $blogpost->publishstate = reset($states);
 712          $blogpost->add();
 713  
 714          core_tag_tag::set_item_tags('core', 'user', $user1->id, context_user::instance($user1->id),
 715                  array('Tag1', 'Tag2'));
 716          core_tag_tag::set_item_tags('core', 'user', $user2->id, context_user::instance($user2->id),
 717                  array('Tag2', 'Tag3'));
 718          $this->getDataGenerator()->create_tag(array('rawname' => 'Tag4',
 719              'tagcollid' => $collid1, 'isstandard' => 1));
 720          $this->getDataGenerator()->create_tag(array('rawname' => 'Tag5',
 721              'tagcollid' => $collid2, 'isstandard' => 1));
 722  
 723          return array($collid1, $collid2, $user1, $user2, $blogpost);
 724      }
 725  
 726      public function test_move_tags_simple() {
 727          global $DB;
 728          list($collid1, $collid2, $user1, $user2, $blogpost) = $this->prepare_move_tags();
 729  
 730          // Move 'user' area from collection 1 to collection 2, make sure tags were moved completely.
 731          $tagarea = $DB->get_record('tag_area', array('itemtype' => 'user', 'component' => 'core'));
 732          core_tag_area::update($tagarea, array('tagcollid' => $collid2));
 733  
 734          $tagsaftermove = $DB->get_records('tag');
 735          foreach ($tagsaftermove as $tag) {
 736              // Confirm that the time modified has not been unset.
 737              $this->assertNotEmpty($tag->timemodified);
 738          }
 739  
 740          $this->assertEquals(array('Tag4'),
 741                  $DB->get_fieldset_select('tag', 'rawname', 'tagcollid = ? ORDER BY name', array($collid1)));
 742          $this->assertEquals(array('Tag1', 'Tag2', 'Tag3', 'Tag5'),
 743                  $DB->get_fieldset_select('tag', 'rawname', 'tagcollid = ? ORDER BY name', array($collid2)));
 744          $this->assertEquals(array('Tag1', 'Tag2'), array_values(core_tag_tag::get_item_tags_array('core', 'user', $user1->id)));
 745          $this->assertEquals(array('Tag2', 'Tag3'), array_values(core_tag_tag::get_item_tags_array('core', 'user', $user2->id)));
 746      }
 747  
 748      public function test_move_tags_split_tag() {
 749          global $DB;
 750          list($collid1, $collid2, $user1, $user2, $blogpost) = $this->prepare_move_tags();
 751  
 752          core_tag_tag::set_item_tags('core', 'post', $blogpost->id, context_system::instance(),
 753                  array('Tag1', 'Tag3'));
 754  
 755          // Move 'user' area from collection 1 to collection 2, make sure tag Tag2 was moved and tags Tag1 and Tag3 were duplicated.
 756          $tagareauser = $DB->get_record('tag_area', array('itemtype' => 'user', 'component' => 'core'));
 757          core_tag_area::update($tagareauser, array('tagcollid' => $collid2));
 758  
 759          $tagsaftermove = $DB->get_records('tag');
 760          foreach ($tagsaftermove as $tag) {
 761              // Confirm that the time modified has not been unset.
 762              $this->assertNotEmpty($tag->timemodified);
 763          }
 764  
 765          $this->assertEquals(array('Tag1', 'Tag3', 'Tag4'),
 766                  $DB->get_fieldset_select('tag', 'rawname', 'tagcollid = ? ORDER BY name', array($collid1)));
 767          $this->assertEquals(array('Tag1', 'Tag2', 'Tag3', 'Tag5'),
 768                  $DB->get_fieldset_select('tag', 'rawname', 'tagcollid = ? ORDER BY name', array($collid2)));
 769          $this->assertEquals(array('Tag1', 'Tag2'), array_values(core_tag_tag::get_item_tags_array('core', 'user', $user1->id)));
 770          $this->assertEquals(array('Tag2', 'Tag3'), array_values(core_tag_tag::get_item_tags_array('core', 'user', $user2->id)));
 771          $this->assertEquals(array('Tag1', 'Tag3'), array_values(core_tag_tag::get_item_tags_array('core', 'post', $blogpost->id)));
 772      }
 773  
 774      public function test_move_tags_merge_tag() {
 775          global $DB;
 776          list($collid1, $collid2, $user1, $user2, $blogpost) = $this->prepare_move_tags();
 777  
 778          // Set collection for 'post' tag area to be collection 2 and add some tags there.
 779          $tagareablog = $DB->get_record('tag_area', array('itemtype' => 'post', 'component' => 'core'));
 780          core_tag_area::update($tagareablog, array('tagcollid' => $collid2));
 781  
 782          core_tag_tag::set_item_tags('core', 'post', $blogpost->id, context_system::instance(),
 783                  array('TAG1', 'Tag3'));
 784  
 785          // Move 'user' area from collection 1 to collection 2,
 786          // make sure tag Tag2 was moved and tags Tag1 and Tag3 were merged into existing.
 787          $tagareauser = $DB->get_record('tag_area', array('itemtype' => 'user', 'component' => 'core'));
 788          core_tag_area::update($tagareauser, array('tagcollid' => $collid2));
 789  
 790          $tagsaftermove = $DB->get_records('tag');
 791          foreach ($tagsaftermove as $tag) {
 792              // Confirm that the time modified has not been unset.
 793              $this->assertNotEmpty($tag->timemodified);
 794          }
 795  
 796          $this->assertEquals(array('Tag4'),
 797                  $DB->get_fieldset_select('tag', 'rawname', 'tagcollid = ? ORDER BY name', array($collid1)));
 798          $this->assertEquals(array('TAG1', 'Tag2', 'Tag3', 'Tag5'),
 799                  $DB->get_fieldset_select('tag', 'rawname', 'tagcollid = ? ORDER BY name', array($collid2)));
 800          $this->assertEquals(array('TAG1', 'Tag2'), array_values(core_tag_tag::get_item_tags_array('core', 'user', $user1->id)));
 801          $this->assertEquals(array('Tag2', 'Tag3'), array_values(core_tag_tag::get_item_tags_array('core', 'user', $user2->id)));
 802          $this->assertEquals(array('TAG1', 'Tag3'), array_values(core_tag_tag::get_item_tags_array('core', 'post', $blogpost->id)));
 803      }
 804  
 805      public function test_move_tags_with_related() {
 806          global $DB;
 807          list($collid1, $collid2, $user1, $user2, $blogpost) = $this->prepare_move_tags();
 808  
 809          // Set Tag1 to be related to Tag2 and Tag4 (in collection 1).
 810          core_tag_tag::get_by_name($collid1, 'Tag1')->set_related_tags(array('Tag2', 'Tag4'));
 811  
 812          // Set collection for 'post' tag area to be collection 2 and add some tags there.
 813          $tagareablog = $DB->get_record('tag_area', array('itemtype' => 'post', 'component' => 'core'));
 814          core_tag_area::update($tagareablog, array('tagcollid' => $collid2));
 815  
 816          core_tag_tag::set_item_tags('core', 'post', $blogpost->id, context_system::instance(),
 817                  array('TAG1', 'Tag3'));
 818  
 819          // Move 'user' area from collection 1 to collection 2, make sure tags were moved completely.
 820          $tagarea = $DB->get_record('tag_area', array('itemtype' => 'user', 'component' => 'core'));
 821          core_tag_area::update($tagarea, array('tagcollid' => $collid2));
 822  
 823          $tagsaftermove = $DB->get_records('tag');
 824          foreach ($tagsaftermove as $tag) {
 825              // Confirm that the time modified has not been unset.
 826              $this->assertNotEmpty($tag->timemodified);
 827          }
 828  
 829          $this->assertEquals(array('Tag1', 'Tag2', 'Tag4'),
 830                  $DB->get_fieldset_select('tag', 'rawname', 'tagcollid = ? ORDER BY name', array($collid1)));
 831          $this->assertEquals(array('TAG1', 'Tag2', 'Tag3', 'Tag4', 'Tag5'),
 832                  $DB->get_fieldset_select('tag', 'rawname', 'tagcollid = ? ORDER BY name', array($collid2)));
 833          $this->assertEquals(array('TAG1', 'Tag2'), array_values(core_tag_tag::get_item_tags_array('core', 'user', $user1->id)));
 834          $this->assertEquals(array('Tag2', 'Tag3'), array_values(core_tag_tag::get_item_tags_array('core', 'user', $user2->id)));
 835  
 836          $tag11 = core_tag_tag::get_by_name($collid1, 'Tag1');
 837          $related11 = tag_get_related_tags($tag11->id, TAG_RELATED_MANUAL);
 838          $this->assertDebuggingCalled();
 839          $related11 = array_map('core_tag_tag::make_display_name', $related11);
 840          sort($related11); // Order of related tags may be random.
 841          $this->assertEquals('Tag2, Tag4', join(', ', $related11));
 842  
 843          $tag21 = core_tag_tag::get_by_name($collid2, 'TAG1');
 844          $related21 = tag_get_related_tags($tag21->id, TAG_RELATED_MANUAL);
 845          $this->assertDebuggingCalled();
 846          $related21 = array_map('core_tag_tag::make_display_name', $related21);
 847          sort($related21); // Order of related tags may be random.
 848          $this->assertEquals('Tag2, Tag4', join(', ', $related21));
 849      }
 850  
 851      public function test_move_tags_corrupted() {
 852          global $DB;
 853          list($collid1, $collid2, $user1, $user2, $blogpost) = $this->prepare_move_tags();
 854          $collid3 = core_tag_collection::create(array('name' => 'weirdcoll'))->id;
 855  
 856          // We already have Tag1 in coll1, now let's create it in coll3.
 857          $extratag1 = $this->getDataGenerator()->create_tag(array('rawname' => 'Tag1',
 858              'tagcollid' => $collid3, 'isstandard' => 1));
 859  
 860          // Artificially add 'Tag1' from coll3 to user2.
 861          $DB->insert_record('tag_instance', array('tagid' => $extratag1->id, 'itemtype' => 'user',
 862              'component' => 'core', 'itemid' => $user2->id, 'ordering' => 3));
 863  
 864          // Now we have corrupted data: both users are tagged with 'Tag1', however these are two tags in different collections.
 865          $user1tags = array_values(core_tag_tag::get_item_tags('core', 'user', $user1->id));
 866          $user2tags = array_values(core_tag_tag::get_item_tags('core', 'user', $user2->id));
 867          $this->assertEquals('Tag1', $user1tags[0]->rawname);
 868          $this->assertEquals('Tag1', $user2tags[2]->rawname);
 869          $this->assertNotEquals($user1tags[0]->tagcollid, $user2tags[2]->tagcollid);
 870  
 871          // Move user interests tag area into coll2.
 872          $tagarea = $DB->get_record('tag_area', array('itemtype' => 'user', 'component' => 'core'));
 873          core_tag_area::update($tagarea, array('tagcollid' => $collid2));
 874  
 875          $tagsaftermove = $DB->get_records('tag');
 876          foreach ($tagsaftermove as $tag) {
 877              // Confirm that the time modified has not been unset.
 878              $this->assertNotEmpty($tag->timemodified);
 879          }
 880  
 881          // Now all tags are correctly moved to the new collection and both tags 'Tag1' were merged.
 882          $user1tags = array_values(core_tag_tag::get_item_tags('core', 'user', $user1->id));
 883          $user2tags = array_values(core_tag_tag::get_item_tags('core', 'user', $user2->id));
 884          $this->assertEquals('Tag1', $user1tags[0]->rawname);
 885          $this->assertEquals('Tag1', $user2tags[2]->rawname);
 886          $this->assertEquals($collid2, $user1tags[0]->tagcollid);
 887          $this->assertEquals($collid2, $user2tags[2]->tagcollid);
 888      }
 889  
 890      public function test_normalize() {
 891          $tagset = array('Cat', ' Dog  ', '<Mouse', '<>', 'mouse', 'Dog');
 892  
 893          // Test function tag_normalize() that was deprecated in 3.1.
 894          $this->assertEquals(array('Cat' => 'Cat', 'Dog' => 'Dog', '<Mouse' => 'Mouse', '<>' => '', 'mouse' => 'mouse'),
 895              tag_normalize($tagset, TAG_CASE_ORIGINAL));
 896          $this->assertDebuggingCalled();
 897          $this->assertEquals(array('Cat' => 'cat', 'Dog' => 'dog', '<Mouse' => 'mouse', '<>' => '', 'mouse' => 'mouse'),
 898              tag_normalize($tagset, TAG_CASE_LOWER));
 899          $this->assertDebuggingCalled();
 900  
 901          // Test replacement function core_tag_tag::normalize().
 902          $this->assertEquals(array('Cat' => 'Cat', 'Dog' => 'Dog', '<Mouse' => 'Mouse', '<>' => '', 'mouse' => 'mouse'),
 903              core_tag_tag::normalize($tagset, false));
 904          $this->assertEquals(array('Cat' => 'cat', 'Dog' => 'dog', '<Mouse' => 'mouse', '<>' => '', 'mouse' => 'mouse'),
 905              core_tag_tag::normalize($tagset, true));
 906      }
 907  
 908      /**
 909       * Test functions core_tag_tag::create_if_missing() and core_tag_tag::get_by_name_bulk().
 910       */
 911      public function test_create_get() {
 912          $tagset = array('Cat', ' Dog  ', '<Mouse', '<>', 'mouse', 'Dog');
 913  
 914          $collid = core_tag_collection::get_default();
 915          $tags = core_tag_tag::create_if_missing($collid, $tagset);
 916          $this->assertEquals(array('cat', 'dog', 'mouse'), array_keys($tags));
 917          $this->assertEquals('Dog', $tags['dog']->rawname);
 918          $this->assertEquals('mouse', $tags['mouse']->rawname); // Case of the last tag wins.
 919  
 920          $tags2 = core_tag_tag::create_if_missing($collid, array('CAT', 'Elephant'));
 921          $this->assertEquals(array('cat', 'elephant'), array_keys($tags2));
 922          $this->assertEquals('Cat', $tags2['cat']->rawname);
 923          $this->assertEquals('Elephant', $tags2['elephant']->rawname);
 924          $this->assertEquals($tags['cat']->id, $tags2['cat']->id); // Tag 'cat' already existed and was not created again.
 925  
 926          $tags3 = core_tag_tag::get_by_name_bulk($collid, $tagset);
 927          $this->assertEquals(array('cat', 'dog', 'mouse'), array_keys($tags3));
 928          $this->assertEquals('Dog', $tags3['dog']->rawname);
 929          $this->assertEquals('mouse', $tags3['mouse']->rawname);
 930  
 931      }
 932  
 933      /**
 934       * Testing function core_tag_tag::combine_tags()
 935       */
 936      public function test_combine_tags() {
 937          $initialtags = array(
 938              array('Cat', 'Dog'),
 939              array('Dog', 'Cat'),
 940              array('Cats', 'Hippo'),
 941              array('Hippo', 'Cats'),
 942              array('Cat', 'Mouse', 'Kitten'),
 943              array('Cats', 'Mouse', 'Kitten'),
 944              array('Kitten', 'Mouse', 'Cat'),
 945              array('Kitten', 'Mouse', 'Cats'),
 946              array('Cats', 'Mouse', 'Kitten'),
 947              array('Mouse', 'Hippo')
 948          );
 949  
 950          $finaltags = array(
 951              array('Cat', 'Dog'),
 952              array('Dog', 'Cat'),
 953              array('Cat', 'Hippo'),
 954              array('Hippo', 'Cat'),
 955              array('Cat', 'Mouse'),
 956              array('Cat', 'Mouse'),
 957              array('Mouse', 'Cat'),
 958              array('Mouse', 'Cat'),
 959              array('Cat', 'Mouse'),
 960              array('Mouse', 'Hippo')
 961          );
 962  
 963          $collid = core_tag_collection::get_default();
 964          $context = context_system::instance();
 965          foreach ($initialtags as $id => $taglist) {
 966              core_tag_tag::set_item_tags('core', 'course', $id + 10, $context, $initialtags[$id]);
 967          }
 968  
 969          core_tag_tag::get_by_name($collid, 'Cats', '*')->update(array('isstandard' => 1));
 970  
 971          // Combine tags 'Cats' and 'Kitten' into 'Cat'.
 972          $cat = core_tag_tag::get_by_name($collid, 'Cat', '*');
 973          $cats = core_tag_tag::get_by_name($collid, 'Cats', '*');
 974          $kitten = core_tag_tag::get_by_name($collid, 'Kitten', '*');
 975          $cat->combine_tags(array($cats, $kitten));
 976  
 977          foreach ($finaltags as $id => $taglist) {
 978              $this->assertEquals($taglist,
 979                  array_values(core_tag_tag::get_item_tags_array('core', 'course', $id + 10)),
 980                      'Original array ('.join(', ', $initialtags[$id]).')');
 981          }
 982  
 983          // Ensure combined tags are deleted and 'Cat' is now official (because 'Cats' was official).
 984          $this->assertEmpty(core_tag_tag::get_by_name($collid, 'Cats'));
 985          $this->assertEmpty(core_tag_tag::get_by_name($collid, 'Kitten'));
 986          $cattag = core_tag_tag::get_by_name($collid, 'Cat', '*');
 987          $this->assertEquals(1, $cattag->isstandard);
 988      }
 989  
 990      /**
 991       * Testing function core_tag_tag::combine_tags() when related tags are present.
 992       */
 993      public function test_combine_tags_with_related() {
 994          $collid = core_tag_collection::get_default();
 995          $context = context_system::instance();
 996          core_tag_tag::set_item_tags('core', 'course', 10, $context, array('Cat', 'Cats', 'Dog'));
 997          core_tag_tag::get_by_name($collid, 'Cat', '*')->set_related_tags(array('Kitty'));
 998          core_tag_tag::get_by_name($collid, 'Cats', '*')->set_related_tags(array('Cat', 'Kitten', 'Kitty'));
 999  
1000          // Combine tags 'Cats' into 'Cat'.
1001          $cat = core_tag_tag::get_by_name($collid, 'Cat', '*');
1002          $cats = core_tag_tag::get_by_name($collid, 'Cats', '*');
1003          $cat->combine_tags(array($cats));
1004  
1005          // Ensure 'Cat' is now related to 'Kitten' and 'Kitty' (order of related tags may be random).
1006          $relatedtags = array_map(function($t) {return $t->rawname;}, $cat->get_manual_related_tags());
1007          sort($relatedtags);
1008          $this->assertEquals(array('Kitten', 'Kitty'), array_values($relatedtags));
1009      }
1010  
1011      /**
1012       * Testing function core_tag_tag::combine_tags() when correlated tags are present.
1013       */
1014      public function test_combine_tags_with_correlated() {
1015          $task = new \core\task\tag_cron_task();
1016  
1017          $tags = $this->prepare_correlated();
1018  
1019          $task->compute_correlations();
1020          // Now 'cat' is correlated with 'cats'.
1021          // Also 'dog', 'dogs' and 'puppy' are correlated.
1022          // There is a manual relation between 'cat' and 'kitten'.
1023          // See function test_correlations() for assertions.
1024  
1025          // Combine tags 'dog' and 'kitten' into 'cat' and make sure that cat is now correlated with dogs and puppy.
1026          $tags['cat']->combine_tags(array($tags['dog'], $tags['kitten']));
1027  
1028          $correlatedtags = $this->get_correlated_tags_names($tags['cat']);
1029          $this->assertEquals(['cats', 'dogs', 'puppy'], $correlatedtags);
1030  
1031          $correlatedtags = $this->get_correlated_tags_names($tags['dogs']);
1032          $this->assertEquals(['cat', 'puppy'], $correlatedtags);
1033  
1034          $correlatedtags = $this->get_correlated_tags_names($tags['puppy']);
1035          $this->assertEquals(['cat', 'dogs'], $correlatedtags);
1036  
1037          // Add tag that does not have any correlations.
1038          $user7 = $this->getDataGenerator()->create_user();
1039          core_tag_tag::set_item_tags('core', 'user', $user7->id, context_user::instance($user7->id), array('hippo'));
1040          $tags['hippo'] = core_tag_tag::get_by_name(core_tag_collection::get_default(), 'hippo', '*');
1041  
1042          // Combine tag 'cat' into 'hippo'. Now 'hippo' should have the same correlations 'cat' used to have and also
1043          // tags 'dogs' and 'puppy' should have 'hippo' in correlations.
1044          $tags['hippo']->combine_tags(array($tags['cat']));
1045  
1046          $correlatedtags = $this->get_correlated_tags_names($tags['hippo']);
1047          $this->assertEquals(['cats', 'dogs', 'puppy'], $correlatedtags);
1048  
1049          $correlatedtags = $this->get_correlated_tags_names($tags['dogs']);
1050          $this->assertEquals(['hippo', 'puppy'], $correlatedtags);
1051  
1052          $correlatedtags = $this->get_correlated_tags_names($tags['puppy']);
1053          $this->assertEquals(['dogs', 'hippo'], $correlatedtags);
1054      }
1055  
1056      /**
1057       * Help method to return sorted array of names of correlated tags to use for assertions
1058       * @param core_tag $tag
1059       * @return string
1060       */
1061      protected function get_correlated_tags_names($tag) {
1062          $rv = array_map(function($t) {
1063              return $t->rawname;
1064          }, $tag->get_correlated_tags());
1065          sort($rv);
1066          return array_values($rv);
1067      }
1068  }


Generated: Thu Aug 11 10:00:09 2016 Cross-referenced by PHPXref 0.7.1