MDL-68098 ws: Add unit tests to test mathjax in WS
authorDani Palou <dani@moodle.com>
Fri, 4 Sep 2020 07:25:15 +0000 (09:25 +0200)
committerDani Palou <dani@moodle.com>
Wed, 23 Sep 2020 09:18:41 +0000 (11:18 +0200)
auth/email/tests/external_test.php
blocks/tests/externallib_test.php
calendar/tests/externallib_test.php
enrol/tests/externallib_test.php
lib/external/tests/external_test.php
message/tests/externallib_test.php
webservice/tests/helpers.php
webservice/upgrade.txt

index 0220640..f62f95c 100644 (file)
@@ -93,6 +93,51 @@ class auth_email_external_testcase extends externallib_advanced_testcase {
         $this->assertEquals('textarea', $namedarray['sometext']['datatype']);
     }
 
+    /**
+     * Test get_signup_settings with mathjax in a profile field.
+     */
+    public function test_get_signup_settings_with_mathjax_in_profile_fields() {
+        global $CFG, $DB;
+
+        require_once($CFG->dirroot . '/lib/externallib.php');
+
+        // Enable MathJax filter in content and headings.
+        $this->configure_filters([
+            ['name' => 'mathjaxloader', 'state' => TEXTFILTER_ON, 'move' => -1, 'applytostrings' => true],
+        ]);
+
+        // Create category with MathJax and a new field with MathJax.
+        $categoryname = 'Cat $$(a+b)=2$$';
+        $fieldname = 'Some text $$(a+b)=2$$';
+        $categoryid = $DB->insert_record('user_info_category', array('name' => $categoryname, 'sortorder' => 1));
+        $field3 = $DB->insert_record('user_info_field', array(
+                'shortname' => 'mathjaxname', 'name' => $fieldname, 'categoryid' => $categoryid,
+                'datatype' => 'textarea', 'signup' => 1, 'visible' => 1, 'required' => 1, 'sortorder' => 2));
+
+        $result = auth_email_external::get_signup_settings();
+        $result = external_api::clean_returnvalue(auth_email_external::get_signup_settings_returns(), $result);
+
+        // Format the original data.
+        $sitecontext = context_system::instance();
+        $categoryname = external_format_string($categoryname, $sitecontext->id);
+        $fieldname = external_format_string($fieldname, $sitecontext->id);
+
+        // Whip up a array with named entries to easily check against.
+        $namedarray = array();
+        foreach ($result['profilefields'] as $key => $value) {
+            $namedarray[$value['shortname']] = $value;
+        }
+
+        // Check the new profile field.
+        $this->assertArrayHasKey('mathjaxname', $namedarray);
+        $this->assertStringContainsString('<span class="filter_mathjaxloader_equation">',
+                $namedarray['mathjaxname']['categoryname']);
+        $this->assertStringContainsString('<span class="filter_mathjaxloader_equation">',
+                $namedarray['mathjaxname']['name']);
+        $this->assertEquals($categoryname, $namedarray['mathjaxname']['categoryname']);
+        $this->assertEquals($fieldname, $namedarray['mathjaxname']['name']);
+    }
+
     public function test_signup_user() {
         global $DB;
 
index ee1b61b..f5bb942 100644 (file)
@@ -235,6 +235,85 @@ class core_block_externallib_testcase extends externallib_advanced_testcase {
         $this->assertEquals(5, $configcounts);
     }
 
+    /**
+     * Test get_course_blocks contents with mathjax.
+     */
+    public function test_get_course_blocks_contents_with_mathjax() {
+        global $DB, $CFG;
+
+        require_once($CFG->dirroot . '/lib/externallib.php');
+
+        $this->resetAfterTest(true);
+
+        // Enable MathJax filter in content and headings.
+        $this->configure_filters([
+            ['name' => 'mathjaxloader', 'state' => TEXTFILTER_ON, 'move' => -1, 'applytostrings' => true],
+        ]);
+
+        // Create a few stuff to test with.
+        $user = $this->getDataGenerator()->create_user();
+        $course = $this->getDataGenerator()->create_course();
+        $studentrole = $DB->get_record('role', array('shortname' => 'student'));
+        $this->getDataGenerator()->enrol_user($user->id, $course->id, $studentrole->id);
+        $coursecontext = context_course::instance($course->id);
+
+        // Create a HTML block.
+        $title = 'My block $$(a+b)=2$$';
+        $body = 'My block contents $$(a+b)=2$$';
+        $bodyformat = FORMAT_MOODLE;
+        $page = new moodle_page();
+        $page->set_context($coursecontext);
+        $page->set_pagelayout('course');
+        $course->format = course_get_format($course)->get_format();
+        $page->set_pagetype('course-view-' . $course->format);
+        $page->blocks->load_blocks();
+        $newblock = 'html';
+        $page->blocks->add_block_at_end_of_default_region($newblock);
+
+        $this->setUser($user);
+        // Re-create the page.
+        $page = new moodle_page();
+        $page->set_context($coursecontext);
+        $page->set_pagelayout('course');
+        $course->format = course_get_format($course)->get_format();
+        $page->set_pagetype('course-view-' . $course->format);
+        $page->blocks->load_blocks();
+        $blocks = $page->blocks->get_blocks_for_region($page->blocks->get_default_region());
+        $block = end($blocks);
+        $block = block_instance('html', $block->instance);
+        $nonscalar = [
+            'something' => true,
+        ];
+        $configdata = (object) [
+            'title' => $title,
+            'text' => [
+                'itemid' => 0,
+                'text' => $body,
+                'format' => $bodyformat,
+            ],
+            'nonscalar' => $nonscalar
+        ];
+        $block->instance_config_save((object) $configdata);
+
+        // Check for the new block.
+        $result = core_block_external::get_course_blocks($course->id, true);
+        $result = external_api::clean_returnvalue(core_block_external::get_course_blocks_returns(), $result);
+
+        // Format the original data.
+        $sitecontext = context_system::instance();
+        $title = external_format_string($title, $coursecontext->id);
+        list($body, $bodyformat) = external_format_text($body, $bodyformat, $coursecontext->id, 'block_html', 'content');
+
+        // Check that the block data is formatted.
+        $this->assertCount(1, $result['blocks']);
+        $this->assertStringContainsString('<span class="filter_mathjaxloader_equation">',
+                $result['blocks'][0]['contents']['title']);
+        $this->assertStringContainsString('<span class="filter_mathjaxloader_equation">',
+                $result['blocks'][0]['contents']['content']);
+        $this->assertEquals($title, $result['blocks'][0]['contents']['title']);
+        $this->assertEquals($body, $result['blocks'][0]['contents']['content']);
+    }
+
     /**
      * Test user get default dashboard blocks.
      */
index fc5ea7e..1d41b31 100644 (file)
@@ -542,6 +542,42 @@ class core_calendar_externallib_testcase extends externallib_advanced_testcase {
         $this->assertEquals($category2->id, $events['events'][1]['categoryid']);
     }
 
+    /**
+     * Test get_calendar_events with mathjax in the name.
+     */
+    public function test_get_calendar_events_with_mathjax() {
+        global $USER;
+
+        $this->resetAfterTest(true);
+        set_config('calendar_adminseesall', 1);
+        $this->setAdminUser();
+
+        // Enable MathJax filter in content and headings.
+        $this->configure_filters([
+            ['name' => 'mathjaxloader', 'state' => TEXTFILTER_ON, 'move' => -1, 'applytostrings' => true],
+        ]);
+
+        // Create a site event with mathjax in the name and description.
+        $siteevent = $this->create_calendar_event('Site Event $$(a+b)=2$$', $USER->id, 'site', 0, time(),
+                ['description' => 'Site Event Description $$(a+b)=2$$']);
+
+        // Now call the WebService.
+        $events = core_calendar_external::get_calendar_events();
+        $events = external_api::clean_returnvalue(core_calendar_external::get_calendar_events_returns(), $events);
+
+        // Format the original data.
+        $sitecontext = context_system::instance();
+        $siteevent->name = $siteevent->format_external_name();
+        list($siteevent->description, $siteevent->descriptionformat) = $siteevent->format_external_text();
+
+        // Check that the event data is formatted.
+        $this->assertCount(1, $events['events']);
+        $this->assertStringContainsString('<span class="filter_mathjaxloader_equation">', $events['events'][0]['name']);
+        $this->assertStringContainsString('<span class="filter_mathjaxloader_equation">', $events['events'][0]['description']);
+        $this->assertEquals($siteevent->name, $events['events'][0]['name']);
+        $this->assertEquals($siteevent->description, $events['events'][0]['description']);
+    }
+
     /**
      * Test core_calendar_external::create_calendar_events
      */
index baf1d70..3a1b1de 100644 (file)
@@ -521,6 +521,61 @@ class core_enrol_externallib_testcase extends externallib_advanced_testcase {
         $this->assertEquals(0, $enrolledincourses[0]['lastaccess']); // I can't see this, hidden by global setting.
     }
 
+    /**
+     * Test get_users_courses with mathjax in the name.
+     */
+    public function test_get_users_courses_with_mathjax() {
+        global $DB;
+
+        $this->resetAfterTest(true);
+
+        // Enable MathJax filter in content and headings.
+        $this->configure_filters([
+            ['name' => 'mathjaxloader', 'state' => TEXTFILTER_ON, 'move' => -1, 'applytostrings' => true],
+        ]);
+
+        // Create a course with MathJax in the name and summary.
+        $coursedata = [
+            'fullname'         => 'Course 1 $$(a+b)=2$$',
+            'shortname'         => 'Course 1 $$(a+b)=2$$',
+            'summary'          => 'Lightwork Course 1 description $$(a+b)=2$$',
+            'summaryformat'    => FORMAT_HTML,
+        ];
+
+        $course = self::getDataGenerator()->create_course($coursedata);
+        $context = context_course::instance($course->id);
+
+        // Enrol a student in the course.
+        $student = $this->getDataGenerator()->create_user();
+        $studentroleid = $DB->get_field('role', 'id', ['shortname' => 'student']);
+        $this->getDataGenerator()->enrol_user($student->id, $course->id, $studentroleid);
+
+        $this->setUser($student);
+
+        // Call the external function.
+        $enrolledincourses = core_enrol_external::get_users_courses($student->id, true);
+
+        // We need to execute the return values cleaning process to simulate the web service server.
+        $enrolledincourses = external_api::clean_returnvalue(core_enrol_external::get_users_courses_returns(), $enrolledincourses);
+
+        // Check that the amount of courses is the right one.
+        $this->assertCount(1, $enrolledincourses);
+
+        // Filter the values to compare them with the returned ones.
+        $course->fullname = external_format_string($course->fullname, $context->id);
+        $course->shortname = external_format_string($course->shortname, $context->id);
+        list($course->summary, $course->summaryformat) =
+             external_format_text($course->summary, $course->summaryformat, $context->id, 'course', 'summary', 0);
+
+        // Compare the values.
+        $this->assertStringContainsString('<span class="filter_mathjaxloader_equation">', $enrolledincourses[0]['fullname']);
+        $this->assertStringContainsString('<span class="filter_mathjaxloader_equation">', $enrolledincourses[0]['shortname']);
+        $this->assertStringContainsString('<span class="filter_mathjaxloader_equation">', $enrolledincourses[0]['summary']);
+        $this->assertEquals($course->fullname, $enrolledincourses[0]['fullname']);
+        $this->assertEquals($course->shortname, $enrolledincourses[0]['shortname']);
+        $this->assertEquals($course->summary, $enrolledincourses[0]['summary']);
+    }
+
     /**
      * Test get_course_enrolment_methods
      */
index bf43f49..788371a 100644 (file)
@@ -199,9 +199,41 @@ class core_external_testcase extends externallib_advanced_testcase {
         $tag = $this->getDataGenerator()->create_tag();
         $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);
+
         $this->assertEquals('new tag name', $res['value']);
     }
 
