MDL-63960 dataprivacy: Do not perform strict type checks for id
authorAndrew Nicols <andrew@nicols.co.uk>
Fri, 9 Nov 2018 23:27:58 +0000 (07:27 +0800)
committerAndrew Nicols <andrew@nicols.co.uk>
Sat, 10 Nov 2018 07:34:21 +0000 (15:34 +0800)
When inherit is specified in the data registry it is stored as a
string and we cannot perform a strict comparison with it.

We should still compare strict comparison checks against null, or false,
but not for the NOTSET (0) or INHERIT values (-1).

admin/tool/dataprivacy/classes/data_registry.php
admin/tool/dataprivacy/tests/api_test.php

index 50681ba..75670f4 100644 (file)
@@ -80,12 +80,12 @@ class data_registry {
         if (!empty($pluginname)) {
             list($purposevar, $categoryvar) = self::var_names_from_context($classname);
             // If the plugin-level doesn't have a default purpose set, try the context level.
-            if ($purposeid === false) {
+            if ($purposeid == false) {
                 $purposeid = get_config('tool_dataprivacy', $purposevar);
             }
 
             // If the plugin-level doesn't have a default category set, try the context level.
-            if ($categoryid === false) {
+            if ($categoryid == false) {
                 $categoryid = get_config('tool_dataprivacy', $categoryvar);
             }
         }
@@ -184,11 +184,11 @@ class data_registry {
         }
         $fieldname = $element . 'id';
 
-        if (!empty($forcedvalue) && ($forcedvalue === context_instance::INHERIT)) {
+        if (!empty($forcedvalue) && ($forcedvalue == context_instance::INHERIT)) {
             // Do not include the current context when calculating the value.
             // This has the effect that an inheritted value is calculated.
             $parentcontextids = $context->get_parent_context_ids(false);
-        } else if (!empty($forcedvalue) && ($forcedvalue !== context_instance::NOTSET)) {
+        } else if (!empty($forcedvalue) && ($forcedvalue != context_instance::NOTSET)) {
             return self::get_element_instance($element, $forcedvalue);
         } else {
             // Fetch all parent contexts, including self.
@@ -237,7 +237,7 @@ class data_registry {
                 $checkcontextlevel = true;
             }
 
-            if (!empty($forcedvalue) && context_instance::NOTSET === $forcedvalue) {
+            if (!empty($forcedvalue) && context_instance::NOTSET == $forcedvalue) {
                 $checkcontextlevel = true;
             }
 
@@ -249,7 +249,7 @@ class data_registry {
 
                 $instancevalue = $$fieldname;
 
-                if (context_instance::NOTSET !== $instancevalue && context_instance::INHERIT !== $instancevalue) {
+                if (context_instance::NOTSET != $instancevalue && context_instance::INHERIT != $instancevalue) {
                     // There is an actual value. Return it.
                     return self::get_element_instance($element, $instancevalue);
                 }
@@ -290,7 +290,7 @@ class data_registry {
         list($purposeid, $categoryid) = self::get_effective_default_contextlevel_purpose_and_category($contextlevel);
 
         // Note: The $$fieldname points to either $purposeid, or $categoryid.
-        if (context_instance::NOTSET !== $$fieldname && context_instance::INHERIT !== $$fieldname) {
+        if (context_instance::NOTSET != $$fieldname && context_instance::INHERIT != $$fieldname) {
             // There is a specific value set.
             return self::get_element_instance($element, $$fieldname);
         }
@@ -325,7 +325,7 @@ class data_registry {
             list($parentpurposeid, $parentcategoryid) = self::get_defaults(CONTEXT_SYSTEM);
 
             if (context_instance::INHERIT == $purposeid || context_instance::NOTSET == $purposeid) {
-                $purposeid = $parentpurposeid;
+                $purposeid = (int)$parentpurposeid;
             }
 
             if (context_instance::INHERIT == $categoryid || context_instance::NOTSET == $categoryid) {
index 8eed7cb..e9bd9f5 100644 (file)
@@ -1263,34 +1263,72 @@ class tool_dataprivacy_api_testcase extends advanced_testcase {
         // Initially everything is set to Inherit.
         $this->assertEquals($systemdata->purpose, api::get_effective_context_purpose($contextsystem));
         $this->assertEquals($systemdata->purpose, api::get_effective_context_purpose($contextcat));
+        $this->assertEquals($systemdata->purpose, api::get_effective_context_purpose($contextcat, "-1"));
+        $this->assertEquals($systemdata->purpose, api::get_effective_context_purpose($contextcat, "0"));
         $this->assertEquals($systemdata->purpose, api::get_effective_context_purpose($contextsubcat));
+        $this->assertEquals($systemdata->purpose, api::get_effective_context_purpose($contextsubcat, "-1"));
+        $this->assertEquals($systemdata->purpose, api::get_effective_context_purpose($contextsubcat, "0"));
         $this->assertEquals($systemdata->purpose, api::get_effective_context_purpose($contextcourse));
+        $this->assertEquals($systemdata->purpose, api::get_effective_context_purpose($contextcourse, "-1"));
+        $this->assertEquals($systemdata->purpose, api::get_effective_context_purpose($contextcourse, "0"));
         $this->assertEquals($systemdata->purpose, api::get_effective_context_purpose($contextforum));
+        $this->assertEquals($systemdata->purpose, api::get_effective_context_purpose($contextforum, "-1"));
+        $this->assertEquals($systemdata->purpose, api::get_effective_context_purpose($contextforum, "0"));
         $this->assertEquals($systemdata->purpose, api::get_effective_context_purpose($contextuser));
+        $this->assertEquals($systemdata->purpose, api::get_effective_context_purpose($contextuser, "-1"));
+        $this->assertEquals($systemdata->purpose, api::get_effective_context_purpose($contextuser, "0"));
 
         $this->assertEquals($systemdata->category, api::get_effective_context_category($contextsystem));
         $this->assertEquals($systemdata->category, api::get_effective_context_category($contextcat));
+        $this->assertEquals($systemdata->category, api::get_effective_context_category($contextcat, "-1"));
+        $this->assertEquals($systemdata->category, api::get_effective_context_category($contextcat, "0"));
         $this->assertEquals($systemdata->category, api::get_effective_context_category($contextsubcat));
+        $this->assertEquals($systemdata->category, api::get_effective_context_category($contextsubcat, "-1"));
+        $this->assertEquals($systemdata->category, api::get_effective_context_category($contextsubcat, "0"));
         $this->assertEquals($systemdata->category, api::get_effective_context_category($contextcourse));
+        $this->assertEquals($systemdata->category, api::get_effective_context_category($contextcourse, "-1"));
+        $this->assertEquals($systemdata->category, api::get_effective_context_category($contextcourse, "0"));
         $this->assertEquals($systemdata->category, api::get_effective_context_category($contextforum));
+        $this->assertEquals($systemdata->category, api::get_effective_context_category($contextforum, "-1"));
+        $this->assertEquals($systemdata->category, api::get_effective_context_category($contextforum, "0"));
         $this->assertEquals($systemdata->category, api::get_effective_context_category($contextuser));
+        $this->assertEquals($systemdata->category, api::get_effective_context_category($contextuser, "-1"));
+        $this->assertEquals($systemdata->category, api::get_effective_context_category($contextuser, "0"));
 
         // When actively set, user will use the specified value.
         $userdata = $this->create_and_set_purpose_for_contextlevel('PT1S', CONTEXT_USER);
 
         $this->assertEquals($systemdata->purpose, api::get_effective_context_purpose($contextsystem));
         $this->assertEquals($systemdata->purpose, api::get_effective_context_purpose($contextcat));
+        $this->assertEquals($systemdata->purpose, api::get_effective_context_purpose($contextcat, "-1"));
+        $this->assertEquals($systemdata->purpose, api::get_effective_context_purpose($contextcat, "0"));
         $this->assertEquals($systemdata->purpose, api::get_effective_context_purpose($contextsubcat));
+        $this->assertEquals($systemdata->purpose, api::get_effective_context_purpose($contextsubcat, "-1"));
+        $this->assertEquals($systemdata->purpose, api::get_effective_context_purpose($contextsubcat, "0"));
         $this->assertEquals($systemdata->purpose, api::get_effective_context_purpose($contextcourse));
+        $this->assertEquals($systemdata->purpose, api::get_effective_context_purpose($contextcourse, "-1"));
+        $this->assertEquals($systemdata->purpose, api::get_effective_context_purpose($contextcourse, "0"));
         $this->assertEquals($systemdata->purpose, api::get_effective_context_purpose($contextforum));
+        $this->assertEquals($systemdata->purpose, api::get_effective_context_purpose($contextforum, "-1"));
+        $this->assertEquals($systemdata->purpose, api::get_effective_context_purpose($contextforum, "0"));
         $this->assertEquals($userdata->purpose, api::get_effective_context_purpose($contextuser));
+        $this->assertEquals($systemdata->purpose, api::get_effective_context_purpose($contextuser, "-1"));
 
         $this->assertEquals($systemdata->category, api::get_effective_context_category($contextsystem));
         $this->assertEquals($systemdata->category, api::get_effective_context_category($contextcat));
+        $this->assertEquals($systemdata->category, api::get_effective_context_category($contextcat, "-1"));
+        $this->assertEquals($systemdata->category, api::get_effective_context_category($contextcat, "0"));
         $this->assertEquals($systemdata->category, api::get_effective_context_category($contextsubcat));
+        $this->assertEquals($systemdata->category, api::get_effective_context_category($contextsubcat, "-1"));
+        $this->assertEquals($systemdata->category, api::get_effective_context_category($contextsubcat, "0"));
         $this->assertEquals($systemdata->category, api::get_effective_context_category($contextcourse));
+        $this->assertEquals($systemdata->category, api::get_effective_context_category($contextcourse, "-1"));
+        $this->assertEquals($systemdata->category, api::get_effective_context_category($contextcourse, "0"));
         $this->assertEquals($systemdata->category, api::get_effective_context_category($contextforum));
+        $this->assertEquals($systemdata->category, api::get_effective_context_category($contextforum, "-1"));
+        $this->assertEquals($systemdata->category, api::get_effective_context_category($contextforum, "0"));
         $this->assertEquals($userdata->category, api::get_effective_context_category($contextuser));
+        $this->assertEquals($systemdata->purpose, api::get_effective_context_purpose($contextuser, "-1"));
 
         // Set a context for the top category.
         $catpurpose = new purpose(0, (object) [
@@ -1309,15 +1347,32 @@ class tool_dataprivacy_api_testcase extends advanced_testcase {
 
         $this->assertEquals($systemdata->purpose, api::get_effective_context_purpose($contextsystem));
         $this->assertEquals($catpurpose, api::get_effective_context_purpose($contextcat));
+        $this->assertEquals($systemdata->purpose, api::get_effective_context_purpose($contextcat, "-1"));
+        $this->assertEquals($catpurpose, api::get_effective_context_purpose($contextcat, "0"));
         $this->assertEquals($catpurpose, api::get_effective_context_purpose($contextsubcat));
+        $this->assertEquals($catpurpose, api::get_effective_context_purpose($contextsubcat, "-1"));
+        $this->assertEquals($catpurpose, api::get_effective_context_purpose($contextsubcat, "0"));
         $this->assertEquals($catpurpose, api::get_effective_context_purpose($contextcourse));
+        $this->assertEquals($catpurpose, api::get_effective_context_purpose($contextcourse, "-1"));
+        $this->assertEquals($catpurpose, api::get_effective_context_purpose($contextcourse, "0"));
         $this->assertEquals($catpurpose, api::get_effective_context_purpose($contextforum));
+        $this->assertEquals($catpurpose, api::get_effective_context_purpose($contextforum, "-1"));
+        $this->assertEquals($catpurpose, api::get_effective_context_purpose($contextforum, "0"));
+        $this->assertEquals($catpurpose, api::get_effective_context_purpose($contextforum, "0"));
 
         $this->assertEquals($systemdata->category, api::get_effective_context_category($contextsystem));
         $this->assertEquals($catcategory, api::get_effective_context_category($contextcat));
+        $this->assertEquals($systemdata->category, api::get_effective_context_category($contextcat, "-1"));
+        $this->assertEquals($catcategory, api::get_effective_context_category($contextcat, "0"));
         $this->assertEquals($catcategory, api::get_effective_context_category($contextsubcat));
+        $this->assertEquals($catcategory, api::get_effective_context_category($contextsubcat, "-1"));
+        $this->assertEquals($catcategory, api::get_effective_context_category($contextsubcat, "0"));
         $this->assertEquals($catcategory, api::get_effective_context_category($contextcourse));
+        $this->assertEquals($catcategory, api::get_effective_context_category($contextcourse, "-1"));
+        $this->assertEquals($catcategory, api::get_effective_context_category($contextcourse, "0"));
         $this->assertEquals($catcategory, api::get_effective_context_category($contextforum));
+        $this->assertEquals($catcategory, api::get_effective_context_category($contextforum, "-1"));
+        $this->assertEquals($catcategory, api::get_effective_context_category($contextforum, "0"));
 
         // Set a context for the sub category.
         $subcatpurpose = new purpose(0, (object) [
@@ -1336,15 +1391,31 @@ class tool_dataprivacy_api_testcase extends advanced_testcase {
 
         $this->assertEquals($systemdata->purpose, api::get_effective_context_purpose($contextsystem));
         $this->assertEquals($catpurpose, api::get_effective_context_purpose($contextcat));
+        $this->assertEquals($systemdata->purpose, api::get_effective_context_purpose($contextcat, "-1"));
+        $this->assertEquals($catpurpose, api::get_effective_context_purpose($contextcat, "0"));
         $this->assertEquals($subcatpurpose, api::get_effective_context_purpose($contextsubcat));
+        $this->assertEquals($catpurpose, api::get_effective_context_purpose($contextsubcat, "-1"));
+        $this->assertEquals($subcatpurpose, api::get_effective_context_purpose($contextsubcat, "0"));
         $this->assertEquals($subcatpurpose, api::get_effective_context_purpose($contextcourse));
+        $this->assertEquals($subcatpurpose, api::get_effective_context_purpose($contextcourse, "-1"));
+        $this->assertEquals($subcatpurpose, api::get_effective_context_purpose($contextcourse, "0"));
         $this->assertEquals($subcatpurpose, api::get_effective_context_purpose($contextforum));
+        $this->assertEquals($subcatpurpose, api::get_effective_context_purpose($contextforum, "-1"));
+        $this->assertEquals($subcatpurpose, api::get_effective_context_purpose($contextforum, "0"));
 
         $this->assertEquals($systemdata->category, api::get_effective_context_category($contextsystem));
         $this->assertEquals($catcategory, api::get_effective_context_category($contextcat));
+        $this->assertEquals($systemdata->category, api::get_effective_context_category($contextcat, "-1"));
+        $this->assertEquals($catcategory, api::get_effective_context_category($contextcat, "0"));
         $this->assertEquals($subcatcategory, api::get_effective_context_category($contextsubcat));
+        $this->assertEquals($catcategory, api::get_effective_context_category($contextsubcat, "-1"));
+        $this->assertEquals($subcatcategory, api::get_effective_context_category($contextsubcat, "0"));
         $this->assertEquals($subcatcategory, api::get_effective_context_category($contextcourse));
+        $this->assertEquals($subcatcategory, api::get_effective_context_category($contextcourse, "-1"));
+        $this->assertEquals($subcatcategory, api::get_effective_context_category($contextcourse, "0"));
         $this->assertEquals($subcatcategory, api::get_effective_context_category($contextforum));
+        $this->assertEquals($subcatcategory, api::get_effective_context_category($contextforum, "-1"));
+        $this->assertEquals($subcatcategory, api::get_effective_context_category($contextforum, "0"));
 
         // Set a context for the course.
         $coursepurpose = new purpose(0, (object) [
@@ -1363,15 +1434,31 @@ class tool_dataprivacy_api_testcase extends advanced_testcase {
 
         $this->assertEquals($systemdata->purpose, api::get_effective_context_purpose($contextsystem));
         $this->assertEquals($catpurpose, api::get_effective_context_purpose($contextcat));
+        $this->assertEquals($systemdata->purpose, api::get_effective_context_purpose($contextcat, "-1"));
+        $this->assertEquals($catpurpose, api::get_effective_context_purpose($contextcat, "0"));
         $this->assertEquals($subcatpurpose, api::get_effective_context_purpose($contextsubcat));
+        $this->assertEquals($catpurpose, api::get_effective_context_purpose($contextsubcat, "-1"));
+        $this->assertEquals($subcatpurpose, api::get_effective_context_purpose($contextsubcat, "0"));
         $this->assertEquals($coursepurpose, api::get_effective_context_purpose($contextcourse));
+        $this->assertEquals($subcatpurpose, api::get_effective_context_purpose($contextcourse, "-1"));
+        $this->assertEquals($coursepurpose, api::get_effective_context_purpose($contextcourse, "0"));
         $this->assertEquals($coursepurpose, api::get_effective_context_purpose($contextforum));
+        $this->assertEquals($coursepurpose, api::get_effective_context_purpose($contextforum, "-1"));
+        $this->assertEquals($coursepurpose, api::get_effective_context_purpose($contextforum, "0"));
 
         $this->assertEquals($systemdata->category, api::get_effective_context_category($contextsystem));
         $this->assertEquals($catcategory, api::get_effective_context_category($contextcat));
+        $this->assertEquals($systemdata->category, api::get_effective_context_category($contextcat, "-1"));
+        $this->assertEquals($catcategory, api::get_effective_context_category($contextcat, "0"));
         $this->assertEquals($subcatcategory, api::get_effective_context_category($contextsubcat));
+        $this->assertEquals($catcategory, api::get_effective_context_category($contextsubcat, "-1"));
+        $this->assertEquals($subcatcategory, api::get_effective_context_category($contextsubcat, "0"));
         $this->assertEquals($coursecategory, api::get_effective_context_category($contextcourse));
+        $this->assertEquals($subcatcategory, api::get_effective_context_category($contextcourse, "-1"));
+        $this->assertEquals($coursecategory, api::get_effective_context_category($contextcourse, "0"));
         $this->assertEquals($coursecategory, api::get_effective_context_category($contextforum));
+        $this->assertEquals($coursecategory, api::get_effective_context_category($contextforum, "-1"));
+        $this->assertEquals($coursecategory, api::get_effective_context_category($contextforum, "0"));
 
         // Set a context for the forum.
         $forumpurpose = new purpose(0, (object) [
@@ -1390,15 +1477,132 @@ class tool_dataprivacy_api_testcase extends advanced_testcase {
 
         $this->assertEquals($systemdata->purpose, api::get_effective_context_purpose($contextsystem));
         $this->assertEquals($catpurpose, api::get_effective_context_purpose($contextcat));
+        $this->assertEquals($systemdata->purpose, api::get_effective_context_purpose($contextcat, "-1"));
+        $this->assertEquals($catpurpose, api::get_effective_context_purpose($contextcat, "0"));
         $this->assertEquals($subcatpurpose, api::get_effective_context_purpose($contextsubcat));
+        $this->assertEquals($catpurpose, api::get_effective_context_purpose($contextsubcat, "-1"));
+        $this->assertEquals($subcatpurpose, api::get_effective_context_purpose($contextsubcat, "0"));
         $this->assertEquals($coursepurpose, api::get_effective_context_purpose($contextcourse));
+        $this->assertEquals($subcatpurpose, api::get_effective_context_purpose($contextcourse, "-1"));
+        $this->assertEquals($coursepurpose, api::get_effective_context_purpose($contextcourse, "0"));
         $this->assertEquals($forumpurpose, api::get_effective_context_purpose($contextforum));
+        $this->assertEquals($coursepurpose, api::get_effective_context_purpose($contextforum, "-1"));
+        $this->assertEquals($forumpurpose, api::get_effective_context_purpose($contextforum, "0"));
 
         $this->assertEquals($systemdata->category, api::get_effective_context_category($contextsystem));
         $this->assertEquals($catcategory, api::get_effective_context_category($contextcat));
+        $this->assertEquals($systemdata->category, api::get_effective_context_category($contextcat, "-1"));
+        $this->assertEquals($catcategory, api::get_effective_context_category($contextcat, "0"));
         $this->assertEquals($subcatcategory, api::get_effective_context_category($contextsubcat));
+        $this->assertEquals($catcategory, api::get_effective_context_category($contextsubcat, "-1"));
+        $this->assertEquals($subcatcategory, api::get_effective_context_category($contextsubcat, "0"));
         $this->assertEquals($coursecategory, api::get_effective_context_category($contextcourse));
+        $this->assertEquals($subcatcategory, api::get_effective_context_category($contextcourse, "-1"));
+        $this->assertEquals($coursecategory, api::get_effective_context_category($contextcourse, "0"));
         $this->assertEquals($forumcategory, api::get_effective_context_category($contextforum));
+        $this->assertEquals($coursecategory, api::get_effective_context_category($contextforum, "-1"));
+        $this->assertEquals($forumcategory, api::get_effective_context_category($contextforum, "0"));
+    }
+
+    /**
+     * Ensure that context inheritance works up the context tree when inherit values are explicitly set at the
+     * contextlevel.
+     *
+     * Although it should not be possible to set hard INHERIT values at this level, there may be legacy data which still
+     * contains this.
+     */
+    public function test_effective_context_inheritance_explicitly_set() {
+        $this->resetAfterTest();
+
+        $systemdata = $this->create_and_set_purpose_for_contextlevel('PT1S', CONTEXT_SYSTEM);
+
+        /*
+         * System
+         * - Cat
+         *   - Subcat
+         *     - Course
+         *       - Forum
+         * - User
+         *   - User block
+         */
+        $cat = $this->getDataGenerator()->create_category();
+        $subcat = $this->getDataGenerator()->create_category(['parent' => $cat->id]);
+        $course = $this->getDataGenerator()->create_course(['category' => $subcat->id]);
+        $forum = $this->getDataGenerator()->create_module('forum', ['course' => $course->id]);
+        list(, $forumcm) = get_course_and_cm_from_instance($forum->id, 'forum');
+
+        $contextsystem = \context_system::instance();
+        $contextcat = \context_coursecat::instance($cat->id);
+        $contextsubcat = \context_coursecat::instance($subcat->id);
+        $contextcourse = \context_course::instance($course->id);
+        $contextforum = \context_module::instance($forumcm->id);
+
+        // Initially everything is set to Inherit.
+        $this->assertEquals($systemdata->purpose, api::get_effective_context_purpose($contextsystem));
+        $this->assertEquals($systemdata->purpose, api::get_effective_context_purpose($contextcat));
+        $this->assertEquals($systemdata->purpose, api::get_effective_context_purpose($contextsubcat));
+        $this->assertEquals($systemdata->purpose, api::get_effective_context_purpose($contextcourse));
+        $this->assertEquals($systemdata->purpose, api::get_effective_context_purpose($contextforum));
+
+        $this->assertEquals($systemdata->category, api::get_effective_context_category($contextsystem));
+        $this->assertEquals($systemdata->category, api::get_effective_context_category($contextcat));
+        $this->assertEquals($systemdata->category, api::get_effective_context_category($contextsubcat));
+        $this->assertEquals($systemdata->category, api::get_effective_context_category($contextcourse));
+        $this->assertEquals($systemdata->category, api::get_effective_context_category($contextforum));
+
+        // Set a default value of inherit for CONTEXT_COURSECAT.
+        $classname = \context_helper::get_class_for_level(CONTEXT_COURSECAT);
+        list($purposevar, $categoryvar) = data_registry::var_names_from_context($classname);
+        set_config($purposevar, '-1', 'tool_dataprivacy');
+        set_config($categoryvar, '-1', 'tool_dataprivacy');
+
+        $this->assertEquals($systemdata->purpose, api::get_effective_context_purpose($contextsystem));
+        $this->assertEquals($systemdata->purpose, api::get_effective_context_purpose($contextcat));
+        $this->assertEquals($systemdata->purpose, api::get_effective_context_purpose($contextsubcat));
+        $this->assertEquals($systemdata->purpose, api::get_effective_context_purpose($contextcourse));
+        $this->assertEquals($systemdata->purpose, api::get_effective_context_purpose($contextforum));
+
+        $this->assertEquals($systemdata->category, api::get_effective_context_category($contextsystem));
+        $this->assertEquals($systemdata->category, api::get_effective_context_category($contextcat));
+        $this->assertEquals($systemdata->category, api::get_effective_context_category($contextsubcat));
+        $this->assertEquals($systemdata->category, api::get_effective_context_category($contextcourse));
+        $this->assertEquals($systemdata->category, api::get_effective_context_category($contextforum));
+
+        // Set a default value of inherit for CONTEXT_COURSE.
+        $classname = \context_helper::get_class_for_level(CONTEXT_COURSE);
+        list($purposevar, $categoryvar) = data_registry::var_names_from_context($classname);
+        set_config($purposevar, '-1', 'tool_dataprivacy');
+        set_config($categoryvar, '-1', 'tool_dataprivacy');
+
+        $this->assertEquals($systemdata->purpose, api::get_effective_context_purpose($contextsystem));
+        $this->assertEquals($systemdata->purpose, api::get_effective_context_purpose($contextcat));
+        $this->assertEquals($systemdata->purpose, api::get_effective_context_purpose($contextsubcat));
+        $this->assertEquals($systemdata->purpose, api::get_effective_context_purpose($contextcourse));
+        $this->assertEquals($systemdata->purpose, api::get_effective_context_purpose($contextforum));
+
+        $this->assertEquals($systemdata->category, api::get_effective_context_category($contextsystem));
+        $this->assertEquals($systemdata->category, api::get_effective_context_category($contextcat));
+        $this->assertEquals($systemdata->category, api::get_effective_context_category($contextsubcat));
+        $this->assertEquals($systemdata->category, api::get_effective_context_category($contextcourse));
+        $this->assertEquals($systemdata->category, api::get_effective_context_category($contextforum));
+
+        // Set a default value of inherit for CONTEXT_MODULE.
+        $classname = \context_helper::get_class_for_level(CONTEXT_MODULE);
+        list($purposevar, $categoryvar) = data_registry::var_names_from_context($classname);
+        set_config($purposevar, '-1', 'tool_dataprivacy');
+        set_config($categoryvar, '-1', 'tool_dataprivacy');
+
+        $this->assertEquals($systemdata->purpose, api::get_effective_context_purpose($contextsystem));
+        $this->assertEquals($systemdata->purpose, api::get_effective_context_purpose($contextcat));
+        $this->assertEquals($systemdata->purpose, api::get_effective_context_purpose($contextsubcat));
+        $this->assertEquals($systemdata->purpose, api::get_effective_context_purpose($contextcourse));
+        $this->assertEquals($systemdata->purpose, api::get_effective_context_purpose($contextforum));
+
+        $this->assertEquals($systemdata->category, api::get_effective_context_category($contextsystem));
+        $this->assertEquals($systemdata->category, api::get_effective_context_category($contextcat));
+        $this->assertEquals($systemdata->category, api::get_effective_context_category($contextsubcat));
+        $this->assertEquals($systemdata->category, api::get_effective_context_category($contextcourse));
+        $this->assertEquals($systemdata->category, api::get_effective_context_category($contextforum));
     }
 
     /**