Completed
Push — master ( 187618...8c43e0 )
by Will
12s
created

CommentsTest::testGenerate()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
dl 0
loc 4
rs 10
c 1
b 0
f 0
cc 1
eloc 2
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
39
        // Set good default values
40
        Config::modify()->merge(CommentsExtension::class, 'comments', array(
41
            'enabled' => true,
42
            'comment_permalink_prefix' => 'comment-'
43
        ));
44
    }
45
46
    public function testCommentsList()
47
    {
48
        // comments don't require moderation so unmoderated comments can be
49
        // shown but not spam posts
50
        Config::modify()->merge(CommentableItem::class, 'comments', array(
51
            'require_moderation_nonmembers' => false,
52
            'require_moderation' => false,
53
            'require_moderation_cms' => false,
54
        ));
55
56
        $item = $this->objFromFixture(CommentableItem::class, 'spammed');
57
58
        $this->assertDOSEquals(array(
59
            array('Name' => 'Comment 1'),
60
            array('Name' => 'Comment 3')
61
        ), $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...
62
63
        // when moderated, only moderated, non spam posts should be shown.
64
        Config::modify()->merge(CommentableItem::class, 'comments', array('require_moderation_nonmembers' => true));
65
66
        // Check that require_moderation overrides this option
67
        Config::modify()->merge(CommentableItem::class, 'comments', array('require_moderation' => true));
68
69
        $this->assertDOSEquals(array(
70
            array('Name' => 'Comment 3')
71
        ), $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...
72
        $this->assertEquals(1, $item->Comments()->Count());
73
74
        // require_moderation_nonmembers still filters out unmoderated comments
75
        Config::modify()->merge(CommentableItem::class, 'comments', array('require_moderation' => false));
76
        $this->assertEquals(1, $item->Comments()->Count());
77
78
        Config::modify()->merge(CommentableItem::class, 'comments', array('require_moderation_nonmembers' => false));
79
        $this->assertEquals(2, $item->Comments()->Count());
80
81
        // With unmoderated comments set to display in frontend
82
        Config::modify()->merge(CommentableItem::class, 'comments', array(
83
            'require_moderation' => true,
84
            'frontend_moderation' => true
85
        ));
86
        $this->assertEquals(1, $item->Comments()->Count());
87
88
        $this->logInWithPermission('ADMIN');
89
        $this->assertEquals(2, $item->Comments()->Count());
90
91
        // With spam comments set to display in frontend
92
        Config::modify()->merge(CommentableItem::class, 'comments', array(
93
            'require_moderation' => true,
94
            'frontend_moderation' => false,
95
            'frontend_spam' => true,
96
        ));
97
        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...
98
            $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...
99
        }
100
        $this->assertEquals(1, $item->Comments()->Count());
101
102
        $this->logInWithPermission('ADMIN');
103
        $this->assertEquals(2, $item->Comments()->Count());
104
105
106
        // With spam and unmoderated comments set to display in frontend
107
        Config::modify()->merge(CommentableItem::class, 'comments', array(
108
            'require_moderation' => true,
109
            'frontend_moderation' => true,
110
            'frontend_spam' => true,
111
        ));
112
        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...
113
            $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...
114
        }
115
        $this->assertEquals(1, $item->Comments()->Count());
116
117
        $this->logInWithPermission('ADMIN');
118
        $this->assertEquals(4, $item->Comments()->Count());
119
    }
120
121
    /**
122
     * Test moderation options configured via the CMS
123
     */
124
    public function testCommentCMSModerationList()
125
    {
126
        Config::modify()->merge(CommentableItem::class, 'comments', array(
127
            'require_moderation' => true,
128
            'require_moderation_cms' => true,
129
        ));
130
131
        $item = $this->objFromFixture(CommentableItem::class, 'spammed');
132
133
        $this->assertEquals('None', $item->getModerationRequired());
134
135
        $this->assertDOSEquals(array(
136
            array('Name' => 'Comment 1'),
137
            array('Name' => 'Comment 3')
138
        ), $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...
139
140
        // when moderated, only moderated, non spam posts should be shown.
141
        $item->ModerationRequired = 'NonMembersOnly';
142
        $item->write();
143
144
        $this->assertEquals('NonMembersOnly', $item->getModerationRequired());
145
146
        // Check that require_moderation overrides this option
147
        $item->ModerationRequired = 'Required';
148
        $item->write();
149
        $this->assertEquals('Required', $item->getModerationRequired());
150
151
        $this->assertDOSEquals(array(
152
            array('Name' => 'Comment 3')
153
        ), $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...
154
        $this->assertEquals(1, $item->Comments()->Count());
155
156
        // require_moderation_nonmembers still filters out unmoderated comments
157
        $item->ModerationRequired = 'NonMembersOnly';
158
        $item->write();
159
        $this->assertEquals(1, $item->Comments()->Count());
160
161
        $item->ModerationRequired = 'None';
162
        $item->write();
163
        $this->assertEquals(2, $item->Comments()->Count());
164
    }
165
166
    public function testCanPostComment()
167
    {
168
        Config::modify()->merge(CommentableItem::class, 'comments', array(
169
            'require_login' => false,
170
            'require_login_cms' => false,
171
            'required_permission' => false,
172
        ));
173
        $item = $this->objFromFixture(CommentableItem::class, 'first');
174
        $item2 = $this->objFromFixture(CommentableItem::class, 'second');
175
176
        // Test restriction free commenting
177
        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...
178
            $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...
179
        }
180
        $this->assertFalse($item->CommentsRequireLogin);
181
        $this->assertTrue($item->canPostComment());
182
183
        // Test permission required to post
184
        Config::modify()->merge(CommentableItem::class, 'comments', array(
185
            'require_login' => true,
186
            'required_permission' => 'POSTING_PERMISSION',
187
        ));
188
        $this->assertTrue($item->CommentsRequireLogin);
189
        $this->assertFalse($item->canPostComment());
190
        $this->logInWithPermission('WRONG_ONE');
191
        $this->assertFalse($item->canPostComment());
192
        $this->logInWithPermission('POSTING_PERMISSION');
193
        $this->assertTrue($item->canPostComment());
194
        $this->logInWithPermission('ADMIN');
195
        $this->assertTrue($item->canPostComment());
196
197
        // Test require login to post, but not any permissions
198
        Config::modify()->merge(CommentableItem::class, 'comments', array(
199
            'required_permission' => false,
200
        ));
201
        $this->assertTrue($item->CommentsRequireLogin);
202
        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...
203
            $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...
204
        }
205
        $this->assertFalse($item->canPostComment());
206
        $this->logInWithPermission('ANY_PERMISSION');
207
        $this->assertTrue($item->canPostComment());
208
209
        // Test options set via CMS
210
        Config::modify()->merge(CommentableItem::class, 'comments', array(
211
            'require_login' => true,
212
            'require_login_cms' => true,
213
        ));
214
        $this->assertFalse($item->CommentsRequireLogin);
215
        $this->assertTrue($item2->CommentsRequireLogin);
216
        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...
217
            $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...
218
        }
