Completed
Pull Request — master (#216)
by Will
01:38
created

CommentsTest::testGetRepliesEnabled()   B

Complexity

Conditions 1
Paths 1

Size

Total Lines 38
Code Lines 22

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
dl 0
loc 38
rs 8.8571
c 1
b 0
f 0
cc 1
eloc 22
nc 1
nop 0
1
<?php
2
3
namespace SilverStripe\Comments\Tests;
4
5
use HTMLPurifier_Config;
6
use HTMLPurifier;
7
use ReflectionClass;
8
use SilverStripe\Comments\Extensions\CommentsExtension;
9
use SilverStripe\Comments\Model\Comment;
10
use SilverStripe\Comments\Tests\Stubs\CommentableItem;
11
use SilverStripe\Comments\Tests\Stubs\CommentableItemDisabled;
12
use SilverStripe\Comments\Tests\Stubs\CommentableItemEnabled;
13
use SilverStripe\Control\Controller;
14
use SilverStripe\Control\Director;
15
use SilverStripe\Core\Config\Config;
16
use SilverStripe\Core\Email\Email;
17
use SilverStripe\Dev\FunctionalTest;
18
use SilverStripe\Dev\TestOnly;
19
use SilverStripe\i18n\i18n;
20
use SilverStripe\ORM\DataObject;
21
use SilverStripe\Security\Member;
22
use SilverStripe\Security\Security;
23
use SilverStripe\Security\Permission;
24
25
class CommentsTest extends FunctionalTest
26
{
27
    protected static $fixture_file = 'CommentsTest.yml';
28
29
    protected static $extra_dataobjects = array(
30
        CommentableItem::class,
31
        CommentableItemEnabled::class,
32
        CommentableItemDisabled::class
33
    );
34
35
    public function setUp()
36
    {
37
        parent::setUp();
38
        Config::nest();
39
40
        // Set good default values
41
        Config::modify()->merge(CommentsExtension::class, 'comments', array(
42
            'enabled' => true,
43
            'comment_permalink_prefix' => 'comment-'
44
        ));
45
    }
46
47
    public function tearDown()
48
    {
49
        Config::unnest();
50
        parent::tearDown();
51
    }
52
53
    public function testCommentsList()
54
    {
55
        // comments don't require moderation so unmoderated comments can be
56
        // shown but not spam posts
57
        Config::modify()->set(CommentableItem::class, 'comments', array(
58
            'require_moderation_nonmembers' => false,
59
            'require_moderation' => false,
60
            'require_moderation_cms' => false,
61
        ));
62
63
        $item = $this->objFromFixture(CommentableItem::class, 'spammed');
64
65
        $this->assertDOSEquals(array(
66
            array('Name' => 'Comment 1'),
67
            array('Name' => 'Comment 3')
68
        ), $item->Comments(), 'Only 2 non spam posts should be shown');
0 ignored issues
show
Unused Code introduced by
The call to CommentsTest::assertDOSEquals() has too many arguments starting with 'Only 2 non spam posts should be shown'.

This check compares calls to functions or methods with their respective definitions. If the call has more arguments than are defined, it raises an issue.

If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress.

In this case you can add the @ignore PhpDoc annotation to the duplicate definition and it will be ignored.

Loading history...
69
70
        // when moderated, only moderated, non spam posts should be shown.
71
        Config::modify()->set(CommentableItem::class, 'comments', array('require_moderation_nonmembers' => true));
72
73
        // Check that require_moderation overrides this option
74
        Config::modify()->set(CommentableItem::class, 'comments', array('require_moderation' => true));
75
76
        $this->assertDOSEquals(array(
77
            array('Name' => 'Comment 3')
78
        ), $item->Comments(), 'Only 1 non spam, moderated post should be shown');
0 ignored issues
show
Unused Code introduced by
The call to CommentsTest::assertDOSEquals() has too many arguments starting with 'Only 1 non spam, moderated post should be shown'.

This check compares calls to functions or methods with their respective definitions. If the call has more arguments than are defined, it raises an issue.

If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress.

In this case you can add the @ignore PhpDoc annotation to the duplicate definition and it will be ignored.

Loading history...
79
        $this->assertEquals(1, $item->Comments()->Count());
80
81
        // require_moderation_nonmembers still filters out unmoderated comments
82
        Config::modify()->set(CommentableItem::class, 'comments', array('require_moderation' => false));
83
        $this->assertEquals(1, $item->Comments()->Count());
84
85
        Config::modify()->set(CommentableItem::class, 'comments', array('require_moderation_nonmembers' => false));
86
        $this->assertEquals(2, $item->Comments()->Count());
87
88
        // With unmoderated comments set to display in frontend
89
        Config::modify()->set(CommentableItem::class, 'comments', array(
90
            'require_moderation' => true,
91
            'frontend_moderation' => true
92
        ));
93
        $this->assertEquals(1, $item->Comments()->Count());
94
95
        $this->logInWithPermission('ADMIN');
96
        $this->assertEquals(2, $item->Comments()->Count());
97
98
        // With spam comments set to display in frontend
99
        Config::modify()->set(CommentableItem::class, 'comments', array(
100
            'require_moderation' => true,
101
            'frontend_moderation' => false,
102
            'frontend_spam' => true,
103
        ));
104
        if ($member = Member::currentUser()) {
0 ignored issues
show
Deprecated Code introduced by
The method SilverStripe\Security\Member::currentUser() has been deprecated with message: 5.0.0 use Security::getCurrentUser()

This method has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the method will be removed from the class and what other method or class to use instead.

Loading history...
105
            $member->logOut();
0 ignored issues
show
Deprecated Code introduced by
The method SilverStripe\Security\Member::logOut() has been deprecated with message: Use Security::setCurrentUser(null) or an IdentityStore
Logs this member out.

This method has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the method will be removed from the class and what other method or class to use instead.

Loading history...
106
        }
107
        $this->assertEquals(1, $item->Comments()->Count());
108
109
        $this->logInWithPermission('ADMIN');
110
        $this->assertEquals(2, $item->Comments()->Count());
111
112
113
        // With spam and unmoderated comments set to display in frontend
114
        Config::modify()->set(CommentableItem::class, 'comments', array(
115
            'require_moderation' => true,
116
            'frontend_moderation' => true,
117
            'frontend_spam' => true,
118
        ));
119
        if ($member = Member::currentUser()) {
0 ignored issues
show
Deprecated Code introduced by
The method SilverStripe\Security\Member::currentUser() has been deprecated with message: 5.0.0 use Security::getCurrentUser()

This method has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the method will be removed from the class and what other method or class to use instead.

Loading history...
120
            $member->logOut();
0 ignored issues
show
Deprecated Code introduced by
The method SilverStripe\Security\Member::logOut() has been deprecated with message: Use Security::setCurrentUser(null) or an IdentityStore
Logs this member out.

This method has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the method will be removed from the class and what other method or class to use instead.

Loading history...
121
        }
122
        $this->assertEquals(1, $item->Comments()->Count());
123
124
        $this->logInWithPermission('ADMIN');
125
        $this->assertEquals(4, $item->Comments()->Count());
126
    }
127
128
    /**
129
     * Test moderation options configured via the CMS
130
     */
131
    public function testCommentCMSModerationList()
132
    {
133
        Config::modify()->merge(CommentableItem::class, 'comments', array(
134
            'require_moderation' => true,
135
            'require_moderation_cms' => true,
136
        ));
137
138
        $item = $this->objFromFixture(CommentableItem::class, 'spammed');
139
140
        $this->assertEquals('None', $item->getModerationRequired());
141
142
        $this->assertDOSEquals(array(
143
            array('Name' => 'Comment 1'),
144
            array('Name' => 'Comment 3')
145
        ), $item->Comments(), 'Only 2 non spam posts should be shown');
0 ignored issues
show
Unused Code introduced by
The call to CommentsTest::assertDOSEquals() has too many arguments starting with 'Only 2 non spam posts should be shown'.

This check compares calls to functions or methods with their respective definitions. If the call has more arguments than are defined, it raises an issue.

If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress.

In this case you can add the @ignore PhpDoc annotation to the duplicate definition and it will be ignored.

Loading history...
146
147
        // when moderated, only moderated, non spam posts should be shown.
148
        $item->ModerationRequired = 'NonMembersOnly';
149
        $item->write();
150
151
        $this->assertEquals('NonMembersOnly', $item->getModerationRequired());
152
153
        // Check that require_moderation overrides this option
154
        $item->ModerationRequired = 'Required';
155
        $item->write();
156
        $this->assertEquals('Required', $item->getModerationRequired());
157
158
        $this->assertDOSEquals(array(
159
            array('Name' => 'Comment 3')
160
        ), $item->Comments(), 'Only 1 non spam, moderated post should be shown');
0 ignored issues
show
Unused Code introduced by
The call to CommentsTest::assertDOSEquals() has too many arguments starting with 'Only 1 non spam, moderated post should be shown'.

This check compares calls to functions or methods with their respective definitions. If the call has more arguments than are defined, it raises an issue.

If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress.

In this case you can add the @ignore PhpDoc annotation to the duplicate definition and it will be ignored.

Loading history...
161
        $this->assertEquals(1, $item->Comments()->Count());
162
163
        // require_moderation_nonmembers still filters out unmoderated comments
164
        $item->ModerationRequired = 'NonMembersOnly';
165
        $item->write();
166
        $this->assertEquals(1, $item->Comments()->Count());
167
168
        $item->ModerationRequired = 'None';
169
        $item->write();
170
        $this->assertEquals(2, $item->Comments()->Count());
171
    }
172
173
    public function testCanPostComment()
174
    {
175
        Config::modify()->set(CommentableItem::class, 'comments', array(
176
            'require_login' => false,
177
            'require_login_cms' => false,
178
            'required_permission' => false,
179
        ));
180
        $item = $this->objFromFixture(CommentableItem::class, 'first');
181
        $item2 = $this->objFromFixture(CommentableItem::class, 'second');
182
183
        // Test restriction free commenting
184
        if ($member = Member::currentUser()) {
0 ignored issues
show
Deprecated Code introduced by
The method SilverStripe\Security\Member::currentUser() has been deprecated with message: 5.0.0 use Security::getCurrentUser()

This method has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the method will be removed from the class and what other method or class to use instead.

Loading history...
185
            $member->logOut();
0 ignored issues
show
Deprecated Code introduced by
The method SilverStripe\Security\Member::logOut() has been deprecated with message: Use Security::setCurrentUser(null) or an IdentityStore
Logs this member out.

This method has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the method will be removed from the class and what other method or class to use instead.

Loading history...
186
        }
187
        $this->assertFalse($item->CommentsRequireLogin);
188
        $this->assertTrue($item->canPostComment());
189
190
        // Test permission required to post
191
        Config::modify()->set(CommentableItem::class, 'comments', array(
192
            'require_login' => true,
193
            'required_permission' => 'POSTING_PERMISSION',
194
        ));
195
        $this->assertTrue($item->CommentsRequireLogin);
196
        $this->assertFalse($item->canPostComment());
197
        $this->logInWithPermission('WRONG_ONE');
198
        $this->assertFalse($item->canPostComment());
199
        $this->logInWithPermission('POSTING_PERMISSION');
200
        $this->assertTrue($item->canPostComment());
201
        $this->logInWithPermission('ADMIN');
202
        $this->assertTrue($item->canPostComment());
203
204
        // Test require login to post, but not any permissions
205
        Config::modify()->set(CommentableItem::class, 'comments', array(
206
            'required_permission' => false,
207
        ));
208
        $this->assertTrue($item->CommentsRequireLogin);
209
        if ($member = Member::currentUser()) {
0 ignored issues
show
Deprecated Code introduced by
The method SilverStripe\Security\Member::currentUser() has been deprecated with message: 5.0.0 use Security::getCurrentUser()

This method has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the method will be removed from the class and what other method or class to use instead.

Loading history...
210
            $member->logOut();
0 ignored issues
show
Deprecated Code introduced by
The method SilverStripe\Security\Member::logOut() has been deprecated with message: Use Security::setCurrentUser(null) or an IdentityStore
Logs this member out.

This method has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the method will be removed from the class and what other method or class to use instead.

Loading history...
211
        }
212
        $this->assertFalse($item->canPostComment());
213
        $this->logInWithPermission('ANY_PERMISSION');
214
        $this->assertTrue($item->canPostComment());
215
216
        // Test options set via CMS
217
        Config::modify()->set(CommentableItem::class, 'comments', array(
218
            'require_login' => true,
219
            'require_login_cms' => true,
220
        ));
221
        $this->assertFalse($item->CommentsRequireLogin);
222
        $this->assertTrue($item2->CommentsRequireLogin);
223
        if ($member = Member::currentUser()) {
0 ignored issues
show
Deprecated Code introduced by
The method SilverStripe\Security\Member::currentUser() has been deprecated with message: 5.0.0 use Security::getCurrentUser()

This method has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the method will be removed from the class and what other method or class to use instead.

Loading history...
224
            $member->logOut();
0 ignored issues
show
Deprecated Code introduced by
The method SilverStripe\Security\Member::logOut() has been deprecated with message: Use Security::setCurrentUser(null) or an IdentityStore
Logs this member out.

This method has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the method will be removed from the class and what other method or class to use instead.

Loading history...
225
        }
226
        $this->assertTrue($item->canPostComment());
227
        $this->assertFalse($item2->canPostComment());
228
229
        // Login grants permission to post
230
        $this->logInWithPermission('ANY_PERMISSION');
231
        $this->assertTrue($item->canPostComment());
232
        $this->assertTrue($item2->canPostComment());
233
    }
234
    public function testDeleteComment()
235
    {
236
        // Test anonymous user
237
        if ($member = Member::currentUser()) {
0 ignored issues
show
Deprecated Code introduced by
The method SilverStripe\Security\Member::currentUser() has been deprecated with message: 5.0.0 use Security::getCurrentUser()

This method has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the method will be removed from the class and what other method or class to use instead.

Loading history...
238
            $member->logOut();
0 ignored issues
show
Deprecated Code introduced by
The method SilverStripe\Security\Member::logOut() has been deprecated with message: Use Security::setCurrentUser(null) or an IdentityStore
Logs this member out.

This method has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the method will be removed from the class and what other method or class to use instead.

Loading history...
239
        }
240
        $comment = $this->objFromFixture(Comment::class, 'firstComA');
241
        $commentID = $comment->ID;
242
        $this->assertNull($comment->DeleteLink(), 'No permission to see delete link');
243
        $delete = $this->get('comments/delete/' . $comment->ID . '?ajax=1');
244
        $this->assertEquals(403, $delete->getStatusCode());
245
        $check = DataObject::get_by_id(Comment::class, $commentID);
246
        $this->assertTrue($check && $check->exists());
247
248
        // Test non-authenticated user
249
        $this->logInAs('visitor');
250
        $this->assertNull($comment->DeleteLink(), 'No permission to see delete link');
251
252
        // Test authenticated user
253
        $this->logInAs('commentadmin');
254
        $comment = $this->objFromFixture(Comment::class, 'firstComA');
255
        $commentID = $comment->ID;
256
        $adminComment1Link = $comment->DeleteLink();
257
        $this->assertContains('comments/delete/' . $commentID . '?t=', $adminComment1Link);
258
259
        // Test that this link can't be shared / XSS exploited
260
        $this->logInAs('commentadmin2');
261
        $delete = $this->get($adminComment1Link);
262
        $this->assertEquals(400, $delete->getStatusCode());
263
        $check = DataObject::get_by_id(Comment::class, $commentID);
264
        $this->assertTrue($check && $check->exists());
265
266
        // Test that this other admin can delete the comment with their own link
267
        $adminComment2Link = $comment->DeleteLink();
268
        $this->assertNotEquals($adminComment2Link, $adminComment1Link);
269
        $this->autoFollowRedirection = false;
270
        $delete = $this->get($adminComment2Link);
271
        $this->assertEquals(302, $delete->getStatusCode());
272
        $check = DataObject::get_by_id(Comment::class, $commentID);
273
        $this->assertFalse($check && $check->exists());
274
    }
275
276 View Code Duplication
    public function testSpamComment()
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
277
    {
278
        // Test anonymous user
279
        if ($member = Member::currentUser()) {
0 ignored issues
show
Deprecated Code introduced by
The method SilverStripe\Security\Member::currentUser() has been deprecated with message: 5.0.0 use Security::getCurrentUser()

This method has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the method will be removed from the class and what other method or class to use instead.

Loading history...
280
            $member->logOut();
0 ignored issues
show
Deprecated Code introduced by
The method SilverStripe\Security\Member::logOut() has been deprecated with message: Use Security::setCurrentUser(null) or an IdentityStore
Logs this member out.

This method has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the method will be removed from the class and what other method or class to use instead.

Loading history...
281
        }
282
        $comment = $this->objFromFixture(Comment::class, 'firstComA');
283
        $commentID = $comment->ID;
284
        $this->assertNull($comment->SpamLink(), 'No permission to see mark as spam link');
285
        $spam = $this->get('comments/spam/'.$comment->ID.'?ajax=1');
286
        $this->assertEquals(403, $spam->getStatusCode());
287
        $check = DataObject::get_by_id(Comment::class, $commentID);
288
        $this->assertEquals(0, $check->IsSpam, 'No permission to mark as spam');
289
290
        // Test non-authenticated user
291
        $this->logInAs('visitor');
292
        $this->assertNull($comment->SpamLink(), 'No permission to see mark as spam link');
293
294
        // Test authenticated user
295
        $this->logInAs('commentadmin');
296
        $comment = $this->objFromFixture(Comment::class, 'firstComA');
297
        $commentID = $comment->ID;
298
        $adminComment1Link = $comment->SpamLink();
299
        $this->assertContains('comments/spam/' . $commentID . '?t=', $adminComment1Link);
300
301
        // Test that this link can't be shared / XSS exploited
302
        $this->logInAs('commentadmin2');
303
        $spam = $this->get($adminComment1Link);
304
        $this->assertEquals(400, $spam->getStatusCode());
305
        $check = DataObject::get_by_id(Comment::class, $comment->ID);
306
        $this->assertEquals(0, $check->IsSpam, 'No permission to mark as spam');
307
308
        // Test that this other admin can spam the comment with their own link
309
        $adminComment2Link = $comment->SpamLink();
310
        $this->assertNotEquals($adminComment2Link, $adminComment1Link);
311
        $this->autoFollowRedirection = false;
312
        $spam = $this->get($adminComment2Link);
313
        $this->assertEquals(302, $spam->getStatusCode());
314
        $check = DataObject::get_by_id(Comment::class, $commentID);
315
        $this->assertEquals(1, $check->IsSpam);
316
317
        // Cannot re-spam spammed comment
318
        $this->assertNull($check->SpamLink());
319
    }
320
321 View Code Duplication
    public function testHamComment()
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
322
    {
323
        // Test anonymous user
324
        if ($member = Member::currentUser()) {
0 ignored issues
show
Deprecated Code introduced by
The method SilverStripe\Security\Member::currentUser() has been deprecated with message: 5.0.0 use Security::getCurrentUser()

This method has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the method will be removed from the class and what other method or class to use instead.

Loading history...
325
            $member->logOut();
0 ignored issues
show
Deprecated Code introduced by
The method SilverStripe\Security\Member::logOut() has been deprecated with message: Use Security::setCurrentUser(null) or an IdentityStore
Logs this member out.

This method has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the method will be removed from the class and what other method or class to use instead.

Loading history...
326
        }
327
        $comment = $this->objFromFixture(Comment::class, 'secondComC');
328
        $commentID = $comment->ID;
329
        $this->assertNull($comment->HamLink(), 'No permission to see mark as ham link');
330
        $ham = $this->get('comments/ham/' . $comment->ID . '?ajax=1');
331
        $this->assertEquals(403, $ham->getStatusCode());
332
        $check = DataObject::get_by_id(Comment::class, $commentID);
333
        $this->assertEquals(1, $check->IsSpam, 'No permission to mark as ham');
334
335
        // Test non-authenticated user
336
        $this->logInAs('visitor');
337
        $this->assertNull($comment->HamLink(), 'No permission to see mark as ham link');
338
339
        // Test authenticated user
340
        $this->logInAs('commentadmin');
341
        $comment = $this->objFromFixture(Comment::class, 'secondComC');
342
        $commentID = $comment->ID;
343
        $adminComment1Link = $comment->HamLink();
344
        $this->assertContains('comments/ham/' . $commentID . '?t=', $adminComment1Link);
345
346
        // Test that this link can't be shared / XSS exploited
347
        $this->logInAs('commentadmin2');
348
        $ham = $this->get($adminComment1Link);
349
        $this->assertEquals(400, $ham->getStatusCode());
350
        $check = DataObject::get_by_id(Comment::class, $comment->ID);
351
        $this->assertEquals(1, $check->IsSpam, 'No permission to mark as ham');
352
353
        // Test that this other admin can ham the comment with their own link
354
        $adminComment2Link = $comment->HamLink();
355
        $this->assertNotEquals($adminComment2Link, $adminComment1Link);
356
        $this->autoFollowRedirection = false;
357
        $ham = $this->get($adminComment2Link);
358
        $this->assertEquals(302, $ham->getStatusCode());
359
        $check = DataObject::get_by_id(Comment::class, $commentID);
360
        $this->assertEquals(0, $check->IsSpam);
361
362
        // Cannot re-ham hammed comment
363
        $this->assertNull($check->HamLink());
364
    }
365
366 View Code Duplication
    public function testApproveComment()
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
367
    {
368
        // Test anonymous user
369
        if ($member = Member::currentUser()) {
0 ignored issues
show
Deprecated Code introduced by
The method SilverStripe\Security\Member::currentUser() has been deprecated with message: 5.0.0 use Security::getCurrentUser()

This method has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the method will be removed from the class and what other method or class to use instead.

Loading history...
370
            $member->logOut();
0 ignored issues
show
Deprecated Code introduced by
The method SilverStripe\Security\Member::logOut() has been deprecated with message: Use Security::setCurrentUser(null) or an IdentityStore
Logs this member out.

This method has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the method will be removed from the class and what other method or class to use instead.

Loading history...
371
        }
372
        $comment = $this->objFromFixture(Comment::class, 'secondComB');
373
        $commentID = $comment->ID;
374
        $this->assertNull($comment->ApproveLink(), 'No permission to see approve link');
375
        $approve = $this->get('comments/approve/' . $comment->ID . '?ajax=1');
376
        $this->assertEquals(403, $approve->getStatusCode());
377
        $check = DataObject::get_by_id(Comment::class, $commentID);
378
        $this->assertEquals(0, $check->Moderated, 'No permission to approve');
379
380
        // Test non-authenticated user
381
        $this->logInAs('visitor');
382
        $this->assertNull($comment->ApproveLink(), 'No permission to see approve link');
383
384
        // Test authenticated user
385
        $this->logInAs('commentadmin');
386
        $comment = $this->objFromFixture(Comment::class, 'secondComB');
387
        $commentID = $comment->ID;
388
        $adminComment1Link = $comment->ApproveLink();
389
        $this->assertContains('comments/approve/' . $commentID . '?t=', $adminComment1Link);
390
391
        // Test that this link can't be shared / XSS exploited
392
        $this->logInAs('commentadmin2');
393
        $approve = $this->get($adminComment1Link);
394
        $this->assertEquals(400, $approve->getStatusCode());
395
        $check = DataObject::get_by_id(Comment::class, $comment->ID);
396
        $this->assertEquals(0, $check->Moderated, 'No permission to approve');
397
398
        // Test that this other admin can approve the comment with their own link
399
        $adminComment2Link = $comment->ApproveLink();
400
        $this->assertNotEquals($adminComment2Link, $adminComment1Link);
401
        $this->autoFollowRedirection = false;
402
        $approve = $this->get($adminComment2Link);
403
        $this->assertEquals(302, $approve->getStatusCode());
404
        $check = DataObject::get_by_id(Comment::class, $commentID);
405
        $this->assertEquals(1, $check->Moderated);
406
407
        // Cannot re-approve approved comment
408
        $this->assertNull($check->ApproveLink());
409
    }
410
411
    public function testCommenterURLWrite()
412
    {
413
        $comment = new Comment();
414
        // We only care about the CommenterURL, so only set that
415
        // Check a http and https URL. Add more test urls here as needed.
416
        $protocols = array(
417
            'Http',
418
            'Https',
419
        );
420
        $url = '://example.com';
421
422
        foreach ($protocols as $protocol) {
423
            $comment->CommenterURL = $protocol . $url;
0 ignored issues
show
Bug introduced by
The property CommenterURL does not seem to exist. Did you mean Comment?

An attempt at access to an undefined property has been detected. This may either be a typographical error or the property has been renamed but there are still references to its old name.

If you really want to allow access to undefined properties, you can define magic methods to allow access. See the php core documentation on Overloading.

Loading history...
424
            // The protocol should stay as if, assuming it is valid
425
            $comment->write();
426
            $this->assertEquals($comment->CommenterURL, $protocol . $url, $protocol . ':// is a valid protocol');
0 ignored issues
show
Bug introduced by
The property CommenterURL does not seem to exist. Did you mean Comment?

An attempt at access to an undefined property has been detected. This may either be a typographical error or the property has been renamed but there are still references to its old name.

If you really want to allow access to undefined properties, you can define magic methods to allow access. See the php core documentation on Overloading.

Loading history...
427
        }
428
    }
429
430
    public function testSanitizesWithAllowHtml()
431
    {
432
        if (!class_exists('\\HTMLPurifier')) {
433
            $this->markTestSkipped('HTMLPurifier class not found');
434
            return;
435
        }
436
437
        // Add p for paragraph
438
        // NOTE: The config method appears to append to the existing array
439
        Config::modify()->set(CommentableItem::class, 'comments', array(
440
            'html_allowed_elements' => array('p'),
441
        ));
442
443
        // Without HTML allowed
444
        $comment1 = new Comment();
445
        $comment1->AllowHtml = false;
446
        $comment1->ParentClass = CommentableItem::class;
0 ignored issues
show
Documentation introduced by
The property ParentClass does not exist on object<SilverStripe\Comments\Model\Comment>. Since you implemented __set, maybe consider adding a @property annotation.

Since your code implements the magic setter _set, this function will be called for any write access on an undefined variable. You can add the @property annotation to your class or interface to document the existence of this variable.

<?php

/**
 * @property int $x
 * @property int $y
 * @property string $text
 */
class MyLabel
{
    private $properties;

    private $allowedProperties = array('x', 'y', 'text');

    public function __get($name)
    {
        if (isset($properties[$name]) && in_array($name, $this->allowedProperties)) {
            return $properties[$name];
        } else {
            return null;
        }
    }

    public function __set($name, $value)
    {
        if (in_array($name, $this->allowedProperties)) {
            $properties[$name] = $value;
        } else {
            throw new \LogicException("Property $name is not defined.");
        }
    }

}

Since the property has write access only, you can use the @property-write annotation instead.

Of course, you may also just have mistyped another name, in which case you should fix the error.

See also the PhpDoc documentation for @property.

Loading history...
447
        $comment1->Comment = '<p><script>alert("w00t")</script>my comment</p>';
448
        $comment1->write();
449
        $this->assertEquals(
450
            '<p><script>alert("w00t")</script>my comment</p>',
451
            $comment1->Comment,
452
            'Does not remove HTML tags with html_allowed=false, ' .
453
            'which is correct behaviour because the HTML will be escaped'
454
        );
455
456
        // With HTML allowed
457
        $comment2 = new Comment();
458
        $comment2->AllowHtml = true;
459
        $comment2->ParentClass = CommentableItem::class;
0 ignored issues
show
Documentation introduced by
The property ParentClass does not exist on object<SilverStripe\Comments\Model\Comment>. Since you implemented __set, maybe consider adding a @property annotation.

Since your code implements the magic setter _set, this function will be called for any write access on an undefined variable. You can add the @property annotation to your class or interface to document the existence of this variable.

<?php

/**
 * @property int $x
 * @property int $y
 * @property string $text
 */
class MyLabel
{
    private $properties;

    private $allowedProperties = array('x', 'y', 'text');

    public function __get($name)
    {
        if (isset($properties[$name]) && in_array($name, $this->allowedProperties)) {
            return $properties[$name];
        } else {
            return null;
        }
    }

    public function __set($name, $value)
    {
        if (in_array($name, $this->allowedProperties)) {
            $properties[$name] = $value;
        } else {
            throw new \LogicException("Property $name is not defined.");
        }
    }

}

Since the property has write access only, you can use the @property-write annotation instead.

Of course, you may also just have mistyped another name, in which case you should fix the error.

See also the PhpDoc documentation for @property.

Loading history...
460
        $comment2->Comment = '<p><script>alert("w00t")</script>my comment</p>';
461
        $comment2->write();
462
        $this->assertEquals(
463
            '<p>my comment</p>',
464
            $comment2->Comment,
465
            'Removes HTML tags which are not on the whitelist'
466
        );
467
    }
468
469
    public function testDefaultTemplateRendersHtmlWithAllowHtml()
470
    {
471
        if (!class_exists('\\HTMLPurifier')) {
472
            $this->markTestSkipped('HTMLPurifier class not found');
473
        }
474
475
        Config::modify()->set(CommentableItem::class, 'comments', array(
476
            'html_allowed_elements' => array('p'),
477
        ));
478
479
        $item = new CommentableItem();
480
        $item->write();
481
482
        // Without HTML allowed
483
        $comment = new Comment();
484
        $comment->Comment = '<p>my comment</p>';
485
        $comment->AllowHtml = false;
486
        $comment->ParentID = $item->ID;
487
        $comment->ParentClass = CommentableItem::class;
0 ignored issues
show
Documentation introduced by
The property ParentClass does not exist on object<SilverStripe\Comments\Model\Comment>. Since you implemented __set, maybe consider adding a @property annotation.

Since your code implements the magic setter _set, this function will be called for any write access on an undefined variable. You can add the @property annotation to your class or interface to document the existence of this variable.

<?php

/**
 * @property int $x
 * @property int $y
 * @property string $text
 */
class MyLabel
{
    private $properties;

    private $allowedProperties = array('x', 'y', 'text');

    public function __get($name)
    {
        if (isset($properties[$name]) && in_array($name, $this->allowedProperties)) {
            return $properties[$name];
        } else {
            return null;
        }
    }

    public function __set($name, $value)
    {
        if (in_array($name, $this->allowedProperties)) {
            $properties[$name] = $value;
        } else {
            throw new \LogicException("Property $name is not defined.");
        }
    }

}

Since the property has write access only, you can use the @property-write annotation instead.

Of course, you may also just have mistyped another name, in which case you should fix the error.

See also the PhpDoc documentation for @property.

Loading history...
488
        $comment->write();
489
490
        $html = $item->customise(array('CommentsEnabled' => true))->renderWith('CommentsInterface');
491
        $this->assertContains(
492
            '&lt;p&gt;my comment&lt;/p&gt;',
493
            $html
494
        );
495
496
        $comment->AllowHtml = true;
497
        $comment->write();
498
        $html = $item->customise(array('CommentsEnabled' => true))->renderWith('CommentsInterface');
499
        $this->assertContains(
500
            '<p>my comment</p>',
501
            $html
502
        );
503
    }
504
505
506
    /**
507
     * Tests whether comments are enabled or disabled by default
508
     */
509
    public function testDefaultEnabled()
510
    {
511
        Config::modify()->merge(CommentableItem::class, 'comments', array(
512
            'enabled_cms' => true,
513
            'require_moderation_cms' => true,
514
            'require_login_cms' => true
515
        ));
516
517
        // With default = true
518
        $obj = new CommentableItem();
519
        $this->assertTrue((bool)$obj->getCommentsOption('enabled'), "Default setting is enabled");
0 ignored issues
show
Documentation Bug introduced by
The method getCommentsOption does not exist on object<SilverStripe\Comm...\Stubs\CommentableItem>? Since you implemented __call, maybe consider adding a @method annotation.

If you implement __call and you know which methods are available, you can improve IDE auto-completion and static analysis by adding a @method annotation to the class.

This is often the case, when __call is implemented by a parent class and only the child class knows which methods exist:

class ParentClass {
    private $data = array();

    public function __call($method, array $args) {
        if (0 === strpos($method, 'get')) {
            return $this->data[strtolower(substr($method, 3))];
        }

        throw new \LogicException(sprintf('Unsupported method: %s', $method));
    }
}

/**
 * If this class knows which fields exist, you can specify the methods here:
 *
 * @method string getName()
 */
class SomeClass extends ParentClass { }
Loading history...
520
        $this->assertTrue((bool)$obj->ProvideComments);
0 ignored issues
show
Documentation introduced by
The property ProvideComments does not exist on object<SilverStripe\Comm...\Stubs\CommentableItem>. Since you implemented __get, maybe consider adding a @property annotation.

Since your code implements the magic getter _get, this function will be called for any read access on an undefined variable. You can add the @property annotation to your class or interface to document the existence of this variable.

<?php

/**
 * @property int $x
 * @property int $y
 * @property string $text
 */
class MyLabel
{
    private $properties;

    private $allowedProperties = array('x', 'y', 'text');

    public function __get($name)
    {
        if (isset($properties[$name]) && in_array($name, $this->allowedProperties)) {
            return $properties[$name];
        } else {
            return null;
        }
    }

    public function __set($name, $value)
    {
        if (in_array($name, $this->allowedProperties)) {
            $properties[$name] = $value;
        } else {
            throw new \LogicException("Property $name is not defined.");
        }
    }

}

If the property has read access only, you can use the @property-read annotation instead.

Of course, you may also just have mistyped another name, in which case you should fix the error.

See also the PhpDoc documentation for @property.

Loading history...
521
        $this->assertEquals('None', $obj->ModerationRequired);
0 ignored issues
show
Documentation introduced by
The property ModerationRequired does not exist on object<SilverStripe\Comm...\Stubs\CommentableItem>. Since you implemented __get, maybe consider adding a @property annotation.

Since your code implements the magic getter _get, this function will be called for any read access on an undefined variable. You can add the @property annotation to your class or interface to document the existence of this variable.

<?php

/**
 * @property int $x
 * @property int $y
 * @property string $text
 */
class MyLabel
{
    private $properties;

    private $allowedProperties = array('x', 'y', 'text');

    public function __get($name)
    {
        if (isset($properties[$name]) && in_array($name, $this->allowedProperties)) {
            return $properties[$name];
        } else {
            return null;
        }
    }

    public function __set($name, $value)
    {
        if (in_array($name, $this->allowedProperties)) {
            $properties[$name] = $value;
        } else {
            throw new \LogicException("Property $name is not defined.");
        }
    }

}

If the property has read access only, you can use the @property-read annotation instead.

Of course, you may also just have mistyped another name, in which case you should fix the error.

See also the PhpDoc documentation for @property.

Loading history...
522
        $this->assertFalse((bool)$obj->CommentsRequireLogin);
0 ignored issues
show
Documentation introduced by
The property CommentsRequireLogin does not exist on object<SilverStripe\Comm...\Stubs\CommentableItem>. Since you implemented __get, maybe consider adding a @property annotation.

Since your code implements the magic getter _get, this function will be called for any read access on an undefined variable. You can add the @property annotation to your class or interface to document the existence of this variable.

<?php

/**
 * @property int $x
 * @property int $y
 * @property string $text
 */
class MyLabel
{
    private $properties;

    private $allowedProperties = array('x', 'y', 'text');

    public function __get($name)
    {
        if (isset($properties[$name]) && in_array($name, $this->allowedProperties)) {
            return $properties[$name];
        } else {
            return null;
        }
    }

    public function __set($name, $value)
    {
        if (in_array($name, $this->allowedProperties)) {
            $properties[$name] = $value;
        } else {
            throw new \LogicException("Property $name is not defined.");
        }
    }

}

If the property has read access only, you can use the @property-read annotation instead.

Of course, you may also just have mistyped another name, in which case you should fix the error.

See also the PhpDoc documentation for @property.

Loading history...
523
524
        $obj = new CommentableItemEnabled();
525
        $this->assertTrue((bool)$obj->ProvideComments);
0 ignored issues
show
Documentation introduced by
The property ProvideComments does not exist on object<SilverStripe\Comm...CommentableItemEnabled>. Since you implemented __get, maybe consider adding a @property annotation.

Since your code implements the magic getter _get, this function will be called for any read access on an undefined variable. You can add the @property annotation to your class or interface to document the existence of this variable.

<?php

/**
 * @property int $x
 * @property int $y
 * @property string $text
 */
class MyLabel
{
    private $properties;

    private $allowedProperties = array('x', 'y', 'text');

    public function __get($name)
    {
        if (isset($properties[$name]) && in_array($name, $this->allowedProperties)) {
            return $properties[$name];
        } else {
            return null;
        }
    }

    public function __set($name, $value)
    {
        if (in_array($name, $this->allowedProperties)) {
            $properties[$name] = $value;
        } else {
            throw new \LogicException("Property $name is not defined.");
        }
    }

}

If the property has read access only, you can use the @property-read annotation instead.

Of course, you may also just have mistyped another name, in which case you should fix the error.

See also the PhpDoc documentation for @property.

Loading history...
526
        $this->assertEquals('Required', $obj->ModerationRequired);
0 ignored issues
show
Documentation introduced by
The property ModerationRequired does not exist on object<SilverStripe\Comm...CommentableItemEnabled>. Since you implemented __get, maybe consider adding a @property annotation.

Since your code implements the magic getter _get, this function will be called for any read access on an undefined variable. You can add the @property annotation to your class or interface to document the existence of this variable.

<?php

/**
 * @property int $x
 * @property int $y
 * @property string $text
 */
class MyLabel
{
    private $properties;

    private $allowedProperties = array('x', 'y', 'text');

    public function __get($name)
    {
        if (isset($properties[$name]) && in_array($name, $this->allowedProperties)) {
            return $properties[$name];
        } else {
            return null;
        }
    }

    public function __set($name, $value)
    {
        if (in_array($name, $this->allowedProperties)) {
            $properties[$name] = $value;
        } else {
            throw new \LogicException("Property $name is not defined.");
        }
    }

}

If the property has read access only, you can use the @property-read annotation instead.

Of course, you may also just have mistyped another name, in which case you should fix the error.

See also the PhpDoc documentation for @property.

Loading history...
527
        $this->assertTrue((bool)$obj->CommentsRequireLogin);
0 ignored issues
show
Documentation introduced by
The property CommentsRequireLogin does not exist on object<SilverStripe\Comm...CommentableItemEnabled>. Since you implemented __get, maybe consider adding a @property annotation.

Since your code implements the magic getter _get, this function will be called for any read access on an undefined variable. You can add the @property annotation to your class or interface to document the existence of this variable.

<?php

/**
 * @property int $x
 * @property int $y
 * @property string $text
 */
class MyLabel
{
    private $properties;

    private $allowedProperties = array('x', 'y', 'text');

    public function __get($name)
    {
        if (isset($properties[$name]) && in_array($name, $this->allowedProperties)) {
            return $properties[$name];
        } else {
            return null;
        }
    }

    public function __set($name, $value)
    {
        if (in_array($name, $this->allowedProperties)) {
            $properties[$name] = $value;
        } else {
            throw new \LogicException("Property $name is not defined.");
        }
    }

}

If the property has read access only, you can use the @property-read annotation instead.

Of course, you may also just have mistyped another name, in which case you should fix the error.

See also the PhpDoc documentation for @property.

Loading history...
528
529
        $obj = new CommentableItemDisabled();
530
        $this->assertFalse((bool)$obj->ProvideComments);
0 ignored issues
show
Documentation introduced by
The property ProvideComments does not exist on object<SilverStripe\Comm...ommentableItemDisabled>. Since you implemented __get, maybe consider adding a @property annotation.

Since your code implements the magic getter _get, this function will be called for any read access on an undefined variable. You can add the @property annotation to your class or interface to document the existence of this variable.

<?php

/**
 * @property int $x
 * @property int $y
 * @property string $text
 */
class MyLabel
{
    private $properties;

    private $allowedProperties = array('x', 'y', 'text');

    public function __get($name)
    {
        if (isset($properties[$name]) && in_array($name, $this->allowedProperties)) {
            return $properties[$name];
        } else {
            return null;
        }
    }

    public function __set($name, $value)
    {
        if (in_array($name, $this->allowedProperties)) {
            $properties[$name] = $value;
        } else {
            throw new \LogicException("Property $name is not defined.");
        }
    }

}

If the property has read access only, you can use the @property-read annotation instead.

Of course, you may also just have mistyped another name, in which case you should fix the error.

See also the PhpDoc documentation for @property.

Loading history...
531
        $this->assertEquals('None', $obj->ModerationRequired);
0 ignored issues
show
Documentation introduced by
The property ModerationRequired does not exist on object<SilverStripe\Comm...ommentableItemDisabled>. Since you implemented __get, maybe consider adding a @property annotation.

Since your code implements the magic getter _get, this function will be called for any read access on an undefined variable. You can add the @property annotation to your class or interface to document the existence of this variable.

<?php

/**
 * @property int $x
 * @property int $y
 * @property string $text
 */
class MyLabel
{
    private $properties;

    private $allowedProperties = array('x', 'y', 'text');

    public function __get($name)
    {
        if (isset($properties[$name]) && in_array($name, $this->allowedProperties)) {
            return $properties[$name];
        } else {
            return null;
        }
    }

    public function __set($name, $value)
    {
        if (in_array($name, $this->allowedProperties)) {
            $properties[$name] = $value;
        } else {
            throw new \LogicException("Property $name is not defined.");
        }
    }

}

If the property has read access only, you can use the @property-read annotation instead.

Of course, you may also just have mistyped another name, in which case you should fix the error.

See also the PhpDoc documentation for @property.

Loading history...
532
        $this->assertFalse((bool)$obj->CommentsRequireLogin);
0 ignored issues
show
Documentation introduced by
The property CommentsRequireLogin does not exist on object<SilverStripe\Comm...ommentableItemDisabled>. Since you implemented __get, maybe consider adding a @property annotation.

Since your code implements the magic getter _get, this function will be called for any read access on an undefined variable. You can add the @property annotation to your class or interface to document the existence of this variable.

<?php

/**
 * @property int $x
 * @property int $y
 * @property string $text
 */
class MyLabel
{
    private $properties;

    private $allowedProperties = array('x', 'y', 'text');

    public function __get($name)
    {
        if (isset($properties[$name]) && in_array($name, $this->allowedProperties)) {
            return $properties[$name];
        } else {
            return null;
        }
    }

    public function __set($name, $value)
    {
        if (in_array($name, $this->allowedProperties)) {
            $properties[$name] = $value;
        } else {
            throw new \LogicException("Property $name is not defined.");
        }
    }

}

If the property has read access only, you can use the @property-read annotation instead.

Of course, you may also just have mistyped another name, in which case you should fix the error.

See also the PhpDoc documentation for @property.

Loading history...
533
534
        // With default = false
535
        // Because of config rules about falsey values, apply config to object directly
536
        Config::modify()->set(CommentableItem::class, 'comments', array(
537
            'enabled' => false,
538
            'require_login' => true,
539
            'require_moderation' => true
540
        ));
541
542
        $obj = new CommentableItem();
543
544
        $this->assertFalse((bool)$obj->getCommentsOption('enabled'), 'Default setting is disabled');
0 ignored issues
show
Documentation Bug introduced by
The method getCommentsOption does not exist on object<SilverStripe\Comm...\Stubs\CommentableItem>? Since you implemented __call, maybe consider adding a @method annotation.

If you implement __call and you know which methods are available, you can improve IDE auto-completion and static analysis by adding a @method annotation to the class.

This is often the case, when __call is implemented by a parent class and only the child class knows which methods exist:

class ParentClass {
    private $data = array();

    public function __call($method, array $args) {
        if (0 === strpos($method, 'get')) {
            return $this->data[strtolower(substr($method, 3))];
        }

        throw new \LogicException(sprintf('Unsupported method: %s', $method));
    }
}

/**
 * If this class knows which fields exist, you can specify the methods here:
 *
 * @method string getName()
 */
class SomeClass extends ParentClass { }
Loading history...
545
        $this->assertFalse((bool)$obj->ProvideComments);
0 ignored issues
show
Documentation introduced by
The property ProvideComments does not exist on object<SilverStripe\Comm...\Stubs\CommentableItem>. Since you implemented __get, maybe consider adding a @property annotation.

Since your code implements the magic getter _get, this function will be called for any read access on an undefined variable. You can add the @property annotation to your class or interface to document the existence of this variable.

<?php

/**
 * @property int $x
 * @property int $y
 * @property string $text
 */
class MyLabel
{
    private $properties;

    private $allowedProperties = array('x', 'y', 'text');

    public function __get($name)
    {
        if (isset($properties[$name]) && in_array($name, $this->allowedProperties)) {
            return $properties[$name];
        } else {
            return null;
        }
    }

    public function __set($name, $value)
    {
        if (in_array($name, $this->allowedProperties)) {
            $properties[$name] = $value;
        } else {
            throw new \LogicException("Property $name is not defined.");
        }
    }

}

If the property has read access only, you can use the @property-read annotation instead.

Of course, you may also just have mistyped another name, in which case you should fix the error.

See also the PhpDoc documentation for @property.

Loading history...
546
        $this->assertEquals('Required', $obj->ModerationRequired);
0 ignored issues
show
Documentation introduced by
The property ModerationRequired does not exist on object<SilverStripe\Comm...\Stubs\CommentableItem>. Since you implemented __get, maybe consider adding a @property annotation.

Since your code implements the magic getter _get, this function will be called for any read access on an undefined variable. You can add the @property annotation to your class or interface to document the existence of this variable.

<?php

/**
 * @property int $x
 * @property int $y
 * @property string $text
 */
class MyLabel
{
    private $properties;

    private $allowedProperties = array('x', 'y', 'text');

    public function __get($name)
    {
        if (isset($properties[$name]) && in_array($name, $this->allowedProperties)) {
            return $properties[$name];
        } else {
            return null;
        }
    }

    public function __set($name, $value)
    {
        if (in_array($name, $this->allowedProperties)) {
            $properties[$name] = $value;
        } else {
            throw new \LogicException("Property $name is not defined.");
        }
    }

}

If the property has read access only, you can use the @property-read annotation instead.

Of course, you may also just have mistyped another name, in which case you should fix the error.

See also the PhpDoc documentation for @property.

Loading history...
547
        $this->assertTrue((bool)$obj->CommentsRequireLogin);
0 ignored issues
show
Documentation introduced by
The property CommentsRequireLogin does not exist on object<SilverStripe\Comm...\Stubs\CommentableItem>. Since you implemented __get, maybe consider adding a @property annotation.

Since your code implements the magic getter _get, this function will be called for any read access on an undefined variable. You can add the @property annotation to your class or interface to document the existence of this variable.

<?php

/**
 * @property int $x
 * @property int $y
 * @property string $text
 */
class MyLabel
{
    private $properties;

    private $allowedProperties = array('x', 'y', 'text');

    public function __get($name)
    {
        if (isset($properties[$name]) && in_array($name, $this->allowedProperties)) {
            return $properties[$name];
        } else {
            return null;
        }
    }

    public function __set($name, $value)
    {
        if (in_array($name, $this->allowedProperties)) {
            $properties[$name] = $value;
        } else {
            throw new \LogicException("Property $name is not defined.");
        }
    }

}

If the property has read access only, you can use the @property-read annotation instead.

Of course, you may also just have mistyped another name, in which case you should fix the error.

See also the PhpDoc documentation for @property.

Loading history...
548
549
        $obj = new CommentableItemEnabled();
550
551
        $this->assertTrue((bool)$obj->ProvideComments);
0 ignored issues
show
Documentation introduced by
The property ProvideComments does not exist on object<SilverStripe\Comm...CommentableItemEnabled>. Since you implemented __get, maybe consider adding a @property annotation.

Since your code implements the magic getter _get, this function will be called for any read access on an undefined variable. You can add the @property annotation to your class or interface to document the existence of this variable.

<?php

/**
 * @property int $x
 * @property int $y
 * @property string $text
 */
class MyLabel
{
    private $properties;

    private $allowedProperties = array('x', 'y', 'text');

    public function __get($name)
    {
        if (isset($properties[$name]) && in_array($name, $this->allowedProperties)) {
            return $properties[$name];
        } else {
            return null;
        }
    }

    public function __set($name, $value)
    {
        if (in_array($name, $this->allowedProperties)) {
            $properties[$name] = $value;
        } else {
            throw new \LogicException("Property $name is not defined.");
        }
    }

}

If the property has read access only, you can use the @property-read annotation instead.

Of course, you may also just have mistyped another name, in which case you should fix the error.

See also the PhpDoc documentation for @property.

Loading history...
552
        $this->assertEquals('Required', $obj->ModerationRequired);
0 ignored issues
show
Documentation introduced by
The property ModerationRequired does not exist on object<SilverStripe\Comm...CommentableItemEnabled>. Since you implemented __get, maybe consider adding a @property annotation.

Since your code implements the magic getter _get, this function will be called for any read access on an undefined variable. You can add the @property annotation to your class or interface to document the existence of this variable.

<?php

/**
 * @property int $x
 * @property int $y
 * @property string $text
 */
class MyLabel
{
    private $properties;

    private $allowedProperties = array('x', 'y', 'text');

    public function __get($name)
    {
        if (isset($properties[$name]) && in_array($name, $this->allowedProperties)) {
            return $properties[$name];
        } else {
            return null;
        }
    }

    public function __set($name, $value)
    {
        if (in_array($name, $this->allowedProperties)) {
            $properties[$name] = $value;
        } else {
            throw new \LogicException("Property $name is not defined.");
        }
    }

}

If the property has read access only, you can use the @property-read annotation instead.

Of course, you may also just have mistyped another name, in which case you should fix the error.

See also the PhpDoc documentation for @property.

Loading history...
553
        $this->assertTrue((bool)$obj->CommentsRequireLogin);
0 ignored issues
show
Documentation introduced by
The property CommentsRequireLogin does not exist on object<SilverStripe\Comm...CommentableItemEnabled>. Since you implemented __get, maybe consider adding a @property annotation.

Since your code implements the magic getter _get, this function will be called for any read access on an undefined variable. You can add the @property annotation to your class or interface to document the existence of this variable.

<?php

/**
 * @property int $x
 * @property int $y
 * @property string $text
 */
class MyLabel
{
    private $properties;

    private $allowedProperties = array('x', 'y', 'text');

    public function __get($name)
    {
        if (isset($properties[$name]) && in_array($name, $this->allowedProperties)) {
            return $properties[$name];
        } else {
            return null;
        }
    }

    public function __set($name, $value)
    {
        if (in_array($name, $this->allowedProperties)) {
            $properties[$name] = $value;
        } else {
            throw new \LogicException("Property $name is not defined.");
        }
    }

}

If the property has read access only, you can use the @property-read annotation instead.

Of course, you may also just have mistyped another name, in which case you should fix the error.

See also the PhpDoc documentation for @property.

Loading history...
554
555
        $obj = new CommentableItemDisabled();
556
557
        $this->assertFalse((bool)$obj->ProvideComments);
0 ignored issues
show
Documentation introduced by
The property ProvideComments does not exist on object<SilverStripe\Comm...ommentableItemDisabled>. Since you implemented __get, maybe consider adding a @property annotation.

Since your code implements the magic getter _get, this function will be called for any read access on an undefined variable. You can add the @property annotation to your class or interface to document the existence of this variable.

<?php

/**
 * @property int $x
 * @property int $y
 * @property string $text
 */
class MyLabel
{
    private $properties;

    private $allowedProperties = array('x', 'y', 'text');

    public function __get($name)
    {
        if (isset($properties[$name]) && in_array($name, $this->allowedProperties)) {
            return $properties[$name];
        } else {
            return null;
        }
    }

    public function __set($name, $value)
    {
        if (in_array($name, $this->allowedProperties)) {
            $properties[$name] = $value;
        } else {
            throw new \LogicException("Property $name is not defined.");
        }
    }

}

If the property has read access only, you can use the @property-read annotation instead.

Of course, you may also just have mistyped another name, in which case you should fix the error.

See also the PhpDoc documentation for @property.

Loading history...
558
        $this->assertEquals('None', $obj->ModerationRequired);
0 ignored issues
show
Documentation introduced by
The property ModerationRequired does not exist on object<SilverStripe\Comm...ommentableItemDisabled>. Since you implemented __get, maybe consider adding a @property annotation.

Since your code implements the magic getter _get, this function will be called for any read access on an undefined variable. You can add the @property annotation to your class or interface to document the existence of this variable.

<?php

/**
 * @property int $x
 * @property int $y
 * @property string $text
 */
class MyLabel
{
    private $properties;

    private $allowedProperties = array('x', 'y', 'text');

    public function __get($name)
    {
        if (isset($properties[$name]) && in_array($name, $this->allowedProperties)) {
            return $properties[$name];
        } else {
            return null;
        }
    }

    public function __set($name, $value)
    {
        if (in_array($name, $this->allowedProperties)) {
            $properties[$name] = $value;
        } else {
            throw new \LogicException("Property $name is not defined.");
        }
    }

}

If the property has read access only, you can use the @property-read annotation instead.

Of course, you may also just have mistyped another name, in which case you should fix the error.

See also the PhpDoc documentation for @property.

Loading history...
559
        $this->assertFalse((bool)$obj->CommentsRequireLogin);
0 ignored issues
show
Documentation introduced by
The property CommentsRequireLogin does not exist on object<SilverStripe\Comm...ommentableItemDisabled>. Since you implemented __get, maybe consider adding a @property annotation.

Since your code implements the magic getter _get, this function will be called for any read access on an undefined variable. You can add the @property annotation to your class or interface to document the existence of this variable.

<?php

/**
 * @property int $x
 * @property int $y
 * @property string $text
 */
class MyLabel
{
    private $properties;

    private $allowedProperties = array('x', 'y', 'text');

    public function __get($name)
    {
        if (isset($properties[$name]) && in_array($name, $this->allowedProperties)) {
            return $properties[$name];
        } else {
            return null;
        }
    }

    public function __set($name, $value)
    {
        if (in_array($name, $this->allowedProperties)) {
            $properties[$name] = $value;
        } else {
            throw new \LogicException("Property $name is not defined.");
        }
    }

}

If the property has read access only, you can use the @property-read annotation instead.

Of course, you may also just have mistyped another name, in which case you should fix the error.

See also the PhpDoc documentation for @property.

Loading history...
560
    }
561
562
    public function testOnBeforeDelete()
563
    {
564
        $comment = $this->objFromFixture(Comment::class, 'firstComA');
565
566
        $child = new Comment();
567
        $child->Name = 'Fred Bloggs';
568
        $child->Comment = 'Child of firstComA';
569
        $child->write();
570
        $comment->ChildComments()->add($child);
571
        $this->assertEquals(4, $comment->ChildComments()->count());
572
573
        $commentID = $comment->ID;
574
        $childCommentID = $child->ID;
575
576
        $comment->delete();
577
578
        // assert that the new child been deleted
579
        $this->assertNull(DataObject::get_by_id(Comment::class, $commentID));
580
        $this->assertNull(DataObject::get_by_id(Comment::class, $childCommentID));
581
    }
582
583
    public function testRequireDefaultRecords()
584
    {
585
        $this->markTestSkipped('TODO');
586
    }
587
588
    public function testLink()
589
    {
590
        $comment = $this->objFromFixture(Comment::class, 'thirdComD');
591
        $this->assertEquals(
592
            'CommentableItemController#comment-' . $comment->ID,
593
            $comment->Link()
594
        );
595
        $this->assertEquals($comment->ID, $comment->ID);
596
597
        // An orphan comment has no link
598
        $comment->ParentID = 0;
599
        $comment->ParentClass = null;
600
        $comment->write();
601
        $this->assertEquals('', $comment->Link());
602
    }
603
604
    public function testPermalink()
605
    {
606
        $comment = $this->objFromFixture(Comment::class, 'thirdComD');
607
        $this->assertEquals('comment-' . $comment->ID, $comment->Permalink());
608
    }
609
610
    /**
611
     * Test field labels in 2 languages
612
     */
613
    public function testFieldLabels()
614
    {
615
        $locale = i18n::get_locale();
616
        i18n::set_locale('fr');
617
        $comment = $this->objFromFixture(Comment::class, 'firstComA');
618
        $labels = $comment->FieldLabels();
619
        $expected = array(
620
            'Name' => 'Nom de l\'Auteur',
621
            'Comment' => 'Commentaire',
622
            'Email' => 'Email',
623
            'URL' => 'URL',
624
            'Moderated' => 'Modéré?',
625
            'IsSpam' => 'Spam?',
626
            'AllowHtml' => 'Allow Html',
627
            'SecretToken' => 'Secret Token',
628
            'Depth' => 'Depth',
629
            'Author' => 'Author Member',
630
            'ParentComment' => 'Parent Comment',
631
            'ChildComments' => 'Child Comments',
632
            'ParentTitle' => 'Parent',
633
            'Created' => 'Date de publication',
634
            'Parent' => 'Parent'
635
        );
636
        i18n::set_locale($locale);
637
        $this->assertEquals($expected, $labels);
638
        $labels = $comment->FieldLabels();
639
        $expected = array(
640
            'Name' => 'Author Name',
641
            'Comment' => 'Comment',
642
            'Email' => 'Email',
643
            'URL' => 'URL',
644
            'Moderated' => 'Moderated?',
645
            'IsSpam' => 'Spam?',
646
            'AllowHtml' => 'Allow Html',
647
            'SecretToken' => 'Secret Token',
648
            'Depth' => 'Depth',
649
            'Author' => 'Author Member',
650
            'ParentComment' => 'Parent Comment',
651
            'ChildComments' => 'Child Comments',
652
            'ParentTitle' => 'Parent',
653
            'Created' => 'Date posted',
654
            'Parent' => 'Parent'
655
        );
656
        $this->assertEquals($expected, $labels);
657
    }
658
659
    public function testGetParent()
660
    {
661
        $comment = $this->objFromFixture(Comment::class, 'firstComA');
662
        $item = $this->objFromFixture(CommentableItem::class, 'first');
663
        $parent = $comment->Parent();
664
        $this->assertSame($item->getClassName(), $parent->getClassName());
665
        $this->assertSame($item->ID, $parent->ID);
666
    }
667
668 View Code Duplication
    public function testGetParentTitle()
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
669
    {
670
        $comment = $this->objFromFixture(Comment::class, 'firstComA');
671
        $title = $comment->getParentTitle();
672
        $this->assertEquals('First', $title);
673
674
        // Title from a comment with no parent is blank
675
        $comment->ParentID = 0;
676
        $comment->ParentClass = null;
677
        $comment->write();
678
        $this->assertEquals('', $comment->getParentTitle());
679
    }
680
681
    public function testGetParentClassName()
682
    {
683
        $comment = $this->objFromFixture(Comment::class, 'firstComA');
684
        $className = $comment->getParentClassName();
685
        $this->assertEquals(CommentableItem::class, $className);
686
    }
687
688
    public function testCastingHelper()
689
    {
690
        $this->markTestSkipped('TODO');
691
    }
692
693
    public function testGetEscapedComment()
694
    {
695
        $this->markTestSkipped('TODO');
696
    }
697
698
    public function testIsPreview()
699
    {
700
        $comment = new Comment();
701
        $comment->Name = 'Fred Bloggs';
702
        $comment->Comment = 'this is a test comment';
703
        $this->assertTrue($comment->isPreview());
704
        $comment->write();
705
        $this->assertFalse($comment->isPreview());
706
    }
707
708
    public function testCanCreate()
709
    {
710
        $comment = $this->objFromFixture(Comment::class, 'firstComA');
711
712
        // admin can create - this is always false
713
        $this->logInAs('commentadmin');
714
        $this->assertFalse($comment->canCreate());
715
716
        // visitor can view
717
        $this->logInAs('visitor');
718
        $this->assertFalse($comment->canCreate());
719
    }
720
721 View Code Duplication
    public function testCanView()
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
722
    {
723
        $comment = $this->objFromFixture(Comment::class, 'firstComA');
724
725
        // admin can view
726
        $this->logInAs('commentadmin');
727
        $this->assertTrue($comment->canView());
728
729
        // visitor can view
730
        $this->logInAs('visitor');
731
        $this->assertTrue($comment->canView());
732
733
        $comment->ParentID = 0;
734
        $comment->write();
735
        $this->assertFalse($comment->canView());
736
    }
737
738 View Code Duplication
    public function testCanEdit()
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
739
    {
740
        $comment = $this->objFromFixture(Comment::class, 'firstComA');
741
742
        // admin can edit
743
        $this->logInAs('commentadmin');
744
        $this->assertTrue($comment->canEdit());
745
746
        // visitor cannot
747
        $this->logInAs('visitor');
748
        $this->assertFalse($comment->canEdit());
749
750
        $comment->ParentID = 0;
751
        $comment->write();
752
        $this->assertFalse($comment->canEdit());
753
    }
754
755 View Code Duplication
    public function testCanDelete()
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
756
    {
757
        $comment = $this->objFromFixture(Comment::class, 'firstComA');
758
759
        // admin can delete
760
        $this->logInAs('commentadmin');
761
        $this->assertTrue($comment->canDelete());
762
763
        // visitor cannot
764
        $this->logInAs('visitor');
765
        $this->assertFalse($comment->canDelete());
766
767
        $comment->ParentID = 0;
768
        $comment->write();
769
        $this->assertFalse($comment->canDelete());
770
    }
771
772
    public function testGetMember()
773
    {
774
        $this->logInAs('visitor');
775
        $current = Security::getCurrentUser();
776
        $comment = $this->objFromFixture(Comment::class, 'firstComA');
777
        $method = $this->getMethod('getMember');
778
779
        // null case
780
        $member = $method->invokeArgs($comment, array());
781
        $this->assertEquals($current->ID, $member->ID);
782
783
        // numeric ID case
784
        $member = $method->invokeArgs($comment, array($current->ID));
785
        $this->assertEquals($current->ID, $member->ID);
786
787
        // identity case
788
        $member = $method->invokeArgs($comment, array($current));
789
        $this->assertEquals($current->ID, $member->ID);
790
    }
791
792
    public function testGetAuthorName()
793
    {
794
        $comment = $this->objFromFixture(Comment::class, 'firstComA');
795
        $this->assertEquals(
796
            'FA',
797
            $comment->getAuthorName()
798
        );
799
800
        $comment->Name = '';
801
        $this->assertEquals(
802
            '',
803
            $comment->getAuthorName()
804
        );
805
806
        $author = $this->objFromFixture(Member::class, 'visitor');
807
        $comment->AuthorID = $author->ID;
808
        $comment->write();
809
        $this->assertEquals(
810
            'visitor',
811
            $comment->getAuthorName()
812
        );
813
814
        // null the names, expect null back
815
        $comment->Name = null;
816
        $comment->AuthorID = 0;
817
        $this->assertNull($comment->getAuthorName());
818
    }
819
820
821
    public function testLinks()
822
    {
823
        $comment = $this->objFromFixture(Comment::class, 'firstComA');
824
        $this->logInAs('commentadmin');
825
826
        $method = $this->getMethod('ActionLink');
827
828
        // test with starts of strings and tokens and salts change each time
829
        $this->assertStringStartsWith(
830
            '/comments/theaction/' . $comment->ID,
831
            $method->invokeArgs($comment, array('theaction'))
832
        );
833
834
        $this->assertStringStartsWith(
835
            '/comments/delete/' . $comment->ID,
836
            $comment->DeleteLink()
837
        );
838
839
        $this->assertStringStartsWith(
840
            '/comments/spam/' . $comment->ID,
841
            $comment->SpamLink()
842
        );
843
844
        $comment->markSpam();
845
        $this->assertStringStartsWith(
846
            '/comments/ham/' . $comment->ID,
847
            $comment->HamLink()
848
        );
849
850
        //markApproved
851
        $comment->markUnapproved();
852
        $this->assertStringStartsWith(
853
            '/comments/approve/' . $comment->ID,
854
            $comment->ApproveLink()
855
        );
856
    }
857
858
    public function testMarkSpam()
859
    {
860
        $comment = $this->objFromFixture(Comment::class, 'firstComA');
861
        $comment->markSpam();
862
        $this->assertTrue($comment->Moderated);
863
        $this->assertTrue($comment->IsSpam);
864
    }
865
866
    public function testMarkApproved()
867
    {
868
        $comment = $this->objFromFixture(Comment::class, 'firstComA');
869
        $comment->markApproved();
870
        $this->assertTrue($comment->Moderated);
871
        $this->assertFalse($comment->IsSpam);
872
    }
873
874
    public function testMarkUnapproved()
875
    {
876
        $comment = $this->objFromFixture(Comment::class, 'firstComA');
877
        $comment->markApproved();
878
        $this->assertTrue($comment->Moderated);
879
    }
880
881 View Code Duplication
    public function testSpamClass()
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
882
    {
883
        $comment = $this->objFromFixture(Comment::class, 'firstComA');
884
        $this->assertEquals('notspam', $comment->spamClass());
885
        $comment->Moderated = false;
886
        $this->assertEquals('unmoderated', $comment->spamClass());
887
        $comment->IsSpam = true;
888
        $this->assertEquals('spam', $comment->spamClass());
889
    }
890
891
    public function testGetTitle()
892
    {
893
        $comment = $this->objFromFixture(Comment::class, 'firstComA');
894
        $this->assertEquals(
895
            'Comment by FA on First',
896
            $comment->getTitle()
897
        );
898
    }
899
900
    public function testGetCMSFields()
901
    {
902
        $comment = $this->objFromFixture(Comment::class, 'firstComA');
903
        $fields = $comment->getCMSFields();
904
        $names = array();
905
        foreach ($fields as $field) {
906
            $names[] = $field->getName();
907
        }
908
        $expected = array(
909
            'Created',
910
            'Name',
911
            'Comment',
912
            'Email',
913
            'URL',
914
            'Options'
915
        );
916
        $this->assertEquals($expected, $names);
917
    }
918
919
    public function testGetCMSFieldsCommentHasAuthor()
920
    {
921
        $member = Member::get()->filter('FirstName', 'visitor')->first();
922
        $comment = $this->objFromFixture(Comment::class, 'firstComA');
923
        $comment->AuthorID = $member->ID;
924
        $comment->write();
925
926
        $fields = $comment->getCMSFields();
927
        $names = array();
928
        foreach ($fields as $field) {
929
            $names[] = $field->getName();
930
        }
931
        $expected = array(
932
            'Created',
933
            'Name',
934
            'AuthorMember',
935
            'Comment',
936
            'Email',
937
            'URL',
938
            'Options'
939
        );
940
        $this->assertEquals($expected, $names);
941
    }
942
943
    public function testGetCMSFieldsWithParentComment()
944
    {
945
        $comment = $this->objFromFixture(Comment::class, 'firstComA');
946
947
        $child = new Comment();
948
        $child->Name = 'John Smith';
949
        $child->Comment = 'This is yet another test commnent';
950
        $child->ParentCommentID = $comment->ID;
0 ignored issues
show
Bug introduced by
The property ParentCommentID does not seem to exist. Did you mean Comment?

An attempt at access to an undefined property has been detected. This may either be a typographical error or the property has been renamed but there are still references to its old name.

If you really want to allow access to undefined properties, you can define magic methods to allow access. See the php core documentation on Overloading.

Loading history...
951
        $child->write();
952
953
        $fields = $child->getCMSFields();
954
        $names = array();
955
        foreach ($fields as $field) {
956
            $names[] = $field->getName();
957
        }
958
        $expected = array(
959
            'Created',
960
            'Name',
961
            'Comment',
962
            'Email',
963
            'URL',
964
            'Options',
965
            'ParentComment_Title',
966
            'ParentComment_Created',
967
            'ParentComment_AuthorName',
968
            'ParentComment_EscapedComment'
969
        );
970
        $this->assertEquals($expected, $names);
971
    }
972
973
    public function testPurifyHtml()
974
    {
975
        if (!class_exists(HTMLPurifier_Config::class)) {
976
            $this->markTestSkipped('HTMLPurifier class not found');
977
            return;
978
        }
979
980
        $comment = $this->objFromFixture(Comment::class, 'firstComA');
981
982
        $dirtyHTML = '<p><script>alert("w00t")</script>my comment</p>';
983
        $this->assertEquals(
984
            'my comment',
985
            $comment->purifyHtml($dirtyHTML)
986
        );
987
    }
988
989
    public function testGravatar()
990
    {
991
        // Turn gravatars on
992
        Config::modify()->set(CommentableItem::class, 'comments', array(
993
            'use_gravatar' => true,
994
            'gravatar_size' => 80,
995
            'gravatar_default' => 'identicon',
996
            'gravatar_rating' => 'g'
997
        ));
998
999
        $comment = $this->objFromFixture(Comment::class, 'firstComA');
1000
1001
        $this->assertEquals(
1002
            'http://www.gravatar.com/avatar/d41d8cd98f00b204e9800998ecf8427e?s'
1003
            . '=80&d=identicon&r=g',
1004
            $comment->Gravatar()
1005
        );
1006
1007
        // Turn gravatars off
1008
        Config::modify()->set(CommentableItem::class, 'comments', array(
1009
            'use_gravatar' => false
1010
        ));
1011
1012
        $comment = $this->objFromFixture(Comment::class, 'firstComA');
1013
1014
        $this->assertEquals(
1015
            '',
1016
            $comment->Gravatar()
1017
        );
1018
    }
1019
1020
    public function testGetRepliesEnabled()
1021
    {
1022
        Config::modify()->merge(CommentableItem::class, 'comments', array(
1023
            'nested_comments' => false
1024
        ));
1025
1026
        $comment = $this->objFromFixture(Comment::class, 'firstComA');
1027
        $this->assertFalse($comment->getRepliesEnabled());
1028
1029
        Config::modify()->merge(CommentableItem::class, 'comments', array(
1030
            'nested_comments' => true,
1031
            'nested_depth' => 4
1032
        ));
1033
1034
        $this->assertTrue($comment->getRepliesEnabled());
1035
1036
        $comment->Depth = 4;
1037
        $this->assertFalse($comment->getRepliesEnabled());
1038
1039
1040
        // 0 indicates no limit for nested_depth
1041
        Config::modify()->set(CommentableItem::class, 'comments', array(
1042
            'nested_comments' => true,
1043
            'nested_depth' => 0
1044
        ));
1045
1046
        $comment = $this->objFromFixture(Comment::class, 'firstComA');
1047
        $comment->Depth = 234;
1048
1049
        $comment->markUnapproved();
1050
        $this->assertFalse($comment->getRepliesEnabled());
1051
1052
        $comment->markSpam();
1053
        $this->assertFalse($comment->getRepliesEnabled());
1054
1055
        $comment->markApproved();
1056
        $this->assertTrue($comment->getRepliesEnabled());
1057
    }
1058
1059
    public function testAllReplies()
1060
    {
1061
        Config::modify()->set(CommentableItem::class, 'comments', array(
1062
            'nested_comments' => true,
1063
            'nested_depth' => 4
1064
        ));
1065
1066
        $comment = $this->objFromFixture(Comment::class, 'firstComA');
1067
1068
        $this->assertEquals(
1069
            3,
1070
            $comment->allReplies()->count()
1071
        );
1072
1073
        $child = new Comment();
1074
        $child->Name = 'Fred Smith';
1075
        $child->Comment = 'This is a child comment';
1076
        $child->ParentCommentID = $comment->ID;
0 ignored issues
show
Bug introduced by
The property ParentCommentID does not seem to exist. Did you mean Comment?

An attempt at access to an undefined property has been detected. This may either be a typographical error or the property has been renamed but there are still references to its old name.

If you really want to allow access to undefined properties, you can define magic methods to allow access. See the php core documentation on Overloading.

Loading history...
1077
1078
        // spam should be returned by this method
1079
        $child->markSpam();
1080
        $child->write();
1081
        $replies = $comment->allReplies();
0 ignored issues
show
Unused Code introduced by
$replies is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
1082
        $this->assertEquals(
1083
            4,
1084
            $comment->allReplies()->count()
1085
        );
1086
1087
        Config::modify()->set(CommentableItem::class, 'comments', array(
1088
            'nested_comments' => false
1089
        ));
1090
1091
        $this->assertEquals(0, $comment->allReplies()->count());
1092
    }
1093
1094
    public function testReplies()
1095
    {
1096
        CommentableItem::add_extension(CommentsExtension::class);
1097
        $this->logInWithPermission('ADMIN');
1098
        Config::modify()->set(CommentableItem::class, 'comments', array(
1099
            'nested_comments' => true,
1100
            'nested_depth' => 4
1101
        ));
1102
        $comment = $this->objFromFixture(Comment::class, 'firstComA');
1103
        $this->assertEquals(
1104
            3,
1105
            $comment->Replies()->count()
1106
        );
1107
1108
        // Test that spam comments are not returned
1109
        $childComment = $comment->Replies()->first();
1110
        $childComment->IsSpam = 1;
1111
        $childComment->write();
1112
        $this->assertEquals(
1113
            2,
1114
            $comment->Replies()->count()
1115
        );
1116
1117
        // Test that unmoderated comments are not returned
1118
        //
1119
        $childComment = $comment->Replies()->first();
1120
1121
        // FIXME - moderation settings scenarios need checked here
1122
        $childComment->Moderated = 0;
1123
        $childComment->IsSpam = 0;
1124
        $childComment->write();
1125
        $this->assertEquals(
1126
            2,
1127
            $comment->Replies()->count()
1128
        );
1129
1130
1131
        // Test moderation required on the front end
1132
        $item = $this->objFromFixture(CommentableItem::class, 'first');
1133
        $item->ModerationRequired = 'Required';
1134
        $item->write();
1135
1136
        Config::modify()->set(CommentableItemDisabled::class, 'comments', array(
1137
            'nested_comments' => true,
1138
            'nested_depth' => 4,
1139
            'frontend_moderation' => true
1140
        ));
1141
1142
        $comment = DataObject::get_by_id(Comment::class, $comment->ID);
1143
1144
        $this->assertEquals(
1145
            2,
1146
            $comment->Replies()->count()
1147
        );
1148
1149
        // Turn off nesting, empty array should be returned
1150
        Config::modify()->set(CommentableItem::class, 'comments', array(
1151
            'nested_comments' => false
1152
        ));
1153
1154
        $this->assertEquals(
1155
            0,
1156
            $comment->Replies()->count()
1157
        );
1158
1159
        CommentableItem::remove_extension(CommentsExtension::class);
1160
    }
1161
1162
    public function testPagedReplies()
1163
    {
1164
        Config::modify()->merge(CommentableItem::class, 'comments', array(
1165
            'nested_comments' => true,
1166
            'nested_depth' => 4,
1167
            'comments_per_page' => 2
1168
        ));
1169
1170
        $comment = $this->objFromFixture(Comment::class, 'firstComA');
1171
        $pagedList = $comment->pagedReplies();
1172
1173
        $this->assertEquals(
1174
            2,
1175
            $pagedList->TotalPages()
1176
        );
1177
1178
        $this->assertEquals(
1179
            3,
1180
            $pagedList->getTotalItems()
1181
        );
1182
1183
        Config::modify()->set(CommentableItem::class, 'comments', array(
1184
            'nested_comments' => false
1185
        ));
1186
1187
        $this->assertEquals(0, $comment->PagedReplies()->count());
1188
    }
1189
1190
    public function testReplyForm()
1191
    {
1192
        Config::modify()->set(CommentableItem::class, 'comments', array(
1193
            'nested_comments' => false,
1194
            'nested_depth' => 4
1195
        ));
1196
1197
        $comment = $this->objFromFixture(Comment::class, 'firstComA');
1198
1199
        // No nesting, no reply form
1200
        $form = $comment->replyForm();
1201
        $this->assertNull($form);
1202
1203
        // parent item so show form
1204
        Config::modify()->set(CommentableItem::class, 'comments', array(
1205
            'nested_comments' => true,
1206
            'nested_depth' => 4
1207
        ));
1208
        $form = $comment->ReplyForm();
1209
        $this->assertNotNull($form);
1210
        $names = array();
1211
1212
        foreach ($form->Fields() as $field) {
1213
            array_push($names, $field->getName());
1214
        }
1215
1216
        $this->assertEquals(
1217
            array(
1218
                'NameEmailURLComment', // The CompositeField name?
1219
                'ParentID',
1220
                'ParentClassName',
1221
                'ReturnURL',
1222
                'ParentCommentID'
1223
            ),
1224
            $names
1225
        );
1226
1227
        // no parent, no reply form
1228
1229
        $comment->ParentID = 0;
1230
        $comment->ParentClass = null;
1231
        $comment->write();
1232
        $form = $comment->replyForm();
1233
        $this->assertNull($form);
1234
    }
1235
1236
    public function testUpdateDepth()
1237
    {
1238
        Config::modify()->set(CommentableItem::class, 'comments', array(
1239
            'nested_comments' => true,
1240
            'nested_depth' => 4
1241
        ));
1242
1243
        $comment = $this->objFromFixture(Comment::class, 'firstComA');
1244
        $children = $comment->allReplies()->toArray();
1245
        // Make the second child a child of the first
1246
        // Make the third child a child of the second
1247
        $reply1 = $children[0];
1248
        $reply2 = $children[1];
1249
        $reply3 = $children[2];
1250
        $reply2->ParentCommentID = $reply1->ID;
1251
        $reply2->write();
1252
        $this->assertEquals(3, $reply2->Depth);
1253
        $reply3->ParentCommentID = $reply2->ID;
1254
        $reply3->write();
1255
        $this->assertEquals(4, $reply3->Depth);
1256
    }
1257
1258
    public function testGetToken()
1259
    {
1260
        $this->markTestSkipped('TODO');
1261
    }
1262
1263
    public function testMemberSalt()
1264
    {
1265
        $this->markTestSkipped('TODO');
1266
    }
1267
1268
    public function testAddToUrl()
1269
    {
1270
        $this->markTestSkipped('TODO');
1271
    }
1272
1273
    public function testCheckRequest()
1274
    {
1275
        $this->markTestSkipped('TODO');
1276
    }
1277
1278
    public function testGenerate()
1279
    {
1280
        $this->markTestSkipped('TODO');
1281
    }
1282
1283
    protected static function getMethod($name)
1284
    {
1285
        $class = new ReflectionClass(Comment::class);
1286
        $method = $class->getMethod($name);
1287
        $method->setAccessible(true);
1288
        return $method;
1289
    }
1290
}
1291