+    /**
+     * Test update_inplace_editable with mathjax.
+     */
+    public function test_update_inplace_editable_with_mathjax() {
+        $this->resetAfterTest(true);
+        $this->setAdminUser();
+
+        // Enable MathJax filter in content and headings.
+        $this->configure_filters([
+            ['name' => 'mathjaxloader', 'state' => TEXTFILTER_ON, 'move' => -1, 'applytostrings' => true],
+        ]);
+
+        // Create a forum.
+        $course = $this->getDataGenerator()->create_course();
+        $forum = self::getDataGenerator()->create_module('forum', array('course' => $course->id, 'name' => 'forum name'));
+
+        // Change the forum name.
+        $newname = 'New forum name $$(a+b)=2$$';
+        $res = core_external::update_inplace_editable('core_course', 'activityname', $forum->cmid, $newname);
+        $res = external_api::clean_returnvalue(core_external::update_inplace_editable_returns(), $res);
+
+        // Format original data.
+        $context = context_module::instance($forum->cmid);
+        $newname = external_format_string($newname, $context->id);
+        $editlabel = get_string('newactivityname', '', $newname);
+
+        // Check editlabel is the same and has mathjax.
+        $this->assertStringContainsString('<span class="filter_mathjaxloader_equation">', $res['editlabel']);
+        $this->assertEquals($editlabel, $res['editlabel']);
+    }
+
     public function test_get_user_dates() {
         $this->resetAfterTest();
 
index 35f3150..4fd7e6e 100644 (file)
@@ -4242,6 +4242,54 @@ class core_message_externallib_testcase extends externallib_advanced_testcase {
         $this->assertCount(0, $conversations);
     }
 
+    /**
+     * Test that group conversations containing MathJax don't break the WebService.
+     */
+    public function test_get_conversations_group_with_mathjax() {
+        $this->resetAfterTest(true);
+        $this->setAdminUser();
+
+        // Enable MathJax filter in content and headings.
+        $this->configure_filters([
+            ['name' => 'mathjaxloader', 'state' => TEXTFILTER_ON, 'move' => -1, 'applytostrings' => true],
+        ]);
+
+        // Create some users, a course and a group with a linked conversation.
+        $user1 = self::getDataGenerator()->create_user();
+        $user2 = self::getDataGenerator()->create_user();
+
+        $coursename = 'Course $$(a+b)=2$$';
+        $groupname = 'Group $$(a+b)=2$$';
+        $course1 = $this->getDataGenerator()->create_course(['shortname' => $coursename]);
+
+        $this->getDataGenerator()->enrol_user($user1->id, $course1->id);
+        $this->getDataGenerator()->enrol_user($user2->id, $course1->id);
+        $group1 = $this->getDataGenerator()->create_group([
+            'name' => $groupname,
+            'courseid' => $course1->id,
+            'enablemessaging' => 1,
+        ]);
+
+        // Add users to group1.
+        $this->getDataGenerator()->create_group_member(array('groupid' => $group1->id, 'userid' => $user1->id));
+        $this->getDataGenerator()->create_group_member(array('groupid' => $group1->id, 'userid' => $user2->id));
+
+        // Call the WebService.
+        $result = core_message_external::get_conversations($user1->id, 0, 20, null, false);
+        $result = external_api::clean_returnvalue(core_message_external::get_conversations_returns(), $result);
+        $conversations = $result['conversations'];
+
+        // Format original data.
+        $coursecontext = \context_course::instance($course1->id);
+        $coursename = external_format_string($coursename, $coursecontext->id);
+        $groupname = external_format_string($groupname, $coursecontext->id);
+
+        $this->assertStringContainsString('<span class="filter_mathjaxloader_equation">', $conversations[0]['name']);
+        $this->assertStringContainsString('<span class="filter_mathjaxloader_equation">', $conversations[0]['subname']);
+        $this->assertEquals($groupname, $conversations[0]['name']);
+        $this->assertEquals($coursename, $conversations[0]['subname']);
+    }
+
     /**
      * Test verifying get_conversations when there are users in a group and/or individual conversation. The reason this
      * test is performed is because we do not need as much data for group conversations (saving DB calls), so we want
index 4d02871..e30a955 100644 (file)
@@ -64,6 +64,43 @@ abstract class externallib_advanced_testcase extends advanced_testcase {
         return $roleid;
     }
 
+    /**
+     * Configure some filters for external tests.
+     *
+     * @param array $filters Filters to enable. Each filter should contain:
+     *                           - name: name of the filter.
+     *                           - state: the state of the filter.
+     *                           - move: -1 means up, 0 means the same, 1 means down.
+     *                           - applytostrings: true to apply the filter to content and headings, false for just content.
+     */
+    public static function configure_filters($filters) {
+        global $CFG;
+
+        $filterstrings = false;
+
+        // Enable the filters.
+        foreach ($filters as $filter) {
+            $filter = (array) $filter;
+            filter_set_global_state($filter['name'], $filter['state'], $filter['move']);
+            filter_set_applies_to_strings($filter['name'], $filter['applytostrings']);
+
+            $filterstrings = $filterstrings || $filter['applytostrings'];
+        }
+
+        // Set WS filtering.
+        $wssettings = external_settings::get_instance();
+        $wssettings->set_filter(true);
+
+        // Reset filter caches.
+        $filtermanager = filter_manager::instance();
+        $filtermanager->reset_caches();
+
+        if ($filterstrings) {
+            // Don't strip tags in strings.
+            $CFG->formatstringstriptags = false;
+        }
+    }
+
     /**
      * Unassign a capability to $USER.
      *
index 6f92dd3..ec06f9f 100644 (file)
@@ -3,6 +3,10 @@ information provided here is intended especially for developers.
 
 This information is intended for authors of webservices, not people writing webservice clients.
 
+=== 3.10 ===
+
+* The class externallib_advanced_testcase, used in unit tests, has a new function called "configure_filters" to easily configure filters for external functions testing.
+
 === 3.8 ===
 
 * Ajax calls can now specify a cache key. This allows for better caching capabilities on servers. If a cache key