See Release Notes
Long Term Support Release
<?php // This file is part of Moodle - http://moodle.org/ // // Moodle is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. // // Moodle is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // You should have received a copy of the GNU General Public License // along with Moodle. If not, see <http://www.gnu.org/licenses/>. /** * Unit tests for WS in tags * * @package core_tag * @category test * @copyright 2015 Marina Glancy * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later */ namespace core_tag\external; use externallib_advanced_testcase;> use core_external\external_api;defined('MOODLE_INTERNAL') || die(); global $CFG;< require_once($CFG->libdir . '/externallib.php');require_once($CFG->dirroot . '/webservice/tests/helpers.php'); class external_test extends externallib_advanced_testcase { /** * Test update_categories */ public function test_update_tags() { global $DB; $this->resetAfterTest(); $context = \context_system::instance(); $originaltag = array( 'isstandard' => 0, 'flag' => 1, 'rawname' => 'test', 'description' => 'desc' ); $tag = $this->getDataGenerator()->create_tag($originaltag); $updatetag = array( 'id' => $tag->id, 'description' => 'Trying to change tag description', 'rawname' => 'Trying to change tag name', 'flag' => 0, 'isstandard' => 1, ); $gettag = array( 'id' => $tag->id, ); // User without any caps can not change anything about a tag but can request [partial] tag data. $this->setUser($this->getDataGenerator()->create_user()); $result = \core_tag_external::update_tags(array($updatetag));< $result = \external_api::clean_returnvalue(\core_tag_external::update_tags_returns(), $result);> $result = external_api::clean_returnvalue(\core_tag_external::update_tags_returns(), $result);$this->assertEquals($tag->id, $result['warnings'][0]['item']); $this->assertEquals('nothingtoupdate', $result['warnings'][0]['warningcode']); $this->assertEquals($originaltag['rawname'], $DB->get_field('tag', 'rawname', array('id' => $tag->id))); $this->assertEquals($originaltag['description'], $DB->get_field('tag', 'description', array('id' => $tag->id))); $result = \core_tag_external::get_tags(array($gettag));< $result = \external_api::clean_returnvalue(\core_tag_external::get_tags_returns(), $result);> $result = external_api::clean_returnvalue(\core_tag_external::get_tags_returns(), $result);$this->assertEquals($originaltag['rawname'], $result['tags'][0]['rawname']); $this->assertEquals($originaltag['description'], $result['tags'][0]['description']); $this->assertNotEmpty($result['tags'][0]['viewurl']); $this->assertArrayNotHasKey('changetypeurl', $result['tags'][0]); $this->assertArrayNotHasKey('changeflagurl', $result['tags'][0]); $this->assertArrayNotHasKey('flag', $result['tags'][0]); $this->assertArrayNotHasKey('official', $result['tags'][0]); $this->assertArrayNotHasKey('isstandard', $result['tags'][0]); // User with editing only capability can change description but not the tag name. $roleid = $this->assignUserCapability('moodle/tag:edit', $context->id); $result = \core_tag_external::update_tags(array($updatetag));< $result = \external_api::clean_returnvalue(\core_tag_external::update_tags_returns(), $result);> $result = external_api::clean_returnvalue(\core_tag_external::update_tags_returns(), $result);$this->assertEmpty($result['warnings']); $result = \core_tag_external::get_tags(array($gettag));< $result = \external_api::clean_returnvalue(\core_tag_external::get_tags_returns(), $result);> $result = external_api::clean_returnvalue(\core_tag_external::get_tags_returns(), $result);$this->assertEquals($updatetag['id'], $result['tags'][0]['id']); $this->assertEquals($updatetag['description'], $result['tags'][0]['description']); $this->assertEquals($originaltag['rawname'], $result['tags'][0]['rawname']); $this->assertArrayNotHasKey('flag', $result['tags'][0]); // 'Flag' is not available unless 'moodle/tag:manage' cap exists. $this->assertEquals(0, $result['tags'][0]['official']); $this->assertEquals(0, $result['tags'][0]['isstandard']); $this->assertEquals($originaltag['rawname'], $DB->get_field('tag', 'rawname', array('id' => $tag->id))); $this->assertEquals($updatetag['description'], $DB->get_field('tag', 'description', array('id' => $tag->id))); // User with editing and manage cap can also change the tag name, // make it standard and reset flag. assign_capability('moodle/tag:manage', CAP_ALLOW, $roleid, $context->id); $this->assertTrue(has_capability('moodle/tag:manage', $context)); $result = \core_tag_external::update_tags(array($updatetag));< $result = \external_api::clean_returnvalue(\core_tag_external::update_tags_returns(), $result);> $result = external_api::clean_returnvalue(\core_tag_external::update_tags_returns(), $result);$this->assertEmpty($result['warnings']); $result = \core_tag_external::get_tags(array($gettag));< $result = \external_api::clean_returnvalue(\core_tag_external::get_tags_returns(), $result);> $result = external_api::clean_returnvalue(\core_tag_external::get_tags_returns(), $result);$this->assertEquals($updatetag['id'], $result['tags'][0]['id']); $this->assertEquals($updatetag['rawname'], $result['tags'][0]['rawname']); $this->assertEquals(\core_text::strtolower($updatetag['rawname']), $result['tags'][0]['name']); $this->assertEquals($updatetag['flag'], $result['tags'][0]['flag']); $this->assertEquals($updatetag['isstandard'], $result['tags'][0]['official']); $this->assertEquals($updatetag['isstandard'], $result['tags'][0]['isstandard']); $this->assertEquals($updatetag['rawname'], $DB->get_field('tag', 'rawname', array('id' => $tag->id))); $this->assertEquals(1, $DB->get_field('tag', 'isstandard', array('id' => $tag->id))); // Updating and getting non-existing tag. $nonexistingtag = array( 'id' => 123, 'description' => 'test' ); $getnonexistingtag = array( 'id' => 123, ); $result = \core_tag_external::update_tags(array($nonexistingtag));< $result = \external_api::clean_returnvalue(\core_tag_external::update_tags_returns(), $result);> $result = external_api::clean_returnvalue(\core_tag_external::update_tags_returns(), $result);$this->assertEquals(123, $result['warnings'][0]['item']); $this->assertEquals('tagnotfound', $result['warnings'][0]['warningcode']); $result = \core_tag_external::get_tags(array($getnonexistingtag));< $result = \external_api::clean_returnvalue(\core_tag_external::get_tags_returns(), $result);> $result = external_api::clean_returnvalue(\core_tag_external::get_tags_returns(), $result);$this->assertEmpty($result['tags']); $this->assertEquals(123, $result['warnings'][0]['item']); $this->assertEquals('tagnotfound', $result['warnings'][0]['warningcode']); // Attempt to update a tag to the name that is reserved. $anothertag = $this->getDataGenerator()->create_tag(array('rawname' => 'Mytag')); $updatetag2 = array('id' => $tag->id, 'rawname' => 'MYTAG'); $result = \core_tag_external::update_tags(array($updatetag2));< $result = \external_api::clean_returnvalue(\core_tag_external::update_tags_returns(), $result);> $result = external_api::clean_returnvalue(\core_tag_external::update_tags_returns(), $result);$this->assertEquals($tag->id, $result['warnings'][0]['item']); $this->assertEquals('namesalreadybeeingused', $result['warnings'][0]['warningcode']); } /** * Test update_inplace_editable() */ public function test_update_inplace_editable() { global $CFG, $DB, $PAGE; require_once($CFG->dirroot . '/lib/external/externallib.php'); $this->resetAfterTest(true); $tag = $this->getDataGenerator()->create_tag(); $this->setUser($this->getDataGenerator()->create_user()); // Call service for core_tag component without necessary permissions. try { \core_external::update_inplace_editable('core_tag', 'tagname', $tag->id, 'new tag name'); $this->fail('Exception expected'); } catch (\moodle_exception $e) { $this->assertEquals('Sorry, but you do not currently have permissions to do that (Manage all tags).', $e->getMessage()); } // Change to admin user and make sure that tag name can be updated using web service update_inplace_editable(). $this->setAdminUser(); $res = \core_external::update_inplace_editable('core_tag', 'tagname', $tag->id, 'New tag name');< $res = \external_api::clean_returnvalue(\core_external::update_inplace_editable_returns(), $res);> $res = external_api::clean_returnvalue(\core_external::update_inplace_editable_returns(), $res);$this->assertEquals('New tag name', $res['value']); $this->assertEquals('New tag name', $DB->get_field('tag', 'rawname', array('id' => $tag->id))); // Call callback core_tag_inplace_editable() directly. $tmpl = component_callback('core_tag', 'inplace_editable', array('tagname', $tag->id, 'Rename me again')); $this->assertInstanceOf('core\output\inplace_editable', $tmpl); $res = $tmpl->export_for_template($PAGE->get_renderer('core')); $this->assertEquals('Rename me again', $res['value']); $this->assertEquals('Rename me again', $DB->get_field('tag', 'rawname', array('id' => $tag->id))); } /** * Test get_tagindex_per_area. */ public function test_get_tagindex_per_area() { global $USER; $this->resetAfterTest(true); // Create tags for two user profiles and one course. $this->setAdminUser(); $context = \context_user::instance($USER->id); \core_tag_tag::set_item_tags('core', 'user', $USER->id, $context, array('test')); $this->setUser($this->getDataGenerator()->create_user()); $context = \context_user::instance($USER->id); \core_tag_tag::set_item_tags('core', 'user', $USER->id, $context, array('test')); $course = $this->getDataGenerator()->create_course(); $context = \context_course::instance($course->id); \core_tag_tag::set_item_tags('core', 'course', $course->id, $context, array('test')); $tag = \core_tag_tag::get_by_name(0, 'test'); // First, search by id. $result = \core_tag_external::get_tagindex_per_area(array('id' => $tag->id));< $result = \external_api::clean_returnvalue(\core_tag_external::get_tagindex_per_area_returns(), $result);> $result = external_api::clean_returnvalue(\core_tag_external::get_tagindex_per_area_returns(), $result);$this->assertCount(2, $result); // Two different areas: course and user. $this->assertEquals($tag->id, $result[0]['tagid']); $this->assertEquals('course', $result[0]['itemtype']); $this->assertEquals($tag->id, $result[1]['tagid']); $this->assertEquals('user', $result[1]['itemtype']); // Now, search by name. $result = \core_tag_external::get_tagindex_per_area(array('tag' => 'test'));< $result = \external_api::clean_returnvalue(\core_tag_external::get_tagindex_per_area_returns(), $result);> $result = external_api::clean_returnvalue(\core_tag_external::get_tagindex_per_area_returns(), $result);$this->assertCount(2, $result); // Two different areas: course and user. $this->assertEquals($tag->id, $result[0]['tagid']); $this->assertEquals('course', $result[0]['itemtype']); $this->assertEquals($tag->id, $result[1]['tagid']); $this->assertEquals('user', $result[1]['itemtype']); // Filter by tag area. $result = \core_tag_external::get_tagindex_per_area(array('tag' => 'test', 'ta' => $result[0]['ta']));< $result = \external_api::clean_returnvalue(\core_tag_external::get_tagindex_per_area_returns(), $result);> $result = external_api::clean_returnvalue(\core_tag_external::get_tagindex_per_area_returns(), $result);$this->assertCount(1, $result); // Just the given area. $this->assertEquals($tag->id, $result[0]['tagid']); $this->assertEquals('course', $result[0]['itemtype']); // Now, search by tag collection (use default). $result = \core_tag_external::get_tagindex_per_area(array('id' => $tag->id, 'tc' => 1));< $result = \external_api::clean_returnvalue(\core_tag_external::get_tagindex_per_area_returns(), $result);> $result = external_api::clean_returnvalue(\core_tag_external::get_tagindex_per_area_returns(), $result);$this->assertCount(2, $result); // Two different areas: course and user. } /** * Test get_tag_areas. */ public function test_get_tag_areas() { global $DB; $this->resetAfterTest(true); $this->setAdminUser(); $result = \core_tag_external::get_tag_areas();< $result = \external_api::clean_returnvalue(\core_tag_external::get_tag_areas_returns(), $result);> $result = external_api::clean_returnvalue(\core_tag_external::get_tag_areas_returns(), $result);$areas = $DB->get_records('tag_area'); $this->assertCount(count($areas), $result['areas']); foreach ($result['areas'] as $area) { $this->assertEquals($areas[$area['id']]->component, $area['component']); $this->assertEquals($areas[$area['id']]->itemtype, $area['itemtype']); } } /** * Test get_tag_collections. */ public function test_get_tag_collections() { global $DB; $this->resetAfterTest(true); // Create new tag collection. $data = (object) array('name' => 'new tag coll'); \core_tag_collection::create($data); $this->setAdminUser(); $result = \core_tag_external::get_tag_collections();< $result = \external_api::clean_returnvalue(\core_tag_external::get_tag_collections_returns(), $result);> $result = external_api::clean_returnvalue(\core_tag_external::get_tag_collections_returns(), $result);$collections = $DB->get_records('tag_coll'); $this->assertCount(count($collections), $result['collections']); foreach ($result['collections'] as $collection) { $this->assertEquals($collections[$collection['id']]->component, $collection['component']); $this->assertEquals($collections[$collection['id']]->name, $collection['name']); } } /** * Test get_tag_cloud. */ public function test_get_tag_cloud() { global $USER, $DB; $this->resetAfterTest(true); // Create tags for two user profiles, a post and one course. $this->setAdminUser(); $context = \context_user::instance($USER->id); \core_tag_tag::set_item_tags('core', 'user', $USER->id, $context, array('Cats', 'Dogs')); $this->setUser($this->getDataGenerator()->create_user()); $context = \context_user::instance($USER->id); \core_tag_tag::set_item_tags('core', 'user', $USER->id, $context, array('Mice')); $course = $this->getDataGenerator()->create_course(); $coursecontext = \context_course::instance($course->id); \core_tag_tag::set_item_tags('core', 'course', $course->id, $coursecontext, array('Cats')); $post = new \stdClass(); $post->userid = $USER->id; $post->content = 'test post content text'; $post->id = $DB->insert_record('post', $post); $context = \context_system::instance(); \core_tag_tag::set_item_tags('core', 'post', $post->id, $context, array('Horses', 'Cats')); // First, retrieve complete cloud. $result = \core_tag_external::get_tag_cloud();< $result = \external_api::clean_returnvalue(\core_tag_external::get_tag_cloud_returns(), $result);> $result = external_api::clean_returnvalue(\core_tag_external::get_tag_cloud_returns(), $result);$this->assertCount(4, $result['tags']); // Four different tags: Cats, Dogs, Mice, Horses. $this->assertEquals(4, $result['tagscount']); $this->assertEquals(4, $result['totalcount']); foreach ($result['tags'] as $tag) { if ($tag['name'] == 'Cats') { $this->assertEquals(3, $tag['count']); } else { $this->assertEquals(1, $tag['count']); } } // Test filter by collection, pagination and sorting. $defaultcoll = \core_tag_collection::get_default(); $result = \core_tag_external::get_tag_cloud($defaultcoll, false, 2, 'count');< $result = \external_api::clean_returnvalue(\core_tag_external::get_tag_cloud_returns(), $result);> $result = external_api::clean_returnvalue(\core_tag_external::get_tag_cloud_returns(), $result);$this->assertCount(2, $result['tags']); // Only two tags. $this->assertEquals(2, $result['tagscount']); $this->assertEquals(4, $result['totalcount']); $this->assertEquals('Dogs', $result['tags'][0]['name']); // Lower count first. // Test search. $result = \core_tag_external::get_tag_cloud(0, false, 150, 'name', 'Mice');< $result = \external_api::clean_returnvalue(\core_tag_external::get_tag_cloud_returns(), $result);> $result = external_api::clean_returnvalue(\core_tag_external::get_tag_cloud_returns(), $result);$this->assertCount(1, $result['tags']); // Only the searched tags. $this->assertEquals(1, $result['tagscount']); $this->assertEquals(1, $result['totalcount']); // When searching, the total is always for the search. $this->assertEquals('Mice', $result['tags'][0]['name']); $result = \core_tag_external::get_tag_cloud(0, false, 150, 'name', 'Conejo');< $result = \external_api::clean_returnvalue(\core_tag_external::get_tag_cloud_returns(), $result);> $result = external_api::clean_returnvalue(\core_tag_external::get_tag_cloud_returns(), $result);$this->assertCount(0, $result['tags']); // Nothing found. $this->assertEquals(0, $result['tagscount']); $this->assertEquals(0, $result['totalcount']); // When searching, the total is always for the search. // Test standard filtering. $micetag = \core_tag_tag::get_by_name($defaultcoll, 'Mice', '*'); $micetag->update(array('isstandard' => 1)); $result = \core_tag_external::get_tag_cloud(0, true);< $result = \external_api::clean_returnvalue(\core_tag_external::get_tag_cloud_returns(), $result);> $result = external_api::clean_returnvalue(\core_tag_external::get_tag_cloud_returns(), $result);$this->assertCount(1, $result['tags']); $this->assertEquals(1, $result['tagscount']); $this->assertEquals(1, $result['totalcount']); // When searching, the total is always for the search. $this->assertEquals('Mice', $result['tags'][0]['name']); // Test course context filtering. $result = \core_tag_external::get_tag_cloud(0, false, 150, 'name', '', 0, $coursecontext->id);< $result = \external_api::clean_returnvalue(\core_tag_external::get_tag_cloud_returns(), $result);> $result = external_api::clean_returnvalue(\core_tag_external::get_tag_cloud_returns(), $result);$this->assertCount(1, $result['tags']); $this->assertEquals(1, $result['tagscount']); $this->assertEquals(1, $result['totalcount']); // When searching, the total is always for the search. $this->assertEquals('Cats', $result['tags'][0]['name']); // Complete system context. $result = \core_tag_external::get_tag_cloud(0, false, 150, 'name', '', 0, \context_system::instance()->id);< $result = \external_api::clean_returnvalue(\core_tag_external::get_tag_cloud_returns(), $result);> $result = external_api::clean_returnvalue(\core_tag_external::get_tag_cloud_returns(), $result);$this->assertCount(4, $result['tags']); $this->assertEquals(4, $result['tagscount']); // Just system context - avoid children. $result = \core_tag_external::get_tag_cloud(0, false, 150, 'name', '', 0, \context_system::instance()->id, 0);< $result = \external_api::clean_returnvalue(\core_tag_external::get_tag_cloud_returns(), $result);> $result = external_api::clean_returnvalue(\core_tag_external::get_tag_cloud_returns(), $result);$this->assertCount(2, $result['tags']); $this->assertEquals(2, $result['tagscount']); // Horses and Cats. $this->assertEquals('Cats', $result['tags'][0]['name']); $this->assertEquals('Horses', $result['tags'][1]['name']); } }