Proyectos de Subversion Moodle

Rev

Rev 1 | | Comparar con el anterior | Ultima modificación | Ver Log |

Rev Autor Línea Nro. Línea
1 efrain 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
 * This file contains unit test related to xAPI library.
19
 *
20
 * @package    core_xapi
21
 * @copyright  2020 Ferran Recio
22
 * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
23
 */
24
 
25
namespace core_xapi\local;
26
 
27
use core_xapi\local\statement\item;
28
use core_xapi\local\statement\item_actor;
29
use core_xapi\local\statement\item_object;
30
use core_xapi\local\statement\item_activity;
31
use core_xapi\local\statement\item_verb;
32
use core_xapi\local\statement\item_agent;
33
use core_xapi\local\statement\item_group;
34
use core_xapi\local\statement\item_result;
35
use core_xapi\local\statement\item_attachment;
36
use core_xapi\local\statement\item_context;
37
use core_xapi\iri;
38
use core_xapi\xapi_exception;
39
use advanced_testcase;
40
use stdClass;
41
 
42
defined('MOODLE_INTERNAL') || die();
43
 
44
/**
45
 * Contains test cases for testing statement class.
46
 *
47
 * @package    core_xapi
48
 * @since      Moodle 3.9
49
 * @copyright  2020 Ferran Recio
50
 * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
51
 */