219
        $this->assertTrue($item->canPostComment());
220
        $this->assertFalse($item2->canPostComment());
221
222
        // Login grants permission to post
223
        $this->logInWithPermission('ANY_PERMISSION');
224
        $this->assertTrue($item->canPostComment());
225
        $this->assertTrue($item2->canPostComment());
226
    }
227
    public function testDeleteComment()
228
    {
229
        // Test anonymous user
230
        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...
231
            $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...
232
        }
233
        $comment = $this->objFromFixture(Comment::class, 'firstComA');
234
        $commentID = $comment->ID;
235
        $this->assertNull($comment->DeleteLink(), 'No permission to see delete link');
236
        $delete = $this->get('comments/delete/' . $comment->ID . '?ajax=1');
237
        $this->assertEquals(403, $delete->getStatusCode());
238
        $check = DataObject::get_by_id(Comment::class, $commentID);
239
        $this->assertTrue($check && $check->exists());
240
241
        // Test non-authenticated user
242
        $this->logInAs('visitor');
243
        $this->assertNull($comment->DeleteLink(), 'No permission to see delete link');
244
245
        // Test authenticated user
246
        $this->logInAs('commentadmin');
247
        $comment = $this->objFromFixture(Comment::class, 'firstComA');
248
        $commentID = $comment->ID;
249
        $adminComment1Link = $comment->DeleteLink();
250
        $this->assertContains('comments/delete/' . $commentID . '?t=', $adminComment1Link);
251
252
        // Test that this link can't be shared / XSS exploited
253
        $this->logInAs('commentadmin2');
254
        $delete = $this->get($adminComment1Link);
255
        $this->assertEquals(400, $delete->getStatusCode());
256
        $check = DataObject::get_by_id(Comment::class, $commentID);
257
        $this->assertTrue($check && $check->exists());
258
259
        // Test that this other admin can delete the comment with their own link
260
        $adminComment2Link = $comment->DeleteLink();
261
        $this->assertNotEquals($adminComment2Link, $adminComment1Link);
262
        $this->autoFollowRedirection = false;
263
        $delete = $this->get($adminComment2Link);
264
        $this->assertEquals(302, $delete->getStatusCode());
265
        $check = DataObject::get_by_id(Comment::class, $commentID);
266
        $this->assertFalse($check && $check->exists());
267
    }
268
269 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...
270
    {
271
        // Test anonymous user
272
        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...
273
            $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...
274
        }
275
        $comment = $this->objFromFixture(Comment::class, 'firstComA');
276
        $commentID = $comment->ID;
277
        $this->assertNull($comment->SpamLink(), 'No permission to see mark as spam link');
278
        $spam = $this->get('comments/spam/'.$comment->ID.'?ajax=1');
279
        $this->assertEquals(403, $spam->getStatusCode());
280
        $check = DataObject::get_by_id(Comment::class, $commentID);
281
        $this->assertEquals(0, $check->IsSpam, 'No permission to mark as spam');
282
283
        // Test non-authenticated user
284
        $this->logInAs('visitor');
285
        $this->assertNull($comment->SpamLink(), 'No permission to see mark as spam link');
286
287
        // Test authenticated user
288
        $this->logInAs('commentadmin');
289
        $comment = $this->objFromFixture(Comment::class, 'firstComA');
290
        $commentID = $comment->ID;
291
        $adminComment1Link = $comment->SpamLink();
292
        $this->assertContains('comments/spam/' . $commentID . '?t=', $adminComment1Link);
293
294
        // Test that this link can't be shared / XSS exploited
295
        $this->logInAs('commentadmin2');
296
        $spam = $this->get($adminComment1Link);
297
        $this->assertEquals(400, $spam->getStatusCode());
298
        $check = DataObject::get_by_id(Comment::class, $comment->ID);
299
        $this->assertEquals(0, $check->IsSpam, 'No permission to mark as spam');
300
301
        // Test that this other admin can spam the comment with their own link
