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/>.
16
17/**
18 * Competency rule tests.
19 *
20 * @package    core_competency
21 * @copyright  2015 Frédéric Massart - FMCorz.net
22 * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
23 */
24
25defined('MOODLE_INTERNAL') || die();
26
27global $CFG;
28require_once($CFG->dirroot . '/webservice/tests/helpers.php');
29
30use core_competency\user_competency;
31use core_competency\competency;
32use core_competency\competency_rule_all;
33use core_competency\competency_rule_points;
34
35/**
36 * Competency rule testcase.
37 *
38 * @package    core_competency
39 * @copyright  2015 Frédéric Massart - FMCorz.net
40 * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
41 */
42class core_competency_competency_rule_testcase extends externallib_advanced_testcase {
43
44    public function test_rule_all_matching() {
45        $this->resetAfterTest(true);
46
47        $this->setAdminUser();
48        $lpg = $this->getDataGenerator()->get_plugin_generator('core_competency');
49        $u1 = $this->getDataGenerator()->create_user();
50
51        // Set up the framework and competencies.
52        $framework = $lpg->create_framework();
53        $c1 = $lpg->create_competency(array('competencyframeworkid' => $framework->get('id'),
54            'ruletype' => 'core_competency\competency_rule_all'));
55        $c11 = $lpg->create_competency(array('competencyframeworkid' => $framework->get('id'), 'parentid' => $c1->get('id'),
56            'ruletype' => 'core_competency\competency_rule_all'));
57        $c111 = $lpg->create_competency(array('competencyframeworkid' => $framework->get('id'), 'parentid' => $c11->get('id'),
58            'ruletype' => 'core_competency\competency_rule_all'));
59        $c112 = $lpg->create_competency(array('competencyframeworkid' => $framework->get('id'), 'parentid' => $c11->get('id'),
60            'ruletype' => 'core_competency\competency_rule_all'));
61        $c12 = $lpg->create_competency(array('competencyframeworkid' => $framework->get('id'), 'parentid' => $c1->get('id'),
62            'ruletype' => 'core_competency\competency_rule_all'));
63        $c13 = $lpg->create_competency(array('competencyframeworkid' => $framework->get('id'), 'parentid' => $c1->get('id'),
64            'ruletype' => 'core_competency\competency_rule_all'));
65        $c131 = $lpg->create_competency(array('competencyframeworkid' => $framework->get('id'), 'parentid' => $c13->get('id'),
66            'ruletype' => 'core_competency\competency_rule_all'));
67
68        // Create some user competency records.
69        $uc1 = $lpg->create_user_competency(array('competencyid' => $c1->get('id'), 'userid' => $u1->id));
70        $uc11 = $lpg->create_user_competency(array('competencyid' => $c11->get('id'), 'userid' => $u1->id,
71            'grade' => 1, 'proficiency' => 1));
72        $uc111 = $lpg->create_user_competency(array('competencyid' => $c111->get('id'), 'userid' => $u1->id,
73            'grade' => 1, 'proficiency' => 1));
74        $uc112 = $lpg->create_user_competency(array('competencyid' => $c112->get('id'), 'userid' => $u1->id,
75            'grade' => 1, 'proficiency' => 1));
76        $uc12 = $lpg->create_user_competency(array('competencyid' => $c12->get('id'), 'userid' => $u1->id));
77        $uc13 = new user_competency(0, (object) array('userid' => $u1->id, 'competencyid' => $c13->get('id')));
78
79        // Not all children are met.
80        $cr = new competency_rule_all($c1);
81        $this->assertFalse($cr->matches($uc1));
82
83        // All children are met.
84        $cr = new competency_rule_all($c11);
85        $this->assertTrue($cr->matches($uc11));
86
87        // The competency doesn't have any children.
88        $cr = new competency_rule_all($c12);
89        $this->assertFalse($cr->matches($uc12));
90
91        // The competency doesn't have saved user competency records.
92        $cr = new competency_rule_all($c13);
93        $this->assertFalse($cr->matches($uc13));
94    }
95
96    public function test_rule_points_validation() {
97        $this->resetAfterTest(true);
98        $this->setAdminUser();
99
100        $lpg = $this->getDataGenerator()->get_plugin_generator('core_competency');
101        $framework = $lpg->create_framework();
102        $framework2 = $lpg->create_framework();
103        $c1 = $lpg->create_competency(array('competencyframeworkid' => $framework->get('id')));
104        $c2 = $lpg->create_competency(array('competencyframeworkid' => $framework->get('id'), 'parentid' => $c1->get('id')));
105        $c3 = $lpg->create_competency(array('competencyframeworkid' => $framework->get('id'), 'parentid' => $c1->get('id')));
106        $c4 = $lpg->create_competency(array('competencyframeworkid' => $framework->get('id')));
107        $cx = $lpg->create_competency(array('competencyframeworkid' => $framework2->get('id')));
108
109        $c1->set('ruletype', 'core_competency\competency_rule_points');
110        $rule = new competency_rule_points($c1);
111
112        // Invalid config.
113        $config = json_encode(array());
114        $this->assertFalse($rule->validate_config($config));
115
116        // Missing required points.
117        $config = json_encode(array(
118            'base' => array(),
119            'competencies' => array(
120                array('id' => $c2->get('id'), 'points' => 1, 'required' => 0),
121                array('id' => $c3->get('id'), 'points' => 1, 'required' => 0),
122            )
123        ));
124        $this->assertFalse($rule->validate_config($config));
125
126        // Invalid required points.
127        $config = json_encode(array(
128            'base' => array('points' => 'abc'),
129            'competencies' => array(
130                array('id' => $c2->get('id'), 'points' => 1, 'required' => 0),
131                array('id' => $c3->get('id'), 'points' => 1, 'required' => 0),
132            )
133        ));
134        $this->assertFalse($rule->validate_config($config));
135
136        // Less than 1 required points.
137        $config = json_encode(array(
138            'base' => array('points' => 0),
139            'competencies' => array(
140                array('id' => $c2->get('id'), 'points' => 1, 'required' => 0),
141                array('id' => $c3->get('id'), 'points' => 1, 'required' => 0),
142            )
143        ));
144        $this->assertFalse($rule->validate_config($config));
145
146        // Not enough required points.
147        $config = json_encode(array(
148            'base' => array('points' => 3),
149            'competencies' => array(
150                array('id' => $c2->get('id'), 'points' => 1, 'required' => 0),
151                array('id' => $c3->get('id'), 'points' => 1, 'required' => 0),
152            )
153        ));
154        $this->assertFalse($rule->validate_config($config));
155
156        // Duplicate competency.
157        $config = json_encode(array(
158            'base' => array('points' => 1),
159            'competencies' => array(
160                array('id' => $c2->get('id'), 'points' => 1, 'required' => 0),
161                array('id' => $c2->get('id'), 'points' => 1, 'required' => 0),
162            )
163        ));
164        $this->assertFalse($rule->validate_config($config));
165
166        // Competency includes itself.
167        $config = json_encode(array(
168            'base' => array('points' => 1),
169            'competencies' => array(
170                array('id' => $c1->get('id'), 'points' => 1, 'required' => 0),
171                array('id' => $c2->get('id'), 'points' => 1, 'required' => 0),
172            )
173        ));
174        $this->assertFalse($rule->validate_config($config));
175
176        // Cannot use negative points.
177        $config = json_encode(array(
178            'base' => array('points' => 1),
179            'competencies' => array(
180                array('id' => $c2->get('id'), 'points' => -1, 'required' => 0),
181                array('id' => $c3->get('id'), 'points' => 1, 'required' => 0),
182            )
183        ));
184        $this->assertFalse($rule->validate_config($config));
185
186        // Not competencies set.
187        $config = json_encode(array(
188            'base' => array('points' => 1),
189            'competencies' => array(
190            )
191        ));
192        $this->assertFalse($rule->validate_config($config));
193
194        // There is a competency that is not a child.
195        $config = json_encode(array(
196            'base' => array('points' => 1),
197            'competencies' => array(
198                array('id' => $c1->get('id'), 'points' => 1, 'required' => 0),
199                array('id' => $c2->get('id'), 'points' => 1, 'required' => 0),
200                array('id' => $c3->get('id'), 'points' => 1, 'required' => 0),
201            )
202        ));
203        $this->assertFalse($rule->validate_config($config));
204
205        // There is a competency from another framework in there.
206        $config = json_encode(array(
207            'base' => array('points' => 1),
208            'competencies' => array(
209                array('id' => $cx->get('id'), 'points' => 1, 'required' => 0),
210                array('id' => $c3->get('id'), 'points' => 1, 'required' => 0),
211            )
212        ));
213        $this->assertFalse($rule->validate_config($config));
214
215        // A normal config.
216        $config = json_encode(array(
217            'base' => array('points' => 4),
218            'competencies' => array(
219                array('id' => $c2->get('id'), 'points' => 3, 'required' => 0),
220                array('id' => $c3->get('id'), 'points' => 2, 'required' => 1),
221            )
222        ));
223        $this->assertTrue($rule->validate_config($config));
224    }
225
226    public function test_rule_points_matching() {
227        $this->resetAfterTest(true);
228
229        $this->setAdminUser();
230        $lpg = $this->getDataGenerator()->get_plugin_generator('core_competency');
231        $u1 = $this->getDataGenerator()->create_user();
232
233        // Set up the framework and competencies.
234        $framework = $lpg->create_framework();
235        $c1 = $lpg->create_competency(array('competencyframeworkid' => $framework->get('id')));
236        $c1->set('ruletype', 'core_competency\competency_rule_points');
237        $comprule = new competency_rule_points($c1);
238        $c11 = $lpg->create_competency(array('competencyframeworkid' => $framework->get('id'), 'parentid' => $c1->get('id')));
239        $c12 = $lpg->create_competency(array('competencyframeworkid' => $framework->get('id'), 'parentid' => $c1->get('id')));
240        $c13 = $lpg->create_competency(array('competencyframeworkid' => $framework->get('id'), 'parentid' => $c1->get('id')));
241        $c14 = $lpg->create_competency(array('competencyframeworkid' => $framework->get('id'), 'parentid' => $c1->get('id')));
242
243        // Create some user competency records.
244        $uc1 = $lpg->create_user_competency(array('competencyid' => $c1->get('id'), 'userid' => $u1->id));
245        $uc11 = $lpg->create_user_competency(array('competencyid' => $c11->get('id'), 'userid' => $u1->id,
246            'grade' => 1, 'proficiency' => 1));
247        $uc12 = $lpg->create_user_competency(array('competencyid' => $c12->get('id'), 'userid' => $u1->id,
248            'grade' => 1, 'proficiency' => 1));
249        $uc13 = $lpg->create_user_competency(array('competencyid' => $c13->get('id'), 'userid' => $u1->id));
250
251        // Enough points.
252        $rule = array(
253            'base' => array('points' => 8),
254            'competencies' => array(
255                array(
256                    'id' => $c11->get('id'),
257                    'points' => 4,
258                    'required' => 0
259                ),
260                array(
261                    'id' => $c12->get('id'),
262                    'points' => 4,
263                    'required' => 0
264                ),
265            )
266        );
267        $c1->set('ruleconfig', json_encode($rule));
268        $c1->update();
269        $this->assertTrue($comprule->matches($uc1));
270
271        // Not enough points.
272        $rule = array(
273            'base' => array('points' => 8),
274            'competencies' => array(
275                array(
276                    'id' => $c11->get('id'),
277                    'points' => 4,
278                    'required' => 0
279                ),
280                array(
281                    'id' => $c13->get('id'),
282                    'points' => 4,
283                    'required' => 0
284                ),
285            )
286        );
287        $c1->set('ruleconfig', json_encode($rule));
288        $c1->update();
289        $this->assertFalse($comprule->matches($uc1));
290
291        // One required that is not met but points were OK.
292        $rule = array(
293            'base' => array('points' => 8),
294            'competencies' => array(
295                array(
296                    'id' => $c11->get('id'),
297                    'points' => 4,
298                    'required' => 0
299                ),
300                array(
301                    'id' => $c12->get('id'),
302                    'points' => 4,
303                    'required' => 0
304                ),
305                array(
306                    'id' => $c13->get('id'),
307                    'points' => 4,
308                    'required' => 1
309                ),
310            )
311        );
312        $c1->set('ruleconfig', json_encode($rule));
313        $c1->update();
314        $this->assertFalse($comprule->matches($uc1));
315
316        // One required, one not, should match.
317        $rule = array(
318            'base' => array('points' => 8),
319            'competencies' => array(
320                array(
321                    'id' => $c11->get('id'),
322                    'points' => 4,
323                    'required' => 0
324                ),
325                array(
326                    'id' => $c12->get('id'),
327                    'points' => 4,
328                    'required' => 1
329                ),
330            )
331        );
332        $c1->set('ruleconfig', json_encode($rule));
333        $c1->update();
334        $this->assertTrue($comprule->matches($uc1));
335
336        // All required and should match.
337        $rule = array(
338            'base' => array('points' => 8),
339            'competencies' => array(
340                array(
341                    'id' => $c11->get('id'),
342                    'points' => 4,
343                    'required' => 1
344                ),
345                array(
346                    'id' => $c12->get('id'),
347                    'points' => 4,
348                    'required' => 1
349                ),
350            )
351        );
352        $c1->set('ruleconfig', json_encode($rule));
353        $c1->update();
354        $this->assertTrue($comprule->matches($uc1));
355
356        // All required, but one doesn't have a user record.
357        $rule = array(
358            'base' => array('points' => 4),
359            'competencies' => array(
360                array(
361                    'id' => $c12->get('id'),
362                    'points' => 4,
363                    'required' => 1
364                ),
365                array(
366                    'id' => $c14->get('id'),
367                    'points' => 4,
368                    'required' => 1
369                ),
370            )
371        );
372        $c1->set('ruleconfig', json_encode($rule));
373        $c1->update();
374        $this->assertFalse($comprule->matches($uc1));
375    }
376
377}
378