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
+254
View File
@@ -0,0 +1,254 @@
<?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_customfield;
/**
* Functional test for class \core_customfield\api
*
* @package core_customfield
* @category test
* @copyright 2018 Toni Barbera <toni@moodle.com>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class api_test extends \advanced_testcase {
/**
* Get generator.
*
* @return core_customfield_generator
*/
protected function get_generator(): \core_customfield_generator {
return $this->getDataGenerator()->get_plugin_generator('core_customfield');
}
/**
* Help to assert that the given property in an array of object has the expected value
*
* @param array $expected
* @param array $array array of objects with "get($property)" method
* @param string $propertyname
*/
protected function assert_property_in_array($expected, $array, $propertyname) {
$this->assertEquals($expected, array_values(array_map(function($a) use ($propertyname) {
return $a->get($propertyname);
}, $array)));
}
/**
* Tests for \core_customfield\api::move_category() behaviour.
*
* This replicates what is happening when categories are moved
* in the interface using drag-drop.
*/
public function test_move_category(): void {
$this->resetAfterTest();
// Create the categories.
$params = ['component' => 'core_course', 'area' => 'course', 'itemid' => 0];
$id0 = $this->get_generator()->create_category($params)->get('id');
$id1 = $this->get_generator()->create_category($params)->get('id');
$id2 = $this->get_generator()->create_category($params)->get('id');
$id3 = $this->get_generator()->create_category($params)->get('id');
$id4 = $this->get_generator()->create_category($params)->get('id');
$id5 = $this->get_generator()->create_category($params)->get('id');
// Check order after re-fetch.
$categories = api::get_categories_with_fields($params['component'], $params['area'], $params['itemid']);
$this->assertEquals([$id0, $id1, $id2, $id3, $id4, $id5], array_keys($categories));
$this->assert_property_in_array([0, 1, 2, 3, 4, 5], $categories, 'sortorder');
// Move up 1 position.
api::move_category(category_controller::create($id3), $id2);
$categories = api::get_categories_with_fields($params['component'], $params['area'], $params['itemid']);
$this->assertEquals([$id0, $id1, $id3, $id2, $id4, $id5], array_keys($categories));
$this->assert_property_in_array([0, 1, 2, 3, 4, 5], $categories, 'sortorder');
// Move down 1 position.
api::move_category(category_controller::create($id2), $id3);
$categories = api::get_categories_with_fields($params['component'], $params['area'], $params['itemid']);
$this->assertEquals([$id0, $id1, $id2, $id3, $id4, $id5], array_keys($categories));
$this->assert_property_in_array([0, 1, 2, 3, 4, 5], $categories, 'sortorder');
// Move up 2 positions.
api::move_category(category_controller::create($id4), $id2);
$categories = api::get_categories_with_fields($params['component'], $params['area'], $params['itemid']);
$this->assertEquals([$id0, $id1, $id4, $id2, $id3, $id5], array_keys($categories));
$this->assert_property_in_array([0, 1, 2, 3, 4, 5], $categories, 'sortorder');
// Move down 2 positions.
api::move_category(category_controller::create($id4), $id5);
$categories = api::get_categories_with_fields($params['component'], $params['area'], $params['itemid']);
$this->assertEquals([$id0, $id1, $id2, $id3, $id4, $id5], array_keys($categories));
$this->assert_property_in_array([0, 1, 2, 3, 4, 5], $categories, 'sortorder');
// Move to the end of the list.
api::move_category(category_controller::create($id2));
$categories = api::get_categories_with_fields($params['component'], $params['area'], $params['itemid']);
$this->assertEquals([$id0, $id1, $id3, $id4, $id5, $id2], array_keys($categories));
$this->assert_property_in_array([0, 1, 2, 3, 4, 5], $categories, 'sortorder');
}
/**
* Tests for \core_customfield\api::get_categories_with_fields() behaviour.
*/
public function test_get_categories_with_fields(): void {
$this->resetAfterTest();
// Create the categories.
$options = [
'component' => 'core_course',
'area' => 'course',
'itemid' => 0,
'contextid' => \context_system::instance()->id
];
$category0 = $this->get_generator()->create_category(['name' => 'aaaa'] + $options);
$category1 = $this->get_generator()->create_category(['name' => 'bbbb'] + $options);
$category2 = $this->get_generator()->create_category(['name' => 'cccc'] + $options);
$category3 = $this->get_generator()->create_category(['name' => 'dddd'] + $options);
$category4 = $this->get_generator()->create_category(['name' => 'eeee'] + $options);
$category5 = $this->get_generator()->create_category(['name' => 'ffff'] + $options);
// Let's test counts.
$this->assertCount(6, api::get_categories_with_fields($options['component'], $options['area'], $options['itemid']));
api::delete_category($category5);
$this->assertCount(5, api::get_categories_with_fields($options['component'], $options['area'], $options['itemid']));
api::delete_category($category4);
$this->assertCount(4, api::get_categories_with_fields($options['component'], $options['area'], $options['itemid']));
api::delete_category($category3);
$this->assertCount(3, api::get_categories_with_fields($options['component'], $options['area'], $options['itemid']));
api::delete_category($category2);
$this->assertCount(2, api::get_categories_with_fields($options['component'], $options['area'], $options['itemid']));
api::delete_category($category1);
$this->assertCount(1, api::get_categories_with_fields($options['component'], $options['area'], $options['itemid']));
api::delete_category($category0);
$this->assertCount(0, api::get_categories_with_fields($options['component'], $options['area'], $options['itemid']));
}
/**
* Test for functions api::save_category() and rename_category)
*/
public function test_save_category(): void {
$this->resetAfterTest();
$params = ['component' => 'core_course', 'area' => 'course', 'itemid' => 0, 'name' => 'Cat1',
'contextid' => \context_system::instance()->id];
$c1 = category_controller::create(0, (object)$params);
api::save_category($c1);
$this->assertNotEmpty($c1->get('id'));
$c1 = category_controller::create($c1->get('id'));
$expected = $params + ['sortorder' => 0, 'id' => $c1->get('id'), 'description' => '', 'descriptionformat' => 0];
$actual = array_intersect_key((array)$c1->to_record(), $expected); // Ignore timecreated, timemodified.
ksort($expected);
ksort($actual);
$this->assertEquals($expected, $actual);
// Create new category and check that the sortorder will be 1.
$params['name'] = 'Cat2';
$c2 = category_controller::create(0, (object)$params);
api::save_category($c2);
$this->assertNotEmpty($c2->get('id'));
$this->assertEquals(1, $c2->get('sortorder'));
$c2 = category_controller::create($c2->get('id'));
$this->assertEquals(1, $c2->get('sortorder'));
// Rename a category.
$c1->set('name', 'Cat3');
$c1->save();
$c1 = category_controller::create($c1->get('id'));
$this->assertEquals('Cat3', $c1->get('name'));
}
/**
* Test for function handler::create_category
*/
public function test_create_category(): void {
$this->resetAfterTest();
$handler = \core_course\customfield\course_handler::create();
$c1id = $handler->create_category();
$c1 = $handler->get_categories_with_fields()[$c1id];
$this->assertEquals('Other fields', $c1->get('name'));
$this->assertEquals($handler->get_component(), $c1->get('component'));
$this->assertEquals($handler->get_area(), $c1->get('area'));
$this->assertEquals($handler->get_itemid(), $c1->get('itemid'));
$this->assertEquals($handler->get_configuration_context()->id, $c1->get('contextid'));
// Generate more categories and make sure they have different names.
$c2id = $handler->create_category();
$c3id = $handler->create_category();
$c2 = $handler->get_categories_with_fields()[$c2id];
$c3 = $handler->get_categories_with_fields()[$c3id];
$this->assertEquals('Other fields 1', $c2->get('name'));
$this->assertEquals('Other fields 2', $c3->get('name'));
}
/**
* Tests for \core_customfield\api::delete_category() behaviour.
*/
public function test_delete_category_with_fields(): void {
$this->resetAfterTest();
global $DB;
// Create two categories with fields and data.
$options = [
'component' => 'core_course',
'area' => 'course',
'itemid' => 0,
'contextid' => \context_system::instance()->id
];
$lpg = $this->get_generator();
$course = $this->getDataGenerator()->create_course();
$dataparams = ['instanceid' => $course->id, 'contextid' => \context_course::instance($course->id)->id];
$category0 = $lpg->create_category($options);
$category1 = $lpg->create_category($options);
for ($i = 0; $i < 6; $i++) {
$f = $lpg->create_field(['categoryid' => $category0->get('id')]);
\core_customfield\data_controller::create(0, (object)$dataparams, $f)->save();
$f = $lpg->create_field(['categoryid' => $category1->get('id')]);
\core_customfield\data_controller::create(0, (object)$dataparams, $f)->save();
}
// Check that each category have fields and store ids for future checks.
list($category0, $category1) = array_values(api::get_categories_with_fields($options['component'],
$options['area'], $options['itemid']));
$category0fieldsids = array_keys($category0->get_fields());
$category1fieldsids = array_keys($category1->get_fields());
// There are 6 records in field table and 6 records in data table for each category.
list($sql, $p) = $DB->get_in_or_equal($category0fieldsids);
$this->assertCount(6, $DB->get_records_select(\core_customfield\field::TABLE, 'id '.$sql, $p));
$this->assertCount(6, $DB->get_records_select(\core_customfield\data::TABLE, 'fieldid '.$sql, $p));
list($sql, $p) = $DB->get_in_or_equal($category1fieldsids);
$this->assertCount(6, $DB->get_records_select(\core_customfield\field::TABLE, 'id '.$sql, $p));
$this->assertCount(6, $DB->get_records_select(\core_customfield\data::TABLE, 'fieldid '.$sql, $p));
// Delete one category.
$this->assertTrue($category0->get_handler()->delete_category($category0));
// Check that the category fields and data were deleted.
list($sql, $p) = $DB->get_in_or_equal($category0fieldsids);
$this->assertEmpty($DB->get_records_select(\core_customfield\field::TABLE, 'id '.$sql, $p));
$this->assertEmpty($DB->get_records_select(\core_customfield\data::TABLE, 'fieldid '.$sql, $p));
// Check that fields and data for the other category remain.
list($sql, $p) = $DB->get_in_or_equal($category1fieldsids);
$this->assertCount(6, $DB->get_records_select(\core_customfield\field::TABLE, 'id '.$sql, $p));
$this->assertCount(6, $DB->get_records_select(\core_customfield\data::TABLE, 'fieldid '.$sql, $p));
}
}
@@ -0,0 +1,104 @@
@core @core_course @core_customfield @javascript
Feature: Managers can manage categories for course custom fields
In order to have additional data on the course
As a manager
I need to create, edit, remove and sort custom field's categories
Scenario: Create a category for custom course fields
Given I log in as "admin"
When I navigate to "Courses > Default settings > Course custom fields" in site administration
And I press "Add a new category"
And I wait until the page is ready
Then I should see "Other fields" in the "#customfield_catlist" "css_element"
And I navigate to "Reports > Logs" in site administration
And I press "Get these logs"
Scenario: Edit a category name for custom course fields
Given the following "custom field categories" exist:
| name | component | area | itemid |
| Category for test | core_course | course | 0 |
And I log in as "admin"
And I navigate to "Courses > Default settings > Course custom fields" in site administration
And I set the field "Edit category name" in the "//div[contains(@class,'categoryinstance') and contains(.,'Category for test')]" "xpath_element" to "Good fields"
Then I should not see "Category for test" in the "#customfield_catlist" "css_element"
And "New value for Category for test" "field" should not exist
And I should see "Good fields" in the "#customfield_catlist" "css_element"
And I navigate to "Reports > Logs" in site administration
And I press "Get these logs"
Scenario: Delete a category for custom course fields
Given the following "custom field categories" exist:
| name | component | area | itemid |
| Category for test | core_course | course | 0 |
And the following "custom fields" exist:
| name | category | type | shortname |
| Field 1 | Category for test | text | f1 |
And I log in as "admin"
And I navigate to "Courses > Default settings > Course custom fields" in site administration
And I click on "[data-role='deletecategory']" "css_element"
And I click on "Yes" "button" in the "Confirm" "dialogue"
And I wait until the page is ready
And I wait until "Test category" "text" does not exist
Then I should not see "Test category" in the "#customfield_catlist" "css_element"
And I navigate to "Reports > Logs" in site administration
And I press "Get these logs"
Scenario: Move field in the course custom fields to another category
Given the following "custom field categories" exist:
| name | component | area | itemid |
| Category1 | core_course | course | 0 |
| Category2 | core_course | course | 0 |
| Category3 | core_course | course | 0 |
And the following "custom fields" exist:
| name | category | type | shortname |
| Field1 | Category1 | text | f1 |
| Field2 | Category2 | text | f2 |
When I log in as "admin"
And I navigate to "Courses > Default settings > Course custom fields" in site administration
Then "Field1" "text" should appear after "Category1" "text"
And "Category2" "text" should appear after "Field1" "text"
And "Field2" "text" should appear after "Category2" "text"
And "Category3" "text" should appear after "Field2" "text"
And I press "Move \"Field1\""
And I follow "To the top of category Category2"
And "Category2" "text" should appear after "Category1" "text"
And "Field1" "text" should appear after "Category2" "text"
And "Field2" "text" should appear after "Field1" "text"
And "Category3" "text" should appear after "Field2" "text"
And I navigate to "Courses > Default settings > Course custom fields" in site administration
And "Category2" "text" should appear after "Category1" "text"
And "Field1" "text" should appear after "Category2" "text"
And "Field2" "text" should appear after "Field1" "text"
And "Category3" "text" should appear after "Field2" "text"
And I press "Move \"Field1\""
And I follow "After field Field2"
And "Field1" "text" should appear after "Field2" "text"
Scenario: Reorder course custom field categories
Given the following "custom field categories" exist:
| name | component | area | itemid |
| Category1 | core_course | course | 0 |
| Category2 | core_course | course | 0 |
| Category3 | core_course | course | 0 |
And the following "custom fields" exist:
| name | category | type | shortname |
| Field1 | Category1 | text | f1 |
When I log in as "admin"
And I navigate to "Courses > Default settings > Course custom fields" in site administration
Then "Field1" "text" should appear after "Category1" "text"
And "Category2" "text" should appear after "Field1" "text"
And "Category3" "text" should appear after "Category2" "text"
And I press "Move \"Category2\""
And I follow "After \"Category3\""
And "Field1" "text" should appear after "Category1" "text"
And "Category3" "text" should appear after "Field1" "text"
And "Category2" "text" should appear after "Category3" "text"
And I navigate to "Courses > Default settings > Course custom fields" in site administration
And "Field1" "text" should appear after "Category1" "text"
And "Category3" "text" should appear after "Field1" "text"
And "Category2" "text" should appear after "Category3" "text"
And I press "Move \"Category2\""
And I follow "After \"Category1\""
And "Field1" "text" should appear after "Category1" "text"
And "Category2" "text" should appear after "Field1" "text"
And "Category3" "text" should appear after "Category2" "text"
@@ -0,0 +1,114 @@
@core @core_course @core_customfield @javascript
Feature: Teachers can edit course custom fields
In order to have additional data on the course
As a teacher
I need to edit data for custom fields
Background:
Given the following "custom field categories" exist:
| name | component | area | itemid |
| Category for test | core_course | course | 0 |
And the following "custom fields" exist:
| name | category | type | shortname | description | configdata |
| Field 1 | Category for test | text | f1 | d1 | |
| Field 2 | Category for test | textarea | f2 | d2 | |
| Field 3 | Category for test | checkbox | f3 | d3 | |
| Field 4 | Category for test | date | f4 | d4 | |
| Field 5 | Category for test | select | f5 | d5 | {"options":"a\nb\nc"} |
And the following "users" exist:
| username | firstname | lastname | email |
| teacher1 | Teacher | 1 | teacher1@example.com |
And the following "courses" exist:
| fullname | shortname | format |
| Course 1 | C1 | topics |
And the following "course enrolments" exist:
| user | course | role |
| teacher1 | C1 | editingteacher |
And the following "user private files" exist:
| user | filepath |
| admin | lib/tests/fixtures/gd-logo.png |
Scenario: Display custom fields on course edit form
When I log in as "teacher1"
And I am on "Course 1" course homepage
And I navigate to "Settings" in current page administration
And I expand all fieldsets
Then I should see "Category for test"
And I should see "Field 1"
And I should see "Field 2"
And I should see "Field 3"
And I should see "Field 4"
And I should see "Field 5"
And I log out
Scenario: Create a course with custom fields from the management interface
When I log in as "admin"
And I go to the courses management page
And I should see the "Categories" management page
And I click on category "Category 1" in the management interface
And I should see the "Course categories and courses" management page
And I click on "Create new course" "link" in the "#course-listing" "css_element"
And I set the following fields to these values:
| Course full name | Course 2 |
| Course short name | C2 |
| Field 1 | testcontent1 |
| Field 2 | testcontent2 |
| Field 3 | 1 |
| customfield_f4[enabled] | 1 |
| customfield_f4[day] | 1 |
| customfield_f4[month] | January |
| customfield_f4[year] | 2019 |
| Field 5 | b |
And I press "Save and display"
And I navigate to "Settings" in current page administration
And the following fields match these values:
| Course full name | Course 2 |
| Course short name | C2 |
| Field 1 | testcontent1 |
| Field 2 | testcontent2 |
| Field 3 | 1 |
| customfield_f4[day] | 1 |
| customfield_f4[month] | January |
| customfield_f4[year] | 2019 |
| Field 5 | b |
And I log out
@javascript @editor_tiny
Scenario: Use images in the custom field description
When I log in as "admin"
And I navigate to "Courses > Default settings > Course custom fields" in site administration
And I click on "Edit" "link" in the "Field 1" "table_row"
And I click on "Image" "button" in the "Description" "form_row"
And I click on "Browse repositories" "button"
And I click on "Private files" "link" in the ".fp-repo-area" "css_element"
And I click on "gd-logo.png" "link"
And I click on "Select this file" "button"
And I set the field "How would you describe this image to someone who can't see it?" to "Example"
And I click on "Save" "button" in the "Image details" "dialogue"
And I click on "Save changes" "button" in the "Updating Field 1" "dialogue"
And I log out
And I log in as "teacher1"
And I am on "Course 1" course homepage
And I navigate to "Settings" in current page administration
And I expand all fieldsets
Then the image at "//div[contains(@class, 'fitem')][contains(., 'Field 1')]/following-sibling::div[1]//img[contains(@src, 'pluginfile.php') and contains(@src, '/core_customfield/description/') and @alt='Example']" "xpath_element" should be identical to "lib/tests/fixtures/gd-logo.png"
And I log out
@javascript
Scenario: Custom field short name must be present and unique
When I log in as "admin"
And I navigate to "Courses > Default settings > Course custom fields" in site administration
And I click on "Add a new custom field" "link"
And I click on "Short text" "link"
And I set the following fields to these values:
| Name | Test field |
And I click on "Save changes" "button" in the "Adding a new Short text" "dialogue"
Then I should see "You must supply a value here" in the "Short name" "form_row"
And I set the field "Short name" to "short name"
And I click on "Save changes" "button" in the "Adding a new Short text" "dialogue"
Then I should see "The short name can only contain alphanumeric lowercase characters and underscores (_)." in the "Short name" "form_row"
And I set the field "Short name" to "f1"
And I click on "Save changes" "button" in the "Adding a new Short text" "dialogue"
Then I should see "Short name already exists" in the "Short name" "form_row"
And I click on "Cancel" "button" in the "Adding a new Short text" "dialogue"
And I log out
@@ -0,0 +1,58 @@
@core @core_course @core_customfield @javascript
Feature: Requiredness The course custom fields can be mandatory or not
In order to make users required to fill a custom field
As a manager
I can change the requiredness of the fields
Background:
Given the following "custom field categories" exist:
| name | component | area | itemid |
| Category for test | core_course | course | 0 |
Given the following "users" exist:
| username | firstname | lastname | email |
| teacher1 | Teacher | 1 | teacher1@example.com |
And the following "courses" exist:
| fullname | shortname | format |
| Course 1 | C1 | topics |
And the following "course enrolments" exist:
| user | course | role |
| teacher1 | C1 | editingteacher |
Scenario: A required course custom field must be filled when editing course settings
When I log in as "admin"
And I navigate to "Courses > Default settings > Course custom fields" in site administration
And I click on "Add a new custom field" "link"
And I click on "Short text" "link"
And I set the following fields to these values:
| Name | Test field |
| Short name | testfield |
| Required | Yes |
And I click on "Save changes" "button" in the "Adding a new Short text" "dialogue"
And I log out
And I log in as "teacher1"
And I am on "Course 1" course homepage
And I navigate to "Settings" in current page administration
And I press "Save and display"
Then I should see "You must supply a value here"
And I set the field "Test field" to "some value"
And I press "Save and display"
And I should not see "This field is required"
And I log out
Scenario: A course custom field that is not required may not be filled
When I log in as "admin"
And I navigate to "Courses > Default settings > Course custom fields" in site administration
And I click on "Add a new custom field" "link"
And I click on "Short text" "link"
And I set the following fields to these values:
| Name | Test field |
| Short name | testfield |
| Required | No |
And I click on "Save changes" "button" in the "Adding a new Short text" "dialogue"
And I log out
And I log in as "teacher1"
And I am on "Course 1" course homepage
And I navigate to "Settings" in current page administration
And I press "Save and display"
Then I should see "Course 1"
And I should see "New section"
@@ -0,0 +1,74 @@
@core @core_course @core_customfield @javascript
Feature: Uniqueness The course custom fields can be mandatory or not
In order to make users required to fill a custom field
As a manager
I can change the uniqueness of the fields
Background:
Given the following "custom field categories" exist:
| name | component | area | itemid |
| Category for test | core_course | course | 0 |
Given the following "users" exist:
| username | firstname | lastname | email |
| teacher1 | Teacher | 1 | teacher1@example.com |
And the following "courses" exist:
| fullname | shortname | format |
| Course 1 | C1 | topics |
| Course 2 | C2 | topics |
And the following "course enrolments" exist:
| user | course | role |
| teacher1 | C1 | editingteacher |
| teacher1 | C2 | editingteacher |
When I log in as "admin"
And I navigate to "Courses > Default settings > Course custom fields" in site administration
And I click on "Add a new custom field" "link"
And I click on "Short text" "link"
And I set the following fields to these values:
| Name | Test field |
| Short name | testfield |
| Unique data | Yes |
And I click on "Save changes" "button" in the "Adding a new Short text" "dialogue"
And I log out
Scenario: A course custom field with unique data must not allow same data in same field in different courses
When I log in as "teacher1"
And I am on "Course 1" course homepage
And I navigate to "Settings" in current page administration
And I set the following fields to these values:
| Test field | testcontent |
And I press "Save and display"
And I am on "Course 2" course homepage
And I navigate to "Settings" in current page administration
And I set the following fields to these values:
| Test field | testcontent |
And I press "Save and display"
Then I should see "This value is already used"
Scenario: A course custom field with unique data must not compare with itself
When I log in as "teacher1"
And I am on "Course 1" course homepage
And I navigate to "Settings" in current page administration
And I set the following fields to these values:
| Test field | testcontent |
And I press "Save and display"
And I am on "Course 1" course homepage
And I navigate to "Settings" in current page administration
And I set the following fields to these values:
| Test field | testcontent |
And I press "Save and display"
Then I should not see "This value is already used"
And I should see "New section"
Scenario: A course custom field with unique data must allow empty data
When I log in as "teacher1"
And I am on "Course 1" course homepage
And I navigate to "Settings" in current page administration
And I set the following fields to these values:
| Test field | |
And I press "Save and display"
And I am on "Course 2" course homepage
And I navigate to "Settings" in current page administration
And I set the following fields to these values:
| Test field | |
And I press "Save and display"
Then I should not see "This value is already used"
@@ -0,0 +1,275 @@
<?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_customfield;
use core_customfield_generator;
/**
* Functional test for class \core_customfield\category_controller.
*
* @package core_customfield
* @category test
* @copyright 2018 Toni Barbera <toni@moodle.com>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
* @covers \core_customfield\category_controller
*/
class category_controller_test extends \advanced_testcase {
/**
* Get generator.
*
* @return core_customfield_generator
*/
protected function get_generator(): core_customfield_generator {
return $this->getDataGenerator()->get_plugin_generator('core_customfield');
}
/**
* Test for the field_controller::__construct function.
*/
public function test_constructor(): void {
$this->resetAfterTest();
$c = category_controller::create(0, (object)['component' => 'core_course', 'area' => 'course', 'itemid' => 0]);
$handler = $c->get_handler();
$this->assertTrue($c instanceof category_controller);
$cat = $this->get_generator()->create_category();
$c = category_controller::create($cat->get('id'));
$this->assertTrue($c instanceof category_controller);
$c = category_controller::create($cat->get('id'), null, $handler);
$this->assertTrue($c instanceof category_controller);
$c = category_controller::create(0, $cat->to_record());
$this->assertTrue($c instanceof category_controller);
$c = category_controller::create(0, $cat->to_record(), $handler);
$this->assertTrue($c instanceof category_controller);
}
/**
* Test creation of category instance from pre-defined object
*/
public function test_constructor_from_record(): void {
$this->resetAfterTest();
// Create field object that matches the persistent/schema definition.
$category = category_controller::create(0, (object) [
'name' => 'Test',
'description' => null,
'descriptionformat' => null,
'component' => 'core_course',
'area' => 'course',
'itemid' => 0,
'sortorder' => null,
]);
// Saving the category will validate the persistent internally.
$category->save();
$this->assertInstanceOf(category_controller::class, $category);
}
/**
* Test for function \core_customfield\field_controller::create() in case of wrong parameters
*/
public function test_constructor_errors(): void {
global $DB;
$this->resetAfterTest();
$cat = $this->get_generator()->create_category();
$catrecord = $cat->to_record();
// Both id and record give warning.
$c = category_controller::create($catrecord->id, $catrecord);
$debugging = $this->getDebuggingMessages();
$this->assertEquals(1, count($debugging));
$this->assertEquals('Too many parameters, either id need to be specified or a record, but not both.',
$debugging[0]->message);
$this->resetDebugging();
$this->assertTrue($c instanceof category_controller);
// Retrieve non-existing data.
try {
category_controller::create($catrecord->id + 1);
$this->fail('Expected exception');
} catch (\moodle_exception $e) {
$this->assertEquals('Category not found', $e->getMessage());
$this->assertEquals(\moodle_exception::class, get_class($e));
}
// Missing required elements.
try {
category_controller::create(0, (object)['area' => 'course', 'itemid' => 0]);
$this->fail('Expected exception');
} catch (\coding_exception $e) {
$this->assertEquals('Coding error detected, it must be fixed by a programmer: Not enough parameters ' .
'to initialise category_controller - unknown component', $e->getMessage());
$this->assertEquals(\coding_exception::class, get_class($e));
}
// Missing required elements.
try {
category_controller::create(0, (object)['component' => 'core_course', 'itemid' => 0]);
$this->fail('Expected exception');
} catch (\coding_exception $e) {
$this->assertEquals('Coding error detected, it must be fixed by a programmer: Not enough parameters ' .
'to initialise category_controller - unknown area', $e->getMessage());
$this->assertEquals(\coding_exception::class, get_class($e));
}
// Missing required elements.
try {
category_controller::create(0, (object)['component' => 'core_course', 'area' => 'course']);
$this->fail('Expected exception');
} catch (\coding_exception $e) {
$this->assertEquals('Coding error detected, it must be fixed by a programmer: Not enough parameters ' .
'to initialise category_controller - unknown itemid', $e->getMessage());
$this->assertEquals(\coding_exception::class, get_class($e));
}
$handler = \core_course\customfield\course_handler::create();
// Missing required elements.
try {
category_controller::create(0, (object)['component' => 'x', 'area' => 'course', 'itemid' => 0], $handler);
$this->fail('Expected exception');
} catch (\coding_exception $e) {
$this->assertEquals('Coding error detected, it must be fixed by a programmer: Component of the handler ' .
'does not match the one from the record', $e->getMessage());
$this->assertEquals(\coding_exception::class, get_class($e));
}
try {
category_controller::create(0, (object)['component' => 'core_course', 'area' => 'x', 'itemid' => 0], $handler);
$this->fail('Expected exception');
} catch (\coding_exception $e) {
$this->assertEquals('Coding error detected, it must be fixed by a programmer: Area of the handler ' .
'does not match the one from the record', $e->getMessage());
$this->assertEquals(\coding_exception::class, get_class($e));
}
try {
category_controller::create(0, (object)['component' => 'core_course', 'area' => 'course', 'itemid' => 1], $handler);
$this->fail('Expected exception');
} catch (\coding_exception $e) {
$this->assertEquals('Coding error detected, it must be fixed by a programmer: Itemid of the ' .
'handler does not match the one from the record', $e->getMessage());
$this->assertEquals(\coding_exception::class, get_class($e));
}
try {
$user = $this->getDataGenerator()->create_user();
category_controller::create(0, (object)['component' => 'core_course', 'area' => 'course', 'itemid' => 0,
'contextid' => \context_user::instance($user->id)->id], $handler);
$this->fail('Expected exception');
} catch (\coding_exception $e) {
$this->assertEquals('Coding error detected, it must be fixed by a programmer: Context of the ' .
'handler does not match the one from the record', $e->getMessage());
$this->assertEquals(\coding_exception::class, get_class($e));
}
}
/**
* Tests for behaviour of:
* \core_customfield\category_controller::save()
* \core_customfield\category_controller::get()
*/
public function test_create_category(): void {
$this->resetAfterTest();
// Create the category.
$lpg = $this->get_generator();
$categorydata = new \stdClass();
$categorydata->name = 'Category1';
$categorydata->component = 'core_course';
$categorydata->area = 'course';
$categorydata->itemid = 0;
$categorydata->contextid = \context_system::instance()->id;
$category = category_controller::create(0, $categorydata);
$category->save();
$this->assertNotEmpty($category->get('id'));
// Confirm record exists.
$this->assertTrue(\core_customfield\category::record_exists($category->get('id')));
// Confirm that base data was inserted correctly.
$category = category_controller::create($category->get('id'));
$this->assertSame($category->get('name'), $categorydata->name);
$this->assertSame($category->get('component'), $categorydata->component);
$this->assertSame($category->get('area'), $categorydata->area);
$this->assertSame((int)$category->get('itemid'), $categorydata->itemid);
}
/**
* Tests for \core_customfield\category_controller::set() behaviour.
*/
public function test_rename_category(): void {
$this->resetAfterTest();
// Create the category.
$params = ['component' => 'core_course', 'area' => 'course', 'itemid' => 0, 'name' => 'Cat1',
'contextid' => \context_system::instance()->id];
$c1 = category_controller::create(0, (object)$params);
$c1->save();
$this->assertNotEmpty($c1->get('id'));
// Checking new name are correct updated.
$category = category_controller::create($c1->get('id'));
$category->set('name', 'Cat2');
$this->assertSame('Cat2', $category->get('name'));
// Checking new name are correct updated after save.
$category->save();
$category = category_controller::create($c1->get('id'));
$this->assertSame('Cat2', $category->get('name'));
}
/**
* Tests for \core_customfield\category_controller::delete() behaviour.
*/
public function test_delete_category(): void {
$this->resetAfterTest();
// Create the category.
$lpg = $this->get_generator();
$category0 = $lpg->create_category();
$id0 = $category0->get('id');
$category1 = $lpg->create_category();
$id1 = $category1->get('id');
$category2 = $lpg->create_category();
$id2 = $category2->get('id');
// Confirm that exist in the database.
$this->assertTrue(\core_customfield\category::record_exists($id0));
// Delete and confirm that is deleted.
$category0->delete();
$this->assertFalse(\core_customfield\category::record_exists($id0));
// Confirm correct order after delete.
// Check order after re-fetch.
$category1 = category_controller::create($id1);
$category2 = category_controller::create($id2);
$this->assertSame((int) $category1->get('sortorder'), 1);
$this->assertSame((int) $category2->get('sortorder'), 2);
}
}
+180
View File
@@ -0,0 +1,180 @@
<?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_customfield;
use core_customfield_generator;
use customfield_checkbox;
use customfield_date;
use customfield_select;
use customfield_text;
use customfield_textarea;
/**
* Functional test for class data_controller.
*
* @package core_customfield
* @category test
* @copyright 2018 Toni Barbera <toni@moodle.com>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class data_controller_test extends \advanced_testcase {
/**
* Get generator.
*
* @return core_customfield_generator
*/
protected function get_generator(): core_customfield_generator {
return $this->getDataGenerator()->get_plugin_generator('core_customfield');
}
/**
* Test for function data_controller::create()
*/
public function test_constructor(): void {
global $DB;
$this->resetAfterTest();
// Create a course, fields category and fields.
$course = $this->getDataGenerator()->create_course();
$category0 = $this->get_generator()->create_category(['name' => 'aaaa']);
// Add fields to this category.
$fielddata = new \stdClass();
$fielddata->categoryid = $category0->get('id');
$fielddata->configdata = "{\"required\":\"0\",\"uniquevalues\":\"0\",\"locked\":\"0\",\"visibility\":\"0\",
\"defaultvalue\":\"\",\"displaysize\":0,\"maxlength\":0,\"ispassword\":\"0\",
\"link\":\"\",\"linktarget\":\"\"}";
$fielddata->type = 'checkbox';
$field0 = $this->get_generator()->create_field($fielddata);
$fielddata->type = 'date';
$field1 = $this->get_generator()->create_field($fielddata);
$fielddata->type = 'select';
$field2 = $this->get_generator()->create_field($fielddata);
$fielddata->type = 'text';
$field3 = $this->get_generator()->create_field($fielddata);
$fielddata->type = 'textarea';
$field4 = $this->get_generator()->create_field($fielddata);
$params = ['instanceid' => $course->id, 'contextid' => \context_course::instance($course->id)->id];
// Generate new data_controller records for these fields, specifying field controller or fieldid or both.
$data0 = data_controller::create(0, (object)$params, $field0);
$this->assertInstanceOf(customfield_checkbox\data_controller::class, $data0);
$data1 = data_controller::create(0,
(object)($params + ['fieldid' => $field1->get('id')]), $field1);
$this->assertInstanceOf(customfield_date\data_controller::class, $data1);
$data2 = data_controller::create(0,
(object)($params + ['fieldid' => $field2->get('id')]));
$this->assertInstanceOf(customfield_select\data_controller::class, $data2);
$data3 = data_controller::create(0, (object)$params, $field3);
$this->assertInstanceOf(customfield_text\data_controller::class, $data3);
$data4 = data_controller::create(0, (object)$params, $field4);
$this->assertInstanceOf(customfield_textarea\data_controller::class, $data4);
// Save data so we can have ids.
$data0->save();
$data1->save();
$data2->save();
$data3->save();
$data4->save();
// Retrieve data by id.
$this->assertInstanceOf(customfield_checkbox\data_controller::class, data_controller::create($data0->get('id')));
$this->assertInstanceOf(customfield_date\data_controller::class, data_controller::create($data1->get('id')));
// Retrieve data by id and field.
$this->assertInstanceOf(customfield_select\data_controller::class,
data_controller::create($data2->get('id'), null, $field2));
// Retrieve data by record without field.
$datarecord = $DB->get_record(\core_customfield\data::TABLE, ['id' => $data3->get('id')], '*', MUST_EXIST);
$this->assertInstanceOf(customfield_text\data_controller::class, data_controller::create(0, $datarecord));
// Retrieve data by record with field.
$datarecord = $DB->get_record(\core_customfield\data::TABLE, ['id' => $data4->get('id')], '*', MUST_EXIST);
$this->assertInstanceOf(customfield_textarea\data_controller::class, data_controller::create(0, $datarecord, $field4));
}
/**
* Test for function \core_customfield\field_controller::create() in case of wrong parameters
*/
public function test_constructor_errors(): void {
global $DB;
$this->resetAfterTest();
// Create a category, field and data.
$category = $this->get_generator()->create_category();
$field = $this->get_generator()->create_field(['categoryid' => $category->get('id')]);
$course = $this->getDataGenerator()->create_course();
$data = data_controller::create(0, (object)['instanceid' => $course->id,
'contextid' => \context_course::instance($course->id)->id], $field);
$data->save();
$datarecord = $DB->get_record(\core_customfield\data::TABLE, ['id' => $data->get('id')], '*', MUST_EXIST);
// Both id and record give warning.
$d = data_controller::create($datarecord->id, $datarecord);
$debugging = $this->getDebuggingMessages();
$this->assertEquals(1, count($debugging));
$this->assertEquals('Too many parameters, either id need to be specified or a record, but not both.',
$debugging[0]->message);
$this->resetDebugging();
$this->assertInstanceOf(customfield_text\data_controller::class, $d);
// Retrieve non-existing data.
try {
data_controller::create($datarecord->id + 1);
$this->fail('Expected exception');
} catch (\dml_missing_record_exception $e) {
$this->assertStringMatchesFormat('Can\'t find data record in database table customfield_data%a', $e->getMessage());
$this->assertEquals(\dml_missing_record_exception::class, get_class($e));
}
// Missing field id.
try {
data_controller::create(0, (object)['instanceid' => $course->id]);
$this->fail('Expected exception');
} catch (\coding_exception $e) {
$this->assertEquals('Coding error detected, it must be fixed by a programmer: Not enough parameters to ' .
'initialise data_controller - unknown field', $e->getMessage());
$this->assertEquals(\coding_exception::class, get_class($e));
}
// Mismatching field id.
try {
data_controller::create(0, (object)['instanceid' => $course->id, 'fieldid' => $field->get('id') + 1], $field);
$this->fail('Expected exception');
} catch (\coding_exception $e) {
$this->assertEquals('Coding error detected, it must be fixed by a programmer: Field id from the record ' .
'does not match field from the parameter', $e->getMessage());
$this->assertEquals(\coding_exception::class, get_class($e));
}
// Nonexisting class.
try {
$field->set('type', 'invalid');
data_controller::create(0, (object)['instanceid' => $course->id], $field);
$this->fail('Expected exception');
} catch (\moodle_exception $e) {
$this->assertEquals('Field type invalid not found', $e->getMessage());
$this->assertEquals(\moodle_exception::class, get_class($e));
}
}
}
+270
View File
@@ -0,0 +1,270 @@
<?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_customfield;
use core_customfield_generator;
use customfield_checkbox;
use customfield_date;
use customfield_select;
use customfield_text;
use customfield_textarea;
/**
* Functional test for class \core_customfield\field_controller.
*
* @package core_customfield
* @category test
* @copyright 2018 Ruslan Kabalin
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
* @covers \core_customfield\field_controller
*/
class field_controller_test extends \advanced_testcase {
/**
* Get generator.
*
* @return core_customfield_generator
*/
protected function get_generator(): core_customfield_generator {
return $this->getDataGenerator()->get_plugin_generator('core_customfield');
}
/**
* Test for function \core_customfield\field_controller::create()
*/
public function test_constructor(): void {
global $DB;
$this->resetAfterTest();
// Create the category.
$category0 = $this->get_generator()->create_category();
// Initiate objects without id, try with the category object or with category id or with both.
$field0 = field_controller::create(0, (object)['type' => 'checkbox'], $category0);
$this->assertInstanceOf(customfield_checkbox\field_controller::class, $field0);
$field1 = field_controller::create(0, (object)['type' => 'date', 'categoryid' => $category0->get('id')]);
$this->assertInstanceOf(customfield_date\field_controller::class, $field1);
$field2 = field_controller::create(0, (object)['type' => 'select', 'categoryid' => $category0->get('id')], $category0);
$this->assertInstanceOf(customfield_select\field_controller::class, $field2);
$field3 = field_controller::create(0, (object)['type' => 'text'], $category0);
$this->assertInstanceOf(customfield_text\field_controller::class, $field3);
$field4 = field_controller::create(0, (object)['type' => 'textarea'], $category0);
$this->assertInstanceOf(customfield_textarea\field_controller::class, $field4);
// Save fields to the db so we have ids.
\core_customfield\api::save_field_configuration($field0, (object)['name' => 'a', 'shortname' => 'a']);
\core_customfield\api::save_field_configuration($field1, (object)['name' => 'b', 'shortname' => 'b']);
\core_customfield\api::save_field_configuration($field2, (object)['name' => 'c', 'shortname' => 'c']);
\core_customfield\api::save_field_configuration($field3, (object)['name' => 'd', 'shortname' => 'd']);
\core_customfield\api::save_field_configuration($field4, (object)['name' => 'e', 'shortname' => 'e']);
// Retrieve fields by id.
$this->assertInstanceOf(customfield_checkbox\field_controller::class, field_controller::create($field0->get('id')));
$this->assertInstanceOf(customfield_date\field_controller::class, field_controller::create($field1->get('id')));
// Retrieve field by id and category.
$this->assertInstanceOf(customfield_select\field_controller::class,
field_controller::create($field2->get('id'), null, $category0));
// Retrieve fields by record without category.
$fieldrecord = $DB->get_record(\core_customfield\field::TABLE, ['id' => $field3->get('id')], '*', MUST_EXIST);
$this->assertInstanceOf(customfield_text\field_controller::class, field_controller::create(0, $fieldrecord));
// Retrieve fields by record with category.
$fieldrecord = $DB->get_record(\core_customfield\field::TABLE, ['id' => $field4->get('id')], '*', MUST_EXIST);
$this->assertInstanceOf(customfield_textarea\field_controller::class,
field_controller::create(0, $fieldrecord, $category0));
}
/**
* Test creation of field instance from pre-defined object
*/
public function test_constructor_from_record(): void {
$this->resetAfterTest();
// Create field object that matches the persistent/schema definition.
$category = $this->get_generator()->create_category();
$field = field_controller::create(0, (object) [
'name' => 'Test',
'shortname' => 'test',
'type' => 'text',
'description' => null,
'descriptionformat' => null,
'sortorder' => null,
'configdata' => null,
], $category);
// Saving the field will validate the persistent internally.
$field->save();
$this->assertInstanceOf(\customfield_text\field_controller::class, $field);
}
/**
* Test for function \core_customfield\field_controller::create() in case of wrong parameters
*/
public function test_constructor_errors(): void {
global $DB;
$this->resetAfterTest();
// Create a category and a field.
$category = $this->get_generator()->create_category();
$field = $this->get_generator()->create_field(['categoryid' => $category->get('id')]);
$fieldrecord = $DB->get_record(\core_customfield\field::TABLE, ['id' => $field->get('id')], '*', MUST_EXIST);
// Both id and record give warning.
$field = field_controller::create($fieldrecord->id, $fieldrecord);
$debugging = $this->getDebuggingMessages();
$this->assertEquals(1, count($debugging));
$this->assertEquals('Too many parameters, either id need to be specified or a record, but not both.',
$debugging[0]->message);
$this->resetDebugging();
$this->assertInstanceOf(customfield_text\field_controller::class, $field);
// Retrieve non-existing field.
try {
field_controller::create($fieldrecord->id + 1);
$this->fail('Expected exception');
} catch (\moodle_exception $e) {
$this->assertEquals('Field not found', $e->getMessage());
$this->assertEquals(\moodle_exception::class, get_class($e));
}
// Retrieve without id and without type.
try {
field_controller::create(0, (object)['name' => 'a'], $category);
$this->fail('Expected exception');
} catch (\coding_exception $e) {
$this->assertEquals('Coding error detected, it must be fixed by a programmer: Not enough parameters to ' .
'initialise field_controller - unknown field type', $e->getMessage());
$this->assertEquals(\coding_exception::class, get_class($e));
}
// Missing category id.
try {
field_controller::create(0, (object)['type' => 'text']);
$this->fail('Expected exception');
} catch (\coding_exception $e) {
$this->assertEquals('Coding error detected, it must be fixed by a programmer: Not enough parameters ' .
'to initialise field_controller - unknown category', $e->getMessage());
$this->assertEquals(\coding_exception::class, get_class($e));
}
// Mismatching category id.
try {
field_controller::create(0, (object)['type' => 'text', 'categoryid' => $category->get('id') + 1], $category);
$this->fail('Expected exception');
} catch (\coding_exception $e) {
$this->assertEquals('Coding error detected, it must be fixed by a programmer: Category of the field ' .
'does not match category from the parameter', $e->getMessage());
$this->assertEquals(\coding_exception::class, get_class($e));
}
// Non-existing type.
try {
field_controller::create(0, (object)['type' => 'nonexisting'], $category);
$this->fail('Expected exception');
} catch (\moodle_exception $e) {
$this->assertEquals('Field type nonexisting not found', $e->getMessage());
$this->assertEquals(\moodle_exception::class, get_class($e));
}
}
/**
* Tests for behaviour of:
* \core_customfield\field_controller::save()
* \core_customfield\field_controller::get()
* \core_customfield\field_controller::get_category()
*/
public function test_create_field(): void {
global $DB;
$this->resetAfterTest();
$lpg = $this->get_generator();
$category = $lpg->create_category();
$fields = $DB->get_records(\core_customfield\field::TABLE, ['categoryid' => $category->get('id')]);
$this->assertCount(0, $fields);
// Create field.
$fielddata = new \stdClass();
$fielddata->name = 'Field';
$fielddata->shortname = 'field';
$fielddata->type = 'text';
$fielddata->categoryid = $category->get('id');
$field = field_controller::create(0, $fielddata);
$field->save();
$fields = $DB->get_records(\core_customfield\field::TABLE, ['categoryid' => $category->get('id')]);
$this->assertCount(1, $fields);
$this->assertTrue(\core_customfield\field::record_exists($field->get('id')));
$this->assertInstanceOf(\customfield_text\field_controller::class, $field);
$this->assertSame($field->get('name'), $fielddata->name);
$this->assertSame($field->get('type'), $fielddata->type);
$this->assertEquals($field->get_category()->get('id'), $category->get('id'));
}
/**
* Tests for \core_customfield\field_controller::delete() behaviour.
*/
public function test_delete_field(): void {
global $DB;
$this->resetAfterTest();
$lpg = $this->get_generator();
$category = $lpg->create_category();
$fields = $DB->get_records(\core_customfield\field::TABLE, ['categoryid' => $category->get('id')]);
$this->assertCount(0, $fields);
// Create field using generator.
$field1 = $lpg->create_field(array('categoryid' => $category->get('id')));
$field2 = $lpg->create_field(array('categoryid' => $category->get('id')));
$fields = $DB->get_records(\core_customfield\field::TABLE, ['categoryid' => $category->get('id')]);
$this->assertCount(2, $fields);
// Delete fields.
$this->assertTrue($field1->delete());
$this->assertTrue($field2->delete());
// Check that the fields have been deleted.
$fields = $DB->get_records(\core_customfield\field::TABLE, ['categoryid' => $category->get('id')]);
$this->assertCount(0, $fields);
$this->assertFalse(\core_customfield\field::record_exists($field1->get('id')));
$this->assertFalse(\core_customfield\field::record_exists($field2->get('id')));
}
/**
* Tests for \core_customfield\field_controller::get_configdata_property() behaviour.
*/
public function test_get_configdata_property(): void {
$this->resetAfterTest();
$lpg = $this->get_generator();
$category = $lpg->create_category();
$configdata = ['a' => 'b', 'c' => ['d', 'e']];
$field = field_controller::create(0, (object)['type' => 'text',
'configdata' => json_encode($configdata), 'shortname' => 'a', 'name' => 'a'], $category);
$field->save();
// Retrieve field and check configdata.
$field = field_controller::create($field->get('id'));
$this->assertEquals($configdata, $field->get('configdata'));
$this->assertEquals('b', $field->get_configdata_property('a'));
$this->assertEquals(['d', 'e'], $field->get_configdata_property('c'));
$this->assertEquals(null, $field->get_configdata_property('x'));
}
}
+79
View File
@@ -0,0 +1,79 @@
<?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/>.
/**
* Class core_customfield_test_instance_form
*
* @package core_customfield
* @copyright 2019 Marina Glancy
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
defined('MOODLE_INTERNAL') || die();
global $CFG;
require_once($CFG->libdir . '/formslib.php');
/**
* Class core_customfield_test_instance_form
*
* @package core_customfield
* @copyright 2019 Marina Glancy
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class core_customfield_test_instance_form extends moodleform {
/** @var \core_customfield\handler */
protected $handler;
/** @var stdClass */
protected $instance;
/**
* Form definition
*/
public function definition() {
$this->handler = $this->_customdata['handler'];
$this->instance = $this->_customdata['instance'];
$this->_form->addElement('hidden', 'id');
$this->_form->setType('id', PARAM_INT);
$this->handler->instance_form_definition($this->_form, $this->instance->id);
$this->add_action_buttons();
$this->handler->instance_form_before_set_data($this->instance);
$this->set_data($this->instance);
}
/**
* Definition after data
*/
public function definition_after_data() {
$this->handler->instance_form_definition_after_data($this->_form, $this->instance->id);
}
/**
* Form validation
*
* @param array $data
* @param array $files
* @return array
*/
public function validation($data, $files) {
return $this->handler->instance_form_validation($data, $files);
}
}
+164
View File
@@ -0,0 +1,164 @@
<?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/>.
/**
* Customfield data generator.
*
* @package core_customfield
* @category test
* @copyright 2018 Ruslan Kabalin
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
defined('MOODLE_INTERNAL') || die();
use \core_customfield\category_controller;
use \core_customfield\field_controller;
use \core_customfield\api;
/**
* Customfield data generator class.
*
* @package core_customfield
* @category test
* @copyright 2018 Ruslan Kabalin
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class core_customfield_generator extends component_generator_base {
/** @var int Number of created categories. */
protected $categorycount = 0;
/** @var int Number of created fields. */
protected $fieldcount = 0;
/**
* Create a new category.
*
* @param array|stdClass $record
* @return category_controller
*/
public function create_category($record = null) {
$this->categorycount++;
$i = $this->categorycount;
$record = (object) $record;
if (!isset($record->name)) {
$record->name = "Category $i";
}
if (!isset($record->component)) {
$record->component = 'core_course';
}
if (!isset($record->area)) {
$record->area = 'course';
}
if (!isset($record->itemid)) {
$record->itemid = 0;
}
$handler = \core_customfield\handler::get_handler($record->component, $record->area, $record->itemid);
$categoryid = $handler->create_category($record->name);
return $handler->get_categories_with_fields()[$categoryid];
}
/**
* Create a new field.
*
* @param array|stdClass $record
* @return field_controller
*/
public function create_field($record): field_controller {
$this->fieldcount++;
$i = $this->fieldcount;
$record = (object) $record;
if (empty($record->categoryid)) {
throw new coding_exception('The categoryid value is required.');
}
$category = category_controller::create($record->categoryid);
$handler = $category->get_handler();
if (!isset($record->name)) {
$record->name = "Field $i";
}
if (!isset($record->shortname)) {
$record->shortname = "fld$i";
}
if (!property_exists($record, 'description')) {
$record->description = "Field $i description";
}
if (!isset($record->descriptionformat)) {
$record->descriptionformat = FORMAT_HTML;
}
if (!isset($record->type)) {
$record->type = 'text';
}
if (!isset($record->sortorder)) {
$record->sortorder = 0;
}
if (empty($record->configdata)) {
$configdata = [];
} else if (is_array($record->configdata)) {
$configdata = $record->configdata;
} else {
$configdata = @json_decode($record->configdata, true);
$configdata = $configdata ?? [];
}
$configdata += [
'required' => 0,
'uniquevalues' => 0,
'locked' => 0,
'visibility' => 2,
'defaultvalue' => '',
'defaultvalueformat' => FORMAT_MOODLE,
'displaysize' => 0,
'maxlength' => 0,
'ispassword' => 0,
'link' => '',
'linktarget' => '',
'checkbydefault' => 0,
'startyear' => 2000,
'endyear' => 3000,
'includetime' => 1,
];
$record->configdata = json_encode($configdata);
$field = field_controller::create(0, (object)['type' => $record->type], $category);
$handler->save_field_configuration($field, $record);
return $handler->get_categories_with_fields()[$field->get('categoryid')]->get_fields()[$field->get('id')];
}
/**
* Adds instance data for one field
*
* @param field_controller $field
* @param int $instanceid
* @param mixed $value
* @return \core_customfield\data_controller
*/
public function add_instance_data(field_controller $field, int $instanceid, $value): \core_customfield\data_controller {
$data = \core_customfield\data_controller::create(0, (object)['instanceid' => $instanceid], $field);
$data->set('contextid', $data->get_context()->id);
$rc = new ReflectionClass(get_class($data));
$rcm = $rc->getMethod('get_form_element_name');
$formelementname = $rcm->invokeArgs($data, []);
$record = (object)[$formelementname => $value];
$data->instance_form_save($record);
return $data;
}
}
+105
View File
@@ -0,0 +1,105 @@
<?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_customfield;
/**
* core_customfield test data generator testcase.
*
* @package core_customfield
* @category test
* @copyright 2018 Ruslan Kabalin
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class generator_test extends \advanced_testcase {
/**
* Get generator
* @return core_customfield_generator
*/
protected function get_generator(): \core_customfield_generator {
return $this->getDataGenerator()->get_plugin_generator('core_customfield');
}
/**
* Test creating category
*/
public function test_create_category(): void {
$this->resetAfterTest(true);
$lpg = $this->get_generator();
$category = $lpg->create_category();
$this->assertInstanceOf('\core_customfield\category_controller', $category);
$this->assertTrue(\core_customfield\category::record_exists($category->get('id')));
}
/**
* Test creating field
*/
public function test_create_field(): void {
$this->resetAfterTest(true);
$lpg = $this->get_generator();
$category = $lpg->create_category();
$field = $lpg->create_field(['categoryid' => $category->get('id')]);
$this->assertInstanceOf('\core_customfield\field_controller', $field);
$this->assertTrue(\core_customfield\field::record_exists($field->get('id')));
$category = \core_customfield\category_controller::create($category->get('id'));
$category = \core_customfield\api::get_categories_with_fields($category->get('component'),
$category->get('area'), $category->get('itemid'))[$category->get('id')];
$this->assertCount(1, $category->get_fields());
}
/**
* Test for function add_instance_data()
*/
public function test_add_instance_data(): void {
$this->resetAfterTest(true);
$lpg = $this->get_generator();
$c1 = $lpg->create_category();
$course1 = $this->getDataGenerator()->create_course();
$f11 = $this->get_generator()->create_field(['categoryid' => $c1->get('id'), 'type' => 'checkbox']);
$f12 = $this->get_generator()->create_field(['categoryid' => $c1->get('id'), 'type' => 'date']);
$f13 = $this->get_generator()->create_field(['categoryid' => $c1->get('id'),
'type' => 'select', 'configdata' => ['options' => "a\nb\nc"]]);
$f14 = $this->get_generator()->create_field(['categoryid' => $c1->get('id'), 'type' => 'text']);
$f15 = $this->get_generator()->create_field(['categoryid' => $c1->get('id'), 'type' => 'textarea']);
$this->get_generator()->add_instance_data($f11, $course1->id, 1);
$this->get_generator()->add_instance_data($f12, $course1->id, 1546300800);
$this->get_generator()->add_instance_data($f13, $course1->id, 2);
$this->get_generator()->add_instance_data($f14, $course1->id, 'Hello');
$this->get_generator()->add_instance_data($f15, $course1->id, ['text' => '<p>Hi there</p>', 'format' => FORMAT_HTML]);
$handler = $c1->get_handler();
list($data1, $data2, $data3, $data4, $data5) = array_values($handler->get_instance_data($course1->id));
$this->assertNotEmpty($data1->get('id'));
$this->assertEquals(1, $data1->get_value());
$this->assertNotEmpty($data2->get('id'));
$this->assertEquals(1546300800, $data2->get_value());
$this->assertNotEmpty($data3->get('id'));
$this->assertEquals(2, $data3->get_value());
$this->assertNotEmpty($data4->get('id'));
$this->assertEquals('Hello', $data4->get_value());
$this->assertNotEmpty($data5->get('id'));
$this->assertEquals('<p>Hi there</p>', $data5->get_value());
}
}
+51
View File
@@ -0,0 +1,51 @@
<?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/>.
declare(strict_types=1);
namespace core_customfield;
use advanced_testcase;
use core_course\customfield\course_handler;
use moodle_exception;
/**
* Unit tests for the abstract custom fields handler
*
* @package core_customfield
* @covers \core_customfield\handler
* @copyright 2023 Paul Holden <paulh@moodle.com>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class handler_test extends advanced_testcase {
/**
* Test retrieving handler for given component/area
*/
public function test_get_handler(): void {
$handler = handler::get_handler('core_course', 'course');
$this->assertInstanceOf(course_handler::class, $handler);
}
/**
* Test retrieving handler for invalid component/area
*/
public function test_get_handler_invalid(): void {
$this->expectException(moodle_exception::class);
$this->expectExceptionMessage('Unable to find handler for custom fields for component core_blimey and area test');
handler::get_handler('core_blimey', 'test');
}
}
+290
View File
@@ -0,0 +1,290 @@
<?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/>.
/**
* Class provider_test
*
* @package core_customfield
* @copyright 2019 Marina Glancy
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
namespace core_customfield\privacy;
defined('MOODLE_INTERNAL') || die();
use core_privacy\tests\provider_testcase;
use core_privacy\local\request\approved_contextlist;
use core_privacy\local\request\writer;
use core_customfield\privacy\provider;
/**
* Class provider_test
*
* @package core_customfield
* @copyright 2019 Marina Glancy
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class provider_test extends provider_testcase {
/**
* Generate data.
*
* @return array
*/
protected function generate_test_data(): array {
$this->resetAfterTest();
$generator = $this->getDataGenerator()->get_plugin_generator('core_customfield');
$cfcats[1] = $generator->create_category();
$cfcats[2] = $generator->create_category();
$cffields[11] = $generator->create_field(
['categoryid' => $cfcats[1]->get('id'), 'type' => 'checkbox']);
$cffields[12] = $generator->create_field(
['categoryid' => $cfcats[1]->get('id'), 'type' => 'date']);
$cffields[13] = $generator->create_field(
['categoryid' => $cfcats[1]->get('id'),
'type' => 'select', 'configdata' => ['options' => "a\nb\nc"]]);
$cffields[14] = $generator->create_field(
['categoryid' => $cfcats[1]->get('id'), 'type' => 'text']);
$cffields[15] = $generator->create_field(
['categoryid' => $cfcats[1]->get('id'), 'type' => 'textarea']);
$cffields[21] = $generator->create_field(
['categoryid' => $cfcats[2]->get('id')]);
$cffields[22] = $generator->create_field(
['categoryid' => $cfcats[2]->get('id')]);
$courses[1] = $this->getDataGenerator()->create_course();
$courses[2] = $this->getDataGenerator()->create_course();
$courses[3] = $this->getDataGenerator()->create_course();
$generator->add_instance_data($cffields[11], $courses[1]->id, 1);
$generator->add_instance_data($cffields[12], $courses[1]->id, 1546300800);
$generator->add_instance_data($cffields[13], $courses[1]->id, 2);
$generator->add_instance_data($cffields[14], $courses[1]->id, 'Hello1');
$generator->add_instance_data($cffields[15], $courses[1]->id,
['text' => '<p>Hi there</p>', 'format' => FORMAT_HTML]);
$generator->add_instance_data($cffields[21], $courses[1]->id, 'hihi1');
$generator->add_instance_data($cffields[14], $courses[2]->id, 'Hello2');
$generator->add_instance_data($cffields[21], $courses[2]->id, 'hihi2');
$user = $this->getDataGenerator()->create_user();
$this->setUser($user);
return [
'user' => $user,
'cfcats' => $cfcats,
'cffields' => $cffields,
'courses' => $courses,
];
}
/**
* Test for provider::get_metadata()
*/
public function test_get_metadata(): void {
$collection = new \core_privacy\local\metadata\collection('core_customfield');
$collection = provider::get_metadata($collection);
$this->assertNotEmpty($collection);
}
/**
* Test for provider::get_customfields_data_contexts
*/
public function test_get_customfields_data_contexts(): void {
global $DB;
[
'cffields' => $cffields,
'cfcats' => $cfcats,
'courses' => $courses,
] = $this->generate_test_data();
list($sql, $params) = $DB->get_in_or_equal([$courses[1]->id, $courses[2]->id], SQL_PARAMS_NAMED);
$r = provider::get_customfields_data_contexts('core_course', 'course', '=0',
$sql, $params);
$this->assertEqualsCanonicalizing([\context_course::instance($courses[1]->id)->id,
\context_course::instance($courses[2]->id)->id],
$r->get_contextids());
}
/**
* Test for provider::get_customfields_configuration_contexts()
*/
public function test_get_customfields_configuration_contexts(): void {
$this->generate_test_data();
$r = provider::get_customfields_configuration_contexts('core_course', 'course');
$this->assertEquals([\context_system::instance()->id], $r->get_contextids());
}
/**
* Test for provider::export_customfields_data()
*/
public function test_export_customfields_data(): void {
global $USER, $DB;
$this->resetAfterTest();
[
'cffields' => $cffields,
'cfcats' => $cfcats,
'courses' => $courses,
] = $this->generate_test_data();
// Hack one of the fields so it has an invalid field type.
$invalidfieldid = $cffields[21]->get('id');
$DB->update_record('customfield_field', ['id' => $invalidfieldid, 'type' => 'invalid']);
$context = \context_course::instance($courses[1]->id);
$contextlist = new approved_contextlist($USER, 'core_customfield', [$context->id]);
provider::export_customfields_data($contextlist, 'core_course', 'course', '=0', '=:i', ['i' => $courses[1]->id]);
/** @var core_privacy\tests\request\content_writer $writer */
$writer = writer::with_context($context);
// Make sure that all and only data for the course1 was exported.
// There is no way to fetch all data from writer as array so we need to fetch one-by-one for each data id.
$invaldfieldischecked = false;
foreach ($DB->get_records('customfield_data', []) as $dbrecord) {
$data = $writer->get_data(['Custom fields data', $dbrecord->id]);
if ($dbrecord->instanceid == $courses[1]->id) {
$this->assertEquals($dbrecord->fieldid, $data->fieldid);
$this->assertNotEmpty($data->fieldtype);
$this->assertNotEmpty($data->fieldshortname);
$this->assertNotEmpty($data->fieldname);
$invaldfieldischecked = $invaldfieldischecked ?: ($data->fieldid == $invalidfieldid);
} else {
$this->assertEmpty($data);
}
}
// Make sure field with was checked in this test.
$this->assertTrue($invaldfieldischecked);
}
/**
* Test for provider::delete_customfields_data()
*/
public function test_delete_customfields_data(): void {
global $USER, $DB;
$this->resetAfterTest();
[
'cffields' => $cffields,
'cfcats' => $cfcats,
'courses' => $courses,
] = $this->generate_test_data();
$approvedcontexts = new approved_contextlist($USER, 'core_course', [\context_course::instance($courses[1]->id)->id]);
provider::delete_customfields_data($approvedcontexts, 'core_course', 'course');
$this->assertEmpty($DB->get_records('customfield_data', ['instanceid' => $courses[1]->id]));
$this->assertNotEmpty($DB->get_records('customfield_data', ['instanceid' => $courses[2]->id]));
}
/**
* Test for provider::delete_customfields_configuration()
*/
public function test_delete_customfields_configuration(): void {
global $USER, $DB;
$this->resetAfterTest();
[
'cffields' => $cffields,
'cfcats' => $cfcats,
'courses' => $courses,
] = $this->generate_test_data();
// Remember the list of fields in the category 2 before we delete it.
$catid1 = $cfcats[1]->get('id');
$catid2 = $cfcats[2]->get('id');
$fids2 = $DB->get_fieldset_select('customfield_field', 'id', 'categoryid=?', [$catid2]);
$this->assertNotEmpty($fids2);
list($fsql, $fparams) = $DB->get_in_or_equal($fids2, SQL_PARAMS_NAMED);
$this->assertNotEmpty($DB->get_records_select('customfield_data', 'fieldid ' . $fsql, $fparams));
// A little hack here, modify customfields configuration so they have different itemids.
$DB->update_record('customfield_category', ['id' => $catid2, 'itemid' => 1]);
$contextlist = new approved_contextlist($USER, 'core_course', [\context_system::instance()->id]);
provider::delete_customfields_configuration($contextlist, 'core_course', 'course', '=:i', ['i' => 1]);
// Make sure everything for category $catid2 is gone but present for $catid1.
$this->assertEmpty($DB->get_records('customfield_category', ['id' => $catid2]));
$this->assertEmpty($DB->get_records_select('customfield_field', 'id ' . $fsql, $fparams));
$this->assertEmpty($DB->get_records_select('customfield_data', 'fieldid ' . $fsql, $fparams));
$this->assertNotEmpty($DB->get_records('customfield_category', ['id' => $catid1]));
$fids1 = $DB->get_fieldset_select('customfield_field', 'id', 'categoryid=?', [$catid1]);
list($fsql1, $fparams1) = $DB->get_in_or_equal($fids1, SQL_PARAMS_NAMED);
$this->assertNotEmpty($DB->get_records_select('customfield_field', 'id ' . $fsql1, $fparams1));
$this->assertNotEmpty($DB->get_records_select('customfield_data', 'fieldid ' . $fsql1, $fparams1));
}
/**
* Test for provider::delete_customfields_configuration_for_context()
*/
public function test_delete_customfields_configuration_for_context(): void {
global $USER, $DB;
$this->resetAfterTest();
[
'cffields' => $cffields,
'cfcats' => $cfcats,
'courses' => $courses,
] = $this->generate_test_data();
// Remember the list of fields in the category 2 before we delete it.
$catid1 = $cfcats[1]->get('id');
$catid2 = $cfcats[2]->get('id');
$fids2 = $DB->get_fieldset_select('customfield_field', 'id', 'categoryid=?', [$catid2]);
$this->assertNotEmpty($fids2);
list($fsql, $fparams) = $DB->get_in_or_equal($fids2, SQL_PARAMS_NAMED);
$this->assertNotEmpty($DB->get_records_select('customfield_data', 'fieldid ' . $fsql, $fparams));
// A little hack here, modify customfields configuration so they have different contexts.
$context = \context_user::instance($USER->id);
$DB->update_record('customfield_category', ['id' => $catid2, 'contextid' => $context->id]);
provider::delete_customfields_configuration_for_context('core_course', 'course', $context);
// Make sure everything for category $catid2 is gone but present for $catid1.
$this->assertEmpty($DB->get_records('customfield_category', ['id' => $catid2]));
$this->assertEmpty($DB->get_records_select('customfield_field', 'id ' . $fsql, $fparams));
$this->assertEmpty($DB->get_records_select('customfield_data', 'fieldid ' . $fsql, $fparams));
$this->assertNotEmpty($DB->get_records('customfield_category', ['id' => $catid1]));
$fids1 = $DB->get_fieldset_select('customfield_field', 'id', 'categoryid=?', [$catid1]);
list($fsql1, $fparams1) = $DB->get_in_or_equal($fids1, SQL_PARAMS_NAMED);
$this->assertNotEmpty($DB->get_records_select('customfield_field', 'id ' . $fsql1, $fparams1));
$this->assertNotEmpty($DB->get_records_select('customfield_data', 'fieldid ' . $fsql1, $fparams1));
}
/**
* Test for provider::delete_customfields_data_for_context()
*/
public function test_delete_customfields_data_for_context(): void {
global $DB;
$this->resetAfterTest();
[
'cffields' => $cffields,
'cfcats' => $cfcats,
'courses' => $courses,
] = $this->generate_test_data();
provider::delete_customfields_data_for_context('core_course', 'course',
\context_course::instance($courses[1]->id));
$fids2 = $DB->get_fieldset_select('customfield_field', 'id', '1=1', []);
list($fsql, $fparams) = $DB->get_in_or_equal($fids2, SQL_PARAMS_NAMED);
$fparams['course1'] = $courses[1]->id;
$fparams['course2'] = $courses[2]->id;
$this->assertEmpty($DB->get_records_select('customfield_data', 'instanceid = :course1 AND fieldid ' . $fsql, $fparams));
$this->assertNotEmpty($DB->get_records_select('customfield_data', 'instanceid = :course2 AND fieldid ' . $fsql, $fparams));
}
}