302
        $adminComment2Link = $comment->SpamLink();
303
        $this->assertNotEquals($adminComment2Link, $adminComment1Link);
304
        $this->autoFollowRedirection = false;
305
        $spam = $this->get($adminComment2Link);
306
        $this->assertEquals(302, $spam->getStatusCode());
307
        $check = DataObject::get_by_id(Comment::class, $commentID);
308
        $this->assertEquals(1, $check->IsSpam);
309
310
        // Cannot re-spam spammed comment
311
        $this->assertNull($check->SpamLink());
312
    }
313
314 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...
315
    {
316
        // Test anonymous user
317
        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...
318
            $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...
319
        }
320
        $comment = $this->objFromFixture(Comment::class, 'secondComC');
321
        $commentID = $comment->ID;
322
        $this->assertNull($comment->HamLink(), 'No permission to see mark as ham link');
323
        $ham = $this->get('comments/ham/' . $comment->ID . '?ajax=1');
324
        $this->assertEquals(403, $ham->getStatusCode());
325
        $check = DataObject::get_by_id(Comment::class, $commentID);
326
        $this->assertEquals(1, $check->IsSpam, 'No permission to mark as ham');
327
328
        // Test non-authenticated user
329
        $this->logInAs('visitor');
330
        $this->assertNull($comment->HamLink(), 'No permission to see mark as ham link');
331
332
        // Test authenticated user
333
        $this->logInAs('commentadmin');
334
        $comment = $this->objFromFixture(Comment::class, 'secondComC');
335
        $commentID = $comment->ID;
336
        $adminComment1Link = $comment->HamLink();
337
        $this->assertContains('comments/ham/' . $commentID . '?t=', $adminComment1Link);
338
339
        // Test that this link can't be shared / XSS exploited
340
        $this->logInAs('commentadmin2');
341
        $ham = $this->get($adminComment1Link);
342
        $this->assertEquals(400, $ham->getStatusCode());
343
        $check = DataObject::get_by_id(Comment::class, $comment->ID);
344
        $this->assertEquals(1, $check->IsSpam, 'No permission to mark as ham');
345
346
        // Test that this other admin can ham the comment with their own link
347
        $adminComment2Link = $comment->HamLink();
348
        $this->assertNotEquals($adminComment2Link, $adminComment1Link);
349
        $this->autoFollowRedirection = false;
350
        $ham = $this->get($adminComment2Link);
351
        $this->assertEquals(302, $ham->getStatusCode());
352
        $check = DataObject::get_by_id(Comment::class, $commentID);
353
        $this->assertEquals(0, $check->IsSpam);
354
355
        // Cannot re-ham hammed comment
356
        $this->assertNull($check->HamLink());
357
    }
358
359 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...
360
    {
361
        // Test anonymous user
362
        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...
363
            $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...
364
        }
365
        $comment = $this->objFromFixture(Comment::class, 'secondComB');
366
        $commentID = $comment->ID;
367
        $this->assertNull($comment->ApproveLink(), 'No permission to see approve link');
368
        $approve = $this->get('comments/approve/' . $comment->ID . '?ajax=1');
369
        $this->assertEquals(403, $approve->getStatusCode());
370
        $check = DataObject::get_by_id(Comment::class, $commentID);
371
        $this->assertEquals(0, $check->Moderated, 'No permission to approve');
372
373
        // Test non-authenticated user
374
        $this->logInAs('visitor');
375
        $this->assertNull($comment->ApproveLink(), 'No permission to see approve link');
376
377
        // Test authenticated user
378
        $this->logInAs('commentadmin');
379
        $comment = $this->objFromFixture(Comment::class, 'secondComB');
380
        $commentID = $comment->ID;
381
        $adminComment1Link = $comment->ApproveLink();
382
        $this->assertContains('comments/approve/' . $commentID . '?t=', $adminComment1Link);
383
384
        // Test that this link can't be shared / XSS exploited
385
        $this->logInAs('commentadmin2');
386
        $approve = $this->get($adminComment1Link);
387
        $this->assertEquals(400, $approve->getStatusCode());
388
        $check = DataObject::get_by_id(Comment::class, $comment->ID);
389
        $this->assertEquals(0, $check->Moderated, 'No permission to approve');
390
391
        // Test that this other admin can approve the comment with their own link
392
        $adminComment2Link = $comment->ApproveLink();
393
        $this->assertNotEquals($adminComment2Link, $adminComment1Link);
394
        $this->autoFollowRedirection = false;
395
        $approve = $this->get($adminComment2Link);
396
        $this->assertEquals(302, $approve->getStatusCode());
397
        $check = DataObject::get_by_id(Comment::class, $commentID);
398
        $this->assertEquals(1, $check->Moderated);
399
400
        // Cannot re-approve approved comment
401
        $this->assertNull($check->ApproveLink());
402
    }
403
404
    public function testCommenterURLWrite()
405
    {
406
        $comment = new Comment();
407
        // We only care about the CommenterURL, so only set that
408
        // Check a http and https URL. Add more test urls here as needed.
409
        $protocols = array(
410
            'Http',
411
            'Https',
412
        );
413
        $url = '://example.com';
414
415
        foreach ($protocols as $protocol) {
416
            $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...
417
            // The protocol should stay as if, assuming it is valid
418
            $comment->write();
419
            $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...
420
        }
421
    }
422
423
    public function testSanitizesWithAllowHtml()
