first commit

This commit is contained in:
CHIEFSOFT\ameye
2024-09-30 18:11:26 -04:00
commit e592ca6823
27270 changed files with 5002257 additions and 0 deletions
@@ -0,0 +1,63 @@
<?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 the approved contextlist Class
*
* @package core_privacy
* @category test
* @copyright 2018 Andrew Nicols <andrew@nicols.co.uk>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
defined('MOODLE_INTERNAL') || die();
global $CFG;
use \core_privacy\local\request\approved_contextlist;
/**
* Tests for the \core_privacy API's approved contextlist functionality.
*
* @copyright 2018 Andrew Nicols <andrew@nicols.co.uk>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
* @coversDefaultClass \core_privacy\local\request\approved_contextlist
*/
class approved_contextlist_test extends advanced_testcase {
/**
* The approved contextlist should not be modifiable once set.
*
* @covers ::__construct
* @covers \core_privacy\local\request\approved_contextlist<extended>
*/
public function test_default_values_set(): void {
$testuser = \core_user::get_user_by_username('admin');
$contextids = [3, 2, 1];
$component = 'core_privacy';
$uit = new approved_contextlist($testuser, $component, $contextids);
$this->assertEquals($testuser, $uit->get_user());
$this->assertEquals($component, $uit->get_component());
$result = $uit->get_contextids();
// Note: Array order is not guaranteed and should not matter.
foreach ($contextids as $contextid) {
$this->assertNotFalse(array_search($contextid, $result));
}
}
}
+108
View File
@@ -0,0 +1,108 @@
<?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 the approved userlist Class
*
* @package core_privacy
* @category test
* @copyright 2018 Andrew Nicols <andrew@nicols.co.uk>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
defined('MOODLE_INTERNAL') || die();
global $CFG;
use \core_privacy\local\request\approved_userlist;
use \core_privacy\local\request\userlist;
/**
* Tests for the \core_privacy API's approved userlist functionality.
*
* @copyright 2018 Andrew Nicols <andrew@nicols.co.uk>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
* @coversDefaultClass \core_privacy\local\request\approved_userlist
*/
class approved_userlist_test extends advanced_testcase {
/**
* The approved userlist should not be modifiable once set.
*
* @covers ::__construct
* @covers \core_privacy\local\request\approved_userlist<extended>
*/
public function test_default_values_set(): void {
$this->resetAfterTest();
$u1 = $this->getDataGenerator()->create_user();
$u2 = $this->getDataGenerator()->create_user();
$u3 = $this->getDataGenerator()->create_user();
$u4 = $this->getDataGenerator()->create_user();
$context = \context_system::instance();
$component = 'core_privacy';
$uut = new approved_userlist($context, $component, [$u1->id, $u2->id]);
$this->assertEquals($context, $uut->get_context());
$this->assertEquals($component, $uut->get_component());
$expected = [
$u1->id,
$u2->id,
];
sort($expected);
$result = $uut->get_userids();
sort($result);
$this->assertEquals($expected, $result);
}
/**
* @covers ::create_from_userlist
* @covers \core_privacy\local\request\approved_userlist<extended>
*/
public function test_create_from_userlist(): void {
$this->resetAfterTest();
$u1 = $this->getDataGenerator()->create_user();
$u2 = $this->getDataGenerator()->create_user();
$u3 = $this->getDataGenerator()->create_user();
$u4 = $this->getDataGenerator()->create_user();
$context = \context_system::instance();
$component = 'core_privacy';
$sourcelist = new userlist($context, $component);
$sourcelist->add_users([$u1->id, $u3->id]);
$expected = [
$u1->id,
$u3->id,
];
sort($expected);
$approvedlist = approved_userlist::create_from_userlist($sourcelist);
$this->assertEquals($component, $approvedlist->get_component());
$this->assertEquals($context, $approvedlist->get_context());
$result = $approvedlist->get_userids();
sort($result);
$this->assertEquals($expected, $result);
}
}
+223
View File
@@ -0,0 +1,223 @@
<?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/>.
namespace core_privacy;
defined('MOODLE_INTERNAL') || die();
global $CFG;
use core_privacy\local\metadata\collection;
use core_privacy\local\metadata\types;
/**
* Tests for the \core_privacy API's collection functionality.
*
* @package core_privacy
* @category test
* @copyright 2018 Andrew Nicols <andrew@nicols.co.uk>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
* @coversDefaultClass \core_privacy\local\metadata\collection
*/
class collection_test extends \advanced_testcase {
/**
* Test that adding an unknown type causes the type to be added to the collection.
*
* @covers ::add_type
*/
public function test_add_type_generic_type(): void {
$collection = new collection('core_privacy');
// Mock a new types\type.
$mockedtype = $this->createMock(types\type::class);
$collection->add_type($mockedtype);
$items = $collection->get_collection();
$this->assertCount(1, $items);
$this->assertEquals($mockedtype, reset($items));
}
/**
* Test that adding a known type works as anticipated.
*
* @covers ::add_type
*/
public function test_add_type_known_type(): void {
$collection = new collection('core_privacy');
$linked = new types\subsystem_link('example', [], 'langstring');
$collection->add_type($linked);
$items = $collection->get_collection();
$this->assertCount(1, $items);
$this->assertEquals($linked, reset($items));
}
/**
* Test that adding multiple types returns them all.
*
* @covers ::add_type
*/
public function test_add_type_multiple(): void {
$collection = new collection('core_privacy');
$a = new types\subsystem_link('example', [], 'langstring');
$collection->add_type($a);
$b = new types\subsystem_link('example', [], 'langstring');
$collection->add_type($b);
$items = $collection->get_collection();
$this->assertCount(2, $items);
}
/**
* Test that the add_database_table function adds a database table.
*
* @covers ::add_database_table
*/
public function test_add_database_table(): void {
$collection = new collection('core_privacy');
$name = 'example';
$fields = ['field' => 'description'];
$summary = 'summarisation';
$collection->add_database_table($name, $fields, $summary);
$items = $collection->get_collection();
$this->assertCount(1, $items);
$item = reset($items);
$this->assertInstanceOf(types\database_table::class, $item);
$this->assertEquals($name, $item->get_name());
$this->assertEquals($fields, $item->get_privacy_fields());
$this->assertEquals($summary, $item->get_summary());
}
/**
* Test that the add_user_preference function adds a single user preference.
*
* @covers ::add_user_preference
*/
public function test_add_user_preference(): void {
$collection = new collection('core_privacy');
$name = 'example';
$summary = 'summarisation';
$collection->add_user_preference($name, $summary);
$items = $collection->get_collection();
$this->assertCount(1, $items);
$item = reset($items);
$this->assertInstanceOf(types\user_preference::class, $item);
$this->assertEquals($name, $item->get_name());
$this->assertEquals($summary, $item->get_summary());
}
/**
* Test that the link_external_location function links an external location.
*
* @covers ::link_external_location
*/
public function test_link_external_location(): void {
$collection = new collection('core_privacy');
$name = 'example';
$fields = ['field' => 'description'];
$summary = 'summarisation';
$collection->link_external_location($name, $fields, $summary);
$items = $collection->get_collection();
$this->assertCount(1, $items);
$item = reset($items);
$this->assertInstanceOf(types\external_location::class, $item);
$this->assertEquals($name, $item->get_name());
$this->assertEquals($fields, $item->get_privacy_fields());
$this->assertEquals($summary, $item->get_summary());
}
/**
* Test that the link_subsystem function links the subsystem.
*
* @covers ::link_subsystem
*/
public function test_link_subsystem(): void {
$collection = new collection('core_privacy');
$name = 'example';
$summary = 'summarisation';
$collection->link_subsystem($name, $summary);
$items = $collection->get_collection();
$this->assertCount(1, $items);
$item = reset($items);
$this->assertInstanceOf(types\subsystem_link::class, $item);
$this->assertEquals($name, $item->get_name());
$this->assertEquals($summary, $item->get_summary());
}
/**
* Test that the link_plugintype function links the plugin.
*
* @covers ::link_plugintype
*/
public function test_link_plugintype(): void {
$collection = new collection('core_privacy');
$name = 'example';
$summary = 'summarisation';
$collection->link_plugintype($name, $summary);
$items = $collection->get_collection();
$this->assertCount(1, $items);
$item = reset($items);
$this->assertInstanceOf(types\plugintype_link::class, $item);
$this->assertEquals($name, $item->get_name());
$this->assertEquals($summary, $item->get_summary());
}
/**
* Data provider to supply a list of valid components.
*
* @return array
*/
public function component_list_provider() {
return [
['core_privacy'],
['mod_forum'],
];
}
/**
* Test that we can get the component correctly.
*
* The component will be used for string translations.
*
* @dataProvider component_list_provider
* @param string $component The component to test
* @covers ::get_component
*/
public function test_get_component($component): void {
$collection = new collection($component);
$this->assertEquals($component, $collection->get_component());
}
}
+305
View File
@@ -0,0 +1,305 @@
<?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 the abstract contextlist Class
*
* @package core_privacy
* @category test
* @copyright 2018 Andrew Nicols <andrew@nicols.co.uk>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
defined('MOODLE_INTERNAL') || die();
global $CFG;
use \core_privacy\local\request\contextlist_base;
/**
* Tests for the \core_privacy API's contextlist base functionality.
*
* @copyright 2018 Andrew Nicols <andrew@nicols.co.uk>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
* @coversDefaultClass \core_privacy\local\request\contextlist_base
*/
class contextlist_base_test extends advanced_testcase {
/**
* Ensure that get_contextids returns the list of unique contextids.
*
* @dataProvider get_contextids_provider
* @param array $input List of context IDs
* @param array $expected list of contextids
* @param int $count Expected count
* @covers ::get_contextids
*/
public function test_get_contextids($input, $expected, $count): void {
$uit = new test_contextlist_base();
$uit->set_contextids($input);
$result = $uit->get_contextids();
$this->assertCount($count, $result);
// Note: Array order is not guaranteed and should not matter.
foreach ($expected as $contextid) {
$this->assertNotFalse(array_search($contextid, $result));
}
}
/**
* Provider for the list of contextids.
*
* @return array
*/
public function get_contextids_provider() {
return [
'basic' => [
[1, 2, 3, 4, 5],
[1, 2, 3, 4, 5],
5,
],
'duplicates' => [
[1, 1, 2, 2, 3, 4, 5],
[1, 2, 3, 4, 5],
5,
],
'Mixed order with duplicates' => [
[5, 4, 2, 5, 4, 1, 3, 4, 1, 5, 5, 5, 2, 4, 1, 2],
[1, 2, 3, 4, 5],
5,
],
];
}
/**
* Ensure that get_contexts returns the correct list of contexts.
*
* @covers ::get_contexts
*/
public function test_get_contexts(): void {
global $DB;
$contexts = [];
$contexts[] = \context_system::instance();
$contexts[] = \context_user::instance(\core_user::get_user_by_username('admin')->id);
$ids = [];
foreach ($contexts as $context) {
$ids[] = $context->id;
}
$uit = new test_contextlist_base();
$uit->set_contextids($ids);
$result = $uit->get_contexts();
$this->assertCount(count($contexts), $result);
foreach ($contexts as $context) {
$this->assertNotFalse(array_search($context, $result));
}
}
/**
* Ensure that the contextlist_base is countable.
*
* @dataProvider get_contextids_provider
* @param array $input List of context IDs
* @param array $expected list of contextids
* @param int $count Expected count
* @covers ::count
*/
public function test_countable($input, $expected, $count): void {
$uit = new test_contextlist_base();
$uit->set_contextids($input);
$this->assertCount($count, $uit);
}
/**
* Ensure that the contextlist_base iterates over the set of contexts.
*
* @covers ::current
* @covers ::key
* @covers ::next
* @covers ::rewind
* @covers ::valid
*/
public function test_context_iteration(): void {
global $DB;
$allcontexts = $DB->get_records('context');
$contexts = [];
foreach ($allcontexts as $context) {
$contexts[] = \context::instance_by_id($context->id);
}
$uit = new test_contextlist_base();
$uit->set_contextids(array_keys($allcontexts));
foreach ($uit as $key => $context) {
$this->assertNotFalse(array_search($context, $contexts));
}
}
/**
* Test that deleting a context results in current returning nothing.
*
* @covers ::current
*/
public function test_current_context_one_context(): void {
global $DB;
$this->resetAfterTest();
$data = (object) [
'contextlevel' => CONTEXT_BLOCK,
'instanceid' => 45,
'path' => '1/5/67/107',
'depth' => 4
];
$contextid = $DB->insert_record('context', $data);
$contextbase = new test_contextlist_base();
$contextbase->set_contextids([$contextid]);
$this->assertCount(1, $contextbase);
$currentcontext = $contextbase->current();
$this->assertEquals($contextid, $currentcontext->id);
$DB->delete_records('context', ['id' => $contextid]);
context_helper::reset_caches();
$this->assertEmpty($contextbase->current());
}
/**
* Test that deleting a context results in the next record being returned.
*
* @covers ::current
*/
public function test_current_context_two_contexts(): void {
global $DB;
$this->resetAfterTest();
$data = (object) [
'contextlevel' => CONTEXT_BLOCK,
'instanceid' => 45,
'path' => '1/5/67/107',
'depth' => 4
];
$contextid1 = $DB->insert_record('context', $data);
$data = (object) [
'contextlevel' => CONTEXT_BLOCK,
'instanceid' => 47,
'path' => '1/5/54/213',
'depth' => 4
];
$contextid2 = $DB->insert_record('context', $data);
$contextbase = new test_contextlist_base();
$contextbase->set_contextids([$contextid1, $contextid2]);
$this->assertCount(2, $contextbase);
$DB->delete_records('context', ['id' => $contextid1]);
context_helper::reset_caches();
// Current should return context 2.
$this->assertEquals($contextid2, $contextbase->current()->id);
}
/**
* Test that if there are no non-deleted contexts that nothing is returned.
*
* @covers ::get_contexts
*/
public function test_get_contexts_all_deleted(): void {
global $DB;
$this->resetAfterTest();
$data = (object) [
'contextlevel' => CONTEXT_BLOCK,
'instanceid' => 45,
'path' => '1/5/67/107',
'depth' => 4
];
$contextid = $DB->insert_record('context', $data);
$contextbase = new test_contextlist_base();
$contextbase->set_contextids([$contextid]);
$this->assertCount(1, $contextbase);
$DB->delete_records('context', ['id' => $contextid]);
context_helper::reset_caches();
$this->assertEmpty($contextbase->get_contexts());
}
/**
* Test that get_contexts() returns only active contexts.
*
* @covers ::get_contexts
*/
public function test_get_contexts_one_deleted(): void {
global $DB;
$this->resetAfterTest();
$data = (object) [
'contextlevel' => CONTEXT_BLOCK,
'instanceid' => 45,
'path' => '1/5/67/107',
'depth' => 4
];
$contextid1 = $DB->insert_record('context', $data);
$data = (object) [
'contextlevel' => CONTEXT_BLOCK,
'instanceid' => 47,
'path' => '1/5/54/213',
'depth' => 4
];
$contextid2 = $DB->insert_record('context', $data);
$contextbase = new test_contextlist_base();
$contextbase->set_contextids([$contextid1, $contextid2]);
$this->assertCount(2, $contextbase);
$DB->delete_records('context', ['id' => $contextid1]);
context_helper::reset_caches();
$contexts = $contextbase->get_contexts();
$this->assertCount(1, $contexts);
$context = array_shift($contexts);
$this->assertEquals($contextid2, $context->id);
}
}
/**
* A test class extending the contextlist_base allowing setting of the
* contextids.
*
* @copyright 2018 Andrew Nicols <andrew@nicols.co.uk>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class test_contextlist_base extends contextlist_base {
/**
* Set the contextids for the test class.
*
* @param int[] $contexids The list of contextids to use.
*/
public function set_contextids(array $contextids) {
parent::set_contextids($contextids);
}
}
@@ -0,0 +1,196 @@
<?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 a the collection of contextlists class
*
* @package core_privacy
* @category test
* @copyright 2018 Andrew Nicols <andrew@nicols.co.uk>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
defined('MOODLE_INTERNAL') || die();
global $CFG;
use \core_privacy\local\request\contextlist_collection;
use \core_privacy\local\request\contextlist;
use \core_privacy\local\request\approved_contextlist;
/**
* Tests for the \core_privacy API's contextlist collection functionality.
*
* @copyright 2018 Andrew Nicols <andrew@nicols.co.uk>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
* @coversDefaultClass \core_privacy\local\request\contextlist_collection
*/
class contextlist_collection_test extends advanced_testcase {
/**
* A contextlist_collection should support the contextlist type.
*
* @covers ::add_contextlist
*/
public function test_supports_contextlist(): void {
$uit = new contextlist_collection(1);
$contextlist = new contextlist();
$contextlist->set_component('core_privacy');
$uit->add_contextlist($contextlist);
$this->assertCount(1, $uit->get_contextlists());
}
/**
* A contextlist_collection should support the approved_contextlist type.
*
* @covers ::add_contextlist
*/
public function test_supports_approved_contextlist(): void {
$uit = new contextlist_collection(1);
$testuser = \core_user::get_user_by_username('admin');
$contextids = [3, 2, 1];
$uit->add_contextlist(new approved_contextlist($testuser, 'core_privacy', $contextids));
$this->assertCount(1, $uit->get_contextlists());
}
/**
* Ensure that get_contextlist_for_component returns the correct contextlist.
*
* @covers ::get_contextlist_for_component
*/
public function test_get_contextlist_for_component(): void {
$uit = new contextlist_collection(1);
$coretests = new contextlist();
$coretests->set_component('core_tests');
$uit->add_contextlist($coretests);
$coreprivacy = new contextlist();
$coreprivacy->set_component('core_privacy');
$uit->add_contextlist($coreprivacy);
// Note: This uses assertSame rather than assertEquals.
// The former checks the actual object, whilst assertEquals only checks that they look the same.
$this->assertSame($coretests, $uit->get_contextlist_for_component('core_tests'));
$this->assertSame($coreprivacy, $uit->get_contextlist_for_component('core_privacy'));
}
/**
* Ensure that get_contextlist_for_component does not die horribly when querying a non-existent component.
*
* @covers ::get_contextlist_for_component
*/
public function test_get_contextlist_for_component_not_found(): void {
$uit = new contextlist_collection(1);
$this->assertNull($uit->get_contextlist_for_component('core_tests'));
}
/**
* Ensure that a duplicate contextlist in the collection throws an Exception.
*
* @covers ::add_contextlist
*/
public function test_duplicate_addition_throws(): void {
$uit = new contextlist_collection(1);
$coretests = new contextlist();
$coretests->set_component('core_tests');
$uit->add_contextlist($coretests);
$this->expectException('moodle_exception');
$uit->add_contextlist($coretests);
}
/**
* Ensure that the contextlist_collection is countable.
*
* @covers ::count
*/
public function test_countable(): void {
$uit = new contextlist_collection(1);
$contextlist = new contextlist();
$contextlist->set_component('test_example');
$uit->add_contextlist($contextlist);
$contextlist = new contextlist();
$contextlist->set_component('test_another');
$uit->add_contextlist($contextlist);
$this->assertCount(2, $uit);
}
/**
* Ensure that the contextlist_collection iterates over the set of contextlists.
*
* @covers ::current
* @covers ::key
* @covers ::next
* @covers ::rewind
* @covers ::valid
*/
public function test_iteration(): void {
$uit = new contextlist_collection(1);
$testdata = [];
$component = 'test_example';
$contextlist = new contextlist();
$contextlist->set_component($component);
$uit->add_contextlist($contextlist);
$testdata[$component] = $contextlist;
$component = 'test_another';
$contextlist = new contextlist();
$contextlist->set_component($component);
$uit->add_contextlist($contextlist);
$testdata[$component] = $contextlist;
$component = 'test_third';
$contextlist = new contextlist();
$contextlist->set_component($component);
$uit->add_contextlist($contextlist);
$testdata[$component] = $contextlist;
foreach ($uit as $component => $list) {
$this->assertEquals($testdata[$component], $list);
}
$this->assertCount(3, $uit);
}
/**
* Test that the userid is correctly returned.
*
* @covers ::get_userid
*/
public function test_get_userid(): void {
$uit = new contextlist_collection(1);
$this->assertEquals(1, $uit->get_userid());
}
/**
* Test that an exception is thrown if a contextlist does not contain a component.
*/
public function test_add_without_component(): void {
$uit = new contextlist_collection(1);
$this->expectException(moodle_exception::class);
$uit->add_contextlist(new contextlist());
}
}
+219
View File
@@ -0,0 +1,219 @@
<?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 the approved contextlist Class
*
* @package core_privacy
* @category test
* @copyright 2018 Andrew Nicols <andrew@nicols.co.uk>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
defined('MOODLE_INTERNAL') || die();
global $CFG;
use \core_privacy\local\request\contextlist;
/**
* Tests for the \core_privacy API's approved contextlist functionality.
*
* @copyright 2018 Andrew Nicols <andrew@nicols.co.uk>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
* @coversDefaultClass \core_privacy\local\request\contextlist
*/
class contextlist_test extends advanced_testcase {
/**
* Ensure that valid SQL results in the relevant contexts being added.
*
* @covers ::add_from_sql
*/
public function test_add_from_sql(): void {
global $DB;
$sql = "SELECT c.id FROM {context} c";
$params = [];
$allcontexts = $DB->get_records_sql($sql, $params);
$uit = new contextlist();
$uit->add_from_sql($sql, $params);
$this->assertCount(count($allcontexts), $uit);
}
/**
* Ensure that valid system context id is added.
*
* @covers ::add_system_context
*/
public function test_add_system_context(): void {
$cl = new contextlist();
$cl->add_system_context();
$this->assertCount(1, $cl);
foreach ($cl->get_contexts() as $context) {
$this->assertEquals(SYSCONTEXTID, $context->id);
}
}
/**
* Ensure that a valid user context id is added.
*
* @covers ::add_user_context
*/
public function test_add_user_context(): void {
$this->resetAfterTest();
$user = $this->getDataGenerator()->create_user();
$this->getDataGenerator()->create_user();
$cl = new contextlist();
$cl->add_user_context($user->id);
$this->assertCount(1, $cl);
foreach ($cl->get_contexts() as $context) {
$this->assertEquals(\context_user::instance($user->id)->id, $context->id);
}
}
/**
* Ensure that valid user contexts are added.
*
* @covers ::add_user_contexts
*/
public function test_add_user_contexts(): void {
$this->resetAfterTest();
$user1 = $this->getDataGenerator()->create_user();
$user2 = $this->getDataGenerator()->create_user();
$this->getDataGenerator()->create_user();
$cl = new contextlist();
$cl->add_user_contexts([$user1->id, $user2->id]);
$this->assertCount(2, $cl);
$contexts = $cl->get_contextids();
$this->assertContainsEquals(\context_user::instance($user1->id)->id, $contexts);
$this->assertContainsEquals(\context_user::instance($user2->id)->id, $contexts);
}
/**
* Test {@link \core_privacy\local\request\contextlist::test_guess_id_field_from_sql()} implementation.
*
* @dataProvider data_guess_id_field_from_sql
* @param string $sql Input SQL we try to extract the context id field name from.
* @param string $expected Expected detected value.
* @covers ::guess_id_field_from_sql
*/
public function test_guess_id_field_from_sql($sql, $expected): void {
$rc = new \ReflectionClass(contextlist::class);
$rcm = $rc->getMethod('guess_id_field_from_sql');
$actual = $rcm->invoke(new contextlist(), $sql);
$this->assertEquals($expected, $actual, 'Unable to guess context id field in: '.$sql);
}
/**
* Provides data sets for {@link self::test_guess_id_field_from_sql()}.
*
* @return array
*/
public function data_guess_id_field_from_sql() {
return [
'easy' => [
'SELECT contextid FROM {foo}',
'contextid',
],
'with_distinct' => [
'SELECT DISTINCT contextid FROM {foo}',
'contextid',
],
'with_dot' => [
'SELECT cx.id FROM {foo} JOIN {context} cx ON blahblahblah',
'id',
],
'letter_case_does_not_matter' => [
'Select ctxid From {foo} Where bar = ?',
'ctxid',
],
'alias' => [
'SELECT foo.contextid AS ctx FROM {bar} JOIN {foo} ON bar.id = foo.barid',
'ctx',
],
'tabs' => [
"SELECT\tctxid\t\tFROM foo f",
'ctxid',
],
'whitespace' => [
"SELECT
ctxid\t
\tFROM foo f",
'ctxid',
],
'just_number' => [
'1',
'1',
],
'select_number' => [
'SELECT 2',
'2',
],
'select_number_with_semicolon' => [
'SELECT 3;',
'3',
],
'select_number_from_table' => [
'SELECT 4 FROM users',
'4',
],
'select_with_complex_subqueries' => [
'SELECT id FROM table WHERE id IN (
SELECT x FROM xtable
UNION
SELECT y FROM (
SELECT y FROM ytable
JOIN ztable ON (z = y)))',
'id'
],
'invalid_union_with_first_being_column_name' => [
'SELECT id FROM table UNION SELECT 1 FROM table',
''
],
'invalid_union_with_first_being_numeric' => [
'SELECT 1 FROM table UNION SELECT id FROM table',
''
],
'invalid_union_without_from' => [
'SELECT 1 UNION SELECT id FROM table',
''
],
'invalid_1' => [
'SELECT 1+1',
'',
],
'invalid_2' => [
'muhehe',
'',
],
];
}
}
BIN
View File
Binary file not shown.

