Rev 1 | AutorÃa | Comparar con el anterior | Ultima modificación | Ver Log |
<?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 core_table\local\filter\filterset.** @package core_table* @category test* @copyright 2020 Andrew Nicols <andrew@nicols.co.uk>* @license http://www.gnu.org/copyleft/gpl.html GNU Public License*/declare(strict_types=1);namespace core_table\local\filter;use InvalidArgumentException;use UnexpectedValueException;use advanced_testcase;use moodle_exception;/*** Unit tests for core_table\local\filter\filterset.** @package core_table* @category test* @copyright 2020 Andrew Nicols <andrew@nicols.co.uk>* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later*/final class filterset_test extends advanced_testcase {/*** Ensure that it is possibly to set the join type.*/public function test_set_join_type(): void {$filterset = $this->get_mocked_filterset();// Initial set with the default type should just work.// The setter should be chainable.$this->assertEquals($filterset, $filterset->set_join_type(filterset::JOINTYPE_DEFAULT));$this->assertEquals(filterset::JOINTYPE_DEFAULT, $filterset->get_join_type());// It should be possible to update the join type later.$this->assertEquals($filterset, $filterset->set_join_type(filterset::JOINTYPE_NONE));$this->assertEquals(filterset::JOINTYPE_NONE, $filterset->get_join_type());$this->assertEquals($filterset, $filterset->set_join_type(filterset::JOINTYPE_ANY));$this->assertEquals(filterset::JOINTYPE_ANY, $filterset->get_join_type());$this->assertEquals($filterset, $filterset->set_join_type(filterset::JOINTYPE_ALL));$this->assertEquals(filterset::JOINTYPE_ALL, $filterset->get_join_type());}/*** Ensure that it is not possible to provide a value out of bounds when setting the join type.*/public function test_set_join_type_invalid_low(): void {$filterset = $this->get_mocked_filterset();// Valid join types are current 0, 1, or 2.// A value too low should be rejected.$this->expectException(InvalidArgumentException::class);$this->expectExceptionMessage("Invalid join type specified");$filterset->set_join_type(-1);}/*** Ensure that it is not possible to provide a value out of bounds when setting the join type.*/public function test_set_join_type_invalid_high(): void {$filterset = $this->get_mocked_filterset();// Valid join types are current 0, 1, or 2.// A value too low should be rejected.$this->expectException(InvalidArgumentException::class);$this->expectExceptionMessage("Invalid join type specified");$filterset->set_join_type(4);}/*** Ensure that adding filter values works as expected.*/public function test_add_filter_value(): void {$filterset = $this->get_mocked_filterset(['get_optional_filters']);$filterset->method('get_optional_filters')->will($this->returnValue(['name' => filter::class,'species' => filter::class,]));// Initially an empty list.$this->assertEmpty($filterset->get_filters());// Test data.$speciesfilter = new filter('species', null, ['canine']);$namefilter = new filter('name', null, ['rosie']);// Add a filter to the list.$filterset->add_filter($speciesfilter);$this->assertSame([$speciesfilter,], array_values($filterset->get_filters()));// Adding a second value should add that value.// The values should sorted.$filterset->add_filter($namefilter);$this->assertSame([$namefilter,$speciesfilter,], array_values($filterset->get_filters()));// Adding an existing filter again should be ignored.$filterset->add_filter($speciesfilter);$this->assertSame([$namefilter,$speciesfilter,], array_values($filterset->get_filters()));}/*** Ensure that it is possible to add a filter of a validated filter type.*/public function test_add_filter_validated_type(): void {$namefilter = $this->getMockBuilder(filter::class)->setConstructorArgs(['name'])->onlyMethods([])->getMock();$namefilter->add_filter_value('rosie');// Mock the get_optional_filters function.$filterset = $this->get_mocked_filterset(['get_optional_filters']);$filterset->method('get_optional_filters')->will($this->returnValue(['name' => get_class($namefilter),]));// Add a filter to the list.// This is the 'name' filter.$filterset->add_filter($namefilter);$this->assertNull($filterset->check_validity());}/*** Ensure that it is not possible to add a type which is not expected.*/public function test_add_filter_unexpected_key(): void {// Mock the get_optional_filters function.$filterset = $this->get_mocked_filterset(['get_optional_filters']);$filterset->method('get_optional_filters')->will($this->returnValue([]));// Add a filter to the list.// This is the 'name' filter.$namefilter = new filter('name');$this->expectException(InvalidArgumentException::class);$this->expectExceptionMessage("The filter 'name' was not recognised.");$filterset->add_filter($namefilter);}/*** Ensure that it is not possible to add a validated type where the type is incorrect.*/public function test_add_filter_validated_type_incorrect(): void {$filtername = "name";$otherfilter = $this->createMock(filter::class);// Mock the get_optional_filters function.$filterset = $this->get_mocked_filterset(['get_optional_filters']);$filterset->method('get_optional_filters')->will($this->returnValue([$filtername => get_class($otherfilter),]));// Add a filter to the list.// This is the 'name' filter.$namefilter = $this->getMockBuilder(filter::class)->onlyMethods([])->setConstructorArgs([$filtername])->getMock();$actualtype = get_class($namefilter);$requiredtype = get_class($otherfilter);$this->expectException(InvalidArgumentException::class);$this->expectExceptionMessage("The filter '{$filtername}' was incorrectly specified as a {$actualtype}. It must be a {$requiredtype}.");$filterset->add_filter($namefilter);}/*** Ensure that a filter can be added from parameters provided to a web service.*/public function test_add_filter_from_params(): void {$filtername = "name";$otherfilter = $this->getMockBuilder(filter::class)->onlyMethods([])->setConstructorArgs([$filtername])->getMock();// Mock the get_optional_filters function.$filterset = $this->get_mocked_filterset(['get_optional_filters']);$filterset->method('get_optional_filters')->will($this->returnValue([$filtername => get_class($otherfilter),]));$result = $filterset->add_filter_from_params($filtername, filter::JOINTYPE_DEFAULT, ['kevin']);// The function is chainable.$this->assertEquals($filterset, $result);// Get the filter back.$filter = $filterset->get_filter($filtername);$this->assertEquals($filtername, $filter->get_name());$this->assertEquals(filter::JOINTYPE_DEFAULT, $filter->get_join_type());$this->assertEquals(['kevin'], $filter->get_filter_values());}/*** Ensure that an unknown filter is not added.*/public function test_add_filter_from_params_unable_to_autoload(): void {// Mock the get_optional_filters function.$filterset = $this->get_mocked_filterset(['get_optional_filters']);$filterset->method('get_optional_filters')->will($this->returnValue(['name' => '\\moodle\\this\\is\\a\\fake\\class\\name',]));$this->expectException(InvalidArgumentException::class);$this->expectExceptionMessage("The filter class '\\moodle\\this\\is\\a\\fake\\class\\name' for filter 'name' could not be found.");$filterset->add_filter_from_params('name', filter::JOINTYPE_DEFAULT, ['kevin']);}/*** Ensure that an unknown filter is not added.*/public function test_add_filter_from_params_invalid(): void {$filtername = "name";$otherfilter = $this->getMockBuilder(filter::class)->onlyMethods([])->setConstructorArgs([$filtername])->getMock();// Mock the get_optional_filters function.$filterset = $this->get_mocked_filterset(['get_optional_filters']);$filterset->method('get_optional_filters')->will($this->returnValue([$filtername => get_class($otherfilter),]));$this->expectException(InvalidArgumentException::class);$this->expectExceptionMessage("The filter 'unknownfilter' was not recognised.");$filterset->add_filter_from_params('unknownfilter', filter::JOINTYPE_DEFAULT, ['kevin']);}/*** Ensure that adding a different filter with a different object throws an Exception.*/public function test_duplicate_filter_value(): void {$filterset = $this->get_mocked_filterset(['get_optional_filters']);$filterset->method('get_optional_filters')->will($this->returnValue(['name' => filter::class,'species' => filter::class,]));// Add a filter to the list.// This is the 'name' filter.$namefilter = new filter('name', null, ['rosie']);$filterset->add_filter($namefilter);// Add another filter to the list.// This one has been incorrectly called the 'name' filter when it should be 'species'.$this->expectException(UnexpectedValueException::Class);$this->expectExceptionMessage("A filter of type 'name' has already been added. Check that you have the correct filter.");$speciesfilter = new filter('name', null, ['canine']);$filterset->add_filter($speciesfilter);}/*** Ensure that validating a filterset correctly compares filter types.*/public function test_check_validity_optional_filters_not_specified(): void {$filterset = $this->get_mocked_filterset(['get_optional_filters']);$filterset->method('get_optional_filters')->will($this->returnValue(['name' => filter::class,'species' => filter::class,]));$this->assertNull($filterset->check_validity());}/*** Ensure that validating a filterset correctly requires required filters.*/public function test_check_validity_required_filter(): void {$filterset = $this->get_mocked_filterset(['get_required_filters']);$filterset->expects($this->any())->method('get_required_filters')->willReturn(['name' => filter::class]);// Add a filter to the list.// This is the 'name' filter.$filterset->add_filter(new filter('name'));$this->assertNull($filterset->check_validity());}/*** Ensure that validating a filterset excepts correctly when a required fieldset is missing.*/public function test_check_validity_filter_missing_required(): void {$filterset = $this->get_mocked_filterset(['get_required_filters']);$filterset->expects($this->any())->method('get_required_filters')->willReturn(['name' => filter::class,'species' => filter::class,]);$this->expectException(moodle_exception::Class);$this->expectExceptionMessage("One or more required filters were missing (name, species)");$filterset->check_validity();}/*** Ensure that getting the filters returns a sorted list of filters.*/public function test_get_filters(): void {$filterset = $this->get_mocked_filterset(['get_optional_filters']);$filterset->method('get_optional_filters')->will($this->returnValue([// Filters are not defined lexically.'d' => filter::class,'b' => filter::class,'a' => filter::class,'c' => filter::class,]));// Filters are added in a different non-lexical order.$c = new filter('c');$filterset->add_filter($c);$b = new filter('b');$filterset->add_filter($b);$d = new filter('d');$filterset->add_filter($d);$a = new filter('a');$filterset->add_filter($a);// But they are returned lexically sorted.$this->assertEquals(['a' => $a,'b' => $b,'c' => $c,'d' => $d,], $filterset->get_filters());}/*** Ensure that getting a singlel filter returns the correct filter.*/public function test_get_filter(): void {$filterset = $this->get_mocked_filterset(['get_optional_filters']);$filterset->method('get_optional_filters')->will($this->returnValue([// Filters are not defined lexically.'d' => filter::class,'b' => filter::class,'a' => filter::class,'c' => filter::class,]));// Filters are added in a different non-lexical order.$c = new filter('c');$filterset->add_filter($c);$b = new filter('b');$filterset->add_filter($b);$d = new filter('d');$filterset->add_filter($d);$a = new filter('a');$filterset->add_filter($a);// Filters can be individually retrieved in any order.$this->assertEquals($d, $filterset->get_filter('d'));$this->assertEquals($a, $filterset->get_filter('a'));$this->assertEquals($b, $filterset->get_filter('b'));$this->assertEquals($c, $filterset->get_filter('c'));}/*** Ensure that it is not possible to retrieve an unknown filter.*/public function test_get_filter_unknown(): void {$filterset = $this->get_mocked_filterset(['get_optional_filters']);$filterset->method('get_optional_filters')->will($this->returnValue(['a' => filter::class,]));$a = new filter('a');$filterset->add_filter($a);$this->expectException(UnexpectedValueException::Class);$this->expectExceptionMessage("The filter specified (d) is invalid.");$filterset->get_filter('d');}/*** Ensure that it is not possible to retrieve a valid filter before it is created.*/public function test_get_filter_not_yet_added(): void {$filterset = $this->get_mocked_filterset(['get_optional_filters']);$filterset->method('get_optional_filters')->will($this->returnValue(['a' => filter::class,]));$this->expectException(UnexpectedValueException::Class);$this->expectExceptionMessage("The filter specified (a) has not been created.");$filterset->get_filter('a');}/*** Ensure that the get_all_filtertypes function correctly returns the combined filterset.*/public function test_get_all_filtertypes(): void {$otherfilter = $this->createMock(filter::class);$filterset = $this->get_mocked_filterset(['get_optional_filters','get_required_filters',]);$filterset->method('get_optional_filters')->will($this->returnValue(['a' => filter::class,'c' => get_class($otherfilter),]));$filterset->method('get_required_filters')->will($this->returnValue(['b' => get_class($otherfilter),'d' => filter::class,]));$this->assertEquals(['a' => filter::class,'b' => get_class($otherfilter),'c' => get_class($otherfilter),'d' => filter::class,], $filterset->get_all_filtertypes());}/*** Ensure that the get_all_filtertypes function correctly returns the combined filterset.*/public function test_get_all_filtertypes_conflict(): void {$otherfilter = $this->createMock(filter::class);$filterset = $this->get_mocked_filterset(['get_optional_filters','get_required_filters',]);$filterset->method('get_optional_filters')->will($this->returnValue(['a' => filter::class,'b' => get_class($otherfilter),'d' => filter::class,]));$filterset->method('get_required_filters')->will($this->returnValue(['b' => get_class($otherfilter),'c' => filter::class,'d' => filter::class,]));$this->expectException(InvalidArgumentException::Class);$this->expectExceptionMessage("Some filter types are both required, and optional: b, d");$filterset->get_all_filtertypes();}/*** Ensure that the has_filter function works as expected.*/public function test_has_filter(): void {$filterset = $this->get_mocked_filterset(['get_optional_filters']);$filterset->method('get_optional_filters')->will($this->returnValue([// Define filters 'a', and 'b'.'a' => filter::class,'b' => filter::class,]));// Only add filter 'a'.$a = new filter('a');$filterset->add_filter($a);// Filter 'a' should exist.$this->assertTrue($filterset->has_filter('a'));// Filter 'b' is defined, but has not been added.$this->assertFalse($filterset->has_filter('b'));// Filter 'c' is not defined.// No need to throw any kind of exception - this is an existence check.$this->assertFalse($filterset->has_filter('c'));}/*** Get a mocked copy of the filterset, mocking the specified methods.** @param array $mockedmethods anonymous array containing the list of mocked methods* @return filterset Mock of the filterset*/protected function get_mocked_filterset(array $mockedmethods = []): filterset {return $this->getMockForAbstractClass(filterset::class, [], '', true, true, true, $mockedmethods);}}