424
    {
425
        if (!class_exists('\\HTMLPurifier')) {
426
            $this->markTestSkipped('HTMLPurifier class not found');
427
            return;
428
        }
429
430
        // Add p for paragraph
431
        // NOTE: The config method appears to append to the existing array
432
        Config::modify()->merge(CommentableItem::class, 'comments', array(
433
            'html_allowed_elements' => array('p'),
434
        ));
435
436
        // Without HTML allowed
437
        $comment1 = new Comment();
438
        $comment1->AllowHtml = false;
439
        $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...
440
        $comment1->Comment = '<p><script>alert("w00t")</script>my comment</p>';
441
        $comment1->write();
442
        $this->assertEquals(
443
            '<p><script>alert("w00t")</script>my comment</p>',
444
            $comment1->Comment,
445
            'Does not remove HTML tags with html_allowed=false, ' .
446
            'which is correct behaviour because the HTML will be escaped'
447
        );
448
449
        // With HTML allowed
450
        $comment2 = new Comment();
451
        $comment2->AllowHtml = true;
452
        $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...
453
        $comment2->Comment = '<p><script>alert("w00t")</script>my comment</p>';
454
        $comment2->write();
455
        $this->assertEquals(
456
            '<p>my comment</p>',
457
            $comment2->Comment,
458
            'Removes HTML tags which are not on the whitelist'
459
        );
460
    }
461
462
    public function testDefaultTemplateRendersHtmlWithAllowHtml()
463
    {
464
        if (!class_exists('\\HTMLPurifier')) {
465
            $this->markTestSkipped('HTMLPurifier class not found');
466
        }
467
468
        Config::modify()->merge(CommentableItem::class, 'comments', array(
469
            'html_allowed_elements' => array('p'),
470
        ));
471
472
        $item = new CommentableItem();
473
        $item->write();
474
475
        // Without HTML allowed
476
        $comment = new Comment();
477
        $comment->Comment = '<p>my comment</p>';
478
        $comment->AllowHtml = false;
479
        $comment->ParentID = $item->ID;
480
        $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...
481
        $comment->write();
482
483
        $html = $item->customise(array('CommentsEnabled' => true))->renderWith('CommentsInterface');
484
        $this->assertContains(
485
            '&lt;p&gt;my comment&lt;/p&gt;',
486
            $html
487
        );
488
489
        $comment->AllowHtml = true;
490
        $comment->write();
491
        $html = $item->customise(array('CommentsEnabled' => true))->renderWith('CommentsInterface');
492
        $this->assertContains(
493
            '<p>my comment</p>',
494
            $html
495
        );
496
    }
497
498
499
    /**
500
     * Tests whether comments are enabled or disabled by default
501
     */
502
    public function testDefaultEnabled()
503
    {
504
        Config::modify()->merge(CommentableItem::class, 'comments', array(
505
            'enabled_cms' => true,
506
            'require_moderation_cms' => true,
507
            'require_login_cms' => true
508
        ));
509
510
        // With default = true
511
        $obj = new CommentableItem();
512
        $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...
513
        $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...
514
        $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...
515
        $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...
516
517
        $obj = new CommentableItemEnabled();
518
        $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...
519
        $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...
520
        $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...
521
522
        $obj = new CommentableItemDisabled();
523
        $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...
524
        $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...
525
        $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...
526
527
        // With default = false
528
        // Because of config rules about falsey values, apply config to object directly
529
        Config::modify()->merge(CommentableItem::class, 'comments', array(
530
            'enabled' => false,
531
            'require_login' => true,
532
            'require_moderation' => true
533
        ));
534
535
        $obj = new CommentableItem();
536
537
        $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...
538
        $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...
539
        $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...
540
        $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...
541
542
        $obj = new CommentableItemEnabled();
543
544
        $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...
545
        $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...
546
        $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...
547
548
        $obj = new CommentableItemDisabled();
549
550
        $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...
551
        $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...
552
        $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...
553
    }
554
555
    public function testOnBeforeDelete()
556
    {
557
        $comment = $this->objFromFixture(Comment::class, 'firstComA');
558
559
        $child = new Comment();
560
        $child->Name = 'Fred Bloggs';
561
        $child->Comment = 'Child of firstComA';
562
        $child->write();
563
        $comment->ChildComments()->add($child);
564
        $this->assertEquals(4, $comment->ChildComments()->count());
565
566
        $commentID = $comment->ID;
567
        $childCommentID = $child->ID;
568
569
        $comment->delete();
570
571
        // assert that the new child been deleted
572
        $this->assertNull(DataObject::get_by_id(Comment::class, $commentID));
573
        $this->assertNull(DataObject::get_by_id(Comment::class, $childCommentID));
574
    }
575
576
    public function testRequireDefaultRecords()
577
    {
578
        $this->markTestSkipped('TODO');
579
    }
580
581
    public function testLink()
582
    {
583
        $comment = $this->objFromFixture(Comment::class, 'thirdComD');
584
        $this->assertEquals(
585
            'CommentableItemController#comment-' . $comment->ID,
586
            $comment->Link()
587
        );
588
        $this->assertEquals($comment->ID, $comment->ID);
589
590
        // An orphan comment has no link
591
        $comment->ParentID = 0;
592
        $comment->ParentClass = null;
593
        $comment->write();
594
        $this->assertEquals('', $comment->Link());
595
    }
596
597
    public function testPermalink()
598
    {
599
        $comment = $this->objFromFixture(Comment::class, 'thirdComD');
600
        $this->assertEquals('comment-' . $comment->ID, $comment->Permalink());
601
    }
602
603
    /**
604
     * Test field labels in 2 languages
605
     */