52
class statement_test extends advanced_testcase {
53
 
54
    /**
55
     * Returns a valid item for a specific attribute.
56
     *
57
     * @param string $itemname statement item name
58
     * @return item the resulting item
59
     */
60
    private function get_valid_item(string $itemname): item {
61
        global $USER, $CFG;
62
        switch ($itemname) {
63
            case 'attachments':
64
            case 'attachment':
65
                $data = (object) [
66
                    'usageType' => iri::generate('example', 'attachment'),
67
                    'display' => (object) [
68
                        'en-US' => 'Example',
69
                    ],
70
                    'description' => (object) [
71
                        'en-US' => 'Description example',
72
                    ],
73
                    "contentType" => "image/jpg",
74
                    "length" => 1234,
75
                    "sha2" => "b94c0f1cffb77475c6f1899111a0181efe1d6177"
76
                ];
77
                return item_attachment::create_from_data($data);
78
            case 'authority':
79
                $data = (object) [
80
                    'objectType' => 'Agent',
81
                    'account' => (object) [
82
                        'homePage' => $CFG->wwwroot,
83
                        'name' => $USER->id,
84
                    ],
85
                ];
86
                return item_agent::create_from_data($data);
87
        }
88
        // For now, the rest of the optional properties have no validation
89
        // so we create a standard stdClass for all of them.
90
        $data = (object)[
91
            'some' => 'data',
92
        ];
93
        $classname = 'core_xapi\local\statement\item_'.$itemname;
94
        if (class_exists($classname)) {
95
            $item = $classname::create_from_data($data);
96
        } else {
97
            $item = item::create_from_data($data);
98
        }
99
        return $item;
100
    }
101
 
102
    /**
103
     * Test statement creation.
104
     *
105
     * @dataProvider create_provider
106
     * @param bool $useagent if use agent as actor (or group if false)
107
     * @param array $extras extra item elements
108
     * @param array $extravalues extra string values
109
     */
11 efrain 110
    public function test_create(bool $useagent, array $extras, array $extravalues): void {
1 efrain 111
 
112
        $this->resetAfterTest();
113
 
114
        // Create one course with a group.
115
        $course = $this->getDataGenerator()->create_course();
116
        $user = $this->getDataGenerator()->create_user();
117
        $this->getDataGenerator()->enrol_user($user->id, $course->id);
118
        $group = $this->getDataGenerator()->create_group(array('courseid' => $course->id));
119
        $this->getDataGenerator()->create_group_member(array('groupid' => $group->id, 'userid' => $user->id));
120
 
121
        $this->setUser($user);
122
 
123
        // Our statement.
124
        $statement = new statement();
125
 
126
        // Populate statement.
127
        if ($useagent) {
128
            $statement->set_actor(item_agent::create_from_user($user));
129
        } else {
130
            $statement->set_actor(item_group::create_from_group($group));
131
        }
132
        $statement->set_verb(item_verb::create_from_id('cook'));
133
        $statement->set_object(item_activity::create_from_id('paella'));
134
 
135
        foreach ($extras as $extra) {
136
            $method = 'set_'.$extra;
137
            $item = $this->get_valid_item($extra);
138
            $statement->$method($item);
139
        }
140
 
141
        // For now extra values have no validation.
142
        foreach ($extravalues as $extra) {
143
            $method = 'set_'.$extra;
144
            $statement->$method('Example');
145
        }
146
 
147
        // Check resulting statement.
148
        if ($useagent) {
149
            $stuser = $statement->get_user();
150
            $this->assertEquals($user->id, $stuser->id);
151
            $stusers = $statement->get_all_users();
152
            $this->assertCount(1, $stusers);
153
        } else {
154
            $stgroup = $statement->get_group();
155
            $this->assertEquals($group->id, $stgroup->id);
156
            $stusers = $statement->get_all_users();
157
            $this->assertCount(1, $stusers);
158
            $stuser = array_shift($stusers);
159
            $this->assertEquals($user->id, $stuser->id);
160
        }
161
        $this->assertEquals('cook', $statement->get_verb_id());
162
        $this->assertEquals('paella', $statement->get_activity_id());
163
 
164
        // Check resulting json (only first node structure, internal structure
165
        // depends on every item json_encode test).
166
        $data = json_decode(json_encode($statement));
167
        $this->assertNotEmpty($data->actor);
168
        $this->assertNotEmpty($data->verb);
169
        $this->assertNotEmpty($data->object);
170
        $allextras = ['context', 'result', 'timestamp', 'stored', 'authority', 'version', 'attachments'];
171
        $alldefined = array_merge($extras, $extravalues);
172
        foreach ($allextras as $extra) {
173
            if (in_array($extra, $alldefined)) {
174
                $this->assertObjectHasProperty($extra, $data);
175
                $this->assertNotEmpty($data->$extra);
176
            } else {
177
                $this->assertObjectNotHasProperty($extra, $data);
178
            }
179
        }
180
    }
181
 
182
    /**
183
     * Data provider for the test_create and test_create_from_data tests.
184
     *
185
     * @return  array
186
     */
187
    public function create_provider(): array {
188
        return [
189
            'Agent statement with no extras' => [
190
                true, [], []
191
            ],
192
            'Agent statement with context' => [
193
                true, ['context'], []
194
            ],
195
            'Agent statement with result' => [
196
                true, ['result'], []
197
            ],
198
            'Agent statement with timestamp' => [
199
                true, [], ['timestamp']
200
            ],
201
            'Agent statement with stored' => [
202
                true, [], ['stored']
203
            ],
204
            'Agent statement with authority' => [
205
                true, ['authority'], []
206
            ],
207
            'Agent statement with version' => [
208
                true, [], ['version']
209
            ],
210
            'Group statement with no extras' => [
211
                false, [], []
212
            ],
213
            'Group statement with context' => [
214
                false, ['context'], []
215
            ],
216
            'Group statement with result' => [
217
                false, ['result'], []
218
            ],
219
            'Group statement with timestamp' => [
220
                false, [], ['timestamp']
221
            ],
222
            'Group statement with stored' => [
223
                false, [], ['stored']
224
            ],
225
            'Group statement with authority' => [
226
                false, ['authority'], []
227
            ],
228
            'Group statement with version' => [
229
                false, [], ['version']
230
            ],
231
        ];
232
    }
233
 
234
    /**
235
     * Test statement creation from xAPI statement data.
236
     *
237
     * @dataProvider create_provider
238
     * @param bool $useagent if use agent as actor (or group if false)
239
     * @param array $extras extra item elements
240
     * @param array $extravalues extra string values
241
     */
11 efrain 242
    public function test_create_from_data(bool $useagent, array $extras, array $extravalues): void {
1 efrain 243
        $this->resetAfterTest();
244
 
245
        // Create one course with a group.
246
        $course = $this->getDataGenerator()->create_course();
247
        $user = $this->getDataGenerator()->create_user();
248
        $this->getDataGenerator()->enrol_user($user->id, $course->id);
249
        $group = $this->getDataGenerator()->create_group(array('courseid' => $course->id));
250
        $this->getDataGenerator()->create_group_member(array('groupid' => $group->id, 'userid' => $user->id));
251
 
252
        $this->setUser($user);
253
 
254
        // Populate data.
255
        if ($useagent) {
256
            $actor = item_agent::create_from_user($user);
257
        } else {
258
            $actor = item_group::create_from_group($group);
259
        }
260
        $verb = item_verb::create_from_id('cook');
261
        $object = item_activity::create_from_id('paella');
262
 
263
        $data = (object) [
264
            'actor' => $actor->get_data(),
265
            'verb' => $verb->get_data(),
266
            'object' => $object->get_data(),
267
        ];
268
 
269
        foreach ($extras as $extra) {
270
            $item = $this->get_valid_item($extra);
271
            $data->$extra = $item->get_data();
272
        }
273
 
274
        // For now extra values have no validation.
275
        foreach ($extravalues as $extra) {
276
            $data->$extra = 'Example';
277
        }
278
 
279
        $statement = statement::create_from_data($data);
280
 
281
        // Check resulting statement.
282
        if ($useagent) {
283
            $stuser = $statement->get_user();
284
            $this->assertEquals($user->id, $stuser->id);
285
            $stusers = $statement->get_all_users();
286
            $this->assertCount(1, $stusers);
287
        } else {
288
            $stgroup = $statement->get_group();
289
            $this->assertEquals($group->id, $stgroup->id);
290
            $stusers = $statement->get_all_users();
291
            $this->assertCount(1, $stusers);
292
            $stuser = array_shift($stusers);
293
            $this->assertEquals($user->id, $stuser->id);
294
        }
295
        $this->assertEquals('cook', $statement->get_verb_id());
296
        $this->assertEquals('paella', $statement->get_activity_id());
297
 
298
        // Check resulting json (only first node structure, internal structure
299
        // depends on every item json_encode test).
300
        $data = json_decode(json_encode($statement));
301
        $this->assertNotEmpty($data->actor);
302
        $this->assertNotEmpty($data->verb);
303
        $this->assertNotEmpty($data->object);
304
        $allextras = ['context', 'result', 'timestamp', 'stored', 'authority', 'version', 'attachments'];
305
        $alldefined = array_merge($extras, $extravalues);
306
        foreach ($allextras as $extra) {
307
            if (in_array($extra, $alldefined)) {
308
                $this->assertObjectHasProperty($extra, $data);
309
                $this->assertNotEmpty($data->object);
310
            } else {
311
                $this->assertObjectNotHasProperty($extra, $data);
312
            }
313
        }
314
    }
315
 
316
    /**
317
     * Test adding attachments to statement.
318
     *
319
     */
11 efrain 320
    public function test_add_attachment(): void {
1 efrain 321
 
322
        // Our statement.
323
        $statement = new statement();
324
 
325
        $attachments = $statement->get_attachments();
326
        $this->assertNull($attachments);
327
 
328
        $item = $this->get_valid_item('attachment');
329
        $itemdata = $item->get_data();
330
        $statement->add_attachment($item);
331
 
332
        $attachments = $statement->get_attachments();
333
        $this->assertNotNull($attachments);
334
        $this->assertCount(1, $attachments);
335
 
336
        $attachment = current($attachments);
337
        $attachmentdata = $attachment->get_data();
338
        $this->assertEquals($itemdata->usageType, $attachmentdata->usageType);
339
        $this->assertEquals($itemdata->length, $attachmentdata->length);
340
 
341
        // Check resulting json.
342
        $statementdata = json_decode(json_encode($statement));
343
        $this->assertObjectHasProperty('attachments', $statementdata);
344
        $this->assertNotEmpty($statementdata->attachments);
345
        $this->assertCount(1, $statementdata->attachments);
346
    }
347
 
348
    /**
349
     * Test adding attachments to statement.
350
     *
351
     */
11 efrain 352
    public function test_add_attachment_from_data(): void {
1 efrain 353
 
354
        $this->resetAfterTest();
355
 
356
        $user = $this->getDataGenerator()->create_user();
357
        $this->setUser($user);
358
 
359
        $actor = item_agent::create_from_user($user);
360
        $verb = item_verb::create_from_id('cook');
361
        $object = item_activity::create_from_id('paella');
362
 
363
        $data = (object) [
364
            'actor' => $actor->get_data(),
365
            'verb' => $verb->get_data(),
366
            'object' => $object->get_data(),
367
        ];
368
 
369
        $item = $this->get_valid_item('attachment');
370
        $itemdata = $item->get_data();
371
        $data->attachments = [$itemdata];
372
 
373
        $statement = statement::create_from_data($data);
374
 
375
        $attachments = $statement->get_attachments();
376
        $this->assertNotNull($attachments);
377
        $this->assertCount(1, $attachments);
378
 
379
        $attachment = current($attachments);
380
        $attachmentdata = $attachment->get_data();
381
        $this->assertEquals($itemdata->usageType, $attachmentdata->usageType);
382
        $this->assertEquals($itemdata->length, $attachmentdata->length);
383
 
384
        $statementdata = json_decode(json_encode($statement));
385
        $this->assertObjectHasProperty('attachments', $statementdata);
386
        $this->assertNotEmpty($statementdata->attachments);
387
        $this->assertCount(1, $statementdata->attachments);
388
 
389
        // Now try to send an invalid attachments.
390
        $this->expectException(xapi_exception::class);
391
        $data->attachments = 'Invalid data';
392
        $statement = statement::create_from_data($data);
393
    }
394
 
395
    /**
396
     * Test all getters into a not set statement.
397
     *
398
     * @dataProvider invalid_gets_provider
399
     * @param string $method the method to test
400
     * @param bool $exception if an exception is expected
401
     */
11 efrain 402
    public function test_invalid_gets(string $method, bool $exception): void {
1 efrain 403
        $statement = new statement();
404
        if ($exception) {
405
            $this->expectException(xapi_exception::class);
406
        }
407
        $result = $statement->$method();
408
        $this->assertNull($result);
409
    }
410
 
411
    /**
412
     * Data provider for the text_invalid_gets.
413
     *
414
     * @return  array
415
     */
416
    public function invalid_gets_provider(): array {
417
        return [
418
            'Method get_user on empty statement' => ['get_user', true],
419
            'Method get_all_users on empty statement' => ['get_all_users', true],
420
            'Method get_group on empty statement' => ['get_group', true],
421
            'Method get_verb_id on empty statement' => ['get_verb_id', true],
422
            'Method get_activity_id on empty statement' => ['get_activity_id', true],
423
            'Method get_actor on empty statement' => ['get_actor', false],
424
            'Method get_verb on empty statement' => ['get_verb', false],
425
            'Method get_object on empty statement' => ['get_object', false],
426
            'Method get_context on empty statement' => ['get_context', false],
427
            'Method get_result on empty statement' => ['get_result', false],
428
            'Method get_timestamp on empty statement' => ['get_timestamp', false],
429
            'Method get_stored on empty statement' => ['get_stored', false],
430
            'Method get_authority on empty statement' => ['get_authority', false],
431
            'Method get_version on empty statement' => ['get_version', false],
432
            'Method get_attachments on empty statement' => ['get_attachments', false],
433
        ];
434
    }
435
 
436
    /**
437
     * Try to get a user from a group statement.
438
     */
11 efrain 439
    public function test_invalid_get_user(): void {
1 efrain 440
 
441
        $this->resetAfterTest();
442
 
443
        // Create one course with a group.
444
        $course = $this->getDataGenerator()->create_course();
445
        $user = $this->getDataGenerator()->create_user();
446
        $this->getDataGenerator()->enrol_user($user->id, $course->id);
447
        $group = $this->getDataGenerator()->create_group(array('courseid' => $course->id));
448
        $this->getDataGenerator()->create_group_member(array('groupid' => $group->id, 'userid' => $user->id));
449
 
450
        // Our statement.
451
        $statement = new statement();
452
 
453
        // Populate statement.
454
        $statement->set_actor(item_group::create_from_group($group));
455
        $statement->set_verb(item_verb::create_from_id('cook'));
456
        $statement->set_object(item_activity::create_from_id('paella'));
457
 
458
        $this->expectException(xapi_exception::class);
459
        $statement->get_user();
460
    }
461
 
462
    /**
463
     * Try to get a group from an agent statement.
464
     */
11 efrain 465
    public function test_invalid_get_group(): void {
1 efrain 466
        $this->resetAfterTest();
467
 
468
        $user = $this->getDataGenerator()->create_user();
469
 
470
        // Our statement.
471
        $statement = new statement();
472
 
473
        // Populate statement.
474
        $statement->set_actor(item_agent::create_from_user($user));
475
        $statement->set_verb(item_verb::create_from_id('cook'));
476
        $statement->set_object(item_activity::create_from_id('paella'));
477
 
478
        $this->expectException(xapi_exception::class);
479
        $statement->get_group();
480
    }
481
 
482
    /**
483
     * Try to get activity Id from a statement with agent object.
484
     */
11 efrain 485
    public function test_invalid_get_activity_id(): void {
1 efrain 486
        $this->resetAfterTest();
487
 
488
        $user = $this->getDataGenerator()->create_user();
489
 
490
        // Our statement.
491
        $statement = new statement();
492
 
493
        // Populate statement with and agent object.
494
        $statement->set_actor(item_agent::create_from_user($user));
495
        $statement->set_verb(item_verb::create_from_id('cook'));
496
        $statement->set_object(item_agent::create_from_user($user));
497
 
498
        $this->expectException(xapi_exception::class);
499
        $statement->get_activity_id();
500
    }
501
 
502
    /**
503
     * Test for invalid structures.
504
     *
505
     * @dataProvider invalid_data_provider
506
     * @param bool $useuser if use user into statement
507
     * @param bool $userverb if use verb into statement
508
     * @param bool $useobject if use object into statement
509
     */
510
    public function test_invalid_data(bool $useuser, bool $userverb, bool $useobject): void {
511
 
512
        $data = new stdClass();
513
 
514
        if ($useuser) {
515
            $this->resetAfterTest();
516
            $user = $this->getDataGenerator()->create_user();
517
            $data->actor = item_agent::create_from_user($user);
518
        }
519
        if ($userverb) {
520
            $data->verb = item_verb::create_from_id('cook');
521
        }
522
        if ($useobject) {
523
            $data->object = item_activity::create_from_id('paella');
524
        }
525
 
526
        $this->expectException(xapi_exception::class);
527
        $statement = statement::create_from_data($data);
528
    }
529
 
530
    /**
531
     * Data provider for the test_invalid_data tests.
532
     *
533
     * @return  array
534
     */
535
    public function invalid_data_provider(): array {
536
        return [
537
            'No actor, no verb, no object'  => [false, false, false],
538
            'No actor, verb, no object'     => [false, true, false],
539
            'No actor, no verb, object'     => [false, false, true],
540
            'No actor, verb, object'        => [false, true, true],
541
            'Actor, no verb, no object'     => [true, false, false],
542
            'Actor, verb, no object'        => [true, true, false],
543
            'Actor, no verb, object'        => [true, false, true],
544
        ];
545
    }
546
 
547
    /**
548
     * Test minify statement.
549
     */
11 efrain 550
    public function test_minify(): void {
1 efrain 551
 
552
        $this->resetAfterTest();
553
 
554
        $user = $this->getDataGenerator()->create_user();
555
 
556
        $this->setUser($user);
557
 
558
        // Our statement.
559
        $statement = new statement();
560
 
561
        // Populate statement.
562
        $statement->set_actor(item_agent::create_from_user($user));
563
        $statement->set_verb(item_verb::create_from_id('cook'));
564
        $statement->set_object(item_activity::create_from_id('paella'));
565
        $statement->set_result($this->get_valid_item('result'));
566
        $statement->set_context($this->get_valid_item('context'));
567
        $statement->set_authority($this->get_valid_item('authority'));
568
        $statement->add_attachment($this->get_valid_item('attachment'));
569
        $statement->set_version('Example');
570
        $statement->set_timestamp('Example');
571
        $statement->set_stored('Example');
572
 
573
        $min = $statement->minify();
574
 
575
        // Check calculated fields.
576
        $this->assertCount(6, $min);
577
        $this->assertArrayNotHasKey('actor', $min);
578
        $this->assertArrayHasKey('verb', $min);
579
        $this->assertArrayHasKey('object', $min);
580
        $this->assertArrayHasKey('context', $min);
581
        $this->assertArrayHasKey('result', $min);
582
        $this->assertArrayNotHasKey('timestamp', $min);
583
        $this->assertArrayNotHasKey('stored', $min);
584
        $this->assertArrayHasKey('authority', $min);
585
        $this->assertArrayNotHasKey('version', $min);
586
        $this->assertArrayHasKey('attachments', $min);
587
    }
588
}