ceab97ed0235212f0f20a71158546c3caf415189
[moodle.git] / mod / data / tests / search_test.php
1 <?php
2 // This file is part of Moodle - http://moodle.org/
3 //
4 // Moodle is free software: you can redistribute it and/or modify
5 // it under the terms of the GNU General Public License as published by
6 // the Free Software Foundation, either version 3 of the License, or
7 // (at your option) any later version.
8 //
9 // Moodle is distributed in the hope that it will be useful,
10 // but WITHOUT ANY WARRANTY; without even the implied warranty of
11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12 // GNU General Public License for more details.
13 //
14 // You should have received a copy of the GNU General Public License
15 // along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
17 /**
18  * Unit tests for data_get_all_recordsids(), data_get_advance_search_ids(), data_get_record_ids(),
19  * and data_get_advanced_search_sql()
20  *
21  * @package    mod_data
22  * @category   phpunit
23  * @copyright  2012 Adrian Greeve
24  * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
25  */
27 defined('MOODLE_INTERNAL') || die();
29 global $CFG;
30 require_once($CFG->dirroot . '/mod/data/lib.php');
31 require_once($CFG->dirroot . '/lib/datalib.php');
32 require_once($CFG->dirroot . '/lib/csvlib.class.php');
33 require_once($CFG->dirroot . '/search/tests/fixtures/testable_core_search.php');
34 require_once($CFG->dirroot . '/mod/data/tests/generator/lib.php');
36 /**
37  * Unit tests for {@see data_get_all_recordids()}.
38  *                {@see data_get_advanced_search_ids()}
39  *                {@see data_get_record_ids()}
40  *                {@see data_get_advanced_search_sql()}
41  *
42  * @package    mod_data
43  * @copyright  2012 Adrian Greeve
44  * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
45  */
46 class mod_data_search_test extends advanced_testcase {
47     /**
48      * @var stdObject $recorddata An object that holds information from the table data.
49      */
50     public $recorddata = null;
51     /**
52      * @var int $recordcontentid The content ID.
53      */
54     public $recordcontentid = null;
55     /**
56      * @var int $recordrecordid The record ID.
57      */
58     public $recordrecordid = null;
59     /**
60      * @var int $recordfieldid The field ID.
61      */
62     public $recordfieldid = null;
63     /**
64      * @var array $recordsearcharray An array of stdClass which contains search criteria.
65      */
66     public $recordsearcharray = null;
68     // CONSTANTS
70     /**
71      * @var int $datarecordcount   The number of records in the database.
72      */
73     public $datarecordcount = 100;
75     /**
76      * @var int $groupdatarecordcount  The number of records in the database in groups 0 and 1.
77      */
78     public $groupdatarecordcount = 75;
80     /**
81      * @var array $datarecordset   Expected record IDs.
82      */
83     public $datarecordset = array('0' => '6');
85     /**
86      * @var array $finalrecord   Final record for comparison with test four.
87      */
88     public $finalrecord = array();
90     /**
91      * @var int $approvedatarecordcount  The number of approved records in the database.
92      */
93     public $approvedatarecordcount = 89;
95     /**
96      * @var string Area id
97      */
98     protected $databaseentryareaid = null;
100     /**
101      * Set up function. In this instance we are setting up database
102      * records to be used in the unit tests.
103      */
104     protected function setUp(): void {
105         global $DB, $CFG;
106         parent::setUp();
108         $this->resetAfterTest(true);
110         set_config('enableglobalsearch', true);
112         $this->databaseentryareaid = \core_search\manager::generate_areaid('mod_data', 'entry');
114         // Set \core_search::instance to the mock_search_engine as we don't require the search engine to be working to test this.
115         $search = testable_core_search::instance();
117     }
119     /**
120      * Test 1: The function data_get_all_recordids.
121      *
122      * Test 2: This tests the data_get_advance_search_ids() function. The function takes a set
123      * of all the record IDs in the database and then with the search details ($this->recordsearcharray)
124      * returns a comma seperated string of record IDs that match the search criteria.
125      *
126      * Test 3: This function tests data_get_recordids(). This is the function that is nested in the last
127      * function (see data_get_advance_search_ids). This function takes a couple of
128      * extra parameters. $alias is the field alias used in the sql query and $commaid
129      * is a comma seperated string of record IDs.
130      *
131      * Test 3.1: This tests that if no recordids are provided (In a situation where a search is done on an empty database)
132      * That an empty array is returned.
133      *
134      * Test 4: data_get_advanced_search_sql provides an array which contains an sql string to be used for displaying records
135      * to the user when they use the advanced search criteria and the parameters that go with the sql statement. This test
136      * takes that information and does a search on the database, returning a record.
137      *
138      * Test 5: Returning to data_get_all_recordids(). Here we are ensuring that the total amount of record ids is reduced to
139      * match the group conditions that are provided. There are 25 entries which relate to group 2. They are removed
140      * from the total so we should only have 75 records total.
141      *
142      * Test 6: data_get_all_recordids() again. This time we are testing approved database records. We only want to
143      * display the records that have been approved. In this record set we have 89 approved records.
144      */
145     public function test_advanced_search_sql_section() {
146         global $DB;
148         // we already have 2 users, we need 98 more - let's ignore the fact that guest can not post anywhere
149         // We reset the user sequence here to ensure we get the expected numbers.
150         // TODO: Invent a better way for managing data file input against database sequence id's.
151         $DB->get_manager()->reset_sequence('user');
152         for($i=3;$i<=100;$i++) {
153             $this->getDataGenerator()->create_user();
154         }
156         // create database module - there should be more of these I guess
157         $course = $this->getDataGenerator()->create_course();
158         $data = $this->getDataGenerator()->create_module('data', array('course'=>$course->id));
159         $this->recorddata = $data;
161         // Set up data for the test database.
162         $files = array(
163                 'data_fields'  => __DIR__.'/fixtures/test_data_fields.csv',
164                 'data_records' => __DIR__.'/fixtures/test_data_records.csv',
165                 'data_content' => __DIR__.'/fixtures/test_data_content.csv',
166         );
167         $this->loadDataSet($this->createCsvDataSet($files));
168         // Set dataid to the correct value now the data has been inserted by csv file.
169         $DB->execute('UPDATE {data_fields} SET dataid = ?', array($data->id));
170         $DB->execute('UPDATE {data_records} SET dataid = ?', array($data->id));
172         // Create the search array which contains our advanced search criteria.
173         $fieldinfo = array('0' => new stdClass(),
174                 '1' => new stdClass(),
175                 '2' => new stdClass(),
176                 '3' => new stdClass(),
177                 '4' => new stdClass());
178         $fieldinfo['0']->id = 1;
179         $fieldinfo['0']->data = '3.721,46.6126';
180         $fieldinfo['1']->id = 2;
181         $fieldinfo['1']->data = 'Hahn Premium';
182         $fieldinfo['2']->id = 5;
183         $fieldinfo['2']->data = 'Female';
184         $fieldinfo['3']->id = 7;
185         $fieldinfo['3']->data = 'kel';
186         $fieldinfo['4']->id = 9;
187         $fieldinfo['4']->data = 'VIC';
189         foreach($fieldinfo as $field) {
190             $searchfield = data_get_field_from_id($field->id, $data);
191             if ($field->id == 2) {
192                 $searchfield->field->param1 = 'Hahn Premium';
193                 $val = array();
194                 $val['selected'] = array('0' => 'Hahn Premium');
195                 $val['allrequired'] = 0;
196             } else {
197                 $val = $field->data;
198             }
199             $search_array[$field->id] = new stdClass();
200             list($search_array[$field->id]->sql, $search_array[$field->id]->params) = $searchfield->generate_sql('c' . $field->id, $val);
201         }
203         $this->recordsearcharray = $search_array;
205         // Setting up the comparison stdClass for the last test.
206         $user = $DB->get_record('user', array('id'=>6));
207         $this->finalrecord[6] = new stdClass();
208         $this->finalrecord[6]->id = 6;
209         $this->finalrecord[6]->approved = 1;
210         $this->finalrecord[6]->timecreated = 1234567891;
211         $this->finalrecord[6]->timemodified = 1234567892;
212         $this->finalrecord[6]->userid = 6;
213         $this->finalrecord[6]->firstname = $user->firstname;
214         $this->finalrecord[6]->lastname = $user->lastname;
215         $this->finalrecord[6]->firstnamephonetic = $user->firstnamephonetic;
216         $this->finalrecord[6]->lastnamephonetic = $user->lastnamephonetic;
217         $this->finalrecord[6]->middlename = $user->middlename;
218         $this->finalrecord[6]->alternatename = $user->alternatename;
219         $this->finalrecord[6]->picture = $user->picture;
220         $this->finalrecord[6]->imagealt = $user->imagealt;
221         $this->finalrecord[6]->email = $user->email;
223         // Test 1
224         $recordids = data_get_all_recordids($this->recorddata->id);
225         $this->assertEquals(count($recordids), $this->datarecordcount);
227         // Test 2
228         $key = array_keys($this->recordsearcharray);
229         $alias = $key[0];
230         $newrecordids = data_get_recordids($alias, $this->recordsearcharray, $this->recorddata->id, $recordids);
231         $this->assertEquals($this->datarecordset, $newrecordids);
233         // Test 3
234         $newrecordids = data_get_advance_search_ids($recordids, $this->recordsearcharray, $this->recorddata->id);
235         $this->assertEquals($this->datarecordset, $newrecordids);
237         // Test 3.1
238         $resultrecordids = data_get_advance_search_ids(array(), $this->recordsearcharray, $this->recorddata->id);
239         $this->assertEmpty($resultrecordids);
241         // Test 4
242         $sortorder = 'ORDER BY r.timecreated ASC , r.id ASC';
243         $html = data_get_advanced_search_sql('0', $this->recorddata, $newrecordids, '', $sortorder);
244         $allparams = array_merge($html['params'], array('dataid' => $this->recorddata->id));
245         $records = $DB->get_records_sql($html['sql'], $allparams);
246         $this->assertEquals($records, $this->finalrecord);
248         // Test 5
249         $groupsql = " AND (r.groupid = :currentgroup OR r.groupid = 0)";
250         $params = array('currentgroup' => 1);
251         $recordids = data_get_all_recordids($this->recorddata->id, $groupsql, $params);
252         $this->assertEquals($this->groupdatarecordcount, count($recordids));
254         // Test 6
255         $approvesql = ' AND r.approved=1 ';
256         $recordids = data_get_all_recordids($this->recorddata->id, $approvesql, $params);
257         $this->assertEquals($this->approvedatarecordcount, count($recordids));
258     }
260     public function test_advanced_search_tags() {
261         $this->resetAfterTest();
262         $this->setAdminUser();
264         // Setup test data.
265         $datagenerator = $this->getDataGenerator()->get_plugin_generator('mod_data');
266         $course1 = $this->getDataGenerator()->create_course();
268         $fieldrecord = new StdClass();
269         $fieldrecord->name = 'field-1';
270         $fieldrecord->type = 'text';
271         $fieldrecord->titlefield = true;
273         $data1 = $this->getDataGenerator()->create_module('data', array('course' => $course1->id, 'approval' => true));
274         $field1 = $datagenerator->create_field($fieldrecord, $data1);
276         $record11 = $datagenerator->create_entry($data1, [$field1->field->id => 'value11'], 0, ['Cats', 'Dogs']);
277         $record12 = $datagenerator->create_entry($data1, [$field1->field->id => 'value12'], 0, ['Cats', 'mice']);
278         $record13 = $datagenerator->create_entry($data1, [$field1->field->id => 'value13'], 0, ['Bats']);
280         $searcharray = [];
281         $searcharray[DATA_TAGS] = new stdClass();
282         $searcharray[DATA_TAGS]->params = [];
283         $searcharray[DATA_TAGS]->rawtagnames = ['Cats'];
284         $searcharray[DATA_TAGS]->sql = '';
286         $recordids = data_get_all_recordids($data1->id);
287         $newrecordids = data_get_advance_search_ids($recordids, $searcharray, $data1->id);
289         $this->assertContains($record11, $newrecordids);
290         $this->assertContains($record12, $newrecordids);
291         $this->assertNotContains($record13, $newrecordids);
292     }
294     /**
295      * Indexing database entries contents.
296      *
297      * @return void
298      */
299     public function test_data_entries_indexing() {
300         global $DB;
302         // Returns the instance as long as the area is supported.
303         $searcharea = \core_search\manager::get_search_area($this->databaseentryareaid);
304         $this->assertInstanceOf('\mod_data\search\entry', $searcharea);
306         $user1 = self::getDataGenerator()->create_user();
308         $course1 = self::getDataGenerator()->create_course();
310         $this->getDataGenerator()->enrol_user($user1->id, $course1->id, 'student');
312         $record = new stdClass();
313         $record->course = $course1->id;
315         $this->setUser($user1);
317         // Available for both student and teacher.
318         $data1 = $this->getDataGenerator()->create_module('data', $record);
320         // Excluding LatLong and Picture as we aren't indexing LatLong and Picture fields any way
321         // ...and they're complex and not of any use to consider for this test.
322         // Excluding File as we are indexing files seperately and its complex to implement.
323         $fieldtypes = array( 'checkbox', 'date', 'menu', 'multimenu', 'number', 'radiobutton', 'text', 'textarea', 'url' );
325         $this->create_default_data_fields($fieldtypes, $data1);
327         $data1record1id = $this->create_default_data_record($data1);
328         // All records.
329         $recordset = $searcharea->get_recordset_by_timestamp(0);
331         $this->assertTrue($recordset->valid());
333         $nrecords = 0;
334         foreach ($recordset as $record) {
335             $this->assertInstanceOf('stdClass', $record);
336             $doc = $searcharea->get_document($record);
337             $this->assertInstanceOf('\core_search\document', $doc);
338             $nrecords++;
339         }
341         // If there would be an error/failure in the foreach above the recordset would be closed on shutdown.
342         $recordset->close();
343         $this->assertEquals(1, $nrecords);
345         // The +2 is to prevent race conditions.
346         $recordset = $searcharea->get_recordset_by_timestamp(time() + 2);
348         // No new records.
349         $this->assertFalse($recordset->valid());
350         $recordset->close();
352         // Create a second database, also with one record.
353         $data2 = $this->getDataGenerator()->create_module('data', ['course' => $course1->id]);
354         $this->create_default_data_fields($fieldtypes, $data2);
355         $this->create_default_data_record($data2);
357         // Test indexing with contexts.
358         $rs = $searcharea->get_document_recordset(0, context_module::instance($data1->cmid));
359         $this->assertEquals(1, iterator_count($rs));
360         $rs->close();
361         $rs = $searcharea->get_document_recordset(0, context_module::instance($data2->cmid));
362         $this->assertEquals(1, iterator_count($rs));
363         $rs->close();
364         $rs = $searcharea->get_document_recordset(0, context_course::instance($course1->id));
365         $this->assertEquals(2, iterator_count($rs));
366         $rs->close();
367     }
369     /**
370      * Document contents.
371      *
372      * @return void
373      */
374     public function test_data_entries_document() {
375         global $DB;
377         // Returns the instance as long as the area is supported.
378         $searcharea = \core_search\manager::get_search_area($this->databaseentryareaid);
379         $this->assertInstanceOf('\mod_data\search\entry', $searcharea);
381         $user1 = self::getDataGenerator()->create_user();
383         $course = self::getDataGenerator()->create_course();
385         $this->getDataGenerator()->enrol_user($user1->id, $course->id, 'student');
387         $record = new stdClass();
388         $record->course = $course->id;
390         $this->setAdminUser();
392         // First Case.
393         $data1 = $this->getDataGenerator()->create_module('data', $record);
395         $fieldtypes = array( 'checkbox', 'date', 'menu', 'multimenu', 'number', 'radiobutton', 'text', 'textarea', 'url' );
397         $this->create_default_data_fields($fieldtypes, $data1);
399         $data1record1id = $this->create_default_data_record($data1);
401         $data1entry1 = $this->get_entry_for_id($data1record1id);
403         $data1doc = $searcharea->get_document($data1entry1);
405         $this->assertEquals($data1doc->get('courseid'), $course->id);
406         $this->assertEquals($data1doc->get('title'), 'text for testing');
407         $this->assertEquals($data1doc->get('content'), 'menu1');
408         $this->assertEquals($data1doc->get('description1'), 'radioopt1');
409         $this->assertEquals($data1doc->get('description2'), 'opt1 opt2 opt3 opt4 multimenu1 multimenu2 multimenu3 multimenu4 text area testing http://example.url');
411         // Second Case.
412         $data2 = $this->getDataGenerator()->create_module('data', $record);
414         $fieldtypes = array(
415                 array('checkbox', 1),
416                 array('textarea', 0),
417                 array('menu', 0),
418                 array('number', 1),
419                 array('url', 0),
420                 array('text', 0)
421         );
423         $this->create_default_data_fields($fieldtypes, $data2);
425         $data2record1id = $this->create_default_data_record($data2);
427         $data2entry1 = $this->get_entry_for_id($data2record1id);
429         $data2doc = $searcharea->get_document($data2entry1);
431         $this->assertEquals($data2doc->get('courseid'), $course->id);
432         $this->assertEquals($data2doc->get('title'), 'opt1 opt2 opt3 opt4');
433         $this->assertEquals($data2doc->get('content'), 'text for testing');
434         $this->assertEquals($data2doc->get('description1'), 'menu1');
435         $this->assertEquals($data2doc->get('description2'), 'text area testing http://example.url');
437         // Third Case.
438         $data3 = $this->getDataGenerator()->create_module('data', $record);
440         $fieldtypes = array( 'url' );
442         $this->create_default_data_fields($fieldtypes, $data3);
444         $data3record1id = $this->create_default_data_record($data3);
446         $data3entry1 = $this->get_entry_for_id($data3record1id);
448         $this->assertFalse($searcharea->get_document($data3entry1));
450         // Fourth Case.
451         $data4 = $this->getDataGenerator()->create_module('data', $record);
453         $fieldtypes = array( array('date', 1), array('text', 1));
455         $this->create_default_data_fields($fieldtypes, $data4);
457         $data4record1id = $this->create_default_data_record($data4);
459         $data4entry1 = $this->get_entry_for_id($data4record1id);
461         $this->assertFalse($searcharea->get_document($data4entry1));
463         // Fifth Case.
464         $data5 = $this->getDataGenerator()->create_module('data', $record);
466         $fieldtypes = array(
467                 array('checkbox', 0),
468                 array('number', 1),
469                 array('text', 0),
470                 array('date', 1),
471                 array('textarea', 0),
472                 array('url', 1));
474         $this->create_default_data_fields($fieldtypes, $data5);
476         $data5record1id = $this->create_default_data_record($data5);
478         $data5entry1 = $this->get_entry_for_id($data5record1id);
480         $data5doc = $searcharea->get_document($data5entry1);
482         $this->assertEquals($data5doc->get('courseid'), $course->id);
483         $this->assertEquals($data5doc->get('title'), 'http://example.url');
484         $this->assertEquals($data5doc->get('content'), 'text for testing');
485         $this->assertEquals($data5doc->get('description1'), 'opt1 opt2 opt3 opt4');
486         $this->assertEquals($data5doc->get('description2'), 'text area testing');
488         // Sixth Case.
489         $data6 = $this->getDataGenerator()->create_module('data', $record);
491         $fieldtypes = array( array('date', 1), array('number', 1));
493         $this->create_default_data_fields($fieldtypes, $data6);
495         $data6record1id = $this->create_default_data_record($data6);
497         $data6entry1 = $this->get_entry_for_id($data6record1id);
499         $data6doc = $searcharea->get_document($data6entry1);
501         $this->assertFalse($data6doc);
503         // Seventh Case.
504         $data7 = $this->getDataGenerator()->create_module('data', $record);
506         $fieldtypes = array( array('date', 1), array('number', 1),
507                 array('text', 0), array('textarea', 0));
509         $this->create_default_data_fields($fieldtypes, $data7);
511         $data7record1id = $this->create_default_data_record($data7);
513         $data7entry1 = $this->get_entry_for_id($data7record1id);
515         $data7doc = $searcharea->get_document($data7entry1);
517         $this->assertEquals($data7doc->get('courseid'), $course->id);
518         $this->assertEquals($data7doc->get('title'), 'text for testing');
519         $this->assertEquals($data7doc->get('content'), 'text area testing');
521         // Eight Case.
522         $data8 = $this->getDataGenerator()->create_module('data', $record);
524         $fieldtypes = array('url', 'url', 'url', 'text');
526         $this->create_default_data_fields($fieldtypes, $data8);
528         $data8record1id = $this->create_default_data_record($data8);
530         $data8entry1 = $this->get_entry_for_id($data8record1id);
532         $data8doc = $searcharea->get_document($data8entry1);
534         $this->assertEquals($data8doc->get('courseid'), $course->id);
535         $this->assertEquals($data8doc->get('title'), 'text for testing');
536         $this->assertEquals($data8doc->get('content'), 'http://example.url');
537         $this->assertEquals($data8doc->get('description1'), 'http://example.url');
538         $this->assertEquals($data8doc->get('description2'), 'http://example.url');
540         // Ninth Case.
541         $data9 = $this->getDataGenerator()->create_module('data', $record);
543         $fieldtypes = array('radiobutton', 'menu', 'multimenu');
545         $this->create_default_data_fields($fieldtypes, $data9);
547         $data9record1id = $this->create_default_data_record($data9);
549         $data9entry1 = $this->get_entry_for_id($data9record1id);
551         $data9doc = $searcharea->get_document($data9entry1);
553         $this->assertEquals($data9doc->get('courseid'), $course->id);
554         $this->assertEquals($data9doc->get('title'), 'radioopt1');
555         $this->assertEquals($data9doc->get('content'), 'menu1');
556         $this->assertEquals($data9doc->get('description1'), 'multimenu1 multimenu2 multimenu3 multimenu4');
558         // Tenth Case.
559         $data10 = $this->getDataGenerator()->create_module('data', $record);
561         $fieldtypes = array('checkbox', 'textarea', 'multimenu');
563         $this->create_default_data_fields($fieldtypes, $data10);
565         $data10record1id = $this->create_default_data_record($data10);
567         $data10entry1 = $this->get_entry_for_id($data10record1id);
569         $data10doc = $searcharea->get_document($data10entry1);
571         $this->assertEquals($data10doc->get('courseid'), $course->id);
572         $this->assertEquals($data10doc->get('title'), 'opt1 opt2 opt3 opt4');
573         $this->assertEquals($data10doc->get('content'), 'text area testing');
574         $this->assertEquals($data10doc->get('description1'), 'multimenu1 multimenu2 multimenu3 multimenu4');
576     }
578     /**
579      * Group support for data entries.
580      */
581     public function test_data_entries_group_support() {
582         global $DB;
584         // Get the search area and test generators.
585         $searcharea = \core_search\manager::get_search_area($this->databaseentryareaid);
586         $generator = $this->getDataGenerator();
587         $datagenerator = $generator->get_plugin_generator('mod_data');
589         // Create a course, a user, and two groups.
590         $course = $generator->create_course();
591         $user = $generator->create_user();
592         $generator->enrol_user($user->id, $course->id, 'teacher');
593         $group1 = $generator->create_group(['courseid' => $course->id]);
594         $group2 = $generator->create_group(['courseid' => $course->id]);
596         // Separate groups database.
597         $data = self::getDataGenerator()->create_module('data', ['course' => $course->id,
598                 'groupmode' => SEPARATEGROUPS]);
599         $fieldtypes = ['text', 'textarea'];
600         $this->create_default_data_fields($fieldtypes, $data);
601         $fields = $DB->get_records('data_fields', array('dataid' => $data->id));
602         foreach ($fields as $field) {
603             switch ($field->type) {
604                 case 'text' :
605                     $textid = $field->id;
606                     break;
607                 case 'textarea' :
608                     $textareaid = $field->id;
609                     break;
610             }
611         }
613         // As admin, create entries with each group and all groups.
614         $this->setAdminUser();
615         $fieldvalues = [$textid => 'Title', $textareaid => 'Content'];
616         $e1 = $datagenerator->create_entry($data, $fieldvalues, $group1->id);
617         $e2 = $datagenerator->create_entry($data, $fieldvalues, $group2->id);
618         $e3 = $datagenerator->create_entry($data, $fieldvalues);
620         // Do the indexing of all 3 entries.
621         $rs = $searcharea->get_recordset_by_timestamp(0);
622         $results = [];
623         foreach ($rs as $rec) {
624             $results[$rec->id] = $rec;
625         }
626         $rs->close();
627         $this->assertCount(3, $results);
629         // Check each has the correct groupid.
630         $doc = $searcharea->get_document($results[$e1]);
631         $this->assertTrue($doc->is_set('groupid'));
632         $this->assertEquals($group1->id, $doc->get('groupid'));
633         $doc = $searcharea->get_document($results[$e2]);
634         $this->assertTrue($doc->is_set('groupid'));
635         $this->assertEquals($group2->id, $doc->get('groupid'));
636         $doc = $searcharea->get_document($results[$e3]);
637         $this->assertFalse($doc->is_set('groupid'));
639         // While we're here, also test that the search area requests restriction by group.
640         $modinfo = get_fast_modinfo($course);
641         $this->assertTrue($searcharea->restrict_cm_access_by_group($modinfo->get_cm($data->cmid)));
643         // In visible groups mode, it won't request restriction by group.
644         set_coursemodule_groupmode($data->cmid, VISIBLEGROUPS);
645         $modinfo = get_fast_modinfo($course);
646         $this->assertFalse($searcharea->restrict_cm_access_by_group($modinfo->get_cm($data->cmid)));
647     }
649     /**
650      * Document accesses.
651      *
652      * @return void
653      */
654     public function test_data_entries_access() {
655         global $DB;
657         // Returns the instance as long as the area is supported.
658         $searcharea = \core_search\manager::get_search_area($this->databaseentryareaid);
659         $this->assertInstanceOf('\mod_data\search\entry', $searcharea);
661         $user1 = self::getDataGenerator()->create_user();
662         $user2 = self::getDataGenerator()->create_user();
663         $user3 = self::getDataGenerator()->create_user();
664         $userteacher1 = self::getDataGenerator()->create_user();
666         $course1 = self::getDataGenerator()->create_course();
667         $course2 = self::getDataGenerator()->create_course();
669         $this->getDataGenerator()->enrol_user($user1->id, $course1->id, 'student');
670         $this->getDataGenerator()->enrol_user($user2->id, $course1->id, 'student');
671         $this->getDataGenerator()->enrol_user($userteacher1->id, $course1->id, 'teacher');
673         $this->getDataGenerator()->enrol_user($user3->id, $course2->id, 'student');
675         $record = new stdClass();
676         $record->course = $course1->id;
678         $this->setUser($userteacher1);
680         $data1 = $this->getDataGenerator()->create_module('data', $record);
682         $fieldtypes = array( 'checkbox', 'date', 'menu', 'multimenu', 'number', 'radiobutton', 'text', 'textarea', 'url' );
684         $this->create_default_data_fields($fieldtypes, $data1);
686         $this->setUser($user1);
687         $data1record1id = $this->create_default_data_record($data1);
689         $this->assertEquals(\core_search\manager::ACCESS_GRANTED, $searcharea->check_access($data1record1id));
690         $this->assertEquals(\core_search\manager::ACCESS_DELETED, $searcharea->check_access(-1));
692         $this->setUser($user2);
693         $this->assertEquals(\core_search\manager::ACCESS_GRANTED, $searcharea->check_access($data1record1id));
695         $this->setUser($user3);
696         $this->assertEquals(\core_search\manager::ACCESS_DENIED, $searcharea->check_access($data1record1id));
698         $this->setUser($userteacher1);
699         $this->assertEquals(\core_search\manager::ACCESS_GRANTED, $searcharea->check_access($data1record1id));
701         $this->setAdminUser();
702         $this->assertEquals(\core_search\manager::ACCESS_GRANTED, $searcharea->check_access($data1record1id));
704         $this->setGuestUser();
705         $this->assertEquals(\core_search\manager::ACCESS_DENIED, $searcharea->check_access($data1record1id));
707         // Case with groups.
708         $user1 = self::getDataGenerator()->create_user();
709         $user2 = self::getDataGenerator()->create_user();
710         $user3 = self::getDataGenerator()->create_user();
711         $userteacher1 = self::getDataGenerator()->create_user();
713         $course = self::getDataGenerator()->create_course(array('groupmode' => 1, 'groupmodeforce' => 1));
715         $this->getDataGenerator()->enrol_user($user1->id, $course->id, 'student');
716         $this->getDataGenerator()->enrol_user($user2->id, $course->id, 'student');
717         $this->getDataGenerator()->enrol_user($userteacher1->id, $course->id, 'teacher');
718         $this->getDataGenerator()->enrol_user($user3->id, $course->id, 'student');
720         $groupa = $this->getDataGenerator()->create_group(array('courseid' => $course->id, 'name' => 'groupA'));
721         $groupb = $this->getDataGenerator()->create_group(array('courseid' => $course->id, 'name' => 'groupB'));
723         $this->getDataGenerator()->create_group_member(array('userid' => $user1->id, 'groupid' => $groupa->id));
724         $this->getDataGenerator()->create_group_member(array('userid' => $user2->id, 'groupid' => $groupa->id));
725         $this->getDataGenerator()->create_group_member(array('userid' => $userteacher1->id, 'groupid' => $groupa->id));
727         $this->getDataGenerator()->create_group_member(array('userid' => $user3->id, 'groupid' => $groupb->id));
729         $record = new stdClass();
730         $record->course = $course->id;
732         $this->setUser($userteacher1);
734         $data2 = $this->getDataGenerator()->create_module('data', $record);
736         $cm = get_coursemodule_from_instance('data', $data2->id, $course->id);
737         $cm->groupmode = '1';
738         $cm->effectivegroupmode = '1';
740         $fieldtypes = array( 'checkbox', 'date', 'menu', 'multimenu', 'number', 'radiobutton', 'text', 'textarea', 'url' );
742         $this->create_default_data_fields($fieldtypes, $data2);
744         $this->setUser($user1);
746         $data2record1id = $this->create_default_data_record($data2, $groupa->id);
748         $this->assertEquals(\core_search\manager::ACCESS_GRANTED, $searcharea->check_access($data2record1id));
749         $this->assertEquals(\core_search\manager::ACCESS_DELETED, $searcharea->check_access(-1));
751         $this->setUser($user2);
752         $this->assertEquals(\core_search\manager::ACCESS_GRANTED, $searcharea->check_access($data2record1id));
754         $this->setUser($user3);
755         $this->assertEquals(\core_search\manager::ACCESS_DENIED, $searcharea->check_access($data2record1id));
757         $this->setUser($userteacher1);
758         $this->assertEquals(\core_search\manager::ACCESS_GRANTED, $searcharea->check_access($data2record1id));
760         $this->setAdminUser();
761         $this->assertEquals(\core_search\manager::ACCESS_GRANTED, $searcharea->check_access($data2record1id));
763         $this->setGuestUser();
764         $this->assertEquals(\core_search\manager::ACCESS_DENIED, $searcharea->check_access($data2record1id));
766         // Case with approval.
767         $user1 = self::getDataGenerator()->create_user();
768         $user2 = self::getDataGenerator()->create_user();
769         $userteacher1 = self::getDataGenerator()->create_user();
771         $course = self::getDataGenerator()->create_course();
773         $this->getDataGenerator()->enrol_user($user1->id, $course->id, 'student');
774         $this->getDataGenerator()->enrol_user($user2->id, $course->id, 'student');
775         $this->getDataGenerator()->enrol_user($userteacher1->id, $course->id, 'teacher');
777         $record = new stdClass();
778         $record->course = $course->id;
780         $this->setUser($userteacher1);
782         $data3 = $this->getDataGenerator()->create_module('data', $record);
784         $DB->update_record('data', array('id' => $data3->id, 'approval' => 1));
786         $fieldtypes = array( 'checkbox', 'date', 'menu', 'multimenu', 'number', 'radiobutton', 'text', 'textarea', 'url' );
788         $this->create_default_data_fields($fieldtypes, $data3);
790         $this->setUser($user1);
792         $data3record1id = $this->create_default_data_record($data3);
794         $this->assertEquals(\core_search\manager::ACCESS_GRANTED, $searcharea->check_access($data3record1id));
795         $this->assertEquals(\core_search\manager::ACCESS_DELETED, $searcharea->check_access(-1));
797         $this->setUser($user2);
798         $this->assertEquals(\core_search\manager::ACCESS_DENIED, $searcharea->check_access($data3record1id));
800         $this->setUser($userteacher1);
801         $this->assertEquals(\core_search\manager::ACCESS_GRANTED, $searcharea->check_access($data3record1id));
803         $this->setAdminUser();
804         $this->assertEquals(\core_search\manager::ACCESS_GRANTED, $searcharea->check_access($data3record1id));
806         $this->setGuestUser();
807         $this->assertEquals(\core_search\manager::ACCESS_DENIED, $searcharea->check_access($data3record1id));
809         $DB->update_record('data_records', array('id' => $data3record1id, 'approved' => 1));
811         $this->setUser($user1);
812         $this->assertEquals(\core_search\manager::ACCESS_GRANTED, $searcharea->check_access($data3record1id));
813         $this->assertEquals(\core_search\manager::ACCESS_DELETED, $searcharea->check_access(-1));
815         $this->setUser($user2);
816         $this->assertEquals(\core_search\manager::ACCESS_GRANTED, $searcharea->check_access($data3record1id));
818         $this->setUser($userteacher1);
819         $this->assertEquals(\core_search\manager::ACCESS_GRANTED, $searcharea->check_access($data3record1id));
821         $this->setAdminUser();
822         $this->assertEquals(\core_search\manager::ACCESS_GRANTED, $searcharea->check_access($data3record1id));
824         $this->setGuestUser();
825         $this->assertEquals(\core_search\manager::ACCESS_DENIED, $searcharea->check_access($data3record1id));
827         // Case with requiredentriestoview.
828         $this->setAdminUser();
830         $record->requiredentriestoview = 2;
832         $data4 = $this->getDataGenerator()->create_module('data', $record);
833         $fieldtypes = array( 'checkbox', 'date', 'menu', 'multimenu', 'number', 'radiobutton', 'text', 'textarea', 'url' );
835         $this->create_default_data_fields($fieldtypes, $data4);
837         $data4record1id = $this->create_default_data_record($data4);
839         $this->setUser($user1);
840         $this->assertEquals(\core_search\manager::ACCESS_DENIED, $searcharea->check_access($data4record1id));
842         $data4record2id = $this->create_default_data_record($data4);
843         $this->assertEquals(\core_search\manager::ACCESS_GRANTED, $searcharea->check_access($data4record1id));
844         $this->assertEquals(\core_search\manager::ACCESS_GRANTED, $searcharea->check_access($data4record2id));
845     }
847     /**
848      * Test for file contents.
849      *
850      * @return void
851      */
852     public function test_attach_files() {
853         global $DB, $USER;
855         $fs = get_file_storage();
857         // Returns the instance as long as the area is supported.
858         $searcharea = \core_search\manager::get_search_area($this->databaseentryareaid);
859         $this->assertInstanceOf('\mod_data\search\entry', $searcharea);
861         $user1 = self::getDataGenerator()->create_user();
863         $course = self::getDataGenerator()->create_course();
865         $this->getDataGenerator()->enrol_user($user1->id, $course->id, 'student');
867         $record = new stdClass();
868         $record->course = $course->id;
870         $this->setAdminUser();
872         // Creating database activity instance.
873         $data1 = $this->getDataGenerator()->create_module('data', $record);
875         // Creating file field.
876         $record = new stdClass;
877         $record->type = 'file';
878         $record->dataid = $data1->id;
879         $record->required = 0;
880         $record->name = 'FileFld';
881         $record->description = 'Just another file field';
882         $record->param3 = 0;
883         $record->param1 = '';
884         $record->param2 = '';
886         $data1filefieldid = $DB->insert_record('data_fields', $record);
888         // Creating text field.
889         $record = new stdClass;
890         $record->type = 'text';
891         $record->dataid = $data1->id;
892         $record->required = 0;
893         $record->name = 'TextFld';
894         $record->description = 'Just another text field';
895         $record->param3 = 0;
896         $record->param1 = '';
897         $record->param2 = '';
899         $data1textfieldid = $DB->insert_record('data_fields', $record);
901         // Creating textarea field.
902         $record = new stdClass;
903         $record->type = 'textarea';
904         $record->dataid = $data1->id;
905         $record->required = 0;
906         $record->name = 'TextAreaFld';
907         $record->description = 'Just another textarea field';
908         $record->param1 = '';
909         $record->param2 = 60;
910         $record->param3 = 35;
911         $record->param3 = 1;
912         $record->param3 = 0;
914         $data1textareafieldid = $DB->insert_record('data_fields', $record);
916         // Creating 1st entry.
917         $record = new stdClass;
918         $record->userid = $USER->id;
919         $record->dataid = $data1->id;
920         $record->groupid = 0;
922         $data1record1id = $DB->insert_record('data_records', $record);
924         $filerecord = array(
925                 'contextid' => context_module::instance($data1->cmid)->id,
926                 'component' => 'mod_data',
927                 'filearea'  => 'content',
928                 'itemid'    => $data1record1id,
929                 'filepath'  => '/',
930                 'filename'  => 'myfile1.txt'
931         );
933         $data1record1file = $fs->create_file_from_string($filerecord, 'Some contents 1');
935         $record = new stdClass;
936         $record->fieldid = $data1filefieldid;
937         $record->recordid = $data1record1id;
938         $record->content = 'myfile1.txt';
939         $DB->insert_record('data_content', $record);
941         $record = new stdClass;
942         $record->fieldid = $data1textfieldid;
943         $record->recordid = $data1record1id;
944         $record->content = 'sample text';
945         $DB->insert_record('data_content', $record);
947         $record = new stdClass;
948         $record->fieldid = $data1textareafieldid;
949         $record->recordid = $data1record1id;
950         $record->content = '<br>sample text<p /><br/>';
951         $record->content1 = 1;
952         $DB->insert_record('data_content', $record);
954         // Creating 2nd entry.
955         $record = new stdClass;
956         $record->userid = $USER->id;
957         $record->dataid = $data1->id;
958         $record->groupid = 0;
959         $data1record2id = $DB->insert_record('data_records', $record);
961         $filerecord['itemid'] = $data1record2id;
962         $filerecord['filename'] = 'myfile2.txt';
963         $data1record2file = $fs->create_file_from_string($filerecord, 'Some contents 2');
965         $record = new stdClass;
966         $record->fieldid = $data1filefieldid;
967         $record->recordid = $data1record2id;
968         $record->content = 'myfile2.txt';
969         $DB->insert_record('data_content', $record);
971         $record = new stdClass;
972         $record->fieldid = $data1textfieldid;
973         $record->recordid = $data1record2id;
974         $record->content = 'sample text';
975         $DB->insert_record('data_content', $record);
977         $record = new stdClass;
978         $record->fieldid = $data1textareafieldid;
979         $record->recordid = $data1record2id;
980         $record->content = '<br>sample text<p /><br/>';
981         $record->content1 = 1;
982         $DB->insert_record('data_content', $record);
984         // Now get all the posts and see if they have the right files attached.
985         $searcharea = \core_search\manager::get_search_area($this->databaseentryareaid);
986         $recordset = $searcharea->get_recordset_by_timestamp(0);
987         $nrecords = 0;
988         foreach ($recordset as $record) {
989             $doc = $searcharea->get_document($record);
990             $searcharea->attach_files($doc);
991             $files = $doc->get_files();
992             // Now check that each doc has the right files on it.
993             switch ($doc->get('itemid')) {
994                 case ($data1record1id):
995                     $this->assertCount(1, $files);
996                     $this->assertEquals($data1record1file->get_id(), $files[$data1record1file->get_id()]->get_id());
997                     break;
998                 case ($data1record2id):
999                     $this->assertCount(1, $files);
1000                     $this->assertEquals($data1record2file->get_id(), $files[$data1record2file->get_id()]->get_id());
1001                     break;
1002                 default:
1003                     $this->fail('Unexpected entry returned');
1004                     break;
1005             }
1006             $nrecords++;
1007         }
1008         $recordset->close();
1009         $this->assertEquals(2, $nrecords);
1010     }
1012     /**
1013      * Creates default fields for a database instance
1014      *
1015      * @param array $fieldtypes
1016      * @param mod_data $data
1017      * @return void
1018      */
1019     protected function create_default_data_fields($fieldtypes = array(), $data) {
1020         $count = 1;
1022         // Creating test Fields with default parameter values.
1023         foreach ($fieldtypes as $fieldtype) {
1025             // Creating variables dynamically.
1026             $fieldname = 'field-'.$count;
1027             $record = new stdClass();
1028             $record->name = $fieldname;
1030             if (is_array($fieldtype)) {
1031                 $record->type = $fieldtype[0];
1032                 $record->required = $fieldtype[1];
1033             } else {
1034                 $record->type = $fieldtype;
1035                 $record->required = 0;
1036             }
1038             ${$fieldname} = $this->getDataGenerator()->get_plugin_generator('mod_data')->create_field($record, $data);
1039             $count++;
1040         }
1041     }
1043     /**
1044      * Creates default database entry content values for default field param values
1045      *
1046      * @param mod_data $data
1047      * @param int $groupid
1048      * @return int
1049      */
1050     protected function create_default_data_record($data, $groupid = 0) {
1051         global $DB;
1053         $fields = $DB->get_records('data_fields', array('dataid' => $data->id));
1055         $fieldcontents = array();
1056         foreach ($fields as $fieldrecord) {
1057             switch ($fieldrecord->type) {
1058                 case 'checkbox':
1059                     $fieldcontents[$fieldrecord->id] = array('opt1', 'opt2', 'opt3', 'opt4');
1060                     break;
1062                 case 'multimenu':
1063                     $fieldcontents[$fieldrecord->id] = array('multimenu1', 'multimenu2', 'multimenu3', 'multimenu4');
1064                     break;
1066                 case 'date':
1067                     $fieldcontents[$fieldrecord->id] = '27-07-2016';
1068                     break;
1070                 case 'menu':
1071                     $fieldcontents[$fieldrecord->id] = 'menu1';
1072                     break;
1074                 case 'radiobutton':
1075                     $fieldcontents[$fieldrecord->id] = 'radioopt1';
1076                     break;
1078                 case 'number':
1079                     $fieldcontents[$fieldrecord->id] = '12345';
1080                     break;
1082                 case 'text':
1083                     $fieldcontents[$fieldrecord->id] = 'text for testing';
1084                     break;
1086                 case 'textarea':
1087                     $fieldcontents[$fieldrecord->id] = '<p>text area testing<br /></p>';
1088                     break;
1090                 case 'url':
1091                     $fieldcontents[$fieldrecord->id] = array('example.url', 'sampleurl');
1092                     break;
1094                 default:
1095                     $this->fail('Unexpected field type');
1096                     break;
1097             }
1099         }
1101         return $this->getDataGenerator()->get_plugin_generator('mod_data')->create_entry($data, $fieldcontents, $groupid);
1102     }
1104     /**
1105      * Creates default database entry content values for default field param values
1106      *
1107      * @param int $recordid
1108      * @return stdClass
1109      */
1110     protected function get_entry_for_id($recordid ) {
1111         global $DB;
1113         $sql = "SELECT dr.*, d.course
1114                   FROM {data_records} dr
1115                   JOIN {data} d ON d.id = dr.dataid
1116                  WHERE dr.id = :drid";
1117         return $DB->get_record_sql($sql, array('drid' => $recordid));
1118     }