606
    public function testFieldLabels()
607
    {
608
        $locale = i18n::get_locale();
609
        i18n::set_locale('fr');
610
        $comment = $this->objFromFixture(Comment::class, 'firstComA');
611
        $labels = $comment->FieldLabels();
612
        $expected = array(
613
            'Name' => 'Nom de l\'Auteur',
614
            'Comment' => 'Commentaire',
615
            'Email' => 'Email',
616
            'URL' => 'URL',
617
            'Moderated' => 'Modéré?',
618
            'IsSpam' => 'Spam?',
619
            'AllowHtml' => 'Allow Html',
620
            'SecretToken' => 'Secret Token',
621
            'Depth' => 'Depth',
622
            'Author' => 'Author Member',
623
            'ParentComment' => 'Parent Comment',
624
            'ChildComments' => 'Child Comments',
625
            'ParentTitle' => 'Parent',
626
            'Created' => 'Date de publication',
627
            'Parent' => 'Parent'
628
        );
629
        i18n::set_locale($locale);
630
        $this->assertEquals($expected, $labels);
631
        $labels = $comment->FieldLabels();
632
        $expected = array(
633
            'Name' => 'Author Name',
634
            'Comment' => 'Comment',
635
            'Email' => 'Email',
636
            'URL' => 'URL',
637
            'Moderated' => 'Moderated?',
638
            'IsSpam' => 'Spam?',
639
            'AllowHtml' => 'Allow Html',
640
            'SecretToken' => 'Secret Token',
641
            'Depth' => 'Depth',
642
            'Author' => 'Author Member',
643
            'ParentComment' => 'Parent Comment',
644
            'ChildComments' => 'Child Comments',
645
            'ParentTitle' => 'Parent',
646
            'Created' => 'Date posted',
647
            'Parent' => 'Parent'
648
        );
649
        $this->assertEquals($expected, $labels);
650
    }
651
652
    public function testGetParent()
653
    {
654
        $comment = $this->objFromFixture(Comment::class, 'firstComA');
655
        $item = $this->objFromFixture(CommentableItem::class, 'first');
656
        $parent = $comment->Parent();
657
        $this->assertSame($item->getClassName(), $parent->getClassName());
658
        $this->assertSame($item->ID, $parent->ID);
659
    }
660
661 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...
662
    {
663
        $comment = $this->objFromFixture(Comment::class, 'firstComA');
664
        $title = $comment->getParentTitle();
665
        $this->assertEquals('First', $title);
666
667
        // Title from a comment with no parent is blank
668
        $comment->ParentID = 0;
669
        $comment->ParentClass = null;
670
        $comment->write();
671
        $this->assertEquals('', $comment->getParentTitle());
672
    }
673
674
    public function testGetParentClassName()
675
    {
676
        $comment = $this->objFromFixture(Comment::class, 'firstComA');
677
        $className = $comment->getParentClassName();
678
        $this->assertEquals(CommentableItem::class, $className);
679
    }
680
681
    public function testCastingHelper()
682
    {
683
        $this->markTestSkipped('TODO');
684
    }
685
686
    public function testGetEscapedComment()
687
    {
688
        $this->markTestSkipped('TODO');
689
    }
690
691
    public function testIsPreview()
692
    {
693
        $comment = new Comment();
694
        $comment->Name = 'Fred Bloggs';
695
        $comment->Comment = 'this is a test comment';
696
        $this->assertTrue($comment->isPreview());
697
        $comment->write();
698
        $this->assertFalse($comment->isPreview());
699
    }
700
701
    public function testCanCreate()
702
    {
703
        $comment = $this->objFromFixture(Comment::class, 'firstComA');
704
705
        // admin can create - this is always false
706
        $this->logInAs('commentadmin');
707
        $this->assertFalse($comment->canCreate());
708
709
        // visitor can view
710
        $this->logInAs('visitor');
711
        $this->assertFalse($comment->canCreate());
712
    }
713
714 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...
715
    {
716
        $comment = $this->objFromFixture(Comment::class, 'firstComA');
717
718
        // admin can view
719
        $this->logInAs('commentadmin');
720
        $this->assertTrue($comment->canView());
721
722
        // visitor can view
723
        $this->logInAs('visitor');
724
        $this->assertTrue($comment->canView());
725
726
        $comment->ParentID = 0;
727
        $comment->write();
728
        $this->assertFalse($comment->canView());
729
    }
730
731 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...
732
    {
733
        $comment = $this->objFromFixture(Comment::class, 'firstComA');
734
735
        // admin can edit
736
        $this->logInAs('commentadmin');
737
        $this->assertTrue($comment->canEdit());
738
739
        // visitor cannot
740
        $this->logInAs('visitor');
741
        $this->assertFalse($comment->canEdit());
742
743
        $comment->ParentID = 0;
744
        $comment->write();
745
        $this->assertFalse($comment->canEdit());
746
    }
747
748 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...
749
    {
750
        $comment = $this->objFromFixture(Comment::class, 'firstComA');
751
752
        // admin can delete
753
        $this->logInAs('commentadmin');
754
        $this->assertTrue($comment->canDelete());
755
756
        // visitor cannot
757
        $this->logInAs('visitor');
758
        $this->assertFalse($comment->canDelete());
759
760
        $comment->ParentID = 0;
761
        $comment->write();
762
        $this->assertFalse($comment->canDelete());
763
    }
764
765
    public function testGetMember()