After

Width:  |  Height:  |  Size: 2.4 KiB

@@ -0,0 +1,54 @@
<?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/>.
/**
* Test provider using a fake plugin name.
*
* @package core_privacy
* @copyright 2018 Jake Dallimore <jrhdallimore@gmail.com>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
namespace mod_testcomponent4\privacy;
use core_privacy\local\request\writer;
/**
* Mock core_user_data_provider for unit tests.
* @copyright 2018 Jake Dallimore <jrhdallimore@gmail.com>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class provider implements \core_privacy\local\metadata\null_provider, \core_privacy\local\request\user_preference_provider {
/**
* Get the language string identifier with the component's language
* file to explain why this plugin stores no data.
*
* @return string
*/
public static function get_reason(): string {
return 'notimplemented';
}
/**
* Export all user preferences for the plugin.
*
* @param int $userid The userid of the user whose data is to be exported.
*/
public static function export_user_preferences(int $userid) {
writer::export_user_preference('mod_testcomponent4', 'mykey', 'myvalue', 'mydescription');
}
}
+42
View File
@@ -0,0 +1,42 @@
<?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/>.
/**
* Test null provider using a fake plugin name.
*
* @package core_privacy
* @copyright 2018 Jake Dallimore <jrhdallimore@gmail.com>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
namespace mod_testcomponent2\privacy;
/**
* Mock null_provider for unit tests.
* @copyright 2018 Jake Dallimore <jrhdallimore@gmail.com>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class provider implements \core_privacy\local\metadata\null_provider {
/**
* Get the language string identifier with the component's language
* file to explain why this plugin stores no data.
*
* @return string the reason for being a null provider.
*/
public static function get_reason(): string {
return 'testcomponent2 null provider reason';
}
}
@@ -0,0 +1,46 @@
<?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/>.
/**
* Test provider using a fake plugin name.
*
* @package core_privacy
* @copyright 2018 Jake Dallimore <jrhdallimore@gmail.com>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
namespace mod_testcomponent3\privacy;
use core_privacy\local\metadata\collection;
/**
* Mock shared_data_provider for unit tests.
* @copyright 2018 Jake Dallimore <jrhdallimore@gmail.com>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class provider implements \core_privacy\local\metadata\provider, \core_privacy\local\request\plugin\subplugin_provider {
/**
* Returns meta data about this system.
*
* @param collection $collection The initialised collection to add items to.
* @return collection A listing of user data stored through this system.
*/
public static function get_metadata(collection $collection): collection {
$collection = new collection('testcomponent3');
$collection->add_database_table('testtable', ['testfield1', 'testfield2'], 'testsummary');
return $collection;
}
}
+85
View File
@@ -0,0 +1,85 @@
<?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/>.
/**
* Test provider using a fake plugin name.
*
* @package core_privacy
* @copyright 2018 Jake Dallimore <jrhdallimore@gmail.com>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
namespace mod_testcomponent\privacy;
use core_privacy\local\metadata\collection;
use core_privacy\local\request\approved_contextlist;
use core_privacy\local\request\contextlist;
/**
* Mock core_user_data_provider for unit tests.
* @copyright 2018 Jake Dallimore <jrhdallimore@gmail.com>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class provider implements \core_privacy\local\metadata\provider, \core_privacy\local\request\plugin\provider {
/**
* @return array The array of metadata.
*/
public static function get_metadata(collection $collection): collection {
$collection = new collection('testcomponent');
$collection->add_database_table('testtable', ['testfield1', 'testfield2'], 'testsummary');
return $collection;
}
/**
* Get the list of contexts that contain user information for the specified user.
*
* @param int $userid The user to search.
* @return contextlist $contextlist The contextlist containing the list of contexts used in this plugin.
*/
public static function get_contexts_for_userid(int $userid): contextlist {
$cl = new contextlist();
$cl->add_from_sql("SELECT c.id FROM {context} c WHERE c.id = :id", ['id' => \context_system::instance()->id]);
return $cl;
}
/**
* Export all user data for the specified user, in the specified contexts.
*
* @param approved_contextlist $contextlist The approved contexts to export information for.
*/
public static function export_user_data(approved_contextlist $contextlist) {
// This does nothing. We only want to confirm this can be called via the \core_privacy\manager.
}
/**
* Delete all use data which matches the specified deletion criteria.
*
* @param context $context The specific context to delete data for.
*/
public static function delete_data_for_all_users_in_context(\context $context) {
// This does nothing. We only want to confirm this can be called via the \core_privacy\manager.
}
/**
* Delete all user data for the specified user, in the specified contexts.
*
* @param approved_contextlist $contextlist The approved contexts and user information to delete information for.
*/
public static function delete_data_for_user(approved_contextlist $contextlist) {
// This does nothing. We only want to confirm this can be called via the \core_privacy\manager.
}
}
+77
View File
@@ -0,0 +1,77 @@
<?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/>.
/**
* Mock handler for site policies
*
* @package core_privacy
* @copyright 2018 Marina Glancy
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
defined('MOODLE_INTERNAL') || die();
/**
* Mock handler for site policies
*
* @package core_privacy
* @copyright 2018 Marina Glancy
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class mock_sitepolicy_handler extends \core_privacy\local\sitepolicy\handler {
/**
* Returns URL to redirect user to when user needs to agree to site policy
*
* This is a regular interactive page for web users. It should have normal Moodle header/footers, it should
* allow user to view policies and accept them.
*
* @param bool $forguests
* @return moodle_url|null (returns null if site policy is not defined)
*/
public static function get_redirect_url($forguests = false) {
return 'http://example.com/policy.php';
}
/**
* Returns URL of the site policy that needs to be displayed to the user (inside iframe or to use in WS such as mobile app)
*
* This page should not have any header/footer, it does not also have any buttons/checkboxes. The caller needs to implement
* the "Accept" button and call {@link self::accept()} on completion.
*
* @param bool $forguests
* @return moodle_url|null
*/
public static function get_embed_url($forguests = false) {
return 'http://example.com/view.htm';
}
/**
* Accept site policy for the current user
*
* @return bool - false if sitepolicy not defined, user is not logged in or user has already agreed to site policy;
* true - if we have successfully marked the user as agreed to the site policy
*/
public static function accept() {
global $USER, $DB;
// Accepts policy on behalf of the current user. We set it to 2 here to check that this callback was called.
$USER->policyagreed = 2;
if (!isguestuser()) {
$DB->update_record('user', ['policyagreed' => 2, 'id' => $USER->id]);
}
return true;
}
}
+91
View File
@@ -0,0 +1,91 @@
<?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/>.
/**
* Test provider which works.
*
* @package core_privacy
* @copyright 2018 Andrew Nicols <andrew@nicols.co.uk>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
namespace mod_component_a\privacy;
defined('MOODLE_INTERNAL') || die();
use core_privacy\local\metadata\collection;
use core_privacy\local\request\contextlist;
use core_privacy\local\request\approved_contextlist;
/**
* Mock core_user_data_provider for unit tests.
*
* @package core_privacy
* @copyright 2018 Andrew Nicols <andrew@nicols.co.uk>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class provider implements
\core_privacy\local\metadata\provider,
\core_privacy\local\request\plugin\provider {
/**
* Get metadata.
*
* @param collection $collection The initialised collection to add items to.
* @return collection A listing of user data stored through this system.
*/
public static function get_metadata(collection $collection): collection {
$collection->add_subsystem_link('core_files');
return $collection;
}
/**
* Get the list of contexts that contain user information for the specified user.
*
* @param int $userid The user to search.
* @return contextlist $contextlist The contextlist containing the list of contexts used in this plugin.
*/
public static function get_contexts_for_userid(int $userid): \core_privacy\local\request\contextlist {
$c = new \core_privacy\local\request\contextlist();
$c->add_system_context();
return $c;
}
/**
* Export all user data for the specified user, in the specified contexts.
*
* @param approved_contextlist $contextlist The approved contexts to export information for.
*/
public static function export_user_data(approved_contextlist $contextlist) {
}
/**
* Delete all data for all users in the specified context.
*
* @param context $context The specific context to delete data for.
*/
public static function delete_data_for_all_users_in_context(\context $context) {
}
/**
* Delete all user data for the specified user, in the specified contexts.
*
* @param approved_contextlist $contextlist The approved contexts and user information to delete information for.
*/
public static function delete_data_for_user(approved_contextlist $contextlist) {
}
}
+88
View File
@@ -0,0 +1,88 @@
<?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/>.
/**
* Test provider which has issues.
*
* @package core_privacy
* @copyright 2018 Andrew Nicols <andrew@nicols.co.uk>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
namespace mod_component_broken\privacy;
use core_privacy\local\metadata\collection;
use core_privacy\local\request\contextlist;
use core_privacy\local\request\approved_contextlist;
/**
* Mock core_user_data_provider for unit tests.
*
* @package core_privacy
* @copyright 2018 Andrew Nicols <andrew@nicols.co.uk>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class provider implements
\core_privacy\local\metadata\provider,
\core_privacy\local\request\plugin\provider {
/**
* Get metadata.
*
* @param collection $collection The initialised collection to add items to.
* @return collection A listing of user data stored through this system.
*/
public static function get_metadata(collection $collection): collection {
throw new \coding_exception(__FUNCTION__);
}
/**
* Get the list of contexts that contain user information for the specified user.
*
* @param int $userid The user to search.
* @return contextlist $contextlist The contextlist containing the list of contexts used in this plugin.
*/
public static function get_contexts_for_userid(int $userid): \core_privacy\local\request\contextlist {
throw new \coding_exception(__FUNCTION__);
}
/**
* Export all user data for the specified user, in the specified contexts.
*
* @param approved_contextlist $contextlist The approved contexts to export information for.
*/
public static function export_user_data(approved_contextlist $contextlist) {
throw new \coding_exception(__FUNCTION__);
}
/**
* Delete all data for all users in the specified context.
*
* @param context $context The specific context to delete data for.
*/
public static function delete_data_for_all_users_in_context(\context $context) {
throw new \coding_exception(__FUNCTION__);
}
/**
* Delete all user data for the specified user, in the specified contexts.
*
* @param approved_contextlist $contextlist The approved contexts and user information to delete information for.
*/
public static function delete_data_for_user(approved_contextlist $contextlist) {
throw new \coding_exception(__FUNCTION__);
}
}
+282
View File
@@ -0,0 +1,282 @@
<?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 the Privacy API's legacy_polyfill.
*
* @package core_privacy
* @category test
* @copyright 2018 Andrew Nicols <andrew@nicols.co.uk>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
namespace core_privacy;
use core_privacy\local\metadata\collection;
use core_privacy\local\request\contextlist;
use core_privacy\local\request\approved_contextlist;
defined('MOODLE_INTERNAL') || die();
global $CFG;
/**
* Unit tests for the Privacy API's legacy_polyfill.
*
* @package core_privacy
* @category test
* @copyright 2018 Andrew Nicols <andrew@nicols.co.uk>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
* @coversDefaultClass \core_privacy\local\legacy_polyfill
*/
class legacy_polyfill_test extends \advanced_testcase {
/**
* Test that the null_provider polyfill works and that the static _get_reason can be
* successfully called.
*
* @covers ::get_reason
*/
public function test_null_provider(): void {
$this->assertEquals('thisisareason', test_legacy_polyfill_null_provider::get_reason());
}
/**
* Test that the metdata\provider polyfill works and that the static _get_metadata can be
* successfully called.
*
* @covers ::get_metadata
*/
public function test_metadata_provider(): void {
$collection = new collection('core_privacy');
$this->assertSame($collection, test_legacy_polyfill_metadata_provider::get_metadata($collection));
}
/**
* Test that the local\request\user_preference_provider polyfill works and that the static
* _export_user_preferences can be successfully called.
*
* @covers ::export_user_preferences
*/
public function test_user_preference_provider(): void {
$userid = 417;
$mock = $this->createMock(test_legacy_polyfill_mock_wrapper::class);
$mock->expects($this->once())
->method('get_return_value')
->with('_export_user_preferences', [$userid]);
test_legacy_polyfill_user_preference_provider::$mock = $mock;
test_legacy_polyfill_user_preference_provider::export_user_preferences($userid);
}
/**
* Test that the local\request\core_user_preference_provider polyfill works and that the static
* _get_contexts_for_userid can be successfully called.
*
* @covers ::get_contexts_for_userid
*/
public function test_get_contexts_for_userid(): void {
$userid = 417;
$contextlist = new contextlist('core_privacy');
$mock = $this->createMock(test_legacy_polyfill_mock_wrapper::class);
$mock->expects($this->once())
->method('get_return_value')
->with('_get_contexts_for_userid', [$userid])
->willReturn($contextlist);
test_legacy_polyfill_request_provider::$mock = $mock;
$result = test_legacy_polyfill_request_provider::get_contexts_for_userid($userid);
$this->assertSame($contextlist, $result);
}
/**
* Test that the local\request\core_user_preference_provider polyfill works and that the static
* _export_user_data can be successfully called.
*
* @covers ::export_user_data
*/
public function test_export_user_data(): void {
$contextlist = new approved_contextlist(\core_user::get_user_by_username('admin'), 'core_privacy', [98]);
$mock = $this->createMock(test_legacy_polyfill_mock_wrapper::class);
$mock->expects($this->once())
->method('get_return_value')
->with('_export_user_data', [$contextlist]);
test_legacy_polyfill_request_provider::$mock = $mock;
test_legacy_polyfill_request_provider::export_user_data($contextlist);
}
/**
* Test that the local\request\core_user_preference_provider polyfill works and that the static
* _delete_data_for_all_users_in_context can be successfully called.
*
* @covers ::delete_data_for_all_users_in_context
*/
public function test_delete_data_for_all_users_in_context(): void {
$mock = $this->createMock(test_legacy_polyfill_mock_wrapper::class);
$mock->expects($this->once())
->method('get_return_value')
->with('_delete_data_for_all_users_in_context', [\context_system::instance()]);
test_legacy_polyfill_request_provider::$mock = $mock;
test_legacy_polyfill_request_provider::delete_data_for_all_users_in_context(\context_system::instance());
}
/**
* Test that the local\request\core_user_preference_provider polyfill works and that the static
* _delete_data_for_user can be successfully called.
*
* @covers ::delete_data_for_user
*/
public function test_delete_data_for_user(): void {
$contextlist = new approved_contextlist(\core_user::get_user_by_username('admin'), 'core_privacy', [98]);
$mock = $this->createMock(test_legacy_polyfill_mock_wrapper::class);
$mock->expects($this->once())
->method('get_return_value')
->with('_delete_data_for_user', [$contextlist]);
test_legacy_polyfill_request_provider::$mock = $mock;
test_legacy_polyfill_request_provider::delete_data_for_user($contextlist);
}
}
/**
* Legacy polyfill test for the null provider.
*
* @copyright 2018 Andrew Nicols <andrew@nicols.co.uk>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class test_legacy_polyfill_null_provider implements \core_privacy\local\metadata\null_provider {
use \core_privacy\local\legacy_polyfill;
/**
* Test for get_reason
*/
protected static function _get_reason() {
return 'thisisareason';
}
}
/**
* Legacy polyfill test for the metadata provider.
*
* @copyright 2018 Andrew Nicols <andrew@nicols.co.uk>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class test_legacy_polyfill_metadata_provider implements \core_privacy\local\metadata\provider {
use \core_privacy\local\legacy_polyfill;
/**
* Test for get_metadata.
*
* @param collection $collection The initialised collection to add items to.
* @return collection A listing of user data stored through this system.
*/
protected static function _get_metadata(collection $collection) {
return $collection;
}
}
/**
* Legacy polyfill test for the metadata provider.
*
* @copyright 2018 Andrew Nicols <andrew@nicols.co.uk>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class test_legacy_polyfill_user_preference_provider implements \core_privacy\local\request\user_preference_provider {
use \core_privacy\local\legacy_polyfill;
/**
* @var test_legacy_polyfill_request_provider $mock
*/
public static $mock = null;
/**
* Export all user preferences for the plugin.
*
* @param int $userid The userid of the user whose data is to be exported.
*/
protected static function _export_user_preferences($userid) {
return static::$mock->get_return_value(__FUNCTION__, func_get_args());
}
}
/**
* Legacy polyfill test for the request provider.
*
* @copyright 2018 Andrew Nicols <andrew@nicols.co.uk>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class test_legacy_polyfill_request_provider implements \core_privacy\local\request\core_user_data_provider {
use \core_privacy\local\legacy_polyfill;
/**
* @var test_legacy_polyfill_request_provider $mock
*/
public static $mock = null;
/**
* Test for get_contexts_for_userid.
*
* @param int $userid The user to search.
* @return contextlist $contextlist The contextlist containing the list of contexts used in this plugin.
*/
protected static function _get_contexts_for_userid($userid) {
return static::$mock->get_return_value(__FUNCTION__, func_get_args());
}
/**
* Test for export_user_data.
*
* @param approved_contextlist $contextlist The approved contexts to export information for.
*/
protected static function _export_user_data(approved_contextlist $contextlist) {
return static::$mock->get_return_value(__FUNCTION__, func_get_args());
}
/**
* Delete all use data which matches the specified deletion criteria.
*
* @param context $context The specific context to delete data for.
*/
public static function _delete_data_for_all_users_in_context(\context $context) {
return static::$mock->get_return_value(__FUNCTION__, func_get_args());
}
/**
* Delete all user data for the specified user, in the specified contexts.
*
* @param approved_contextlist $contextlist The approved contexts and user information to delete information for.
*/
public static function _delete_data_for_user(approved_contextlist $contextlist) {
return static::$mock->get_return_value(__FUNCTION__, func_get_args());
}
}
class test_legacy_polyfill_mock_wrapper {
/**
* Get the return value for the specified item.
*/
public function get_return_value() {}
}
+491
View File
@@ -0,0 +1,491 @@
<?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/>.
namespace core_privacy;
use core_privacy\local\request\writer;
use core_privacy\local\request\approved_contextlist;
defined('MOODLE_INTERNAL') || die();
global $CFG;
require_once($CFG->dirroot . '/privacy/tests/fixtures/mock_null_provider.php');
require_once($CFG->dirroot . '/privacy/tests/fixtures/mock_provider.php');
require_once($CFG->dirroot . '/privacy/tests/fixtures/mock_plugin_subplugin_provider.php');
require_once($CFG->dirroot . '/privacy/tests/fixtures/mock_mod_with_user_data_provider.php');
require_once($CFG->dirroot . '/privacy/tests/fixtures/provider_a.php');
require_once($CFG->dirroot . '/privacy/tests/fixtures/provider_throwing_exception.php');
/**
* Privacy manager unit tests.
*
* @copyright 2018 Jake Dallimore <jrhdallimore@gmail.com>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
* @coversDefaultClass \core_privacy\manager
*/
class manager_test extends \advanced_testcase {
/**
* Test tearDown.
*/
public function tearDown(): void {
\core_privacy\local\request\writer::reset();
}
/**
* Helper to spoof the results of the internal function get_components_list, allowing mock components to be tested.
*
* @param array $componentnames and array of component names to include as valid core components.
* @return PHPUnit_Framework_MockObject_MockObject
*/
protected function get_mock_manager_with_core_components($componentnames) {
$mock = $this->getMockBuilder(\core_privacy\manager::class)
->onlyMethods(['get_component_list'])
->getMock();
$mock->expects($this->any())
->method('get_component_list')
->will($this->returnValue($componentnames));
return $mock;
}
/**
* Test collection of metadata for components implementing a metadata provider.
*
* @covers ::get_metadata_for_components
*/
public function test_get_metadata_for_components(): void {
// Get a mock manager, in which the core components list is mocked to include all mock plugins.
// testcomponent is a core provider, testcomponent2 is a null provider, testcomponent3 is subplugin provider (non core).
$mockman = $this->get_mock_manager_with_core_components(['mod_testcomponent', 'mod_testcomponent2', 'mod_testcomponent3']);
// Core providers and shared providers both implement the metadata provider.
$collectionarray = $mockman->get_metadata_for_components();
$this->assertArrayHasKey('mod_testcomponent', $collectionarray);
$collection = $collectionarray['mod_testcomponent'];
$this->assertInstanceOf(\core_privacy\local\metadata\collection::class, $collection);
$this->assertArrayHasKey('mod_testcomponent3', $collectionarray);
$collection = $collectionarray['mod_testcomponent3'];
$this->assertInstanceOf(\core_privacy\local\metadata\collection::class, $collection);
// Component which implements just the local\metadata\null_provider. Metadata is not provided.
$this->assertArrayNotHasKey('mod_testcomponent2', $collectionarray);
}
/**
* Test that get_contexts_for_userid() only returns contextlist collections for core providers.
*
* @covers ::get_contexts_for_userid
*/
public function test_get_contexts_for_userid(): void {
// Get a mock manager, in which the core components list is mocked to include all mock plugins.
// testcomponent is a core provider, testcomponent2 is a null provider, testcomponent3 is subplugin provider (non core).
$mockman = $this->get_mock_manager_with_core_components(['mod_testcomponent', 'mod_testcomponent2', 'mod_testcomponent3']);
// Get the contextlist_collection.
$contextlistcollection = $mockman->get_contexts_for_userid(10);
$this->assertInstanceOf(\core_privacy\local\request\contextlist_collection::class, $contextlistcollection);
ob_flush();
// Verify we have a contextlist for the component in the collection.
$this->assertInstanceOf(\core_privacy\local\request\contextlist::class,
$contextlistcollection->get_contextlist_for_component('mod_testcomponent'));
// Verify we don't have a contextlist for the shared provider in the collection.
$this->assertNull($contextlistcollection->get_contextlist_for_component('mod_testcomponent3'));
// Verify we don't have a contextlist for the component which does not store user data.
$this->assertEmpty($contextlistcollection->get_contextlist_for_component('mod_testcomponent2'));
}
/**
* Test verifying the output of component_is_compliant.
*
* @covers ::component_is_compliant
*/
public function test_component_is_compliant(): void {
// Get a mock manager, in which the core components list is mocked to include all mock plugins.
// testcomponent is a core provider, testcomponent2 is a null provider, testcomponent3 is subplugin provider (non core).
$mockman = $this->get_mock_manager_with_core_components(['mod_testcomponent', 'mod_testcomponent2', 'mod_testcomponent3']);
// A core_provider plugin implementing all required interfaces (local\metadata\provider, local\request\plugin_provider).
$this->assertTrue($mockman->component_is_compliant('mod_testcomponent'));
// A component implementing just the \core_privacy\local\metadata\null_provider is compliant.
$this->assertTrue($mockman->component_is_compliant('mod_testcomponent2'));
// A shared provider plugin implementing all required interfaces (local\metadata\provider, local\request\plugin\subplugin_provider)
// is compliant.
$this->assertTrue($mockman->component_is_compliant('mod_testcomponent3'));
// A component implementing none of the providers.
$this->assertFalse($mockman->component_is_compliant('tool_thisisnotarealtool123'));
}
/**
* Provider for component_is_compliant tests.
*
* @return array
*/
public function component_is_compliant_provider() {
return [
'An empty subsystem' => [
'core_countries',
true,
],
'A real subsystem' => [
'core_privacy',
true,
],
];
}
/**
* Test verifying the output of component_is_compliant with specified
* components.
*
* @dataProvider component_is_compliant_provider
* @param string $component
* @param boolean $expected
* @covers ::component_is_compliant
*/
public function test_component_is_compliant_examples($component, $expected): void {
$manager = new \core_privacy\manager();
$this->assertEquals($expected, $manager->component_is_compliant($component));
}
/**
* Test verifying only approved contextlists can be used with the export_user_data method.
*
* @covers ::export_user_data
*/
public function test_export_user_data(): void {
// Get a mock manager, in which the core components list is mocked to include all mock plugins.
// testcomponent is a core provider, testcomponent2 is a null provider, testcomponent3 is subplugin provider (non core).
$mockman = $this->get_mock_manager_with_core_components(['mod_testcomponent', 'mod_testcomponent2', 'mod_testcomponent3', 'mod_testcomponent4']);
// Get the non-approved contextlists.
$contextlistcollection = $mockman->get_contexts_for_userid(10);
// Create an approved contextlist.
$approvedcontextlistcollection = new \core_privacy\local\request\contextlist_collection(10);
foreach ($contextlistcollection->get_contextlists() as $contextlist) {
$approvedcontextlist = new approved_contextlist(new \stdClass(), $contextlist->get_component(),
$contextlist->get_contextids());
$approvedcontextlistcollection->add_contextlist($approvedcontextlist);
}
// Verify the mocked return from the writer, meaning the manager method exited normally.
$this->assertEquals('mock_path', $mockman->export_user_data($approvedcontextlistcollection));
// Verify that a user preference was exported for 'mod_testcomponent4'.
$prefs = writer::with_context(\context_system::instance())->get_user_preferences('mod_testcomponent4');
$this->assertNotEmpty($prefs);
$this->assertNotEmpty($prefs->mykey);
$this->assertEquals('myvalue', $prefs->mykey->value);
$this->assertEquals('mydescription', $prefs->mykey->description);
// Verify an exception is thrown if trying to pass in a collection of non-approved_contextlist items.
$this->expectException(\moodle_exception::class);
$mockman->export_user_data($contextlistcollection);
}
/**
* Test verifying only approved contextlists can be used with the delete_data_for_user method.
*
* @covers ::delete_data_for_user
*/
public function test_delete_data_for_user(): void {
$this->resetAfterTest();
// Get a mock manager, in which the core components list is mocked to include all mock plugins.
// testcomponent is a core provider, testcomponent2 is a null provider, testcomponent3 is subplugin provider (non core).
$mockman = $this->get_mock_manager_with_core_components(['mod_testcomponent', 'mod_testcomponent2', 'mod_testcomponent3']);
// Get the non-approved contextlists.
$user = \core_user::get_user_by_username('admin');
$contextlistcollection = $mockman->get_contexts_for_userid($user->id);
// Create an approved contextlist.
$approvedcontextlistcollection = new \core_privacy\local\request\contextlist_collection($user->id);
foreach ($contextlistcollection->get_contextlists() as $contextlist) {
$approvedcontextlist = new approved_contextlist($user, $contextlist->get_component(),
$contextlist->get_contextids());
$approvedcontextlistcollection->add_contextlist($approvedcontextlist);
}
// Verify null, as the method has no return type and exits normally. Mainly checking we don't see any exception.
$this->assertNull($mockman->delete_data_for_user($approvedcontextlistcollection));
// Verify an exception is thrown if trying to pass in a collection of non-approved_contextlist items.
$this->expectException(\moodle_exception::class);
$mockman->delete_data_for_user($contextlistcollection);
}
/**
* Ensure that all installed plugins can provide metadata.
*
* This really just checks that all providers can be safely autoloaded.
*
* @covers ::get_metadata_for_components
*/
public function test_installed_plugins(): void {
$manager = new \core_privacy\manager();
$metadata = $manager->get_metadata_for_components();
$this->assertNotEmpty($metadata);
}
/**
* Test that the reason for the null provider is returned.
*
* @covers ::get_null_provider_reason
*/
public function test_get_null_provider_reason(): void {
$manager = new \core_privacy\manager();
// Null providers return the reason string.
$this->assertEquals('testcomponent2 null provider reason', $manager->get_null_provider_reason('mod_testcomponent2'));
// Throw an exception if the wrong type of provider is given.
$this->expectException(\coding_exception::class);
$string = $manager->get_null_provider_reason('mod_testcomponent');
}
/**
* Test that manager::plugintype_class_callback() can be executed.
*
* @covers ::plugintype_class_callback
*/
public function test_plugintype_class_callback(): void {
\core_privacy\manager::plugintype_class_callback('doesnotexist', 'unusable', 'foo', ['bar']);
}
/**
* Test that manager::component_class_callback() can be executed.
*
* @covers ::component_class_callback
*/
public function test_component_class_callback(): void {
\core_privacy\manager::component_class_callback('foo_bar', 'unusable', 'foo', ['bar']);
}
/**
* Test the manager::is_empty_subsystem function.
*
* @dataProvider is_empty_subsystem_provider
* @param string $component
* @param bool $expected
* @covers ::is_empty_subsystem
*/
public function test_is_empty_subsystem($component, $expected): void {
$this->assertEquals($expected, \core_privacy\manager::is_empty_subsystem($component));
}
/**
* Test cases for the is_empty_subsystem function.
*
* @return array
*/
public function is_empty_subsystem_provider() {
return [
'A subsystem which has no directory' => [
'core_langconfig',
true,
],
'A subsystem with a directory' => [
'core_portfolio',
false,
],
'A plugin' => [
'mod_forum',
false,
],
'A plugintype' => [
'mod',
false,
],
'An unprefixed subsystem with no directory' => [
'langconfig',
false,
],
];
}
/**
* Test that get_contexts_for_userid() with a failing item.
*
* @covers ::get_contexts_for_userid
*/
public function test_get_contexts_for_userid_with_failing(): void {
// Get a mock manager, in which the core components list is mocked to include all mock plugins.
// testcomponent is a core provider, testcomponent2 isa null provider, testcomponent3 is subplugin provider (non core).
$mockman = $this->get_mock_manager_with_core_components(['mod_component_broken', 'mod_component_a']);
$observer = $this->getMockBuilder(\core_privacy\manager_observer::class)
->onlyMethods(['handle_component_failure'])
->getMock();
$mockman->set_observer($observer);
$observer->expects($this->once())
->method('handle_component_failure')
->with(
$this->isInstanceOf(\coding_exception::class),
$this->identicalTo('mod_component_broken'),
$this->identicalTo(\core_privacy\local\request\core_user_data_provider::class),
$this->identicalTo('get_contexts_for_userid'),
$this->anything()
);
// Get the contextlist_collection.
$contextlistcollection = $mockman->get_contexts_for_userid(10);
$this->assertDebuggingCalled();
$this->assertInstanceOf(\core_privacy\local\request\contextlist_collection::class, $contextlistcollection);
$this->assertCount(1, $contextlistcollection);
// The component which completed shoudl have returned a contextlist.
$this->assertInstanceOf(\core_privacy\local\request\contextlist::class,
$contextlistcollection->get_contextlist_for_component('mod_component_a'));
$this->assertEmpty($contextlistcollection->get_contextlist_for_component('mod_component_broken'));
}
/**
* Test that export_user_data() with a failing item.
*
* @covers ::export_user_data
*/
public function test_export_user_data_with_failing(): void {
$user = \core_user::get_user_by_username('admin');
$mockman = $this->get_mock_manager_with_core_components(['mod_component_broken', 'mod_component_a']);
$context = \context_system::instance();
$contextid = $context->id;
$observer = $this->getMockBuilder(\core_privacy\manager_observer::class)
->onlyMethods(['handle_component_failure'])
->getMock();
$mockman->set_observer($observer);
$observer->expects($this->once())
->method('handle_component_failure')
->with(
$this->isInstanceOf(\coding_exception::class),
$this->identicalTo('mod_component_broken'),
$this->identicalTo(\core_privacy\local\request\core_user_data_provider::class),
$this->identicalTo('export_user_data'),
$this->anything()
);
$collection = new \core_privacy\local\request\contextlist_collection(10);
$collection->add_contextlist(new approved_contextlist($user, 'mod_component_broken', [$contextid]));
$collection->add_contextlist(new approved_contextlist($user, 'mod_component_a', [$contextid]));
// Get the contextlist_collection.
$mockman->export_user_data($collection);
$this->assertDebuggingCalled();
}
/**
* Test that delete_data_for_user() with a failing item.
*
* @covers ::delete_data_for_user
*/
public function test_delete_data_for_user_with_failing(): void {
$user = \core_user::get_user_by_username('admin');
$mockman = $this->get_mock_manager_with_core_components(['mod_component_broken', 'mod_component_a']);
$context = \context_system::instance();
$contextid = $context->id;
$observer = $this->getMockBuilder(\core_privacy\manager_observer::class)
->onlyMethods(['handle_component_failure'])
->getMock();
$mockman->set_observer($observer);
$observer->expects($this->once())
->method('handle_component_failure')
->with(
$this->isInstanceOf(\coding_exception::class),
$this->identicalTo('mod_component_broken'),
$this->identicalTo(\core_privacy\local\request\core_user_data_provider::class),
$this->identicalTo('delete_data_for_user'),
$this->anything()
);
$collection = new \core_privacy\local\request\contextlist_collection(10);
$collection->add_contextlist(new approved_contextlist($user, 'mod_component_broken', [$contextid]));
$collection->add_contextlist(new approved_contextlist($user, 'mod_component_a', [$contextid]));
// Get the contextlist_collection.
$mockman->delete_data_for_user($collection);
$this->assertDebuggingCalled();
}
/**
* Test that delete_data_for_all_users_in_context() with a failing item.
*
* @covers ::delete_data_for_all_users_in_context
*/
public function test_delete_data_for_all_users_in_context_with_failing(): void {
$user = \core_user::get_user_by_username('admin');
$mockman = $this->get_mock_manager_with_core_components(['mod_component_broken', 'mod_component_a']);
$context = \context_system::instance();
$observer = $this->getMockBuilder(\core_privacy\manager_observer::class)
->onlyMethods(['handle_component_failure'])
->getMock();
$mockman->set_observer($observer);
$observer->expects($this->once())
->method('handle_component_failure')
->with(
$this->isInstanceOf(\coding_exception::class),
$this->identicalTo('mod_component_broken'),
$this->identicalTo(\core_privacy\local\request\core_user_data_provider::class),
$this->identicalTo('delete_data_for_all_users_in_context'),
$this->anything()
);
// Get the contextlist_collection.
$mockman->delete_data_for_all_users_in_context($context);
$this->assertDebuggingCalled();
}
/**
* Test that get_metadata_for_components() with a failing item.
*
* @covers ::get_metadata_for_components
*/
public function test_get_metadata_for_components_with_failing(): void {
$user = \core_user::get_user_by_username('admin');
$mockman = $this->get_mock_manager_with_core_components(['mod_component_broken', 'mod_component_a']);
$context = \context_system::instance();
$observer = $this->getMockBuilder(\core_privacy\manager_observer::class)
->onlyMethods(['handle_component_failure'])
->getMock();
$mockman->set_observer($observer);
$observer->expects($this->once())
->method('handle_component_failure')
->with(
$this->isInstanceOf(\coding_exception::class),
$this->identicalTo('mod_component_broken'),
$this->identicalTo(\core_privacy\local\metadata\provider::class),
$this->identicalTo('get_metadata'),
$this->anything()
);
// Get the contextlist_collection.
$metadata = $mockman->get_metadata_for_components();
$this->assertDebuggingCalled();
$this->assertIsArray($metadata);
$this->assertCount(1, $metadata);
}
}
File diff suppressed because it is too large Load Diff
+332
View File
@@ -0,0 +1,332 @@
<?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 all Privacy Providers.
*
* @package core_privacy
* @copyright 2018 Andrew Nicols <andrew@nicols.co.uk>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
namespace core_privacy\privacy;
defined('MOODLE_INTERNAL') || die();
use core_privacy\manager;
use core_privacy\local\metadata\collection;
use core_privacy\local\metadata\types\type;
use core_privacy\local\metadata\types\database_table;
use core_privacy\local\metadata\types\external_location;
use core_privacy\local\metadata\types\plugin_type_link;
use core_privacy\local\metadata\types\subsystem_link;
use core_privacy\local\metadata\types\user_preference;
/**
* Unit tests for all Privacy Providers.
*
* @copyright 2018 Andrew Nicols <andrew@nicols.co.uk>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class provider_test extends \advanced_testcase {
/**
* Returns a list of frankenstyle names of core components (plugins and subsystems).
*
* @return array the array of frankenstyle component names with the relevant class name.
*/
public function get_component_list() {
$components = ['core' => [
'component' => 'core',
'classname' => manager::get_provider_classname_for_component('core')
]];
// Get all plugins.
$plugintypes = \core_component::get_plugin_types();
foreach ($plugintypes as $plugintype => $typedir) {
$plugins = \core_component::get_plugin_list($plugintype);
foreach ($plugins as $pluginname => $plugindir) {
$frankenstyle = $plugintype . '_' . $pluginname;
$components[$frankenstyle] = [
'component' => $frankenstyle,
'classname' => manager::get_provider_classname_for_component($frankenstyle),
];
}
}
// Get all subsystems.
foreach (\core_component::get_core_subsystems() as $name => $path) {
if (isset($path)) {
$frankenstyle = 'core_' . $name;
$components[$frankenstyle] = [
'component' => $frankenstyle,
'classname' => manager::get_provider_classname_for_component($frankenstyle),
];
}
}
return $components;
}
/**
* Test that the specified null_provider works as expected.
*
* @dataProvider null_provider_provider
* @param string $component The name of the component.
* @param string $classname The name of the class for privacy
*/
public function test_null_provider($component, $classname): void {
$reason = $classname::get_reason();
$this->assertIsString($reason);
$this->assertIsString(get_string($reason, $component));
$this->assertDebuggingNotCalled();
}
/**
* Data provider for the null_provider tests.
*
* @return array
*/
public function null_provider_provider() {
return array_filter($this->get_component_list(), function($component) {
return static::component_implements(
$component['classname'],
\core_privacy\local\metadata\null_provider::class
);
});
}
/**
* Test that the specified metadata_provider works as expected.
*
* @dataProvider metadata_provider_provider
* @param string $component The name of the component.
* @param string $classname The name of the class for privacy
*/
public function test_metadata_provider($component, $classname): void {
global $DB;
$collection = new collection($component);
$metadata = $classname::get_metadata($collection);
$this->assertInstanceOf(collection::class, $metadata);
$this->assertSame($collection, $metadata);
$this->assertContainsOnlyInstancesOf(type::class, $metadata->get_collection());
foreach ($metadata->get_collection() as $item) {
// All items must have a valid string name.
// Note: This is not a string identifier.
$this->assertIsString($item->get_name());
if ($item instanceof database_table) {
// Check that the table is valid.
$this->assertTrue($DB->get_manager()->table_exists($item->get_name()));
}
if ($item instanceof \core_privacy\local\metadata\types\plugintype_link) {
// Check that plugin type is valid.
$this->assertTrue(array_key_exists($item->get_name(), \core_component::get_plugin_types()));
}
if ($item instanceof subsystem_link) {
// Check that core subsystem exists.
list($plugintype, $pluginname) = \core_component::normalize_component($item->get_name());
$this->assertEquals('core', $plugintype);
$this->assertTrue(\core_component::is_core_subsystem($pluginname));
}
if ($summary = $item->get_summary()) {
// Summary is optional, but when provided must be a valid string identifier.
$this->assertIsString($summary);
// Check that the string is also correctly defined.
$this->assertIsString(get_string($summary, $component));
$this->assertDebuggingNotCalled();
}
if ($fields = $item->get_privacy_fields()) {
// Privacy fields are optional, but when provided must be a valid string identifier.
foreach ($fields as $field => $identifier) {
$this->assertIsString($field);
$this->assertIsString($identifier);
// Check that the string is also correctly defined.
$this->assertIsString(get_string($identifier, $component));
$this->assertDebuggingNotCalled();
}
}
}
}
/**
* Test that all providers implement some form of compliant provider.
*
* @dataProvider get_component_list
* @param string $component frankenstyle component name, e.g. 'mod_assign'
* @param string $classname the fully qualified provider classname
*/
public function test_all_providers_compliant($component, $classname): void {
$manager = new manager();
$this->assertTrue($manager->component_is_compliant($component));
}
/**
* Ensure that providers do not throw an error when processing a deleted user.
*
* @dataProvider is_user_data_provider
* @param string $component
*/
public function test_component_understands_deleted_users($component): void {
$this->resetAfterTest();
// Create a user.
$user = $this->getDataGenerator()->create_user();
// Delete the user and their context.
delete_user($user);
$usercontext = \context_user::instance($user->id);
$usercontext->delete();
$contextlist = manager::component_class_callback($component, \core_privacy\local\request\core_user_data_provider::class,
'get_contexts_for_userid', [$user->id]);
$this->assertInstanceOf(\core_privacy\local\request\contextlist::class, $contextlist);
}
/**
* Ensure that providers do not throw an error when processing a deleted user.
*
* @dataProvider is_user_data_provider
* @param string $component
*/
public function test_userdata_provider_implements_userlist($component): void {
$classname = manager::get_provider_classname_for_component($component);
$this->assertTrue(is_subclass_of($classname, \core_privacy\local\request\core_userlist_provider::class));
}
/**
* Data provider for the metadata\provider tests.
*
* @return array
*/
public function metadata_provider_provider() {
return array_filter($this->get_component_list(), function($component) {
return static::component_implements(
$component['classname'],
\core_privacy\local\metadata\provider::class
);
});
}
/**
* List of providers which implement the core_user_data_provider.
*
* @return array
*/
public function is_user_data_provider() {
return array_filter($this->get_component_list(), function($component) {
return static::component_implements(
$component['classname'],
\core_privacy\local\request\core_user_data_provider::class
);
});
}
/**
* Checks whether the component's provider class implements the specified interface, either directly or as a grandchild.
*
* @param string $providerclass The name of the class to test.
* @param string $interface the name of the interface we want to check.
* @return bool Whether the class implements the interface.
*/
protected static function component_implements($providerclass, $interface) {
if (class_exists($providerclass) && interface_exists($interface)) {
return is_subclass_of($providerclass, $interface);
}
return false;
}
/**
* Finds user fields in a table
*
* Returns fields that have foreign key to user table and fields that are named 'userid'.
*
* @param \xmldb_table $table
* @return array
*/
protected function get_userid_fields(\xmldb_table $table) {
$userfields = [];
// Find all fields that have a foreign key to 'id' field in 'user' table.
$keys = $table->getKeys();
foreach ($keys as $key) {
$reffields = $key->getRefFields();
$fields = $key->getFields();
if ($key->getRefTable() === 'user' && count($reffields) == 1 && $reffields[0] == 'id' && count($fields) == 1) {
$userfields[$fields[0]] = $fields[0];
}
}
// Find fields with the name 'userid' even if they don't have a foreign key.
$fields = $table->getFields();
foreach ($fields as $field) {
if ($field->getName() == 'userid') {
$userfields['userid'] = 'userid';
}
}
return $userfields;
}
/**
* Test that all tables with user fields are covered by metadata providers
*/
public function test_table_coverage(): void {
global $DB;
$dbman = $DB->get_manager();
$tables = [];
foreach ($dbman->get_install_xml_files() as $filename) {
$xmldbfile = new \xmldb_file($filename);
if (!$xmldbfile->loadXMLStructure()) {
continue;
}
$structure = $xmldbfile->getStructure();
$tablelist = $structure->getTables();
foreach ($tablelist as $table) {
if ($fields = $this->get_userid_fields($table)) {
$tables[$table->getName()] = ' - ' . $table->getName() . ' (' . join(', ', $fields) . ')';
}
}
}
$componentlist = $this->metadata_provider_provider();
foreach ($componentlist as $componentarray) {
$component = $componentarray['component'];
$classname = $componentarray['classname'];
$collection = new collection($component);
$metadata = $classname::get_metadata($collection);
foreach ($metadata->get_collection() as $item) {
if ($item instanceof database_table) {
unset($tables[$item->get_name()]);
}
}
}
if ($tables) {
$this->fail("The following tables with user fields must be covered with metadata providers: \n".
join("\n", $tables));
}
}
}
+219
View File
@@ -0,0 +1,219 @@
<?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 the request helper.
*
* @package core_privacy
* @category test
* @copyright 2018 Andrew Nicols <andrew@nicols.co.uk>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
defined('MOODLE_INTERNAL') || die();
global $CFG;
use \core_privacy\local\request\helper;
use \core_privacy\local\request\writer;
/**
* Tests for the \core_privacy API's request helper functionality.
*
* @copyright 2018 Andrew Nicols <andrew@nicols.co.uk>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
* @coversDefaultClass \core_privacy\local\request\helper
*/
class request_helper_test extends advanced_testcase {
/**
* Test that basic module data is returned.
*
* @covers ::get_context_data
*/
public function test_get_context_data_context_module(): void {
$this->resetAfterTest();
// Setup.
$course = $this->getDataGenerator()->create_course();
$user = \core_user::get_user_by_username('admin');
$forum = $this->getDataGenerator()->create_module('forum', [
'course' => $course->id,
]);
$context = context_module::instance($forum->cmid);
$modinfo = get_fast_modinfo($course->id);
$cm = $modinfo->cms[$context->instanceid];
// Fetch the data.
$result = helper::get_context_data($context, $user);
$this->assertInstanceOf('stdClass', $result);
// Check that the name matches.
$this->assertEquals($cm->get_formatted_name(), $result->name);
// This plugin supports the intro. Check that it is included and correct.
$formattedintro = format_text($forum->intro, $forum->introformat, [
'noclean' => true,
'para' => false,
'context' => $context,
'overflowdiv' => true,
]);
$this->assertEquals($formattedintro, $result->intro);
// This function should only fetch data. It does not export it.
$this->assertFalse(writer::with_context($context)->has_any_data());
}
/**
* Test that basic block data is returned.
*
* @covers ::get_context_data
*/
public function test_get_context_data_context_block(): void {
$this->resetAfterTest();
// Setup.
$block = $this->getDataGenerator()->create_block('online_users');
$context = context_block::instance($block->id);
$user = \core_user::get_user_by_username('admin');
// Fetch the data.
$data = helper::get_context_data($context, $user);
$this->assertEquals(get_string('pluginname', 'block_online_users'), $data->blocktype);
// This function should only fetch data. It does not export it.
$this->assertFalse(writer::with_context($context)->has_any_data());
}
/**
* Test that a course moudle with completion tracking enabled has the completion data returned.
*
* @covers ::get_context_data
*/
public function test_get_context_data_context_module_completion(): void {
$this->resetAfterTest();
// Create a module and set completion.
$course = $this->getDataGenerator()->create_course(['enablecompletion' => 1]);
$user = $this->getDataGenerator()->create_user();
$this->getDataGenerator()->enrol_user($user->id, $course->id, 'student');
$assign = $this->getDataGenerator()->create_module('assign', ['course' => $course->id, 'completion' => 1]);
$context = context_module::instance($assign->cmid);
$cm = get_coursemodule_from_id('assign', $assign->cmid);
// Fetch context data.
$contextdata = helper::get_context_data($context, $user);
// Completion state is zero.
// Check non completion for a user.
$this->assertEquals(0, $contextdata->completion->state);
// Complete the activity as a user.
$completioninfo = new completion_info($course);
$completioninfo->update_state($cm, COMPLETION_COMPLETE, $user->id);
// Check that completion is now exported.
$contextdata = helper::get_context_data($context, $user);
$this->assertEquals(1, $contextdata->completion->state);
// This function should only fetch data. It does not export it.
$this->assertFalse(writer::with_context($context)->has_any_data());
}
/**
* Test that when there are no files to export for a course module context, nothing is exported.
*
* @covers ::export_context_files
*/
public function test_export_context_files_context_module_no_files(): void {
$this->resetAfterTest();
// Setup.
$course = $this->getDataGenerator()->create_course();
$user = \core_user::get_user_by_username('admin');
$forum = $this->getDataGenerator()->create_module('forum', [
'course' => $course->id,
]);
$context = context_module::instance($forum->cmid);
$modinfo = get_fast_modinfo($course->id);
$cm = $modinfo->cms[$context->instanceid];
// Fetch the data.
helper::export_context_files($context, $user);
// This function should only fetch data. It does not export it.
$this->assertFalse(writer::with_context($context)->has_any_data());
}
/**
* Test that when there are no files to export for a course context, nothing is exported.
*
* @covers ::export_context_files
*/
public function test_export_context_files_context_course_no_files(): void {
$this->resetAfterTest();
// Setup.
$course = $this->getDataGenerator()->create_course();
$user = \core_user::get_user_by_username('admin');
$context = context_course::instance($course->id);
// Fetch the data.
helper::export_context_files($context, $user);
// This function should only fetch data. It does not export it.
$this->assertFalse(writer::with_context($context)->has_any_data());
}
/**
* Test that when there are files to export for a course context, the files are exported.
*
* @covers ::export_context_files
*/
public function test_export_context_files_context_course_intro_files(): void {
$this->resetAfterTest();
// Setup.
$course = $this->getDataGenerator()->create_course();
$user = \core_user::get_user_by_username('admin');
$assign = $this->getDataGenerator()->create_module('assign', ['course' => $course->id]);
$context = context_module::instance($assign->cmid);
// File details.
$filerecord = array(
'contextid' => $context->id,
'component' => 'mod_assign',
'filearea' => 'intro',
'itemid' => 0,
'filepath' => '/',
'filename' => 'logo.png',
);
$content = file_get_contents(__DIR__ . '/fixtures/logo.png');
// Store the file.
$fs = get_file_storage();
$file = $fs->create_file_from_string($filerecord, $content);
// Fetch the data.
helper::export_context_files($context, $user);
// This should have resulted in the file being exported.
$this->assertTrue(writer::with_context($context)->has_any_data());
}
}
+141
View File
@@ -0,0 +1,141 @@
<?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 the request transform helper.
*
* @package core_privacy
* @category test
* @copyright 2018 Andrew Nicols <andrew@nicols.co.uk>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
defined('MOODLE_INTERNAL') || die();
global $CFG;
use \core_privacy\local\request\transform;
/**
* Tests for the \core_privacy API's request transform helper functionality.
*
* @copyright 2018 Andrew Nicols <andrew@nicols.co.uk>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
* @coversDefaultClass \core_privacy\local\request\transform
*/
class request_transform_test extends advanced_testcase {
/**
* Test that user translation currently does nothing.
*
* We have not determined if we will do this or not, but we provide the functionality and encourgae people to use
* it so that it can be retrospectively fitted if required.
*
* @covers ::user
*/
public function test_user(): void {
// Note: This test currently sucks, but there's no point creating users just to test this.
for ($i = 0; $i < 10; $i++) {
$this->assertEquals($i, transform::user($i));
}
}
/**
* Test that the datetime is translated into a string.
*
* @covers ::datetime
*/
public function test_datetime(): void {
$time = 1;
$datestr = transform::datetime($time);
// Assert it is a string.
$this->assertIsString($datestr);
// To prevent failures on MAC where we are returned with a lower-case 'am' we want to convert this to 'AM'.
$datestr = str_replace('am', 'AM', $datestr);
// Assert the formatted date is correct.
$dateobj = new DateTime();
$dateobj->setTimestamp($time);
$this->assertEquals($dateobj->format('l, j F Y, g:i A'), $datestr);
}
/**
* Test that the date is translated into a string.
*
* @covers ::date
*/
public function test_date(): void {
$time = 1;
$datestr = transform::date($time);
// Assert it is a string.
$this->assertIsString($datestr);
// Assert the formatted date is correct.
$dateobj = new DateTime();
$dateobj->setTimestamp($time);
$this->assertEquals($dateobj->format('j F Y'), $datestr);
}
/**
* Ensure that the yesno function translates correctly.
*
* @dataProvider yesno_provider
* @param mixed $input The input to test
* @param string $expected The expected value
* @covers ::yesno
*/
public function test_yesno($input, $expected): void {
$this->assertEquals($expected, transform::yesno($input));
}
/**
* Data provider for tests of the yesno transformation.
*
* @return array
*/
public function yesno_provider() {
return [
'Bool False' => [
false,
get_string('no'),
],
'Bool true' => [
true,
get_string('yes'),
],
'Int 0' => [
0,
get_string('no'),
],
'Int 1' => [
1,
get_string('yes'),
],
'String 0' => [
'0',
get_string('no'),
],
'String 1' => [
'1',
get_string('yes'),
],
];
}
}
+384
View File
@@ -0,0 +1,384 @@
<?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 sitepolicy manager
*
* @package core_privacy
* @category test
* @copyright 2018 Marina Glancy
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
defined('MOODLE_INTERNAL') || die();
global $CFG;
/**
* Unit Tests for sitepolicy manager
*
* @package core_privacy
* @category test
* @copyright 2018 Marina Glancy
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class sitepolicy_test extends advanced_testcase {
/**
* Tests for \core_privacy\local\sitepolicy\manager::get_handler_classname() behaviour.
*/
public function test_get_handler_classname(): void {
global $CFG;
$this->resetAfterTest(true);
$manager = $this->get_mock_manager_with_handler();
// If no handler is specified, then we should get the default one.
$CFG->sitepolicyhandler = '';
$this->assertEquals($manager->get_handler_classname(), \core_privacy\local\sitepolicy\default_handler::class);
// If non-existing handler is specified, we should get the default one too.
$CFG->sitepolicyhandler = 'non_existing_plugin_which_i_really_hope_will_never_exist';
$this->assertEquals($manager->get_handler_classname(), \core_privacy\local\sitepolicy\default_handler::class);
// If the defined handler is among known handlers, we should get its class name.
$CFG->sitepolicyhandler = 'testtool_testhandler';
$this->assertEquals($manager->get_handler_classname(), 'mock_sitepolicy_handler');
}
/**
* Tests for \core_privacy\local\sitepolicy\manager::is_defined()
*/
public function test_is_defined(): void {
global $CFG;
$this->resetAfterTest(true);
$manager = new \core_privacy\local\sitepolicy\manager();
$this->assertFalse($manager->is_defined(true));
$this->assertFalse($manager->is_defined(false));
$CFG->sitepolicy = 'http://example.com/sitepolicy.html';
$this->assertFalse($manager->is_defined(true));
$this->assertTrue($manager->is_defined(false));
$CFG->sitepolicyguest = 'http://example.com/sitepolicyguest.html';
$this->assertTrue($manager->is_defined(true));
$this->assertTrue($manager->is_defined(false));
$CFG->sitepolicy = null;
$this->assertTrue($manager->is_defined(true));
$this->assertFalse($manager->is_defined(false));
// When non existing plugin is set as $CFG->sitepolicyhandler, assume that $CFG->sitepolicy* are all not set.
$CFG->sitepolicy = 'http://example.com/sitepolicy.html';
$CFG->sitepolicyguest = 'http://example.com/sitepolicyguest.html';
$CFG->sitepolicyhandler = 'non_existing_plugin_which_i_really_hope_will_never_exist';
$this->assertFalse($manager->is_defined(true));
$this->assertFalse($manager->is_defined(false));
}
/**
* Tests for \core_privacy\local\sitepolicy\manager::get_redirect_url()
*/
public function test_get_redirect_url(): void {
global $CFG;
$this->resetAfterTest(true);
$manager = new \core_privacy\local\sitepolicy\manager();
$this->assertEquals(null, $manager->get_redirect_url(true));
$this->assertEquals(null, $manager->get_redirect_url(false));
$CFG->sitepolicy = 'http://example.com/sitepolicy.html';
$this->assertEquals(null, $manager->get_redirect_url(true));
$this->assertEquals($CFG->wwwroot.'/user/policy.php', $manager->get_redirect_url(false)->out(false));
$CFG->sitepolicyguest = 'http://example.com/sitepolicyguest.html';
$this->assertEquals($CFG->wwwroot.'/user/policy.php', $manager->get_redirect_url(true)->out(false));
$this->assertEquals($CFG->wwwroot.'/user/policy.php', $manager->get_redirect_url(false)->out(false));
$CFG->sitepolicy = null;
$this->assertEquals($CFG->wwwroot.'/user/policy.php', $manager->get_redirect_url(true)->out(false));
$this->assertEquals(null, $manager->get_redirect_url(false));
// When non existing plugin is set as $CFG->sitepolicyhandler, assume that $CFG->sitepolicy* are all not set.
$CFG->sitepolicy = 'http://example.com/sitepolicy.html';
$CFG->sitepolicyguest = 'http://example.com/sitepolicyguest.html';
$CFG->sitepolicyhandler = 'non_existing_plugin_which_i_really_hope_will_never_exist';
$this->assertEquals(null, $manager->get_redirect_url(true));
$this->assertEquals(null, $manager->get_redirect_url(false));
}
/**
* Tests for \core_privacy\local\sitepolicy\manager::get_redirect_url()
*/
public function test_get_embed_url(): void {
global $CFG;
$this->resetAfterTest(true);
$manager = new \core_privacy\local\sitepolicy\manager();
$this->assertEquals(null, $manager->get_embed_url(true));
$this->assertEquals(null, $manager->get_embed_url(false));
$CFG->sitepolicy = 'http://example.com/sitepolicy.html';
$this->assertEquals(null, $manager->get_embed_url(true));
$this->assertEquals($CFG->sitepolicy, $manager->get_embed_url(false)->out(false));
$CFG->sitepolicyguest = 'http://example.com/sitepolicyguest.html';
$this->assertEquals($CFG->sitepolicyguest, $manager->get_embed_url(true)->out(false));
$this->assertEquals($CFG->sitepolicy, $manager->get_embed_url(false)->out(false));
$CFG->sitepolicy = null;
$this->assertEquals($CFG->sitepolicyguest, $manager->get_embed_url(true)->out(false));
$this->assertEquals(null, $manager->get_embed_url(false));
// When non existing plugin is set as $CFG->sitepolicyhandler, assume that $CFG->sitepolicy* are all not set.
$CFG->sitepolicy = 'http://example.com/sitepolicy.html';
$CFG->sitepolicyguest = 'http://example.com/sitepolicyguest.html';
$CFG->sitepolicyhandler = 'non_existing_plugin_which_i_really_hope_will_never_exist';
$this->assertEquals(null, $manager->get_embed_url(true));
$this->assertEquals(null, $manager->get_embed_url(false));
}
/**
* Tests for \core_privacy\local\sitepolicy\manager::get_redirect_url()
*/
public function test_accept(): void {
global $CFG, $USER, $DB;
$this->resetAfterTest(true);
$manager = new \core_privacy\local\sitepolicy\manager();
// No site policy.
$user1 = $this->getDataGenerator()->create_user();
$this->setUser($user1);
$this->assertFalse($manager->accept());
$this->assertEquals(0, $USER->policyagreed);
// With site policy.
$CFG->sitepolicy = 'http://example.com/sitepolicy.html';
$user2 = $this->getDataGenerator()->create_user();
$this->setUser($user2);
$this->assertEquals(0, $USER->policyagreed);
$this->assertEquals(0, $DB->get_field('user', 'policyagreed', ['id' => $USER->id]));
$this->assertTrue($manager->accept());
$this->assertEquals(1, $USER->policyagreed);
$this->assertEquals(1, $DB->get_field('user', 'policyagreed', ['id' => $USER->id]));
// When non existing plugin is set as $CFG->sitepolicyhandler, assume that $CFG->sitepolicy* are all not set.
$CFG->sitepolicy = 'http://example.com/sitepolicy.html';
$CFG->sitepolicyhandler = 'non_existing_plugin_which_i_really_hope_will_never_exist';
$user3 = $this->getDataGenerator()->create_user();
$this->setUser($user3);
$this->assertEquals(0, $USER->policyagreed);
$this->assertFalse($manager->accept());
$this->assertEquals(0, $USER->policyagreed);
}
/**
* Tests for \core_privacy\local\sitepolicy\manager::get_redirect_url() for guests
*/
public function test_accept_guests(): void {
global $CFG, $USER, $DB;
$this->resetAfterTest(true);
$manager = new \core_privacy\local\sitepolicy\manager();
$this->setGuestUser();
// No site policy.
$this->assertFalse($manager->accept());
$this->assertEquals(0, $USER->policyagreed);
// With site policy.
$CFG->sitepolicyguest = 'http://example.com/sitepolicy.html';
$this->assertEquals(0, $USER->policyagreed);
$this->assertTrue($manager->accept());
$this->assertEquals(1, $USER->policyagreed);
$this->assertEquals(0, $DB->get_field('user', 'policyagreed', ['id' => $USER->id]));
// When non existing plugin is set as $CFG->sitepolicyhandler, assume that $CFG->sitepolicy* are all not set.
$USER->policyagreed = 0; // Reset.
$CFG->sitepolicyguest = 'http://example.com/sitepolicyguest.html';
$CFG->sitepolicyhandler = 'non_existing_plugin_which_i_really_hope_will_never_exist';
$this->assertFalse($manager->accept());
$this->assertEquals(0, $USER->policyagreed);
}
/**
* Helper to spoof the results of the internal function get_all_handlers, allowing mock handler to be tested.
*
* @return PHPUnit_Framework_MockObject_MockObject
*/
protected function get_mock_manager_with_handler() {
global $CFG;
require_once($CFG->dirroot.'/privacy/tests/fixtures/mock_sitepolicy_handler.php');
$mock = $this->getMockBuilder(\core_privacy\local\sitepolicy\manager::class)
->onlyMethods(['get_all_handlers'])
->getMock();
$mock->expects($this->any())
->method('get_all_handlers')
->will($this->returnValue(['testtool_testhandler' => 'mock_sitepolicy_handler']));
return $mock;
}
/**
* Tests for \core_privacy\local\sitepolicy\manager::is_defined() with a handler
*/
public function test_is_defined_with_handler(): void {
global $CFG;
$this->resetAfterTest(true);
$CFG->sitepolicyhandler = 'testtool_testhandler';
$manager = $this->get_mock_manager_with_handler();
$this->assertTrue($manager->is_defined(true));
$this->assertTrue($manager->is_defined(false));
}
/**
* Tests for \core_privacy\local\sitepolicy\manager::get_redirect_url() with a handler
*/
public function test_get_redirect_url_with_handler(): void {
global $CFG;
$this->resetAfterTest(true);
$CFG->sitepolicyhandler = 'testtool_testhandler';
$manager = $this->get_mock_manager_with_handler();
$this->assertEquals('http://example.com/policy.php', $manager->get_redirect_url(true)->out(false));
$this->assertEquals('http://example.com/policy.php', $manager->get_redirect_url(false)->out(false));
}
/**
* Tests for \core_privacy\local\sitepolicy\manager::get_redirect_url() with a handler
*/
public function test_get_embed_url_with_handler(): void {
global $CFG;
$this->resetAfterTest(true);
$CFG->sitepolicyhandler = 'testtool_testhandler';
$manager = $this->get_mock_manager_with_handler();
$this->assertEquals('http://example.com/view.htm', $manager->get_embed_url(true)->out(false));
$this->assertEquals('http://example.com/view.htm', $manager->get_embed_url(false)->out(false));
}
/**
* Tests for \core_privacy\local\sitepolicy\manager::get_redirect_url() with a handler
*/
public function test_accept_with_handler(): void {
global $CFG, $USER, $DB;
$this->resetAfterTest(true);
$CFG->sitepolicyhandler = 'testtool_testhandler';
$manager = $this->get_mock_manager_with_handler();
$user2 = $this->getDataGenerator()->create_user();
$this->setUser($user2);
$this->assertEquals(0, $USER->policyagreed);
$this->assertEquals(0, $DB->get_field('user', 'policyagreed', ['id' => $USER->id]));
$this->assertTrue($manager->accept());
$this->assertEquals(2, $USER->policyagreed);
$this->assertEquals(2, $DB->get_field('user', 'policyagreed', ['id' => $USER->id]));
}
/**
* Tests for \core_privacy\local\sitepolicy\manager::get_redirect_url() for guests with a handler
*/
public function test_accept_guests_with_handler(): void {
global $CFG, $USER, $DB;
$this->resetAfterTest(true);
$CFG->sitepolicyhandler = 'testtool_testhandler';
$manager = $this->get_mock_manager_with_handler();
$this->setGuestUser();
$this->assertEquals(0, $USER->policyagreed);
$this->assertTrue($manager->accept());
$this->assertEquals(2, $USER->policyagreed);
$this->assertEquals(0, $DB->get_field('user', 'policyagreed', ['id' => $USER->id]));
}
}
/**
* Mock handler for site policies
*
* @package core_privacy
* @copyright 2018 Marina Glancy
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class handler extends \core_privacy\local\sitepolicy\handler {
/**
* Checks if the site has site policy defined
*
* @param bool $forguests
* @return bool
*/
public static function is_defined($forguests = false) {
return true;
}
/**
* Returns URL to redirect user to when user needs to agree to site policy
*
* This is a regular interactive page for web users. It should have normal Moodle header/footers, it should
* allow user to view policies and accept them.
*
* @param bool $forguests
* @return moodle_url|null (returns null if site policy is not defined)
*/
public static function get_redirect_url($forguests = false) {
return 'http://example.com/policy.php';
}
/**
* Returns URL of the site policy that needs to be displayed to the user (inside iframe or to use in WS such as mobile app)
*
* This page should not have any header/footer, it does not also have any buttons/checkboxes. The caller needs to implement
* the "Accept" button and call {@link self::accept()} on completion.
*
* @param bool $forguests
* @return moodle_url|null
*/
public static function get_embed_url($forguests = false) {
return 'http://example.com/view.htm';
}
/**
* Accept site policy for the current user
*
* @return bool - false if sitepolicy not defined, user is not logged in or user has already agreed to site policy;
* true - if we have successfully marked the user as agreed to the site policy
*/
public static function accept() {
global $USER, $DB;
// Accepts policy on behalf of the current user. We set it to 2 here to check that this callback was called.
$USER->policyagreed = 2;
if (!isguestuser()) {
$DB->update_record('user', ['policyagreed' => 2, 'id' => $USER->id]);
}
return true;
}
}
+540
View File
@@ -0,0 +1,540 @@
<?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 the Content Writer used for unit testing.
*
* @package core_privacy
* @category test
* @copyright 2018 Andrew Nicols <andrew@nicols.co.uk>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
defined('MOODLE_INTERNAL') || die();
global $CFG;
use \core_privacy\local\request\writer;
use \core_privacy\tests\request\content_writer;
/**
* Unit Tests for the Content Writer used for unit testing.
*
* @copyright 2018 Andrew Nicols <andrew@nicols.co.uk>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class tests_content_writer_test extends advanced_testcase {
/**
* It should be possible to store and retrieve data.
*/
public function test_export_data(): void {
$context = \context_system::instance();
$writer = $this->get_writer_instance();
$dataa = (object) [
'example' => 'a',
];
$datab = (object) [
'example' => 'b',
];
$writer->set_context($context)
->export_data(['data'], $dataa)
->export_data([], $datab);
$data = $writer->get_data([]);
$this->assertSame($datab, $data);
$data = $writer->get_data(['data']);
$this->assertSame($dataa, $data);
}
/**
* It should be possible to store and retrieve data at the same point in different contexts.
*/
public function test_export_data_no_context_clash(): void {
$writer = $this->get_writer_instance();
$context = \context_system::instance();
$dataa = (object) [
'example' => 'a',
];
$writer->set_context($context)
->export_data(['data'], $dataa);
$adminuser = \core_user::get_user_by_username('admin');
$usercontext = \context_user::instance($adminuser->id);
$datab = (object) [
'example' => 'b',
];
$writer->set_context($usercontext)
->export_data(['data'], $datab);
$writer->set_context($context);
$data = $writer->get_data(['data']);
$this->assertSame($dataa, $data);
$this->assertTrue($writer->has_any_data());
$this->assertTrue($writer->has_any_data(['data']));
$this->assertFalse($writer->has_any_data(['somepath']));
$writer->set_context($usercontext);
$data = $writer->get_data(['data']);
$this->assertSame($datab, $data);
}
/**
* Test export and recover with children.
*/
public function test_get_data_with_children(): void {
$writer = $this->get_writer_instance();
$context = \context_system::instance();
$writer->set_context($context)
->export_data(['a'], (object) ['parent' => true])
->export_data(['a', 'b'], (object) ['parent' => false]);
$this->assertTrue($writer->get_data(['a'])->parent);
$this->assertFalse($writer->get_data(['a', 'b'])->parent);
$this->assertEquals([], $writer->get_data(['a', 'b', 'c']));
}
/**
* It should be possible to store and retrieve metadata.
*/
public function test_export_metadata(): void {
$context = \context_system::instance();
$writer = $this->get_writer_instance();
$writer->set_context($context)
->export_metadata(['metadata'], 'somekey', 'value1', 'description1')
->export_metadata([], 'somekey', 'value2', 'description2');
$allmetadata = $writer->get_all_metadata([]);
$this->assertCount(1, $allmetadata);
$this->assertArrayHasKey('somekey', $allmetadata);
$this->assertEquals('value2', $allmetadata['somekey']->value);
$this->assertEquals('description2', $allmetadata['somekey']->description);
$metadata = $writer->get_metadata([], 'somekey', false);
$this->assertEquals('value2', $metadata->value);
$this->assertEquals('description2', $metadata->description);
$this->assertEquals('value2', $writer->get_metadata([], 'somekey', true));
$allmetadata = $writer->get_all_metadata(['metadata']);
$this->assertCount(1, $allmetadata);
$this->assertArrayHasKey('somekey', $allmetadata);
$this->assertEquals('value1', $allmetadata['somekey']->value);
$this->assertEquals('description1', $allmetadata['somekey']->description);
$metadata = $writer->get_metadata(['metadata'], 'somekey', false);
$this->assertEquals('value1', $metadata->value);
$this->assertEquals('description1', $metadata->description);
$this->assertEquals('value1', $writer->get_metadata(['metadata'], 'somekey', true));
}
/**
* It should be possible to store and retrieve metadata at the same point in different contexts.
*/
public function test_export_metadata_no_context_clash(): void {
$writer = $this->get_writer_instance();
$context = \context_system::instance();
$writer->set_context($context)
->export_metadata(['metadata'], 'somekey', 'value1', 'description1');
$adminuser = \core_user::get_user_by_username('admin');
$usercontext = \context_user::instance($adminuser->id);
$writer->set_context($usercontext)
->export_metadata(['metadata'], 'somekey', 'value2', 'description2');
$writer->set_context($context);
$allmetadata = $writer->get_all_metadata(['metadata']);
$this->assertCount(1, $allmetadata);
$this->assertArrayHasKey('somekey', $allmetadata);
$this->assertEquals('value1', $allmetadata['somekey']->value);
$this->assertEquals('description1', $allmetadata['somekey']->description);
$metadata = $writer->get_metadata(['metadata'], 'somekey', false);
$this->assertEquals('value1', $metadata->value);
$this->assertEquals('description1', $metadata->description);
$this->assertEquals('value1', $writer->get_metadata(['metadata'], 'somekey', true));
$writer->set_context($usercontext);
$allmetadata = $writer->get_all_metadata(['metadata']);
$this->assertCount(1, $allmetadata);
$this->assertArrayHasKey('somekey', $allmetadata);
$this->assertEquals('value2', $allmetadata['somekey']->value);
$this->assertEquals('description2', $allmetadata['somekey']->description);
$metadata = $writer->get_metadata(['metadata'], 'somekey', false);
$this->assertEquals('value2', $metadata->value);
$this->assertEquals('description2', $metadata->description);
$this->assertEquals('value2', $writer->get_metadata(['metadata'], 'somekey', true));
$this->assertTrue($writer->has_any_data());
$this->assertTrue($writer->has_any_data(['metadata']));
$this->assertFalse($writer->has_any_data(['somepath']));
}
/**
* It should be possible to store and retrieve user preferences.
*/
public function test_export_user_preference(): void {
$context = \context_system::instance();
$adminuser = \core_user::get_user_by_username('admin');
$usercontext = \context_user::instance($adminuser->id);
$writer = $this->get_writer_instance();
$writer->set_context($context)
->export_user_preference('core_privacy', 'somekey', 'value0', 'description0');
$writer->set_context($usercontext)
->export_user_preference('core_tests', 'somekey', 'value1', 'description1')
->export_user_preference('core_privacy', 'somekey', 'value2', 'description2')
->export_user_preference('core_tests', 'someotherkey', 'value2', 'description2');
$writer->set_context($usercontext);
$someprefs = $writer->get_user_preferences('core_privacy');
$this->assertCount(1, (array) $someprefs);
$this->assertTrue(isset($someprefs->somekey));
$this->assertEquals('value0', $someprefs->somekey->value);
$this->assertEquals('description0', $someprefs->somekey->description);
$someprefs = $writer->get_user_context_preferences('core_tests');
$this->assertCount(2, (array) $someprefs);
$this->assertTrue(isset($someprefs->somekey));
$this->assertEquals('value1', $someprefs->somekey->value);
$this->assertEquals('description1', $someprefs->somekey->description);
$this->assertTrue(isset($someprefs->someotherkey));
$this->assertEquals('value2', $someprefs->someotherkey->value);
$this->assertEquals('description2', $someprefs->someotherkey->description);
$someprefs = $writer->get_user_context_preferences('core_privacy');
$this->assertCount(1, (array) $someprefs);
$this->assertTrue(isset($someprefs->somekey));
$this->assertEquals('value2', $someprefs->somekey->value);
$this->assertEquals('description2', $someprefs->somekey->description);
}
/**
* It should be possible to store and retrieve user preferences at the same point in different contexts.
*/
public function test_export_user_preference_no_context_clash(): void {
$writer = $this->get_writer_instance();
$context = \context_system::instance();
$coursecontext = \context_course::instance(SITEID);
$adminuser = \core_user::get_user_by_username('admin');
$usercontext = \context_user::instance($adminuser->id);
$writer->set_context($context)
->export_user_preference('core_tests', 'somekey', 'value0', 'description0');
$writer->set_context($coursecontext)
->export_user_preference('core_tests', 'somekey', 'value1', 'description1');
$writer->set_context($usercontext)
->export_user_preference('core_tests', 'somekey', 'value2', 'description2');
// Set the course context and fetch with get_user_preferences to get the global preference.
$writer->set_context($coursecontext);
$someprefs = $writer->get_user_preferences('core_tests');
$this->assertCount(1, (array) $someprefs);
$this->assertTrue(isset($someprefs->somekey));
$this->assertEquals('value0', $someprefs->somekey->value);
$this->assertEquals('description0', $someprefs->somekey->description);
// Set the course context and fetch with get_user_context_preferences.
$someprefs = $writer->get_user_context_preferences('core_tests');
$this->assertCount(1, (array) $someprefs);
$this->assertTrue(isset($someprefs->somekey));
$this->assertEquals('value1', $someprefs->somekey->value);
$this->assertEquals('description1', $someprefs->somekey->description);
$writer->set_context($usercontext);
$someprefs = $writer->get_user_context_preferences('core_tests');
$this->assertCount(1, (array) $someprefs);
$this->assertTrue(isset($someprefs->somekey));
$this->assertEquals('value2', $someprefs->somekey->value);
$this->assertEquals('description2', $someprefs->somekey->description);
}
/**
* Test export and recover with children.
*/
public function test_get_metadata_with_children(): void {
$writer = $this->get_writer_instance();
$context = \context_system::instance();
$writer->set_context($context)
->export_metadata(['a'], 'abc', 'ABC', 'A, B, C')
->export_metadata(['a', 'b'], 'def', 'DEF', 'D, E, F');
$this->assertEquals('ABC', $writer->get_metadata(['a'], 'abc'));
$this->assertEquals('DEF', $writer->get_metadata(['a', 'b'], 'def'));
}
/**
* It should be possible to export files in the files and children contexts.
*/
public function test_export_file_special_folders(): void {
$context = \context_system::instance();
$filea = $this->get_stored_file('/', 'files');
$fileb = $this->get_stored_file('/children/', 'foo.zip');
$writer = $this->get_writer_instance()
->set_context($context)
->export_file([], $filea)
->export_file([], $fileb);
$files = $writer->get_files([]);
$this->assertCount(2, $files);
$this->assertEquals($filea, $files['files']);
$this->assertEquals($fileb, $files['children/foo.zip']);
}
/**
* It should be possible to export mutliple files in the same subcontext/path space but different context and not
* have them clash.
*/
public function test_export_file_no_context_clash(): void {
$writer = $this->get_writer_instance();
$context = \context_system::instance();
$filea = $this->get_stored_file('/foo/', 'foo.txt');
$writer = $this->get_writer_instance()
->set_context($context)
->export_file([], $filea);
$adminuser = \core_user::get_user_by_username('admin');
$usercontext = \context_user::instance($adminuser->id);
$fileb = $this->get_stored_file('/foo/', 'foo.txt');
$writer->set_context($usercontext)
->export_file([], $fileb);
$writer->set_context($context);
$files = $writer->get_files([]);
$this->assertCount(1, $files);
$this->assertEquals($filea, $files['foo/foo.txt']);
$writer->set_context($usercontext);
$files = $writer->get_files([]);
$this->assertCount(1, $files);
$this->assertEquals($fileb, $files['foo/foo.txt']);
$this->assertTrue($writer->has_any_data());
$this->assertFalse($writer->has_any_data(['somepath']));
}
/**
* Test export and recover with children.
*/
public function test_get_file_with_children(): void {
$writer = $this->get_writer_instance();
$context = \context_system::instance();
$filea = $this->get_stored_file('/foo/', 'foo.txt');
$fileb = $this->get_stored_file('/foo/', 'foo.txt');
$writer->set_context($context)
->export_file(['a'], $filea)
->export_file(['a', 'b'], $fileb);
$files = $writer->get_files(['a']);
$this->assertCount(1, $files);
$this->assertEquals($filea, $files['foo/foo.txt']);
$files = $writer->get_files(['a', 'b']);
$this->assertCount(1, $files);
$this->assertEquals($fileb, $files['foo/foo.txt']);
}
/**
* It should be possible to export related data in the files and children contexts.
*/
public function test_export_related_data(): void {
$context = \context_system::instance();
$writer = $this->get_writer_instance()
->set_context($context)
->export_related_data(['file', 'data'], 'file', 'data1')
->export_related_data([], 'file', 'data2');
$data = $writer->get_related_data([]);
$this->assertCount(1, $data);
$this->assertEquals('data2', $data['file']);
$data = $writer->get_related_data([], 'file');
$this->assertEquals('data2', $data);
$data = $writer->get_related_data(['file', 'data']);
$this->assertCount(1, $data);
$this->assertEquals('data1', $data['file']);
$data = $writer->get_related_data(['file', 'data'], 'file');
$this->assertEquals('data1', $data);
$this->assertTrue($writer->has_any_data());
$this->assertTrue($writer->has_any_data(['file']));
$this->assertTrue($writer->has_any_data(['file', 'data']));
$this->assertFalse($writer->has_any_data(['somepath']));
}
/**
* It should be possible to export related data in the same location,but in a different context.
*/
public function test_export_related_data_no_context_clash(): void {
$writer = $this->get_writer_instance();
$context = \context_system::instance();
$writer->set_context($context)
->export_related_data(['file', 'data'], 'file', 'data1');
$adminuser = \core_user::get_user_by_username('admin');
$usercontext = \context_user::instance($adminuser->id);
$writer->set_context($usercontext)
->export_related_data(['file', 'data'], 'file', 'data2');
$writer->set_context($context);
$data = $writer->get_related_data(['file', 'data']);
$this->assertCount(1, $data);
$this->assertEquals('data1', $data['file']);
$writer->set_context($usercontext);
$data = $writer->get_related_data(['file', 'data']);
$this->assertCount(1, $data);
$this->assertEquals('data2', $data['file']);
}
/**
* Test export and recover with children.
*/
public function test_get_related_data_with_children(): void {
$writer = $this->get_writer_instance();
$context = \context_system::instance();
$writer->set_context($context)
->export_related_data(['a'], 'abc', 'ABC')
->export_related_data(['a', 'b'], 'def', 'DEF');
$this->assertEquals('ABC', $writer->get_related_data(['a'], 'abc'));
$this->assertEquals('DEF', $writer->get_related_data(['a', 'b'], 'def'));
}
/**
* It should be possible to export related files in the files and children contexts.
*/
public function test_export_custom_file(): void {
$context = \context_system::instance();
$writer = $this->get_writer_instance()
->set_context($context)
->export_custom_file(['file.txt'], 'file.txt', 'Content 1')
->export_custom_file([], 'file.txt', 'Content 2');
$files = $writer->get_custom_file([]);
$this->assertCount(1, $files);
$this->assertEquals('Content 2', $files['file.txt']);
$file = $writer->get_custom_file([], 'file.txt');
$this->assertEquals('Content 2', $file);
$files = $writer->get_custom_file(['file.txt']);
$this->assertCount(1, $files);
$this->assertEquals('Content 1', $files['file.txt']);
$file = $writer->get_custom_file(['file.txt'], 'file.txt');
$this->assertEquals('Content 1', $file);
$this->assertTrue($writer->has_any_data());
$this->assertTrue($writer->has_any_data(['file.txt']));
$this->assertFalse($writer->has_any_data(['somepath']));
}
/**
* It should be possible to export related files in the same location
* in different contexts.
*/
public function test_export_custom_file_no_context_clash(): void {
$writer = $this->get_writer_instance();
$context = \context_system::instance();
$writer->set_context($context)
->export_custom_file(['file.txt'], 'file.txt', 'Content 1');
$adminuser = \core_user::get_user_by_username('admin');
$usercontext = \context_user::instance($adminuser->id);
$writer->set_context($usercontext)
->export_custom_file(['file.txt'], 'file.txt', 'Content 2');
$writer->set_context($context);
$files = $writer->get_custom_file(['file.txt']);
$this->assertCount(1, $files);
$this->assertEquals('Content 1', $files['file.txt']);
$writer->set_context($usercontext);
$files = $writer->get_custom_file(['file.txt']);
$this->assertCount(1, $files);
$this->assertEquals('Content 2', $files['file.txt']);
}
/**
* Test export and recover with children.
*/
public function test_get_custom_file_with_children(): void {
$writer = $this->get_writer_instance();
$context = \context_system::instance();
$writer->set_context($context)
->export_custom_file(['a'], 'file.txt', 'ABC')
->export_custom_file(['a', 'b'], 'file.txt', 'DEF');
$this->assertEquals('ABC', $writer->get_custom_file(['a'], 'file.txt'));
$this->assertEquals('DEF', $writer->get_custom_file(['a', 'b'], 'file.txt'));
}
/**
* Get a fresh content writer.
*
* @return moodle_content_writer
*/
public function get_writer_instance() {
$factory = $this->createMock(writer::class);
return new content_writer($factory);
}
/**
* Helper to create a stored file objectw with the given supplied content.
*
* @param string $filepath The file path to use in the stored_file
* @param string $filename The file name to use in the stored_file
* @return stored_file
*/
protected function get_stored_file($filepath, $filename) {
static $counter = 0;
$counter++;
$filecontent = "Example content {$counter}";
$contenthash = file_storage::hash_from_string($filecontent);
$file = $this->getMockBuilder(stored_file::class)
->onlyMethods([])
->setConstructorArgs([
get_file_storage(),
(object) [
'contenthash' => $contenthash,
'filesize' => strlen($filecontent),
'filepath' => $filepath,
'filename' => $filename,
]
])
->getMock();
return $file;
}
}
+143
View File
@@ -0,0 +1,143 @@
<?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/>.
namespace core_privacy;
use core_privacy\local\metadata\types\database_table;
defined('MOODLE_INTERNAL') || die();
global $CFG;
/**
* Tests for the \core_privacy API's types\database_table functionality.
*
* @package core_privacy
* @category test
* @copyright 2018 Andrew Nicols <andrew@nicols.co.uk>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
* @coversDefaultClass \core_privacy\local\metadata\types\database_table
*/
class types_database_table_test extends \advanced_testcase {
/**
* Ensure that warnings are thrown if string identifiers contain invalid characters.
*
* @dataProvider invalid_string_provider
* @param string $name Name
* @param array $fields List of fields
* @param string $summary Summary
* @covers ::__construct
*/
public function test_invalid_configs($name, $fields, $summary): void {
$record = new database_table($name, $fields, $summary);
$this->assertDebuggingCalled();
}
/**
* Ensure that warnings are not thrown if debugging is not enabled, even if string identifiers contain invalid characters.
*
* @dataProvider invalid_string_provider
* @param string $name Name
* @param array $fields List of fields
* @param string $summary Summary
* @covers ::__construct
*/
public function test_invalid_configs_debug_normal($name, $fields, $summary): void {
global $CFG;
$this->resetAfterTest();
$CFG->debug = DEBUG_NORMAL;
$record = new database_table($name, $fields, $summary);
$this->assertDebuggingNotCalled();
}
/**
* Ensure that no warnings are shown for valid combinations.
*
* @dataProvider valid_string_provider
* @param string $name Name
* @param array $fields List of fields
* @param string $summary Summary
* @covers ::__construct
*/
public function test_valid_configs($name, $fields, $summary): void {
$record = new database_table($name, $fields, $summary);
$this->assertDebuggingNotCalled();
}
/**
* Data provider with a list of invalid string identifiers.
*
* @return array
*/
public function invalid_string_provider() {
return [
'Space in summary' => [
'example',
[
'field' => 'privacy:valid',
],
'This table is used for purposes.',
],
'Comma in summary' => [
'example',
[
'field' => 'privacy:valid',
],
'privacy,foo',
],
'Space in field name' => [
'example',
[
'field' => 'This field is used for purposes.',
],
'privacy:valid',
],
'Comma in field name' => [
'example',
[
'field' => 'invalid,name',
],
'privacy:valid',
],
'No fields specified' => [
'example',
[],
'privacy:example:valid',
],
];
}
/**
* Data provider with a list of valid string identifiers.
*
* @return array
*/
public function valid_string_provider() {
return [
'Valid combination' => [
'example',
[
'field' => 'privacy:example:valid:field',
'field2' => 'privacy:example:valid:field2',
],
'privacy:example:valid',
],
];
}
}
@@ -0,0 +1,143 @@
<?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/>.
namespace core_privacy;
defined('MOODLE_INTERNAL') || die();
global $CFG;
use core_privacy\local\metadata\types\external_location;
/**
* Tests for the \core_privacy API's types\external_location functionality.
*
* @package core_privacy
* @category test
* @copyright 2018 Andrew Nicols <andrew@nicols.co.uk>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
* @coversDefaultClass \core_privacy\local\metadata\types\external_location
*/
class types_external_location_test extends \advanced_testcase {
/**
* Ensure that warnings are thrown if string identifiers contain invalid characters.
*
* @dataProvider invalid_string_provider
* @param string $name Name
* @param array $fields List of fields
* @param string $summary Summary
* @covers ::__construct
*/
public function test_invalid_configs($name, $fields, $summary): void {
$record = new external_location($name, $fields, $summary);
$this->assertDebuggingCalled();
}
/**
* Ensure that warnings are not thrown if debugging is not enabled, even if string identifiers contain invalid characters.
*
* @dataProvider invalid_string_provider
* @param string $name Name
* @param array $fields List of fields
* @param string $summary Summary
* @covers ::__construct
*/
public function test_invalid_configs_debug_normal($name, $fields, $summary): void {
global $CFG;
$this->resetAfterTest();
$CFG->debug = DEBUG_NORMAL;
$record = new external_location($name, $fields, $summary);
$this->assertDebuggingNotCalled();
}
/**
* Ensure that no warnings are shown for valid combinations.
*
* @dataProvider valid_string_provider
* @param string $name Name
* @param array $fields List of fields
* @param string $summary Summary
* @covers ::__construct
*/
public function test_valid_configs($name, $fields, $summary): void {
$record = new external_location($name, $fields, $summary);
$this->assertDebuggingNotCalled();
}
/**
* Data provider with a list of invalid string identifiers.
*
* @return array
*/
public function invalid_string_provider() {
return [
'Space in summary' => [
'example',
[
'field' => 'privacy:valid',
],
'This table is used for purposes.',
],
'Comma in summary' => [
'example',
[
'field' => 'privacy:valid',
],
'privacy,foo',
],
'Space in field name' => [
'example',
[
'field' => 'This field is used for purposes.',
],
'privacy:valid',
],
'Comma in field name' => [
'example',
[
'field' => 'invalid,name',
],
'privacy:valid',
],
'No fields specified' => [
'example',
[],
'privacy:example:valid',
],
];
}
/**
* Data provider with a list of valid string identifiers.
*
* @return array
*/
public function valid_string_provider() {
return [
'Valid combination' => [
'example',
[
'field' => 'privacy:example:valid:field',
'field2' => 'privacy:example:valid:field2',
],
'privacy:example:valid',
],
];
}
}
@@ -0,0 +1,109 @@
<?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/>.
namespace core_privacy;
use core_privacy\local\metadata\types\plugintype_link;
/**
* Tests for the \core_privacy API's types\plugintype_link functionality.
*
* @package core_privacy
* @category test
* @copyright 2018 Andrew Nicols <andrew@nicols.co.uk>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
* @coversDefaultClass \core_privacy\local\metadata\types\plugintype_link
*/
class types_plugintype_link_test extends \advanced_testcase {
/**
* Ensure that warnings are thrown if string identifiers contain invalid characters.
*
* @dataProvider invalid_string_provider
* @param string $name Name
* @param string $summary Summary
* @covers ::__construct
*/
public function test_invalid_configs($name, $privacyfields, $summary): void {
$record = new plugintype_link($name, $privacyfields, $summary);
$this->assertDebuggingCalled();
}
/**
* Ensure that warnings are not thrown if debugging is not enabled, even if string identifiers contain invalid characters.
*
* @dataProvider invalid_string_provider
* @param string $name Name
* @param string $summary Summary
* @covers ::__construct
*/
public function test_invalid_configs_debug_normal($name, $privacyfields, $summary): void {
global $CFG;
$this->resetAfterTest();
$CFG->debug = DEBUG_NORMAL;
$record = new plugintype_link($name, $privacyfields, $summary);
$this->assertDebuggingNotCalled();
}
/**
* Ensure that no warnings are shown for valid combinations.
*
* @dataProvider valid_string_provider
* @param string $name Name
* @param string $summary Summary
* @covers ::__construct
*/
public function test_valid_configs($name, $privacyfields, $summary): void {
$record = new plugintype_link($name, $privacyfields, $summary);
$this->assertDebuggingNotCalled();
}
/**
* Data provider with a list of invalid string identifiers.
*
* @return array
*/
public function invalid_string_provider() {
return [
'Space in summary' => [
'example',
[],
'This table is used for purposes.',
],
'Comma in summary' => [
'example',
[],
'privacy,foo',
],
];
}
/**
* Data provider with a list of valid string identifiers.
*
* @return array
*/
public function valid_string_provider() {
return [
'Valid combination' => [
'example',
[],
'privacy:example:valid',
],
];
}
}
+109
View File
@@ -0,0 +1,109 @@
<?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/>.
namespace core_privacy;
use core_privacy\local\metadata\types\subsystem_link;
/**
* Tests for the \core_privacy API's types\subsystem_link functionality.
*
* @package core_privacy
* @category test
* @copyright 2018 Andrew Nicols <andrew@nicols.co.uk>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
* @coversDefaultClass \core_privacy\local\metadata\types\subsystem_link
*/
class types_subsystem_link_test extends \advanced_testcase {
/**
* Ensure that warnings are thrown if string identifiers contain invalid characters.
*
* @dataProvider invalid_string_provider
* @param string $name Name
* @param string $summary Summary
* @covers ::__construct
*/
public function test_invalid_configs($name, $privacyfields, $summary): void {
$record = new subsystem_link($name, $privacyfields, $summary);
$this->assertDebuggingCalled();
}
/**
* Ensure that warnings are not thrown if debugging is not enabled, even if string identifiers contain invalid characters.
*
* @dataProvider invalid_string_provider
* @param string $name Name
* @param string $summary Summary
* @covers ::__construct
*/
public function test_invalid_configs_debug_normal($name, $privacyfields, $summary): void {
global $CFG;
$this->resetAfterTest();
$CFG->debug = DEBUG_NORMAL;
$record = new subsystem_link($name, $privacyfields, $summary);
$this->assertDebuggingNotCalled();
}
/**
* Ensure that no warnings are shown for valid combinations.
*
* @dataProvider valid_string_provider
* @param string $name Name
* @param string $summary Summary
* @covers ::__construct
*/
public function test_valid_configs($name, $privacyfields, $summary): void {
$record = new subsystem_link($name, $privacyfields, $summary);
$this->assertDebuggingNotCalled();
}
/**
* Data provider with a list of invalid string identifiers.
*
* @return array
*/
public function invalid_string_provider() {
return [
'Space in summary' => [
'example',
[],
'This table is used for purposes.',
],
'Comma in summary' => [
'example',
[],
'privacy,foo',
],
];
}
/**
* Data provider with a list of valid string identifiers.
*
* @return array
*/
public function valid_string_provider() {
return [
'Valid combination' => [
'example',
[],
'privacy:example:valid',
],
];
}
}
@@ -0,0 +1,106 @@
<?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/>.
namespace core_privacy;
use core_privacy\local\metadata\types\user_preference;
/**
* Tests for the \core_privacy API's types\user_preference functionality.
*
* @package core_privacy
* @category test
* @copyright 2018 Andrew Nicols <andrew@nicols.co.uk>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
* @coversDefaultClass \core_privacy\local\metadata\types\user_preference
*/
class types_user_preference_test extends \advanced_testcase {
/**
* Ensure that warnings are thrown if string identifiers contain invalid characters.
*
* @dataProvider invalid_string_provider
* @param string $name Name
* @param string $summary Summary
* @covers ::__construct
*/
public function test_invalid_configs($name, $summary): void {
$record = new user_preference($name, $summary);
$this->assertDebuggingCalled();
}
/**
* Ensure that warnings are not thrown if debugging is not enabled, even if string identifiers contain invalid characters.
*
* @dataProvider invalid_string_provider
* @param string $name Name
* @param string $summary Summary
* @covers ::__construct
*/
public function test_invalid_configs_debug_normal($name, $summary): void {
global $CFG;
$this->resetAfterTest();
$CFG->debug = DEBUG_NORMAL;
$record = new user_preference($name, $summary);
$this->assertDebuggingNotCalled();
}
/**
* Ensure that no warnings are shown for valid combinations.
*
* @dataProvider valid_string_provider
* @param string $name Name
* @param string $summary Summary
* @covers ::__construct
*/
public function test_valid_configs($name, $summary): void {
$record = new user_preference($name, $summary);
$this->assertDebuggingNotCalled();
}
/**
* Data provider with a list of invalid string identifiers.
*
* @return array
*/
public function invalid_string_provider() {
return [
'Space in summary' => [
'example',
'This table is used for purposes.',
],
'Comma in summary' => [
'example',
'privacy,foo',
],
];
}
/**
* Data provider with a list of valid string identifiers.
*
* @return array
*/
public function valid_string_provider() {
return [
'Valid combination' => [
'example',
'privacy:example:valid',
],
];
}
}
+262
View File
@@ -0,0 +1,262 @@
<?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 the abstract userlist Class
*
* @package core_privacy
* @category test
* @copyright 2018 Andrew Nicols <andrew@nicols.co.uk>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
defined('MOODLE_INTERNAL') || die();
global $CFG;
use \core_privacy\local\request\userlist_base;
/**
* Tests for the \core_privacy API's userlist base functionality.
*
* @copyright 2018 Andrew Nicols <andrew@nicols.co.uk>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
* @coversDefaultClass \core_privacy\local\request\userlist_base
*/
class userlist_base_test extends advanced_testcase {
/**
* Ensure that get_userids returns the list of unique userids.
*
* @dataProvider get_userids_provider
* @param array $input List of user IDs
* @param array $expected list of userids
* @param int $count Expected count
* @covers ::get_userids
*/
public function test_get_userids($input, $expected, $count): void {
$uut = new test_userlist_base(\context_system::instance(), 'core_tests');
$uut->set_userids($input);
$result = $uut->get_userids();
$this->assertCount($count, $result);
// Note: Array order is not guaranteed and should not matter.
foreach ($expected as $userid) {
$this->assertNotFalse(array_search($userid, $result));
}
}
/**
* Provider for the list of userids.
*
* @return array
*/
public function get_userids_provider() {
return [
'basic' => [
[1, 2, 3, 4, 5],
[1, 2, 3, 4, 5],
5,
],
'duplicates' => [
[1, 1, 2, 2, 3, 4, 5],
[1, 2, 3, 4, 5],
5,
],
'Mixed order with duplicates' => [
[5, 4, 2, 5, 4, 1, 3, 4, 1, 5, 5, 5, 2, 4, 1, 2],
[1, 2, 3, 4, 5],
5,
],
];
}
/**
* Ensure that get_users returns the correct list of users.
*
* @covers ::get_users
*/
public function test_get_users(): void {
$this->resetAfterTest();
$users = [];
$user = $this->getDataGenerator()->create_user();
$users[$user->id] = $user;
$user = $this->getDataGenerator()->create_user();
$users[$user->id] = $user;
$user = $this->getDataGenerator()->create_user();
$users[$user->id] = $user;
$otheruser = $this->getDataGenerator()->create_user();
$ids = array_keys($users);
$uut = new test_userlist_base(\context_system::instance(), 'core_tests');
$uut->set_userids($ids);
$result = $uut->get_users();
sort($users);
sort($result);
$this->assertCount(3, $result);
$this->assertEquals($users, $result);
}
/**
* Ensure that the userlist_base is countable.
*
* @dataProvider get_userids_provider
* @param array $input List of user IDs
* @param array $expected list of userids
* @param int $count Expected count
* @covers ::count
*/
public function test_countable($input, $expected, $count): void {
$uut = new test_userlist_base(\context_system::instance(), 'core_tests');
$uut->set_userids($input);
$this->assertCount($count, $uut);
}
/**
* Ensure that the userlist_base iterates over the set of users.
*
* @covers ::current
* @covers ::key
* @covers ::next
* @covers ::rewind
* @covers ::valid
*/
public function test_user_iteration(): void {
$this->resetAfterTest();
$users = [];
$user = $this->getDataGenerator()->create_user();
$users[$user->id] = $user;
$user = $this->getDataGenerator()->create_user();
$users[$user->id] = $user;
$user = $this->getDataGenerator()->create_user();
$users[$user->id] = $user;
$otheruser = $this->getDataGenerator()->create_user();
$ids = array_keys($users);
$uut = new test_userlist_base(\context_system::instance(), 'core_tests');
$uut->set_userids($ids);
foreach ($uut as $key => $user) {
$this->assertTrue(isset($users[$user->id]));
$this->assertEquals($users[$user->id], $user);
}
}
/**
* Test that a deleted user is still returned.
* If a user has data then it still must be deleted, even if they are deleted.
*
* @covers ::count
*/
public function test_current_user_one_user(): void {
$this->resetAfterTest();
$user = $this->getDataGenerator()->create_user();
$uut = new test_userlist_base(\context_system::instance(), 'core_tests');
$uut->set_userids([$user->id]);
$this->assertCount(1, $uut);
$this->assertEquals($user, $uut->current());
delete_user($user);
$u = $uut->current();
$this->assertEquals($user->id, $u->id);
}
/**
* Test that an invalid user returns no entry.
*
* @covers ::count
*/
public function test_current_user_invalid(): void {
$uut = new test_userlist_base(\context_system::instance(), 'core_tests');
$uut->set_userids([-100]);
$this->assertCount(1, $uut);
$this->assertNull($uut->current());
}
/**
* Test that where an invalid user is listed, the next user in the list is returned instead.
*
* @covers ::count
*/
public function test_current_user_two_users(): void {
$this->resetAfterTest();
$u1 = $this->getDataGenerator()->create_user();
$uut = new test_userlist_base(\context_system::instance(), 'core_tests');
$uut->set_userids([-100, $u1->id]);
$this->assertCount(2, $uut);
$this->assertEquals($u1, $uut->current());
}
/**
* Ensure that the component specified in the constructor is used and available.
*
* @covers ::set_component
*/
public function test_set_component_in_constructor(): void {
$uut = new test_userlist_base(\context_system::instance(), 'core_tests');
$this->assertEquals('core_tests', $uut->get_component());
}
/**
* Ensure that the context specified in the constructor is available.
*
* @covers ::__construct
*/
public function test_set_context_in_constructor(): void {
$context = \context_user::instance(\core_user::get_user_by_username('admin')->id);
$uut = new test_userlist_base($context, 'core_tests');
$this->assertEquals($context, $uut->get_context());
}
}
/**
* A test class extending the userlist_base allowing setting of the userids.
*
* @copyright 2018 Andrew Nicols <andrew@nicols.co.uk>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class test_userlist_base extends userlist_base {
/**
* Set the contextids for the test class.
*
* @param int[] $contexids The list of contextids to use.
*/
public function set_userids(array $userids): userlist_base {
return parent::set_userids($userids);
}
}
+174
View File
@@ -0,0 +1,174 @@
<?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/>.
namespace core_privacy;
use advanced_testcase;
use \core_privacy\local\request\userlist_collection;
use \core_privacy\local\request\userlist;
use \core_privacy\local\request\approved_userlist;
/**
* Tests for the \core_privacy API's userlist collection functionality.
*
* @package core_privacy
* @category test
* @copyright 2018 Andrew Nicols <andrew@nicols.co.uk>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
* @coversDefaultClass \core_privacy\local\request\userlist_collection
*/
final class userlist_collection_test extends advanced_testcase {
/**
* A userlist_collection should support the userlist type.
*
* @covers ::add_userlist
*/
public function test_supports_userlist() {
$cut = \context_system::instance();
$uut = new userlist_collection($cut);
$userlist = new userlist($cut, 'core_privacy');
$uut->add_userlist($userlist);
$this->assertCount(1, $uut->get_userlists());
}
/**
* A userlist_collection should support the approved_userlist type.
*
* @covers ::add_userlist
*/
public function test_supports_approved_userlist() {
$cut = \context_system::instance();
$uut = new userlist_collection($cut);
$userlist = new approved_userlist($cut, 'core_privacy', [1, 2, 3]);
$uut->add_userlist($userlist);
$this->assertCount(1, $uut->get_userlists());
}
/**
* Ensure that get_userlist_for_component returns the correct userlist.
*
* @covers ::get_userlist_for_component
*/
public function test_get_userlist_for_component() {
$cut = \context_system::instance();
$uut = new userlist_collection($cut);
$privacy = new userlist($cut, 'core_privacy');
$uut->add_userlist($privacy);
$test = new userlist($cut, 'core_tests');
$uut->add_userlist($test);
// Note: This uses assertSame rather than assertEquals.
// The former checks the actual object, whilst assertEquals only checks that they look the same.
$this->assertSame($privacy, $uut->get_userlist_for_component('core_privacy'));
$this->assertSame($test, $uut->get_userlist_for_component('core_tests'));
}
/**
* Ensure that get_userlist_for_component does not die horribly when querying a non-existent component.
*
* @covers ::get_userlist_for_component
*/
public function test_get_userlist_for_component_not_found() {
$cut = \context_system::instance();
$uut = new userlist_collection($cut);
$this->assertNull($uut->get_userlist_for_component('core_tests'));
}
/**
* Ensure that a duplicate userlist in the collection throws an Exception.
*
* @covers ::add_userlist
*/
public function test_duplicate_addition_throws() {
$cut = \context_system::instance();
$uut = new userlist_collection($cut);
$userlist = new userlist($cut, 'core_privacy');
$uut->add_userlist($userlist);
$this->expectException('moodle_exception');
$uut->add_userlist($userlist);
}
/**
* Ensure that the userlist_collection is countable.
*
* @covers ::count
*/
public function test_countable() {
$cut = \context_system::instance();
$uut = new userlist_collection($cut);
$uut->add_userlist(new userlist($cut, 'core_privacy'));
$uut->add_userlist(new userlist($cut, 'core_tests'));
$this->assertCount(2, $uut);
}
/**
* Ensure that the userlist_collection iterates over the set of userlists.
*
* @covers ::current
* @covers ::key
* @covers ::next
* @covers ::rewind
* @covers ::valid
*/
public function test_iteration() {
$cut = \context_system::instance();
$uut = new userlist_collection($cut);
$testdata = [];
$privacy = new userlist($cut, 'core_privacy');
$uut->add_userlist($privacy);
$testdata['core_privacy'] = $privacy;
$test = new userlist($cut, 'core_tests');
$uut->add_userlist($test);
$testdata['core_tests'] = $test;
$another = new userlist($cut, 'privacy_another');
$uut->add_userlist($another);
$testdata['privacy_another'] = $another;
foreach ($uut as $component => $list) {
$this->assertEquals($testdata[$component], $list);
}
$this->assertCount(3, $uut);
}
/**
* Test that the context is correctly returned.
*
* @covers ::get_context
*/
public function test_get_context() {
$cut = \context_system::instance();
$uut = new userlist_collection($cut);
$this->assertSame($cut, $uut->get_context());
}
}
+100
View File
@@ -0,0 +1,100 @@
<?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 the approved userlist Class
*
* @package core_privacy
* @category test
* @copyright 2018 Andrew Nicols <andrew@nicols.co.uk>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
defined('MOODLE_INTERNAL') || die();
global $CFG;
use \core_privacy\local\request\userlist;
/**
* Tests for the \core_privacy API's approved userlist functionality.
*
* @copyright 2018 Andrew Nicols <andrew@nicols.co.uk>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
* @coversDefaultClass \core_privacy\local\request\userlist
*/
class userlist_test extends advanced_testcase {
/**
* Ensure that valid SQL results in the relevant users being added.
*
* @covers ::add_from_sql
*/
public function test_add_from_sql(): void {
global $DB;
$sql = "SELECT c.id FROM {user} c";
$params = [];
$allusers = $DB->get_records_sql($sql, $params);
$uut = new userlist(\context_system::instance(), 'core_privacy');
$uut->add_from_sql('id', $sql, $params);
$this->assertCount(count($allusers), $uut);
}
/**
* Ensure that adding a single user adds that user.
*
* @covers ::add_user
*/
public function test_add_user(): void {
$this->resetAfterTest();
$u1 = $this->getDataGenerator()->create_user();
$u2 = $this->getDataGenerator()->create_user();
$uut = new userlist(\context_system::instance(), 'core_privacy');
$uut->add_user($u1->id);
$this->assertCount(1, $uut);
$this->assertEquals($uut->current(), $u1);
}
/**
* Ensure that adding multiple users by ID adds those users.
*
* @covers ::add_users
*/
public function test_add_users(): void {
$this->resetAfterTest();
$u1 = $this->getDataGenerator()->create_user();
$u2 = $this->getDataGenerator()->create_user();
$u3 = $this->getDataGenerator()->create_user();
$expected = [$u1->id, $u3->id];
$uut = new userlist(\context_system::instance(), 'core_privacy');
$uut->add_users([$u1->id, $u3->id]);
$this->assertCount(2, $uut);
foreach ($uut as $user) {
$this->assertNotFalse(array_search($user->id, $expected));
}
}
}
+98
View File
@@ -0,0 +1,98 @@
<?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 the Moodle Content Writer.
*
* @package core_privacy
* @category test
* @copyright 2018 Andrew Nicols <andrew@nicols.co.uk>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
defined('MOODLE_INTERNAL') || die();
global $CFG;
use \core_privacy\local\request\writer;
/**
* Tests for the \core_privacy API's moodle_content_writer functionality.
*
* Note: The \core_privacy\tests\request\content_writer will be used for these tests.
* This content writer has additional sugar methods for fetching infromation which are not part of the standard
* content_writer interface.
*
* @copyright 2018 Andrew Nicols <andrew@nicols.co.uk>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
* @coversDefaultClass \core_privacy\local\request\writer
*/
class writer_test extends advanced_testcase {
/**
* Ensure that the writer is cleared away as appropriate after each
* test.
*/
public function tearDown(): void {
writer::reset();
}
/**
* Test that calling with_context multiple times will return the same write instance.
*
* @covers ::with_context
*/
public function test_with_context(): void {
$writer = writer::with_context(\context_system::instance());
$this->assertSame($writer, writer::with_context(\context_system::instance()));
}
/**
* Test that calling with_context multiple times will return the same write instance.
*
* @covers ::with_context
*/
public function test_with_context_different_context_same_instance(): void {
$writer = writer::with_context(\context_system::instance());
$this->assertSame($writer, writer::with_context(\context_user::instance(\core_user::get_user_by_username('admin')->id)));
}
/**
* Test that calling writer::reset() causes a new copy of the writer to be returned.
*
* @covers ::reset
*/
public function test_reset(): void {
$writer = writer::with_context(\context_system::instance());
writer::reset();
$this->assertNotSame($writer, writer::with_context(\context_system::instance()));
}
/**
* Test that the export_user_preference calls the writer against the system context.
*
* @covers ::export_user_preference
*/
public function test_export_user_preference_sets_system_context(): void {
$writer = writer::with_context(\context_user::instance(\core_user::get_user_by_username('admin')->id));
writer::export_user_preference('core_test', 'key', 'value', 'description');
$this->assertSame(\context_system::instance(), $writer->get_current_context());
}
}