From d043aa071b2efc51d78b01c3c3c054fb28fcbb1b Mon Sep 17 00:00:00 2001 From: Andrew Nicols Date: Thu, 5 Apr 2018 10:43:21 +0800 Subject: [PATCH] MDL-61861 privacy: Add unit tests to check all providers. --- privacy/tests/provider_test.php | 176 ++++++++++++++++++++++++++++++++ 1 file changed, 176 insertions(+) create mode 100644 privacy/tests/provider_test.php diff --git a/privacy/tests/provider_test.php b/privacy/tests/provider_test.php new file mode 100644 index 00000000000..b90abfac550 --- /dev/null +++ b/privacy/tests/provider_test.php @@ -0,0 +1,176 @@ +. + +/** + * Unit tests for all Privacy Providers. + * + * @package core_privacy + * @copyright 2018 Andrew Nicols + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ + +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 + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ +class provider_testcase 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 = []; + // 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) { + $reason = $classname::get_reason(); + $this->assertInternalType('string', $reason); + + $this->assertInternalType('string', 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) { + $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->assertInternalType('string', $item->get_name()); + + if ($summary = $item->get_summary()) { + // Summary is optional, but when provided must be a valid string identifier. + $this->assertInternalType('string', $summary); + + // Check that the string is also correctly defined. + $this->assertInternalType('string', 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->assertInternalType('string', $field); + $this->assertInternalType('string', $identifier); + + // Check that the string is also correctly defined. + $this->assertInternalType('string', get_string($identifier, $component)); + $this->assertDebuggingNotCalled(); + } + } + } + } + + /** + * 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 + ); + }); + } + + /** + * 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; + } + +}