766
    {
767
        $this->logInAs('visitor');
768
        $current = Security::getCurrentUser();
769
        $comment = $this->objFromFixture(Comment::class, 'firstComA');
770
        $method = $this->getMethod('getMember');
771
772
        // null case
773
        $member = $method->invokeArgs($comment, array());
774
        $this->assertEquals($current->ID, $member->ID);
775
776
        // numeric ID case
777
        $member = $method->invokeArgs($comment, array($current->ID));
778
        $this->assertEquals($current->ID, $member->ID);
779
780
        // identity case
781
        $member = $method->invokeArgs($comment, array($current));
782
        $this->assertEquals($current->ID, $member->ID);
783
    }
784
785
    public function testGetAuthorName()
786
    {
787
        $comment = $this->objFromFixture(Comment::class, 'firstComA');
788
        $this->assertEquals(
789
            'FA',
790
            $comment->getAuthorName()
791
        );
792
793
        $comment->Name = '';
794
        $this->assertEquals(
795
            '',
796
            $comment->getAuthorName()
797
        );
798
799
        $author = $this->objFromFixture(Member::class, 'visitor');
800
        $comment->AuthorID = $author->ID;
801
        $comment->write();
802
        $this->assertEquals(
803
            'visitor',
804
            $comment->getAuthorName()
805
        );
806
807
        // null the names, expect null back
808
        $comment->Name = null;
809
        $comment->AuthorID = 0;
810
        $this->assertNull($comment->getAuthorName());
811
    }
812
813
814
    public function testLinks()
815
    {
816
        $comment = $this->objFromFixture(Comment::class, 'firstComA');
817
        $this->logInAs('commentadmin');
818
819
        $method = $this->getMethod('ActionLink');
820
821
        // test with starts of strings and tokens and salts change each time
822
        $this->assertContains(
823
            '/comments/theaction/' . $comment->ID,
824
            $method->invokeArgs($comment, array('theaction'))
825
        );
826
827
        $this->assertContains(
828
            '/comments/delete/' . $comment->ID,
829
            $comment->DeleteLink()
830
        );
831
832
        $this->assertContains(
833
            '/comments/spam/' . $comment->ID,
834
            $comment->SpamLink()
835
        );
836
837
        $comment->markSpam();
838
        $this->assertContains(
839
            '/comments/ham/' . $comment->ID,
840
            $comment->HamLink()
841
        );
842
843
        //markApproved
844
        $comment->markUnapproved();
845
        $this->assertContains(
846
            '/comments/approve/' . $comment->ID,
847
            $comment->ApproveLink()
848
        );
849
    }
850
851
    public function testMarkSpam()
852
    {
853
        $comment = $this->objFromFixture(Comment::class, 'firstComA');
854
        $comment->markSpam();
855
        $this->assertTrue($comment->Moderated);
856
        $this->assertTrue($comment->IsSpam);
857
    }
858
859
    public function testMarkApproved()
860
    {
861
        $comment = $this->objFromFixture(Comment::class, 'firstComA');
862
        $comment->markApproved();
863
        $this->assertTrue($comment->Moderated);
864
        $this->assertFalse($comment->IsSpam);
865
    }
866
867
    public function testMarkUnapproved()
868
    {
869
        $comment = $this->objFromFixture(Comment::class, 'firstComA');
870
        $comment->markApproved();
871
        $this->assertTrue($comment->Moderated);
872
    }
873
874 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...
875
    {
876
        $comment = $this->objFromFixture(Comment::class, 'firstComA');
877
        $this->assertEquals('notspam', $comment->spamClass());
878
        $comment->Moderated = false;
879
        $this->assertEquals('unmoderated', $comment->spamClass());
880
        $comment->IsSpam = true;
881
        $this->assertEquals('spam', $comment->spamClass());
882
    }
883
884
    public function testGetTitle()
885
    {
886
        $comment = $this->objFromFixture(Comment::class, 'firstComA');
887
        $this->assertEquals(
888
            'Comment by FA on First',
889
            $comment->getTitle()
890
        );
891
    }
892
893
    public function testGetCMSFields()
894
    {
895
        $comment = $this->objFromFixture(Comment::class, 'firstComA');
896
        $fields = $comment->getCMSFields();
897
        $names = array();
898
        foreach ($fields as $field) {
899
            $names[] = $field->getName();
900
        }
901
        $expected = array(
902
            'Created',
903
            'Name',
904
            'Comment',
905
            'Email',
906
            'URL',
907
            'Options'
908
        );
909
        $this->assertEquals($expected, $names);
910
    }
911
912
    public function testGetCMSFieldsCommentHasAuthor()
913
    {
914
        $member = Member::get()->filter('FirstName', 'visitor')->first();
915
        $comment = $this->objFromFixture(Comment::class, 'firstComA');
916
        $comment->AuthorID = $member->ID;
917
        $comment->write();
918
919
        $fields = $comment->getCMSFields();
920
        $names = array();
921
        foreach ($fields as $field) {
922
            $names[] = $field->getName();
923
        }
924
        $expected = array(
925
            'Created',
926
            'Name',
927
            'AuthorMember',
928
            'Comment',
929
            'Email',
930
            'URL',
931
            'Options'
932
        );
933
        $this->assertEquals($expected, $names);
934
    }
935
936
    public function testGetCMSFieldsWithParentComment()
