1<?php
2
3/* Copyright (c) 2015 Richard Klees <richard.klees@concepts-and-training.de> Extended GPL, see docs/LICENSE */
4
5use PHPUnit\Framework\TestCase;
6
7require_once(__DIR__ . "/mocks.php");
8
9/**
10 * TestCase for the progress of users at a programme.
11 * @group needsInstalledILIAS
12 *
13 * @author Michael Herren <mh@studer-raimann.ch>
14 * @author Richard Klees <richard.klees@concepts-and-training.de>
15 * @version 1.0.0
16 */
17class ilStudyProgrammeUserProgressTest extends TestCase
18{
19    protected $backupGlobals = false;
20
21    protected function setUp() : void
22    {
23        require_once("./Modules/StudyProgramme/classes/class.ilObjStudyProgramme.php");
24        PHPUnit\Framework\Error\Deprecated::$enabled = false;
25
26        global $DIC;
27        if (!$DIC) {
28            include_once("./Services/PHPUnit/classes/class.ilUnitUtil.php");
29            try {
30                ilUnitUtil::performInitialisation();
31            } catch (Exception $e) {
32            }
33        }
34
35        $this->root = ilObjStudyProgramme::createInstance();
36        $this->root->putInTree(ROOT_FOLDER_ID);
37        $this->root->object_factory = new ilObjectFactoryWrapperMock();
38
39        $this->node1 = ilObjStudyProgramme::createInstance();
40        $this->node2 = ilObjStudyProgramme::createInstance();
41
42        $this->leaf1 = new ilStudyProgrammeLeafMock();
43        $this->leaf2 = new ilStudyProgrammeLeafMock();
44
45        $this->root->addNode($this->node1);
46        $this->root->addNode($this->node2);
47        $this->node1->addLeaf($this->leaf1);
48        $this->node2->addLeaf($this->leaf2);
49
50        global $DIC;
51        $tree = $DIC['tree'];
52        $this->tree = $tree;
53
54        global $DIC;
55        $ilUser = $DIC['ilUser'];
56        $this->user = $ilUser;
57    }
58
59    protected function tearDown() : void
60    {
61        if ($this->root) {
62            $this->root->delete();
63        }
64    }
65
66    protected function newUser()
67    {
68        $user = new ilObjUser();
69        $user->create();
70        return $user;
71    }
72
73    protected function setAllNodesActive()
74    {
75        $this->root->setStatus(ilStudyProgrammeSettings::STATUS_ACTIVE)->update();
76        $this->node1->setStatus(ilStudyProgrammeSettings::STATUS_ACTIVE)->update();
77        $this->node2->setStatus(ilStudyProgrammeSettings::STATUS_ACTIVE)->update();
78    }
79
80    protected function assignNewUserToRoot()
81    {
82        $user = $this->newUser();
83        return array($this->root->assignUser($user->getId(), 6), $user);
84    }
85
86    public function testInitialProgressActive()
87    {
88        $this->setAllNodesActive();
89        $tmp = $this->assignNewUserToRoot();
90        $ass = $tmp[0];
91        $user = $tmp[1];
92
93        $root_progresses = $this->root->getProgressesOf($user->getId());
94        $this->assertCount(1, $root_progresses);
95        $root_progress = $root_progresses[0];
96        $this->assertEquals(ilStudyProgrammeProgress::STATUS_IN_PROGRESS, $root_progress->getStatus());
97        $this->assertEquals($this->root->getPoints(), $root_progress->getAmountOfPoints());
98        $this->assertEquals(0, $root_progress->getCurrentAmountOfPoints());
99        $this->assertEquals($this->root->getId(), $root_progress->getStudyProgramme()->getId());
100        $this->assertEquals($ass->getId(), $root_progress->getAssignmentId());
101        $this->assertEquals($user->getId(), $root_progress->getUserId());
102        $this->assertNull($root_progress->getLastChangeBy());
103        $this->assertNull($root_progress->getCompletionBy());
104        $this->assertNull($root_progress->getCompletionDate());
105        $this->assertEquals($root_progress->getAssignmentDate()->format('Y-m-d'), (new \DateTime())->format('Y-m-d'));
106
107
108        $node1_progresses = $this->node1->getProgressesOf($user->getId());
109        $this->assertCount(1, $node1_progresses);
110        $node1_progress = $node1_progresses[0];
111        $this->assertEquals(ilStudyProgrammeProgress::STATUS_IN_PROGRESS, $node1_progress->getStatus());
112        $this->assertEquals($this->node1->getPoints(), $node1_progress->getAmountOfPoints());
113        $this->assertEquals(0, $node1_progress->getCurrentAmountOfPoints());
114        $this->assertEquals($this->node1->getId(), $node1_progress->getStudyProgramme()->getId());
115        $this->assertEquals($ass->getId(), $node1_progress->getAssignmentId());
116        $this->assertEquals($user->getId(), $node1_progress->getUserId());
117        $this->assertNull($node1_progress->getLastChangeBy());
118        $this->assertNull($node1_progress->getCompletionBy());
119
120        $node2_progresses = $this->node2->getProgressesOf($user->getId());
121        $this->assertCount(1, $node2_progresses);
122        $node2_progress = $node2_progresses[0];
123        $this->assertEquals(ilStudyProgrammeProgress::STATUS_IN_PROGRESS, $node2_progress->getStatus());
124        $this->assertEquals($this->node2->getPoints(), $node2_progress->getAmountOfPoints());
125        $this->assertEquals(0, $node2_progress->getCurrentAmountOfPoints());
126        $this->assertEquals($this->node2->getId(), $node2_progress->getStudyProgramme()->getId());
127        $this->assertEquals($ass->getId(), $node2_progress->getAssignmentId());
128        $this->assertEquals($user->getId(), $node2_progress->getUserId());
129        $this->assertNull($node2_progress->getLastChangeBy());
130        $this->assertNull($node2_progress->getCompletionBy());
131    }
132
133    public function testInitialProgressDraft()
134    {
135        $this->root->setStatus(ilStudyProgrammeSettings::STATUS_ACTIVE)->update();
136        $this->node1->setStatus(ilStudyProgrammeSettings::STATUS_ACTIVE)->update();
137        $this->node2->setStatus(ilStudyProgrammeSettings::STATUS_DRAFT)->update();
138
139        $tmp = $this->assignNewUserToRoot();
140        $user = $tmp[1];
141        $ass = $tmp[0];
142
143        $root_progresses = $this->root->getProgressesOf($user->getId());
144        $root_progress = $root_progresses[0];
145        $this->assertEquals(ilStudyProgrammeProgress::STATUS_IN_PROGRESS, $root_progress->getStatus());
146
147        $node1_progresses = $this->node1->getProgressesOf($user->getId());
148        $node1_progress = $node1_progresses[0];
149        $this->assertEquals(ilStudyProgrammeProgress::STATUS_IN_PROGRESS, $node1_progress->getStatus());
150
151        $node2_progresses = $this->node2->getProgressesOf($user->getId());
152        $node2_progress = $node2_progresses[0];
153        $this->assertEquals(ilStudyProgrammeProgress::STATUS_NOT_RELEVANT, $node2_progress->getStatus());
154    }
155
156    public function testInitialProgressOutdated()
157    {
158        $this->root->setStatus(ilStudyProgrammeSettings::STATUS_ACTIVE)->update();
159        $this->node1->setStatus(ilStudyProgrammeSettings::STATUS_ACTIVE)->update();
160        $this->node2->setStatus(ilStudyProgrammeSettings::STATUS_OUTDATED)->update();
161
162        $tmp = $this->assignNewUserToRoot();
163        $user = $tmp[1];
164        $ass = $tmp[0];
165
166        $root_progresses = $this->root->getProgressesOf($user->getId());
167        $root_progress = $root_progresses[0];
168        $this->assertEquals(ilStudyProgrammeProgress::STATUS_IN_PROGRESS, $root_progress->getStatus());
169
170        $node1_progresses = $this->node1->getProgressesOf($user->getId());
171        $node1_progress = $node1_progresses[0];
172        $this->assertEquals(ilStudyProgrammeProgress::STATUS_IN_PROGRESS, $node1_progress->getStatus());
173
174        $node2_progresses = $this->node2->getProgressesOf($user->getId());
175        $node2_progress = $node2_progresses[0];
176        $this->assertEquals(ilStudyProgrammeProgress::STATUS_NOT_RELEVANT, $node2_progress->getStatus());
177    }
178
179    public function testUserSelection()
180    {
181        $this->setAllNodesActive();
182        $this->assignNewUserToRoot();
183        $tmp = $this->assignNewUserToRoot();
184        $ass = $tmp[0];
185        $user = $tmp[1];
186
187        $root_progresses = $this->root->getProgressesOf($user->getId());
188        $this->assertCount(1, $root_progresses);
189    }
190
191    public function testMarkAccredited()
192    {
193        $this->setAllNodesActive();
194        $tmp = $this->assignNewUserToRoot();
195        $ass = $tmp[0];
196        $user = $tmp[1];
197
198        $user2 = $this->newUser();
199        $USER_ID = $user2->getId();
200
201        $root_progress = array_shift($this->root->getProgressesOf($user->getId()));
202        $node1_progress = array_shift($this->node1->getProgressesOf($user->getId()));
203        $node2_progress = array_shift($this->node2->getProgressesOf($user->getId()));
204        $this->assertEquals($root_progress->getAmountOfPoints(), ilStudyProgrammeSettings::DEFAULT_POINTS);
205        $this->assertEquals($node1_progress->getAmountOfPoints(), ilStudyProgrammeSettings::DEFAULT_POINTS);
206        $this->assertEquals($node2_progress->getAmountOfPoints(), ilStudyProgrammeSettings::DEFAULT_POINTS);
207
208        $ts_before_change = $node2_progress->getLastChange()->format('Y-m-d H:i:s');
209        $node2_progress->markAccredited($USER_ID);
210        $ts_after_change = $node2_progress->getLastChange()->format('Y-m-d H:i:s');
211
212
213        $root_progress = array_shift($this->root->getProgressesOf($user->getId()));
214        $node1_progress = array_shift($this->node1->getProgressesOf($user->getId()));
215        $node2_progress = array_shift($this->node2->getProgressesOf($user->getId()));
216
217        $this->assertTrue($node2_progress->isSuccessful());
218        $this->assertEquals($root_progress->getAmountOfPoints(), $root_progress->getCurrentAmountOfPoints());
219
220        $this->assertEquals(ilStudyProgrammeProgress::STATUS_COMPLETED, $root_progress->getStatus());
221        $this->assertEquals((new \DateTime())->format('Y-m-d'), $root_progress->getCompletionDate()->format('Y-m-d'));
222        $this->assertEquals(ilStudyProgrammeProgress::STATUS_IN_PROGRESS, $node1_progress->getStatus());
223        $this->assertNull($node1_progress->getCompletionDate());
224        $this->assertEquals(ilStudyProgrammeProgress::STATUS_ACCREDITED, $node2_progress->getStatus());
225        $this->assertEquals((new \DateTime())->format('Y-m-d'), $node2_progress->getCompletionDate()->format('Y-m-d'));
226        $this->assertEquals($USER_ID, $node2_progress->getCompletionBy());
227        $this->assertLessThanOrEqual($ts_before_change, $ts_after_change);
228    }
229
230    public function testUnmarkAccredited()
231    {
232        $this->setAllNodesActive();
233        $tmp = $this->assignNewUserToRoot();
234        $ass = $tmp[0];
235        $user = $tmp[1];
236
237        $user2 = $this->newUser();
238        $USER_ID = $user2->getId();
239
240        $root_progress = array_shift($this->root->getProgressesOf($user->getId()));
241        $node1_progress = array_shift($this->node1->getProgressesOf($user->getId()));
242        $node2_progress = array_shift($this->node2->getProgressesOf($user->getId()));
243
244        $this->assertEquals(ilStudyProgrammeProgress::STATUS_IN_PROGRESS, $root_progress->getStatus());
245        $this->assertEquals(ilStudyProgrammeProgress::STATUS_IN_PROGRESS, $node1_progress->getStatus());
246        $this->assertEquals(ilStudyProgrammeProgress::STATUS_IN_PROGRESS, $node2_progress->getStatus());
247
248        $ts_before_change = $node2_progress->getLastChange()->format('Y-m-d H:i:s');
249        $node2_progress->markAccredited($USER_ID);
250        $node2_progress->unmarkAccredited();
251        $ts_after_change = $node2_progress->getLastChange()->format('Y-m-d H:i:s');
252
253        // The root node will still be completed, as we do not go back from completed to some other
254        // status.
255        $this->assertEquals(ilStudyProgrammeProgress::STATUS_IN_PROGRESS, $root_progress->getStatus());
256        $this->assertEquals(ilStudyProgrammeProgress::STATUS_IN_PROGRESS, $node1_progress->getStatus());
257        $this->assertEquals(ilStudyProgrammeProgress::STATUS_IN_PROGRESS, $node2_progress->getStatus());
258        $this->assertNull($root_progress->getCompletionDate());
259        $this->assertNull($node1_progress->getCompletionDate());
260        $this->assertNull($node2_progress->getCompletionDate());
261        $this->assertEquals(null, $node2_progress->getCompletionBy());
262        $this->assertLessThanOrEqual($ts_before_change, $ts_after_change);
263    }
264
265    public function testMarkFailed()
266    {
267        $this->setAllNodesActive();
268        $tmp = $this->assignNewUserToRoot();
269        $ass = $tmp[0];
270        $user = $tmp[1];
271
272        $user2 = $this->newUser();
273        $USER_ID = $user2->getId();
274
275        $root_progress = array_shift($this->root->getProgressesOf($user->getId()));
276        $node1_progress = array_shift($this->node1->getProgressesOf($user->getId()));
277        $node2_progress = array_shift($this->node2->getProgressesOf($user->getId()));
278        $node2_progress->markFailed($USER_ID);
279
280        $this->assertEquals(ilStudyProgrammeProgress::STATUS_IN_PROGRESS, $root_progress->getStatus());
281        $this->assertEquals(ilStudyProgrammeProgress::STATUS_IN_PROGRESS, $node1_progress->getStatus());
282        $this->assertEquals(ilStudyProgrammeProgress::STATUS_FAILED, $node2_progress->getStatus());
283        $this->assertNull($root_progress->getCompletionDate());
284        $this->assertNull($node1_progress->getCompletionDate());
285        $this->assertNull($node2_progress->getCompletionDate());
286    }
287
288    public function testMarkNotFailed()
289    {
290        $this->setAllNodesActive();
291        $tmp = $this->assignNewUserToRoot();
292        $ass = $tmp[0];
293        $user = $tmp[1];
294
295        $user2 = $this->newUser();
296        $USER_ID = (int) $user2->getId();
297
298        $root_progress = array_shift($this->root->getProgressesOf($user->getId()));
299        $node1_progress = array_shift($this->node1->getProgressesOf($user->getId()));
300        $node2_progress = array_shift($this->node2->getProgressesOf($user->getId()));
301        $node2_progress->markFailed($USER_ID);
302
303        $this->assertEquals(ilStudyProgrammeProgress::STATUS_IN_PROGRESS, $root_progress->getStatus());
304        $this->assertEquals(ilStudyProgrammeProgress::STATUS_IN_PROGRESS, $node1_progress->getStatus());
305        $this->assertEquals(ilStudyProgrammeProgress::STATUS_FAILED, $node2_progress->getStatus());
306        $this->assertNull($root_progress->getCompletionDate());
307        $this->assertNull($node1_progress->getCompletionDate());
308        $this->assertNull($node2_progress->getCompletionDate());
309        $node2_progress->markNotFailed($USER_ID);
310
311        $this->assertEquals(ilStudyProgrammeProgress::STATUS_IN_PROGRESS, $node2_progress->getStatus());
312    }
313
314    public function testMarkNotRelevant()
315    {
316        $this->setAllNodesActive();
317        $tmp = $this->assignNewUserToRoot();
318        $ass = $tmp[0];
319        $user = $tmp[1];
320
321        $user2 = $this->newUser();
322        $USER_ID = $user2->getId();
323
324        $root_progress = array_shift($this->root->getProgressesOf($user->getId()));
325        $node1_progress = array_shift($this->node1->getProgressesOf($user->getId()));
326        $node2_progress = array_shift($this->node2->getProgressesOf($user->getId()));
327        $ts_before_change = $node2_progress->getLastChange()->format('Y-m-d H:i:s');
328        $node2_progress->markNotRelevant($USER_ID);
329        $ts_after_change = $node2_progress->getLastChange()->format('Y-m-d H:i:s');
330        $this->assertEquals(ilStudyProgrammeProgress::STATUS_IN_PROGRESS, $root_progress->getStatus());
331        $this->assertEquals(ilStudyProgrammeProgress::STATUS_IN_PROGRESS, $node1_progress->getStatus());
332        $this->assertEquals(ilStudyProgrammeProgress::STATUS_NOT_RELEVANT, $node2_progress->getStatus());
333        $this->assertNull($root_progress->getCompletionDate());
334        $this->assertNull($node1_progress->getCompletionDate());
335        $this->assertNull($node2_progress->getCompletionDate());
336        $this->assertEquals($USER_ID, $node2_progress->getCompletionBy());
337        $this->assertLessThanOrEqual($ts_before_change, $ts_after_change);
338        $this->assertTrue($node2_progress->hasIndividualModifications());
339    }
340
341    // Neues Moduls: Wird dem Studierenden-Studierenden inkl. Kurse, Punkte als "Nicht relevant" hinzugefügt.
342    public function testNewNodesAreNotRelevant()
343    {
344        $this->setAllNodesActive();
345        $tmp = $this->assignNewUserToRoot();
346        $ass = $tmp[0];
347        $user = $tmp[1];
348
349        $node3 = ilObjStudyProgramme::createInstance();
350        $this->root->addNode($node3);
351
352        $node3_progress = array_shift($node3->getProgressesOf($user->getId()));
353        $this->assertNotNull($node3_progress);
354        $this->assertEquals(ilStudyProgrammeProgress::STATUS_NOT_RELEVANT, $node3_progress->getStatus());
355    }
356
357    public function testIndividualRequiredPoints()
358    {
359        $this->setAllNodesActive();
360        $tmp = $this->assignNewUserToRoot();
361        $ass1 = $tmp[0];
362        $user1 = $tmp[1];
363
364
365        $NEW_AMOUNT_OF_POINTS_1 = 205;
366        $this->assertNotEquals($NEW_AMOUNT_OF_POINTS_1, ilStudyProgrammeSettings::DEFAULT_POINTS);
367
368        $node2_progress1 = array_shift($this->node2->getProgressesOf($user1->getId()));
369        $node2_progress1->setRequiredAmountOfPoints($NEW_AMOUNT_OF_POINTS_1, 6);
370
371        $this->assertEquals($NEW_AMOUNT_OF_POINTS_1, $node2_progress1->getAmountOfPoints());
372    }
373
374    public function testMaximimPossibleAmountOfPoints1()
375    {
376        $this->setAllNodesActive();
377        $tmp = $this->assignNewUserToRoot();
378        $ass = $tmp[0];
379        $user = $tmp[1];
380
381        $root_progress = array_shift($this->root->getProgressesOf($user->getId()));
382        $node1_progress = array_shift($this->node1->getProgressesOf($user->getId()));
383        $node2_progress = array_shift($this->node2->getProgressesOf($user->getId()));
384
385        $this->assertEquals(2 * ilStudyProgrammeSettings::DEFAULT_POINTS, $root_progress->getMaximumPossibleAmountOfPoints());
386        $this->assertEquals(ilStudyProgrammeSettings::DEFAULT_POINTS, $node1_progress->getMaximumPossibleAmountOfPoints());
387        $this->assertEquals(ilStudyProgrammeSettings::DEFAULT_POINTS, $node2_progress->getMaximumPossibleAmountOfPoints());
388    }
389
390    public function testMaximimPossibleAmountOfPoints2()
391    {
392        $this->setAllNodesActive();
393        $tmp = $this->assignNewUserToRoot();
394        $ass = $tmp[0];
395        $user = $tmp[1];
396
397        $root_progress = array_shift($this->root->getProgressesOf($user->getId()));
398        $node1_progress = array_shift($this->node1->getProgressesOf($user->getId()));
399        $node2_progress = array_shift($this->node2->getProgressesOf($user->getId()));
400
401        $this->assertEquals(2 * ilStudyProgrammeSettings::DEFAULT_POINTS, $root_progress->getMaximumPossibleAmountOfPoints());
402        $this->assertEquals(ilStudyProgrammeSettings::DEFAULT_POINTS, $node1_progress->getMaximumPossibleAmountOfPoints());
403        $this->assertEquals(ilStudyProgrammeSettings::DEFAULT_POINTS, $node2_progress->getMaximumPossibleAmountOfPoints());
404    }
405
406    public function testCanBeCompleted1()
407    {
408        $this->setAllNodesActive();
409        $tmp = $this->assignNewUserToRoot();
410        $ass = $tmp[0];
411        $user = $tmp[1];
412
413        $root_progress = array_shift($this->root->getProgressesOf($user->getId()));
414        $node1_progress = array_shift($this->node1->getProgressesOf($user->getId()));
415        $node2_progress = array_shift($this->node2->getProgressesOf($user->getId()));
416
417        $this->assertTrue($root_progress->canBeCompleted());
418        $this->assertTrue($node1_progress->canBeCompleted());
419        $this->assertTrue($node2_progress->canBeCompleted());
420    }
421
422    public function testCanBeCompleted2()
423    {
424        $NEW_AMOUNT_OF_POINTS = 3003;
425        $this->assertGreaterThan(ilStudyProgrammeSettings::DEFAULT_POINTS, $NEW_AMOUNT_OF_POINTS);
426
427        $this->setAllNodesActive();
428        $this->root->setPoints($NEW_AMOUNT_OF_POINTS)
429                   ->update();
430        $tmp = $this->assignNewUserToRoot();
431        $ass = $tmp[0];
432        $user = $tmp[1];
433
434        $this->assertLessThan($NEW_AMOUNT_OF_POINTS, $this->node1->getPoints() + $this->node2->getPoints());
435
436        $root_progress = array_shift($this->root->getProgressesOf($user->getId()));
437        $this->assertFalse($root_progress->canBeCompleted());
438    }
439
440    public function testCanBeCompleted3()
441    {
442        $NEW_AMOUNT_OF_POINTS = 3003;
443        $this->assertGreaterThan(ilStudyProgrammeSettings::DEFAULT_POINTS, $NEW_AMOUNT_OF_POINTS);
444
445        $this->setAllNodesActive();
446        $node3 = ilObjStudyProgramme::createInstance();
447        $this->root->addNode($node3);
448        $node3->setPoints($NEW_AMOUNT_OF_POINTS)
449              ->setStatus(ilStudyProgrammeSettings::STATUS_ACTIVE)
450              ->update();
451
452
453        $tmp = $this->assignNewUserToRoot();
454        $ass = $tmp[0];
455        $user = $tmp[1];
456
457        $root_progress = array_shift($this->root->getProgressesOf($user->getId()));
458        $node3_progress = array_shift($node3->getProgressesOf($user->getId()));
459
460        $this->assertFalse($root_progress->canBeCompleted());
461        $this->assertFalse($node3_progress->canBeCompleted());
462    }
463
464    public function testUserDeletionDeletesAssignments()
465    {
466        $this->setAllNodesActive();
467        $tmp = $this->assignNewUserToRoot();
468        $ass = $tmp[0];
469        $user = $tmp[1];
470
471        $user->delete();
472
473        $root_progresses = $this->root->getProgressesOf($user->getId());
474        $this->assertCount(0, $root_progresses);
475        $node1_progresses = $this->node1->getProgressesOf($user->getId());
476        $this->assertCount(0, $node1_progresses);
477        $node2_progresses = $this->node2->getProgressesOf($user->getId());
478        $this->assertCount(0, $node2_progresses);
479    }
480
481    // - Änderungen von Punkten bei bestehenden qua-Objekten werden nicht direkt übernommen
482    public function testNoImplicitPointUpdate()
483    {
484        $this->setAllNodesActive();
485        $tmp = $this->assignNewUserToRoot();
486        $ass = $tmp[0];
487        $user = $tmp[1];
488
489        $NEW_AMOUNT_OF_POINTS = 201;
490        $this->assertNotEquals($NEW_AMOUNT_OF_POINTS, ilStudyProgrammeSettings::DEFAULT_POINTS);
491
492        $this->root->setPoints($NEW_AMOUNT_OF_POINTS)
493                   ->update();
494
495        $root_progress = array_shift($this->root->getProgressesOf($user->getId()));
496        $this->assertEquals(ilStudyProgrammeSettings::DEFAULT_POINTS, $root_progress->getAmountOfPoints());
497    }
498
499    // Änderungen von Punkten bei bestehenden qua-Objekten werden nicht direkt übernommen,
500    //  sondern dann bei bewusster Aktualisierung.
501    public function testExplicitPointUpdate1()
502    {
503        $this->setAllNodesActive();
504        $tmp = $this->assignNewUserToRoot();
505        $ass = $tmp[0];
506        $user = $tmp[1];
507
508        $NEW_AMOUNT_OF_POINTS = 202;
509        $this->assertNotEquals($NEW_AMOUNT_OF_POINTS, ilStudyProgrammeSettings::DEFAULT_POINTS);
510
511        $this->root->setPoints($NEW_AMOUNT_OF_POINTS)
512                   ->update();
513
514        $ass->updateFromProgram();
515        $root_progress = array_shift($this->root->getProgressesOf($user->getId()));
516        $this->assertEquals($NEW_AMOUNT_OF_POINTS, $root_progress->getAmountOfPoints());
517    }
518
519    // Änderungen von Punkten bei bestehenden qua-Objekten werden nicht direkt übernommen,
520    // sondern dann bei bewusster Aktualisierung.
521    // Similar to testExplicitPointUpdate1, but order of calls differs.
522    public function testExplicitPointUpdate2()
523    {
524        $this->setAllNodesActive();
525        $tmp = $this->assignNewUserToRoot();
526        $ass = $tmp[0];
527        $user = $tmp[1];
528
529        $NEW_AMOUNT_OF_POINTS = 203;
530        $this->assertNotEquals($NEW_AMOUNT_OF_POINTS, ilStudyProgrammeSettings::DEFAULT_POINTS);
531
532        $this->root->setPoints($NEW_AMOUNT_OF_POINTS)
533                   ->update();
534
535        $root_progress = array_shift($this->root->getProgressesOf($user->getId()));
536        $ass->updateFromProgram();
537        $root_progress = array_shift($this->root->getProgressesOf($user->getId()));
538        $this->assertEquals($NEW_AMOUNT_OF_POINTS, $root_progress->getAmountOfPoints());
539    }
540
541    // Änderungen von Punkten bei bestehenden qua-Objekten werden nicht direkt übernommen,
542    //  sondern dann bei bewusster Aktualisierung (sofern nicht ein darüberliegenden
543    // Knotenpunkt manuell angepasst worden ist)
544    public function testNoUpdateOnModifiedNodes()
545    {
546        $this->setAllNodesActive();
547        $tmp = $this->assignNewUserToRoot();
548        $ass1 = $tmp[0];
549        $user1 = $tmp[1];
550
551        $tmp = $this->assignNewUserToRoot();
552        $ass2 = $tmp[0];
553        $user2 = $tmp[1];
554
555        $NEW_AMOUNT_OF_POINTS_1 = 205;
556        $this->assertNotEquals($NEW_AMOUNT_OF_POINTS_1, ilStudyProgrammeSettings::DEFAULT_POINTS);
557        $NEW_AMOUNT_OF_POINTS_2 = 206;
558        $this->assertNotEquals($NEW_AMOUNT_OF_POINTS_2, ilStudyProgrammeSettings::DEFAULT_POINTS);
559        $this->assertNotEquals($NEW_AMOUNT_OF_POINTS_1, $NEW_AMOUNT_OF_POINTS_2);
560
561        $node2_progress1 = array_shift($this->node2->getProgressesOf($user1->getId()));
562
563
564        $node2_progress2 = array_shift($this->node2->getProgressesOf($user2->getId()));
565
566        $node2_progress1->setRequiredAmountOfPoints($NEW_AMOUNT_OF_POINTS_1, 6);
567        $this->assertEquals($NEW_AMOUNT_OF_POINTS_1, $node2_progress1->getAmountOfPoints());
568        $node2_progress1 = array_shift($this->node2->getProgressesOf($user1->getId()));
569        $this->assertEquals($NEW_AMOUNT_OF_POINTS_1, $node2_progress1->getAmountOfPoints());
570        $this->node2->setPoints($NEW_AMOUNT_OF_POINTS_2)
571                    ->update();
572        $this->root->updateAllAssignments();
573        $node2_progress2 = array_shift($this->node2->getProgressesOf($user2->getId()));
574        //$this->assertEquals($NEW_AMOUNT_OF_POINTS_1, $node2_progress1->getAmountOfPoints());
575        $this->assertEquals($NEW_AMOUNT_OF_POINTS_2, $node2_progress2->getAmountOfPoints());
576
577        //$node2_progress1 = array_shift($this->node2->getProgressesOf($user1->getId()));
578        $node2_progress2 = array_shift($this->node2->getProgressesOf($user2->getId()));
579
580        //$this->assertEquals($NEW_AMOUNT_OF_POINTS_1, $node2_progress1->getAmountOfPoints());
581        $this->assertEquals($NEW_AMOUNT_OF_POINTS_2, $node2_progress2->getAmountOfPoints());
582    }
583
584    /**
585     * QUA-Objekte, welche "Inaktiv" sind können bei Studierenden-Studienplänen nicht von
586     * "nicht relevant" auf irgendeinen anderen Status  gesetzt werden.
587     *
588     * @expectedException ilException
589     */
590    public function testOutdatedNodesCantBeSetToRelevant()
591    {
592        $this->setAllNodesActive();
593        $this->node1->setStatus(ilStudyProgrammeSettings::STATUS_OUTDATED);
594        $tmp = $this->assignNewUserToRoot();
595        $ass1 = $tmp[0];
596        $user1 = $tmp[1];
597
598        $progress = $this->node1->getProgressForAssignment($ass1->getId());
599        $this->assertEquals(ilStudyProgrammeProgress::STATUS_NOT_RELEVANT, $progress->getStatus());
600        $progress->markAccredited($this->user->getId());
601    }
602
603    // Hinweis bei der bei der Studierenden-Instanz des Studienplanes, falls dieser vom
604    // Original-Studienplan abweicht.
605    public function testHasDeviationToProgram1()
606    {
607        $this->setAllNodesActive();
608        $tmp = $this->assignNewUserToRoot();
609        $ass1 = $tmp[0];
610        $user1 = $tmp[1];
611
612        $progress = $this->node1->getProgressForAssignment($ass1->getId());
613        $this->assertFalse($progress->hasIndividualModifications());
614    }
615
616    public function testHasDeviationToProgram2()
617    {
618        $this->setAllNodesActive();
619        $tmp = $this->assignNewUserToRoot();
620        $ass1 = $tmp[0];
621        $user1 = $tmp[1];
622
623        $progress = $this->node1->getProgressForAssignment($ass1->getId());
624        $progress->setRequiredAmountOfPoints(1000, 6);
625        $this->assertTrue($progress->hasIndividualModifications());
626    }
627
628    public function testHasDeviationToProgram3()
629    {
630        $this->setAllNodesActive();
631        $tmp = $this->assignNewUserToRoot();
632        $ass1 = $tmp[0];
633        $user1 = $tmp[1];
634
635        $progress = $this->node1->getProgressForAssignment($ass1->getId());
636        $progress->markNotRelevant(6);
637        $this->assertTrue($progress->hasIndividualModifications());
638    }
639
640    public function testHasDeviationToProgram4()
641    {
642        $this->setAllNodesActive();
643        $tmp = $this->assignNewUserToRoot();
644        $ass1 = $tmp[0];
645        $user1 = $tmp[1];
646
647        $progress = $this->node1->getProgressForAssignment($ass1->getId());
648        $progress->markAccredited($this->user->getId());
649        $this->assertFalse($progress->hasIndividualModifications());
650    }
651
652    public function testGetNamesOfCompletedOrAccreditedChildren()
653    {
654        $this->setAllNodesActive();
655        $tmp = $this->assignNewUserToRoot();
656        $ass = $tmp[0];
657        $user = $tmp[1];
658
659        $user2 = $this->newUser();
660        $USER_ID = $user2->getId();
661
662        $this->node1->setTitle("node1");
663        $this->node1->update();
664        $this->node2->setTitle("node2");
665        $this->node2->update();
666
667        $names = $this->root->getProgressForAssignment($ass->getId())
668                    ->getNamesOfCompletedOrAccreditedChildren();
669        $this->assertEquals($names, array());
670
671        $this->node1->getProgressForAssignment($ass->getId())->markAccredited($USER_ID);
672        $names = $this->root->getProgressForAssignment($ass->getId())
673                    ->getNamesOfCompletedOrAccreditedChildren();
674        $this->assertEquals($names, array("node1"));
675
676        $this->node2->getProgressForAssignment($ass->getId())->markAccredited($USER_ID);
677        $names = $this->root->getProgressForAssignment($ass->getId())
678                    ->getNamesOfCompletedOrAccreditedChildren();
679        $this->assertEquals($names, array("node1", "node2"));
680    }
681
682    public function testCompletionOnDeeplyNestedProgresses()
683    {
684        $depth1 = ilObjStudyProgramme::createInstance();
685        $depth2 = ilObjStudyProgramme::createInstance();
686        $depth3 = ilObjStudyProgramme::createInstance();
687        $depth4 = ilObjStudyProgramme::createInstance();
688        $depth1->putInTree(ROOT_FOLDER_ID);
689        $depth1->addNode($depth2);
690        $depth2->addNode($depth3);
691        $depth3->addNode($depth4);
692        $depth1->setStatus(ilStudyProgrammeSettings::STATUS_ACTIVE);
693        $depth2->setStatus(ilStudyProgrammeSettings::STATUS_ACTIVE);
694        $depth3->setStatus(ilStudyProgrammeSettings::STATUS_ACTIVE);
695        $depth4->setStatus(ilStudyProgrammeSettings::STATUS_ACTIVE);
696
697        $user = $this->newUser();
698
699        $assignment = $depth1->assignUser($user->getId(), 6);
700        $progress4 = $depth4->getProgressForAssignment($assignment->getId());
701        $progress4->markAccredited(6);
702
703        $progress1 = $depth1->getProgressForAssignment($assignment->getId());
704        $progress2 = $depth2->getProgressForAssignment($assignment->getId());
705        $progress3 = $depth3->getProgressForAssignment($assignment->getId());
706
707        $this->assertTrue($progress1->isSuccessful());
708        $this->assertTrue($progress2->isSuccessful());
709        $this->assertTrue($progress3->isSuccessful());
710        $this->assertTrue($progress4->isSuccessful());
711
712        $this->assertEquals(ilStudyProgrammeSettings::DEFAULT_POINTS, $progress1->getCurrentAmountOfPoints());
713        $this->assertEquals(ilStudyProgrammeSettings::DEFAULT_POINTS, $progress2->getCurrentAmountOfPoints());
714        $this->assertEquals(ilStudyProgrammeSettings::DEFAULT_POINTS, $progress3->getCurrentAmountOfPoints());
715        $this->assertEquals(ilStudyProgrammeSettings::DEFAULT_POINTS, $progress4->getCurrentAmountOfPoints());
716    }
717
718
719    public function testPossibleActions()
720    {
721        //node is root-node, status is "not relevant"
722        $expected = array(
723            ilStudyProgrammeUserProgress::ACTION_SHOW_INDIVIDUAL_PLAN,
724            ilStudyProgrammeUserProgress::ACTION_REMOVE_USER
725        );
726        $this->assertEquals(
727            $expected,
728            ilStudyProgrammeUserProgress::getPossibleActions(
729                1,
730                1,
731                ilStudyProgrammeProgress::STATUS_NOT_RELEVANT
732            )
733        );
734
735        //node is root-node, status is "in progress"
736        $expected = array(
737            ilStudyProgrammeUserProgress::ACTION_SHOW_INDIVIDUAL_PLAN,
738            ilStudyProgrammeUserProgress::ACTION_REMOVE_USER,
739            ilStudyProgrammeUserProgress::ACTION_MARK_ACCREDITED
740        );
741        $this->assertEquals(
742            $expected,
743            ilStudyProgrammeUserProgress::getPossibleActions(
744                1,
745                1,
746                ilStudyProgrammeProgress::STATUS_IN_PROGRESS
747            )
748        );
749
750        //node is root-node, status is "accredited"
751        $expected = array(
752            ilStudyProgrammeUserProgress::ACTION_SHOW_INDIVIDUAL_PLAN,
753            ilStudyProgrammeUserProgress::ACTION_REMOVE_USER,
754            ilStudyProgrammeUserProgress::ACTION_UNMARK_ACCREDITED
755        );
756        $this->assertEquals(
757            $expected,
758            ilStudyProgrammeUserProgress::getPossibleActions(
759                1,
760                1,
761                ilStudyProgrammeProgress::STATUS_ACCREDITED
762            )
763        );
764
765        //node is _not_ root-node, status is "accredited"
766        $expected = array(
767            ilStudyProgrammeUserProgress::ACTION_UNMARK_ACCREDITED
768        );
769        $this->assertEquals(
770            $expected,
771            ilStudyProgrammeUserProgress::getPossibleActions(
772                0,
773                1,
774                ilStudyProgrammeProgress::STATUS_ACCREDITED
775            )
776        );
777    }
778
779    //get progress instance via DB-class
780    public function testGetInstance()
781    {
782        $this->setAllNodesActive();
783        $tmp = $this->assignNewUserToRoot();
784        $ass = $tmp[0];
785        $user = $tmp[1];
786
787        $sp_user_progress_db = ilStudyProgrammeDIC::dic()['ilStudyProgrammeUserProgressDB'];
788        $inst = $sp_user_progress_db->getInstance(
789            $ass->getId(),
790            $this->root->getId(),
791            $user->getId()
792        );
793        $this->assertInstanceOf(ilStudyProgrammeUserProgress::class, $inst);
794        $this->assertEquals(
795            $this->root->getProgressesOf($user->getId()),
796            $sp_user_progress_db->getInstancesForUser($this->root->getId(), $user->getId())
797        );
798
799        $up = $this->root->getProgressesOf($user->getId())[0];
800        $this->assertEquals(
801            $up,
802            $sp_user_progress_db->getInstanceById($up->getId())
803        );
804    }
805
806    public function testGetInstanceCalls()
807    {
808        $sp_user_progress_db = ilStudyProgrammeDIC::dic()['ilStudyProgrammeUserProgressDB'];
809        try {
810            $sp_user_progress_db->getInstanceById(-1);
811            $this->assertFalse("This should not happen");
812        } catch (ilException $e) {
813            $this->assertTrue(true);
814        }
815
816
817        try {
818            $sp_user_progress_db->getInstancesForAssignment(-1);
819            $this->assertFalse("This should not happen");
820        } catch (ilStudyProgrammeNoProgressForAssignmentException $e) {
821            $this->assertTrue(true);
822        }
823    }
824
825    public function test_limited_validity_period()
826    {
827        $prg1 = ilObjStudyProgramme::createInstance();
828        $prg2 = ilObjStudyProgramme::createInstance();
829
830
831        $prg1->putInTree(ROOT_FOLDER_ID);
832        $prg1->addNode($prg2);
833        $prg1->setValidityOfQualificationPeriod(100);
834
835        $prg1->update();
836
837        $prg1->setStatus(ilStudyProgrammeSettings::STATUS_ACTIVE);
838        $prg2->setStatus(ilStudyProgrammeSettings::STATUS_ACTIVE);
839
840        $user = $this->newUser();
841
842        $assignment = $prg1->assignUser($user->getId(), 6);
843        $progress2 = $prg2->getProgressForAssignment($assignment->getId());
844        $progress2->markAccredited(6);
845
846        $progress1 = $prg1->getProgressForAssignment($assignment->getId());
847        $progress2 = $prg2->getProgressForAssignment($assignment->getId());
848
849        $this->assertTrue($progress1->isSuccessful());
850        $this->assertTrue($progress2->isSuccessful());
851        $val_date = new DateTime();
852        $val_date->add(new DateInterval('P100D'));
853        $this->assertEquals(
854            $val_date->format('Ymd'),
855            $progress1->getValidityOfQualification()->format('Ymd')
856        );
857        $this->assertNull($progress2->getValidityOfQualification());
858    }
859
860    public function test_limited_validity_date()
861    {
862        $prg1 = ilObjStudyProgramme::createInstance();
863        $prg2 = ilObjStudyProgramme::createInstance();
864
865
866        $prg1->putInTree(ROOT_FOLDER_ID);
867        $prg1->addNode($prg2);
868        $val_date_ref = new DateTime();
869        $val_date_ref->add(new DateInterval('P100D'));
870        $prg1->setValidityOfQualificationDate($val_date_ref);
871
872        $prg1->update();
873
874        $prg1->setStatus(ilStudyProgrammeSettings::STATUS_ACTIVE);
875        $prg2->setStatus(ilStudyProgrammeSettings::STATUS_ACTIVE);
876
877        $user = $this->newUser();
878
879        $assignment = $prg1->assignUser($user->getId(), 6);
880        $progress2 = $prg2->getProgressForAssignment($assignment->getId());
881        $progress2->markAccredited(6);
882
883        $progress1 = $prg1->getProgressForAssignment($assignment->getId());
884        $progress2 = $prg2->getProgressForAssignment($assignment->getId());
885
886        $this->assertTrue($progress1->isSuccessful());
887        $this->assertTrue($progress2->isSuccessful());
888        $this->assertEquals(
889            $val_date_ref->format('Ymd'),
890            $progress1->getValidityOfQualification()->format('Ymd')
891        );
892    }
893
894
895    public function test_limited_validity_accredited()
896    {
897        $prg1 = ilObjStudyProgramme::createInstance();
898
899
900        $prg1->putInTree(ROOT_FOLDER_ID);
901        $prg1->setValidityOfQualificationPeriod(100);
902        $prg1->update();
903
904        $prg1->setStatus(ilStudyProgrammeSettings::STATUS_ACTIVE);
905
906        $user = $this->newUser();
907
908        $assignment = $prg1->assignUser($user->getId(), 6);
909        $progress1 = $prg1->getProgressForAssignment($assignment->getId());
910        $progress1->markAccredited(6);
911
912        $progress1 = $prg1->getProgressForAssignment($assignment->getId());
913
914        $this->assertTrue($progress1->isSuccessful());
915        $val_date = new DateTime();
916        $val_date->add(new DateInterval('P100D'));
917        $this->assertEquals($val_date->format('Ymd'), $progress1->getValidityOfQualification()->format('Ymd'));
918    }
919
920    public function test_set_failed_limited_validity_future()
921    {
922        $prg1 = ilObjStudyProgramme::createInstance();
923        $prg2 = ilObjStudyProgramme::createInstance();
924
925
926        $prg1->putInTree(ROOT_FOLDER_ID);
927        $prg1->addNode($prg2);
928        $val_date_ref = new DateTime();
929        $val_date_ref->add(new DateInterval('P1D'));
930        $prg1->setValidityOfQualificationDate($val_date_ref);
931
932        $prg1->update();
933
934        $prg1->setStatus(ilStudyProgrammeSettings::STATUS_ACTIVE);
935        $prg2->setStatus(ilStudyProgrammeSettings::STATUS_ACTIVE);
936
937        $user = $this->newUser();
938
939        $assignment = $prg1->assignUser($user->getId(), 6);
940        $progress1 = $prg2->getProgressForAssignment($assignment->getId());
941        $this->assertFalse($progress1->isSuccessfulExpired());
942        $progress2 = $prg2->getProgressForAssignment($assignment->getId());
943        $progress2->markAccredited(6);
944
945        $progress1 = $prg1->getProgressForAssignment($assignment->getId());
946        $this->assertEquals(
947            $val_date_ref->format('Ymd'),
948            $progress1->getValidityOfQualification()->format('Ymd')
949        );
950        $this->assertTrue($progress1->isSuccessful());
951        $this->assertFalse($progress1->isSuccessfulExpired());
952        try {
953            $progress1->markFailed(6);
954            $this->assertFalse('did not throw');
955        } catch (ilException $e) {
956            $this->assertTrue(true);
957        }
958    }
959
960    public function test_set_failed_limited_validity_past()
961    {
962        $prg1 = ilObjStudyProgramme::createInstance();
963        $prg2 = ilObjStudyProgramme::createInstance();
964
965
966        $prg1->putInTree(ROOT_FOLDER_ID);
967        $prg1->addNode($prg2);
968        $val_date_ref = new DateTime();
969        $val_date_ref->sub(new DateInterval('P1D'));
970        $prg1->setValidityOfQualificationDate($val_date_ref);
971
972        $prg1->update();
973
974        $prg1->setStatus(ilStudyProgrammeSettings::STATUS_ACTIVE);
975        $prg2->setStatus(ilStudyProgrammeSettings::STATUS_ACTIVE);
976
977        $user = $this->newUser();
978
979        $assignment = $prg1->assignUser($user->getId(), 6);
980        $progress1 = $prg2->getProgressForAssignment($assignment->getId());
981        $this->assertFalse($progress1->isSuccessfulExpired());
982        $progress2 = $prg2->getProgressForAssignment($assignment->getId());
983        $progress2->markAccredited(6);
984
985        $progress1 = $prg1->getProgressForAssignment($assignment->getId());
986        $this->assertEquals(
987            $val_date_ref->format('Ymd'),
988            $progress1->getValidityOfQualification()->format('Ymd')
989        );
990        $this->assertTrue($progress1->isSuccessful());
991        $this->assertTrue($progress1->isSuccessfulExpired());
992        try {
993            $progress1->invalidate();
994            $this->assertTrue(true);
995        } catch (ilException $e) {
996            $this->assertFalse('did throw');
997        }
998        $this->assertTrue($progress1->isSuccessful());
999        $this->assertTrue($progress1->isInvalidated());
1000    }
1001
1002
1003    public function test_set_failed_no_limited_validity()
1004    {
1005        $prg1 = ilObjStudyProgramme::createInstance();
1006        $prg2 = ilObjStudyProgramme::createInstance();
1007
1008
1009        $prg1->putInTree(ROOT_FOLDER_ID);
1010        $prg1->addNode($prg2);
1011
1012        $prg1->update();
1013
1014        $prg1->setStatus(ilStudyProgrammeSettings::STATUS_ACTIVE);
1015        $prg2->setStatus(ilStudyProgrammeSettings::STATUS_ACTIVE);
1016
1017        $user = $this->newUser();
1018
1019        $assignment = $prg1->assignUser($user->getId(), 6);
1020        $progress1 = $prg2->getProgressForAssignment($assignment->getId());
1021        $this->assertFalse($progress1->isSuccessfulExpired());
1022        $progress2 = $prg2->getProgressForAssignment($assignment->getId());
1023        $progress2->markAccredited(6);
1024
1025        $progress1 = $prg1->getProgressForAssignment($assignment->getId());
1026        $this->assertNull($progress1->getValidityOfQualification());
1027        $this->assertTrue($progress1->isSuccessful());
1028        $this->assertFalse($progress1->isSuccessfulExpired());
1029        try {
1030            $progress1->invalidate();
1031            $this->assertFalse('did not throw');
1032        } catch (ilException $e) {
1033            $this->assertTrue(true);
1034        }
1035        $this->assertFalse($progress1->isInvalidated());
1036    }
1037}
1038