Proyectos de Subversion Moodle

Rev

| 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
namespace tool_courserating;
18
 
19
use core\event\base;
20
use tool_courserating\event\flag_created;
21
use tool_courserating\event\flag_deleted;
22
use tool_courserating\event\rating_created;
23
use tool_courserating\event\rating_deleted;
24
use tool_courserating\event\rating_updated;
25
use tool_courserating\local\models\rating;
26
use tool_courserating\local\models\summary;
27
 
28
/**
29
 * Tests for api class
30
 *
31
 * @package     tool_courserating
32
 * @covers      \tool_courserating\api
33
 * @copyright   2022 Marina Glancy <marina.glancy@gmail.com>
34
 * @license     https://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
35
 */
36
final class api_test extends \advanced_testcase {
37
 
38
    /**
39
     * Set up
40
     */
41
    public function setUp(): void {
42
        $this->resetAfterTest();
43
        set_config(\tool_courserating\constants::SETTING_RATINGMODE,
44
            \tool_courserating\constants::RATEBY_ANYTIME, 'tool_courserating');
45
    }
46
 
47
    /**
48
     * Generator
49
     *
50
     * @return \tool_courserating_generator
51
     */
52
    protected function get_generator(): \tool_courserating_generator {
53
        /** @var \tool_courserating_generator $generator */
54
        $generator = self::getDataGenerator()->get_plugin_generator('tool_courserating');
55
        return $generator;
56
    }
57
 
58
    /**
59
     * Assert rating in the database matches expectations
60
     *
61
     * @param array|null $expected
62
     * @param int $userid
63
     * @param int $courseid
64
     */
65
    protected function assert_rating(?array $expected, int $userid, int $courseid) {
66
        global $DB;
67
 
68
        $params = ['courseid' => $courseid, 'userid' => $userid];
69
        if (empty($expected)) {
70
            $this->assertEmpty($DB->get_records(rating::TABLE, $params));
71
        } else {
72
            $fields = join(', ', array_keys($expected));
73
            $this->assertEquals($expected,
74
                (array)$DB->get_record(rating::TABLE, $params, $fields, MUST_EXIST));
75
        }
76
    }
77
 
78
    /**
79
     * Assert summary in the database matches expectations
80
     *
81
     * @param array $expected
82
     * @param int $courseid
83
     */
84
    protected function assert_summary(array $expected, int $courseid) {
85
        global $DB;
86
 
87
        $cfield = $DB->get_field_sql('SELECT d.value FROM {customfield_field} f
88
            JOIN {customfield_data} d ON d.fieldid = f.id
89
            JOIN {customfield_category} c ON f.categoryid = c.id
90
            WHERE f.shortname = ? AND d.instanceid = ?
91
                  AND c.component = ? AND c.area = ?',
92
            [constants::CFIELD_RATING, $courseid, 'core_course', 'course']);
93
 
94
        $params = ['courseid' => $courseid];
95
        if (empty($expected)) {
96
            $this->assertEmpty($DB->get_records(summary::TABLE, $params));
97
            $this->assertEmpty($cfield);
98
        } else {
99
            $record = (array)$DB->get_record(summary::TABLE, $params, '*', MUST_EXIST);
100
            $this->assertEquals($expected, array_intersect_key($record, $expected));
101
        }
102
 
103
        if ($record['cntall'] ?? 0) {
104
            $this->assertStringContainsString("({$record['cntall']})", strip_tags($cfield));
105
        } else {
106
            $this->assertEmpty($cfield);
107
        }
108
    }
109
 
110
    /**
111
     * Assert contents of an event
112
     *
113
     * @param \phpunit_event_sink $sink
114
     * @param string $classname
115
     * @param int $courseid
116
     * @param string $namematch
117
     * @param string $descriptionmatch
118
     * @return void
119
     */
120
    protected function assert_event(\phpunit_event_sink $sink, string $classname, int $courseid,
121
                                    string $namematch, string $descriptionmatch) {
122
        $events = $sink->get_events();
123
        $this->assertEquals(1, count($events));
124
        /** @var base $event */
125
        $event = reset($events);
126
        $this->assertEquals($classname, ltrim($event->eventname, '\\'));
127
        $this->assertEquals($courseid, $event->courseid);
128
        $this->assertEquals(\context_course::instance($courseid)->id, $event->contextid);
129
        $this->assertStringMatchesFormat($namematch, $event->get_name());
130
        $this->assertStringMatchesFormat($descriptionmatch, $event->get_description());
131
 
132
        $sink->clear();
133
    }
134
 
135
    public function test_set_rating(): void {
136
        $user = $this->getDataGenerator()->create_user();
137
        $user2 = $this->getDataGenerator()->create_user();
138
        $course = $this->getDataGenerator()->create_course();
139
 
140
        $this->assert_rating([], $user->id, $course->id);
141
        $this->assert_rating([], $user2->id, $course->id);
142
        $this->assert_summary(['cntall' => 0], $course->id);
143
 
144
        // Set rating as the first user.
145
        $this->setUser($user);
146
        $sink = $this->redirectEvents();
147
        api::set_rating($course->id, (object)['rating' => 4]);
148
        $this->assert_event($sink, rating_created::class, $course->id, 'Course rating created',
149
            '%ahas rated the course with 4 stars');
150
 
151
        $this->assert_rating(['rating' => 4, 'review' => ''], $user->id, $course->id);
152
        $expected = ['cntall' => 1, 'avgrating' => 4, 'sumrating' => 4, 'cnt02' => 0, 'cnt03' => 0, 'cnt04' => 1];
153
        $this->assert_summary($expected, $course->id);
154
 
155
        // Set rating as the second user.
156
        $this->setUser($user2);
157
        api::set_rating($course->id, (object)['rating' => 2]);
158
 
159
        $this->assert_rating(['rating' => 4, 'review' => ''], $user->id, $course->id);
160
        $this->assert_rating(['rating' => 2, 'review' => ''], $user2->id, $course->id);
161
        $expected = ['cntall' => 2, 'avgrating' => 3, 'sumrating' => 6, 'cnt02' => 1, 'cnt03' => 0, 'cnt04' => 1];
162
        $this->assert_summary($expected, $course->id);
163
 
164
        // Change rating as the first user.
165
        $this->setUser($user);
166
        $sink->clear();
167
        api::set_rating($course->id, (object)['rating' => 3, 'review' => 'hello']);
168
        $this->assert_event($sink, rating_updated::class, $course->id, 'Course rating updated',
169
            'User %a has changed the rating for the course from 4 to 3');
170
 
171
        $this->assert_rating(['rating' => 3, 'review' => 'hello', 'hasreview' => 1], $user->id, $course->id);
172
        $this->assert_rating(['rating' => 2, 'review' => '', 'hasreview' => 0], $user2->id, $course->id);
173
        $expected = ['cntall' => 2, 'avgrating' => 2.5, 'sumrating' => 5, 'cnt02' => 1, 'cnt03' => 1, 'cnt04' => 0,
174
            'cntreviews' => 1, ];
175
        $this->assert_summary($expected, $course->id);
176
 
177
        summary::get_for_course($course->id)->recalculate();
178
        $this->assert_summary($expected, $course->id);
179
    }
180
 
181
    public function test_delete_rating(): void {
182
        $user = $this->getDataGenerator()->create_user();
183
        $user2 = $this->getDataGenerator()->create_user();
184
        $course = $this->getDataGenerator()->create_course();
185
 
186
        // Set rating as the first user.
187
        $this->setUser($user);
188
        api::set_rating($course->id, (object)['rating' => 4]);
189
 
190
        // Set rating as the second user.
191
        $this->setUser($user2);
192
        api::set_rating($course->id, (object)['rating' => 2]);
193
 
194
        $this->assert_rating(['rating' => 4, 'review' => ''], $user->id, $course->id);
195
        $this->assert_rating(['rating' => 2, 'review' => ''], $user2->id, $course->id);
196
        $expected = ['cntall' => 2, 'avgrating' => 3, 'sumrating' => 6, 'cnt02' => 1, 'cnt03' => 0, 'cnt04' => 1];
197
        $this->assert_summary($expected, $course->id);
198
        $rating = rating::get_record(['userid' => $user->id, 'courseid' => $course->id]);
199
 
200
        // Delete rating for the first user.
201
        $sink = $this->redirectEvents();
202
        api::delete_rating($rating->get('id'));
203
        $this->assert_event($sink, rating_deleted::class, $course->id, 'Course rating deleted',
204
            '%ahas deleted course rating%a');
205
 
206
        $this->assert_rating(null, $user->id, $course->id);
207
        $this->assert_rating(['rating' => 2, 'review' => ''], $user2->id, $course->id);
208
        $expected = ['cntall' => 1, 'avgrating' => 2, 'sumrating' => 2, 'cnt02' => 1, 'cnt03' => 0, 'cnt04' => 0];
209
        $this->assert_summary($expected, $course->id);
210
    }
211
 
212
    public function test_flag_rating(): void {
213
        $user = $this->getDataGenerator()->create_user();
214
        $user2 = $this->getDataGenerator()->create_user();
215
        $course = $this->getDataGenerator()->create_course();
216
 
217
        // Set rating as the first user.
218
        $this->setUser($user);
219
        $rating = api::set_rating($course->id, (object)['rating' => 4]);
220
 
221
        // Flag rating as the second user.
222
        $this->setUser($user2);
223
        $sink = $this->redirectEvents();
224
        api::flag_review($rating->get('id'));
225
        $this->assert_event($sink, flag_created::class, $course->id, 'Course rating flagged',
226
            '%ahas flagged the course rating%a');
227
 
228
        // Revoke.
229
        api::revoke_review_flag($rating->get('id'));
230
        $this->assert_event($sink, flag_deleted::class, $course->id, 'Course rating flag revoked',
231
            '%ahas revoked their flag%a');
232
 
233
        // Flag again and delete rating as admin.
234
        api::flag_review($rating->get('id'));
235
        $this->assert_event($sink, flag_created::class, $course->id, 'Course rating flagged',
236
            '%ahas flagged the course rating%a');
237
        $this->setAdminUser();
238
        api::delete_rating($rating->get('id'), 'spam');
239
        $this->assert_event($sink, rating_deleted::class, $course->id, 'Course rating deleted',
240
            '%ahas deleted course rating%a. Reason provided: spam');
241
    }
242
 
243
    public function test_reindex(): void {
244
        $user = $this->getDataGenerator()->create_user();
245
        $user2 = $this->getDataGenerator()->create_user();
246
        $course = $this->getDataGenerator()->create_course();
247
 
248
        $this->assert_rating([], $user->id, $course->id);
249
        $this->assert_rating([], $user2->id, $course->id);
250
        $this->assert_summary(['cntall' => 0], $course->id);
251
 
252
        // Set rating as the first user.
253
        $this->setUser($user);
254
        $sink = $this->redirectEvents();
255
        api::set_rating($course->id, (object)['rating' => 4]);
256
        $this->assert_event($sink, rating_created::class, $course->id, 'Course rating created',
257
            '%ahas rated the course with 4 stars');
258
 
259
        $this->assert_rating(['rating' => 4, 'review' => ''], $user->id, $course->id);
260
        $expected = ['cntall' => 1, 'avgrating' => 4, 'sumrating' => 4, 'cnt02' => 0, 'cnt03' => 0, 'cnt04' => 1];
261
        $this->assert_summary($expected, $course->id);
262
 
263
        api::reindex();
264
 
265
        $this->assert_rating(['rating' => 4, 'review' => ''], $user->id, $course->id);
266
        $expected = ['cntall' => 1, 'avgrating' => 4, 'sumrating' => 4, 'cnt02' => 0, 'cnt03' => 0, 'cnt04' => 1];
267
        $this->assert_summary($expected, $course->id);
268
    }
269
 
270
    public function test_create_rating(): void {
271
        $user = $this->getDataGenerator()->create_user();
272
        $course = $this->getDataGenerator()->create_course();
273
        $this->get_generator()->create_rating($user->id, $course->id, 3);
274
        $this->assertEquals(3, summary::get_for_course($course->id)->get('avgrating'));
275
    }
276
}