937
    {
938
        $comment = $this->objFromFixture(Comment::class, 'firstComA');
939
940
        $child = new Comment();
941
        $child->Name = 'John Smith';
942
        $child->Comment = 'This is yet another test commnent';
943
        $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...
944
        $child->write();
945
946
        $fields = $child->getCMSFields();
947
        $names = array();
948
        foreach ($fields as $field) {
949
            $names[] = $field->getName();
950
        }
951
        $expected = array(
952
            'Created',
953
            'Name',
954
            'Comment',
955
            'Email',
956
            'URL',
957
            'Options',
958
            'ParentComment_Title',
959
            'ParentComment_Created',
960
            'ParentComment_AuthorName',
961
            'ParentComment_EscapedComment'
962
        );
963
        $this->assertEquals($expected, $names);
964
    }
965
966
    public function testPurifyHtml()
967
    {
968
        if (!class_exists(HTMLPurifier_Config::class)) {
969
            $this->markTestSkipped('HTMLPurifier class not found');
970
            return;
971
        }
972
973
        $comment = $this->objFromFixture(Comment::class, 'firstComA');
974
975
        $dirtyHTML = '<p><script>alert("w00t")</script>my comment</p>';
976
        $this->assertEquals(
977
            'my comment',
978
            $comment->purifyHtml($dirtyHTML)
979
        );
980
    }
981
982
    public function testGravatar()
983
    {
984
        // Turn gravatars on
985
        Config::modify()->merge(CommentableItem::class, 'comments', array(
986
            'use_gravatar' => true,
987
            'gravatar_size' => 80,
988
            'gravatar_default' => 'identicon',
989
            'gravatar_rating' => 'g'
990
        ));
991
992
        $comment = $this->objFromFixture(Comment::class, 'firstComA');
993
994
        $this->assertEquals(
995
            'http://www.gravatar.com/avatar/d41d8cd98f00b204e9800998ecf8427e?s'
996
            . '=80&d=identicon&r=g',
997
            $comment->Gravatar()
998
        );
999
1000
        // Turn gravatars off
1001
        Config::modify()->merge(CommentableItem::class, 'comments', array(
1002
            'use_gravatar' => false
1003
        ));
1004
1005
        $comment = $this->objFromFixture(Comment::class, 'firstComA');
1006
1007
        $this->assertEquals(
1008
            '',
1009
            $comment->Gravatar()
1010
        );
1011
    }
1012
1013
    public function testGetRepliesEnabled()
1014
    {
1015
        Config::modify()->merge(CommentableItem::class, 'comments', array(
1016
            'nested_comments' => false
1017
        ));
1018
1019
        $comment = $this->objFromFixture(Comment::class, 'firstComA');
1020
        $this->assertFalse($comment->getRepliesEnabled());
1021
1022
        Config::modify()->merge(CommentableItem::class, 'comments', array(
1023
            'nested_comments' => true,
1024
            'nested_depth' => 4
1025
        ));
1026
1027
        $this->assertTrue($comment->getRepliesEnabled());
1028
1029
        $comment->Depth = 4;
1030
        $this->assertFalse($comment->getRepliesEnabled());
1031
1032
1033
        // 0 indicates no limit for nested_depth
1034
        Config::modify()->merge(CommentableItem::class, 'comments', array(
1035
            'nested_comments' => true,
1036
            'nested_depth' => 0
1037
        ));
1038
1039
        $comment = $this->objFromFixture(Comment::class, 'firstComA');
1040
        $comment->Depth = 234;
1041
1042
        $comment->markUnapproved();
1043
        $this->assertFalse($comment->getRepliesEnabled());
1044
1045
        $comment->markSpam();
1046
        $this->assertFalse($comment->getRepliesEnabled());
1047
1048
        $comment->markApproved();
1049
        $this->assertTrue($comment->getRepliesEnabled());
1050
    }
1051
1052
    public function testAllReplies()
1053
    {
1054
        Config::modify()->merge(CommentableItem::class, 'comments', array(
1055
            'nested_comments' => true,
1056
            'nested_depth' => 4
1057
        ));
1058
1059
        $comment = $this->objFromFixture(Comment::class, 'firstComA');
1060
1061
        $this->assertEquals(
1062
            3,
1063
            $comment->allReplies()->count()
1064
        );
1065
1066
        $child = new Comment();
1067
        $child->Name = 'Fred Smith';
1068
        $child->Comment = 'This is a child comment';
1069
        $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...
1070
1071
        // spam should be returned by this method
1072
        $child->markSpam();
1073
        $child->write();
1074
        $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...
1075
        $this->assertEquals(
1076
            4,
1077
            $comment->allReplies()->count()
1078
        );
1079
1080
        Config::modify()->merge(CommentableItem::class, 'comments', array(
1081
            'nested_comments' => false
1082
        ));
1083
1084
        $this->assertEquals(0, $comment->allReplies()->count());
1085
    }
1086
1087
    public function testReplies()
1088
    {
1089
        CommentableItem::add_extension(CommentsExtension::class);
1090
        $this->logInWithPermission('ADMIN');
1091
        Config::modify()->merge(CommentableItem::class, 'comments', array(
1092
            'nested_comments' => true,
1093
            'nested_depth' => 4
1094
        ));
1095
        $comment = $this->objFromFixture(Comment::class, 'firstComA');
1096
        $this->assertEquals(
1097
            3,
1098
            $comment->Replies()->count()
1099
        );
1100
1101
        // Test that spam comments are not returned
1102
        $childComment = $comment->Replies()->first();
1103
        $childComment->IsSpam = 1;
1104
        $childComment->write();
1105
        $this->assertEquals(
1106
            2,
1107
            $comment->Replies()->count()
1108
        );
1109
1110
        // Test that unmoderated comments are not returned
1111
        //
1112
        $childComment = $comment->Replies()->first();
1113
1114
        // FIXME - moderation settings scenarios need checked here
1115
        $childComment->Moderated = 0;
1116
        $childComment->IsSpam = 0;
1117
        $childComment->write();
1118
        $this->assertEquals(
1119
            2,
1120
            $comment->Replies()->count()
1121
        );
1122
1123
1124
        // Test moderation required on the front end
1125
        $item = $this->objFromFixture(CommentableItem::class, 'first');
1126
        $item->ModerationRequired = 'Required';
1127
        $item->write();
1128
1129
        Config::modify()->merge(CommentableItemDisabled::class, 'comments', array(
1130
            'nested_comments' => true,
1131
            'nested_depth' => 4,
1132
            'frontend_moderation' => true
1133
        ));
1134
1135
        $comment = DataObject::get_by_id(Comment::class, $comment->ID);
1136
1137
        $this->assertEquals(
1138
            2,
1139
            $comment->Replies()->count()
1140
        );
1141
1142
        // Turn off nesting, empty array should be returned
1143
        Config::modify()->merge(CommentableItem::class, 'comments', array(
1144
            'nested_comments' => false
1145
        ));
1146
1147
        $this->assertEquals(
1148
            0,
1149
            $comment->Replies()->count()
1150
        );
1151
1152
        CommentableItem::remove_extension(CommentsExtension::class);
1153
    }
1154
1155
    public function testPagedReplies()
1156
    {
1157
        Config::modify()->merge(CommentableItem::class, 'comments', array(
1158
            'nested_comments' => true,
1159
            'nested_depth' => 4,
1160
            'comments_per_page' => 2
1161
        ));
1162
1163
        $comment = $this->objFromFixture(Comment::class, 'firstComA');
1164
        $pagedList = $comment->pagedReplies();
1165
1166
        $this->assertEquals(
1167
            2,
1168
            $pagedList->TotalPages()
1169
        );
1170
1171
        $this->assertEquals(
1172
            3,
1173
            $pagedList->getTotalItems()
1174
        );
1175
1176
        Config::modify()->merge(CommentableItem::class, 'comments', array(
1177
            'nested_comments' => false
1178
        ));
1179
1180
        $this->assertEquals(0, $comment->PagedReplies()->count());
1181
    }
1182
1183
    public function testReplyForm()
1184
    {
1185
        Config::modify()->merge(CommentableItem::class, 'comments', array(
1186
            'nested_comments' => false,
1187
            'nested_depth' => 4
1188
        ));
1189
1190
        $comment = $this->objFromFixture(Comment::class, 'firstComA');
1191
1192
        // No nesting, no reply form
1193
        $form = $comment->replyForm();
1194
        $this->assertNull($form);
1195
1196
        // parent item so show form
1197
        Config::modify()->merge(CommentableItem::class, 'comments', array(
1198
            'nested_comments' => true,
1199
            'nested_depth' => 4
1200
        ));
1201
        $form = $comment->ReplyForm();
1202
        $this->assertNotNull($form);
1203
        $names = array();
1204
1205
        foreach ($form->Fields() as $field) {
1206
            array_push($names, $field->getName());
1207
        }
1208
1209
        $this->assertEquals(
1210
            array(
1211
                'NameEmailURLComment', // The CompositeField name?
1212
                'ParentID',
1213
                'ParentClassName',
1214
                'ReturnURL',
1215
                'ParentCommentID'
1216
            ),
1217
            $names
1218
        );
1219
1220
        // no parent, no reply form
1221
1222
        $comment->ParentID = 0;
1223
        $comment->ParentClass = null;
1224
        $comment->write();
1225
        $form = $comment->replyForm();
1226
        $this->assertNull($form);
1227
    }
1228
1229
    public function testUpdateDepth()
1230
    {
1231
        Config::modify()->merge(CommentableItem::class, 'comments', array(
1232
            'nested_comments' => true,
1233
            'nested_depth' => 4
1234
        ));
1235
1236
        $comment = $this->objFromFixture(Comment::class, 'firstComA');
1237
        $children = $comment->allReplies()->toArray();
1238
        // Make the second child a child of the first
1239
        // Make the third child a child of the second
1240
        $reply1 = $children[0];
1241
        $reply2 = $children[1];
1242
        $reply3 = $children[2];
1243
        $reply2->ParentCommentID = $reply1->ID;
1244
        $reply2->write();
1245
        $this->assertEquals(3, $reply2->Depth);
1246
        $reply3->ParentCommentID = $reply2->ID;
1247
        $reply3->write();
1248
        $this->assertEquals(4, $reply3->Depth);
1249
    }
1250
1251
    public function testGetToken()
1252
    {
1253
        $this->markTestSkipped('TODO');
1254
    }
1255
1256
    public function testMemberSalt()
1257
    {
1258
        $this->markTestSkipped('TODO');
1259
    }
1260
1261
    public function testAddToUrl()
1262
    {
1263
        $this->markTestSkipped('TODO');
1264
    }
1265
1266
    public function testCheckRequest()
1267
    {
1268
        $this->markTestSkipped('TODO');
1269
    }
1270
1271
    public function testGenerate()
1272
    {
1273
        $this->markTestSkipped('TODO');
1274
    }
1275
1276
    protected static function getMethod($name)
1277
    {
1278
        $class = new ReflectionClass(Comment::class);
1279
        $method = $class->getMethod($name);
1280
        $method->setAccessible(true);
1281
        return $method;
1282
    }
1283
}
1284